]> git.mjollnir.org Git - moodle.git/commitdiff
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 fad629a24275fc8dba6435c3bb73ff96928a9af0..da49241c65a622401d5ac8144b96eaa9a69031fb 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 daac9b5e1d7ac39ffbe291bcebe32ed72a51a68c..99cec4244cf4047ee6754787c186b7c2e9fa8e6f 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 4c2bd2d72bf8733196589ef4195bd01d39522c24..70bedab44b3be0e816a04fcfe1c3dcd431bf45e3 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 9783aa34e730b95016320343e26758e55e2db206..3bd89305b59a61e385ca61301eba34faa6e01e5e 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 b915845f3dd92706bc0c93a863449836133a1a9b..879670a2c2e5957eef47352ffde818e95b66646a 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 f3595ddcd21a11175f73ae4ebd6762347e4064c8..a2bfd247ad36146825633ffce88afca3b229bbc0 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 0b5714d025714a6f42a5b2763a495cb7fe26ab3c..ae15a80dffd1ead3b34935db8469b9e2c4bbed78 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 35772e4ddd5a1b5da738129c9103e07ca089f014..3e3231664837722168df7eb384fd0158fa3c7054 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 035edc50da7a25f7780132c055e48943ff31b6fe..d5db116059b9b87be2124b1e496b9baa6121dfea 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 4d37b58361f20a42a3ab3bc8642b1a18a2820e02..f56c1594f283ea33849f833b1f23dab3461a0a6e 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 c9a924c1cdf4f3f57487f1293b1df2419780394e..ff585a6262b39071a263fce8e08aa4ff2be649c9 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 e8e1258e5c53bcf65baa13aac8b70e48540005c8..ab27e9dd2fa6d84e1d136f8fdaca532ce393d2f4 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 2e4d3bf498cb797c6dc0302c4deeebdff3b875d6..4710792cc5487ef4625a93fd2a75e9b818eb9687 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 b2f9f5d206a64db7a05537880bc4d7a53e88052d..678b075cfe031a125815f0f0a2679d11b20f83d4 100644 (file)
@@ -1,2 +1,2 @@
-<html>\r
-<body>\r
+<html>
+<body>
index 6cef94d8eaa241d9a0d81aadd7df153218eda864..d89c9e5c3e56f9fbea0e1dff6afea1e72fc25315 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 658cb6b35dc163f590cc3d5889e011c50d02d4a3..ca6c9057f439e98a4ec687f2c90a7276cb0d00e6 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 e8d8d15e30d85638b1f2e3759769be4783d6f99d..605ee0c9cd0e41f402bd53a12ea2fe6519105470 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 5274dda597a26fe17d25183e014d2fa927007e28..ad3482603c3b43ce1c6a1f07b756aa8c9c818df3 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 cc0db7797e475680678d37e5d8e6aa21e5806196..1d9adf5f5cf64daecf60dfc49b0ef04e06dd08fa 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 5b245ce68d3084726a485e840c2f783b59381b33..9ff41018177e2ac354c41db18d799b9e75ec3d3a 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 c6f6f2e3e406a8de2a0def3dae3827bd687579a5..4d9dbaee05319fff70c1b499392a6f55e641aba5 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 07b687c0bf2026a6cbe09229001bc9c7289da506..474d66105fe86b01e31c43d7227f70afb016c99f 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 86d18a6ba1575e201fe9ead3359b6fe975f08952..d112bb7e3115f9c588ae194dcd72a2813a0ab48c 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 de87cbdc9fdb11c420b0727ef22d70f8d95f4eb4..3c01ae0469458f54919ae440e4c59748a32058fe 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);\r
-               if (a[0]=='ShowHint') {\r
-                       if (a[1]=='QNum') {\r
-                               // JQuiz v3, v5-v6[HP5]\r
-                               x = 'if(!ShowHint&&Status[QNum][0]<1)hpClick(3,QNum);'; \r
-                       } else {\r
-                               // JQuiz v4\r
-                               x = 'if(!ShowHint&&State[QNum-1][0]<1)hpClick(3,QNum-1);'; // QNum is a global variable\r
-                       }\r
-               } else if (a[0]=='CheckType') {\r
-                       // JMix v5-v6\r
-                       x = 'if(CheckType==0)hpClick(3,0);'; // question number is always 0;\r
-               } else if (a[0]=='Chosen') {\r
-                       // Sequitur\r
-                       x = 'if (!(CurrentNumber==TotalSegments||AllDone||Btn.innerHTML==IncorrectIndicator))hpClick(3,Chosen);';\r
-               }\r
-       } else if (window.CheckWord) { \r
-               f = 'CheckWord';\r
-               var a = getFuncArgs(f, true);\r
-               if (a[0]=='InputWord') {\r
-                       // Rhubarb\r
-                       x = 'if(!window.AllDone)hpClick(3,InputWord);';\r
-               }\r
-       } else if (window.CheckText && !window.CheckAnswers) { // Rottmeier Find-It (3a)\r
-               f = 'CheckText';\r
-               var a = getFuncArgs(f, true);\r
-               if ((a[0]=='bool' && a[1]=='item') || (a[0]=='GapState' && a[1]=='GapId')) {\r
-                       x = 'if(!window.Finished&&'+a[0]+')hpClick(3,'+a[1]+');';\r
-               }\r
-       }\r
-       if (f) {\r
-               var s = getFuncCode(f, x, '', true);\r
-               eval('window.' + f + '=new Function(' + getArgsStr(a) + 's);');\r
-       }\r
-       // JMatch has three possible check functions, depending on the version\r
-       // (NB: other quiz types also have these functions)\r
-       var f = new Array('CheckAnswers', 'CheckAnswer', 'CheckResults');\r
-       for (var i=0; i<f.length; i++) {\r
-               if (eval('window.' + f[i])) {\r
-                       var a = getFuncArgs(f[i], true);\r
-                       if (a.length==0) {\r
-                               var s = getFuncCode(f[i], "hpClick(3);", '', true);\r
-                               eval('window.' + f[i] + '=new Function(' + getArgsStr(a) + 's);');\r
-                               break; // out of the loop\r
-                       }\r
-               }\r
-       }\r
-}\r
-// ***************\r
-//  fix IE5 and NS6\r
-// ***************\r
-// add Array.push if required (allows v6 quizzes to run on ie5win)\r
-if (Array.prototype && Array.prototype.push==null) {\r
-       Array.prototype.push = new Function("x", "this[this.length]=x");\r
-}\r
-// add attachEvent function, if required (allows HP5 v6 quizzes to run on ie5mac)\r
-//     NOTE: to allow v6 quizzes on ie5mac, the following code \r
-//     needs to be inserted BEFORE the Hot Potatoes javascript\r
-if (window.attachEvent==null) {\r
-       window.attachEvent = new Function('evt', 'fn', 'eval("window."+evt+"="+fn)');\r
-}\r
-if (document.attachEvent==null) {\r
-       document.attachEvent = new Function('evt', 'fn', 'eval("document."+evt+"="+fn)');\r
-}\r
-// fix the ShowMessage function for NS6\r
-// by removing calls to a button's "focus()" method\r
-if (navigator.userAgent.indexOf("Netscape6")>=0 && window.ShowMessage) {\r
-       var s = ShowMessage.toString();\r
-       var r = new RegExp('document\\.getElementById\\((\'|")FeedbackOKButton(\'|")\\)\\.focus\\(\\);', 'gi');\r
-       s = s.substring(s.indexOf('{')+1, s.lastIndexOf('}')).replace(r, '');\r
-       window.ShowMessage = new Function('Feedback', s);\r
-}\r
-// ns6.0 (in JMix at least) has an error in the FocusAButton function too\r
-// this could be fixed as follows ...\r
-//if (window.FocusAButton) {\r
-//     window.FocusAButton = new Function('return true');\r
-//}\r
-// however, ns6.0 then crashes completely when the mouse moves over a link, so don't bother\r
-// Hot Potatoes quiz sniffing\r
-// === v3 ===\r
-// JBC uses "QuizForm", which contains elements called "Q*_**" (* and ** start at 1)\r
-// JCloze uses "Cloze" form\r
-// JCross uses "Crossword" form\r
-// JMatch uses "QuizForm", which contains elements called "1,2,3..x" and "x+1,x+2...",\r
-//     and "CheckForm" form, which contains an element called "ScoreBox"\r
-//     it is also the only HP quiz type to use an array called "CorrectAnswers"\r
-// JQuiz uses "QForm*" forms (* starts at 1), which each contain an element called "Guess"\r
-// === v4 ===\r
-// JBC uses "QForm" form in "QuestionDiv", which contains elements called "FB* (* starts at 0)"\r
-// JCloze uses "Cloze" form in "QuestionDiv"\r
-// JCross uses "Crossword" form in "CWDiv"\r
-// JMatch uses "ExCheck" form in "TitleDiv"\r
-// (no JMix in hp4)\r
-// JQuiz uses "QForm" form in "QuestionDiv", which contains an element called "Answer"\r
-// === v5 ===\r
-// JBC uses "QForm" form, which contains elements called "FB_*_**" (* and ** start at 0)\r
-// JCloze uses "Cloze" form\r
-// JCross writes out "AnswerForm" from a variable called "GetAnswerOpener"\r
-//     HP5.3: uses "AnswerForm" in "BottomFrame" \r
-//     HP5.5: uses "AnswerForm" in "TopFrame", but it is only there when an answer is being input\r
-// JMatch uses "QForm" form, which contains elements called "sel*" (which disappear by the time the quiz is finished)\r
-// JMix uses "ButtonForm"\r
-// JQuiz uses "QForm*" and "Buttons*" (one for each question)\r
-// === v6 ===\r
-// JBC uses "QForm" form (elements have no name or id)\r
-// JCloze uses "Cloze" form (elements have no name or id)\r
-// JCross does not use any forms, \r
-//     HP5: has "GridDiv" in "MainDiv"\r
-//     HP6: has "Clues" table in "MainDiv"\r
-// JMatch has "MatchDiv" in "MainDiv"\r
-//     HP5: uses "QForm" form, which contains elements called "sel*"\r
-//     HP6: uses "QForm" form, which contains elements called "s*_**"\r
-// JMix does not use any forms, but has "SegmentDiv" in "MainDiv"\r
-// JQuiz \r
-//     HP5: uses "QForm" form, which contains an element called "Guess"\r
-//     HP6: has "Questions" ordered list in "MainDiv"\r
-// === v6+ ===\r
-// JMatch has DIVs called "D*" and  "F*" (* starts at 0)\r
-// JMix has DIVs called "D*" and  "Drop*" (* starts at 0)\r
-// useful sniffing tools (Cut and Paste to browser address box)\r
-//javascript:var s="";var x=new quiz_obj();for(X in x)s+=","+X+"="+x[X];alert(s.substring(1));\r
-//javascript:var s="";var x=document.layers;for(var i=0;i<x.length;i++)s+=","+x[i].name;alert(s.substring(1))\r
-//javascript:var s="";var x=document.forms;for(var i=0;i<x.length;i++)s+=","+x[i].id;alert(s.substring(1))\r
-//javascript:var s="";var x=document.forms;for(var i=0;i<x.length;i++)s+=","+x[i].name;alert(s.substring(1))\r
-//javascript:var s="";var x=document.forms.QForm.elements;for(var i=0;i<x.length;i++)s+=","+x[i].id;alert(s.substring(1))\r
-//javascript:var s="";var x=document.forms.QForm.elements;for(var i=0;i<x.length;i++)s+=","+x[i].name;alert(s.substring(1))\r
-function hpDetectQuiz() {\r
-       // "sniff" (=detect) the quiz's type and intended browser version\r
-       // and cache the values in a global variable called "quiz"\r
-       // Hot Potatoes version\r
-       //      5 : HP5.3 (mac) or HP5.5 (win)\r
-       //      6 : HP6.0 (mac) or HP6.0 (win)\r
-       // intended browser version\r
-       //      3   : ns3, ie3 (frames)\r
-       //      4   : ns4, ie4 (cross browser dhtml)\r
-       //      5   : ie5 (frames, send results via CGI)\r
-       //      6   : ie6, op7, gecko (w3 standards)\r
-       //      6.1 : "drag and drop" versions of JMatch and JMix v6\r
-       // quiz type\r
-       //      0 : unknown\r
-       //      1 : jbc\r
-       //      2 : jcloze\r
-       //      3 : jcross\r
-       //      4 : jmatch\r
-       //      5 : jmix\r
-       //      6 : jquiz\r
-       //      7 : rhubarb (TexToys)\r
-       //      8 : Sequitur (TexToys)\r
-       // rottmeier quiz type\r
-       //      1 : drop-down (JCloze)\r
-       //      2 : find-it (JCloze)\r
-       // shortcut to window object\r
-       var w = window;\r
-       // create the global "quiz" object, if necessary\r
-       if (!w.quiz) w.quiz = new Object();\r
-       // Hot Potatoes version\r
-       //      HP6 v6:    Client()\r
-       //      HP5 v4-v5: BrowserCheck()\r
-       //          v3:    WinStringToMac() [JCloze, JCross, JQuiz]\r
-       //          v3:    winrightchar     [JBC, JMatch]\r
-       //          v3:    DownTime()       [JBC, JCloze, JQuiz]\r
-       if (!quiz.hp) {\r
-               quiz.hp = (w.Client) ? 6 : (w.BrowserCheck) ? 5 : (w.WinStringToMac || w.winrightchar) ? 5 : -1;\r
-       }\r
-       // check the version and type are not already set\r
-       if (!quiz.v || !quiz.t) {\r
-               // initialize version and type\r
-               var v = 0;\r
-               var t = 0;\r
-               // set shortcuts to DOM objects\r
-               var d = document;\r
-               var f = d.forms;\r
-               if (f.QuizForm && f.CheckForm && w.CorrectAnswers) {\r
-                       v = 3;\r
-                       t = 4; // jmatch\r
-               } else if (w.FeedbackFrame && w.CodeFrame) {\r
-                       v = 3;\r
-                       f = CodeFrame.document.forms;\r
-                       t = (f.QuizForm) ? 1 : (f.Cloze) ? 2 : (f.Crossword) ? 3 : (f.QForm1) ? 6 : 0;\r
-               } else if (w.DynLayer) {\r
-                       v = 4;\r
-                       if (d.layers) {\r
-                               // for NS4, adjust "f" to point to a forms object in a layer\r
-                               var lyr = d.QuestionDiv || d.CWDiv || d.TitleDiv || null;\r
-                               if (lyr) f = lyr.document.forms;\r
-                       }\r
-                       t = (f.QForm && f.QForm.FB0) ? 1 : (f.Cloze) ? 2 : (f.Crossword) ? 3 : (f.ExCheck) ? 4 : (f.QForm && f.QForm.Answer) ? 6 : 0;\r
-               } else if (w.TopFrame && w.BottomFrame) {\r
-                       v = 5;\r
-                       f = BottomFrame.document.forms;\r
-                       t = (f.QForm && f.QForm.elements[0].name.substring(0,3)=='FB_') ? 1 : (f.Cloze) ? 2 : (w.GetAnswerOpener && GetAnswerOpener.indexOf('AnswerForm')>=0) ? 3 : (f.QForm && w.RItems) ? 4 : (f.ButtonForm) ? 5 : (f.QForm0 && f.Buttons0) ? 6 : 0;\r
-               } else if (hpObj(d, 'MainDiv')) {\r
-                       v = 6;\r
-                       var obj = (f.QForm) ? f.QForm.elements : null;\r
-                       t = (obj && obj.length>0 && obj[0].id=='') ? 1 : (f.Cloze) ? 2 : (hpObj(d, 'GridDiv') || hpObj(d, 'Clues')) ? 3 : hpObj(d, 'MatchDiv') ? 4 : hpObj(d, 'SegmentDiv') ? 5 : ((f.QForm && f.QForm.Guess) || hpObj(d, 'Questions')) ? 6 : 0;\r
-               } else if (hpObj(d, 'D0')) {\r
-                       v = 6.1; // drag and drop (HP5 and HP6)\r
-                       t = (hpObj(d, 'F0')) ? 4 : (hpObj(d, 'Drop0')) ? 5 : 0;\r
-               } else if (w.Words && f.Rhubarb) {\r
-                       v = 6;\r
-                       t = 7; // rhubarb (TexToys)\r
-               } else if (w.Segments && hpObj(d, 'Story')) {\r
-                       v = 6;\r
-                       t = 8; // sequitur (TexToys)\r
-               }\r
-               quiz.v = v; // intended browser version\r
-               quiz.t = t; // quiz type\r
-       }\r
-}\r
-function hpRottmeier() {\r
-       hpDetectQuiz();\r
-       if (typeof(quiz.r)=='undefined') { // first-time only\r
-               quiz.r = 0;\r
-               if (quiz.t==2) { // JCloze\r
-                       if (quiz.hp==5) { // HP5\r
-                               // ??\r
-                       } else if (quiz.hp==6) { // HP6\r
-                               if (window.Create_StateArray) { // Rottmeier\r
-                                       var obj = new Create_StateArray();\r
-                                       if (typeof(obj.GapLocked)=='boolean') {\r
-                                               quiz.r = 1; // drop-down (v2.4)\r
-                                       } else if (typeof(obj.ErrorFound)=='boolean') {\r
-                                               if (typeof(obj.GapSolved)!='boolean') {\r
-                                                       quiz.r = 2.1; // find-it (v3.1a)\r
-                                               } else {\r
-                                                       quiz.r = 2.2; // find-it (v3.1b)\r
-                                               }\r
-                                       }\r
-                                       obj = null; // prevents memory leakage on some versions of IE\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       return quiz.r;\r
-}\r
-function hpVersion() {\r
-       hpDetectQuiz();\r
-       return quiz.hp;\r
-}\r
-function hpQuizType() {\r
-       hpDetectQuiz();\r
-       return quiz.t;\r
-}\r
-function hpQuizVersion() {\r
-       hpDetectQuiz();\r
-       return quiz.v;\r
-}\r
-function hpScoreEngine(score_i, a, s, aa, ss, count_c, count_i) {\r
-       // calculate the score for the quiz so far\r
-       // score_i : amount by which to increment "score"\r
-       // a  : outer array\r
-       // s  : condition, if any, on outer array (=a)\r
-       //      if true, the score will be incremented by "score_i"\r
-       // aa : inner array, if any\r
-       // ss : condition, if any, on inner array (=aa)\r
-       // count_c : condition, if any, on which "count" is to be incremented\r
-       // count_i : amount by which to increment "count"\r
-       // "a" and "aa" may be passed as arrays or strings containing the name of an array\r
-       // "s" and "ss" are strings containing an expression to be eval(uated)\r
-       // "score_i", "count_i" and "count_c" strings containing an expression to be eval(uated)\r
-       var score = 0;\r
-       var count = 0;\r
-       // set default condition to increment "count", and amount by which to increment the count\r
-       if (count_c==null) count_c = "true";\r
-       if (count_i==null) count_i = "1";\r
-       // set length of outer array. if any\r
-       var l = (typeof(a)=="string") ? eval(a + ".length") : a ? a.length : 0;\r
-       // loop through outer array\r
-       for (var i=0; i<l; i++) {\r
-               if (s==null && ss==null) {\r
-                       score += eval(score_i);\r
-                       if (eval(count_c)) count += eval(count_i);\r
-               } else if (s) {\r
-                       score += eval(s) ? eval(score_i) : 0;\r
-                       if (eval(count_c)) count += eval(count_i);\r
-               } else if (ss) {\r
-                       // set length of inner array, if any\r
-                       var ll = (typeof(aa)=="string") ? eval(aa + ".length") : aa ? aa.length : 0;\r
-                       // loop through inner array. checking inner condition\r
-                       for (var ii=0; ii<ll; ii++) {\r
-                               score += eval(ss) ? eval(score_i) : 0;\r
-                               if (eval(count_c)) count += eval(count_i);\r
-                       }\r
-               }\r
-       }\r
-       if (count) {\r
-               // get p(enalties) for JCross and JMatch (and JMix ?)\r
-               if (window.Penalties) {\r
-                       score -= (Penalties - (hpFinished() ? 0 : 1));\r
-               }\r
-               // adjust count for Find-It 3a and 3b\r
-               if (window.TotWrongChoices) {\r
-                       if (window.CheckText && !window.CheckAnswers) { // Find-It 3a\r
-                               // this seems a little odd, but will replicate behavior of CalculateScore()\r
-                               count = score + TotWrongChoices;\r
-                       } else {\r
-                               count += TotWrongChoices;\r
-                       }\r
-               }\r
-               score = Math.floor(100*score/count);\r
-               if (score<0) { // just in case\r
-                       score = 0;\r
-               }\r
-       }\r
-       return score;\r
-}\r
-function hpScore() {\r
-       var x = ''; // score\r
-       var hp = hpVersion();\r
-       var t = hpQuizType();\r
-       var v = hpQuizVersion();\r
-       if (t==1) { // jbc\r
-               if (v==3) x = hpScoreEngine(1, DoneStatus, "i>0 && a[i]=='0'"); // doesn't work\r
-               else if (v==4) x = hpScoreEngine(1, DoneStatus, "a[i]==0");    // doesn't work\r
-               else if (v==5 || v==6) x = hpScoreEngine("a[i][3]", Status, "a[i][3]");\r
-       } else if (t==2) { // jcloze\r
-               if (v==3 || v==4) x = hpScoreEngine("a[i]", Scores);\r
-               else if (hp==5) x = hpScoreEngine("a[i][3]", State); // v==5 && v==6\r
-               else if (hp==6) {\r
-                       var r = hpRottmeier();\r
-                       if (r==0) x = x = hpScoreEngine("a[i].ItemScore", State);\r
-                       else if (r==1) x = hpScoreEngine("a[i][1].Score", GapList, "a[i][1].GapLocked"); // dropdown\r
-                       else if (r==2.1) x = hpScoreEngine(1, GapList, "a[i][1].ErrorFound"); // Find-It 3a\r
-                       else if (r==2.2) x = hpScoreEngine("a[i][1].Score", GapList, "a[i][1].GapSolved"); // Find-It 3b\r
-               }\r
-       } else if (t==3) { // jcross\r
-               if (v==3) x = hpScoreEngine(1, CorrectAnswers, "document.QuizForm.elements[i*2].selectedIndex==a[i]");\r
-               else if (v==4) x = hpScoreEngine(1, WinLetters, "ConvertCase(GetBoxValue(i),1).charAt(0)==a[i].charAt(0)");\r
-               else if (v==5 || v==6) x = hpScoreEngine(1, L, "", "L[i]", "L[i][ii] && L[i][ii]==G[i][ii]", "L[i][ii]");\r
-       } else if (t==4) { // jmatch\r
-               if (v==3) x = hpScoreEngine(1, CorrectAnswers, "document.QuizForm.elements[i*2].selectedIndex==a[i]");\r
-               else if (v==4) x = hpScoreEngine(1, Draggables, "a[i].correct=='1'");\r
-               else if (v==5) x = hpScoreEngine(1, I, "I[i][2]<1 && I[i][0].length>0 && Status[i][0]==1");\r
-               else if (v==6) x = hpScoreEngine(1, Status, "Status[i][0]==1");\r
-               else if (v==5.1 || v==6.1) x = hpScoreEngine(1, D, "D[i][2]==D[i][1] && D[i][2]>0", "", "", "i<F.length");\r
-       } else if (t==5) { // jmix\r
-               // there was no v3 or v4 of JMix\r
-               if (v==5 || v==6 || v==6.1) x = Math.floor(100*(Segments.length-Penalties)/Segments.length);\r
-       } else if (t==6) { // jquiz\r
-               if (hp==5) {\r
-                       if (v==3 || v==4) x = hpScoreEngine("a[i][4]/10", State, "a[i][0]==1");\r
-                       else if (v==5 || v==6) x = hpScoreEngine("a[i][4]/10", Status, "a[i][0]==1", "", "", "true", "1");\r
-               } else if (hp==6) {\r
-                       if (v==6) x = hpScoreEngine("I[i][0]*a[i][0]", State, "a[i]&&a[i][0]>=0", "", "", "a[i]", "I[i][0]");\r
-               }\r
-       } else if (t==7) { // rhubarb\r
-               if (v==6) {\r
-                       x = Math.floor(100*Correct/TotalWords);\r
-               }\r
-       } else if (t==8) { // sequitur\r
-               if (v==6) {\r
-                       var myTotalPoints = TotalPoints - (hpFinished() ? 0 : (OptionsThisQ-1));\r
-                       x = Math.floor(100*ScoredPoints/myTotalPoints);\r
-               }\r
-       }\r
-       return x; // result\r
-}\r
-function hpFinishedEngine(a, s, aa, ss) {\r
-       // determine whether or not all quistions in a quiz are finished\r
-       // a  : outer array\r
-       // s  : condition, if any, on outer array\r
-       //      if true for any element in "a", the quiz is NOT finished\r
-       // aa : inner array, if any\r
-       // ss : condition, if any, on inner array\r
-       //      if true for any element in "aa", the quiz is NOT finished\r
-       // the arrays "a" and "aa" may be passed as arrays or strings to be eval(uated)\r
-       // the conditions "s" and "ss" are specified as strings to be eval(uated)\r
-       // assume a positive result\r
-       var x = true;\r
-       // set length of outer array. if any\r
-       var l = (typeof(a)=="string") ? eval(a + ".length") : a ? a.length : 0;\r
-       // loop through outer array\r
-       for (var i=0; i<l; i++) {\r
-               // do outer condition, if any\r
-               if (s && eval(s)) x = false;\r
-               // set length of inner array, if any\r
-               var ll = (typeof(aa)=="string") ? eval(aa + ".length") : aa ? aa.length : 0;\r
-               // loop through inner array. checking inner condition\r
-               for (var ii=0; ii<ll; ii++) {\r
-                       if (ss && eval(ss)) x = false;\r
-               }\r
-       }\r
-       return x;\r
-}\r
-function hpTimedOut() {\r
-       // v5 uses "min" and "sec"\r
-       // v6 uses Seconds\r
-       return (typeof(self.Seconds)=='number' && Seconds==0) || (typeof(self.min)=='number' && min==0 && typeof(self.sec)=='number' && sec==0);\r
-}\r
-function hpFinished() {\r
-       // assume false result\r
-       var x = false; \r
-       var hp = hpVersion();\r
-       var t = hpQuizType();\r
-       var v = hpQuizVersion();\r
-       if (t==1) { // jbc\r
-               if (v==3) x = hpFinishedEngine(DoneStatus, "i>0 && a[i]=='0'");\r
-               else if (v==4) x = hpFinishedEngine(DoneStatus, "a[i]==0");\r
-               else if (v==5 || v==6) x = hpFinishedEngine(Status, "a[i][0]==0");\r
-       } else if (t==2) { // jcloze\r
-               var r = hpRottmeier();\r
-               if (r==1) x = hpFinishedEngine(GapList, "a[i][1].GapLocked==false"); // drop-down\r
-               else if (r==2.1) x = hpFinishedEngine(GapList, "a[i][1].ErrorFound==false"); // find-it 3a\r
-               else if (r==2.2) x = hpFinishedEngine(GapList, "a[i][1].GapSolved==false"); // find-it 3b\r
-               else if (v==3 || v==4 || v==5 || v==6) x = hpFinishedEngine(I, "CheckAnswer(i)==-1");\r
-               // also:   else if (v==5 || v==6) x = hpFinishedEngine(State, "a[i][4]!=1")\r
-       } else if (t==3) { // jcross\r
-               if (v==3) x = hpFinishedEngine(document.Crossword.elements, "ConvertCase(is.mac?unescape(MacStringToWin(a[i].value)):a[i].value,1)!=Letters[i]");\r
-               else if (v==4) x = hpFinishedEngine(WinLetters, "ConvertCase(GetBoxValue(i),1).charAt(0) != a[i].charAt(0)");\r
-               else if (v==5 || v==6) x = hpFinishedEngine(L, "", "L[i]", "L[i][ii] && L[i][ii]!=G[i][ii]");\r
-       } else if (t==4) { // jmatch\r
-               if (v==3) x = hpFinishedEngine(CorrectAnswers, "document.QuizForm.elements[i*2].selectedIndex != a[i]");\r
-               else if (v==4) x = hpFinishedEngine(Draggables, "a[i].correct!='1'");\r
-               else if (v==5) x = hpFinishedEngine(I, "I[i][2]<1 && I[i][0].length>0 && Status[i][0]<1 && GetAnswer(i)!=I[i][3]");\r
-               else if (v==6) x = hpFinishedEngine(Status, "Status[i][0]<1");\r
-               else if (v==5.1 || v==6.1) x = hpFinishedEngine(D, "", F, "F[ii][1]==D[i][1]&&D[i][1]!=D[i][2]");\r
-       } else if (t==5) { // jmix\r
-               // there was no v3 or v4 of JMix\r
-               if (v==5 || v==6 || v==6.1) x = !hpFinishedEngine(Answers, "a[i].join(',')=='" + GuessSequence.join(',') + "'");\r
-       } else if (t==6) { // jquiz\r
-               if (v==3 || v==4) x = hpFinishedEngine(State, "a[i][0]==0");\r
-               else if (v==5 || v==6) {\r
-                       if (hp==5) x = hpFinishedEngine(Status, "a[i][0]<1");\r
-                       else if (hp==6) x = hpFinishedEngine(State, "a[i] && a[i][0]<0");\r
-               }\r
-       } else if (t==7) { // rhubarb\r
-               if (v==6) x = hpFinishedEngine(DoneList, "a[i]==1");\r
-       } else if (t==8) { // sequitur\r
-               if (v==6) x = (CurrentNumber==TotalSegments || AllDone);\r
-       }\r
-       return x;\r
-}\r
-function hpObj(d, id) {\r
-       return d.getElementById ? d.getElementById(id) : d.all ? d.all[id] : d[id];\r
-}\r
-function GetViewportHeight() {\r
-       if (window.innerHeight) {\r
-               return innerHeight;\r
-       } else {\r
-               if (hpIsStrict()) {\r
-                       return document.documentElement.clientHeight;\r
-               } else {\r
-                       return document.body.clientHeight;\r
-               }\r
-       }\r
-}\r
-function hpIsStrict() {\r
-       if (!window.hpStrictIsSet) {\r
-               window.hpStrictIsSet = true;\r
-               window.hpStrict = false;\r
-               var s = document.compatMode;\r
-               if (s && s=="CSS1Compat") { // ie6\r
-                       window.hpStrict = true;\r
-               } else {\r
-                       var obj = document.doctype;\r
-                       if (obj) {\r
-                               var s = obj.systemId || obj.name; // n6 || ie5mac\r
-                               if (s && s.indexOf("strict.dtd") >= 0) {\r
-                                       window.hpStrict = true;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       return window.hpStrict;\r
-}\r
-// **************\r
-//  initialization\r
-// **************\r
-hpInterceptFeedback();\r
-hpInterceptHints();\r
-hpInterceptClues();\r
-hpInterceptChecks();\r
-function hpFindForm(formname, w) {\r
-       if (w==null) w = self;\r
-       var f = w.document.forms[formname];\r
-       if (f==null && w.frames) {\r
-               for (var i=0; i<w.frames.length; i++) {\r
-                               f = hpFindForm(formname, w.frames[i]);\r
-                               if (f) break;\r
-               }\r
-       }\r
-       return f;\r
-}\r
-function Finish(quizstatus) {\r
-       var mark = hpScore();\r
-       window.hpForm = hpFindForm('store');\r
-       if (hpForm) { // LMS\r
-               hpForm.starttime.value = getTime(Start_Time);\r
-               hpForm.endtime.value = getTime();\r
-               hpForm.mark.value = mark;\r
-               hpForm.detail.value = '<?xml version="1.0"?><hpjsresult><fields>'+GetQuestionDetails()+'</fields></hpjsresult>';\r
-               if (hpForm.status) {\r
-                       if (!quizstatus) {\r
-                               // 4=completed, 3=abandoned, 2=timed-out or 1=in-progress\r
-                               quizstatus = hpFinished() ? 4 : hpTimedOut() ? 2 : 1;\r
-                       }\r
-                       hpForm.status.value = quizstatus;\r
-               }\r
-               if (!window.hpQuizResultsSent) {\r
-                       if (hpForm.status && quizstatus==4) {\r
-                               window.hpQuizResultsSent = true;\r
-                       }\r
-                       if (quizstatus==4) { // completed\r
-                               // wait 2 seconds for student to see feedback\r
-                               setTimeout("hpForm.submit();", 2000);\r
-                       } else {\r
-                               hpForm.submit();\r
-                       }\r
-               }\r
-       } else if (hpFinished()) {\r
-               SendAllResults(mark);\r
-       }\r
-}\r
-// create form to send results\r
-if (DB[7] && DB[8] && !is_LMS()) { \r
-       ResultForm = ''\r
-               + '<html><body>'\r
-               + '<form name="Results" action="" method="post" enctype="x-www-form-encoded">'\r
-               +       hpHiddenField('recipient', '')\r
-               +       hpHiddenField('subject', '')\r
-               +       hpHiddenField('Exercise', '')\r
-               +       hpHiddenField('realname', '')\r
-               +       hpHiddenField('Score', '')\r
-               +       hpHiddenField('Start_Time', '')\r
-               +       hpHiddenField('End_Time', '')\r
-               +       hpHiddenField('title', 'Thanks!')\r
-               + '</form>'\r
-               + '</body></html>'\r
-       ;\r
-}\r
-// reassign the StartUp function\r
-var p = getPrompt(window.GetUserName || window.StartUp);\r
-var c = getStartUpCode(window.StartUp);\r
-if (p && c) {\r
-       window.StartUp = new Function('QuizLogin("' + p + '")');\r
-       window.StartQuiz = new Function(c);\r
-       // "QuizLogin" finshes by calling "StartQuiz"\r
-}\r
-// reassign the SendResults function\r
-window.SendResults = SendAllResults;\r
-// set start time\r
-var Start_Time = new Date();\r
-//-->\r
+<!--
+// PLEASE NOTE that this version is more recent than the incorrectly 
+// numbered v6.1, dated 2003.11.17. From now on, version numbers will 
+// follow those of Hot Potatoes.
+/* hot-potatoes.js (v6.0.4.0 - 2005.02.18)
+ * =======================================
+ * by Gordon Bateson, February 2003
+ * Copyright (c) 2003 Gordon Bateson. All Rights Reserved.
+ *
+ * You are hereby granted a royalty free license to use or modify this 
+ * software provided that this copyright notice appears on all copies. 
+ *
+ * This software is provided "AS IS" without a warranty of any kind.
+ * 
+ * Documentation and downloads may be available from: 
+ * http://www.kanazawa-gu.ac.jp/~gordon/research/hot-potatoes/
+ */
+// This JavaScript library modifies the SendResults and StartUp functions 
+// used by hotpot v5 and v6, so that more (or less!) details about the
+// student can be input, and more details of a quiz's questions and answers 
+// can be submitted to the server when the quiz is finished
+// If the arrays below (Login, DB, JBC, ...) are set BEFORE calling this 
+// script, they will NOT be overwritten. Any array that is not set, will 
+// use the defaults below. This is useful if you want to use different 
+// settings for different quizzes.
+// ************
+//  Login Screen
+// ************
+if (window.Login==null) {
+       Login = new Array();
+       Login[0] = true;        // Show prompt for user name
+                               // This can also be a string of user names ... 
+                               // Login[0] = "Guest,Peter,Paul,Mary,Webmaster";
+                               // or an array of user names (and on-screen texts) (and passwords) ...
+                               // Login[0] = new Array("Guest", "001,Peter,xxxx", "002,Paul,yyyy", "003,Mary,zzzz", "Webmaster");
+                               // and can also be  written as ...
+                               // Login[0] = new Array(
+                               //      new Array("Guest"),
+                               //      new Array("001", "Peter", "xxxx"),
+                               //      new Array("002", "Paul", "yyyy"),
+                               //      new Array("003", "Mary", "zzzz"),
+                               //      new Array("Webmaster")
+                               // );
+       Login[1] = true;        // Show prompt for student's UserID
+                               // If there is no password prompt (i.e. Logon[3] is false), this value 
+                               // will be checked against the password information, if any, in Login[0]
+       Login[2] = false;       // Show prompt for student's email
+       Login[3] = false;       // Show prompt for quiz password, and check this value against 
+                               // the password information, if any, in Login[0]
+                               // This can also be a string required to start the quiz ...
+                               // Login[3] = "password";
+       Login[4] = true;        // Show prompt for the cookie expiry date
+                               // If false, cookies expire at the end of the current session
+       Login[5] = "guest,webmaster"
+                               // guest user names (case insensitive) ...  
+                               // Login[5] = "guest,webmaster"; 
+                               // These users do NOT need to fill in other login fields
+                               // and their quiz results are NOT added to the database
+       // the Login prompts and error messages 
+       // are defined in the MSG array (see below)
+}
+// *********
+//  Database (for use with BFormMail)
+// *********
+if (window.DB==null) {
+       DB = new Array();
+       DB[0] = true; // append form fields to database on server
+                       // If you are NOT using BFormMail's database feature, 
+                       // set DB[0]=false, and you can then safely ignore DB[1 to 5]
+       DB[1] = "/home/gordon/public_html/cgi/hot-potatoes-data"; 
+                       // append_db folder path (no trailing slash)
+                       // Can be either an absolute path  e.g. "/home/gordon/public_html/cgi/hot-potatoes-data"
+                       // or a relative (to CGI bin) path  e.g. "hot-potatoes-data"
+       DB[2] = "hot-potatoes"; 
+                       // append_db file name (no extension)
+                       // If left blank, the quiz file name, without extension, will be used
+                       // i.e. each quiz will have its results stored in a different file.
+                       // If filled in, this file will store the results for ALL quizzes.
+                       // Database files and folders must be set up BEFORE running the quiz 
+                       // must have appropriate access privileges (on Unix, use "chmod 666").
+       DB[3] = ""; // append_db extension (if left blank, ".txt" will be used)
+       DB[4] = ""; // db_fields (if left blank, ALL quiz fields will be sent)
+       DB[5] = ""; // db_delimiter (if left blank, tab will be used)
+       DB[6] = "REMOTE_ADDR,HTTP_USER_AGENT"; 
+                       // env_report ('REMOTE_ADDR','HTTP_USER_AGENT' and a few others)
+       // for a complete description of these fields are, see ... 
+       // http://www.infosheet.com/stuff/BFormMail.readme
+       // Switches DB[7] and DB[8] force the settings in the ResultForm
+       // In v5 and v6 quizzes, these settings wil be override those in the original quiz
+       // If the quiz results are to be sent to an LMS (via the "store" form)
+       // then switches DB[7] and DB[8] are not used
+       DB[7] = '';     // URL of form processing script
+                       // e.g. http://www.kanazawa-gu.ac.jp/~gordon/cgi/bformmail.cgi
+       DB[8] = '';     // email address to which results should be sent
+                       // e.g. gordon@kanazawa-gu.ac.jp
+}
+// By default the quiz's question's scores will be returned. 
+// If you want more detailed information, set the flags below:
+// ********
+//  JBC
+// ********
+if (window.JBC==null) {
+       JBC = new Array();
+       JBC[0] = true;  // show separator line between answers on email
+       JBC[1] = true;  // show number of attempts to answer question
+       JBC[2] = true;  // show question texts
+       JBC[3] = true;  // show right answer(s)
+       JBC[4] = true;  // show wrong answer(s)
+       JBC[5] = true;  // show ignored answer(s)
+       JBC[6] = false; // show answer as text (false) or number (true)
+}
+// JBC quizzes use the global variables 'I' and 'Status'
+// I : an array of JBC_QUESTIONs (one for each question)
+// JBC_QUESTION :
+//     [0] : question text
+//     [1] : array of JBC_ANSWERs (one for each answer)
+//     [2] : single/multi flag
+//             0 : single answer (using 'button')
+//             1 : multiple answers (using 'checkbox')
+// JBC_ANSWER :
+//     [0] : answer text
+//     [1] : answer feedback
+//     [2] : correct answer flag
+//             0 : this is NOT the correct answer
+//             1 : this is the correct answer
+// Status : an array of JBC_QUESTION_STATUSes
+// JBC_QUESTION_STATUS:
+//     [0] : correctly answered yet flag
+//             0 : this question has NOT been correctly answered
+//             1 : this question has been correctly answered
+//     [1] : array of JBC_ANSWER_STATUSes (one for each answer)
+//             '0' : initial value
+//             'R' : single answer question was answered 'R'ight
+//             'W' : single answer question was answered 'W'rong
+//             'C' : multiple answer question's checkbox was 'C'hecked
+//             'U' : multiple answer question's checkbox was 'U'nchecked
+//     [2] : number of times this question has been wrongly answered
+//     [3] : score (out of 1) for this question (maybe undefined on HP<5.5)
+//             0 : not correct yet
+//             0<[3]<1 : correct but only after [2] wrong attempts
+//             1 : correct first time (bravo!)
+//     N.B. score = (numberOfAnswers - numberofWrongTries) / numberOfAnswers
+// ********
+//  JCloze
+// ********
+if (window.JCloze==null) {
+       JCloze = new Array();
+       JCloze[0] = true;       // show separator line between answers on email
+       JCloze[1] = true;       // show student's correct answer
+       JCloze[2] = true;       // show other correct answer(s), if any
+       JCloze[3] = true;       // show wrong answer(s), if any (NOT available for v5)
+       JCloze[4] = false;      // show number of hints + checks (legacy field, replaced by [7]+[9])
+       JCloze[5] = false;      // show if clue was asked for or not (legacy field, replaced by [8])
+       JCloze[6] = true;       // show clue
+       JCloze[7] = true;       // show number of hints (=next letter requests)
+       JCloze[8] = true;       // show number of clues
+       JCloze[9] = true;       // show number of checks
+}
+// JCloze quizzes use the global variables 'I' and 'State'
+// I : array of JCLOZE_ANSWERs
+// JCLOZE_ANSWER :
+//     [0] : (unused)
+//     [1] : array of JCLOZE_ANSWER_TEXTs
+//     [2] : clue for this answer
+// JCLOZE_ANSWER_TEXT : 
+//     [0] : array (seems unnecessary, just the text would be enough?)
+//             [0] : text of possible answer
+// State : array of JCLOZE_ANSWER_STATEs
+// JCLOZE_ANSWER_STATE (v5) : 
+//     [0] : clue asked for or not
+//     [1] : number of hints (show next letter) and penalties ('check' an incorrect answer)
+//     [2] : length of answer matched
+//     [3] : score for this item
+//     [4] : already answered correctly 
+//     [5] : answer entered in text box (right or not)
+// JCLOZE_ANSWER_STATE (v6)
+//     this.ClueGiven = false;
+//     this.HintsAndChecks = 0;
+//     this.MatchedAnswerLength = 0;
+//     this.ItemScore = 0;
+//     this.AnsweredCorrectly = false;
+//     this.Guesses = new Array(); last guess is correct answer
+// ********
+//  JCross
+// ********
+if (window.JCross==null) {
+       JCross = new Array();
+       JCross[0] = true;       // show separator line between answers on email
+       JCross[1] = true;       // show number of penalties (hints or checks before complete)
+       JCross[2] = true;       // show number of letters
+       JCross[3] = true;       // show correct answers
+       JCross[4] = true;       // show clues
+       JCross[5] = true;       // show wrong answers
+       JCross[6] = true;       // show if clue was asked for or not
+       JCross[7] = true;       // show number of hints (=next letter requests)
+       JCross[8] = true;       // show number of checks
+       // there are no "ignored" answers for JCross quizzes
+}
+// JCross quizzes use the following global variables: 
+//     L : letters (of correct answers)
+//     C : clue numbers (CL in v6)
+//     G : guesses
+// 'L', 'C' ('CL') and 'G' are all 2-dimensional arrays (rows x cols)
+//
+// v5 quizzes additionally use the following single-dimension arrays
+//     A : clues for across (horizontal) words 
+//     D : clues for down (vertical) words 
+// N.B. form is only sent when all answers are correct so 
+// you can't find out what 'wrong' answers were entered
+// ********
+//  JMatch
+// ********
+if (window.JMatch==null) {
+       JMatch = new Array();
+       JMatch[0] = true;       // show separator line between answers on email
+       JMatch[1] = false;      // show number of penalties (= total number of checks)
+       JMatch[2] = true;       // show LHS texts (the question)
+       JMatch[3] = true;       // show correct answers
+       JMatch[4] = true;       // show wrong answers
+       JMatch[5] = true;       // show checks (per match) [empty or unchanged RHS are not counted]
+       // JMatch has no "clue" or "hint" buttons
+       // there cannot be any "ignored" answers
+}
+// v5 JMatch quizzes use the global variables 'I' and 'Status' (and 'RItems')
+// v6 JMatch quizzes use only 'Status'
+// v6+ JMatch quizzes use 'F' and 'D' (see below)
+// I : an array of JMATCH_PAIRs (one for each pair)
+// JMATCH_PAIR :
+//     [0] : LHS text
+//     [1] : RHS text
+//     [2] : fixed (=not jumbled) flag
+//             0 : not fixed
+//             1 : fixed
+//     [3] : index in drop down list selection
+// Status : an array of JMATCH_PAIR_STATUSes
+// JMATCH_PAIR_STATUS:
+//     [0] : correctly matched yet flag
+//             0 : this pair has NOT been correctly matched
+//             1 : this pair has been correctly matched
+//     [1] : number of times this item has been wrongly matched
+//     v6 quizzes only
+//     [2] : id of original SELECT element containing possible matches
+//     Note that after matching, this SELECT is removed, so don't try looking for it :-)
+// v6+ JMatch quizzes use the global variables 'F' and 'D'
+// F : array of JMATCH_FIXED_ITEMs
+// JMATCH_FIXED_ITEM:
+//     [0] : text
+//     [1] : tag
+// D : array of JMATCH_DRAGGABLE_ITEMs
+// JMATCH_DRAGGABLE_ITEM
+//     [0] : text
+//     [1] : tag of the F item to which it SHOULD be dragged
+//     [2] : tag of the F item to which it was dragged (initally 0)
+// N.B. form is only sent when all answers are correct so 
+// you can't find out what 'wrong' answers were entered
+// ********
+//  JMix
+// ********
+if (window.JMix==null) {
+       JMix = new Array();
+       JMix[0] = true;         // show separator line between answers on email
+       JMix[1] = false;        // show number of wrong guesses (replaced by JMix[5])
+       JMix[2] = true;         // show right answer
+       JMix[3] = true;         // show wrong answer, if any
+       JMix[4] = false;        // show answer as text (false) or number (true)
+       JMix[5] = true;         // show number of checks
+       JMix[6] = true;         // show number of hints (=show next word)
+}
+// JMix quizzes use the global variables 
+// 'Segments', 'GuessSequence' and 'Penalties' 
+// Segments : array of JMix_QUESTIONs
+// JMix_QUESTION:
+//     [0] : text
+//     [1] : order in sequence
+//     [2] : used flag
+// GuessSequence : array of 'order in sequence' numbers
+// Penalties : number of incorrect guesses
+// ********
+//  JQuiz
+// ********
+if (window.JQuiz==null) {
+       JQuiz = new Array();
+       JQuiz[0] = true;        // show separator line between answers on email
+       JQuiz[1] = true;        // show question text
+       JQuiz[2] = true;        // show student's correct answer(s)
+       JQuiz[3] = false;       // show wrong and ignored answer(s) (legacy field superceded by [8] & [9])
+       JQuiz[4] = true;        // show number of hints requested
+       JQuiz[5] = false;       // show number of checks of incorrect answers (legacy field superceded by [12])
+       // HP6 v6 quizzes only
+       JQuiz[6] = false;       // show answer value (false) or A,B,C... index (true)
+       JQuiz[7] = true;        // show all students answers
+       JQuiz[8] = true;        // show student's wrong answers
+       JQuiz[9] = true;        // show ignored answers (not relevant for multi-select questions)
+       JQuiz[10] = true;       // show score weightings
+       JQuiz[11] = true;       // show question type
+       JQuiz[12] = true;       // show number of checks (if true, then JQuiz[5] of will be ignored)
+       JQuiz[13] = true;       // show number of times ShowAnswer button was pressed (usually 0 or 1)
+}
+// v5 JQuiz quizzes use the global variables 'I' and 'Status'
+// I : array of JQUIZ_ANSWERs
+// JQUIZ_ANSWER :
+//     [0] : question text
+//     [1] : array of JQUIZ_ANSWER_TEXTs (one for each answer)
+// JQUIZ_ANSWER_TEXT :
+//     [0] : array (seems unnecessary, just the text would be enough?)
+//             [0] : text of possible answer
+// Status : array of JQUIZ_ANSWER_STATEs
+// JQUIZ_ANSWER_STATE : 
+//     [0] : question done or not
+//     [1] : number of wrong checks
+//     [2] : number of hints asked for
+//     [3] : student's answer
+//     [4] : score for this question
+// v6 JQuiz quizzes use the global variables 'I' and 'State'
+// I : array of JQUIZ_QUESTIONs
+// JQUIZ_QUESTION :
+//     [0] : weighting
+//     [1] : ?? (always set to '')
+//     [2] : question type
+//             '0'=multiple-choice, '1'=short-answer, '2'=hybrid, '3'=multi-select
+//     [3] : array of JQUIZ_ANSWERSs (one for each possible answer)
+// JQUIZ_ANSWER :
+//     [0] : answer value
+//     [1] : feedback text
+//     [2] : correct answer flag (1=a correct answer, 0=a wrong answer)
+//     [3] : weighted score (as percentage) if correct
+//     [4] : flag (usually set to 1, but for hybrid answers that are not 
+//             to be included in multiple choice options, it is set to 0)
+// State : array of JQUIZ_QUESTION_STATEs
+// JQUIZ_QUESTION_STATE : 
+//     [0] : score (-1 shows not done yet)
+//     [1] : array showing on which number try each JQUIZ_ANSWER was selected
+//     [2] : number of attempts at this question
+//     [3] : total of weighted scores of correct answers that were selected
+//             i.e. each time a correct answer is selected, 
+//             its JQUIZ_ANSWER[3] weighting is added to this total
+//             so when all the correct answers have been selected, this will be 100
+//     [4] : penalties incurred for hints (score is set to zero if >= 1)
+//     [5] :   - for multiple choice, short-answer and hybrid questions, this is a
+//             comma-delimited list showing order in which answers were chosen
+//             - for multi-select fields, this is bar-delimted ('|') list of settings 
+//             showing whether each checkbox was selected ('Y') on not ('N') when the 
+//             'Check' button was clicked. The final item in the list will be the 
+//             settings for the correct answer.
+// N.B. JBC, JMatch(v5) and JQuiz(v5) all use global variables 'I' and 'Status'
+//     JBC : I[0].length==3 && !window.RItems
+//     JQuiz(v5) : I[0].length==2
+//     JMatch(v5) : I[0].length==4 && window.RItems
+// N.B. JCloze(v5+6) and JQuiz(v6) both use global variables 'I' and 'State'
+//     JCloze (v5) : I[0].length==3 && State[0].Guesses==null
+//     JCloze (v6) : I[0].length==3 && State[0].Guesses!=null
+//     JQuiz  (v6) : I[0].length==4
+// **********
+//  Rhubarb
+// **********
+if (window.Rhubarb==null) {
+       Rhubarb = new Array();
+       Rhubarb[0] = true;  // show correct words (so far)
+       Rhubarb[1] = true;  // show correct words as count (true) or list (false)
+       Rhubarb[2] = true;  // show wrong words
+       Rhubarb[3] = false; // show wrong words as count (true) or list (false)
+       Rhubarb[4] = false; // show ignored words (not implemented yet)
+       Rhubarb[5] = true;  // show hints
+}
+// **********
+//  Sequitur
+// **********
+if (window.Sequitur==null) {
+       Sequitur = new Array();
+       Sequitur[0] = true;  // show count of correct button clicks
+       Sequitur[1] = true;  // show count of wrong button clicks
+}
+// **********
+//  Messages
+// **********
+if (window.MSG==null) {
+       MSG = new Array();
+       // Login prompts
+       MSG[0] = 'Name';
+       MSG[1] = 'ID';
+       MSG[2] = 'Email';
+       MSG[3] = 'Password';
+       MSG[4] = 'Cookies';
+       // Login buttons
+       MSG[5] = 'Start the Quiz';
+       MSG[6] = 'Cancel';
+       // Cookie menu options (only used if Login[4] is true)
+       MSG[7] = 'keep for this session only';
+       MSG[8] = 'keep for one day';
+       MSG[9] = 'keep for one month';
+       MSG[10] = 'do NOT keep cookies';
+       // Login error messages
+       MSG[11] = 'Sorry, you were unable to login. Please try again later.';
+       MSG[12] = 'Please fill in all the information.';
+       MSG[13] = 'Incorrect Password. Please try again.';
+       MSG[14] = 'Incorrect ID. Please try again.';
+       MSG[15] = 'Email address does not appear to be valid.';
+       // day and month names (used in Start_Time and End_Time)
+       MSG[16] = new Array('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
+       MSG[17] = new Array('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
+       // enable popups
+       MSG[18] = 'Please enable pop-up windows on your browser.';
+       // browser specific instuctions on how to enable popup windows
+       var n = navigator;
+       var s = n.userAgent.toLowerCase();
+       if (n.appName=='Netscape' && s.indexOf('gecko')>=0) {
+               // Netscape 6 and 7
+               MSG[18] += '\n\n' + 'Edit->Preferences, ' + (s.indexOf('mac')>=0 ? 'Advanced->Scripts & Plugins' : 'Privacy & Security->Popup Window Controls');
+       } else if (s.indexOf('safari')>=0) {
+               // Safari
+               MSG[18] += '\n\n' + 'on Safari menu, uncheck "Block Pop-Up Windows"';
+       } else if (s.indexOf('firebird')>=0) {
+               // Firebird
+               MSG[18] += '\n\n' + 'Preferences->Web Features, uncheck "Block Pop-Up Windows"';
+       } else if (s.indexOf('msie 6')>=0) {
+               // IE 6 (WinXP.SP2)
+               MSG[18] += '\n\n' + 'Tools->Pop-up Blocker->Turn Off Pop-up Blocker';
+       }
+}
+//if (window.FEEDBACK==null) {
+//     FEEDBACK = new Array();
+//     FEEDBACK[0] = ''; // url of feedback page/script
+//     FEEDBACK[1] = ''; // array of array('teachername', 'value');
+//     FEEDBACK[2] = ''; // 'student name' [formmail only]
+//     FEEDBACK[3] = ''; // 'email@somewhere.com>' [formmail only]
+//     FEEDBACK[4] = ''; // window width
+//     FEEDBACK[5] = ''; // window height
+//     FEEDBACK[6] = ''; // 'Send a message to teacher' [prompt/button text]
+//     FEEDBACK[7] = ''; // 'Title'
+//     FEEDBACK[8] = ''; // 'Teacher'
+//     FEEDBACK[8] = ''; // 'Message'
+//     FEEDBACK[10] = ''; // 'Close this window' [formmail only]
+//}
+// **********
+//  HP array
+// **********
+HP = new Array();
+for (var i=0; i<=8; i++) {
+       HP[i] = new Array();
+}
+// indexes for the HP array (makes the code further down easier to read)
+_score   = 0;
+_weight  = 1;
+_correct = 2;
+_wrong   = 3;
+_unused  = 4;
+_hints   = 5;
+_clues   = 6;
+_checks  = 7;
+_guesses = 8;
+// *************
+//  Server Fields
+// *************
+if (window.ServerFields==null) {
+       ServerFields = new Array();
+       // these fields will be added to the ResultForm and submitted to the CGI script on the server.
+       // 'Sort', 'return_link_title', 'return_link_url' and 'print_blank_fields' are useful for formmail
+       // override the HP setting of sort fields (forces ALL fields to be displayed)
+       ServerFields[0] = new Array('sort', '');
+       // add link to close pop-up results window
+       ServerFields[1] = new Array('return_link_title', 'Close this window');
+       ServerFields[2] = new Array('return_link_url', 'javascript:self.close()');
+       // make sure zero values are printed
+       ServerFields[3] = new Array('print_blank_fields', 'yes');
+       // you can also set other fields for your customized CGI script
+       // e.g. adding a server defined start time (instead of a client defined start time)
+       // ServerFields[4] = new Array('serverStartTime', '<?php echo date("Y-m-d H:i:s") ?>');
+}
+// *********************
+//      Login screen
+//  (not required by LMS)
+// *********************
+function QuizLogin(LoginPrompt) {
+       if (!is_LMS() && (Login[0] || Login[1] || Login[2] || Login[3])) {
+               var html = ''
+                       + '<html>'
+                       + '<head></head>'
+                       + '<body bgColor="#cccccc" onLoad="opener.setFocus(self)">'
+                       + '<form onSubmit="'
+                       +       'self.ok=true;'
+                       +       'self.expiry=null;'
+               ;
+               if (Login[4]) { // cookie expiry
+                       html += "opener.checkOK(self,'CookieExpiry');";
+               }
+               if (Login[0]) { // user name
+                       html += "opener.checkOK(self,'UserName');";
+               }
+               if (Login[1]) { // user ID
+                       html += "opener.checkOK(self,'UserID');";
+               }
+               if (Login[2]) { // user email
+                       html += "opener.checkOK(self,'UserEmail');";
+               }
+               if (Login[3]) { // quiz password
+                       html += "opener.checkOK(self,'Password');";
+               }
+               html +=          'if(ok){'
+                       +               'opener.StartQuiz();'
+                       +               'self.close();'
+                       +         '}else{'
+                       +               'if(isNaN(self.tries))self.tries=0;'
+                       +               'self.tries++;'
+                       +               'if(self.tries<3){'
+                       +                       'opener.setFocus(self);'
+                       +               '}else{'
+                       +                       "alert(opener.MSG[11]);"
+                       +                       'opener.goBack();'
+                       +                       'self.close();'
+                       +               '}'
+                       +         '}'
+                       +         'return false;'
+                       + '">'
+               ;
+               html += '<table>'
+                       +       '<caption>' + LoginPrompt + '</caption>';
+               ;
+               if (Login[0]) { // user name
+                       var v = getCookie(self, 'UserName');
+                       html += '<tr>'
+                               +       '<th align=right nowrap>' + MSG[0] + ' :</th>'
+                               +       '<td>'
+                       ;
+                       if (typeof(Login[0])=='boolean') { // text box
+                               html += '<input type=text name=UserName value="' + v + '">';
+                       } else { // drop down menu of names
+                               // pattern to match commas and white space
+                               var comma = (window.RegExp) ? new RegExp('\\s*,\\s*') : ',';
+                               // convert list of names to array, if necessary
+                               if (typeof(Login[0])=='string') {
+                                       Login[0] = Login[0].split(comma);
+                               }
+                               html += '<select name=UserName size=1>'
+                                       + '<option value=""></option>'
+                               ;
+                               for(var i=0; i<Login[0].length; i++) {
+                                       // convert name details to array if nececount_cary
+                                       if (typeof(Login[0][i])=='string') {
+                                               Login[0][i] = Login[0][i].split(comma);
+                                       }
+                                       html += makeOption(Login[0][i][0], v, Login[0][i][1]);
+                               }
+                               html += '</select>';
+                       }
+                       html +=         '</td>'
+                               + '</tr>'
+                       ;
+               }
+               if (Login[1]) { // user ID
+                       var v = getCookie(self, 'UserID');
+                       html += '<tr><th align=right nowrap>' + MSG[1] + ' :</th><td><input type=text name=UserID value="' + v + '"></td></tr>';
+               }
+               if (Login[2]) { // user email
+                       var v = getCookie(self, 'UserEmail');
+                       html += '<tr><th align=right nowrap>' + MSG[2] +' :</th><td><input type=text name=UserEmail value="' + v + '"></td></tr>';
+               }
+               if (Login[3]) { // quiz password
+                       var v = getCookie(self, 'Password');
+                       html += '<tr><th align=right nowrap>' + MSG[3] + ' :</th><td><input type=password name=Password value="' + v + '"></td></tr>';
+               }
+               if (Login[4]) { // cookie lifespan
+                       var v = getCookie(self, 'CookieExpiry');
+                       html += '<tr>'
+                               +       '<th align=right nowrap>' + MSG[4] + ' :</th>'
+                               +       '<td>'
+                               +               '<select name="CookieExpiry" size=1>'
+                               +                       makeOption('session', v, MSG[7])
+                               +                       makeOption('day', v, MSG[8])
+                               +                       makeOption('month', v, MSG[9])
+                               +                       makeOption('never', v, MSG[10])
+                               +               '</select>'
+                               +       '</td>'
+                               + '</tr>'
+                       ;
+               }
+               html +=         '<tr>'
+                       +               '<th>&nbsp;</th>'
+                       +               '<td nowrap>'
+                       +                       '<input type=submit value="' + MSG[5] + '"> '
+                       +                       '<input type=button value="' + MSG[6] + '" onClick="opener.goBack();self.close();">'
+                       +               '</td>'
+                       +       '</tr>'
+                       + '</table></form></body></html>'
+               ;
+               // set height of Login Window
+               var m = navigator.userAgent.indexOf('Mac')>=0;
+               var h = (m ? 80 : 100);
+               for (var i=0; i<5; i++) h += (Login[i] ? (m ? 20 : 25) : 0);
+               // open up a new window
+               if (!openWindow('', '', (m ? 320 : 300), h, 'RESIZABLE', html)) {
+                       alert(MSG[18]); // unable to open popup window
+               }
+       } else { // no Login required
+               window.UserName = window.UserID = window.UserEmail = window.Password = '';
+               window.StartQuiz();
+       }
+       return true;
+}
+function makeOption(value, v, txt) {
+       return '<option value="' + value + '"' + (value==v ? ' SELECTED' : '') + '>' + (txt ? txt : value) + '</option>';
+}
+function setFocus(w) {
+       w.focus(); // bring window to the front
+       var obj = w.document.forms[0].elements;
+       for(var i=0; i<obj.length; i++) {
+               var v = getValue(w, i);
+               if (v=='' || obj[i].type=='submit') {
+                       obj[i].focus();
+                       break;
+               }
+       }
+}
+function checkOK(w, n){
+       var v = getValue(w, n, true);
+       if (v || (n!='UserName' && isGuest())) {
+               if (n=='CookieExpiry') setCookieExpiry(w, v);
+               setCookie(self, n, v, w.expiry);
+               if (n!='CookieExpiry') eval('self.' + n + '=v');
+       } else {
+               if (w.ok) alert(MSG[12]);
+               w.ok = false;
+       }
+}
+function getValue(w, n, flag) {
+       var obj = w.document.forms[0].elements[n];
+       var TYPE = obj.type.toUpperCase(); // required for ns4 (win)
+       if (obj.options && TYPE.indexOf('SELECT')>=0){ 
+               var v = obj.options[obj.selectedIndex].value;
+       } else {
+               var v = obj.value;
+       }
+       if (flag) {
+               var msg = '';
+               if (n=='Password' || (n=='UserID' && !Login[3])) {
+                       var pwd = getPassword(w);
+                       if (pwd && v!=pwd) msg = MSG[n=='Password' ? 13 : 14];
+               } 
+               if (n=='UserEmail' && window.RegExp) {
+                       var r = '(\\w|-)+';
+                       r = r + '(\\.' + r + ')';
+                       r = new RegExp('^(' + r + '*)@(' + r + '+)$');
+                       if (v.match(r)==null) msg = MSG[15];
+               }
+               if (msg) {
+                       obj.value = v = '';
+                       if (w.ok) alert(msg);
+                       w.ok = false;
+               }
+       }
+       return v;
+}
+function getPassword(w) {
+       var pwd = '';
+       if (Login[3] && typeof(Login[3])=='string') {
+               pwd = Login[3];
+       } else if ((Login[3] || Login[1]) && typeof(Login[0])=='object') {
+               var username = getValue(w, 'UserName');
+               for(var i=0; i<Login[0].length; i++) {
+                       if (username==Login[0][i][0]) {
+                               pwd = Login[0][i][2];
+                               break;
+                       }
+               }
+       }
+       return pwd;
+}
+function setCookieExpiry(w, v) {
+       if (v=='never'){
+               w.expiry = new Date('Thu, 01-Jan-70 00:00:01 GMT');
+       } else if (v=='day' || v=='month') {
+               var ms = (v=='month' ? 31 : 1) * 60 * 60 * 24 * 1000;
+               w.expiry = new Date((new Date()).getTime() + ms);
+       }
+}
+function setCookie(w, name, value, expires, path, domain, secure) {
+       if (name) w.document.cookie = ''
+               + 'HP_' + name + "=" + escape(value)
+               + (expires ? "; expires=" + expires.toGMTString() : "")
+               + (path ? "; path=" + path : "")
+               + (domain ? "; domain=" + domain : "")
+               + (secure ? "; secure" : "")
+       ;
+}
+function getCookie(w, n) {
+       var c = w.document.cookie;
+       var i = c.indexOf('HP_' + n + '=');
+       var j = (i<0) ? -1 : c.indexOf(';', (i += n.length + 4));
+       return (i<0) ? '' : unescape(c.substring(i, ((j<0) ? c.length : j)));
+}
+function goBack(w) {
+       if (w==null) w = self; // default
+       if (w.history.length) w.history.back();
+}
+function openWindow(url, name, width, height, attributes, html) {
+       // set height, width and attributes
+       if (window.screen && width && height) {
+               var W = screen.availWidth;
+               var H = screen.availHeight;
+               width = Math.min(width, W);
+               height = Math.min(height, H);
+               attributes = ''
+                       + (attributes ? (attributes+',') : '')
+                       + 'WIDTH='+width+',HEIGHT='+height
+               ;
+       }
+       // create global hpWindows object, if necessary
+       if (!window.hpWindows) window.hpWindows = new Array();
+       // initialize window object
+       var w = null;
+       // has a window with this name been opened before?
+       if (name && hpWindows[name]) {
+               // http://www.webreference.com/js/tutorial1/exist.html
+               if (hpWindows[name].open && !hpWindows[name].closed) {
+                       w = hpWindows[name];
+                       w.focus();
+               } else {
+                       hpWindows[name] = null;
+               }
+       }
+       // check window is not already open
+       if (w==null) {
+               // workaround for "Access is denied" errors in IE when offline
+               // based on an idea seen at http://www.devshed.com/Client_Side/JavaScript/Mini_FAQ
+               var ie_offline = (document.all && location.protocol=='file:');
+               // try and open the new window
+               w = window.open((ie_offline ? '' : url), name, attributes);
+               // check window opened OK (user may have prevented popups)
+               if (w) {
+                       // center the window
+                       if (window.screen && width && height) {
+                               w.moveTo((W-width)/2, (H-height)/2);
+                       }
+                       // add content, if required
+                       if (html) {
+                               with (w.document) {
+                                       clear();
+                                       open();
+                                       write(html);
+                                       close();
+                               }
+                       } else if (url && ie_offline) {
+                               w.location = url;
+                       }
+                       if (name) hpWindows[name] = w;
+               }
+       }
+       return w;
+}
+// *********************
+//  Send results by email
+//  (not required by LMS)
+// *********************
+function SendAllResults(Score) {
+       // check this quiz is not generated by a LMS
+       if (!is_LMS()) {
+               // add flat file database details to the results form
+               AddDatabaseDetailsToResultForm();
+               // add student details to the results form
+               AddStudentDetailsToResultForm();
+               // add question details to the results form
+               AddQuestionDetailsToResultForm();
+               // add server fields, if any, to results form
+               AddServerFieldsToResultForm();
+               // change "method" of form, because "get" only allows 512 byts of data
+               ResultForm = replaceLast('method="get"', 'method="post"', ResultForm);
+               // create results window and form
+               var w = openWindow('', '', 500, 400, 'RESIZABLE,SCROLLBARS,LOCATION', ResultForm);
+               // check window opened OK (user may have prevented popups)
+               if (w) {
+                       // get shortcut to form object
+                       var form = w.document.forms[0];
+                       // update some important field values
+                       form.Score.value = Score + '%';
+                       form.realname.value = UserName;
+                       form.Start_Time.value = getTime(Start_Time);
+                       form.End_Time.value = getTime();
+                       // force email subject and Exercise title
+                       form.subject.value = document.title;
+                       form. Exercise.value = document.title;
+                       // update DB fields, if required
+                       if (DB[0] && !isGuest()) set_db_fields(form);
+                       if (DB[7]) form.action = DB[7];
+                       if (DB[8]) form.recipient.value = DB[8];
+                       // if this is a Netscape browser, check if the referer will be set OK
+                       if (navigator.appName=='Netscape' && (location.protocol=='file:' || navigator.userAgent.indexOf('Netscape6')>=0)) {
+                               // ns4 and ns7 set referer to 'file:// ...' when running a quiz offline
+                               // ns6.2 (at least) always sets referer to 'about:blank' 
+                               // Netscape's setting of referer can cause BFormMail
+                               // to reject the form, so encode the form data as a URL
+                               var url = form.action;
+                               var obj = form.elements;
+                               for (var i=0; i<obj.length; i++) {
+                                       var  v = escape(obj[i].value);
+                                       v = v.replace((new RegExp('\\+', 'g')), '%2B');
+                                       url += (i==0 ? '?' : '&') + obj[i].name + '=' + v;
+                               }
+                               w.location.href = url;
+                       } else { // browser can POST form ok
+                               form.submit();
+                       }
+               } else { // unable to open popup window
+                       alert(MSG[18]);
+               }
+       } // end if LMS
+}
+function isGuest() {
+       // check username is not a "guest" user
+       var flag = false;
+       var n = getCookie(self, 'UserName').toLowerCase();
+       if (n) {
+               // convert list of user names to array, if necessary
+               if(typeof(Login[5])=='string') {
+                       Login[5] = Login[5].split(',');
+               }
+               for(var i=0; i<Login[5].length; i++) {
+                       if (n==Login[5][i].toLowerCase()) {
+                               flag = true;
+                               break;
+                       }
+               }
+       }
+       return flag;
+}
+function set_db_fields(form) {
+       // update list of DB fields, if required
+       if (DB[4]=='' && window.RegExp) {
+               // add administration fields
+               var db_fields = ''
+                       + 'subject,realname'
+                       + (Login[1] ? ',ID' : '')
+                       + (Login[2] ? ',email' : '')
+                       + (Login[3] ? ',password' : '')
+                       + ',Score,Start_Time,End_Time'
+               ;
+               // add answer fields (except separators)
+               var r = new RegExp('^[^_]+_q\\d\\d_\\w+$');
+               for(var i=0; i<form.elements.length; i++) {
+                       var n = form.elements[i].name;
+                       if (r.test(n)) db_fields += ',' + n;
+               }
+               form.db_fields.value = db_fields;
+       }
+       // make sure delimiter is set (NS6+ requires this be set here, not any earlier)
+       form.db_delimiter.value = (DB[5] ? DB[5] : '\t');
+}
+function AddStudentDetailsToResultForm() {
+       var sDetails = '';
+       if (Login[0]) { // user name
+               // use 'realname' instead of a separate 'Name' field
+               // sDetails += hpHiddenField('Name', window.UserName);
+       }
+       if (Login[1]) { // user ID
+               sDetails += hpHiddenField('ID', window.UserID);
+       }
+       if (Login[2]) { // user email
+               sDetails += hpHiddenField('email', window.UserEmail);
+       }
+       if (sDetails && window.RegExp) {
+               // insert sDetails before '<input...Score...></input>'
+               var r = new RegExp('<input[^>]*Score[^>]*><\\/input>', 'i');
+               var m = r.exec(ResultForm);
+               if (m) {
+                       ResultForm = ResultForm.replace(m[0], sDetails + m[0] + makeSeparator('Time_'));
+                       sDetails = '';
+               }
+       }
+       if (Login[3]) { // quiz password
+               sDetails += hpHiddenField('Password', window.Password);
+               ResultForm = replaceLast('</form>', sDetails + '</form>', ResultForm);
+       }
+}
+function AddQuestionDetailsToResultForm() {
+       var qDetails = GetQuestionDetails();
+       if (qDetails) {
+               // insert qDetails before the final </form> tag in the ResultForm
+               ResultForm = replaceLast('</form>', qDetails + '</form>', ResultForm);
+       }
+}
+function AddDatabaseDetailsToResultForm() {
+       if (window.DB && DB[0] && !isGuest()) {
+               var dbDetails = '';
+               var folder = DB[1];
+               if (folder && folder.charAt(folder.length-1)!='/') folder += '/';
+               var file = DB[2];
+               if (file=='') {
+                       file = location.href;
+                       file= file.substring(file.lastIndexOf('/')+1);
+                       var i = file.indexOf('?');
+                       if (i >= 0) file = file.substring(0, i);
+                       var i = file.lastIndexOf('.');
+                       if (i >= 0) file = file.substring(0, i);
+               }
+               var ext = (DB[3] ? DB[3] : 'txt');
+               if (ext.charAt(0)!='.') ext = '.' + ext;
+               dbDetails += hpHiddenField('append_db', folder + file + ext);
+               dbDetails += hpHiddenField('db_fields', DB[4]);
+               dbDetails += hpHiddenField('db_delimiter', ''); // NS6+ requires this be set later
+               if (DB[6]) dbDetails += hpHiddenField('env_report', DB[6]);
+               // insert dbDetails before the final </form> tag in the ResultForm
+               ResultForm = replaceLast('</form>', dbDetails + '</form>', ResultForm);
+       }
+}
+function AddServerFieldsToResultForm() {
+       if (window.ServerFields) {
+               var s = ''; // input tags for s(erver fields)
+               for (var i=0; i<ServerFields.length; i++) {
+                       if (ServerFields[i][0] && window.RegExp) {
+                               // remove previous field value, if any
+                               var r = new RegExp('<input[^>]*name\\s*=\\s*["\']\\s*' + ServerFields[i][0] + '[^>]*>(\\s*<\\/input>)?', 'i');
+                               if (r.test(ResultForm)) {
+                                       ResultForm = ResultForm.replace(r, '');
+                               }
+                       }
+                       if (ServerFields[i][1]) {
+                               s += hpHiddenField(ServerFields[i][0], ServerFields[i][1]);
+                       }
+               } // end for
+               if (s) ResultForm = replaceLast('</form>', s + '</form>', ResultForm);
+       }
+}
+function replaceLast(a, b, c) {
+       // replace last occurrence of 'a' in 'c' with 'b'
+       var l = a.length;
+       var i = c.lastIndexOf(a);
+       return (i<0 || l==0) ? c : (c.substring(0, i) + b + c.substring(i+l));
+}
+// *************************
+//  Extract question details
+// *************************
+function GetQuestionDetails() {
+       var hp = hpVersion();
+       var t = hpQuizType();
+       var v = hpQuizVersion();
+       return  (t==1) ? GetJbcQuestionDetails(hp, v) : 
+               (t==2) ? GetJClozeQuestionDetails(hp, v) : 
+               (t==3) ? GetJCrossQuestionDetails(hp, v) : 
+               (t==4) ? GetJMatchQuestionDetails(hp, v) : 
+               (t==5) ? GetJMixQuestionDetails(hp, v) : 
+               (t==6) ? GetJQuizQuestionDetails(hp, v) :
+               (t==7) ? GetRhubarbDetails(hp, v) :
+               (t==8) ? GetSequiturDetails(hp, v) : '';
+}
+function GetJbcQuestionDetails(hp, v) {
+       qDetails = '';
+       // check the quiz version
+       if (hp==5 || hp==6) {
+               // get question details 
+               for(var q=0; q<I.length; q++) {
+                       // initialize strings to hold answer details
+                       var aDetails = new Array();
+                       aDetails[0] = new Array(); // right
+                       aDetails[1] = new Array(); // wrong
+                       aDetails[2] = new Array(); // ignored
+                       // get answer details
+                       for(var a=0; a<I[q][1].length; a++) {
+                               var i = (Status[q][1][a]=='R') ? 0 : (Status[q][1][a]=='0') ? 2 : 1; 
+                               aDetails[i][aDetails[i].length] = (JBC[6] ? a : I[q][1][a][0]);
+                       }
+                       // format 'Q' (a padded, two-digit version of 'q')
+                       var Q = getQ('JBC', q);
+                       // add separator, if required
+                       if (JBC[0]) qDetails += makeSeparator(Q);
+                       if (JBC[1]) { // number of attempts to answer question
+                               qDetails += hpHiddenField(Q+'attempts', Status[q][2] + (Status[q][0]==1 ? 1 : 0));
+                       }
+                       if (JBC[2]) { // question text
+                               qDetails += hpHiddenField(Q+'text', I[q][0]);
+                       }
+                       if (JBC[3] && (DB[0] || aDetails[0].length>0)) { // right
+                               qDetails += hpHiddenField(Q+'right', aDetails[0]);
+                       }
+                       if (JBC[4] && (DB[0] || aDetails[1].length>0)) { // wrong
+                               qDetails += hpHiddenField(Q+'wrong', aDetails[1]);
+                       }
+                       if (JBC[5] && (DB[0] || aDetails[2].length>0)) { // ignored
+                               qDetails += hpHiddenField(Q+'ignored', aDetails[2]);
+                       }
+                       // calculate score for this question, if required (for HP version < 5.5)
+                       if (isNaN(Status[q][3])) {
+                               var a1 = Status[q][1].length; // answers
+                               var a2 = Status[q][2]; // attempts
+                               Status[q][3] =  (a1<1 || a1<(a2-1)) ? 0 : ((a1 - (a2-1)) / a1);
+                       }
+                       // add 'score' for this question
+                       qDetails += hpHiddenField(Q+'score', Math.floor(Status[q][3]*100)+'%');
+               } // end for
+       }
+       return qDetails;
+}
+function GetJClozeQuestionDetails(hp, v) {
+       var qDetails = '';
+       // check the quiz version
+       if (hp==5 || hp==6) {
+               var r = hpRottmeier();
+               if (parseInt(r)==2) { // Rottmeier Find-It 3a+3b
+                       qDetails += hpHiddenField('JCloze_penalties', window.TotWrongChoices);
+               }
+               // get details for each question
+               var q_max = (r==0) ? State.length :  GapList.length; // could use I.length for both
+               for (var q=0; q<q_max; q++) {
+                       // format 'Q' (a padded, two-digit version of 'q')
+                       var Q = getQ('JCloze', q);
+                       // add separator, if required
+                       if (JCloze[0]) qDetails += makeSeparator(Q);
+                       // score (as %)
+                       var x = (hp==5) ? State[q][3] : (r==0) ? State[q].ItemScore : GapList[q][1].Score;
+                       qDetails += hpHiddenField(Q+'score', Math.floor(x*100)+'%');
+                       var correct = (HP[_correct][q] ? HP[_correct][q] : '');
+                       if (JCloze[1]) { // student's correct answer
+                               qDetails += hpHiddenField(Q+'correct', correct);
+                       }
+                       if (JCloze[2]) { // ignored answers
+                               var x = new Array();
+                               if (r!=2.1) { // exclude Find-It 3a
+                                       for (var i=0, ii=0; i<I[q][1].length; i++) {
+                                               var s = I[q][1][i][0];
+                                               if (typeof(s)=='string' && s!='' && (s.toUpperCase() != correct.toUpperCase())) {
+                                                       x[ii++] = s;
+                                               }
+                                       }
+                               }
+                               qDetails += hpHiddenField(Q+'ignored', x);
+                       }
+                       if (JCloze[3]) {
+                               var x = (HP[_wrong][q] ? HP[_wrong][q] : '');
+                               qDetails += hpHiddenField(Q+'wrong', x);
+                       }
+                       if (JCloze[4]) { // number of penalties (Hints + Checks)
+                               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;
+                               qDetails += hpHiddenField(Q+'penalties', x);
+                       }
+                       if (JCloze[5]) { // clue shown?
+                               var x = (hp==5) ? State[q][0] : (r==0) ? State[q].ClueGiven: (r==1) ? GapList[q][1].ClueAskedFor : false;
+                               qDetails += hpHiddenField(Q+'clue_shown', (x ? 'YES' : 'NO'));
+                       }
+                       if (JCloze[6]) { // clue text
+                               qDetails += hpHiddenField(Q+'clue_text', I[q][2]);
+                       }
+                       if (JCloze[7]) { // number of hints
+                               var x = (HP[_hints][q] ? HP[_hints][q] : 0);
+                               qDetails += hpHiddenField(Q+'hints', x);
+                       }
+                       if (JCloze[8]) { // number of clues
+                               var x = HP[_clues][q] ? HP[_clues][q] : 0;
+                               qDetails += hpHiddenField(Q+'clues', x);
+                       }
+                       if (JCloze[9]) { // number of checks (including the final one for the correct answer)
+                               var x = (HP[_checks][q] ? HP[_checks][q] : 0);
+                               qDetails += hpHiddenField(Q+'checks', x);
+                       }
+               } // end for
+       }
+       return qDetails;
+}
+function GetJCrossQuestionDetails(hp, v) {
+       var qDetails = '';
+       // check the quiz version
+       if (hp==5 || hp==6) {
+               // inialize letter count
+               var letters = 0;
+               // get details for each question
+               for (var row=0; row<L.length; row++) {
+                       for (var col=0; col<L[row].length; col++) {
+                               // increment letter count, if required
+                               if (L[row][col]) letters++; 
+                               // show answers and clues, if required
+                               var q = (hp==5) ? C[row][col] : CL[row][col];
+                               if (q) {
+                                       for (var i=0; i<2; i++) { // 0==across, 1==down
+                                               var AD = (i==0) ? 'A' : 'D';
+                                               var acrossdown = (i==0) ? 'across' : 'down';
+                                               
+                                               var clue = (hp==5) ? eval(AD+'['+q+']') : GetJCrossClue('Clue_'+AD+'_'+q);
+                                               if (clue) {
+                                                       // format 'Q' (a padded, two-digit version of 'q')
+                                                       var Q = getQ('JCross', q) + acrossdown + '_'; // e.g. JCross_01_across_
+               
+                                                       if (JCross[0]) {
+                                                               qDetails += makeSeparator(Q);
+                                                       }
+                                                       if (JCross[5]) {
+                                                               var x = (HP[_correct][AD] && HP[_correct][AD][q]) ? HP[_correct][AD][q] : '';
+                                                               qDetails += hpHiddenField(Q+'correct', x);
+                                                       }
+                                                       if (JCross[4]) qDetails += hpHiddenField(Q+'clue', clue);
+                                                       if (JCross[5]) {
+                                                               var x = (HP[_wrong][AD] && HP[_wrong][AD][q]) ? HP[_wrong][AD][q] : '';
+                                                               qDetails += hpHiddenField(Q+'wrong', x);
+                                                       }
+                                                       if (JCross[6]) {
+                                                               var x = HP[_clues][q] ? HP[_clues][q] : 0;
+                                                               qDetails += hpHiddenField(Q+'clues', x);
+                                                       }
+                                                       if (JCross[7]) {
+                                                               var x = (HP[_hints][AD] && HP[_hints][AD][q]) ? HP[_hints][AD][q] : 0;
+                                                               qDetails += hpHiddenField(Q+'hints', x);
+                                                       }
+                                                       if (JCross[8]) {
+                                                               var x = (HP[_checks][AD] && HP[_checks][AD][q]) ? HP[_checks][AD][q] : '';
+                                                               qDetails += hpHiddenField(Q+'checks', x);
+                                                       }
+                                               } // end for i
+                                       } // end if clue
+                               } // end if q
+                       } // end for col
+               } // end for row
+               if (JCross[2]) { // show number of letters
+                       qDetails = hpHiddenField('JCross_letters', letters) + qDetails;
+               }
+               if (JCross[1]) { // show penalties
+                       var x = (window.Penalties) ? Penalties : 0;
+                       qDetails = hpHiddenField('JCross_penalties', x) + qDetails;
+               }
+       }
+       return qDetails;
+}
+function GetJCrossClue(id) {
+       var obj = (document.getElementById) ? document.getElementById(id) : null;
+       return (obj) ? GetTextFromNodeN(obj, 'Clue') : '';
+}
+function GetJCrossWord(a, r, c, goDown) {
+       // a is a 2-dimensional array of letters, r is a row number, c is a column number
+       var s = '';
+       while (r<a.length && c<a[r].length && a[r][c]) {
+               s += a[r][c];
+               if (goDown) {
+                       r++;
+               } else {
+                       c++;
+               }
+       }
+       return s;
+}
+function GetJMatchText(q, className) {
+       var obj = (document.getElementById) ? document.getElementById('Questions') : null;
+       return (obj) ? GetTextFromNodeN(obj, className, q) : '';
+}
+function GetJMatchRHS(v, q, getCorrect) {
+       var rhs = '';
+       if (v==5.1 || v==6.1) { // Drag-and-drop
+               var max_i = (window.F && window.D) ? D.length : 0;
+               for (var i=0; i<max_i; i++) {
+                       if (F[q][1]==D[i][getCorrect ? 1 : 2]) break;
+               }
+               if (i<max_i) rhs = D[i][0];
+       } else if (v==5 || v==6) { // drop-down list of options
+               var obj=document.getElementById(Status[q][2]);
+               if (obj) { // not correct yet
+                       if (getCorrect) {
+                               var k = GetKeyFromSelect(obj);
+                               var i_max = obj.options.length;
+                               for (var i=0; i<i_max; i++) {
+                                       if (obj.options[i].value==k) break;
+                               }
+                               if (i>=i_max) i = 0; // shouldn't happen
+                       } else {
+                               // get current guess, if any
+                               var i = obj.selectedIndex;
+                       }
+                       if (i) rhs = obj.options[i].innerHTML;
+               } else { // correct
+                       rhs = GetJMatchText(q, 'RightItem');
+               }
+       }
+       return rhs;
+}
+function GetJMixQuestionDetails(hp, v) {
+       qDetails = '';
+       // check the quiz version
+       if (hp==5 || hp==6) {
+               var q = 0; // question number
+               // format 'Q' (a padded, two-digit version of 'q')
+               var Q = getQ('JMix', q);
+               // add separator, if required
+               if (JMix[0]) qDetails += makeSeparator(Q);
+               // add 'score' for this question
+               var score = HP[_correct]==null ? 0 : ((Segments.length-Penalties)/Segments.length);
+               qDetails += hpHiddenField(Q+'score', Math.floor(score*100)+'%');
+               if (JMix[1]) { // number of wrong guesses
+                       qDetails += hpHiddenField(Q+'wrongGuesses', Penalties);
+               }
+               if (JMix[2]) { // right answer
+                       var x = (HP[_correct][q]) ? HP[_correct][q] : '';
+                       qDetails += hpHiddenField(Q+'correct', x);
+               }
+               if (JMix[3]) { // wrong answer(s)
+                       var x = (HP[_wrong][q]) ? HP[_wrong][q] : '';
+                       qDetails += hpHiddenField(Q+'wrong', x);
+               }
+               if (JMix[5]) { // checks
+                       var x = (HP[_checks][q]) ? HP[_checks][q] : 0;
+                       qDetails += hpHiddenField(Q+'checks', x);
+               }
+               if (JMix[6]) { // hints
+                       var x = (HP[_hints][q]) ? HP[_hints][q] : 0;
+                       qDetails += hpHiddenField(Q+'hints', x);
+               }
+       }
+       return qDetails;
+}
+function GetJMixSequence(indexes) {
+       var s = new Array();
+       for (var i=0; i<indexes.length; i++) {
+               s[i] = JMix[4] ? indexes[i] : GetJMixSegmentText(indexes[i]);
+       }
+       return s;
+}
+function GetJMixSegmentText(index){
+       var i_max = Segments.length;
+       for (var i=0; i<i_max; i++) {
+               if (Segments[i][1] == index) break;
+       }
+       return (i<i_max) ? Segments[i][0] : '';
+}
+function GetJQuizQuestionDetails(hp, v) {
+       var qDetails = '';
+       // HP5.5 uses "Status" for v5 and v6 JMatch quizzes (HP6 uses "State")
+       // var hp =  (window.Status) ? 5 : (window.State) ? 6 : 0;
+       // check the quiz version
+       if (hp==5 || hp==6) {
+               // get details for each question
+               var max_q = (hp==5) ? Status.length : State.length;
+               for (var q=0; q<max_q; q++) {
+                       // skip this question if it was not used (HP6 v6 only)
+                       if (hp==6 && !State[q]) continue;
+                       // format 'Q' (a padded, two-digit version of 'q')
+                       var Q = getQ('JQuiz', q);
+                       // add separator
+                       if (JQuiz[0]) qDetails += makeSeparator(Q);
+                       if (hp==6 && JQuiz[11]) { // question type
+                               var x = parseInt(I[q][2]);
+                               x = (x==0) ? 'multiple-choice' : (x==1) ? 'short-answer' : (x==2) ? 'hybrid' : (x==3) ? 'multi-select' : 'n/a';
+                               qDetails += hpHiddenField(Q+'type', x);
+                       }
+                       // score (as %)
+                       var x = (hp==5) ? Status[q][4]*10 : I[q][0]*State[q][0];
+                       if (x<0) x = 0;
+                       qDetails += hpHiddenField(Q+'score', Math.floor(x)+'%');
+                       if (hp==6 && JQuiz[10]) { // weighting
+                               qDetails += hpHiddenField(Q+'weighting', I[q][0]);
+                       }
+                       if (JQuiz[1]) { // question text
+                               var x = (hp==5) ? I[q][0] : (document.getElementById) ? GetTextFromNodeN(document.getElementById('Q_'+q), 'QuestionText') : '';
+                               qDetails += hpHiddenField(Q+'question', x);
+                       }
+                       if (JQuiz[2]) { // student's correct answers
+                               var x = (HP[_correct][q]) ? HP[_correct][q] : '';
+                               qDetails += hpHiddenField(Q+'correct', x);
+                       }
+                       if (JQuiz[3]) { // ignored and wrong answers
+                               var x = (hp==5) ? new Array() : GetJQuizAnswerDetails(q, 1);
+                               if (hp==5) {
+                                       for (var i=0; i<I[q][1].length; i++) {
+                                               var correct = HP[_correct][q] ? HP[_correct][q] : '';
+                                               if (I[q][1][i][0] && I[q][1][i][0].toUpperCase()!=correct.toUpperCase()) {
+                                                       x[x.length] = I[q][1][i][0];
+                                               }
+                                       }
+                               }
+                               if (DB[0] || x) qDetails += hpHiddenField(Q+'other', x);
+                       }
+                       if (hp==6 && JQuiz[7]) { // all selected answers
+                               var x = GetJQuizAnswerDetails(q, 0);
+                               qDetails += hpHiddenField(Q+'selected', x);
+                       }
+                       if (JQuiz[8]) { // wrong answers
+                               var x = (HP[_wrong][q]) ? HP[_wrong][q] : '';
+                               qDetails += hpHiddenField(Q+'wrong', x);
+                       }
+                       if (hp==6 && JQuiz[9]) { // ignored answers
+                               var x = GetJQuizAnswerDetails(q, 4);
+                               qDetails += hpHiddenField(Q+'ignored', x);
+                       }
+                       if (JQuiz[4]) { // number of hints
+                               var x = (HP[_hints][q]) ? HP[_hints][q] : 0;
+                               qDetails += hpHiddenField(Q+'hints', x);
+                       }
+                       if (JQuiz[5] || JQuiz[12]) { // number of checks
+                               if (JQuiz[12]) { // strictly checks only
+                                       var x = (HP[_checks][q]) ? HP[_checks][q] : 0;
+                               } else { // checks (+ hints in HP6)
+                                       var x = (hp==5) ? Status[q][1] : (State[q][2]-1);
+                               }
+                               qDetails += hpHiddenField(Q+'checks', x);
+                       }
+                       if (JQuiz[13]) { // ShowAnswer button
+                               var x = (HP[_clues][q]) ? HP[_clues][q] : 0;
+                               qDetails += hpHiddenField(Q+'clues', x);
+                       }
+               } // end for
+       } // end if
+       return qDetails;
+}
+function GetTextFromNodeN(obj, className, n) {
+       // returns the text under the nth node of obj with the target class name
+       var txt = '';
+       if (obj && className) {
+               if (typeof(n)=='undefined') {
+                       n = 0;
+               }
+               var nodes = GetNodesByClassName(obj, className);
+               if (n<nodes.length) {
+                       txt += GetTextFromNode(nodes[n]);
+               }
+       }
+       return txt;
+}
+function GetNodesByClassName(obj, className) {
+       // returns an array of nodes with the target classname
+       var nodes = new Array();
+       if (obj) {
+               if (className && obj.className==className) {
+                       nodes.push(obj);
+               } else if (obj.childNodes) {
+                       for (var i=0; i<obj.childNodes.length; i++) {
+                               nodes = nodes.concat(GetNodesByClassName(obj.childNodes[i], className));
+                       }
+               }
+       }
+       return nodes;
+}
+function GetTextFromNode(obj) {
+       // return text in (and under) a single DOM node
+       var txt = '';
+       if (obj) {
+               if (obj.nodeType==3) {
+                       txt = obj.nodeValue + ' ';
+               }
+               if (obj.childNodes) {
+                       for (var i=0; i<obj.childNodes.length; i++) {
+                               txt += GetTextFromNode(obj.childNodes[i]);
+                       }
+               }
+       }
+       return txt;
+}
+function GetJQuizAnswerDetails(q, flag) {
+       // flag : the type of information required about the student's answers
+       //      0 : all student's answers
+       //      1 : student's wrong and ignored answers
+       //      2 : student's correct answers
+       //      3 : student's wrong answers
+       //      4 : ignored answers
+       var x = State[q][5]; //Sequence of answers chosen by number
+       if (I[q][2]=='3') { // multi-select
+               if (flag==4) {
+                       var x = new Array();
+               } else {
+                       // get required part of 'x' and convert to array
+                       var i = x.lastIndexOf('|');
+                       var x = x.substring((flag==2 ? (i+1) : 1), ((flag==0 || flag==2) ? x.length : i)).split('|');
+               }
+               for (var i=0; i<x.length; i++) {
+                       var a = new Array();
+                       for (var ii=0; ii<x[i].length; ii++) {
+                               if (x[i].charAt(ii)=='Y') {
+                                       var s = JQuiz[6] ? String.fromCharCode(97+ii) : I[q][3][ii][0];
+                                       if (s && s.replace && window.RegExp) {
+                                               s = s.replace(new RegExp('\\+', 'g'), '&#43;');
+                                       }
+                                       a.push(s);
+                               }
+                       }
+                       x[i] = a.join('+');
+               }
+       } else if (x) { // multiple-choice, short-answer and hybrid 
+               // remove trailing comma and convert to array
+               x = x.substring(0, x.length-1).split(',');
+               if (flag) {
+                       var a = new Array();
+                       if (flag==1 || flag==2 || flag==3) {
+                               for (var i=0; i<x.length; i++) {
+                                       var ii = I[q][3][(x[i].charCodeAt(0)-65)][2];
+                                       if(((flag==1 || flag==2) && ii==1) || (flag==3 && ii==0)) a.push(x[i]);
+                               }
+                       }
+                       if (flag==1) {
+                               x = a;
+                               a = new Array();
+                       }
+                       if (flag==1 || flag==4) {
+                               for (var i=0; i<I[q][3].length; i++) {
+                                       var s = String.fromCharCode(65+i);
+                                       for (var ii=0; ii<x.length; ii++) {
+                                               if (x[ii]==s) break;
+                                       }
+                                       if (ii==x.length) a.push(s);
+                               }
+                       }
+                       x = a;
+               }
+               // convert answer indexes to values, if required
+               if (JQuiz[6]==false) {
+                       for (var i=0; i<x.length; i++) {
+                               var ii = x[i].charCodeAt(0) - 65;
+                               x[i] = I[q][3][ii][0];
+                       }
+               }
+       } else {
+               x = new Array();
+       }
+       return x;
+}
+function GetRhubarbDetails(v) {
+       qDetails = '';
+       if (v==6) {
+               var q = 0; // always zero
+               var Q = getQ('Rhubarb', q);
+               if (document.title) { // use quiz title as question name
+                       qDetails += hpHiddenField(Q+'name', document.title);
+               }
+               if (Rhubarb[0]) { // correct words
+                       var x = (HP[_correct][q]) ? HP[_correct][q] : '';
+                       if (Rhubarb[1]) { // count of correct words
+                               for (var i=0,ii=0; i<x.length; i++) {
+                                       if (x[i]) ii++;
+                               }
+                               x = ii;
+                       }
+                       qDetails += hpHiddenField(Q+'correct', x);
+               }
+               if (Rhubarb[2]) { // wrong words
+                       var x = (HP[_wrong][q]) ? HP[_wrong][q] : '';
+                       if (Rhubarb[3]) { // count of wrong words
+                               x = x.length;
+                       }
+                       qDetails += hpHiddenField(Q+'wrong', x);
+               }
+               if (Rhubarb[4]) { // ignored
+                       var x = '';
+                       qDetails += hpHiddenField(Q+'ignored', x);
+               }
+               if (Rhubarb[5]) { // hints
+                       var x = (HP[_hints][q]) ? HP[_hints][q] : '';
+                       qDetails += hpHiddenField(Q+'hints', x);
+               }
+       }
+       return qDetails;
+}
+function GetSequiturDetails(v) {
+       qDetails = '';
+       if (v==6) {
+               var q = 0; // always zero
+               var Q = getQ('Sequitur', q);
+               if (document.title) { // use quiz title as question name
+                       qDetails += hpHiddenField(Q+'name', document.title);
+               }
+               if (Sequitur[0]) { // number of correct buttons chosen
+                       var x = (HP[_correct][q]) ? HP[_correct][q] : '';
+                       qDetails += hpHiddenField(Q+'correct', x);
+               }
+               if (Sequitur[1]) { // number of wrong buttons chosen
+                       var x = (HP[_wrong][q]) ? HP[_wrong][q] : '';
+                       qDetails += hpHiddenField(Q+'wrong', x);
+               }
+       }
+       return qDetails;
+}
+// *********************
+//     click event handlers
+// *********************
+function hpClick(x, args) {
+       // x is the button type
+       // args is either empty, a single argument, or an array of arguments
+       var btn = (x==1) ? 'Hint' : (x==2) ? 'Clue' : (x==3) ? 'Check' : (x==4)  ? 'Enter' : '';
+       if (btn) {
+               // convert args to array, if necessary
+               var t = typeof(args);
+               if (t=='object') {
+                       // do nothing (args is already an array)
+               } else if (t=='undefined') {
+                       args = new Array();
+               } else {
+                       args = new Array(''+args);
+               }
+               // call handler for this kind of button
+               var x = eval('hpClick'+btn+'('+hpVersion()+','+hpQuizType()+','+hpQuizVersion()+',args);');
+       }
+}
+function hpClickHint(hp, t, v, args) {
+       if (t==2 || t==5 || t==6 || t==7) { // JCloze, JMix, JQuiz, Rhubarb
+               var q = args[0]; // clue/question number
+               if (!HP[_hints][q]) HP[_hints][q] = 0;
+               HP[_hints][q]++;
+       }
+       if (t==3) { // JCross
+               if (v==6 || v==5) {
+                       var q = args[0]; // clue/question number
+                       var AD = args[1]; // direction ('A' or 'D')
+                       if (!HP[_hints][AD]) HP[_hints][AD] = new Array();
+                       if (!HP[_hints][AD][q]) HP[_hints][AD][q] = 0;
+                       HP[_hints][AD][q]++;
+               }
+       }
+       return true;
+}
+function hpClickClue(hp, t, v, args) {
+       if (t==2 || t==3 || t==6) { // JCloze or JCross, or JQuiz (ShowAnswer button)
+               var q = args[0]; // clue/question number
+               if (!HP[_clues][q]) HP[_clues][q] = 0;
+               HP[_clues][q]++;
+       }
+       return true;
+}
+function hpClickCheck(hp, t, v, args) {
+       if (t==2) { // JCloze
+               if (v==5 || v==6) {
+                       var r = hpRottmeier();
+                       var already_correct = 'true';
+                       if (r==0) {
+                               already_correct = (hp==5) ? 'State[i][4]==1' : 'State[i].AnsweredCorrectly==true';
+                       } else if (r==1) { // DropDown
+                               already_correct = 'GapList[i][1].GapLocked==true';
+                       } else if (r==2.1) { // Find-It 3a
+                               already_correct = 'GapList[i][1].ErrorFound==true';
+                       } else if (r==2.2) { // Find-It 3b
+                               already_correct = 'GapList[i][1].GapSolved==true';
+                       }
+                       var i_max = I.length;
+                       for (var i=0; i<i_max; i++) {
+                               if (eval(already_correct)) continue;
+                               var g = '';
+                               if (r==0 || r==2.2) {
+                                       g = GetGapValue(i);
+                               } else if (r==1) { // DropDown
+                                       if (hp==5) {
+                                               g = eval('document.Cloze.Gap'+i+'.value');
+                                       } else if (hp==6) {
+                                               g = Get_SelectedDropValue(i);
+                                       }
+                               } else if (r==2.1 && i==args[0]) { // Find-It 3a
+                                       g = I[i][1][0][0];
+                               }
+                               if (g) {
+                                       if (!HP[_checks][i]) HP[_checks][i] = 0;
+                                       HP[_checks][i]++;
+                                       if (!HP[_guesses][i]) HP[_guesses][i] = new Array();
+                                       var ii = HP[_guesses][i].length;
+                                       // is this a new guess at this gap?
+                                       if (ii==0 || g!=HP[_guesses][i][ii-1]) { 
+                                               HP[_guesses][i][ii] = g;
+                                               var G = g.toUpperCase();
+       
+                                               var ii_max = I[i][1].length;
+                                               for (var ii=0; ii<ii_max; ii++) {
+                                                       if (window.CaseSensitive) {
+                                                               if (g==I[i][1][ii][0]) break;
+                                                       } else {
+                                                               if (G==I[i][1][ii][0].toUpperCase()) break;
+                                                       }
+                                               }
+       
+                                               if (ii==ii_max) { // guess is wrong
+                                                       if (!HP[_wrong][i]) HP[_wrong][i] = new Array();
+                                                       var ii_max = HP[_wrong][i].length;
+                                                       for (var ii=0; ii<ii_max; ii++) {
+                                                               if (HP[_wrong][i][ii]==g) break;
+                                                       }
+                                                       if (ii==ii_max) {
+                                                               HP[_wrong][i][ii] = g;
+                                                       }
+                                               } else { // guess is correct
+                                                       HP[_correct][i] = g;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+       if (t==3) { // JCross
+               if (v==5 || v==6) {
+                       var q = args[0]; // clue/question number
+                       for (var row=0; row<L.length; row++) {
+                               for (var col=0; col<L[row].length; col++) {
+                                       var q = (v==5) ? C[row][col] : CL[row][col];
+                                       if (q) {
+                                               hpClickCheckJCrossV5V6(hp, v, 'A', q, row, col);
+                                               hpClickCheckJCrossV5V6(hp, v, 'D', q, row, col);
+                                       }
+                               }
+                       }
+               }
+       }
+       if (t==4) { // JMatch
+               var a = new Array();
+               var extra = ''; // extra js code to eval(uate)
+               var guess = ''; // js code to eval(uate) guess
+               var correct = ''; // js code to eval(uate) correct answer
+               if (window.D && window.F) {
+                       // drag-and-drop, i.e. v5+ and v6+ (HP5 and HP6)
+                       a = F;
+                       guess = 'GetJMatchRHS(v,i)';
+                       correct = 'GetJMatchRHS(v,i,true)';
+               } else  if (window.GetKeyFromSelect) {
+                       // HP6 v6
+                       a = Status;
+                       guess = 'GetJMatchRHS(v,i)';
+                       correct = 'GetJMatchRHS(v,i,true)';
+               } else if (window.GetAnswer) {
+                       // HP5 v6,v5
+                       a = I;
+                       guess = "(I[i][2]==0||I[i][0]=='')?'':GetAnswer(i)";
+                       correct = 'I[i][3])';
+               } else if (window.Draggables) {
+                       // HP5 v4
+                       a = Draggables;
+                       s = "Draggables[i].correct=='1'";
+               } else if (window.CorrectAnswers) {
+                       // HP5 v3
+                       a = CorrectAnswers;
+                       guess = 'document.QuizForm.elements[i*2].selectedIndex';
+                       correct = 'CorrectAnswers[i]';
+               }
+               for (var i=0; i<a.length; i++) {
+                       // check this match has not already been finished
+                       if (!HP[_correct][i]) {
+                               // do extra setup, if necessary
+                               if (extra) eval(extra);
+                               // get the guess, if any
+                               var g = ''+eval(guess);
+                               if (g) {
+                                       // is the guess correct?
+                                       if (g==eval(correct)) {
+                                               HP[_correct][i] = g;
+                                       } else { // wrong answer
+                                               // initialize wrong guess array if necessary
+                                               if (!HP[_wrong][i]) HP[_wrong][i] = new Array();
+                                               // check to see if the guess is already in the guess array
+                                               var i_max = HP[_wrong][i].length;
+                                               for (var ii=0; ii<i_max; ii++) {
+                                                       if (HP[_wrong][i][ii]==g) break;
+                                               }
+                                               // add the guess if it was not found
+                                               if (ii==i_max) {
+                                                       HP[_wrong][i][ii]=g;
+                                               } else {
+                                                       g = null; // this is not a new answer
+                                               }
+                                       }
+                                       // increment checks for this question, if necessary
+                                       if (g) {
+                                               if (!HP[_checks][i]) HP[_checks][i] = 0;
+                                               HP[_checks][i]++;
+                                       }
+                               }
+                       }
+               }
+       } // end if JMatch
+       if (t==5) { // JMix
+               // get question number (always 0)
+               var q = args[0];
+               // check question has not already been answered correctly
+               if (!HP[_correct][q]) {
+                       // match current guess against possible correct answers
+                       var a_max = Answers.length;
+                       for (var a=0; a<a_max; a++) {
+                               var i_max = Answers[a].length;
+                               for (var i=0; i<i_max; i++) {
+                                       if (Answers[a][i] != GuessSequence[i]) break;
+                               }
+                               if (i==i_max) break; // correct answer was found
+                       }
+                       // at this point, (a==a_max) means guess is wrong
+                       // get array of segment texts in this g(uess)
+                       var g = GetJMixSequence(GuessSequence);
+                       // convert g(uess) array and to a s(tring)
+                       var s = '';
+                       var i_max = g.length;
+                       for (var i=0; i<i_max; i++) {
+                               g[i] = trim(g[i]);
+                               if (g[i]!='') {
+                                       s += (s=='' ? '' : '+') +  g[i];
+                               }
+                       }
+                       if (s) {
+                               if (a==a_max) { // wrong
+                                       if (!HP[_wrong][q]) HP[_wrong][q] = new Array();
+                                       var i = HP[_wrong][q].length;
+                                       HP[_wrong][q][i] = s;
+                               } else { // correct
+                                       HP[_correct][q] = s;
+                               }
+                               // increment checks for this question
+                               if (!HP[_checks][q]) HP[_checks][q] = 0;
+                               HP[_checks][q]++;
+                       }
+               }
+       }
+       if (t==6) { // JQuiz
+               if (hp==5 || hp==6) {
+                       var q = args[0]; // clue/question number
+                       if (hp==5) {
+                               if (v==5) {
+                                       var g = TrimString(eval('BottomFrame.document.QForm' + q + '.Guess').value);
+                               } else if (v==6) {
+                                       var g = TrimString(eval('document.QForm.Guess').value);
+                               }
+                       } else  { // HP 6
+                               var g = args[1];
+                       }
+                       // increment check count
+                       if (!HP[_checks][q]) HP[_checks][q] = 0;
+                       HP[_checks][q]++;
+                       if (g) {
+                               var G = g.toUpperCase(); // used for shortanswer only
+                               var correct_answer = ''; // used for multiselect only
+                               // set index of answer array in I (the question array)
+                               var ans = (hp==5) ? 1 : 3;
+                               var i_max = I[q][ans].length;
+                               for (var i=0; i<i_max; i++) {
+                                       // is this a (possible) correct answer?
+                                       if (hp==5 || (hp==6 && I[q][ans][i][2])) {
+                                               if (hp==6 && I[q][2]==3) { // multiselect
+                                                       correct_answer += (correct_answer  ? '&#43;' : '') + I[q][ans][i][0];
+                                               } else { // multichoice, shortanswer
+                                                       if (window.CaseSensitive) {
+                                                               if (g==I[q][ans][i][0]) break;
+                                                       } else {
+                                                               if (G==I[q][ans][i][0].toUpperCase()) break;
+                                                       }
+                                               }
+                                       }
+                               }
+                               if (i==i_max && g!=correct_answer) { // wrong
+                                       if (!HP[_wrong][q]) HP[_wrong][q] = new Array();
+                                       var i_max = HP[_wrong][q].length;
+                                       for (var i=0; i<i_max; i++) {
+                                               if (HP[_wrong][q][i]==g) break;
+                                       }
+                                       if (i==i_max) HP[_wrong][q][i] = g;
+                               } else {
+                                       HP[_correct][q] = g;
+                               }
+                       }
+               }
+       }
+       if (t==7) { // Rhubarb
+               if (hp==6) {
+                       var q = 0; // question number (always zero)
+                       var g = args[0]; // InputWord from CheckGuess()
+                       if (g) {
+                               var G = g.toUpperCase();
+                               var i_max = Words.length;
+                               for (var i=0; i<i_max; i++) {
+                                       if (G==Words[i].toUpperCase()) break;
+                               }
+                               if (i<i_max) { // correct
+                                       if (!HP[_correct][q]) HP[_correct][q] = new Array();
+                                       HP[_correct][q][i] = g;
+                               } else { // wrong
+                                       if (!HP[_wrong][q]) HP[_wrong][q] = new Array();
+                                       var i_max = HP[_wrong][q].length;
+                                       for (var i=0; i<i_max; i++) {
+                                               if (G==HP[_wrong][q][i].toUpperCase()) break;
+                                       }
+                                       if (i==i_max) HP[_wrong][q][i] = g;
+                               }
+                       }
+               }
+       }
+       if (t==8) { // Sequitur
+               if (hp==6) {
+                       var q = 0; // question number (always zero)
+                       if (CurrentCorrect==args[0]) { // correct button chosen
+                               if (!HP[_correct][q]) HP[_correct][q] = 0;
+                               HP[_correct][q]++;
+                       } else {
+                               if (!HP[_wrong][q]) HP[_wrong][q] = 0;
+                               HP[_wrong][q]++;
+                       }                       
+               }
+       }
+       return true;
+}
+function hpClickCheckJCrossV5V6(hp, v, AD, q, row, col) {
+       // v is the version of Hot Potatoes
+       // AD is the direction ('A' or 'D')
+       // make sure HP[_checks] and HP[_correct] are initialized
+       if (!HP[_checks][AD]) HP[_checks][AD] = new Array();
+       if (!HP[_correct][AD]) HP[_correct][AD] = new Array();
+       // get clue, if any
+       var clue = (hp==5) ? eval('window.'+AD) : GetJCrossClue('Clue_'+AD+'_' + q);
+       // is this a question that has not been answered correctly yet?
+       if (clue && !HP[_correct][AD][q]) {
+               var check = false;
+               var guess = GetJCrossWord(G, row, col, (AD=='D'));
+               var correct = GetJCrossWord(L, row, col, (AD=='D'));
+               if (guess==correct) {
+                       HP[_correct][AD][q] = correct;
+                       check = true;
+               } else if (guess) {
+                       // make sure HP[_wrong] is initialized
+                       if (!HP[_wrong][AD]) HP[_wrong][AD] = new Array();
+                       if (!HP[_wrong][AD][q]) HP[_wrong][AD][q] = new Array();
+                       // check this guess has not been entered before
+                       var i_max = HP[_wrong][AD][q].length;
+                       for (var i=0; i<i_max; i++) {
+                               if (HP[_wrong][AD][q]==guess) break;
+                       }
+                       // add the guess if it has not been entered before
+                       if (i>=i_max) {
+                               HP[_wrong][AD][q][i] = guess;
+                               check = true;
+                       }
+               }
+               // update HP[_checks], if necessary
+               if (check) {
+                       if (!HP[_checks][AD]) HP[_checks][AD] = new Array();
+                       if (!HP[_checks][AD][q]) HP[_checks][AD][q] = 0;
+                       HP[_checks][AD][q]++;
+               }
+       }
+}
+function hpClickEnter(hp, t, v, args) {
+       if (t==3) { // JCross
+               var q = args[0]; // clue/question number
+               if (!HP[_enter][q]) HP[_enter][q] = 0;
+               HP[_enter][q]++;
+       }
+       return true;
+}
+function GetJMatchQuestionDetails(hp, v) {
+       var qDetails = '';
+       // HP5.5 uses "I" for v5 and v6 JMatch quizzes
+       // var hp5 = (window.I) ? true : false;
+       // check the quiz version
+       if (hp==5 || hp==6) {
+               if (JMatch[1] && v==6.1) { // attempts
+                       qDetails += hpHiddenField('JMatch_attempts', Penalties+1);
+               }
+               // get number of questions
+               var max_q = (hp==5 || v==6) ? Status.length : F.length;
+               // get details for each question
+               for (var q=0; q<max_q; q++) {
+                       // format 'Q' (a padded, two-digit version of 'q')
+                       var Q = getQ('JMatch', q);
+                       // add separator, if required
+                       if (JMatch[0] && (JMatch[1] || JMatch[2] || JMatch[3])) {
+                               qDetails += makeSeparator(Q);
+                       }
+                       if (JMatch[1] && (hp==5 || v==6)) { // attempts
+                               qDetails += hpHiddenField(Q+'attempts', Status[q][1]);
+                       }
+                       if (JMatch[2]) { // LHS text (the question)
+                               var x = (v==5) ? I[q][0] : (v==6) ? GetJMatchText(q, 'LeftItem') : F[q][0];
+                               qDetails += hpHiddenField(Q+'lhs', x);
+                       }
+                       if (JMatch[3]) { // correct answer (if any)
+                               var x = HP[_correct][q] ? HP[_correct][q] : '';
+                               qDetails += hpHiddenField(Q+'correct', x);
+                       }
+                       if (JMatch[4]) { // wrong answers (if any)
+                               var x = HP[_wrong][q] ? HP[_wrong][q] : '';
+                               qDetails += hpHiddenField(Q+'wrong', x);
+                       }
+                       if (JMatch[5]) { // checks
+                               var x = HP[_checks][q] ? HP[_checks][q] : 0;
+                               qDetails += hpHiddenField(Q+'checks', x);
+                       }
+               } // end for
+       }
+       return qDetails;
+}
+// *********************
+//   library functions
+// *********************
+function pad(i, l) {
+       var s = (i+'');
+       while (s.length<l) s = '0' + s;
+       return s;
+}
+function getQ(section, q) {
+       // Q is a padded, two-digit version of the question number, 'q', prefixed by 'section'
+       return section + '_q' + (q<9 ? '0' : '') + (q+1) + '_';
+}
+function makeSeparator(Q) {
+       return  is_LMS() ? '' : hpHiddenField(Q.substring(0, Q.length-1), '---------------------------------');
+}
+function hpHiddenField(name, value, comma, forceHTML) {
+       var field = '';
+       var t = typeof(value);
+       if (t=='string') {
+               value = encode_entities(value);
+       } else if (t=='object') { // array
+               var values = value;
+               var i_max = values.length;
+               value = '';
+               if (comma==null) comma = ','; 
+               for (var i=0; i<i_max; i++) {
+                       values[i] = trim(values[i]);
+                       if (values[i]!='') {
+                               value += (i==0 ? '' : comma) +  encode_entities(values[i]);
+                       }
+               }
+       }
+       if (is_LMS() && !forceHTML) {
+               if (value && value.indexOf && value.indexOf('<')>=0 && value.indexOf('>')>=0) {
+                       value = '<![CDATA[' + value + ']]>';
+               }
+               field = '<field><fieldname>' + name + '</fieldname><fielddata>' + value + '</fielddata></field>';
+       } else {
+               field = '<input type=hidden name="' + name + '" value="' + value + '">';
+       }
+       return field;
+}
+function trim(s) {
+       if (s==null) s = '';
+       var i = 0;
+       var ii = s.length;
+       while (i<ii && s.charAt(i)==' ') {
+               i++;
+       }
+       while (ii>i && s.charAt(ii-1)==' ') {
+               ii--;
+       }
+       return s.substring(i, ii);
+}
+function encode_entities(s_in) {
+       var i_max = (s_in) ? s_in.length : 0;
+       var s_out = '';
+       for (var i=0; i<i_max; i++) {
+               var c = s_in.charCodeAt(i);
+               // 34 : double quote .......["] &amp;
+               // 38 : single quote .......['] &apos;
+               // 43 : plus sign ..........[+]
+               // 44 : comma ..............[,]
+               // 60 : left angle bracket .[<] &lt;
+               // 62 : right angle bracket [>] &gt;
+               // >=128 multibyte character
+               s_out += (c==43 || c==44 || c>=128) ? ('&#x' + pad(c.toString(16), 4) + ';') : s_in.charAt(i);
+       }
+       return s_out;
+}
+// *********************
+//     initialization
+//       functions
+// *********************
+function getTime(obj) {
+       obj = obj ? obj : new Date();
+       // get year, month and day
+       //      for an LMS : yyyy-mm-dd
+       //      for email  : DayName MonthName dd yyyy
+       var s = is_LMS() ? 
+               obj.getFullYear() + '-' + pad(obj.getMonth()+1, 2) + '-' + pad(obj.getDate(), 2) : 
+               MSG[16][obj.getDay()] + ' ' + MSG[17][obj.getMonth()] + ' ' + pad(obj.getDate(), 2) + ' ' + obj.getFullYear()
+       ;
+       // get hours, minutes and seconds (hh:mm:ss)
+       s += ' ' + pad(obj.getHours(), 2) + ':' + pad(obj.getMinutes(), 2) + ':' + pad(obj.getSeconds(), 2);
+       // get time difference
+       //      for an LMS : +xxxx
+       //      for email  : GMT+xxxx
+       var x = obj.getTimezoneOffset(); // e.g. -540
+       if (!isNaN(x)) {
+               s += ' ' + (is_LMS() ? '' : 'GMT') + (x<0 ? '+' : '-');
+               x = Math.abs(x);
+               s += pad(parseInt(x/60), 2) + pad(x - (parseInt(x/60)*60), 2);
+       }
+       return s;
+}
+function getFunc(fn) {
+       if (typeof(fn)=='string') {
+               fn = eval('window.' + fn);
+       }
+       return (typeof(fn)=='function') ? fn : null;
+}
+function getFuncCode(fn, extraCode, anchorCode, beforeAnchor) {
+       var s = '';
+       var obj = getFunc(fn);
+       if (obj) {
+               s = obj.toString();
+               var i1 = s.indexOf('{')+1;
+               var i2 = s.lastIndexOf('}');
+               if (i1>0 && i1<i2) {
+                       s = s.substring(i1, i2);
+               }
+       }
+       if (extraCode) {
+               if (anchorCode) {
+                       if (beforeAnchor) {
+                               s = replaceLast(anchorCode, extraCode + anchorCode, s);
+                       } else {
+                               s = replaceLast(anchorCode, anchorCode + extraCode, s);
+                       }
+               } else {
+                       if (beforeAnchor) {
+                               s = extraCode + s;
+                       } else {
+                               s = s + extraCode;
+                       }
+               }
+       }
+       return s;
+}
+function getArgsStr(args) {
+       // make s(tring) version of function args array
+       var s = '';
+       var i_max = args.length;
+       for (var i=0; i<i_max; i++) {
+               s += '"' + args[i] + '",';
+       }
+       return s;
+}
+function getFuncArgs(fn, flag) {
+       // flag==0 : return args as string
+       // flag==1 ; return args as array
+       var i = 0;
+       var a = new Array();
+       var obj = getFunc(fn);
+       if (obj) {
+               var s = obj.toString();
+               var i1 = s.indexOf('(') + 1;
+               var i2 = s.indexOf(')', i1);
+               // add args to a(rray)
+               while (i1>0 && i1<i2) {
+                       var i3 = s.indexOf(',', i1); // next comma
+                       if (i3<0 || i3>i2) i3 = i2;
+                       a[i++] = trim(s.substring(i1, i3));
+                       i1 = i3+1;
+               }
+       }
+       return flag ? a : getArgsStr(a);
+}
+function getPrompt(fn) {
+       // the LoginPrompt is the text string in the first prompt(...) statement
+       //      v5 : in the StartUp function
+       //      v6 : in the GetUserName function
+       // Note: netscape uses double-quote as delimiter, others use single quote
+       var s = getFuncCode(fn);
+       var i1 = s.indexOf('prompt') + 8;
+       var i2 = s.indexOf(s.charAt(i1-1), i1); 
+       var p = (i1>=8 && i2>i1) ? s.substring(i1, i2) : '';
+       // make sure browser has decoded the unicode prompt properly
+       // this check is mainly for ns4, but there may be others
+       if (window.RegExp) {
+               var r = new RegExp('u([0-9A-F]{4})');
+               var m = r.exec(p);
+               while (m) {
+                       p = p.replace(m[0], '&#' + parseInt(m[1], 16) + ';');
+                       m = r.exec(p);
+               }
+       }
+       return p;
+}
+function getStartUpCode(fn) {
+       // the main initialization code comes from the StartUp function
+       //      v5 : the code before "UserName", if any, 
+       //           and the code after the 2nd subsequent '}'
+       //      v6 : the code before and after 'GetUserName();' 
+       //           i.e. all the code except the call to 'GetUserName();'
+       var s = getFuncCode(fn);
+       var i1 = s.indexOf('GetUserName();');
+       if (i1>=0) { // v6 
+               var i2 = i1 + 14;
+       } else { // v5
+               var i1 = s.indexOf('UserName');
+               var i2 = s.indexOf('}', s.indexOf('}', i1+8)+1)+1;
+       }
+       return (0<i1 && i1<i2) ? s.substring(0, i1) + s.substring(i2) : '';
+}
+function is_LMS() {
+       if (!window.hpCheckedForm) {
+               window.hpCheckedForm = true;
+               window.hpFoundForm = hpFindForm('store') ? true : false;
+       }
+       return hpFoundForm;
+}
+function hpFeedback() {
+       if (FEEDBACK[0]) {
+               var url = '';
+               var html = '';
+               if (FEEDBACK[1] && FEEDBACK[2]) { // formmail
+                       html += '<html><body>'
+                               + '<form action="' + FEEDBACK[0] + '" method="POST">'
+                               + '<table border="0">'
+                               + '<tr><th valign="top" align="right">' + FEEDBACK[7] + ':</th><td>' + document.title + '</td></tr>'
+                               + '<tr><th valign="top" align="right">' + FEEDBACK[8] + ': </th><td>'
+                       ;
+                       if (typeof(FEEDBACK[1])=='string') {
+                               html += FEEDBACK[1] + hpHiddenField('recipient', FEEDBACK[1], ',', true);
+                       } else if (typeof(FEEDBACK[1])=='object') {
+                               var i_max = FEEDBACK[1].length;
+                               if (i_max==1) { // one teacher
+                                       html += FEEDBACK[1][0][0] + hpHiddenField('recipient', FEEDBACK[1][0][0]+' &lt;'+FEEDBACK[1][0][1]+'&gt;', ',', true);
+                               } else if (i_max>1) { // several teachers
+                                       html += '<select name="recipient">';
+                                       for (var i=0; i<i_max; i++) {
+                                               html += '<option value="'+FEEDBACK[1][i][1]+'">' + FEEDBACK[1][i][0] + '</option>';
+                                       }
+                                       html += '</select>';
+                               }
+                       }
+                       html += '</td></tr>'
+                               +       '<tr><th valign="top" align="right">' + FEEDBACK[9] + ':</th>'
+                               +       '<td><TEXTAREA name="message" rows="10" cols="40"></TEXTAREA></td></tr>'
+                               +       '<tr><td>&nbsp;</td><td><input type="submit" value="' + FEEDBACK[6] + '">'
+                               +       hpHiddenField('realname', FEEDBACK[2], ',', true)
+                               +       hpHiddenField('email', FEEDBACK[3], ',', true)
+                               +       hpHiddenField('subject', document.title, ',', true)
+                               +       hpHiddenField('title', document.title, ',', true)
+                               +       hpHiddenField('return_link_title', FEEDBACK[10], ',', true)
+                               +       hpHiddenField('return_link_url', 'javascript:self.close()', ',', true)
+                               +       '</td></tr></table></form></body></html>'
+                       ;
+               } else if (FEEDBACK[1]) { // url only
+                       if (typeof(FEEDBACK[1])=='object') {
+                               var i_max = FEEDBACK[1].length;
+                               if (i_max>1) { // several teachers
+                                       html += '<html><body>'
+                                               + '<form action="' + FEEDBACK[0] + '" method="POST" onsubmit="this.action+=this.recipient.options[this.recipient.selectedIndex].value">'
+                                               + '<table border="0">'
+                                               + '<tr><th valign="top" align="right">' + FEEDBACK[7] + ':</th><td>' + document.title + '</td></tr>'
+                                               + '<tr><th valign="top" align="right">' + FEEDBACK[8] + ': </th><td>'
+                                       ;
+                                       html += '<select name="recipient">';
+                                       for (var i=0; i<i_max; i++) {
+                                               html += '<option value="'+FEEDBACK[1][i][1]+'">' + FEEDBACK[1][i][0] + '</option>';
+                                       }
+                                       html += '</select>';
+                                       html += '</td></tr>'
+                                               +       '<tr><td>&nbsp;</td><td><input type="submit" value="' + FEEDBACK[6] + '">'
+                                               +       '</td></tr></table></form></body></html>'
+                                       ;
+                               } else if (i_max==1) { // one teacher
+                                       url = FEEDBACK[0] + FEEDBACK[1][0][1];
+                               }
+                       } else if (typeof(FEEDBACK[1])=='string') {
+                               url = FEEDBACK[0] + FEEDBACK[1];
+                       }
+               } else {
+                       url = FEEDBACK[0];
+               }
+               if (url || html) {
+                       var w = openWindow(url, 'feedback', FEEDBACK[4], FEEDBACK[5], 'RESIZABLE,SCROLLBARS', html);
+                       if (!w) {
+                                // unable to open popup window
+                               alert(MSG[18]);
+                       }
+               }
+       }
+}
+// ********************
+//     intercept clicks
+// ********************
+function hpInterceptFeedback() {
+       // modify the function which writes feedback
+       //      v6: ShowMessage(Feedback)
+       //              but Rhubarb prints score in other functions, so use 'CheckFinished'
+       //      v5: WriteFeedback(Feedback)
+       //      v4: WriteFeedback(Stuff)
+       //      v3: WriteFeedback(Feedback) [except JMatch]
+       //      v3: CheckAnswer()           [JMatch only]
+       var f = '';
+       if (window.CheckWord) { // Rhubarb
+               f = 'CheckFinished';
+               window.FEEDBACK = null;
+       } else if (window.ShowText) { // Sequitur
+               f = 'CheckAnswer';
+               window.FEEDBACK = null;
+       } else { // JBC, JCloze, JCross, JMatch, JMix, JQuiz
+               f = window.ShowMessage ? 'ShowMessage' : window.WriteFeedback ? 'WriteFeedback' : 'CheckAnswer';
+       }
+       if (f) {
+               var s = getFuncCode(f) + 'Finish();';
+               var a = getFuncArgs(f, true);
+               if (a[0] && window.FEEDBACK && FEEDBACK[0]) {
+                       s = a[0] + "+='<br /><br />" + '<a href="javascript:hpFeedback();">' + FEEDBACK[6] + "</A>';" + s;
+               }
+               eval('window.' + f + '=new Function(' + getArgsStr(a) + 's);');
+       }
+}
+function hpInterceptHints() {
+       // modify the function which shows hints
+       //      JBC:    none
+       //      JCloze  v3-v6: ShowHint()
+       //      JCross  v3: Cheat(), v4: ShowHint(), v5-v6[HP5]: ShowHint(Across,x,y,BoxName), v6[HP6]: ShowHint(Across,ClueNum,x,y,BoxId)
+       //      JMatch: none
+       //      JMix    v5-v6: CheckAnswer(CheckType=1)
+       //      JQuiz   v3: CheckAnswer(ShowHint=true, QNum), v4: CheckAnswer(ShowHint=true), v5-v6[HP5]: CheckAnswer(ShowHint=true,QNum), v6[HP6]: ShowHint(QNum)
+       var x = ''; // extra code, if any
+       if (window.Cheat) {
+               // JCross v3 ?
+       } else if (window.ShowHint) {
+               var f = 'ShowHint';
+               var a = getFuncArgs(f, true);
+               if (a.length==0) {
+                       if (window.FindCurrent) {
+                               // JCloze v3-v6
+                               x = 'var q=window.Locked?-1:FindCurrent();if(q>=0&&GetHint(q))hpClick(1,q);';
+                       } else {
+                               // JCross v4
+                               // work out which box would have a hint added
+                               // work out which question that box is part of using GridMap and WinLetters
+                       }
+               } else if (a[0]=='Across') {
+                       if (a[1]=='ClueNum') {
+                               // JCross v6 [HP6]
+                               x = "var args=new Array(ClueNum,Across?'A':'D');hpClick(1,args);";
+                       } else if (a[1]=='x' && a[2]=='y') {
+                               // JCross v5-v6 [HP5]
+                               x = "var args=new Array(C[x][y],Across?'A':'D');hpClick(1,args);";
+                       }
+               } else if (a[0]=='QNum') {
+                       // JQuiz v6[HP6]
+                       x = 'hpClick(1,QNum);';
+               }
+       } else if (window.Hint) {
+               // Rhubarb
+               var f = 'Hint';
+               var a = getFuncArgs(f, true);
+               x = 'hpClick(1,0);'; // question number is always zero
+       
+       } else if (window.CheckAnswer) {
+               var f = 'CheckAnswer';
+               var a = getFuncArgs(f, true);
+               if (a[0]=='ShowHint') {
+                       if (a[1]=='QNum') {
+                               // JQuiz v3, v5-v6[HP5]
+                               x = 'if(ShowHint)hpClick(1,QNum);'; 
+                       } else {
+                               // JQuiz v4
+                               x = 'if(ShowHint)hpClick(1,QNum-1);'; // QNum is a global variable
+                       }
+               } else if (a[0]=='CheckType') {
+                       // JMix v5-v6
+                       x = 'if(CheckType==1)hpClick(1,0);'; // question number is always 0;
+               }
+       }
+       // add the e(x)tra code, if any, to the start of the hint (f)unction
+       if (x) {
+               var s = getFuncCode(f, x, '', true);
+               eval('window.' + f + '=new Function(' + getArgsStr(a) + 's);');
+       }
+}
+function hpInterceptClues() {
+       // modify the function which shows clues (or ShowAnswers in JQuiz)
+       //      JBC:    none
+       //      JCloze  v3-v6: ShowClue(ItemNum)
+       //      JCross  v3-v4: ShowClue(ClueNum), v5-v6: ShowClue(ClueNum,x,y)
+       //      JMatch  none
+       //      JMix    none
+       //      JQuiz   ShowAnswers(QNum)
+       var x = ''; // extra code, if any
+       if (window.ShowClue) {
+               var f = 'ShowClue';
+               var a = getFuncArgs(f, true);
+               if (a[0]=='ItemNum') {
+                       // JCloze (v3-v6)
+                       x = 'if(!window.Locked)hpClick(2,ItemNum);'; // v6 [HP6] uses window.Locked
+               } else if (a[0]=='ClueNum') {
+                       if (a[1]=='x' && a[2]=='y') {
+                               if (window.A && window.D) {
+                                       // JCross v5-v6 [HP5]
+                                       x = 'if(A[ClueNum]||D[ClueNum])hpClick(2,ClueNum);';
+                               } else if (document.getElementById) {
+                                       // JCross v6 [HP6]
+                                       x = "if(document.getElementById('clue_' + ClueNum)||document.getElementById('Clue_D_' + ClueNum))hpClick(2,ClueNum);";
+                               }
+                       } else {
+                               if (window.AClues && window.DClues) {
+                                       // JCross v3-v4
+                                       x = 'if(AClues[ClueNum]||DClues[ClueNum])hpClick(2,ClueNum);';
+                               }
+                       }
+               }
+       }
+       // JQuiz: there is no "ShowClue" function but there is a "ShowAnswer" function
+       if (window.ShowAnswers) {
+               var f = 'ShowAnswers';
+               var a = getFuncArgs(f, true);
+               if (window.State) {
+                       if (window.ShowMessage) {
+                               // JQuiz v6 [HP6]
+                               x = 'if(State[QNum][0]<1)hpClick(2,QNum);';
+                       } else if (window.WriteFeedback) {
+                               // JQuiz v3-v4
+                               x = 'if(State[QNum-1][0]<1)hpClick(2,QNum-1);';
+                       }
+               } else if (window.Status) {
+                       // JQuiz v5-v6 [HP5]
+                       x = 'if(Status[QNum][0]<0)hpClick(5,QNum);';
+               }
+       }
+       // add the e(x)tra code, if any, to the start of the clue (f)unction
+       if (x) {
+               var s = getFuncCode(f, x, '', true);
+               eval('window.' + f + '=new Function(' + getArgsStr(a) + 's);');
+       }
+}
+function hpInterceptChecks() {
+       // modify the function which handles checks
+       //      JBC:    none
+       //      JCloze  CheckAnswers()
+       //              NB: Rottmeier Find-It 3a: CheckText(GapState,GapId)
+       //      JCross  none
+       //      JMatch  HP5 v3, v5, v6: CheckAnswer(), HP5 v4: CheckResults(), HP6: CheckAnswers()
+       //      JMix    CheckAnswer(CheckType)
+       //      JQuiz 
+       //              HP5: CheckAnswer(ShowHint, QNum)
+       //              HP6: CheckMCAnswer, CheckMultiSelAnswer, CheckShortAnswer
+       //      Rhubarb  CheckWord(InputWord)
+       //      Sequitur CheckAnswer(Chosen, Btn)
+       // HP6 JQuiz has three "Check Answer" functions
+       var f = new Array('CheckMCAnswer', 'CheckMultiSelAnswer', 'CheckShortAnswer');
+       for (var i=0; i<f.length; i++) {
+               if (eval('window.' + f[i])) {
+                       var a = getFuncArgs(f[i], true);
+                       var x = "";
+                       if (f[i]=='CheckMCAnswer') {
+                               x += "var args=new Array(QNum,I[QNum][3][ANum][0]);";
+                       } else if (f[i]=='CheckShortAnswer') {
+                               x += ""
+                               + "var obj=document.getElementById('Q_'+QNum+'_Guess');"
+                               + "var args=new Array(QNum,obj.value);"
+                               ;
+                       } else if (f[i]=='CheckMultiSelAnswer') {
+                               x += ""
+                               + "var g='';"
+                               + "for (var ANum=0; ANum<I[QNum][3].length; ANum++){"
+                               +       "var obj=document.getElementById('Q_'+QNum+'_'+ANum+'_Chk');"
+                               +       "if (obj.checked)g+=(g?'&#43;':'')+I[QNum][3][ANum][0];"
+                               + "}"
+                               + "var args=new Array(QNum,g);"
+                               ;
+                       }
+                       if (x) {
+                               x = "if(!Finished&&State[QNum].length&&State[QNum][0]<0){" + x + "hpClick(3,args)}";
+                               var s = getFuncCode(f[i], x, '', true);
+                               eval('window.' + f[i] + '=new Function(' + getArgsStr(a) + 's);');
+                       }
+               }
+       }
+       var f = ''; // function name
+       var x = ''; // extra code, if any
+       if (window.CheckAnswer) {
+               f = 'CheckAnswer';
+               var a = getFuncArgs(f, true);
+               if (a[0]=='ShowHint') {
+                       if (a[1]=='QNum') {
+                               // JQuiz v3, v5-v6[HP5]
+                               x = 'if(!ShowHint&&Status[QNum][0]<1)hpClick(3,QNum);'; 
+                       } else {
+                               // JQuiz v4
+                               x = 'if(!ShowHint&&State[QNum-1][0]<1)hpClick(3,QNum-1);'; // QNum is a global variable
+                       }
+               } else if (a[0]=='CheckType') {
+                       // JMix v5-v6
+                       x = 'if(CheckType==0)hpClick(3,0);'; // question number is always 0;
+               } else if (a[0]=='Chosen') {
+                       // Sequitur
+                       x = 'if (!(CurrentNumber==TotalSegments||AllDone||Btn.innerHTML==IncorrectIndicator))hpClick(3,Chosen);';
+               }
+       } else if (window.CheckWord) { 
+               f = 'CheckWord';
+               var a = getFuncArgs(f, true);
+               if (a[0]=='InputWord') {
+                       // Rhubarb
+                       x = 'if(!window.AllDone)hpClick(3,InputWord);';
+               }
+       } else if (window.CheckText && !window.CheckAnswers) { // Rottmeier Find-It (3a)
+               f = 'CheckText';
+               var a = getFuncArgs(f, true);
+               if ((a[0]=='bool' && a[1]=='item') || (a[0]=='GapState' && a[1]=='GapId')) {
+                       x = 'if(!window.Finished&&'+a[0]+')hpClick(3,'+a[1]+');';
+               }
+       }
+       if (f) {
+               var s = getFuncCode(f, x, '', true);
+               eval('window.' + f + '=new Function(' + getArgsStr(a) + 's);');
+       }
+       // JMatch has three possible check functions, depending on the version
+       // (NB: other quiz types also have these functions)
+       var f = new Array('CheckAnswers', 'CheckAnswer', 'CheckResults');
+       for (var i=0; i<f.length; i++) {
+               if (eval('window.' + f[i])) {
+                       var a = getFuncArgs(f[i], true);
+                       if (a.length==0) {
+                               var s = getFuncCode(f[i], "hpClick(3);", '', true);
+                               eval('window.' + f[i] + '=new Function(' + getArgsStr(a) + 's);');
+                               break; // out of the loop
+                       }
+               }
+       }
+}
+// ***************
+//  fix IE5 and NS6
+// ***************
+// add Array.push if required (allows v6 quizzes to run on ie5win)
+if (Array.prototype && Array.prototype.push==null) {
+       Array.prototype.push = new Function("x", "this[this.length]=x");
+}
+// add attachEvent function, if required (allows HP5 v6 quizzes to run on ie5mac)
+//     NOTE: to allow v6 quizzes on ie5mac, the following code 
+//     needs to be inserted BEFORE the Hot Potatoes javascript
+if (window.attachEvent==null) {
+       window.attachEvent = new Function('evt', 'fn', 'eval("window."+evt+"="+fn)');
+}
+if (document.attachEvent==null) {
+       document.attachEvent = new Function('evt', 'fn', 'eval("document."+evt+"="+fn)');
+}
+// fix the ShowMessage function for NS6
+// by removing calls to a button's "focus()" method
+if (navigator.userAgent.indexOf("Netscape6")>=0 && window.ShowMessage) {
+       var s = ShowMessage.toString();
+       var r = new RegExp('document\\.getElementById\\((\'|")FeedbackOKButton(\'|")\\)\\.focus\\(\\);', 'gi');
+       s = s.substring(s.indexOf('{')+1, s.lastIndexOf('}')).replace(r, '');
+       window.ShowMessage = new Function('Feedback', s);
+}
+// ns6.0 (in JMix at least) has an error in the FocusAButton function too
+// this could be fixed as follows ...
+//if (window.FocusAButton) {
+//     window.FocusAButton = new Function('return true');
+//}
+// however, ns6.0 then crashes completely when the mouse moves over a link, so don't bother
+// Hot Potatoes quiz sniffing
+// === v3 ===
+// JBC uses "QuizForm", which contains elements called "Q*_**" (* and ** start at 1)
+// JCloze uses "Cloze" form
+// JCross uses "Crossword" form
+// JMatch uses "QuizForm", which contains elements called "1,2,3..x" and "x+1,x+2...",
+//     and "CheckForm" form, which contains an element called "ScoreBox"
+//     it is also the only HP quiz type to use an array called "CorrectAnswers"
+// JQuiz uses "QForm*" forms (* starts at 1), which each contain an element called "Guess"
+// === v4 ===
+// JBC uses "QForm" form in "QuestionDiv", which contains elements called "FB* (* starts at 0)"
+// JCloze uses "Cloze" form in "QuestionDiv"
+// JCross uses "Crossword" form in "CWDiv"
+// JMatch uses "ExCheck" form in "TitleDiv"
+// (no JMix in hp4)
+// JQuiz uses "QForm" form in "QuestionDiv", which contains an element called "Answer"
+// === v5 ===
+// JBC uses "QForm" form, which contains elements called "FB_*_**" (* and ** start at 0)
+// JCloze uses "Cloze" form
+// JCross writes out "AnswerForm" from a variable called "GetAnswerOpener"
+//     HP5.3: uses "AnswerForm" in "BottomFrame" 
+//     HP5.5: uses "AnswerForm" in "TopFrame", but it is only there when an answer is being input
+// JMatch uses "QForm" form, which contains elements called "sel*" (which disappear by the time the quiz is finished)
+// JMix uses "ButtonForm"
+// JQuiz uses "QForm*" and "Buttons*" (one for each question)
+// === v6 ===
+// JBC uses "QForm" form (elements have no name or id)
+// JCloze uses "Cloze" form (elements have no name or id)
+// JCross does not use any forms, 
+//     HP5: has "GridDiv" in "MainDiv"
+//     HP6: has "Clues" table in "MainDiv"
+// JMatch has "MatchDiv" in "MainDiv"
+//     HP5: uses "QForm" form, which contains elements called "sel*"
+//     HP6: uses "QForm" form, which contains elements called "s*_**"
+// JMix does not use any forms, but has "SegmentDiv" in "MainDiv"
+// JQuiz 
+//     HP5: uses "QForm" form, which contains an element called "Guess"
+//     HP6: has "Questions" ordered list in "MainDiv"
+// === v6+ ===
+// JMatch has DIVs called "D*" and  "F*" (* starts at 0)
+// JMix has DIVs called "D*" and  "Drop*" (* starts at 0)
+// useful sniffing tools (Cut and Paste to browser address box)
+//javascript:var s="";var x=new quiz_obj();for(X in x)s+=","+X+"="+x[X];alert(s.substring(1));
+//javascript:var s="";var x=document.layers;for(var i=0;i<x.length;i++)s+=","+x[i].name;alert(s.substring(1))
+//javascript:var s="";var x=document.forms;for(var i=0;i<x.length;i++)s+=","+x[i].id;alert(s.substring(1))
+//javascript:var s="";var x=document.forms;for(var i=0;i<x.length;i++)s+=","+x[i].name;alert(s.substring(1))
+//javascript:var s="";var x=document.forms.QForm.elements;for(var i=0;i<x.length;i++)s+=","+x[i].id;alert(s.substring(1))
+//javascript:var s="";var x=document.forms.QForm.elements;for(var i=0;i<x.length;i++)s+=","+x[i].name;alert(s.substring(1))
+function hpDetectQuiz() {
+       // "sniff" (=detect) the quiz's type and intended browser version
+       // and cache the values in a global variable called "quiz"
+       // Hot Potatoes version
+       //      5 : HP5.3 (mac) or HP5.5 (win)
+       //      6 : HP6.0 (mac) or HP6.0 (win)
+       // intended browser version
+       //      3   : ns3, ie3 (frames)
+       //      4   : ns4, ie4 (cross browser dhtml)
+       //      5   : ie5 (frames, send results via CGI)
+       //      6   : ie6, op7, gecko (w3 standards)
+       //      6.1 : "drag and drop" versions of JMatch and JMix v6
+       // quiz type
+       //      0 : unknown
+       //      1 : jbc
+       //      2 : jcloze
+       //      3 : jcross
+       //      4 : jmatch
+       //      5 : jmix
+       //      6 : jquiz
+       //      7 : rhubarb (TexToys)
+       //      8 : Sequitur (TexToys)
+       // rottmeier quiz type
+       //      1 : drop-down (JCloze)
+       //      2 : find-it (JCloze)
+       // shortcut to window object
+       var w = window;
+       // create the global "quiz" object, if necessary
+       if (!w.quiz) w.quiz = new Object();
+       // Hot Potatoes version
+       //      HP6 v6:    Client()
+       //      HP5 v4-v5: BrowserCheck()
+       //          v3:    WinStringToMac() [JCloze, JCross, JQuiz]
+       //          v3:    winrightchar     [JBC, JMatch]
+       //          v3:    DownTime()       [JBC, JCloze, JQuiz]
+       if (!quiz.hp) {
+               quiz.hp = (w.Client) ? 6 : (w.BrowserCheck) ? 5 : (w.WinStringToMac || w.winrightchar) ? 5 : -1;
+       }
+       // check the version and type are not already set
+       if (!quiz.v || !quiz.t) {
+               // initialize version and type
+               var v = 0;
+               var t = 0;
+               // set shortcuts to DOM objects
+               var d = document;
+               var f = d.forms;
+               if (f.QuizForm && f.CheckForm && w.CorrectAnswers) {
+                       v = 3;
+                       t = 4; // jmatch
+               } else if (w.FeedbackFrame && w.CodeFrame) {
+                       v = 3;
+                       f = CodeFrame.document.forms;
+                       t = (f.QuizForm) ? 1 : (f.Cloze) ? 2 : (f.Crossword) ? 3 : (f.QForm1) ? 6 : 0;
+               } else if (w.DynLayer) {
+                       v = 4;
+                       if (d.layers) {
+                               // for NS4, adjust "f" to point to a forms object in a layer
+                               var lyr = d.QuestionDiv || d.CWDiv || d.TitleDiv || null;
+                               if (lyr) f = lyr.document.forms;
+                       }
+                       t = (f.QForm && f.QForm.FB0) ? 1 : (f.Cloze) ? 2 : (f.Crossword) ? 3 : (f.ExCheck) ? 4 : (f.QForm && f.QForm.Answer) ? 6 : 0;
+               } else if (w.TopFrame && w.BottomFrame) {
+                       v = 5;
+                       f = BottomFrame.document.forms;
+                       t = (f.QForm && f.QForm.elements[0].name.substring(0,3)=='FB_') ? 1 : (f.Cloze) ? 2 : (w.GetAnswerOpener && GetAnswerOpener.indexOf('AnswerForm')>=0) ? 3 : (f.QForm && w.RItems) ? 4 : (f.ButtonForm) ? 5 : (f.QForm0 && f.Buttons0) ? 6 : 0;
+               } else if (hpObj(d, 'MainDiv')) {
+                       v = 6;
+                       var obj = (f.QForm) ? f.QForm.elements : null;
+                       t = (obj && obj.length>0 && obj[0].id=='') ? 1 : (f.Cloze) ? 2 : (hpObj(d, 'GridDiv') || hpObj(d, 'Clues')) ? 3 : hpObj(d, 'MatchDiv') ? 4 : hpObj(d, 'SegmentDiv') ? 5 : ((f.QForm && f.QForm.Guess) || hpObj(d, 'Questions')) ? 6 : 0;
+               } else if (hpObj(d, 'D0')) {
+                       v = 6.1; // drag and drop (HP5 and HP6)
+                       t = (hpObj(d, 'F0')) ? 4 : (hpObj(d, 'Drop0')) ? 5 : 0;
+               } else if (w.Words && f.Rhubarb) {
+                       v = 6;
+                       t = 7; // rhubarb (TexToys)
+               } else if (w.Segments && hpObj(d, 'Story')) {
+                       v = 6;
+                       t = 8; // sequitur (TexToys)
+               }
+               quiz.v = v; // intended browser version
+               quiz.t = t; // quiz type
+       }
+}
+function hpRottmeier() {
+       hpDetectQuiz();
+       if (typeof(quiz.r)=='undefined') { // first-time only
+               quiz.r = 0;
+               if (quiz.t==2) { // JCloze
+                       if (quiz.hp==5) { // HP5
+                               // ??
+                       } else if (quiz.hp==6) { // HP6
+                               if (window.Create_StateArray) { // Rottmeier
+                                       var obj = new Create_StateArray();
+                                       if (typeof(obj.GapLocked)=='boolean') {
+                                               quiz.r = 1; // drop-down (v2.4)
+                                       } else if (typeof(obj.ErrorFound)=='boolean') {
+                                               if (typeof(obj.GapSolved)!='boolean') {
+                                                       quiz.r = 2.1; // find-it (v3.1a)
+                                               } else {
+                                                       quiz.r = 2.2; // find-it (v3.1b)
+                                               }
+                                       }
+                                       obj = null; // prevents memory leakage on some versions of IE
+                               }
+                       }
+               }
+       }
+       return quiz.r;
+}
+function hpVersion() {
+       hpDetectQuiz();
+       return quiz.hp;
+}
+function hpQuizType() {
+       hpDetectQuiz();
+       return quiz.t;
+}
+function hpQuizVersion() {
+       hpDetectQuiz();
+       return quiz.v;
+}
+function hpScoreEngine(score_i, a, s, aa, ss, count_c, count_i) {
+       // calculate the score for the quiz so far
+       // score_i : amount by which to increment "score"
+       // a  : outer array
+       // s  : condition, if any, on outer array (=a)
+       //      if true, the score will be incremented by "score_i"
+       // aa : inner array, if any
+       // ss : condition, if any, on inner array (=aa)
+       // count_c : condition, if any, on which "count" is to be incremented
+       // count_i : amount by which to increment "count"
+       // "a" and "aa" may be passed as arrays or strings containing the name of an array
+       // "s" and "ss" are strings containing an expression to be eval(uated)
+       // "score_i", "count_i" and "count_c" strings containing an expression to be eval(uated)
+       var score = 0;
+       var count = 0;
+       // set default condition to increment "count", and amount by which to increment the count
+       if (count_c==null) count_c = "true";
+       if (count_i==null) count_i = "1";
+       // set length of outer array. if any
+       var l = (typeof(a)=="string") ? eval(a + ".length") : a ? a.length : 0;
+       // loop through outer array
+       for (var i=0; i<l; i++) {
+               if (s==null && ss==null) {
+                       score += eval(score_i);
+                       if (eval(count_c)) count += eval(count_i);
+               } else if (s) {
+                       score += eval(s) ? eval(score_i) : 0;
+                       if (eval(count_c)) count += eval(count_i);
+               } else if (ss) {
+                       // set length of inner array, if any
+                       var ll = (typeof(aa)=="string") ? eval(aa + ".length") : aa ? aa.length : 0;
+                       // loop through inner array. checking inner condition
+                       for (var ii=0; ii<ll; ii++) {
+                               score += eval(ss) ? eval(score_i) : 0;
+                               if (eval(count_c)) count += eval(count_i);
+                       }
+               }
+       }
+       if (count) {
+               // get p(enalties) for JCross and JMatch (and JMix ?)
+               if (window.Penalties) {
+                       score -= (Penalties - (hpFinished() ? 0 : 1));
+               }
+               // adjust count for Find-It 3a and 3b
+               if (window.TotWrongChoices) {
+                       if (window.CheckText && !window.CheckAnswers) { // Find-It 3a
+                               // this seems a little odd, but will replicate behavior of CalculateScore()
+                               count = score + TotWrongChoices;
+                       } else {
+                               count += TotWrongChoices;
+                       }
+               }
+               score = Math.floor(100*score/count);
+               if (score<0) { // just in case
+                       score = 0;
+               }
+       }
+       return score;
+}
+function hpScore() {
+       var x = ''; // score
+       var hp = hpVersion();
+       var t = hpQuizType();
+       var v = hpQuizVersion();
+       if (t==1) { // jbc
+               if (v==3) x = hpScoreEngine(1, DoneStatus, "i>0 && a[i]=='0'"); // doesn't work
+               else if (v==4) x = hpScoreEngine(1, DoneStatus, "a[i]==0");    // doesn't work
+               else if (v==5 || v==6) x = hpScoreEngine("a[i][3]", Status, "a[i][3]");
+       } else if (t==2) { // jcloze
+               if (v==3 || v==4) x = hpScoreEngine("a[i]", Scores);
+               else if (hp==5) x = hpScoreEngine("a[i][3]", State); // v==5 && v==6
+               else if (hp==6) {
+                       var r = hpRottmeier();
+                       if (r==0) x = x = hpScoreEngine("a[i].ItemScore", State);
+                       else if (r==1) x = hpScoreEngine("a[i][1].Score", GapList, "a[i][1].GapLocked"); // dropdown
+                       else if (r==2.1) x = hpScoreEngine(1, GapList, "a[i][1].ErrorFound"); // Find-It 3a
+                       else if (r==2.2) x = hpScoreEngine("a[i][1].Score", GapList, "a[i][1].GapSolved"); // Find-It 3b
+               }
+       } else if (t==3) { // jcross
+               if (v==3) x = hpScoreEngine(1, CorrectAnswers, "document.QuizForm.elements[i*2].selectedIndex==a[i]");
+               else if (v==4) x = hpScoreEngine(1, WinLetters, "ConvertCase(GetBoxValue(i),1).charAt(0)==a[i].charAt(0)");
+               else if (v==5 || v==6) x = hpScoreEngine(1, L, "", "L[i]", "L[i][ii] && L[i][ii]==G[i][ii]", "L[i][ii]");
+       } else if (t==4) { // jmatch
+               if (v==3) x = hpScoreEngine(1, CorrectAnswers, "document.QuizForm.elements[i*2].selectedIndex==a[i]");
+               else if (v==4) x = hpScoreEngine(1, Draggables, "a[i].correct=='1'");
+               else if (v==5) x = hpScoreEngine(1, I, "I[i][2]<1 && I[i][0].length>0 && Status[i][0]==1");
+               else if (v==6) x = hpScoreEngine(1, Status, "Status[i][0]==1");
+               else if (v==5.1 || v==6.1) x = hpScoreEngine(1, D, "D[i][2]==D[i][1] && D[i][2]>0", "", "", "i<F.length");
+       } else if (t==5) { // jmix
+               // there was no v3 or v4 of JMix
+               if (v==5 || v==6 || v==6.1) x = Math.floor(100*(Segments.length-Penalties)/Segments.length);
+       } else if (t==6) { // jquiz
+               if (hp==5) {
+                       if (v==3 || v==4) x = hpScoreEngine("a[i][4]/10", State, "a[i][0]==1");
+                       else if (v==5 || v==6) x = hpScoreEngine("a[i][4]/10", Status, "a[i][0]==1", "", "", "true", "1");
+               } else if (hp==6) {
+                       if (v==6) x = hpScoreEngine("I[i][0]*a[i][0]", State, "a[i]&&a[i][0]>=0", "", "", "a[i]", "I[i][0]");
+               }
+       } else if (t==7) { // rhubarb
+               if (v==6) {
+                       x = Math.floor(100*Correct/TotalWords);
+               }
+       } else if (t==8) { // sequitur
+               if (v==6) {
+                       var myTotalPoints = TotalPoints - (hpFinished() ? 0 : (OptionsThisQ-1));
+                       x = Math.floor(100*ScoredPoints/myTotalPoints);
+               }
+       }
+       return x; // result
+}
+function hpFinishedEngine(a, s, aa, ss) {
+       // determine whether or not all quistions in a quiz are finished
+       // a  : outer array
+       // s  : condition, if any, on outer array
+       //      if true for any element in "a", the quiz is NOT finished
+       // aa : inner array, if any
+       // ss : condition, if any, on inner array
+       //      if true for any element in "aa", the quiz is NOT finished
+       // the arrays "a" and "aa" may be passed as arrays or strings to be eval(uated)
+       // the conditions "s" and "ss" are specified as strings to be eval(uated)
+       // assume a positive result
+       var x = true;
+       // set length of outer array. if any
+       var l = (typeof(a)=="string") ? eval(a + ".length") : a ? a.length : 0;
+       // loop through outer array
+       for (var i=0; i<l; i++) {
+               // do outer condition, if any
+               if (s && eval(s)) x = false;
+               // set length of inner array, if any
+               var ll = (typeof(aa)=="string") ? eval(aa + ".length") : aa ? aa.length : 0;
+               // loop through inner array. checking inner condition
+               for (var ii=0; ii<ll; ii++) {
+                       if (ss && eval(ss)) x = false;
+               }
+       }
+       return x;
+}
+function hpTimedOut() {
+       // v5 uses "min" and "sec"
+       // v6 uses Seconds
+       return (typeof(self.Seconds)=='number' && Seconds==0) || (typeof(self.min)=='number' && min==0 && typeof(self.sec)=='number' && sec==0);
+}
+function hpFinished() {
+       // assume false result
+       var x = false; 
+       var hp = hpVersion();
+       var t = hpQuizType();
+       var v = hpQuizVersion();
+       if (t==1) { // jbc
+               if (v==3) x = hpFinishedEngine(DoneStatus, "i>0 && a[i]=='0'");
+               else if (v==4) x = hpFinishedEngine(DoneStatus, "a[i]==0");
+               else if (v==5 || v==6) x = hpFinishedEngine(Status, "a[i][0]==0");
+       } else if (t==2) { // jcloze
+               var r = hpRottmeier();
+               if (r==1) x = hpFinishedEngine(GapList, "a[i][1].GapLocked==false"); // drop-down
+               else if (r==2.1) x = hpFinishedEngine(GapList, "a[i][1].ErrorFound==false"); // find-it 3a
+               else if (r==2.2) x = hpFinishedEngine(GapList, "a[i][1].GapSolved==false"); // find-it 3b
+               else if (v==3 || v==4 || v==5 || v==6) x = hpFinishedEngine(I, "CheckAnswer(i)==-1");
+               // also:   else if (v==5 || v==6) x = hpFinishedEngine(State, "a[i][4]!=1")
+       } else if (t==3) { // jcross
+               if (v==3) x = hpFinishedEngine(document.Crossword.elements, "ConvertCase(is.mac?unescape(MacStringToWin(a[i].value)):a[i].value,1)!=Letters[i]");
+               else if (v==4) x = hpFinishedEngine(WinLetters, "ConvertCase(GetBoxValue(i),1).charAt(0) != a[i].charAt(0)");
+               else if (v==5 || v==6) x = hpFinishedEngine(L, "", "L[i]", "L[i][ii] && L[i][ii]!=G[i][ii]");
+       } else if (t==4) { // jmatch
+               if (v==3) x = hpFinishedEngine(CorrectAnswers, "document.QuizForm.elements[i*2].selectedIndex != a[i]");
+               else if (v==4) x = hpFinishedEngine(Draggables, "a[i].correct!='1'");
+               else if (v==5) x = hpFinishedEngine(I, "I[i][2]<1 && I[i][0].length>0 && Status[i][0]<1 && GetAnswer(i)!=I[i][3]");
+               else if (v==6) x = hpFinishedEngine(Status, "Status[i][0]<1");
+               else if (v==5.1 || v==6.1) x = hpFinishedEngine(D, "", F, "F[ii][1]==D[i][1]&&D[i][1]!=D[i][2]");
+       } else if (t==5) { // jmix
+               // there was no v3 or v4 of JMix
+               if (v==5 || v==6 || v==6.1) x = !hpFinishedEngine(Answers, "a[i].join(',')=='" + GuessSequence.join(',') + "'");
+       } else if (t==6) { // jquiz
+               if (v==3 || v==4) x = hpFinishedEngine(State, "a[i][0]==0");
+               else if (v==5 || v==6) {
+                       if (hp==5) x = hpFinishedEngine(Status, "a[i][0]<1");
+                       else if (hp==6) x = hpFinishedEngine(State, "a[i] && a[i][0]<0");
+               }
+       } else if (t==7) { // rhubarb
+               if (v==6) x = hpFinishedEngine(DoneList, "a[i]==1");
+       } else if (t==8) { // sequitur
+               if (v==6) x = (CurrentNumber==TotalSegments || AllDone);
+       }
+       return x;
+}
+function hpObj(d, id) {
+       return d.getElementById ? d.getElementById(id) : d.all ? d.all[id] : d[id];
+}
+function GetViewportHeight() {
+       if (window.innerHeight) {
+               return innerHeight;
+       } else {
+               if (hpIsStrict()) {
+                       return document.documentElement.clientHeight;
+               } else {
+                       return document.body.clientHeight;
+               }
+       }
+}
+function hpIsStrict() {
+       if (!window.hpStrictIsSet) {
+               window.hpStrictIsSet = true;
+               window.hpStrict = false;
+               var s = document.compatMode;
+               if (s && s=="CSS1Compat") { // ie6
+                       window.hpStrict = true;
+               } else {
+                       var obj = document.doctype;
+                       if (obj) {
+                               var s = obj.systemId || obj.name; // n6 || ie5mac
+                               if (s && s.indexOf("strict.dtd") >= 0) {
+                                       window.hpStrict = true;
+                               }
+                       }
+               }
+       }
+       return window.hpStrict;
+}
+// **************
+//  initialization
+// **************
+hpInterceptFeedback();
+hpInterceptHints();
+hpInterceptClues();
+hpInterceptChecks();
+function hpFindForm(formname, w) {
+       if (w==null) w = self;
+       var f = w.document.forms[formname];
+       if (f==null && w.frames) {
+               for (var i=0; i<w.frames.length; i++) {
+                               f = hpFindForm(formname, w.frames[i]);
+                               if (f) break;
+               }
+       }
+       return f;
+}
+function Finish(quizstatus) {
+       var mark = hpScore();
+       window.hpForm = hpFindForm('store');
+       if (hpForm) { // LMS
+               hpForm.starttime.value = getTime(Start_Time);
+               hpForm.endtime.value = getTime();
+               hpForm.mark.value = mark;
+               hpForm.detail.value = '<?xml version="1.0"?><hpjsresult><fields>'+GetQuestionDetails()+'</fields></hpjsresult>';
+               if (hpForm.status) {
+                       if (!quizstatus) {
+                               // 4=completed, 3=abandoned, 2=timed-out or 1=in-progress
+                               quizstatus = hpFinished() ? 4 : hpTimedOut() ? 2 : 1;
+                       }
+                       hpForm.status.value = quizstatus;
+               }
+               if (!window.hpQuizResultsSent) {
+                       if (hpForm.status && quizstatus==4) {
+                               window.hpQuizResultsSent = true;
+                       }
+                       if (quizstatus==4) { // completed
+                               // wait 2 seconds for student to see feedback
+                               setTimeout("hpForm.submit();", 2000);
+                       } else {
+                               hpForm.submit();
+                       }
+               }
+       } else if (hpFinished()) {
+               SendAllResults(mark);
+       }
+}
+// create form to send results
+if (DB[7] && DB[8] && !is_LMS()) { 
+       ResultForm = ''
+               + '<html><body>'
+               + '<form name="Results" action="" method="post" enctype="x-www-form-encoded">'
+               +       hpHiddenField('recipient', '')
+               +       hpHiddenField('subject', '')
+               +       hpHiddenField('Exercise', '')
+               +       hpHiddenField('realname', '')
+               +       hpHiddenField('Score', '')
+               +       hpHiddenField('Start_Time', '')
+               +       hpHiddenField('End_Time', '')
+               +       hpHiddenField('title', 'Thanks!')
+               + '</form>'
+               + '</body></html>'
+       ;
+}
+// reassign the StartUp function
+var p = getPrompt(window.GetUserName || window.StartUp);
+var c = getStartUpCode(window.StartUp);
+if (p && c) {
+       window.StartUp = new Function('QuizLogin("' + p + '")');
+       window.StartQuiz = new Function(c);
+       // "QuizLogin" finshes by calling "StartQuiz"
+}
+// reassign the SendResults function
+window.SendResults = SendAllResults;
+// set start time
+var Start_Time = new Date();
+//-->
index 9ca0dc58a314b41e7064d7d069df16a8148eaa89..f3428e6f0597d33f0f9840818711b1b858699bb6 100644 (file)
-<?php  // $Id$\r
-/// Overview report just displays a big table of all the attempts\r
-class hotpot_report extends hotpot_default_report {\r
-       function display(&$hotpot, &$cm, &$course, &$users, &$attempts, &$questions, &$options) {\r
-               global $CFG;\r
-               // create the tables\r
-               $tables = array();\r
-               $this->create_clickreport_table($hotpot, $cm, $course, $users, $attempts, $questions, $options, $tables);\r
-               // print the tables\r
-               $this->print_report($course, $hotpot, $tables, $options);\r
-               return true;\r
-       }\r
-       function create_clickreport_table(&$hotpot, &$cm, &$course, &$users, &$attempts, &$questions, &$options, &$tables) {\r
-               global $CFG;\r
-               $is_html = ($options['reportformat']=='htm');\r
-               // time and date format strings         // date format strings\r
-               $strftimetime = '%H:%M:%S';\r
-               $strftimedate = get_string('strftimedate');\r
-               // get the current time and max execution time\r
-               $start_report_time = microtime();\r
-               $max_execution_time = ini_get('max_execution_time');\r
-               $correct = get_string('reportcorrectsymbol', 'hotpot');\r
-               $wrong = get_string('reportwrongsymbol', 'hotpot');\r
-               $nottried = get_string('reportnottriedsymbol', 'hotpot');\r
-               // shortcuts for font tags\r
-               $blank = $is_html ? '&nbsp;' : "";\r
-               // store question count\r
-               $questioncount = count($questions);\r
-               // array to map columns onto question ids ($col => $id)\r
-               $questionids = array_keys($questions);\r
-               // store exercise type\r
-               $exercisetype = $this->get_exercisetype($questions, $questionids, $blank);\r
-               // initialize details ('events' must go last)\r
-               $details = array('checks', 'status', 'answers', 'changes', 'hints', 'clues', 'events');\r
-               // initialize $table\r
-               unset($table);\r
-               $table->border = 1;\r
-               $table->width = '100%';\r
-               // initialize legend, if necessary\r
-               if (!empty($options['reportshowlegend'])) {\r
-                       $table->legend = array();\r
-               }\r
-               // start $table headings\r
-               $this->set_head($options, $table, 'exercise');\r
-               $this->set_head($options, $table, 'user');\r
-               $this->set_head($options, $table, 'attempt');\r
-               $this->set_head($options, $table, 'click');\r
-               // store clicktype column number\r
-               $clicktype_col = count($table->head)-1;\r
-               // finish $table headings\r
-               $this->set_head($options, $table, 'details', $exercisetype, $details, $questioncount);\r
-               $this->set_head($options, $table, 'totals', $exercisetype);\r
-               // set align and wrap\r
-               $this->set_align_and_wrap($table);\r
-               // is link to review allowed?\r
-               $allow_review = ($is_html && (has_capability('mod/hotpot:viewreport',get_context_instance(CONTEXT_COURSE, $course->id)) || $hotpot->review));\r
-               // initialize array of data values\r
-               $this->data = array();\r
-               // set exercise data values\r
-               $this->set_data_exercise($cm, $course, $hotpot, $questions, $questionids, $questioncount, $blank);\r
-               // add details of users' responses\r
-               foreach ($users as $user) {\r
-                       $this->set_data_user($options, $course, $user);\r
-                       unset($clickreportid);\r
-                       foreach ($user->attempts as $attempt) {\r
-                               // initialize totals for\r
-                               $click = array(\r
-                                       'qnumber' => array(),\r
-                                       'correct' => array(),\r
-                                       'wrong' => array(),\r
-                                       'answers' => array(),\r
-                                       'hints' => array(),\r
-                                       'clues' => array(),\r
-                                       'changes' => array(),\r
-                                       'checks' => array(),\r
-                                       'events' => array(),\r
-                                       'score' => array(),\r
-                                       'weighting' => array()\r
-                               );\r
-                               $clicktypes = array();\r
-                               // is the start of a new attempt?\r
-                               // (clicks in the same attempt have the same clickreportid)\r
-                               if (!isset($clickreportid) || $clickreportid != $attempt->clickreportid) {\r
-                                       $clickcount = 1;\r
-                                       $clickreportid = $attempt->clickreportid;\r
-                                       // initialize totals for all clicks in this attempt\r
-                                       $clicks = $click; // $click has just been initialized\r
-                                       $this->set_data_attempt($attempt, $strftimedate, $strftimetime, $blank);\r
-                               }\r
-                               $cells = array();\r
-                               $this->set_data($cells, 'exercise');\r
-                               $this->set_data($cells, 'user');\r
-                               $this->set_data($cells, 'attempt');\r
-                               // get responses to questions in this attempt\r
-                               foreach ($attempt->responses as $response) {\r
-                                       // set $q(uestion number)\r
-                                       $q = array_search($response->question, $questionids);\r
-                                       $click['qnumber'][$q] = true;\r
-                                       // was this question answered correctly?\r
-                                       if ($answer = hotpot_strings($response->correct)) {\r
-                                               // mark the question as correctly answered\r
-                                               if (empty($clicks['correct'][$q])) {\r
-                                                       $click['correct'][$q] = true;\r
-                                                       $clicks['correct'][$q] = true;\r
-                                               }\r
-                                               // unset 'wrong' flags, if necessary\r
-                                               if (isset($click['wrong'][$q])) {\r
-                                                       unset($click['wrong'][$q]);\r
-                                               }\r
-                                               if (isset($clicks['wrong'][$q])) {\r
-                                                       unset($clicks['wrong'][$q]);\r
-                                               }\r
-                                       // otherwise, was the question answered wrongly?\r
-                                       } else if ($answer = hotpot_strings($response->wrong)) {\r
-                                               // mark the question as wrongly answered\r
-                                               $click['wrong'][$q] = true;\r
-                                               $clicks['wrong'][$q] = true;\r
-                                       } else { // not correct or wrong (curious?!)\r
-                                               unset($answer);\r
-                                       }\r
-                                       if (!empty($click['correct'][$q]) || !empty($click['wrong'][$q])) {\r
-                                               $click['score'][$q] = $response->score;\r
-                                               $clicks['score'][$q] = $response->score;\r
-                                               $weighting = isset($response->weighting) ? $response->weighting : 100;\r
-                                               $click['weighting'][$q] = $weighting;\r
-                                               $clicks['weighting'][$q] =$weighting;\r
-                                       }\r
-                                       foreach($details as $detail) {\r
-                                               switch ($detail) {\r
-                                                       case 'answers':\r
-                                                               if (isset($answer) && is_string($answer) && !empty($answer)) {\r
-                                                                       $click[$detail][$q] = $answer;\r
-                                                               }\r
-                                                               break;\r
-                                                       case 'hints':\r
-                                                       case 'clues':\r
-                                                       case 'checks':\r
-                                                               if (isset($response->$detail) && is_numeric($response->$detail) && $response->$detail>0) {\r
-                                                                       if (!isset($click[$detail][$q]) || $click[$detail][$q] < $response->$detail) {\r
-                                                                               $click[$detail][$q] = $response->$detail;\r
-                                                                       }\r
-                                                               }\r
-                                                               break;\r
-                                               }\r
-                                       } // end foreach $detail\r
-                               } // end foreach $response\r
-                               $click['types'] = array();\r
-                               $this->data['details'] = array();\r
-                               foreach($details as $detail) {\r
-                                       for ($q=0; $q<$questioncount; $q++) {\r
-                                               switch ($detail) {\r
-                                                       case 'status':\r
-                                                               if (isset($clicks['correct'][$q])) {\r
-                                                                       $this->data['details'][] = $correct;\r
-                                                               } else if (isset($clicks['wrong'][$q])) {\r
-                                                                       $this->data['details'][] = $wrong;\r
-                                                               } else if (isset($click['qnumber'][$q])) {\r
-                                                                       $this->data['details'][] = $nottried;\r
-                                                               } else { // this question did not appear in this attempt\r
-                                                                       $this->data['details'][] = $blank;\r
-                                                               }\r
-                                                               break;\r
-                                                       case 'answers':\r
-                                                       case 'hints':\r
-                                                       case 'clues':\r
-                                                       case 'checks':\r
-                                                               if (!isset($clicks[$detail][$q])) {\r
-                                                                       if (!isset($click[$detail][$q])) {\r
-                                                                               $this->data['details'][] = $blank;\r
-                                                                       } else {\r
-                                                                               $clicks[$detail][$q] = $click[$detail][$q];\r
-                                                                               if ($detail=='answers') {\r
-                                                                                       $this->set_legend($table, $q, $click[$detail][$q], $questions[$questionids[$q]]);\r
-                                                                               }\r
-                                                                               $this->data['details'][] = $click[$detail][$q];\r
-                                                                               $this->update_event_count($click, $detail, $q);\r
-                                                                       }\r
-                                                               } else {\r
-                                                                       if (!isset($click[$detail][$q])) {\r
-                                                                               $this->data['details'][] = $blank;\r
-                                                                       } else {\r
-                                                                               $difference = '';\r
-                                                                               if ($detail=='answers') {\r
-                                                                                       if ($click[$detail][$q] != $clicks[$detail][$q]) {\r
-                                                                                               $pattern = '/^'.preg_quote($clicks[$detail][$q], '/').',/';\r
-                                                                                               $difference = preg_replace($pattern, '', $click[$detail][$q], 1);\r
-                                                                                       }\r
-                                                                               } else { // hints, clues, checks\r
-                                                                                       if ($click[$detail][$q] > $clicks[$detail][$q]) {\r
-                                                                                               $difference = $click[$detail][$q] - $clicks[$detail][$q];\r
-                                                                                       }\r
-                                                                               }\r
-                                                                               if ($difference) {\r
-                                                                                       $clicks[$detail][$q] = $click[$detail][$q];\r
-                                                                                       $click[$detail][$q] = $difference;\r
-                                                                                       if ($detail=='answers') {\r
-                                                                                               $this->set_legend($table, $q, $difference, $questions[$questionids[$q]]);\r
-                                                                                       }\r
-                                                                                       $this->data['details'][] = $difference;\r
-                                                                                       $this->update_event_count($click, $detail, $q);\r
-                                                                               } else {\r
-                                                                                       unset($click[$detail][$q]);\r
-                                                                                       $this->data['details'][] = $blank;\r
-                                                                               }\r
-                                                                       }\r
-                                                               }\r
-                                                               break;\r
-                                                       case 'changes':\r
-                                                       case 'events':\r
-                                                               if (empty($click[$detail][$q])) {\r
-                                                                       $this->data['details'][] = $blank;\r
-                                                               } else {\r
-                                                                       $this->data['details'][] = $click[$detail][$q];\r
-                                                               }\r
-                                                               break;\r
-                                                       default:\r
-                                                               // do nothing\r
-                                                               break;\r
-                                               } // end switch\r
-                                       } // for $q\r
-                               } // foreach $detail\r
-                               // set data cell values for\r
-                               $this->set_data_click(\r
-                                       $allow_review ? '<a href="review.php?hp='.$hotpot->id.'&attempt='.$attempt->id.'">'.$clickcount.'</a>' : $clickcount,\r
-                                       trim(userdate($attempt->timefinish, $strftimetime)),\r
-                                       $exercisetype,\r
-                                       $click\r
-                               );\r
-                               $this->set_data($cells, 'click');\r
-                               $this->set_data($cells, 'details');\r
-                               $this->set_data_totals($click, $clicks, $questioncount, $blank, $attempt);\r
-                               $this->set_data($cells, 'totals');\r
-                               $table->data[] = $cells;\r
-                               $clickcount++;\r
-                       } // end foreach $attempt\r
-                        // insert 'tabledivider' between users\r
-                       $table->data[] = 'hr';\r
-               } // end foreach $user\r
-               // remove final 'hr' from data rows\r
-               array_pop($table->data);\r
-               if ($is_html && $CFG->hotpot_showtimes) {\r
-                       $count = count($users);\r
-                       $duration = sprintf("%0.3f", microtime_diff($start_report_time, microtime()));\r
-                       print "$count users processed in $duration seconds (".sprintf("%0.3f", $duration/$count).' secs/user)<hr size="1" noshade="noshade" />'."\n";\r
-               }\r
-               $tables[] = &$table;\r
-               $this->create_legend_table($tables, $table);\r
-       } // end function\r
-       function get_exercisetype(&$questions, &$questionids, &$blank) {\r
-               if (empty($questions)) {\r
-                       $type = $blank;\r
-               } else {\r
-                       switch ($questions[$questionids[0]]->type) {\r
-                               case HOTPOT_JCB:\r
-                                       $type = "JCB";\r
-                                       break;\r
-                               case HOTPOT_JCLOZE :\r
-                                       $type = "JCloze";\r
-                                       break;\r
-                               case HOTPOT_JCROSS :\r
-                                       $type = "JCross";\r
-                                       break;\r
-                               case HOTPOT_JMATCH :\r
-                                       $type = "JMatch";\r
-                                       break;\r
-                               case HOTPOT_JMIX :\r
-                                       $type = "JMix";\r
-                                       break;\r
-                               case HOTPOT_JQUIZ :\r
-                                       $type = "JQuiz";\r
-                                       break;\r
-                               case HOTPOT_TEXTOYS_RHUBARB :\r
-                                       $type = "Rhubarb";\r
-                                       break;\r
-                               case HOTPOT_TEXTOYS_SEQUITUR :\r
-                                       $type = "Sequitur";\r
-                                       break;\r
-                               default:\r
-                                       $type = $blank;\r
-                       }\r
-               }\r
-               return $type;\r
-       }\r
-       function set_head(&$options, &$table, $zone, $exercisetype='', $details=array(), $questioncount=0) {\r
-               if (empty($table->head)) {\r
-                       $table->head = array();\r
-               }\r
-               switch ($zone) {\r
-                       case 'exercise':\r
-                               array_push($table->head,\r
-                                       get_string('reportcoursename', 'hotpot'),\r
-                                       get_string('reportsectionnumber', 'hotpot'),\r
-                                       get_string('reportexercisenumber', 'hotpot'),\r
-                                       get_string('reportexercisename', 'hotpot'),\r
-                                       get_string('reportexercisetype', 'hotpot'),\r
-                                       get_string('reportnumberofquestions', 'hotpot')\r
-                               );\r
-                               break;\r
-                       case 'user':\r
-                               array_push($table->head,\r
-                                       get_string('reportstudentid', 'hotpot'),\r
-                                       get_string('reportlogindate', 'hotpot'),\r
-                                       get_string('reportlogintime', 'hotpot'),\r
-                                       get_string('reportlogofftime', 'hotpot')\r
-                               );\r
-                               break;\r
-                       case 'attempt':\r
-                               array_push($table->head,\r
-                                       get_string('reportattemptnumber', 'hotpot'),\r
-                                       get_string('reportattemptstart', 'hotpot'),\r
-                                       get_string('reportattemptfinish', 'hotpot')\r
-                               );\r
-                               break;\r
-                       case 'click':\r
-                               array_push($table->head,\r
-                                       get_string('reportclicknumber', 'hotpot'),\r
-                                       get_string('reportclicktime', 'hotpot'),\r
-                                       get_string('reportclicktype', 'hotpot')\r
-                               );\r
-                               break;\r
-                       case 'details':\r
-                               foreach($details as $detail) {\r
-                                       if ($exercisetype=='JQuiz' && $detail=='clues') {\r
-                                               $detail = 'showanswer';\r
-                                       }\r
-                                       $detail = get_string("report$detail", 'hotpot');\r
-                                       for ($i=0; $i<$questioncount; $i++) {\r
-                                               $str = get_string('questionshort', 'hotpot', $i+1);\r
-                                               if ($i==0 || $options['reportformat']!='htm') {\r
-                                                       $str = "$detail $str";\r
-                                               }\r
-                                               $table->head[] = $str;\r
-                                       }\r
-                               }\r
-                               break;\r
-                       case 'totals':\r
-                               $reportpercentscore =get_string('reportpercentscore', 'hotpot');\r
-                               if (!function_exists('clean_getstring_data')) { // Moodle 1.4 (and less)\r
-                                       $reportpercentscore = str_replace('%', '%%', $reportpercentscore);\r
-                               }\r
-                               array_push($table->head, \r
-                                       get_string('reportthisclick', 'hotpot', get_string('reportquestionstried', 'hotpot')),\r
-                                       get_string('reportsofar', 'hotpot', get_string('reportquestionstried', 'hotpot')),\r
-                                       get_string('reportthisclick', 'hotpot', get_string('reportright', 'hotpot')),\r
-                                       get_string('reportthisclick', 'hotpot', get_string('reportwrong', 'hotpot')),\r
-                                       get_string('reportthisclick', 'hotpot', get_string('reportnottried', 'hotpot')),\r
-                                       get_string('reportsofar', 'hotpot', get_string('reportright', 'hotpot')),\r
-                                       get_string('reportsofar', 'hotpot', get_string('reportwrong', 'hotpot')),\r
-                                       get_string('reportsofar', 'hotpot', get_string('reportnottried', 'hotpot')),\r
-                                       get_string('reportthisclick', 'hotpot', get_string('reportanswers', 'hotpot')),\r
-                                       get_string('reportthisclick', 'hotpot', get_string('reporthints', 'hotpot')),\r
-                                       get_string('reportthisclick', 'hotpot', get_string($exercisetype=='JQuiz' ? 'reportshowanswer' : 'reportclues', 'hotpot')),\r
-                                       get_string('reportthisclick', 'hotpot', get_string('reportevents', 'hotpot')),\r
-                                       get_string('reportsofar', 'hotpot', get_string('reporthints', 'hotpot')),\r
-                                       get_string('reportsofar', 'hotpot', get_string($exercisetype=='JQuiz' ? 'reportshowanswer' : 'reportclues', 'hotpot')),\r
-                                       get_string('reportthisclick', 'hotpot', get_string('reportrawscore', 'hotpot')),\r
-                                       get_string('reportthisclick', 'hotpot', get_string('reportmaxscore', 'hotpot')),\r
-                                       get_string('reportthisclick', 'hotpot', $reportpercentscore),\r
-                                       get_string('reportsofar', 'hotpot', get_string('reportrawscore', 'hotpot')),\r
-                                       get_string('reportsofar', 'hotpot', get_string('reportmaxscore', 'hotpot')),\r
-                                       get_string('reportsofar', 'hotpot', $reportpercentscore),\r
-                                       get_string('reporthotpotscore', 'hotpot')\r
-                               );\r
-                               break;\r
-               } // end switch\r
-       }\r
-       function set_align_and_wrap(&$table) {\r
-               $count = count($table->head);\r
-               for ($i=0; $i<$count; $i++) {\r
-                       if ($i==0 || $i==1 || $i==2 || $i==4 || $i==5 || $i>=7) {\r
-                               // numeric (and short text) columns\r
-                               $table->align[] = 'center';\r
-                               $table->wrap[] = '';\r
-                       } else {\r
-                               // text columns\r
-                               $table->align[] = 'left';\r
-                               $table->wrap[] = 'nowrap';\r
-                       }\r
-               }\r
-       }\r
-       function set_data_exercise(&$cm, &$course, &$hotpot, &$questions, &$questionids, &$questioncount, &$blank) {\r
-               // get exercise details (course name, section number, activity number, quiztype and question count)\r
-               $record = get_record("course_sections", "id", $cm->section);\r
-               $this->data['exercise'] = array(\r
-                       'course'  => $course->shortname,\r
-                       'section' => empty($record) ? $blank : $record->section+1,\r
-                       'number'  => empty($record) ? $blank : array_search($cm->id, explode(',', $record->sequence))+1,\r
-                       'name'    => $hotpot->name,\r
-                       'type'    => $this->get_exercisetype($questions, $questionids, $blank),\r
-                       'questioncount' => $questioncount\r
-               );\r
-       }\r
-       function set_data_user(&$options, &$course, &$user) {\r
-               global $CFG;\r
-               // shortcut to first attempt record (which also hold user info)\r
-               $attempt = &$user->attempts[0];\r
-               $idnumber = $attempt->idnumber;\r
-               if (empty($idnumber)) {\r
-                       $idnumber = fullname($attempt);\r
-               }\r
-               if ($options['reportformat']=='htm') {\r
-                       $idnumber = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$attempt->userid.'&course='.$course->id.'">'.$idnumber.'</a>';\r
-               }\r
-               $this->data['user'] = array(\r
-                       'idnumber' => $idnumber,\r
-               );\r
-       }\r
-       function set_data_attempt(&$attempt, &$strftimedate, &$strftimetime, &$blank) {\r
-               global $CFG;\r
-               $records = get_records_sql_menu("\r
-                       SELECT userid, MAX(time) AS logintime\r
-                       FROM {$CFG->prefix}log\r
-                       WHERE userid=$attempt->userid AND action='login' AND time<$attempt->timestart\r
-                       GROUP BY userid\r
-               ");\r
-               if (empty($records)) {\r
-                       $logindate = $blank;\r
-                       $logintime = $blank;\r
-               } else {\r
-                       $logintime = $records[$attempt->userid];\r
-                       $logindate = trim(userdate($logintime, $strftimedate));\r
-                       $logintime = trim(userdate($logintime, $strftimetime));\r
-               }\r
-               $records = get_records_sql_menu("\r
-                       SELECT userid, MIN(time) AS logouttime\r
-                       FROM {$CFG->prefix}log\r
-                       WHERE userid=$attempt->userid AND action='logout' AND time>$attempt->cr_timefinish \r
-                       GROUP BY userid\r
-               ");\r
-               if (empty($records)) {\r
-                       $logouttime = $blank;\r
-               } else {\r
-                       $logouttime = $records[$attempt->userid];\r
-                       $logouttime = trim(userdate($logouttime, $strftimetime));\r
-               }\r
-               $this->data['attempt'] = array(\r
-                       'logindate'  => $logindate,\r
-                       'logintime'  => $logintime,\r
-                       'logouttime' => $logouttime,\r
-                       'number' => $attempt->attempt,\r
-                       'start'  => trim(userdate($attempt->timestart, $strftimetime)),\r
-                       'finish' => trim(userdate($attempt->cr_timefinish, $strftimetime)),\r
-               );\r
-       }\r
-       function set_data_click($number, $time, $exercisetype, $click) {\r
-               $types = array();\r
-               foreach (array_keys($click['types']) as $type) {\r
-                       if ($exercisetype=='JQuiz' && $type=='clues') {\r
-                               $type = 'showanswer';\r
-                       } else {\r
-                               // remove final 's'\r
-                               $type = substr($type, 0, strlen($type)-1);\r
-                       }\r
-                       // $types[] = get_string($type, 'hotpot');\r
-                       $types[] = $type;\r
-               }\r
-               $this->data['click'] = array(\r
-                       'number' => $number,\r
-                       'time'   => $time,\r
-                       'type'   => empty($types) ? '??' : implode(',', $types)\r
-               );\r
-       }\r
-       function set_data_totals(&$click, &$clicks, &$questioncount, &$blank, &$attempt) {\r
-               $count= array(\r
-                       'click' => array(\r
-                               'correct' => count($click['correct']),\r
-                               'wrong' => count($click['wrong']),\r
-                               'answers' => count($click['answers']),\r
-                               'hints' => array_sum($click['hints']),\r
-                               'clues' => array_sum($click['clues']),\r
-                               'events' => array_sum($click['events']),\r
-                               'score' => array_sum($click['score']),\r
-                               'maxscore' => array_sum($click['weighting']),\r
-                       ),\r
-                       'clicks' => array(\r
-                               'correct' => count($clicks['correct']),\r
-                               'wrong' => count($clicks['wrong']),\r
-                               'answers' => count($clicks['answers']),\r
-                               'hints' => array_sum($clicks['hints']),\r
-                               'clues' => array_sum($clicks['clues']),\r
-                               'score' => array_sum($clicks['score']),\r
-                               'maxscore' => array_sum($clicks['weighting']),\r
-                       )\r
-               );\r
-               foreach ($count as $period=>$values) {\r
-                       $count[$period]['nottried'] = $questioncount - ($values['correct'] + $values['wrong']);\r
-                       $count[$period]['percent'] = empty($values['maxscore']) ? $blank : round(100 * $values['score'] / $values['maxscore'], 0);\r
-                       // blank out zero click values\r
-                       if ($period=='click') {\r
-                               foreach ($values as $detail=>$value) {\r
-                                       if ($detail=='answers' || $detail=='hints' || $detail=='clues' || $detail=='events') {\r
-                                               if (empty($value)) {\r
-                                                       $count[$period][$detail] = $blank;\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-               $this->data['totals'] = array(\r
-                       $count['click']['answers'],   // "q's tried"\r
-                       $count['clicks']['answers'],  // "q's tried so far"\r
-                       $count['click']['correct'],   // "right"\r
-                       $count['click']['wrong'],     // "wrong"\r
-                       $count['click']['nottried'],  // "not tried"\r
-                       $count['clicks']['correct'],  // "right so far"\r
-                       $count['clicks']['wrong'],    // "wrong so far"\r
-                       $count['clicks']['nottried'], // "not tried so far"\r
-                       $count['click']['answers'],   // "answers",\r
-                       $count['click']['hints'],     // "hints",\r
-                       $count['click']['clues'],     // "clues",\r
-                       $count['click']['events'],    // "answers",\r
-                       $count['clicks']['hints'],    // "hints so far",\r
-                       $count['clicks']['clues'],    // "clues so far",\r
-                       $count['click']['score'],     // 'raw score',\r
-                       $count['click']['maxscore'],  // 'max score',\r
-                       $count['click']['percent'],   // '% score'\r
-                       $count['clicks']['score'],    // 'raw score,\r
-                       $count['clicks']['maxscore'], // 'max score,\r
-                       $count['clicks']['percent'],  // '% score\r
-                       $attempt->score               // 'hotpot score'\r
-               );\r
-       }\r
-       function update_event_count(&$click, $detail, $q) {\r
-               if ($detail=='checks' || $detail=='hints' || $detail=='clues') {\r
-                       $click['types'][$detail] = true;\r
-               }\r
-               if ($detail=='answers' || $detail=='hints' || $detail=='clues') {\r
-                       $click['events'][$q] = isset($click['events'][$q]) ? $click['events'][$q]+1 : 1;\r
-               }\r
-               if ($detail=='answers') {\r
-                       $click['changes'][$q] = isset($click['changes'][$q]) ? $click['changes'][$q]+1 : 1;\r
-               }\r
-       }\r
-       function set_data(&$cells, $zone) {\r
-               foreach ($this->data[$zone] as $name=>$value) {\r
-                       $cells[] = $value;\r
-               }\r
-       }\r
-} // end class\r
-?>\r
+<?php  // $Id$
+/// Overview report just displays a big table of all the attempts
+class hotpot_report extends hotpot_default_report {
+       function display(&$hotpot, &$cm, &$course, &$users, &$attempts, &$questions, &$options) {
+               global $CFG;
+               // create the tables
+               $tables = array();
+               $this->create_clickreport_table($hotpot, $cm, $course, $users, $attempts, $questions, $options, $tables);
+               // print the tables
+               $this->print_report($course, $hotpot, $tables, $options);
+               return true;
+       }
+       function create_clickreport_table(&$hotpot, &$cm, &$course, &$users, &$attempts, &$questions, &$options, &$tables) {
+               global $CFG;
+               $is_html = ($options['reportformat']=='htm');
+               // time and date format strings         // date format strings
+               $strftimetime = '%H:%M:%S';
+               $strftimedate = get_string('strftimedate');
+               // get the current time and max execution time
+               $start_report_time = microtime();
+               $max_execution_time = ini_get('max_execution_time');
+               $correct = get_string('reportcorrectsymbol', 'hotpot');
+               $wrong = get_string('reportwrongsymbol', 'hotpot');
+               $nottried = get_string('reportnottriedsymbol', 'hotpot');
+               // shortcuts for font tags
+               $blank = $is_html ? '&nbsp;' : "";
+               // store question count
+               $questioncount = count($questions);
+               // array to map columns onto question ids ($col => $id)
+               $questionids = array_keys($questions);
+               // store exercise type
+               $exercisetype = $this->get_exercisetype($questions, $questionids, $blank);
+               // initialize details ('events' must go last)
+               $details = array('checks', 'status', 'answers', 'changes', 'hints', 'clues', 'events');
+               // initialize $table
+               unset($table);
+               $table->border = 1;
+               $table->width = '100%';
+               // initialize legend, if necessary
+               if (!empty($options['reportshowlegend'])) {
+                       $table->legend = array();
+               }
+               // start $table headings
+               $this->set_head($options, $table, 'exercise');
+               $this->set_head($options, $table, 'user');
+               $this->set_head($options, $table, 'attempt');
+               $this->set_head($options, $table, 'click');
+               // store clicktype column number
+               $clicktype_col = count($table->head)-1;
+               // finish $table headings
+               $this->set_head($options, $table, 'details', $exercisetype, $details, $questioncount);
+               $this->set_head($options, $table, 'totals', $exercisetype);
+               // set align and wrap
+               $this->set_align_and_wrap($table);
+               // is link to review allowed?
+               $allow_review = ($is_html && (has_capability('mod/hotpot:viewreport',get_context_instance(CONTEXT_COURSE, $course->id)) || $hotpot->review));
+               // initialize array of data values
+               $this->data = array();
+               // set exercise data values
+               $this->set_data_exercise($cm, $course, $hotpot, $questions, $questionids, $questioncount, $blank);
+               // add details of users' responses
+               foreach ($users as $user) {
+                       $this->set_data_user($options, $course, $user);
+                       unset($clickreportid);
+                       foreach ($user->attempts as $attempt) {
+                               // initialize totals for
+                               $click = array(
+                                       'qnumber' => array(),
+                                       'correct' => array(),
+                                       'wrong' => array(),
+                                       'answers' => array(),
+                                       'hints' => array(),
+                                       'clues' => array(),
+                                       'changes' => array(),
+                                       'checks' => array(),
+                                       'events' => array(),
+                                       'score' => array(),
+                                       'weighting' => array()
+                               );
+                               $clicktypes = array();
+                               // is the start of a new attempt?
+                               // (clicks in the same attempt have the same clickreportid)
+                               if (!isset($clickreportid) || $clickreportid != $attempt->clickreportid) {
+                                       $clickcount = 1;
+                                       $clickreportid = $attempt->clickreportid;
+                                       // initialize totals for all clicks in this attempt
+                                       $clicks = $click; // $click has just been initialized
+                                       $this->set_data_attempt($attempt, $strftimedate, $strftimetime, $blank);
+                               }
+                               $cells = array();
+                               $this->set_data($cells, 'exercise');
+                               $this->set_data($cells, 'user');
+                               $this->set_data($cells, 'attempt');
+                               // get responses to questions in this attempt
+                               foreach ($attempt->responses as $response) {
+                                       // set $q(uestion number)
+                                       $q = array_search($response->question, $questionids);
+                                       $click['qnumber'][$q] = true;
+                                       // was this question answered correctly?
+                                       if ($answer = hotpot_strings($response->correct)) {
+                                               // mark the question as correctly answered
+                                               if (empty($clicks['correct'][$q])) {
+                                                       $click['correct'][$q] = true;
+                                                       $clicks['correct'][$q] = true;
+                                               }
+                                               // unset 'wrong' flags, if necessary
+                                               if (isset($click['wrong'][$q])) {
+                                                       unset($click['wrong'][$q]);
+                                               }
+                                               if (isset($clicks['wrong'][$q])) {
+                                                       unset($clicks['wrong'][$q]);
+                                               }
+                                       // otherwise, was the question answered wrongly?
+                                       } else if ($answer = hotpot_strings($response->wrong)) {
+                                               // mark the question as wrongly answered
+                                               $click['wrong'][$q] = true;
+                                               $clicks['wrong'][$q] = true;
+                                       } else { // not correct or wrong (curious?!)
+                                               unset($answer);
+                                       }
+                                       if (!empty($click['correct'][$q]) || !empty($click['wrong'][$q])) {
+                                               $click['score'][$q] = $response->score;
+                                               $clicks['score'][$q] = $response->score;
+                                               $weighting = isset($response->weighting) ? $response->weighting : 100;
+                                               $click['weighting'][$q] = $weighting;
+                                               $clicks['weighting'][$q] =$weighting;
+                                       }
+                                       foreach($details as $detail) {
+                                               switch ($detail) {
+                                                       case 'answers':
+                                                               if (isset($answer) && is_string($answer) && !empty($answer)) {
+                                                                       $click[$detail][$q] = $answer;
+                                                               }
+                                                               break;
+                                                       case 'hints':
+                                                       case 'clues':
+                                                       case 'checks':
+                                                               if (isset($response->$detail) && is_numeric($response->$detail) && $response->$detail>0) {
+                                                                       if (!isset($click[$detail][$q]) || $click[$detail][$q] < $response->$detail) {
+                                                                               $click[$detail][$q] = $response->$detail;
+                                                                       }
+                                                               }
+                                                               break;
+                                               }
+                                       } // end foreach $detail
+                               } // end foreach $response
+                               $click['types'] = array();
+                               $this->data['details'] = array();
+                               foreach($details as $detail) {
+                                       for ($q=0; $q<$questioncount; $q++) {
+                                               switch ($detail) {
+                                                       case 'status':
+                                                               if (isset($clicks['correct'][$q])) {
+                                                                       $this->data['details'][] = $correct;
+                                                               } else if (isset($clicks['wrong'][$q])) {
+                                                                       $this->data['details'][] = $wrong;
+                                                               } else if (isset($click['qnumber'][$q])) {
+                                                                       $this->data['details'][] = $nottried;
+                                                               } else { // this question did not appear in this attempt
+                                                                       $this->data['details'][] = $blank;
+                                                               }
+                                                               break;
+                                                       case 'answers':
+                                                       case 'hints':
+                                                       case 'clues':
+                                                       case 'checks':
+                                                               if (!isset($clicks[$detail][$q])) {
+                                                                       if (!isset($click[$detail][$q])) {
+                                                                               $this->data['details'][] = $blank;
+                                                                       } else {
+                                                                               $clicks[$detail][$q] = $click[$detail][$q];
+                                                                               if ($detail=='answers') {
+                                                                                       $this->set_legend($table, $q, $click[$detail][$q], $questions[$questionids[$q]]);
+                                                                               }
+                                                                               $this->data['details'][] = $click[$detail][$q];
+                                                                               $this->update_event_count($click, $detail, $q);
+                                                                       }
+                                                               } else {
+                                                                       if (!isset($click[$detail][$q])) {
+                                                                               $this->data['details'][] = $blank;
+                                                                       } else {
+                                                                               $difference = '';
+                                                                               if ($detail=='answers') {
+                                                                                       if ($click[$detail][$q] != $clicks[$detail][$q]) {
+                                                                                               $pattern = '/^'.preg_quote($clicks[$detail][$q], '/').',/';
+                                                                                               $difference = preg_replace($pattern, '', $click[$detail][$q], 1);
+                                                                                       }
+                                                                               } else { // hints, clues, checks
+                                                                                       if ($click[$detail][$q] > $clicks[$detail][$q]) {
+                                                                                               $difference = $click[$detail][$q] - $clicks[$detail][$q];
+                                                                                       }
+                                                                               }
+                                                                               if ($difference) {
+                                                                                       $clicks[$detail][$q] = $click[$detail][$q];
+                                                                                       $click[$detail][$q] = $difference;
+                                                                                       if ($detail=='answers') {
+                                                                                               $this->set_legend($table, $q, $difference, $questions[$questionids[$q]]);
+                                                                                       }
+                                                                                       $this->data['details'][] = $difference;
+                                                                                       $this->update_event_count($click, $detail, $q);
+                                                                               } else {
+                                                                                       unset($click[$detail][$q]);
+                                                                                       $this->data['details'][] = $blank;
+                                                                               }
+                                                                       }
+                                                               }
+                                                               break;
+                                                       case 'changes':
+                                                       case 'events':
+                                                               if (empty($click[$detail][$q])) {
+                                                                       $this->data['details'][] = $blank;
+                                                               } else {
+                                                                       $this->data['details'][] = $click[$detail][$q];
+                                                               }
+                                                               break;
+                                                       default:
+                                                               // do nothing
+                                                               break;
+                                               } // end switch
+                                       } // for $q
+                               } // foreach $detail
+                               // set data cell values for
+                               $this->set_data_click(
+                                       $allow_review ? '<a href="review.php?hp='.$hotpot->id.'&attempt='.$attempt->id.'">'.$clickcount.'</a>' : $clickcount,
+                                       trim(userdate($attempt->timefinish, $strftimetime)),
+                                       $exercisetype,
+                                       $click
+                               );
+                               $this->set_data($cells, 'click');
+                               $this->set_data($cells, 'details');
+                               $this->set_data_totals($click, $clicks, $questioncount, $blank, $attempt);
+                               $this->set_data($cells, 'totals');
+                               $table->data[] = $cells;
+                               $clickcount++;
+                       } // end foreach $attempt
+                        // insert 'tabledivider' between users
+                       $table->data[] = 'hr';
+               } // end foreach $user
+               // remove final 'hr' from data rows
+               array_pop($table->data);
+               if ($is_html && $CFG->hotpot_showtimes) {
+                       $count = count($users);
+                       $duration = sprintf("%0.3f", microtime_diff($start_report_time, microtime()));
+                       print "$count users processed in $duration seconds (".sprintf("%0.3f", $duration/$count).' secs/user)<hr size="1" noshade="noshade" />'."\n";
+               }
+               $tables[] = &$table;
+               $this->create_legend_table($tables, $table);
+       } // end function
+       function get_exercisetype(&$questions, &$questionids, &$blank) {
+               if (empty($questions)) {
+                       $type = $blank;
+               } else {
+                       switch ($questions[$questionids[0]]->type) {
+                               case HOTPOT_JCB:
+                                       $type = "JCB";
+                                       break;
+                               case HOTPOT_JCLOZE :
+                                       $type = "JCloze";
+                                       break;
+                               case HOTPOT_JCROSS :
+                                       $type = "JCross";
+                                       break;
+                               case HOTPOT_JMATCH :
+                                       $type = "JMatch";
+                                       break;
+                               case HOTPOT_JMIX :
+                                       $type = "JMix";
+                                       break;
+                               case HOTPOT_JQUIZ :
+                                       $type = "JQuiz";
+                                       break;
+                               case HOTPOT_TEXTOYS_RHUBARB :
+                                       $type = "Rhubarb";
+                                       break;
+                               case HOTPOT_TEXTOYS_SEQUITUR :
+                                       $type = "Sequitur";
+                                       break;
+                               default:
+                                       $type = $blank;
+                       }
+               }
+               return $type;
+       }
+       function set_head(&$options, &$table, $zone, $exercisetype='', $details=array(), $questioncount=0) {
+               if (empty($table->head)) {
+                       $table->head = array();
+               }
+               switch ($zone) {
+                       case 'exercise':
+                               array_push($table->head,
+                                       get_string('reportcoursename', 'hotpot'),
+                                       get_string('reportsectionnumber', 'hotpot'),
+                                       get_string('reportexercisenumber', 'hotpot'),
+                                       get_string('reportexercisename', 'hotpot'),
+                                       get_string('reportexercisetype', 'hotpot'),
+                                       get_string('reportnumberofquestions', 'hotpot')
+                               );
+                               break;
+                       case 'user':
+                               array_push($table->head,
+                                       get_string('reportstudentid', 'hotpot'),
+                                       get_string('reportlogindate', 'hotpot'),
+                                       get_string('reportlogintime', 'hotpot'),
+                                       get_string('reportlogofftime', 'hotpot')
+                               );
+                               break;
+                       case 'attempt':
+                               array_push($table->head,
+                                       get_string('reportattemptnumber', 'hotpot'),
+                                       get_string('reportattemptstart', 'hotpot'),
+                                       get_string('reportattemptfinish', 'hotpot')
+                               );
+                               break;
+                       case 'click':
+                               array_push($table->head,
+                                       get_string('reportclicknumber', 'hotpot'),
+                                       get_string('reportclicktime', 'hotpot'),
+                                       get_string('reportclicktype', 'hotpot')
+                               );
+                               break;
+                       case 'details':
+                               foreach($details as $detail) {
+                                       if ($exercisetype=='JQuiz' && $detail=='clues') {
+                                               $detail = 'showanswer';
+                                       }
+                                       $detail = get_string("report$detail", 'hotpot');
+                                       for ($i=0; $i<$questioncount; $i++) {
+                                               $str = get_string('questionshort', 'hotpot', $i+1);
+                                               if ($i==0 || $options['reportformat']!='htm') {
+                                                       $str = "$detail $str";
+                                               }
+                                               $table->head[] = $str;
+                                       }
+                               }
+                               break;
+                       case 'totals':
+                               $reportpercentscore =get_string('reportpercentscore', 'hotpot');
+                               if (!function_exists('clean_getstring_data')) { // Moodle 1.4 (and less)
+                                       $reportpercentscore = str_replace('%', '%%', $reportpercentscore);
+                               }
+                               array_push($table->head, 
+                                       get_string('reportthisclick', 'hotpot', get_string('reportquestionstried', 'hotpot')),
+                                       get_string('reportsofar', 'hotpot', get_string('reportquestionstried', 'hotpot')),
+                                       get_string('reportthisclick', 'hotpot', get_string('reportright', 'hotpot')),
+                                       get_string('reportthisclick', 'hotpot', get_string('reportwrong', 'hotpot')),
+                                       get_string('reportthisclick', 'hotpot', get_string('reportnottried', 'hotpot')),
+                                       get_string('reportsofar', 'hotpot', get_string('reportright', 'hotpot')),
+                                       get_string('reportsofar', 'hotpot', get_string('reportwrong', 'hotpot')),
+                                       get_string('reportsofar', 'hotpot', get_string('reportnottried', 'hotpot')),
+                                       get_string('reportthisclick', 'hotpot', get_string('reportanswers', 'hotpot')),
+                                       get_string('reportthisclick', 'hotpot', get_string('reporthints', 'hotpot')),
+                                       get_string('reportthisclick', 'hotpot', get_string($exercisetype=='JQuiz' ? 'reportshowanswer' : 'reportclues', 'hotpot')),
+                                       get_string('reportthisclick', 'hotpot', get_string('reportevents', 'hotpot')),
+                                       get_string('reportsofar', 'hotpot', get_string('reporthints', 'hotpot')),
+                                       get_string('reportsofar', 'hotpot', get_string($exercisetype=='JQuiz' ? 'reportshowanswer' : 'reportclues', 'hotpot')),
+                                       get_string('reportthisclick', 'hotpot', get_string('reportrawscore', 'hotpot')),
+                                       get_string('reportthisclick', 'hotpot', get_string('reportmaxscore', 'hotpot')),
+                                       get_string('reportthisclick', 'hotpot', $reportpercentscore),
+                                       get_string('reportsofar', 'hotpot', get_string('reportrawscore', 'hotpot')),
+                                       get_string('reportsofar', 'hotpot', get_string('reportmaxscore', 'hotpot')),
+                                       get_string('reportsofar', 'hotpot', $reportpercentscore),
+                                       get_string('reporthotpotscore', 'hotpot')
+                               );
+                               break;
+               } // end switch
+       }
+       function set_align_and_wrap(&$table) {
+               $count = count($table->head);
+               for ($i=0; $i<$count; $i++) {
+                       if ($i==0 || $i==1 || $i==2 || $i==4 || $i==5 || $i>=7) {
+                               // numeric (and short text) columns
+                               $table->align[] = 'center';
+                               $table->wrap[] = '';
+                       } else {
+                               // text columns
+                               $table->align[] = 'left';
+                               $table->wrap[] = 'nowrap';
+                       }
+               }
+       }
+       function set_data_exercise(&$cm, &$course, &$hotpot, &$questions, &$questionids, &$questioncount, &$blank) {
+               // get exercise details (course name, section number, activity number, quiztype and question count)
+               $record = get_record("course_sections", "id", $cm->section);
+               $this->data['exercise'] = array(
+                       'course'  => $course->shortname,
+                       'section' => empty($record) ? $blank : $record->section+1,
+                       'number'  => empty($record) ? $blank : array_search($cm->id, explode(',', $record->sequence))+1,
+                       'name'    => $hotpot->name,
+                       'type'    => $this->get_exercisetype($questions, $questionids, $blank),
+                       'questioncount' => $questioncount
+               );
+       }
+       function set_data_user(&$options, &$course, &$user) {
+               global $CFG;
+               // shortcut to first attempt record (which also hold user info)
+               $attempt = &$user->attempts[0];
+               $idnumber = $attempt->idnumber;
+               if (empty($idnumber)) {
+                       $idnumber = fullname($attempt);
+               }
+               if ($options['reportformat']=='htm') {
+                       $idnumber = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$attempt->userid.'&course='.$course->id.'">'.$idnumber.'</a>';
+               }
+               $this->data['user'] = array(
+                       'idnumber' => $idnumber,
+               );
+       }
+       function set_data_attempt(&$attempt, &$strftimedate, &$strftimetime, &$blank) {
+               global $CFG;
+               $records = get_records_sql_menu("
+                       SELECT userid, MAX(time) AS logintime
+                       FROM {$CFG->prefix}log
+                       WHERE userid=$attempt->userid AND action='login' AND time<$attempt->timestart
+                       GROUP BY userid
+               ");
+               if (empty($records)) {
+                       $logindate = $blank;
+                       $logintime = $blank;
+               } else {
+                       $logintime = $records[$attempt->userid];
+                       $logindate = trim(userdate($logintime, $strftimedate));
+                       $logintime = trim(userdate($logintime, $strftimetime));
+               }
+               $records = get_records_sql_menu("
+                       SELECT userid, MIN(time) AS logouttime
+                       FROM {$CFG->prefix}log
+                       WHERE userid=$attempt->userid AND action='logout' AND time>$attempt->cr_timefinish 
+                       GROUP BY userid
+               ");
+               if (empty($records)) {
+                       $logouttime = $blank;
+               } else {
+                       $logouttime = $records[$attempt->userid];
+                       $logouttime = trim(userdate($logouttime, $strftimetime));
+               }
+               $this->data['attempt'] = array(
+                       'logindate'  => $logindate,
+                       'logintime'  => $logintime,
+                       'logouttime' => $logouttime,
+                       'number' => $attempt->attempt,
+                       'start'  => trim(userdate($attempt->timestart, $strftimetime)),
+                       'finish' => trim(userdate($attempt->cr_timefinish, $strftimetime)),
+               );
+       }
+       function set_data_click($number, $time, $exercisetype, $click) {
+               $types = array();
+               foreach (array_keys($click['types']) as $type) {
+                       if ($exercisetype=='JQuiz' && $type=='clues') {
+                               $type = 'showanswer';
+                       } else {
+                               // remove final 's'
+                               $type = substr($type, 0, strlen($type)-1);
+                       }
+                       // $types[] = get_string($type, 'hotpot');
+                       $types[] = $type;
+               }
+               $this->data['click'] = array(
+                       'number' => $number,
+                       'time'   => $time,
+                       'type'   => empty($types) ? '??' : implode(',', $types)
+               );
+       }
+       function set_data_totals(&$click, &$clicks, &$questioncount, &$blank, &$attempt) {
+               $count= array(
+                       'click' => array(
+                               'correct' => count($click['correct']),
+                               'wrong' => count($click['wrong']),
+                               'answers' => count($click['answers']),
+                               'hints' => array_sum($click['hints']),
+                               'clues' => array_sum($click['clues']),
+                               'events' => array_sum($click['events']),
+                               'score' => array_sum($click['score']),
+                               'maxscore' => array_sum($click['weighting']),
+                       ),
+                       'clicks' => array(
+                               'correct' => count($clicks['correct']),
+                               'wrong' => count($clicks['wrong']),
+                               'answers' => count($clicks['answers']),
+                               'hints' => array_sum($clicks['hints']),
+                               'clues' => array_sum($clicks['clues']),
+                               'score' => array_sum($clicks['score']),
+                               'maxscore' => array_sum($clicks['weighting']),
+                       )
+               );
+               foreach ($count as $period=>$values) {
+                       $count[$period]['nottried'] = $questioncount - ($values['correct'] + $values['wrong']);
+                       $count[$period]['percent'] = empty($values['maxscore']) ? $blank : round(100 * $values['score'] / $values['maxscore'], 0);
+                       // blank out zero click values
+                       if ($period=='click') {
+                               foreach ($values as $detail=>$value) {
+                                       if ($detail=='answers' || $detail=='hints' || $detail=='clues' || $detail=='events') {
+                                               if (empty($value)) {
+                                                       $count[$period][$detail] = $blank;
+                                               }
+                                       }
+                               }
+                       }
+               }
+               $this->data['totals'] = array(
+                       $count['click']['answers'],   // "q's tried"
+                       $count['clicks']['answers'],  // "q's tried so far"
+                       $count['click']['correct'],   // "right"
+                       $count['click']['wrong'],     // "wrong"
+                       $count['click']['nottried'],  // "not tried"
+                       $count['clicks']['correct'],  // "right so far"
+                       $count['clicks']['wrong'],    // "wrong so far"
+                       $count['clicks']['nottried'], // "not tried so far"
+                       $count['click']['answers'],   // "answers",
+                       $count['click']['hints'],     // "hints",
+                       $count['click']['clues'],     // "clues",
+                       $count['click']['events'],    // "answers",
+                       $count['clicks']['hints'],    // "hints so far",
+                       $count['clicks']['clues'],    // "clues so far",
+                       $count['click']['score'],     // 'raw score',
+                       $count['click']['maxscore'],  // 'max score',
+                       $count['click']['percent'],   // '% score'
+                       $count['clicks']['score'],    // 'raw score,
+                       $count['clicks']['maxscore'], // 'max score,
+                       $count['clicks']['percent'],  // '% score
+                       $attempt->score               // 'hotpot score'
+               );
+       }
+       function update_event_count(&$click, $detail, $q) {
+               if ($detail=='checks' || $detail=='hints' || $detail=='clues') {
+                       $click['types'][$detail] = true;
+               }
+               if ($detail=='answers' || $detail=='hints' || $detail=='clues') {
+                       $click['events'][$q] = isset($click['events'][$q]) ? $click['events'][$q]+1 : 1;
+               }
+               if ($detail=='answers') {
+                       $click['changes'][$q] = isset($click['changes'][$q]) ? $click['changes'][$q]+1 : 1;
+               }
+       }
+       function set_data(&$cells, $zone) {
+               foreach ($this->data[$zone] as $name=>$value) {
+                       $cells[] = $value;
+               }
+       }
+} // end class
+?>
index 4389b59da2e033bc4f78049ea0c210c3c505394d..ae78f14d6fd3597d76630c3e3ad35856a1f15783 100644 (file)
-<?PHP \r
-\r
-class hotpot_xml_quiz_template extends hotpot_xml_template_default {\r
-\r
-    // constructor function for this class\r
-    function hotpot_xml_quiz_template(&$parent) {\r
-\r
-        $this->parent = &$parent;\r
-        \r
-        $get_js = optional_param('js', false);\r
-        $get_css = optional_param('css', false);\r
-\r
-        if (!empty($get_css)) {\r
-            // set $this->css\r
-            $this->v6_expand_StyleSheet(); \r
-\r
-        } else if (!empty($get_js)) {\r
-            // set $this->js\r
-            $this->read_template($this->parent->draganddrop.$this->parent->quiztype.'6.js_', 'js');\r
-\r
-        } else {\r
-            // set $this->html\r
-            $this->read_template($this->parent->draganddrop.$this->parent->quiztype.'6.ht_', 'html');\r
-        }\r
-\r
-        // expand special strings, if any\r
-        $pattern = '';\r
-        switch ($this->parent->quiztype) {\r
-            case 'jcloze':\r
-                $pattern = '/\[(PreloadImageList)\]/';\r
-                break;\r
-            case 'jcross':\r
-                $pattern = '/\[(PreloadImageList|ShowHideClueList)\]/';\r
-                break;\r
-            case 'jmatch':\r
-                $pattern = '/\[(PreloadImageList|QsToShow|FixedArray|DragArray)\]/';\r
-                break;\r
-            case 'jmix':\r
-                $pattern = '/\[(PreloadImageList|SegmentArray|AnswerArray)\]/';\r
-                break;\r
-            case 'jquiz':\r
-                $pattern = '/\[(PreloadImageList|QsToShow)\]/';\r
-                break;\r
-        }\r
-        if (!empty($pattern)) {\r
-            $this->expand_strings('html', $pattern);\r
-        }\r
-    }\r
-\r
-    // captions and messages\r
-\r
-    function v6_expand_AlsoCorrect() {\r
-        return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',also-correct');\r
-    }\r
-    function v6_expand_CapitalizeFirst() {\r
-        return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',capitalize-first-letter');\r
-    }\r
-    function v6_expand_CheckCaption() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,check-caption');\r
-    }\r
-    function v6_expand_CorrectIndicator() {\r
-        return $this->js_value('hotpot-config-file,global,correct-indicator');\r
-    }\r
-    function v6_expand_Back() {\r
-        return $this->int_value('hotpot-config-file,global,include-back');\r
-    }\r
-    function v6_expand_BackCaption() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,back-caption');\r
-    }\r
-    function v6_expand_ClickToAdd() {\r
-        return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',click-to-add');\r
-    }\r
-    function v6_expand_ClueCaption() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,clue-caption');\r
-    }\r
-    function v6_expand_Clues() {\r
-        return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-clues');\r
-    }\r
-    function v6_expand_Contents() {\r
-        return $this->int_value('hotpot-config-file,global,include-contents');\r
-    }\r
-    function v6_expand_ContentsCaption() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,contents-caption');\r
-    }\r
-    function v6_expand_GuessCorrect() {\r
-        return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',guess-correct');\r
-    }\r
-    function v6_expand_GuessIncorrect() {\r
-        return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',guess-incorrect');\r
-    }\r
-    function v6_expand_Hint() {\r
-        return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-hint');\r
-    }\r
-    function v6_expand_HintCaption() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,hint-caption');\r
-    }\r
-    function v6_expand_IncorrectIndicator() {\r
-        return $this->js_value('hotpot-config-file,global,incorrect-indicator');\r
-    }\r
-    function v6_expand_LastQCaption() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,last-q-caption');\r
-    }\r
-    function v6_expand_NextCorrect() {\r
-        $value = $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',next-correct-part');\r
-        if (empty($value)) { // jquiz\r
-            $value = $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',next-correct-letter');\r
-        }\r
-        return $value;\r
-    }\r
-    function v6_expand_NextEx() {\r
-        return $this->int_value('hotpot-config-file,global,include-next-ex');\r
-    }\r
-    function v6_expand_NextExCaption() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,next-ex-caption');\r
-    }\r
-    function v6_expand_NextQCaption() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,next-q-caption');\r
-    }\r
-    function v6_expand_OKCaption() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,ok-caption');\r
-    }\r
-    function v6_expand_Restart() {\r
-        return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-restart');\r
-    }\r
-    function v6_expand_RestartCaption() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,restart-caption');\r
-    }\r
-    function v6_expand_ShowAllQuestionsCaption() {\r
-        return $this->js_value('hotpot-config-file,global,show-all-questions-caption');\r
-    }\r
-    function v6_expand_ShowOneByOneCaption() {\r
-        return $this->js_value('hotpot-config-file,global,show-one-by-one-caption');\r
-    }\r
-    function v6_expand_TheseAnswersToo() {\r
-        return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',also-correct');\r
-    }\r
-    function v6_expand_ThisMuch() {\r
-        return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',this-much-correct');\r
-    }\r
-    function v6_expand_Undo() {\r
-        return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-undo');\r
-    }\r
-    function v6_expand_UndoCaption() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,undo-caption');\r
-    }\r
-    function v6_expand_YourScoreIs() {\r
-        return $this->js_value('hotpot-config-file,global,your-score-is');\r
-    }\r
-\r
-    // reading\r
-\r
-    function v6_expand_Reading() {\r
-        return $this->int_value('data,reading,include-reading');\r
-    }\r
-    function v6_expand_ReadingText() {\r
-        $title = $this->v6_expand_ReadingTitle();\r
-        $value = $this->parent->xml_value('data,reading,reading-text');\r
-        $value = empty($value) ? '' : ('<div class="ReadingText">'.$value.'</div>');\r
-        return $title.$value;\r
-    }\r
-    function v6_expand_ReadingTitle() {\r
-        $value = $this->parent->xml_value('data,reading,reading-title');\r
-        return empty($value) ? '' : ('<h3 class="ExerciseSubtitle">'.$value.'</h3>');\r
-    }\r
-\r
-    // timer \r
-\r
-    function v6_expand_Timer() {\r
-        return $this->int_value('data,timer,include-timer');\r
-    }\r
-    function v6_expand_JSTimer() {\r
-        return $this->read_template('hp6timer.js_');\r
-    }\r
-    function v6_expand_Seconds() {\r
-        return $this->parent->xml_value('data,timer,seconds');\r
-    }\r
-\r
-    // send results \r
-\r
-    function v6_expand_SendResults() {\r
-        return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',send-email');\r
-    }\r
-    function v6_expand_JSSendResults() {\r
-        return $this->read_template('hp6sendresults.js_');\r
-    }\r
-    function v6_expand_FormMailURL() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,formmail-url');\r
-    }\r
-    function v6_expand_EMail() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,email');\r
-    }\r
-    function v6_expand_NamePlease() {\r
-        return $this->js_value('hotpot-config-file,global,name-please');\r
-    }\r
-\r
-    // preload images\r
-\r
-    function v6_expand_PreloadImages() {\r
-        $value = $this->v6_expand_PreloadImageList();\r
-        return empty($value) ? false : true;\r
-    }\r
-    function v6_expand_PreloadImageList() {\r
-\r
-        // check it has not been set already\r
-        if (!isset($this->PreloadImageList)) {\r
-\r
-            // the list of image urls\r
-            $list = array();\r
-\r
-            // extract <img> tags\r
-            $img_tag = htmlspecialchars('|&#x003C;img.*?src="(.*?)".*?&#x003E;|is');\r
-            if (preg_match_all($img_tag, $this->parent->source, $matches)) {\r
-                $list = $matches[1];\r
-\r
-                // remove duplicates\r
-                $list = array_unique($list);\r
-            }\r
-\r
-            // convert to comma delimited string\r
-            $this->PreloadImageList = empty($list) ? '' : "'".implode(',', $list)."'";\r
-        }\r
-        return $this->PreloadImageList;\r
-    }\r
-\r
-    // html files (all quiz types)\r
-\r
-    function v6_expand_PlainTitle() {\r
-        return $this->parent->xml_value('data,title');\r
-    }\r
-    function v6_expand_ExerciseSubtitle() {\r
-        return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',exercise-subtitle');\r
-    }\r
-    function v6_expand_Instructions() {\r
-        return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',instructions');\r
-    }\r
-    function v6_expand_DublinCoreMetadata() {\r
-        $dc = '<link rel="schema.DC" href="'.$this->parent->xml_value('', "['rdf:RDF'][0]['@']['xmlns:dc']").'" />'."\n";\r
-        if (is_string($this->parent->xml_value('rdf:RDF,rdf:Description'))) {\r
-            // do nothing (there is no more dc info)\r
-        } else {\r
-            $dc .= '<meta name="DC:Creator" content="'.$this->parent->xml_value('rdf:RDF,rdf:Description,dc:creator').'" />'."\n";\r
-            $dc .= '<meta name="DC:Title" content="'.strip_tags($this->parent->xml_value('rdf:RDF,rdf:Description,dc:title')).'" />'."\n";\r
-        }\r
-        return $dc;\r
-    }\r
-    function v6_expand_FullVersionInfo() {\r
-        global $CFG;\r
-        require_once($CFG->hotpotroot.DIRECTORY_SEPARATOR.'version.php'); // set $module\r
-        return $this->parent->xml_value('version').'.x (Moodle '.$CFG->release.', hotpot-module '.$this->parent->obj_value($module, 'release').')';\r
-    }\r
-    function v6_expand_HeaderCode() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,header-code');\r
-    }\r
-    function v6_expand_StyleSheet() {\r
-        $this->read_template('hp6.cs_', 'css');\r
-        $this->css = hotpot_convert_stylesheets_urls($this->parent->get_baseurl(), $this->parent->reference, $this->css);\r
-        return $this->css;\r
-    }\r
-\r
-    // stylesheet (hp6.cs_)\r
-\r
-    function v6_expand_PageBGColor() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,page-bg-color');\r
-    }\r
-    function v6_expand_GraphicURL() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,graphic-url');\r
-    }\r
-    function v6_expand_ExBGColor() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,ex-bg-color');\r
-    }\r
-\r
-    function v6_expand_FontFace() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,font-face');\r
-    }\r
-    function v6_expand_FontSize() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,font-size');\r
-    }\r
-    function v6_expand_TextColor() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,text-color');\r
-    }\r
-    function v6_expand_TitleColor() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,title-color');\r
-    }\r
-    function v6_expand_LinkColor() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,link-color');\r
-    }\r
-    function v6_expand_VLinkColor() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,vlink-color');\r
-    }\r
-\r
-    function v6_expand_NavTextColor() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,page-bg-color');\r
-    }\r
-    function v6_expand_NavBarColor() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,nav-bar-color');\r
-    }\r
-    function v6_expand_NavLightColor() {\r
-        $color = $this->parent->xml_value('hotpot-config-file,global,nav-bar-color');\r
-        return $this->get_halfway_color($color, '#ffffff'); \r
-    }\r
-    function v6_expand_NavShadeColor() {\r
-        $color = $this->parent->xml_value('hotpot-config-file,global,nav-bar-color');\r
-        return $this->get_halfway_color($color, '#000000');\r
-    }\r
-\r
-    function v6_expand_FuncLightColor() { // top-left of buttons\r
-        $color = $this->parent->xml_value('hotpot-config-file,global,ex-bg-color');\r
-        return $this->get_halfway_color($color, '#ffffff');\r
-    }\r
-    function v6_expand_FuncShadeColor() { // bottom right of buttons\r
-        $color = $this->parent->xml_value('hotpot-config-file,global,ex-bg-color');\r
-        return $this->get_halfway_color($color, '#000000');\r
-    }\r
-\r
-    // navigation buttons\r
-\r
-    function v6_expand_NavButtons() {\r
-        $back = $this->v6_expand_Back();\r
-        $next_ex = $this->v6_expand_NextEx();\r
-        $contents = $this->v6_expand_Contents();\r
-        return (empty($back) && empty($next_ex) && empty($contents) ? false : true);\r
-    }\r
-    function v6_expand_NavBarJS() {\r
-        return $this->v6_expand_NavButtons();\r
-    }\r
-\r
-    // js files (all quiz types)\r
-\r
-    function v6_expand_JSBrowserCheck() {\r
-        return $this->read_template('hp6browsercheck.js_');\r
-    }\r
-    function v6_expand_JSButtons() {\r
-        return $this->read_template('hp6buttons.js_');\r
-    }\r
-    function v6_expand_JSCard() {\r
-        return $this->read_template('hp6card.js_');\r
-    }\r
-    function v6_expand_JSCheckShortAnswer() {\r
-        return $this->read_template('hp6checkshortanswer.js_');\r
-    }\r
-    function v6_expand_JSHotPotNet() {\r
-        return $this->read_template('hp6hotpotnet.js_');\r
-    }\r
-    function v6_expand_JSShowMessage() {\r
-        return $this->read_template('hp6showmessage.js_');\r
-    }\r
-    function v6_expand_JSUtilities() {\r
-        return $this->read_template('hp6utilities.js_');\r
-    }\r
-\r
-    // js files\r
-\r
-    function v6_expand_JSJCloze6() {\r
-        return $this->read_template('jcloze6.js_');\r
-    }\r
-    function v6_expand_JSJCross6() {\r
-        return $this->read_template('jcross6.js_');\r
-    }\r
-    function v6_expand_JSJMatch6() {\r
-        return $this->read_template('jmatch6.js_');\r
-    }\r
-    function v6_expand_JSJMix6() {\r
-        return $this->read_template('jmix6.js_');\r
-    }\r
-    function v6_expand_JSJQuiz6() {\r
-        return $this->read_template('jquiz6.js_');\r
-    }\r
-\r
-    // drag and drop\r
-\r
-    function v6_expand_JSDJMatch6() {\r
-        return $this->read_template('djmatch6.js_');\r
-    }\r
-    function v6_expand_JSDJMix6() {\r
-        return $this->read_template('djmix6.js_');\r
-    }\r
-\r
-    // what are these for?\r
-\r
-    function v6_expand_JSFJMatch6() {\r
-        return $this->read_template('fjmatch6.js_');\r
-    }\r
-    function v6_expand_JSFJMix6() {\r
-        return $this->read_template('fjmix6.js_');\r
-    }\r
-\r
-    // jmatch6.js_\r
-\r
-    function v6_expand_ShuffleQs() {\r
-        return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',shuffle-questions');\r
-    }\r
-    function v6_expand_QsToShow() {\r
-        $i = $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',show-limited-questions');\r
-        if ($i) {\r
-            $i = $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',questions-to-show');\r
-        }\r
-        if (empty($i)) {\r
-            $i = 0;\r
-            switch ($this->parent->quiztype) {\r
-                case 'jmatch':\r
-                    $values = $this->parent->xml_values('data,matching-exercise,pair');\r
-                    $i = count($values);\r
-                    break;\r
-                case 'jquiz':\r
-                    while ($this->parent->xml_value('data,questions,question-record', "[$i]['#']['question'][0]['#']")) {\r
-                        $i++;\r
-                    }\r
-                    break;\r
-            } // end switch\r
-        }\r
-        return $i;\r
-    }\r
-    function v6_expand_MatchDivItems() {\r
-        $l_items = array();\r
-        $r_items = array();\r
-        $this->get_jmatch_items($l_items, $r_items);\r
-\r
-        $l_keys = $this->shuffle_jmatch_items($l_items);\r
-        $r_keys = $this->shuffle_jmatch_items($r_items);\r
-\r
-        $options = '<option value="x">'.$this->parent->xml_value('data,matching-exercise,default-right-item').'</option>';\r
-        foreach ($r_keys as $key) {\r
-            $options .= '<option value="'.$key.'">'.$r_items[$key]['text'][0]['#'].'</option>'."\n";\r
-        }\r
-\r
-        $str = '';\r
-        foreach ($l_keys as $key) {\r
-            $str .= '<tr><td class="LeftItem">'.$l_items[$key]['text'][0]['#'].'</td>';\r
-            $str .= '<td class="RightItem"><select id="s'.$key.'_'.$key.'">'.$options.'</select></td>';\r
-            $str .= '<td></td></tr>';\r
-        }\r
-        return $str;\r
-    }\r
-\r
-    // jmix6.js_\r
-\r
-    function v6_expand_Punctuation() {\r
-        $tags = 'data,jumbled-order-exercise';\r
-        $chars = array_merge(\r
-            $this->jmix_Punctuation("$tags,main-order,segment"),\r
-            $this->jmix_Punctuation("$tags,alternate")\r
-        );\r
-        $chars = array_unique($chars);\r
-        $chars = implode('', $chars);\r
-        $chars = $this->js_safe($chars, true);\r
-        return $chars;\r
-    }\r
-    function jmix_Punctuation($tags) {\r
-        $chars = array();\r
-\r
-        // all punctutation except '&#;' (because they are used in html entities)\r
-        $ENTITIES = $this->jmix_encode_punctuation('!"$%'."'".'()*+,-./:<=>?@[\]^_`{|}~');\r
-        $pattern = "/&#x([0-9A-F]+);/i";\r
-        $i = 0;\r
-\r
-        // get next segment (or alternate answer)\r
-        while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {\r
-\r
-            // convert low-ascii punctuation to entities\r
-            $value = strtr($value, $ENTITIES);\r
-\r
-            // extract all hex HTML entities\r
-            if (preg_match_all($pattern, $value, $matches)) {\r
-\r
-                // loop through hex entities\r
-                $m_max = count($matches[0]);\r
-                for ($m=0; $m<$m_max; $m++) {\r
-\r
-                    // convert to hex number\r
-                    eval('$hex=0x'.$matches[1][$m].';');\r
-\r
-                    // is this a punctuation character?\r
-                    if (\r
-                        ($hex>=0x0020 && $hex<=0x00BF) || // ascii punctuation\r
-                        ($hex>=0x2000 && $hex<=0x206F) || // general punctuation\r
-                        ($hex>=0x3000 && $hex<=0x303F) || // CJK punctuation\r
-                        ($hex>=0xFE30 && $hex<=0xFE4F) || // CJK compatability\r
-                        ($hex>=0xFE50 && $hex<=0xFE6F) || // small form variants\r
-                        ($hex>=0xFF00 && $hex<=0xFF40) || // halfwidth and fullwidth forms (1)\r
-                        ($hex>=0xFF5B && $hex<=0xFF65) || // halfwidth and fullwidth forms (2)\r
-                        ($hex>=0xFFE0 && $hex<=0xFFEE)    // halfwidth and fullwidth forms (3)\r
-                    ) {\r
-                        // add this character\r
-                        $chars[] = $matches[0][$m];\r
-                    }\r
-                }\r
-            }\r
-            $i++;\r
-        }\r
-\r
-        return $chars;\r
-    }\r
-    function v6_expand_OpenPunctuation() {\r
-        $tags = 'data,jumbled-order-exercise';\r
-        $chars = array_merge(\r
-            $this->jmix_OpenPunctuation("$tags,main-order,segment"),\r
-            $this->jmix_OpenPunctuation("$tags,alternate")\r
-        );\r
-        $chars = array_unique($chars);\r
-        $chars = implode('', $chars);\r
-        $chars = $this->js_safe($chars, true);\r
-        return $chars;\r
-    }\r
-    function jmix_OpenPunctuation($tags) {\r
-        $chars = array();\r
-\r
-        // unicode punctuation designations (pi="initial quote", ps="open")\r
-        //  http://www.sql-und-xml.de/unicode-database/pi.html\r
-        //  http://www.sql-und-xml.de/unicode-database/ps.html\r
-        $pi = '0022|0027|00AB|2018|201B|201C|201F|2039';\r
-        $ps = '0028|005B|007B|0F3A|0F3C|169B|201A|201E|2045|207D|208D|2329|23B4|2768|276A|276C|276E|2770|2772|2774|27E6|27E8|27EA|2983|2985|2987|2989|298B|298D|298F|2991|2993|2995|2997|29D8|29DA|29FC|3008|300A|300C|300E|3010|3014|3016|3018|301A|301D|FD3E|FE35|FE37|FE39|FE3B|FE3D|FE3F|FE41|FE43|FE47|FE59|FE5B|FE5D|FF08|FF3B|FF5B|FF5F|FF62';\r
-        $pattern = "/(&#x($pi|$ps);)/i";\r
-\r
-        $ENTITIES = $this->jmix_encode_punctuation('"'."'".'(<[{');\r
-\r
-        $i = 0;\r
-        while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {\r
-            $value = strtr($value, $ENTITIES);\r
-            if (preg_match_all($pattern, $value, $matches)) {\r
-                $chars = array_merge($chars, $matches[0]);\r
-            } \r
-            $i++;\r
-        }\r
-\r
-        return $chars;\r
-    }\r
-    function jmix_encode_punctuation($str) {\r
-        $ENTITIES = array();\r
-        $i_max = strlen($str);\r
-        for ($i=0; $i<$i_max; $i++) {\r
-            $ENTITIES[$str{$i}] = '&#x'.sprintf('%04X', ord($str{$i})).';';\r
-        }\r
-        return $ENTITIES;\r
-    }\r
-    function v6_expand_ExerciseTitle() {\r
-        return $this->parent->xml_value('data,title');\r
-    }\r
-\r
-    // Jmix specials\r
-\r
-    function v6_expand_SegmentArray() {\r
-\r
-        $segments = array();\r
-        $values = array();\r
-        $VALUES = array();\r
-\r
-        // XML tags to the start of a segment\r
-        $tags = 'data,jumbled-order-exercise,main-order,segment';\r
-\r
-        $i = 0;\r
-        while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {\r
-            $VALUE = strtoupper($value);\r
-            $key = array_search($VALUE, $VALUES);\r
-            if (is_numeric($key)) {\r
-                $segments[] = $key;\r
-            } else {\r
-                $segments[] = $i;\r
-                $values[$i] = $value;\r
-                $VALUES[$i] = $VALUE;\r
-            }\r
-            $i++;\r
-        }\r
-\r
-        $this->seed_random_number_generator();\r
-        $keys = array_keys($segments);\r
-        shuffle($keys);\r
-\r
-        $str = '';\r
-        for($i=0; $i<count($keys); $i++) {\r
-            $key = $segments[$keys[$i]];\r
-            $str .= "Segments[$i] = new Array();\n";\r
-            $str .= "Segments[$i][0] = '".$this->js_safe($values[$key], true)."';\n";\r
-            $str .= "Segments[$i][1] = ".($key+1).";\n";\r
-            $str .= "Segments[$i][2] = 0;\n";\r
-        }\r
-        return $str;\r
-    }\r
-    function v6_expand_AnswerArray() {\r
-\r
-        $segments = array();\r
-        $values = array();\r
-        $VALUES = array();\r
-        $escapedvalues = array();\r
-\r
-        // XML tags to the start of a segment\r
-        $tags = 'data,jumbled-order-exercise,main-order,segment';\r
-\r
-        $i = 0;\r
-        while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {\r
-            $VALUE = strtoupper($value);\r
-            $key = array_search($VALUE, $VALUES);\r
-            if (is_numeric($key)) {\r
-                $segments[] = $key+1;\r
-            } else {\r
-                $segments[] = $i+1;\r
-                $values[$i] = $value;\r
-                $VALUES[$i] = $VALUE;\r
-                $escapedvalues[] = preg_quote($value, '/');\r
-            }\r
-            $i++;\r
-        }\r
-\r
-        // start the answers array\r
-        $a = 0;\r
-        $str = 'Answers['.($a++).'] = new Array('.implode(',', $segments).");\n";\r
-\r
-        // pattern to match the next part of an alternate answer\r
-        $pattern = '/^('.implode('|', $escapedvalues).')\\s*/i';\r
-\r
-        // XML tags to the start of an alternate answer\r
-        $tags = 'data,jumbled-order-exercise,alternate';\r
-\r
-        $i = 0;\r
-        while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {\r
-            $segments = array();\r
-            while (strlen($value) && preg_match($pattern, $value, $matches)) {\r
-                $key = array_search($matches[1], $values);\r
-                if (is_numeric($key)) {\r
-                    $segments[] = $key+1;\r
-                    $value = substr($value, strlen($matches[0]));\r
-                } else {\r
-                    // invalid alternate sequence\r
-                    $segments = array();\r
-                    break;\r
-                }\r
-            }\r
-            if (count($segments)) {\r
-                $str .= 'Answers['.($a++).'] = new Array('.implode(',', $segments).");\n";\r
-            }\r
-            $i++;\r
-        }\r
-        return $str;\r
-    }\r
-\r
-    // ===============================================================\r
-\r
-    // JMix (jmix6.js_)\r
-\r
-    function v6_expand_RemainingWords() {\r
-        return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',remaining-words');\r
-    }\r
-    function v6_expand_TimesUp() {\r
-        return $this->parent->xml_value('hotpot-config-file,global,times-up');\r
-    }\r
-\r
-    // nav bar\r
-\r
-    function v6_expand_NavBar($navbarid='') {\r
-        $this->navbarid = $navbarid;\r
-\r
-        $tag = 'navbar';\r
-        $this->read_template('hp6navbar.ht_', $tag);\r
-\r
-        unset($this->navbarid);\r
-\r
-        return $this->$tag;\r
-    }\r
-    function v6_expand_TopNavBar() {\r
-        return $this->v6_expand_NavBar('TopNavBar');\r
-    }\r
-    function v6_expand_BottomNavBar() {\r
-        return $this->v6_expand_NavBar('BottomNavBar');\r
-    }\r
-\r
-    // hp6navbar.ht_\r
-\r
-    function v6_expand_NavBarID() {\r
-        // $this->navbarid is set in "$this->v6_expand_NavBar"\r
-        return empty($this->navbarid) ? '' : $this->navbarid;\r
-    }\r
-    function v6_expand_ContentsURL() {\r
-        $url = $this->parent->xml_value('hotpot-config-file,global,contents-url');\r
-        if ($url) {\r
-            $url = hotpot_convert_navbutton_url($this->parent->get_baseurl(), $this->parent->reference, $url, $this->parent->course);\r
-        }\r
-        return $url;\r
-    }\r
-    function v6_expand_NextExURL() {\r
-        $url = $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',next-ex-url');\r
-        if ($url) {\r
-            $url = hotpot_convert_navbutton_url($this->parent->get_baseurl(), $this->parent->reference, $url, $this->parent->course);\r
-        }\r
-        return $url;\r
-    }\r
-\r
-    // conditional blocks\r
-\r
-    function v6_expand_ShowAnswer() {\r
-        return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-show-answer');\r
-    }\r
-    function v6_expand_Slide() {\r
-        return true; // whats's this (JMatch drag and drop)\r
-    }\r
-\r
-    // specials (JMatch)\r
-\r
-    function v6_expand_FixedArray() {\r
-        $l_items = array();\r
-        $r_items = array();\r
-        $this->get_jmatch_items($l_items, $r_items);\r
-\r
-        $str = '';\r
-        foreach ($l_items as $i=>$item) {\r
-            $str .= "F[$i] = new Array();\n";\r
-            $str .= "F[$i][0] = '".$this->js_safe($item['text'][0]['#'], true)."';\n";\r
-            $str .= "F[$i][1] = ".($i+1).";\n";\r
-        }\r
-        return $str;\r
-    }\r
-    function v6_expand_DragArray() {\r
-        $l_items = array();\r
-        $r_items = array();\r
-        $this->get_jmatch_items($l_items, $r_items);\r
-\r
-        $str = '';\r
-        foreach ($r_items as $i=>$item) {\r
-            $str .= "D[$i] = new Array();\n";\r
-            $str .= "D[$i][0] = '".$this->js_safe($item['text'][0]['#'], true)."';\n";\r
-            $str .= "D[$i][1] = ".($i+1).";\n";\r
-            $str .= "D[$i][2] = 0;\n";\r
-        }\r
-        return $str;\r
-    }\r
-\r
-    function get_jmatch_items(&$l_items, &$r_items) {\r
-        $tags = 'data,matching-exercise,pair';\r
-        $i = 0;\r
-        while($item = $this->parent->xml_value($tags,"[$i]['#']['left-item'][0]['#']")) {\r
-            if (!empty($item['text'][0]['#'])) {\r
-                $l_items[] = $item;\r
-            }\r
-            $i++;\r
-        }\r
-        $i = 0;\r
-        while($item = $this->parent->xml_value($tags,"[$i]['#']['right-item'][0]['#']")) {\r
-            if (!empty($item['text'][0]['#'])) {\r
-                $r_items[] = $item;\r
-            }\r
-            $i++;\r
-        }\r
-    }\r
-    function shuffle_jmatch_items(&$items) {\r
-        // get moveable items\r
-        $moveable_keys = array();\r
-        for($i=0; $i<count($items); $i++) {\r
-            if(empty($items[$i]['fixed'][0]['#'])) {\r
-                $moveable_keys[] = $i;\r
-            }\r
-        }\r
-        // shuffle moveable items\r
-        $this->seed_random_number_generator();\r
-        shuffle($moveable_keys);\r
-\r
-        $keys = array();\r
-        for($i=0, $ii=0; $i<count($items); $i++) {\r
-            if(empty($items[$i]['fixed'][0]['#'])) {\r
-                //  moveable items are inserted in a shuffled order\r
-                $keys[] = $moveable_keys[$ii++];\r
-            } else {\r
-                //  fixed items stay where they are\r
-                $keys[] = $i;\r
-            }\r
-        }\r
-        return $keys;\r
-    }\r
-    function seed_random_number_generator() {\r
-        static $seeded_RNG = FALSE;\r
-        if (!$seeded_RNG) {\r
-            srand((double) microtime() * 1000000);\r
-            $seeded_RNG = TRUE;\r
-        }\r
-    }\r
-\r
-    // specials (JMix)\r
-\r
-\r
-    // specials (JCloze)\r
-\r
-    function v6_expand_ItemArray() {\r
-        $q = 0;\r
-        $str = '';\r
-        switch ($this->parent->quiztype) {\r
-            case 'jcloze':\r
-                $tags = 'data,gap-fill,question-record';\r
-                while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {\r
-                    $a = 0;\r
-                    $aa = 0;\r
-                    while (($answer=$question."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {\r
-                        $text = $this->js_value($tags,  $answer."['text'][0]['#']", true);\r
-                        if (strlen($text)) {\r
-                            if ($aa==0) { // first time only\r
-                                $str .= "\n";\r
-                                $str .= "I[$q] = new Array();\n";\r
-                                $str .= "I[$q][1] = new Array();\n";\r
-                            }\r
-                            $str .= "I[$q][1][$aa] = new Array();\n";\r
-                            $str .= "I[$q][1][$aa][0] = '$text';\n";\r
-                            $aa++;\r
-                        }\r
-                        $a++;\r
-                    }\r
-                    // add clue, if any answers were found\r
-                    if ($aa) {\r
-                        $clue = $this->js_value($tags, $question."['clue'][0]['#']", true);\r
-                        $str .= "I[$q][2] = '$clue';\n";\r
-                    }\r
-                    $q++;\r
-                }\r
-                break;\r
-            case 'jquiz':\r
-                $str .= "I=new Array();\n";\r
-                $tags = 'data,questions,question-record';\r
-                while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {\r
-\r
-                    $question_type = $this->int_value($tags, $question."['question-type'][0]['#']");\r
-                    $weighting = $this->int_value($tags, $question."['weighting'][0]['#']");\r
-                    $clue = $this->js_value($tags, $question."['clue'][0]['#']", true);\r
-\r
-                    $answers = $question."['answers'][0]['#']";\r
-\r
-                    $a = 0;\r
-                    $aa = 0;\r
-                    while (($answer = $answers."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {\r
-                        $text =     $this->js_value($tags,  $answer."['text'][0]['#']", true);\r
-                        $feedback = $this->js_value($tags,  $answer."['feedback'][0]['#']", true);\r
-                        $correct =  $this->int_value($tags, $answer."['correct'][0]['#']");\r
-                        $percent =  $this->int_value($tags, $answer."['percent-correct'][0]['#']");\r
-                        $include =  $this->int_value($tags, $answer."['include-in-mc-options'][0]['#']");\r
-                        if (strlen($text)) {\r
-                            if ($aa==0) { // first time only\r
-                                $str .= "\n";\r
-                                $str .= "I[$q] = new Array();\n";\r
-                                $str .= "I[$q][0] = $weighting;\n";\r
-                                $str .= "I[$q][1] = '$clue';\n";\r
-                                $str .= "I[$q][2] = '".($question_type-1)."';\n";\r
-                                $str .= "I[$q][3] = new Array();\n";\r
-                            }\r
-                            $str .= "I[$q][3][$aa] = new Array('$text','$feedback',$correct,$percent,$include);\n";\r
-                            $aa++;\r
-                        }\r
-                        $a++;\r
-                    }\r
-                    $q++;\r
-                }\r
-                break;\r
-        }\r
-        return $str;\r
-    }\r
-\r
-    function v6_expand_ClozeBody() {\r
-        $str = '';\r
-\r
-        // get drop down list of words, if required\r
-        $dropdownlist = '';\r
-        if ($this->v6_use_DropDownList()) {\r
-            $this->v6_set_WordList();\r
-            foreach ($this->wordlist as $word) {\r
-                $dropdownlist .= '<option value="'.$word.'">'.$word.'</option>';\r
-            }\r
-        }\r
-\r
-        // cache clues flag and caption\r
-        $includeclues = $this->v6_expand_Clues();\r
-        $cluecaption = $this->v6_expand_ClueCaption();\r
-\r
-        // detect if cloze starts with gap\r
-        $strpos = strpos($this->parent->source, '<gap-fill><question-record>');\r
-        if (is_numeric($strpos)) {\r
-            $startwithgap = true;\r
-        } else {\r
-            $startwithgap = false;\r
-        }\r
-\r
-        // initialize loop values\r
-        $q = 0;\r
-        $tags = 'data,gap-fill';\r
-        $question_record = "$tags,question-record";\r
-\r
-        // loop through text and gaps\r
-        do {\r
-            $text = $this->parent->xml_value($tags, "[0]['#'][$q]");\r
-            $gap = '';\r
-            if (($question="[$q]['#']") && $this->parent->xml_value($question_record, $question)) {\r
-                $gap .= '<span class="GapSpan" id="GapSpan'.$q.'">';\r
-                if ($this->v6_use_DropDownList()) {\r
-                    $gap .= '<select id="Gap'.$q.'"><option value=""></option>'.$dropdownlist.'</select>';\r
-                } else {\r
-                    // minimum gap size\r
-                    $gapsize = 6;\r
-\r
-                    // increase gap size to length of longest answer for this gap\r
-                    $a = 0;\r
-                    while (($answer=$question."['answer'][$a]['#']") && $this->parent->xml_value($question_record, $answer)) {\r
-                        $answertext = $this->parent->xml_value($question_record,  $answer."['text'][0]['#']");\r
-                        $answertext = preg_replace('|&[#a-zA-Z0-9]+;|', 'x', $answertext);\r
-                        $gapsize = max($gapsize, strlen($answertext));\r
-                        $a++;\r
-                    }\r
-\r
-                    $gap .= '<input type="text" id="Gap'.$q.'" onfocus="TrackFocus('.$q.')" onblur="LeaveGap()" class="GapBox" size="'.$gapsize.'"></input>';\r
-                }\r
-                if ($includeclues) {\r
-                    $clue = $this->parent->xml_value($question_record, $question."['clue'][0]['#']");\r
-                    if (strlen($clue)) {\r
-                        $gap .= '<button style="line-height: 1.0" class="FuncButton" onfocus="FuncBtnOver(this)" onmouseover="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="ShowClue('.$q.')">'.$cluecaption.'</button>';\r
-                    }\r
-                }\r
-                $gap .= '</span>';\r
-            }\r
-            if ($startwithgap) {\r
-                $str .= "$gap$text";\r
-            } else {\r
-                $str .= "$text$gap";\r
-            }\r
-            $q++;\r
-        } while (strlen($text) || strlen($gap));\r
-\r
-        return $str;\r
-    }\r
-\r
-    // JCloze quiztype\r
-\r
-    function v6_expand_WordList() {\r
-        $str = '';\r
-        if ($this->v6_include_WordList()) {\r
-            $this->v6_set_WordList();\r
-            $str = implode(' &#160;&#160; ', $this->wordlist);\r
-        }\r
-        return $str;\r
-    }\r
-    function v6_include_WordList() {\r
-        return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-word-list');\r
-    }\r
-    function v6_use_DropDownList() {\r
-        return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',use-drop-down-list');\r
-    }\r
-    function v6_set_WordList() {\r
-\r
-        if (isset($this->wordlist)) {\r
-            // do nothing\r
-        } else {\r
-            $this->wordlist = array();\r
-\r
-            // is the wordlist required\r
-            if ($this->v6_include_WordList() || $this->v6_use_DropDownList()) {\r
-\r
-                $q = 0;\r
-                $tags = 'data,gap-fill,question-record';\r
-                while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {\r
-                    $a = 0;\r
-                    $aa = 0;\r
-                    while (($answer=$question."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {\r
-                        $text = $this->parent->xml_value($tags,  $answer."['text'][0]['#']");\r
-                        $correct =  $this->int_value($tags, $answer."['correct'][0]['#']");\r
-                        if ($text && $correct) { // $correct is always true\r
-                            $this->wordlist[] = $text;\r
-                            $aa++;\r
-                        }\r
-                        $a++;\r
-                    }\r
-                    $q++;\r
-                }\r
-                $this->wordlist = array_unique($this->wordlist);\r
-                sort($this->wordlist);\r
-            }\r
-        }\r
-    }\r
-    function v6_expand_Keypad() {\r
-        $str = '';\r
-        if ($this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-keypad')) {\r
-\r
-            // these characters must always be in the keypad\r
-            $chars = array();\r
-            $this->add_keypad_chars($chars, $this->parent->xml_value('hotpot-config-file,global,keypad-characters'));\r
-\r
-            // append other characters used in the answers\r
-            $tags = '';\r
-            switch ($this->parent->quiztype) {\r
-                case 'jcloze':\r
-                    $tags = 'data,gap-fill,question-record';\r
-                    break;\r
-                case 'jquiz':\r
-                    $tags = 'data,questions,question-record';\r
-                    break;\r
-            }\r
-            if ($tags) {\r
-                $q = 0;\r
-                while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {\r
-\r
-                    if ($this->parent->quiztype=='jquiz') {\r
-                        $answers = $question."['answers'][0]['#']";\r
-                    } else {\r
-                        $answers = $question;\r
-                    }\r
-\r
-                    $a = 0;\r
-                    while (($answer=$answers."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {\r
-                        $this->add_keypad_chars($chars, $this->parent->xml_value($tags,  $answer."['text'][0]['#']"));\r
-                        $a++;\r
-                    }\r
-                    $q++;\r
-                }\r
-            }\r
-\r
-            // remove duplicate characters and sort\r
-            $chars = array_unique($chars);\r
-            usort($chars, "hotpot_sort_keypad_chars");\r
-\r
-            // create keypad buttons for each character\r
-            $str .= '<div class="Keypad">';\r
-            foreach ($chars as $char) {\r
-                $str .= "<button onclick=\"TypeChars('".$this->js_safe($char, true)."'); return false;\">$char</button>";\r
-            }\r
-            $str .= '</div>';\r
-        }\r
-        return $str;\r
-    }\r
-    function add_keypad_chars(&$chars, $text) {\r
-        if (preg_match_all('|&[^;]+;|i', $text, $more_chars)) {\r
-            $chars = array_merge($chars, $more_chars[0]);\r
-        }\r
-    }\r
-    function v6_expand_Correct() {\r
-        return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',guesses-correct');\r
-    }\r
-    function v6_expand_Incorrect() {\r
-        return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',guesses-incorrect');\r
-    }\r
-    function v6_expand_GiveHint() {\r
-        return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',next-correct-letter');\r
-    }\r
-    function v6_expand_CaseSensitive() {\r
-        return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',case-sensitive');\r
-    }\r
-\r
-    // JCross quiztype\r
-\r
-    function v6_expand_CluesAcrossLabel() {\r
-        return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',clues-across');\r
-    }\r
-    function v6_expand_CluesDownLabel() {\r
-        return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',clues-down');\r
-    }\r
-    function v6_expand_EnterCaption() {\r
-        return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',enter-caption');\r
-    }\r
-    function v6_expand_ShowHideClueList() {\r
-        $value = $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-clue-list');\r
-        return empty($value) ? ' style="display: none;"' : '';\r
-    }\r
-\r
-    // JCross specials\r
-\r
-    function v6_expand_CluesDown() {\r
-        return $this->v6_expand_jcross_clues('D');\r
-    }\r
-    function v6_expand_CluesAcross() {\r
-        return $this->v6_expand_jcross_clues('A');\r
-    }\r
-    function v6_expand_jcross_clues($direction) {\r
-        // $direction: A(cross) or D(own)\r
-        $row = NULL;\r
-        $r_max = 0;\r
-        $c_max = 0;\r
-        $this->v6_get_jcross_grid($row, $r_max, $c_max);\r
-\r
-        $i = 0; // clue index;\r
-        $str = '';\r
-        for($r=0; $r<=$r_max; $r++) {\r
-            for($c=0; $c<=$c_max; $c++) {\r
-                $aword = $this->get_jcross_aword($row, $r, $r_max, $c, $c_max);\r
-                $dword = $this->get_jcross_dword($row, $r, $r_max, $c, $c_max);\r
-                if ($aword || $dword) {\r
-                    $i++; // increment clue index\r
-\r
-                    // get the definition for this word\r
-                    $def = '';\r
-                    $word = ($direction=='A') ? $aword : $dword;\r
-                    $clues = $this->parent->xml_values('data,crossword,clues,item');\r
-                    foreach ($clues as $clue) {\r
-                        if ($clue['word'][0]['#']==$word) {\r
-                            $def = $clue['def'][0]['#'];\r
-                            $def = strtr($def, array('&#x003C;'=>'<', '&#x003E;'=>'>', "\n"=>'<br />'));\r
-                            break;\r
-                        }\r
-                    }\r
-\r
-                    if (!empty($def)) {\r
-                        $str .= '<tr><td class="ClueNum">'.$i.'. </td><td id="Clue_'.$direction.'_'.$i.'" class="Clue">'.$def.'</td></tr>';\r
-                    }\r
-                }\r
-            }\r
-        }\r
-        return $str;\r
-    }\r
-\r
-    // jcross6.js_\r
-\r
-    function v6_expand_LetterArray() {\r
-        $row = NULL;\r
-        $r_max = 0;\r
-        $c_max = 0;\r
-        $this->v6_get_jcross_grid($row, $r_max, $c_max);\r
-\r
-        $str = '';\r
-        for($r=0; $r<=$r_max; $r++) {\r
-            $str .= "L[$r] = new Array(";\r
-            for($c=0; $c<=$c_max; $c++) {\r
-                $str .= ($c>0 ? ',' : '')."'".$this->js_safe($row[$r]['cell'][$c]['#'], true)."'";\r
-            }\r
-            $str .= ");\n";\r
-        }\r
-        return $str;\r
-    }\r
-    function v6_expand_GuessArray() {\r
-        $row = NULL;\r
-        $r_max = 0;\r
-        $c_max = 0;\r
-        $this->v6_get_jcross_grid($row, $r_max, $c_max);\r
-\r
-        $str = '';\r
-        for($r=0; $r<=$r_max; $r++) {\r
-            $str .= "G[$r] = new Array('".str_repeat("','", $c_max)."');\n";\r
-        }\r
-        return $str;\r
-    }\r
-    function v6_expand_ClueNumArray() {\r
-        $row = NULL;\r
-        $r_max = 0;\r
-        $c_max = 0;\r
-        $this->v6_get_jcross_grid($row, $r_max, $c_max);\r
-\r
-        $i = 0; // clue index\r
-        $str = '';\r
-        for($r=0; $r<=$r_max; $r++) {\r
-            $str .= "CL[$r] = new Array(";\r
-            for($c=0; $c<=$c_max; $c++) {\r
-                if ($c>0) {\r
-                    $str .= ',';\r
-                }\r
-                $aword = $this->get_jcross_aword($row, $r, $r_max, $c, $c_max);\r
-                $dword = $this->get_jcross_dword($row, $r, $r_max, $c, $c_max);\r
-                if (empty($aword) && empty($dword)) {\r
-                    $str .= 0;\r
-                } else {\r
-                    $i++; // increment the clue index\r
-                    $str .= $i;\r
-                }\r
-            }\r
-            $str .= ");\n";\r
-        }\r
-        return $str;\r
-    }\r
-    function v6_expand_GridBody() {\r
-        $row = NULL;\r
-        $r_max = 0;\r
-        $c_max = 0;\r
-        $this->v6_get_jcross_grid($row, $r_max, $c_max);\r
-\r
-        $i = 0; // clue index;\r
-        $str = '';\r
-        for($r=0; $r<=$r_max; $r++) {\r
-            $str .= '<tr id="Row_'.$r.'">';\r
-            for($c=0; $c<=$c_max; $c++) {\r
-                if (empty($row[$r]['cell'][$c]['#'])) {\r
-                    $str .= '<td class="BlankCell">&nbsp;</td>';\r
-                } else {\r
-                    $aword = $this->get_jcross_aword($row, $r, $r_max, $c, $c_max);\r
-                    $dword = $this->get_jcross_dword($row, $r, $r_max, $c, $c_max);\r
-                    if (empty($aword) && empty($dword)) {\r
-                        $str .= '<td class="LetterOnlyCell"><span id="L_'.$r.'_'.$c.'">&nbsp;</span></td>';\r
-                    } else {\r
-                        $i++; // increment clue index\r
-                        $str .= '<td class="NumLetterCell"><a href="javascript:void(0);" class="GridNum" onclick="ShowClue('.$i.','.$r.','.$c.')">'.$i.'</a><span class="NumLetterCellText" id="L_'.$r.'_'.$c.'" onclick="ShowClue('.$i.','.$r.','.$c.')">&nbsp;&nbsp;&nbsp;</span></td>';\r
-                    }\r
-                }\r
-            }\r
-            $str .= '</tr>';\r
-        }\r
-        return $str;\r
-    }\r
-    function v6_get_jcross_grid(&$row, &$r_max, &$c_max) {\r
-        $row = $this->parent->xml_values('data,crossword,grid,row');\r
-        $r_max = 0;\r
-        $c_max = 0;\r
-        if (isset($row) && is_array($row)) {\r
-            for($r=0; $r<count($row); $r++) {\r
-                if (isset($row[$r]['cell']) && is_array($row[$r]['cell'])) {\r
-                    for($c=0; $c<count($row[$r]['cell']); $c++) {\r
-                        if (!empty($row[$r]['cell'][$c]['#'])) {\r
-                            $r_max = max($r, $r_max);\r
-                            $c_max = max($c, $c_max);\r
-                        }\r
-                    } // end for $c\r
-                }\r
-            } // end for $r\r
-        }\r
-    }\r
-    function get_jcross_dword(&$row, $r, $r_max, $c, $c_max) {\r
-        $str = '';\r
-        if (($r==0 || empty($row[$r-1]['cell'][$c]['#'])) && $r<$r_max && !empty($row[$r+1]['cell'][$c]['#'])) {\r
-            $str = $this->get_jcross_word($row, $r, $r_max, $c, $c_max, true);\r
-        }\r
-        return $str;\r
-    }\r
-    function get_jcross_aword(&$row, $r, $r_max, $c, $c_max) {\r
-        $str = '';\r
-        if (($c==0 || empty($row[$r]['cell'][$c-1]['#'])) && $c<$c_max && !empty($row[$r]['cell'][$c+1]['#'])) {\r
-            $str = $this->get_jcross_word($row, $r, $r_max, $c, $c_max, false);\r
-        }\r
-        return $str;\r
-    }\r
-    function get_jcross_word(&$row, $r, $r_max, $c, $c_max, $go_down=false) {\r
-        $str = '';\r
-        while ($r<=$r_max && $c<=$c_max && !empty($row[$r]['cell'][$c]['#'])) {\r
-            $str .= $row[$r]['cell'][$c]['#'];\r
-            if ($go_down) {\r
-                $r++;\r
-            } else {\r
-                $c++;\r
-            }\r
-        }\r
-        return $str;\r
-    }\r
-\r
-    // specials (JQuiz)\r
-\r
-    function v6_expand_QuestionOutput() {\r
-        $str = '';\r
-        $str .= '<ol class="QuizQuestions" id="Questions">'."\n";\r
-\r
-        $q = 0;\r
-        $tags = 'data,questions,question-record';\r
-        while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {\r
-\r
-            // get question\r
-            $question_text = $this->parent->xml_value($tags, $question."['question'][0]['#']");\r
-            $question_type = $this->parent->xml_value($tags, $question."['question-type'][0]['#']");\r
-\r
-            // check we have a question\r
-            if ($question_text && $question_type) {\r
-\r
-                $str .= '<li class="QuizQuestion" id="Q_'.$q.'" style="display: none;">';\r
-                $str .= '<p class="QuestionText">'.$question_text.'</p>';\r
-\r
-                if (\r
-                    $question_type==HOTPOT_JQUIZ_SHORTANSWER || \r
-                    $question_type==HOTPOT_JQUIZ_HYBRID\r
-                ) {\r
-                    $str .= '<div class="ShortAnswer" id="Q_'.$q.'_SA"><form method="post" action="" onsubmit="return false;"><div>';\r
-                    $str .= '<input type="text" id="Q_'.$q.'_Guess" onfocus="TrackFocus('."'".'Q_'.$q.'_Guess'."'".')" onblur="LeaveGap()" class="ShortAnswerBox" size="9"></input><br /><br />';\r
-\r
-                    $caption = $this->v6_expand_CheckCaption();\r
-                    $str .= $this->v6_expand_jquiz_button($caption, "CheckShortAnswer($q)");\r
-\r
-                    if ($this->v6_expand_Hint()) {\r
-                        $caption = $this->v6_expand_HintCaption();\r
-                        $str .= $this->v6_expand_jquiz_button($caption, "ShowHint($q)");\r
-                    }\r
-\r
-                    if ($this->v6_expand_ShowAnswer()) {\r
-                        $caption = $this->v6_expand_ShowAnswerCaption();\r
-                        $str .= $this->v6_expand_jquiz_button($caption, "ShowAnswers($q)");\r
-                    }\r
-\r
-                    $str .= '</div></form></div>';\r
-                }\r
-\r
-                if (\r
-                    $question_type==HOTPOT_JQUIZ_MULTICHOICE || \r
-                    $question_type==HOTPOT_JQUIZ_HYBRID ||\r
-                    $question_type==HOTPOT_JQUIZ_MULTISELECT\r
-                ) {\r
-\r
-                    switch ($question_type) {\r
-                        case HOTPOT_JQUIZ_MULTICHOICE: \r
-                            $str .= '<ol class="MCAnswers">'."\n";\r
-                        break;\r
-                        case HOTPOT_JQUIZ_HYBRID:\r
-                            $str .= '<ol class="MCAnswers" id="Q_'.$q.'_Hybrid_MC" style="display: none;">'."\n";\r
-                        break;\r
-                        case HOTPOT_JQUIZ_MULTISELECT:\r
-                            $str .= '<ol class="MSelAnswers">'."\n";\r
-                        break;\r
-                    }\r
-\r
-                    $a = 0;\r
-                    $aa = 0;\r
-                    $answers = $question."['answers'][0]['#']";\r
-                    while (($answer = $answers."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {\r
-                        $text = $this->parent->xml_value($tags, $answer."['text'][0]['#']");\r
-                        if ($text) {\r
-                            switch ($question_type) {\r
-                                case HOTPOT_JQUIZ_MULTICHOICE:\r
-                                case HOTPOT_JQUIZ_HYBRID:\r
-                                    $include = $this->int_value($tags, $answer."['include-in-mc-options'][0]['#']");\r
-                                    if ($include) {\r
-                                        $str .= '<li id="Q_'.$q.'_'.$aa.'"><button class="FuncButton" onfocus="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseover="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" id="Q_'.$q.'_'.$aa.'_Btn" onclick="CheckMCAnswer('.$q.','.$aa.',this)">&nbsp;&nbsp;?&nbsp;&nbsp;</button>&nbsp;&nbsp;'.$text.'</li>'."\n";\r
-                                    }\r
-                                break;\r
-                                case HOTPOT_JQUIZ_MULTISELECT:\r
-                                    $str .= '<li id="Q_'.$q.'_'.$aa.'"><form method="post" action="" onsubmit="return false;"><div><input type="checkbox" id="Q_'.$q.'_'.$aa.'_Chk" class="MSelCheckbox" />'.$text.'</div></form></li>'."\n";\r
-                                break;\r
-                            }\r
-                            $aa++;\r
-                        }\r
-                        $a++;\r
-                    }\r
-\r
-                    $str .= '</ol>';\r
-\r
-                    if ($question_type==HOTPOT_JQUIZ_MULTISELECT) {\r
-                        $caption = $this->v6_expand_CheckCaption();\r
-                        $str .= $this->v6_expand_jquiz_button($caption, "CheckMultiSelAnswer($q)");\r
-                    }\r
-                }\r
-\r
-                $str .= "</li>\n";\r
-            }\r
-            $q++;\r
-\r
-        } // end while $question\r
-\r
-        $str .= "</ol>\n";\r
-        return $str;\r
-    }\r
-\r
-    function v6_expand_jquiz_button($caption, $onclick) {\r
-        return '<button class="FuncButton" onfocus="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseover="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="'.$onclick.'">'.$caption.'</button>';\r
-    }\r
-\r
-    // jquiz.js_\r
-\r
-    function v6_expand_MultiChoice() {\r
-        return $this->v6_jquiz_question_type(HOTPOT_JQUIZ_MULTICHOICE);\r
-    }\r
-    function v6_expand_ShortAnswer() {\r
-        return $this->v6_jquiz_question_type(HOTPOT_JQUIZ_SHORTANSWER);\r
-    }\r
-    function v6_expand_MultiSelect() {\r
-        return $this->v6_jquiz_question_type(HOTPOT_JQUIZ_MULTISELECT);\r
-    }\r
-    function v6_jquiz_question_type($type) {\r
-        // does this quiz have any questions of the given $type?\r
-        $flag = false;\r
-\r
-        $q = 0;\r
-        $tags = 'data,questions,question-record';\r
-        while (($question = "[$q]['#']") && $this->parent->xml_value($tags, $question)) {\r
-            $question_type = $this->parent->xml_value($tags, $question."['question-type'][0]['#']");\r
-            if ($question_type==$type || ($question_type==HOTPOT_JQUIZ_HYBRID && ($type==HOTPOT_JQUIZ_MULTICHOICE || $type==HOTPOT_JQUIZ_SHORTANSWER))) {\r
-                $flag = true;\r
-                break;\r
-            }\r
-            $q++;\r
-        }\r
-        return $flag;\r
-    }\r
-    function v6_expand_CorrectFirstTime() {\r
-        return $this->js_value('hotpot-config-file,global,correct-first-time');\r
-    }\r
-    function v6_expand_ContinuousScoring() {\r
-        return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',continuous-scoring');\r
-    }\r
-    function v6_expand_ShowCorrectFirstTime() {\r
-        return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',show-correct-first-time');\r
-    }\r
-    function v6_expand_ShuffleAs() {\r
-        return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',shuffle-answers');\r
-    }\r
-\r
-    function v6_expand_DefaultRight() {\r
-        return $this->v6_expand_GuessCorrect();\r
-    }\r
-    function v6_expand_DefaultWrong() {\r
-        return $this->v6_expand_GuessIncorrect();\r
-    }\r
-    function v6_expand_ShowAllQuestionsCaptionJS() {\r
-        return $this->v6_expand_ShowAllQuestionsCaption();\r
-    }\r
-    function v6_expand_ShowOneByOneCaptionJS() {\r
-        return $this->v6_expand_ShowOneByOneCaption();\r
-    }\r
-\r
-    // hp6checkshortanswers.js_ (JQuiz)\r
-\r
-    function v6_expand_CorrectList() {\r
-        return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',correct-answers');\r
-    }\r
-    function v6_expand_HybridTries() {\r
-        return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',short-answer-tries-on-hybrid-q');\r
-    }\r
-    function v6_expand_PleaseEnter() {\r
-        return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',enter-a-guess');\r
-    }\r
-    function v6_expand_PartlyIncorrect() {\r
-        return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',partly-incorrect');\r
-    }\r
-    function v6_expand_ShowAnswerCaption() {\r
-        return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',show-answer-caption');\r
-    }\r
-    function v6_expand_ShowAlsoCorrect() {\r
-        return $this->bool_value('hotpot-config-file,global,show-also-correct');\r
-    }\r
-\r
-} // end class\r
-function hotpot_sort_keypad_chars($a, $b) {\r
-    $a =  hotpot_keypad_sort_value($a);\r
-    $b =  hotpot_keypad_sort_value($b);\r
-    return ($a<$b) ? -1 : ($a==$b ? 0 : 1);\r
-}\r
-function hotpot_keypad_sort_value($char) {\r
-\r
-    // hexadecimal\r
-    if (preg_match('|&#x([0-9A-F]+);|ie', $char, $matches)) {\r
-        $ord = hexdec($matches[1]);\r
-\r
-    // decimal\r
-    } else if (preg_match('|&#(\d+);|i', $char, $matches)) {\r
-        $ord = intval($matches[1]);\r
-\r
-    // other html entity\r
-    } else if (preg_match('|&[^;]+;|', $char, $matches)) {\r
-        $char = html_entity_decode($matches[0]);\r
-        $ord = empty($char) ? 0 : ord($char);\r
-\r
-    // not an html entity\r
-    } else {\r
-        $char = trim($char);\r
-        $ord = empty($char) ? 0 : ord($char);\r
-    }\r
-\r
-    // lowercase letters (plain or accented)\r
-    if (($ord>=97 && $ord<=122) || ($ord>=224 && $ord<=255)) {\r
-        $sort_value = ($ord-31).'.'.sprintf('%04d', $ord);\r
-\r
-    // all other characters\r
-    } else {\r
-        $sort_value = $ord;\r
-    }\r
-\r
-    return $sort_value;\r
-} \r
-\r
-?>\r
+<?PHP 
+
+class hotpot_xml_quiz_template extends hotpot_xml_template_default {
+
+    // constructor function for this class
+    function hotpot_xml_quiz_template(&$parent) {
+
+        $this->parent = &$parent;
+        
+        $get_js = optional_param('js', false);
+        $get_css = optional_param('css', false);
+
+        if (!empty($get_css)) {
+            // set $this->css
+            $this->v6_expand_StyleSheet(); 
+
+        } else if (!empty($get_js)) {
+            // set $this->js
+            $this->read_template($this->parent->draganddrop.$this->parent->quiztype.'6.js_', 'js');
+
+        } else {
+            // set $this->html
+            $this->read_template($this->parent->draganddrop.$this->parent->quiztype.'6.ht_', 'html');
+        }
+
+        // expand special strings, if any
+        $pattern = '';
+        switch ($this->parent->quiztype) {
+            case 'jcloze':
+                $pattern = '/\[(PreloadImageList)\]/';
+                break;
+            case 'jcross':
+                $pattern = '/\[(PreloadImageList|ShowHideClueList)\]/';
+                break;
+            case 'jmatch':
+                $pattern = '/\[(PreloadImageList|QsToShow|FixedArray|DragArray)\]/';
+                break;
+            case 'jmix':
+                $pattern = '/\[(PreloadImageList|SegmentArray|AnswerArray)\]/';
+                break;
+            case 'jquiz':
+                $pattern = '/\[(PreloadImageList|QsToShow)\]/';
+                break;
+        }
+        if (!empty($pattern)) {
+            $this->expand_strings('html', $pattern);
+        }
+    }
+
+    // captions and messages
+
+    function v6_expand_AlsoCorrect() {
+        return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',also-correct');
+    }
+    function v6_expand_CapitalizeFirst() {
+        return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',capitalize-first-letter');
+    }
+    function v6_expand_CheckCaption() {
+        return $this->parent->xml_value('hotpot-config-file,global,check-caption');
+    }
+    function v6_expand_CorrectIndicator() {
+        return $this->js_value('hotpot-config-file,global,correct-indicator');
+    }
+    function v6_expand_Back() {
+        return $this->int_value('hotpot-config-file,global,include-back');
+    }
+    function v6_expand_BackCaption() {
+        return $this->parent->xml_value('hotpot-config-file,global,back-caption');
+    }
+    function v6_expand_ClickToAdd() {
+        return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',click-to-add');
+    }
+    function v6_expand_ClueCaption() {
+        return $this->parent->xml_value('hotpot-config-file,global,clue-caption');
+    }
+    function v6_expand_Clues() {
+        return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-clues');
+    }
+    function v6_expand_Contents() {
+        return $this->int_value('hotpot-config-file,global,include-contents');
+    }
+    function v6_expand_ContentsCaption() {
+        return $this->parent->xml_value('hotpot-config-file,global,contents-caption');
+    }
+    function v6_expand_GuessCorrect() {
+        return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',guess-correct');
+    }
+    function v6_expand_GuessIncorrect() {
+        return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',guess-incorrect');
+    }
+    function v6_expand_Hint() {
+        return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-hint');
+    }
+    function v6_expand_HintCaption() {
+        return $this->parent->xml_value('hotpot-config-file,global,hint-caption');
+    }
+    function v6_expand_IncorrectIndicator() {
+        return $this->js_value('hotpot-config-file,global,incorrect-indicator');
+    }
+    function v6_expand_LastQCaption() {
+        return $this->parent->xml_value('hotpot-config-file,global,last-q-caption');
+    }
+    function v6_expand_NextCorrect() {
+        $value = $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',next-correct-part');
+        if (empty($value)) { // jquiz
+            $value = $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',next-correct-letter');
+        }
+        return $value;
+    }
+    function v6_expand_NextEx() {
+        return $this->int_value('hotpot-config-file,global,include-next-ex');
+    }
+    function v6_expand_NextExCaption() {
+        return $this->parent->xml_value('hotpot-config-file,global,next-ex-caption');
+    }
+    function v6_expand_NextQCaption() {
+        return $this->parent->xml_value('hotpot-config-file,global,next-q-caption');
+    }
+    function v6_expand_OKCaption() {
+        return $this->parent->xml_value('hotpot-config-file,global,ok-caption');
+    }
+    function v6_expand_Restart() {
+        return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-restart');
+    }
+    function v6_expand_RestartCaption() {
+        return $this->parent->xml_value('hotpot-config-file,global,restart-caption');
+    }
+    function v6_expand_ShowAllQuestionsCaption() {
+        return $this->js_value('hotpot-config-file,global,show-all-questions-caption');
+    }
+    function v6_expand_ShowOneByOneCaption() {
+        return $this->js_value('hotpot-config-file,global,show-one-by-one-caption');
+    }
+    function v6_expand_TheseAnswersToo() {
+        return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',also-correct');
+    }
+    function v6_expand_ThisMuch() {
+        return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',this-much-correct');
+    }
+    function v6_expand_Undo() {
+        return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-undo');
+    }
+    function v6_expand_UndoCaption() {
+        return $this->parent->xml_value('hotpot-config-file,global,undo-caption');
+    }
+    function v6_expand_YourScoreIs() {
+        return $this->js_value('hotpot-config-file,global,your-score-is');
+    }
+
+    // reading
+
+    function v6_expand_Reading() {
+        return $this->int_value('data,reading,include-reading');
+    }
+    function v6_expand_ReadingText() {
+        $title = $this->v6_expand_ReadingTitle();
+        $value = $this->parent->xml_value('data,reading,reading-text');
+        $value = empty($value) ? '' : ('<div class="ReadingText">'.$value.'</div>');
+        return $title.$value;
+    }
+    function v6_expand_ReadingTitle() {
+        $value = $this->parent->xml_value('data,reading,reading-title');
+        return empty($value) ? '' : ('<h3 class="ExerciseSubtitle">'.$value.'</h3>');
+    }
+
+    // timer 
+
+    function v6_expand_Timer() {
+        return $this->int_value('data,timer,include-timer');
+    }
+    function v6_expand_JSTimer() {
+        return $this->read_template('hp6timer.js_');
+    }
+    function v6_expand_Seconds() {
+        return $this->parent->xml_value('data,timer,seconds');
+    }
+
+    // send results 
+
+    function v6_expand_SendResults() {
+        return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',send-email');
+    }
+    function v6_expand_JSSendResults() {
+        return $this->read_template('hp6sendresults.js_');
+    }
+    function v6_expand_FormMailURL() {
+        return $this->parent->xml_value('hotpot-config-file,global,formmail-url');
+    }
+    function v6_expand_EMail() {
+        return $this->parent->xml_value('hotpot-config-file,global,email');
+    }
+    function v6_expand_NamePlease() {
+        return $this->js_value('hotpot-config-file,global,name-please');
+    }
+
+    // preload images
+
+    function v6_expand_PreloadImages() {
+        $value = $this->v6_expand_PreloadImageList();
+        return empty($value) ? false : true;
+    }
+    function v6_expand_PreloadImageList() {
+
+        // check it has not been set already
+        if (!isset($this->PreloadImageList)) {
+
+            // the list of image urls
+            $list = array();
+
+            // extract <img> tags
+            $img_tag = htmlspecialchars('|&#x003C;img.*?src="(.*?)".*?&#x003E;|is');
+            if (preg_match_all($img_tag, $this->parent->source, $matches)) {
+                $list = $matches[1];
+
+                // remove duplicates
+                $list = array_unique($list);
+            }
+
+            // convert to comma delimited string
+            $this->PreloadImageList = empty($list) ? '' : "'".implode(',', $list)."'";
+        }
+        return $this->PreloadImageList;
+    }
+
+    // html files (all quiz types)
+
+    function v6_expand_PlainTitle() {
+        return $this->parent->xml_value('data,title');
+    }
+    function v6_expand_ExerciseSubtitle() {
+        return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',exercise-subtitle');
+    }
+    function v6_expand_Instructions() {
+        return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',instructions');
+    }
+    function v6_expand_DublinCoreMetadata() {
+        $dc = '<link rel="schema.DC" href="'.$this->parent->xml_value('', "['rdf:RDF'][0]['@']['xmlns:dc']").'" />'."\n";
+        if (is_string($this->parent->xml_value('rdf:RDF,rdf:Description'))) {
+            // do nothing (there is no more dc info)
+        } else {
+            $dc .= '<meta name="DC:Creator" content="'.$this->parent->xml_value('rdf:RDF,rdf:Description,dc:creator').'" />'."\n";
+            $dc .= '<meta name="DC:Title" content="'.strip_tags($this->parent->xml_value('rdf:RDF,rdf:Description,dc:title')).'" />'."\n";
+        }
+        return $dc;
+    }
+    function v6_expand_FullVersionInfo() {
+        global $CFG;
+        require_once($CFG->hotpotroot.DIRECTORY_SEPARATOR.'version.php'); // set $module
+        return $this->parent->xml_value('version').'.x (Moodle '.$CFG->release.', hotpot-module '.$this->parent->obj_value($module, 'release').')';
+    }
+    function v6_expand_HeaderCode() {
+        return $this->parent->xml_value('hotpot-config-file,global,header-code');
+    }
+    function v6_expand_StyleSheet() {
+        $this->read_template('hp6.cs_', 'css');
+        $this->css = hotpot_convert_stylesheets_urls($this->parent->get_baseurl(), $this->parent->reference, $this->css);
+        return $this->css;
+    }
+
+    // stylesheet (hp6.cs_)
+
+    function v6_expand_PageBGColor() {
+        return $this->parent->xml_value('hotpot-config-file,global,page-bg-color');
+    }
+    function v6_expand_GraphicURL() {
+        return $this->parent->xml_value('hotpot-config-file,global,graphic-url');
+    }
+    function v6_expand_ExBGColor() {
+        return $this->parent->xml_value('hotpot-config-file,global,ex-bg-color');
+    }
+
+    function v6_expand_FontFace() {
+        return $this->parent->xml_value('hotpot-config-file,global,font-face');
+    }
+    function v6_expand_FontSize() {
+        return $this->parent->xml_value('hotpot-config-file,global,font-size');
+    }
+    function v6_expand_TextColor() {
+        return $this->parent->xml_value('hotpot-config-file,global,text-color');
+    }
+    function v6_expand_TitleColor() {
+        return $this->parent->xml_value('hotpot-config-file,global,title-color');
+    }
+    function v6_expand_LinkColor() {
+        return $this->parent->xml_value('hotpot-config-file,global,link-color');
+    }
+    function v6_expand_VLinkColor() {
+        return $this->parent->xml_value('hotpot-config-file,global,vlink-color');
+    }
+
+    function v6_expand_NavTextColor() {
+        return $this->parent->xml_value('hotpot-config-file,global,page-bg-color');
+    }
+    function v6_expand_NavBarColor() {
+        return $this->parent->xml_value('hotpot-config-file,global,nav-bar-color');
+    }
+    function v6_expand_NavLightColor() {
+        $color = $this->parent->xml_value('hotpot-config-file,global,nav-bar-color');
+        return $this->get_halfway_color($color, '#ffffff'); 
+    }
+    function v6_expand_NavShadeColor() {
+        $color = $this->parent->xml_value('hotpot-config-file,global,nav-bar-color');
+        return $this->get_halfway_color($color, '#000000');
+    }
+
+    function v6_expand_FuncLightColor() { // top-left of buttons
+        $color = $this->parent->xml_value('hotpot-config-file,global,ex-bg-color');
+        return $this->get_halfway_color($color, '#ffffff');
+    }
+    function v6_expand_FuncShadeColor() { // bottom right of buttons
+        $color = $this->parent->xml_value('hotpot-config-file,global,ex-bg-color');
+        return $this->get_halfway_color($color, '#000000');
+    }
+
+    // navigation buttons
+
+    function v6_expand_NavButtons() {
+        $back = $this->v6_expand_Back();
+        $next_ex = $this->v6_expand_NextEx();
+        $contents = $this->v6_expand_Contents();
+        return (empty($back) && empty($next_ex) && empty($contents) ? false : true);
+    }
+    function v6_expand_NavBarJS() {
+        return $this->v6_expand_NavButtons();
+    }
+
+    // js files (all quiz types)
+
+    function v6_expand_JSBrowserCheck() {
+        return $this->read_template('hp6browsercheck.js_');
+    }
+    function v6_expand_JSButtons() {
+        return $this->read_template('hp6buttons.js_');
+    }
+    function v6_expand_JSCard() {
+        return $this->read_template('hp6card.js_');
+    }
+    function v6_expand_JSCheckShortAnswer() {
+        return $this->read_template('hp6checkshortanswer.js_');
+    }
+    function v6_expand_JSHotPotNet() {
+        return $this->read_template('hp6hotpotnet.js_');
+    }
+    function v6_expand_JSShowMessage() {
+        return $this->read_template('hp6showmessage.js_');
+    }
+    function v6_expand_JSUtilities() {
+        return $this->read_template('hp6utilities.js_');
+    }
+
+    // js files
+
+    function v6_expand_JSJCloze6() {
+        return $this->read_template('jcloze6.js_');
+    }
+    function v6_expand_JSJCross6() {
+        return $this->read_template('jcross6.js_');
+    }
+    function v6_expand_JSJMatch6() {
+        return $this->read_template('jmatch6.js_');
+    }
+    function v6_expand_JSJMix6() {
+        return $this->read_template('jmix6.js_');
+    }
+    function v6_expand_JSJQuiz6() {
+        return $this->read_template('jquiz6.js_');
+    }
+
+    // drag and drop
+
+    function v6_expand_JSDJMatch6() {
+        return $this->read_template('djmatch6.js_');
+    }
+    function v6_expand_JSDJMix6() {
+        return $this->read_template('djmix6.js_');
+    }
+
+    // what are these for?
+
+    function v6_expand_JSFJMatch6() {
+        return $this->read_template('fjmatch6.js_');
+    }
+    function v6_expand_JSFJMix6() {
+        return $this->read_template('fjmix6.js_');
+    }
+
+    // jmatch6.js_
+
+    function v6_expand_ShuffleQs() {
+        return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',shuffle-questions');
+    }
+    function v6_expand_QsToShow() {
+        $i = $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',show-limited-questions');
+        if ($i) {
+            $i = $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',questions-to-show');
+        }
+        if (empty($i)) {
+            $i = 0;
+            switch ($this->parent->quiztype) {
+                case 'jmatch':
+                    $values = $this->parent->xml_values('data,matching-exercise,pair');
+                    $i = count($values);
+                    break;
+                case 'jquiz':
+                    while ($this->parent->xml_value('data,questions,question-record', "[$i]['#']['question'][0]['#']")) {
+                        $i++;
+                    }
+                    break;
+            } // end switch
+        }
+        return $i;
+    }
+    function v6_expand_MatchDivItems() {
+        $l_items = array();
+        $r_items = array();
+        $this->get_jmatch_items($l_items, $r_items);
+
+        $l_keys = $this->shuffle_jmatch_items($l_items);
+        $r_keys = $this->shuffle_jmatch_items($r_items);
+
+        $options = '<option value="x">'.$this->parent->xml_value('data,matching-exercise,default-right-item').'</option>';
+        foreach ($r_keys as $key) {
+            $options .= '<option value="'.$key.'">'.$r_items[$key]['text'][0]['#'].'</option>'."\n";
+        }
+
+        $str = '';
+        foreach ($l_keys as $key) {
+            $str .= '<tr><td class="LeftItem">'.$l_items[$key]['text'][0]['#'].'</td>';
+            $str .= '<td class="RightItem"><select id="s'.$key.'_'.$key.'">'.$options.'</select></td>';
+            $str .= '<td></td></tr>';
+        }
+        return $str;
+    }
+
+    // jmix6.js_
+
+    function v6_expand_Punctuation() {
+        $tags = 'data,jumbled-order-exercise';
+        $chars = array_merge(
+            $this->jmix_Punctuation("$tags,main-order,segment"),
+            $this->jmix_Punctuation("$tags,alternate")
+        );
+        $chars = array_unique($chars);
+        $chars = implode('', $chars);
+        $chars = $this->js_safe($chars, true);
+        return $chars;
+    }
+    function jmix_Punctuation($tags) {
+        $chars = array();
+
+        // all punctutation except '&#;' (because they are used in html entities)
+        $ENTITIES = $this->jmix_encode_punctuation('!"$%'."'".'()*+,-./:<=>?@[\]^_`{|}~');
+        $pattern = "/&#x([0-9A-F]+);/i";
+        $i = 0;
+
+        // get next segment (or alternate answer)
+        while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {
+
+            // convert low-ascii punctuation to entities
+            $value = strtr($value, $ENTITIES);
+
+            // extract all hex HTML entities
+            if (preg_match_all($pattern, $value, $matches)) {
+
+                // loop through hex entities
+                $m_max = count($matches[0]);
+                for ($m=0; $m<$m_max; $m++) {
+
+                    // convert to hex number
+                    eval('$hex=0x'.$matches[1][$m].';');
+
+                    // is this a punctuation character?
+                    if (
+                        ($hex>=0x0020 && $hex<=0x00BF) || // ascii punctuation
+                        ($hex>=0x2000 && $hex<=0x206F) || // general punctuation
+                        ($hex>=0x3000 && $hex<=0x303F) || // CJK punctuation
+                        ($hex>=0xFE30 && $hex<=0xFE4F) || // CJK compatability
+                        ($hex>=0xFE50 && $hex<=0xFE6F) || // small form variants
+                        ($hex>=0xFF00 && $hex<=0xFF40) || // halfwidth and fullwidth forms (1)
+                        ($hex>=0xFF5B && $hex<=0xFF65) || // halfwidth and fullwidth forms (2)
+                        ($hex>=0xFFE0 && $hex<=0xFFEE)    // halfwidth and fullwidth forms (3)
+                    ) {
+                        // add this character
+                        $chars[] = $matches[0][$m];
+                    }
+                }
+            }
+            $i++;
+        }
+
+        return $chars;
+    }
+    function v6_expand_OpenPunctuation() {
+        $tags = 'data,jumbled-order-exercise';
+        $chars = array_merge(
+            $this->jmix_OpenPunctuation("$tags,main-order,segment"),
+            $this->jmix_OpenPunctuation("$tags,alternate")
+        );
+        $chars = array_unique($chars);
+        $chars = implode('', $chars);
+        $chars = $this->js_safe($chars, true);
+        return $chars;
+    }
+    function jmix_OpenPunctuation($tags) {
+        $chars = array();
+
+        // unicode punctuation designations (pi="initial quote", ps="open")
+        //  http://www.sql-und-xml.de/unicode-database/pi.html
+        //  http://www.sql-und-xml.de/unicode-database/ps.html
+        $pi = '0022|0027|00AB|2018|201B|201C|201F|2039';
+        $ps = '0028|005B|007B|0F3A|0F3C|169B|201A|201E|2045|207D|208D|2329|23B4|2768|276A|276C|276E|2770|2772|2774|27E6|27E8|27EA|2983|2985|2987|2989|298B|298D|298F|2991|2993|2995|2997|29D8|29DA|29FC|3008|300A|300C|300E|3010|3014|3016|3018|301A|301D|FD3E|FE35|FE37|FE39|FE3B|FE3D|FE3F|FE41|FE43|FE47|FE59|FE5B|FE5D|FF08|FF3B|FF5B|FF5F|FF62';
+        $pattern = "/(&#x($pi|$ps);)/i";
+
+        $ENTITIES = $this->jmix_encode_punctuation('"'."'".'(<[{');
+
+        $i = 0;
+        while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {
+            $value = strtr($value, $ENTITIES);
+            if (preg_match_all($pattern, $value, $matches)) {
+                $chars = array_merge($chars, $matches[0]);
+            } 
+            $i++;
+        }
+
+        return $chars;
+    }
+    function jmix_encode_punctuation($str) {
+        $ENTITIES = array();
+        $i_max = strlen($str);
+        for ($i=0; $i<$i_max; $i++) {
+            $ENTITIES[$str{$i}] = '&#x'.sprintf('%04X', ord($str{$i})).';';
+        }
+        return $ENTITIES;
+    }
+    function v6_expand_ExerciseTitle() {
+        return $this->parent->xml_value('data,title');
+    }
+
+    // Jmix specials
+
+    function v6_expand_SegmentArray() {
+
+        $segments = array();
+        $values = array();
+        $VALUES = array();
+
+        // XML tags to the start of a segment
+        $tags = 'data,jumbled-order-exercise,main-order,segment';
+
+        $i = 0;
+        while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {
+            $VALUE = strtoupper($value);
+            $key = array_search($VALUE, $VALUES);
+            if (is_numeric($key)) {
+                $segments[] = $key;
+            } else {
+                $segments[] = $i;
+                $values[$i] = $value;
+                $VALUES[$i] = $VALUE;
+            }
+            $i++;
+        }
+
+        $this->seed_random_number_generator();
+        $keys = array_keys($segments);
+        shuffle($keys);
+
+        $str = '';
+        for($i=0; $i<count($keys); $i++) {
+            $key = $segments[$keys[$i]];
+            $str .= "Segments[$i] = new Array();\n";
+            $str .= "Segments[$i][0] = '".$this->js_safe($values[$key], true)."';\n";
+            $str .= "Segments[$i][1] = ".($key+1).";\n";
+            $str .= "Segments[$i][2] = 0;\n";
+        }
+        return $str;
+    }
+    function v6_expand_AnswerArray() {
+
+        $segments = array();
+        $values = array();
+        $VALUES = array();
+        $escapedvalues = array();
+
+        // XML tags to the start of a segment
+        $tags = 'data,jumbled-order-exercise,main-order,segment';
+
+        $i = 0;
+        while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {
+            $VALUE = strtoupper($value);
+            $key = array_search($VALUE, $VALUES);
+            if (is_numeric($key)) {
+                $segments[] = $key+1;
+            } else {
+                $segments[] = $i+1;
+                $values[$i] = $value;
+                $VALUES[$i] = $VALUE;
+                $escapedvalues[] = preg_quote($value, '/');
+            }
+            $i++;
+        }
+
+        // start the answers array
+        $a = 0;
+        $str = 'Answers['.($a++).'] = new Array('.implode(',', $segments).");\n";
+
+        // pattern to match the next part of an alternate answer
+        $pattern = '/^('.implode('|', $escapedvalues).')\\s*/i';
+
+        // XML tags to the start of an alternate answer
+        $tags = 'data,jumbled-order-exercise,alternate';
+
+        $i = 0;
+        while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {
+            $segments = array();
+            while (strlen($value) && preg_match($pattern, $value, $matches)) {
+                $key = array_search($matches[1], $values);
+                if (is_numeric($key)) {
+                    $segments[] = $key+1;
+                    $value = substr($value, strlen($matches[0]));
+                } else {
+                    // invalid alternate sequence
+                    $segments = array();
+                    break;
+                }
+            }
+            if (count($segments)) {
+                $str .= 'Answers['.($a++).'] = new Array('.implode(',', $segments).");\n";
+            }
+            $i++;
+        }
+        return $str;
+    }
+
+    // ===============================================================
+
+    // JMix (jmix6.js_)
+
+    function v6_expand_RemainingWords() {
+        return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',remaining-words');
+    }
+    function v6_expand_TimesUp() {
+        return $this->parent->xml_value('hotpot-config-file,global,times-up');
+    }
+
+    // nav bar
+
+    function v6_expand_NavBar($navbarid='') {
+        $this->navbarid = $navbarid;
+
+        $tag = 'navbar';
+        $this->read_template('hp6navbar.ht_', $tag);
+
+        unset($this->navbarid);
+
+        return $this->$tag;
+    }
+    function v6_expand_TopNavBar() {
+        return $this->v6_expand_NavBar('TopNavBar');
+    }
+    function v6_expand_BottomNavBar() {
+        return $this->v6_expand_NavBar('BottomNavBar');
+    }
+
+    // hp6navbar.ht_
+
+    function v6_expand_NavBarID() {
+        // $this->navbarid is set in "$this->v6_expand_NavBar"
+        return empty($this->navbarid) ? '' : $this->navbarid;
+    }
+    function v6_expand_ContentsURL() {
+        $url = $this->parent->xml_value('hotpot-config-file,global,contents-url');
+        if ($url) {
+            $url = hotpot_convert_navbutton_url($this->parent->get_baseurl(), $this->parent->reference, $url, $this->parent->course);
+        }
+        return $url;
+    }
+    function v6_expand_NextExURL() {
+        $url = $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',next-ex-url');
+        if ($url) {
+            $url = hotpot_convert_navbutton_url($this->parent->get_baseurl(), $this->parent->reference, $url, $this->parent->course);
+        }
+        return $url;
+    }
+
+    // conditional blocks
+
+    function v6_expand_ShowAnswer() {
+        return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-show-answer');
+    }
+    function v6_expand_Slide() {
+        return true; // whats's this (JMatch drag and drop)
+    }
+
+    // specials (JMatch)
+
+    function v6_expand_FixedArray() {
+        $l_items = array();
+        $r_items = array();
+        $this->get_jmatch_items($l_items, $r_items);
+
+        $str = '';
+        foreach ($l_items as $i=>$item) {
+            $str .= "F[$i] = new Array();\n";
+            $str .= "F[$i][0] = '".$this->js_safe($item['text'][0]['#'], true)."';\n";
+            $str .= "F[$i][1] = ".($i+1).";\n";
+        }
+        return $str;
+    }
+    function v6_expand_DragArray() {
+        $l_items = array();
+        $r_items = array();
+        $this->get_jmatch_items($l_items, $r_items);
+
+        $str = '';
+        foreach ($r_items as $i=>$item) {
+            $str .= "D[$i] = new Array();\n";
+            $str .= "D[$i][0] = '".$this->js_safe($item['text'][0]['#'], true)."';\n";
+            $str .= "D[$i][1] = ".($i+1).";\n";
+            $str .= "D[$i][2] = 0;\n";
+        }
+        return $str;
+    }
+
+    function get_jmatch_items(&$l_items, &$r_items) {
+        $tags = 'data,matching-exercise,pair';
+        $i = 0;
+        while($item = $this->parent->xml_value($tags,"[$i]['#']['left-item'][0]['#']")) {
+            if (!empty($item['text'][0]['#'])) {
+                $l_items[] = $item;
+            }
+            $i++;
+        }
+        $i = 0;
+        while($item = $this->parent->xml_value($tags,"[$i]['#']['right-item'][0]['#']")) {
+            if (!empty($item['text'][0]['#'])) {
+                $r_items[] = $item;
+            }
+            $i++;
+        }
+    }
+    function shuffle_jmatch_items(&$items) {
+        // get moveable items
+        $moveable_keys = array();
+        for($i=0; $i<count($items); $i++) {
+            if(empty($items[$i]['fixed'][0]['#'])) {
+                $moveable_keys[] = $i;
+            }
+        }
+        // shuffle moveable items
+        $this->seed_random_number_generator();
+        shuffle($moveable_keys);
+
+        $keys = array();
+        for($i=0, $ii=0; $i<count($items); $i++) {
+            if(empty($items[$i]['fixed'][0]['#'])) {
+                //  moveable items are inserted in a shuffled order
+                $keys[] = $moveable_keys[$ii++];
+            } else {
+                //  fixed items stay where they are
+                $keys[] = $i;
+            }
+        }
+        return $keys;
+    }
+    function seed_random_number_generator() {
+        static $seeded_RNG = FALSE;
+        if (!$seeded_RNG) {
+            srand((double) microtime() * 1000000);
+            $seeded_RNG = TRUE;
+        }
+    }
+
+    // specials (JMix)
+
+
+    // specials (JCloze)
+
+    function v6_expand_ItemArray() {
+        $q = 0;
+        $str = '';
+        switch ($this->parent->quiztype) {
+            case 'jcloze':
+                $tags = 'data,gap-fill,question-record';
+                while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {
+                    $a = 0;
+                    $aa = 0;
+                    while (($answer=$question."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {
+                        $text = $this->js_value($tags,  $answer."['text'][0]['#']", true);
+                        if (strlen($text)) {
+                            if ($aa==0) { // first time only
+                                $str .= "\n";
+                                $str .= "I[$q] = new Array();\n";
+                                $str .= "I[$q][1] = new Array();\n";
+                            }
+                            $str .= "I[$q][1][$aa] = new Array();\n";
+                            $str .= "I[$q][1][$aa][0] = '$text';\n";
+                            $aa++;
+                        }
+                        $a++;
+                    }
+                    // add clue, if any answers were found
+                    if ($aa) {
+                        $clue = $this->js_value($tags, $question."['clue'][0]['#']", true);
+                        $str .= "I[$q][2] = '$clue';\n";
+                    }
+                    $q++;
+                }
+                break;
+            case 'jquiz':
+                $str .= "I=new Array();\n";
+                $tags = 'data,questions,question-record';
+                while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {
+
+                    $question_type = $this->int_value($tags, $question."['question-type'][0]['#']");
+                    $weighting = $this->int_value($tags, $question."['weighting'][0]['#']");
+                    $clue = $this->js_value($tags, $question."['clue'][0]['#']", true);
+
+                    $answers = $question."['answers'][0]['#']";
+
+                    $a = 0;
+                    $aa = 0;
+                    while (($answer = $answers."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {
+                        $text =     $this->js_value($tags,  $answer."['text'][0]['#']", true);
+                        $feedback = $this->js_value($tags,  $answer."['feedback'][0]['#']", true);
+                        $correct =  $this->int_value($tags, $answer."['correct'][0]['#']");
+                        $percent =  $this->int_value($tags, $answer."['percent-correct'][0]['#']");
+                        $include =  $this->int_value($tags, $answer."['include-in-mc-options'][0]['#']");
+                        if (strlen($text)) {
+                            if ($aa==0) { // first time only
+                                $str .= "\n";
+                                $str .= "I[$q] = new Array();\n";
+                                $str .= "I[$q][0] = $weighting;\n";
+                                $str .= "I[$q][1] = '$clue';\n";
+                                $str .= "I[$q][2] = '".($question_type-1)."';\n";
+                                $str .= "I[$q][3] = new Array();\n";
+                            }
+                            $str .= "I[$q][3][$aa] = new Array('$text','$feedback',$correct,$percent,$include);\n";
+                            $aa++;
+                        }
+                        $a++;
+                    }
+                    $q++;
+                }
+                break;
+        }
+        return $str;
+    }
+
+    function v6_expand_ClozeBody() {
+        $str = '';
+
+        // get drop down list of words, if required
+        $dropdownlist = '';
+        if ($this->v6_use_DropDownList()) {
+            $this->v6_set_WordList();
+            foreach ($this->wordlist as $word) {
+                $dropdownlist .= '<option value="'.$word.'">'.$word.'</option>';
+            }
+        }
+
+        // cache clues flag and caption
+        $includeclues = $this->v6_expand_Clues();
+        $cluecaption = $this->v6_expand_ClueCaption();
+
+        // detect if cloze starts with gap
+        $strpos = strpos($this->parent->source, '<gap-fill><question-record>');
+        if (is_numeric($strpos)) {
+            $startwithgap = true;
+        } else {
+            $startwithgap = false;
+        }
+
+        // initialize loop values
+        $q = 0;
+        $tags = 'data,gap-fill';
+        $question_record = "$tags,question-record";
+
+        // loop through text and gaps
+        do {
+            $text = $this->parent->xml_value($tags, "[0]['#'][$q]");
+            $gap = '';
+            if (($question="[$q]['#']") && $this->parent->xml_value($question_record, $question)) {
+                $gap .= '<span class="GapSpan" id="GapSpan'.$q.'">';
+                if ($this->v6_use_DropDownList()) {
+                    $gap .= '<select id="Gap'.$q.'"><option value=""></option>'.$dropdownlist.'</select>';
+                } else {
+                    // minimum gap size
+                    $gapsize = 6;
+
+                    // increase gap size to length of longest answer for this gap
+                    $a = 0;
+                    while (($answer=$question."['answer'][$a]['#']") && $this->parent->xml_value($question_record, $answer)) {
+                        $answertext = $this->parent->xml_value($question_record,  $answer."['text'][0]['#']");
+                        $answertext = preg_replace('|&[#a-zA-Z0-9]+;|', 'x', $answertext);
+                        $gapsize = max($gapsize, strlen($answertext));
+                        $a++;
+                    }
+
+                    $gap .= '<input type="text" id="Gap'.$q.'" onfocus="TrackFocus('.$q.')" onblur="LeaveGap()" class="GapBox" size="'.$gapsize.'"></input>';
+                }
+                if ($includeclues) {
+                    $clue = $this->parent->xml_value($question_record, $question."['clue'][0]['#']");
+                    if (strlen($clue)) {
+                        $gap .= '<button style="line-height: 1.0" class="FuncButton" onfocus="FuncBtnOver(this)" onmouseover="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="ShowClue('.$q.')">'.$cluecaption.'</button>';
+                    }
+                }
+                $gap .= '</span>';
+            }
+            if ($startwithgap) {
+                $str .= "$gap$text";
+            } else {
+                $str .= "$text$gap";
+            }
+            $q++;
+        } while (strlen($text) || strlen($gap));
+
+        return $str;
+    }
+
+    // JCloze quiztype
+
+    function v6_expand_WordList() {
+        $str = '';
+        if ($this->v6_include_WordList()) {
+            $this->v6_set_WordList();
+            $str = implode(' &#160;&#160; ', $this->wordlist);
+        }
+        return $str;
+    }
+    function v6_include_WordList() {
+        return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-word-list');
+    }
+    function v6_use_DropDownList() {
+        return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',use-drop-down-list');
+    }
+    function v6_set_WordList() {
+
+        if (isset($this->wordlist)) {
+            // do nothing
+        } else {
+            $this->wordlist = array();
+
+            // is the wordlist required
+            if ($this->v6_include_WordList() || $this->v6_use_DropDownList()) {
+
+                $q = 0;
+                $tags = 'data,gap-fill,question-record';
+                while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {
+                    $a = 0;
+                    $aa = 0;
+                    while (($answer=$question."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {
+                        $text = $this->parent->xml_value($tags,  $answer."['text'][0]['#']");
+                        $correct =  $this->int_value($tags, $answer."['correct'][0]['#']");
+                        if ($text && $correct) { // $correct is always true
+                            $this->wordlist[] = $text;
+                            $aa++;
+                        }
+                        $a++;
+                    }
+                    $q++;
+                }
+                $this->wordlist = array_unique($this->wordlist);
+                sort($this->wordlist);
+            }
+        }
+    }
+    function v6_expand_Keypad() {
+        $str = '';
+        if ($this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-keypad')) {
+
+            // these characters must always be in the keypad
+            $chars = array();
+            $this->add_keypad_chars($chars, $this->parent->xml_value('hotpot-config-file,global,keypad-characters'));
+
+            // append other characters used in the answers
+            $tags = '';
+            switch ($this->parent->quiztype) {
+                case 'jcloze':
+                    $tags = 'data,gap-fill,question-record';
+                    break;
+                case 'jquiz':
+                    $tags = 'data,questions,question-record';
+                    break;
+            }
+            if ($tags) {
+                $q = 0;
+                while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {
+
+                    if ($this->parent->quiztype=='jquiz') {
+                        $answers = $question."['answers'][0]['#']";
+                    } else {
+                        $answers = $question;
+                    }
+
+                    $a = 0;
+                    while (($answer=$answers."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {
+                        $this->add_keypad_chars($chars, $this->parent->xml_value($tags,  $answer."['text'][0]['#']"));
+                        $a++;
+                    }
+                    $q++;
+                }
+            }
+
+            // remove duplicate characters and sort
+            $chars = array_unique($chars);
+            usort($chars, "hotpot_sort_keypad_chars");
+
+            // create keypad buttons for each character
+            $str .= '<div class="Keypad">';
+            foreach ($chars as $char) {
+                $str .= "<button onclick=\"TypeChars('".$this->js_safe($char, true)."'); return false;\">$char</button>";
+            }
+            $str .= '</div>';
+        }
+        return $str;
+    }
+    function add_keypad_chars(&$chars, $text) {
+        if (preg_match_all('|&[^;]+;|i', $text, $more_chars)) {
+            $chars = array_merge($chars, $more_chars[0]);
+        }
+    }
+    function v6_expand_Correct() {
+        return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',guesses-correct');
+    }
+    function v6_expand_Incorrect() {
+        return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',guesses-incorrect');
+    }
+    function v6_expand_GiveHint() {
+        return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',next-correct-letter');
+    }
+    function v6_expand_CaseSensitive() {
+        return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',case-sensitive');
+    }
+
+    // JCross quiztype
+
+    function v6_expand_CluesAcrossLabel() {
+        return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',clues-across');
+    }
+    function v6_expand_CluesDownLabel() {
+        return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',clues-down');
+    }
+    function v6_expand_EnterCaption() {
+        return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',enter-caption');
+    }
+    function v6_expand_ShowHideClueList() {
+        $value = $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-clue-list');
+        return empty($value) ? ' style="display: none;"' : '';
+    }
+
+    // JCross specials
+
+    function v6_expand_CluesDown() {
+        return $this->v6_expand_jcross_clues('D');
+    }
+    function v6_expand_CluesAcross() {
+        return $this->v6_expand_jcross_clues('A');
+    }
+    function v6_expand_jcross_clues($direction) {
+        // $direction: A(cross) or D(own)
+        $row = NULL;
+        $r_max = 0;
+        $c_max = 0;
+        $this->v6_get_jcross_grid($row, $r_max, $c_max);
+
+        $i = 0; // clue index;
+        $str = '';
+        for($r=0; $r<=$r_max; $r++) {
+            for($c=0; $c<=$c_max; $c++) {
+                $aword = $this->get_jcross_aword($row, $r, $r_max, $c, $c_max);
+                $dword = $this->get_jcross_dword($row, $r, $r_max, $c, $c_max);
+                if ($aword || $dword) {
+                    $i++; // increment clue index
+
+                    // get the definition for this word
+                    $def = '';
+                    $word = ($direction=='A') ? $aword : $dword;
+                    $clues = $this->parent->xml_values('data,crossword,clues,item');
+                    foreach ($clues as $clue) {
+                        if ($clue['word'][0]['#']==$word) {
+                            $def = $clue['def'][0]['#'];
+                            $def = strtr($def, array('&#x003C;'=>'<', '&#x003E;'=>'>', "\n"=>'<br />'));
+                            break;
+                        }
+                    }
+
+                    if (!empty($def)) {
+                        $str .= '<tr><td class="ClueNum">'.$i.'. </td><td id="Clue_'.$direction.'_'.$i.'" class="Clue">'.$def.'</td></tr>';
+                    }
+                }
+            }
+        }
+        return $str;
+    }
+
+    // jcross6.js_
+
+    function v6_expand_LetterArray() {
+        $row = NULL;
+        $r_max = 0;
+        $c_max = 0;
+        $this->v6_get_jcross_grid($row, $r_max, $c_max);
+
+        $str = '';
+        for($r=0; $r<=$r_max; $r++) {
+            $str .= "L[$r] = new Array(";
+            for($c=0; $c<=$c_max; $c++) {
+                $str .= ($c>0 ? ',' : '')."'".$this->js_safe($row[$r]['cell'][$c]['#'], true)."'";
+            }
+            $str .= ");\n";
+        }
+        return $str;
+    }
+    function v6_expand_GuessArray() {
+        $row = NULL;
+        $r_max = 0;
+        $c_max = 0;
+        $this->v6_get_jcross_grid($row, $r_max, $c_max);
+
+        $str = '';
+        for($r=0; $r<=$r_max; $r++) {
+            $str .= "G[$r] = new Array('".str_repeat("','", $c_max)."');\n";
+        }
+        return $str;
+    }
+    function v6_expand_ClueNumArray() {
+        $row = NULL;
+        $r_max = 0;
+        $c_max = 0;
+        $this->v6_get_jcross_grid($row, $r_max, $c_max);
+
+        $i = 0; // clue index
+        $str = '';
+        for($r=0; $r<=$r_max; $r++) {
+            $str .= "CL[$r] = new Array(";
+            for($c=0; $c<=$c_max; $c++) {
+                if ($c>0) {
+                    $str .= ',';
+                }
+                $aword = $this->get_jcross_aword($row, $r, $r_max, $c, $c_max);
+                $dword = $this->get_jcross_dword($row, $r, $r_max, $c, $c_max);
+                if (empty($aword) && empty($dword)) {
+                    $str .= 0;
+                } else {
+                    $i++; // increment the clue index
+                    $str .= $i;
+                }
+            }
+            $str .= ");\n";
+        }
+        return $str;
+    }
+    function v6_expand_GridBody() {
+        $row = NULL;
+        $r_max = 0;
+        $c_max = 0;
+        $this->v6_get_jcross_grid($row, $r_max, $c_max);
+
+        $i = 0; // clue index;
+        $str = '';
+        for($r=0; $r<=$r_max; $r++) {
+            $str .= '<tr id="Row_'.$r.'">';
+            for($c=0; $c<=$c_max; $c++) {
+                if (empty($row[$r]['cell'][$c]['#'])) {
+                    $str .= '<td class="BlankCell">&nbsp;</td>';
+                } else {
+                    $aword = $this->get_jcross_aword($row, $r, $r_max, $c, $c_max);
+                    $dword = $this->get_jcross_dword($row, $r, $r_max, $c, $c_max);
+                    if (empty($aword) && empty($dword)) {
+                        $str .= '<td class="LetterOnlyCell"><span id="L_'.$r.'_'.$c.'">&nbsp;</span></td>';
+                    } else {
+                        $i++; // increment clue index
+                        $str .= '<td class="NumLetterCell"><a href="javascript:void(0);" class="GridNum" onclick="ShowClue('.$i.','.$r.','.$c.')">'.$i.'</a><span class="NumLetterCellText" id="L_'.$r.'_'.$c.'" onclick="ShowClue('.$i.','.$r.','.$c.')">&nbsp;&nbsp;&nbsp;</span></td>';
+                    }
+                }
+            }
+            $str .= '</tr>';
+        }
+        return $str;
+    }
+    function v6_get_jcross_grid(&$row, &$r_max, &$c_max) {
+        $row = $this->parent->xml_values('data,crossword,grid,row');
+        $r_max = 0;
+        $c_max = 0;
+        if (isset($row) && is_array($row)) {
+            for($r=0; $r<count($row); $r++) {
+                if (isset($row[$r]['cell']) && is_array($row[$r]['cell'])) {
+                    for($c=0; $c<count($row[$r]['cell']); $c++) {
+                        if (!empty($row[$r]['cell'][$c]['#'])) {
+                            $r_max = max($r, $r_max);
+                            $c_max = max($c, $c_max);
+                        }
+                    } // end for $c
+                }
+            } // end for $r
+        }
+    }
+    function get_jcross_dword(&$row, $r, $r_max, $c, $c_max) {
+        $str = '';
+        if (($r==0 || empty($row[$r-1]['cell'][$c]['#'])) && $r<$r_max && !empty($row[$r+1]['cell'][$c]['#'])) {
+            $str = $this->get_jcross_word($row, $r, $r_max, $c, $c_max, true);
+        }
+        return $str;
+    }
+    function get_jcross_aword(&$row, $r, $r_max, $c, $c_max) {
+        $str = '';
+        if (($c==0 || empty($row[$r]['cell'][$c-1]['#'])) && $c<$c_max && !empty($row[$r]['cell'][$c+1]['#'])) {
+            $str = $this->get_jcross_word($row, $r, $r_max, $c, $c_max, false);
+        }
+        return $str;
+    }
+    function get_jcross_word(&$row, $r, $r_max, $c, $c_max, $go_down=false) {
+        $str = '';
+        while ($r<=$r_max && $c<=$c_max && !empty($row[$r]['cell'][$c]['#'])) {
+            $str .= $row[$r]['cell'][$c]['#'];
+            if ($go_down) {
+                $r++;
+            } else {
+                $c++;
+            }
+        }
+        return $str;
+    }
+
+    // specials (JQuiz)
+
+    function v6_expand_QuestionOutput() {
+        $str = '';
+        $str .= '<ol class="QuizQuestions" id="Questions">'."\n";
+
+        $q = 0;
+        $tags = 'data,questions,question-record';
+        while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {
+
+            // get question
+            $question_text = $this->parent->xml_value($tags, $question."['question'][0]['#']");
+            $question_type = $this->parent->xml_value($tags, $question."['question-type'][0]['#']");
+
+            // check we have a question
+            if ($question_text && $question_type) {
+
+                $str .= '<li class="QuizQuestion" id="Q_'.$q.'" style="display: none;">';
+                $str .= '<p class="QuestionText">'.$question_text.'</p>';
+
+                if (
+                    $question_type==HOTPOT_JQUIZ_SHORTANSWER || 
+                    $question_type==HOTPOT_JQUIZ_HYBRID
+                ) {
+                    $str .= '<div class="ShortAnswer" id="Q_'.$q.'_SA"><form method="post" action="" onsubmit="return false;"><div>';
+                    $str .= '<input type="text" id="Q_'.$q.'_Guess" onfocus="TrackFocus('."'".'Q_'.$q.'_Guess'."'".')" onblur="LeaveGap()" class="ShortAnswerBox" size="9"></input><br /><br />';
+
+                    $caption = $this->v6_expand_CheckCaption();
+                    $str .= $this->v6_expand_jquiz_button($caption, "CheckShortAnswer($q)");
+
+                    if ($this->v6_expand_Hint()) {
+                        $caption = $this->v6_expand_HintCaption();
+                        $str .= $this->v6_expand_jquiz_button($caption, "ShowHint($q)");
+                    }
+
+                    if ($this->v6_expand_ShowAnswer()) {
+                        $caption = $this->v6_expand_ShowAnswerCaption();
+                        $str .= $this->v6_expand_jquiz_button($caption, "ShowAnswers($q)");
+                    }
+
+                    $str .= '</div></form></div>';
+                }
+
+                if (
+                    $question_type==HOTPOT_JQUIZ_MULTICHOICE || 
+                    $question_type==HOTPOT_JQUIZ_HYBRID ||
+                    $question_type==HOTPOT_JQUIZ_MULTISELECT
+                ) {
+
+                    switch ($question_type) {
+                        case HOTPOT_JQUIZ_MULTICHOICE: 
+                            $str .= '<ol class="MCAnswers">'."\n";
+                        break;
+                        case HOTPOT_JQUIZ_HYBRID:
+                            $str .= '<ol class="MCAnswers" id="Q_'.$q.'_Hybrid_MC" style="display: none;">'."\n";
+                        break;
+                        case HOTPOT_JQUIZ_MULTISELECT:
+                            $str .= '<ol class="MSelAnswers">'."\n";
+                        break;
+                    }
+
+                    $a = 0;
+                    $aa = 0;
+                    $answers = $question."['answers'][0]['#']";
+                    while (($answer = $answers."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {
+                        $text = $this->parent->xml_value($tags, $answer."['text'][0]['#']");
+                        if ($text) {
+                            switch ($question_type) {
+                                case HOTPOT_JQUIZ_MULTICHOICE:
+                                case HOTPOT_JQUIZ_HYBRID:
+                                    $include = $this->int_value($tags, $answer."['include-in-mc-options'][0]['#']");
+                                    if ($include) {
+                                        $str .= '<li id="Q_'.$q.'_'.$aa.'"><button class="FuncButton" onfocus="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseover="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" id="Q_'.$q.'_'.$aa.'_Btn" onclick="CheckMCAnswer('.$q.','.$aa.',this)">&nbsp;&nbsp;?&nbsp;&nbsp;</button>&nbsp;&nbsp;'.$text.'</li>'."\n";
+                                    }
+                                break;
+                                case HOTPOT_JQUIZ_MULTISELECT:
+                                    $str .= '<li id="Q_'.$q.'_'.$aa.'"><form method="post" action="" onsubmit="return false;"><div><input type="checkbox" id="Q_'.$q.'_'.$aa.'_Chk" class="MSelCheckbox" />'.$text.'</div></form></li>'."\n";
+                                break;
+                            }
+                            $aa++;
+                        }
+                        $a++;
+                    }
+
+                    $str .= '</ol>';
+
+                    if ($question_type==HOTPOT_JQUIZ_MULTISELECT) {
+                        $caption = $this->v6_expand_CheckCaption();
+                        $str .= $this->v6_expand_jquiz_button($caption, "CheckMultiSelAnswer($q)");
+                    }
+                }
+
+                $str .= "</li>\n";
+            }
+            $q++;
+
+        } // end while $question
+
+        $str .= "</ol>\n";
+        return $str;
+    }
+
+    function v6_expand_jquiz_button($caption, $onclick) {
+        return '<button class="FuncButton" onfocus="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseover="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="'.$onclick.'">'.$caption.'</button>';
+    }
+
+    // jquiz.js_
+
+    function v6_expand_MultiChoice() {
+        return $this->v6_jquiz_question_type(HOTPOT_JQUIZ_MULTICHOICE);
+    }
+    function v6_expand_ShortAnswer() {
+        return $this->v6_jquiz_question_type(HOTPOT_JQUIZ_SHORTANSWER);
+    }
+    function v6_expand_MultiSelect() {
+        return $this->v6_jquiz_question_type(HOTPOT_JQUIZ_MULTISELECT);
+    }
+    function v6_jquiz_question_type($type) {
+        // does this quiz have any questions of the given $type?
+        $flag = false;
+
+        $q = 0;
+        $tags = 'data,questions,question-record';
+        while (($question = "[$q]['#']") && $this->parent->xml_value($tags, $question)) {
+            $question_type = $this->parent->xml_value($tags, $question."['question-type'][0]['#']");
+            if ($question_type==$type || ($question_type==HOTPOT_JQUIZ_HYBRID && ($type==HOTPOT_JQUIZ_MULTICHOICE || $type==HOTPOT_JQUIZ_SHORTANSWER))) {
+                $flag = true;
+                break;
+            }
+            $q++;
+        }
+        return $flag;
+    }
+    function v6_expand_CorrectFirstTime() {
+        return $this->js_value('hotpot-config-file,global,correct-first-time');
+    }
+    function v6_expand_ContinuousScoring() {
+        return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',continuous-scoring');
+    }
+    function v6_expand_ShowCorrectFirstTime() {
+        return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',show-correct-first-time');
+    }
+    function v6_expand_ShuffleAs() {
+        return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',shuffle-answers');
+    }
+
+    function v6_expand_DefaultRight() {
+        return $this->v6_expand_GuessCorrect();
+    }
+    function v6_expand_DefaultWrong() {
+        return $this->v6_expand_GuessIncorrect();
+    }
+    function v6_expand_ShowAllQuestionsCaptionJS() {
+        return $this->v6_expand_ShowAllQuestionsCaption();
+    }
+    function v6_expand_ShowOneByOneCaptionJS() {
+        return $this->v6_expand_ShowOneByOneCaption();
+    }
+
+    // hp6checkshortanswers.js_ (JQuiz)
+
+    function v6_expand_CorrectList() {
+        return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',correct-answers');
+    }
+    function v6_expand_HybridTries() {
+        return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',short-answer-tries-on-hybrid-q');
+    }
+    function v6_expand_PleaseEnter() {
+        return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',enter-a-guess');
+    }
+    function v6_expand_PartlyIncorrect() {
+        return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',partly-incorrect');
+    }
+    function v6_expand_ShowAnswerCaption() {
+        return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',show-answer-caption');
+    }
+    function v6_expand_ShowAlsoCorrect() {
+        return $this->bool_value('hotpot-config-file,global,show-also-correct');
+    }
+
+} // end class
+function hotpot_sort_keypad_chars($a, $b) {
+    $a =  hotpot_keypad_sort_value($a);
+    $b =  hotpot_keypad_sort_value($b);
+    return ($a<$b) ? -1 : ($a==$b ? 0 : 1);
+}
+function hotpot_keypad_sort_value($char) {
+
+    // hexadecimal
+    if (preg_match('|&#x([0-9A-F]+);|ie', $char, $matches)) {
+        $ord = hexdec($matches[1]);
+
+    // decimal
+    } else if (preg_match('|&#(\d+);|i', $char, $matches)) {
+        $ord = intval($matches[1]);
+
+    // other html entity
+    } else if (preg_match('|&[^;]+;|', $char, $matches)) {
+        $char = html_entity_decode($matches[0]);
+        $ord = empty($char) ? 0 : ord($char);
+
+    // not an html entity
+    } else {
+        $char = trim($char);
+        $ord = empty($char) ? 0 : ord($char);
+    }
+
+    // lowercase letters (plain or accented)
+    if (($ord>=97 && $ord<=122) || ($ord>=224 && $ord<=255)) {
+        $sort_value = ($ord-31).'.'.sprintf('%04d', $ord);
+
+    // all other characters
+    } else {
+        $sort_value = $ord;
+    }
+
+    return $sort_value;
+} 
+
+?>
index e2db93b8c21af40c6c176722808a88be2ee5e30d..c542919f7516715341362eed5c1ffbebf64cad84 100755 (executable)
@@ -1,59 +1,59 @@
-# phpMyAdmin MySQL-Dump\r
-# version 2.2.1\r
-# http://phpwizard.net/phpMyAdmin/\r
-# http://phpmyadmin.sourceforge.net/ (download page)\r
-#\r
-# Host: localhost\r
-# Generation Time: Nov 14, 2001 at 04:44 PM\r
-# Server version: 3.23.36\r
-# PHP Version: 4.0.6\r
-# Database : `moodle`\r
-# --------------------------------------------------------\r
-\r
-#\r
-# Table structure for table `journal`\r
-#\r
-\r
-CREATE TABLE prefix_journal (\r
-  id int(10) unsigned NOT NULL auto_increment,\r
-  course int(10) unsigned NOT NULL default '0',\r
-  name varchar(255) NOT NULL default '',\r
-  intro text NOT NULL default '',\r
-  introformat tinyint(2) NOT NULL default '0',\r
-  days smallint(5) unsigned NOT NULL default '7',\r
-  assessed int(10) NOT NULL default '0',\r
-  timemodified int(10) unsigned NOT NULL default '0',\r
-  PRIMARY KEY  (id),\r
-  KEY course (course)\r
-) TYPE=MyISAM;\r
-# --------------------------------------------------------\r
-\r
-#\r
-# Table structure for table `journal_entries`\r
-#\r
-\r
-CREATE TABLE prefix_journal_entries (\r
-  id int(10) unsigned NOT NULL auto_increment,\r
-  journal int(10) unsigned NOT NULL default '0',\r
-  userid int(10) unsigned NOT NULL default '0',\r
-  modified int(10) unsigned NOT NULL default '0',\r
-  text text NOT NULL default '',\r
-  format tinyint(2) NOT NULL default '0',\r
-  rating int(10) default '0',\r
-  comment text default '',\r
-  teacher int(10) unsigned NOT NULL default '0',\r
-  timemarked int(10) unsigned NOT NULL default '0',\r
-  mailed int(1) unsigned NOT NULL default '0',\r
-  PRIMARY KEY  (id), \r
-  KEY journal (journal),\r
-  KEY userid (userid)\r
-) TYPE=MyISAM COMMENT='All the journal entries of all people';\r
-\r
-#\r
-# Dumping data for table `log_display`\r
-#\r
-\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'view', 'journal', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'add entry', 'journal', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'update entry', 'journal', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'view responses', 'journal', 'name');\r
+# phpMyAdmin MySQL-Dump
+# version 2.2.1
+# http://phpwizard.net/phpMyAdmin/
+# http://phpmyadmin.sourceforge.net/ (download page)
+#
+# Host: localhost
+# Generation Time: Nov 14, 2001 at 04:44 PM
+# Server version: 3.23.36
+# PHP Version: 4.0.6
+# Database : `moodle`
+# --------------------------------------------------------
+
+#
+# Table structure for table `journal`
+#
+
+CREATE TABLE prefix_journal (
+  id int(10) unsigned NOT NULL auto_increment,
+  course int(10) unsigned NOT NULL default '0',
+  name varchar(255) NOT NULL default '',
+  intro text NOT NULL default '',
+  introformat tinyint(2) NOT NULL default '0',
+  days smallint(5) unsigned NOT NULL default '7',
+  assessed int(10) NOT NULL default '0',
+  timemodified int(10) unsigned NOT NULL default '0',
+  PRIMARY KEY  (id),
+  KEY course (course)
+) TYPE=MyISAM;
+# --------------------------------------------------------
+
+#
+# Table structure for table `journal_entries`
+#
+
+CREATE TABLE prefix_journal_entries (
+  id int(10) unsigned NOT NULL auto_increment,
+  journal int(10) unsigned NOT NULL default '0',
+  userid int(10) unsigned NOT NULL default '0',
+  modified int(10) unsigned NOT NULL default '0',
+  text text NOT NULL default '',
+  format tinyint(2) NOT NULL default '0',
+  rating int(10) default '0',
+  comment text default '',
+  teacher int(10) unsigned NOT NULL default '0',
+  timemarked int(10) unsigned NOT NULL default '0',
+  mailed int(1) unsigned NOT NULL default '0',
+  PRIMARY KEY  (id), 
+  KEY journal (journal),
+  KEY userid (userid)
+) TYPE=MyISAM COMMENT='All the journal entries of all people';
+
+#
+# Dumping data for table `log_display`
+#
+
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'view', 'journal', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'add entry', 'journal', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'update entry', 'journal', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'view responses', 'journal', 'name');
index 4a20559fcea111bb76d200edbd6756228e130551..b6ff995dc11181878d194acf0e18250350903051 100755 (executable)
@@ -1,89 +1,89 @@
-rem\r
-rem Table structure for table journal\r
-rem\r
-\r
-drop TABLE prefix_journal;\r
-CREATE TABLE prefix_journal (\r
- id number(10) primary key,\r
- course number(10) default '0' not null,\r
- name varchar(255) default NULL,\r
- intro varchar2(1024),\r
- days number(5) default '7' not null,\r
- assessed number(10) default '0' not null,\r
- timemodified number(10) default '0' not null\r
-);\r
-\r
-drop sequence p_journal_seq;\r
-create sequence p_journal_seq;\r
-\r
-create or replace trigger p_journal_trig\r
-  before insert on prefix_journal\r
-  referencing new as new_row\r
-  for each row\r
-  begin\r
-    select p_journal_seq.nextval into :new_row.id from dual;\r
-  end;\r
-.\r
-/\r
-\r
-insert into prefix_journal(course,name,intro,days,assessed,timemodified) values(1,'1','1',1,1,1);\r
-insert into prefix_journal(course,name,intro,days,assessed,timemodified) values(2,'2','2',2,2,2);\r
-insert into prefix_journal(course,name,intro,days,assessed,timemodified) values(3,'3','3',3,3,3);\r
-insert into prefix_journal(course,name,intro,days,assessed,timemodified) values(4,'4','4',4,4,4);\r
-\r
-select * from prefix_journal order by 1,2;\r
-\r
-rem --------------------------------------------------------\r
-\r
-rem\r
-rem Table structure for table journal_entries\r
-rem\r
-\r
-drop TABLE prefix_journal_entries;\r
-CREATE TABLE prefix_journal_entries (\r
- id number(10) primary key,\r
- journal number(10) default '0' not null,\r
- userid number(10) default '0' not null,\r
- modified number(10) default '0' not null,\r
- text varchar2(1024) NOT NULL,\r
- format number(2) default '0' not null,\r
- rating number(10) default '0',\r
- commentt varchar2(1024),\r
- teacher number(10) default '0' not null,\r
- timemarked number(10) default '0' not null,\r
- mailed number(1) default '0' not null\r
-);\r
-\r
-comment on table prefix_journal_entries is 'All the journal entries of all people';\r
-\r
-drop sequence p_journal_entries_seq;\r
-create sequence p_journal_entries_seq;\r
-\r
-create or replace trigger p_journal_entries_trig\r
-  before insert on prefix_journal_entries\r
-  referencing new as new_row\r
-  for each row\r
-  begin\r
-    select p_journal_entries_seq.nextval into :new_row.id from dual;\r
-  end;\r
-.\r
-/\r
-\r
-insert into prefix_journal_entries(journal,userid,modified,text,format,rating,commentt,teacher,timemarked,mailed) values(1,1,1,'1',1,1,'1',1,1,1);\r
-insert into prefix_journal_entries(journal,userid,modified,text,format,rating,commentt,teacher,timemarked,mailed) values(2,2,2,'2',2,2,'2',2,2,2);\r
-insert into prefix_journal_entries(journal,userid,modified,text,format,rating,commentt,teacher,timemarked,mailed) values(3,3,3,'3',3,3,'3',3,3,3);\r
-insert into prefix_journal_entries(journal,userid,modified,text,format,rating,commentt,teacher,timemarked,mailed) values(4,4,4,'4',4,4,'4',4,4,4);\r
-\r
-select * from prefix_journal_entries order by 1,2;\r
-\r
-rem\r
-rem Dumping data for table log_display\r
-rem\r
-delete from prefix_log_display where module = 'journal';\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'view', 'journal', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'add entry', 'journal', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'update entry', 'journal', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'view responses', 'journal', 'name');\r
-\r
-col module format a10\r
-select * from prefix_log_display where module = 'journal';\r
+rem
+rem Table structure for table journal
+rem
+
+drop TABLE prefix_journal;
+CREATE TABLE prefix_journal (
+ id number(10) primary key,
+ course number(10) default '0' not null,
+ name varchar(255) default NULL,
+ intro varchar2(1024),
+ days number(5) default '7' not null,
+ assessed number(10) default '0' not null,
+ timemodified number(10) default '0' not null
+);
+
+drop sequence p_journal_seq;
+create sequence p_journal_seq;
+
+create or replace trigger p_journal_trig
+  before insert on prefix_journal
+  referencing new as new_row
+  for each row
+  begin
+    select p_journal_seq.nextval into :new_row.id from dual;
+  end;
+.
+/
+
+insert into prefix_journal(course,name,intro,days,assessed,timemodified) values(1,'1','1',1,1,1);
+insert into prefix_journal(course,name,intro,days,assessed,timemodified) values(2,'2','2',2,2,2);
+insert into prefix_journal(course,name,intro,days,assessed,timemodified) values(3,'3','3',3,3,3);
+insert into prefix_journal(course,name,intro,days,assessed,timemodified) values(4,'4','4',4,4,4);
+
+select * from prefix_journal order by 1,2;
+
+rem --------------------------------------------------------
+
+rem
+rem Table structure for table journal_entries
+rem
+
+drop TABLE prefix_journal_entries;
+CREATE TABLE prefix_journal_entries (
+ id number(10) primary key,
+ journal number(10) default '0' not null,
+ userid number(10) default '0' not null,
+ modified number(10) default '0' not null,
+ text varchar2(1024) NOT NULL,
+ format number(2) default '0' not null,
+ rating number(10) default '0',
+ commentt varchar2(1024),
+ teacher number(10) default '0' not null,
+ timemarked number(10) default '0' not null,
+ mailed number(1) default '0' not null
+);
+
+comment on table prefix_journal_entries is 'All the journal entries of all people';
+
+drop sequence p_journal_entries_seq;
+create sequence p_journal_entries_seq;
+
+create or replace trigger p_journal_entries_trig
+  before insert on prefix_journal_entries
+  referencing new as new_row
+  for each row
+  begin
+    select p_journal_entries_seq.nextval into :new_row.id from dual;
+  end;
+.
+/
+
+insert into prefix_journal_entries(journal,userid,modified,text,format,rating,commentt,teacher,timemarked,mailed) values(1,1,1,'1',1,1,'1',1,1,1);
+insert into prefix_journal_entries(journal,userid,modified,text,format,rating,commentt,teacher,timemarked,mailed) values(2,2,2,'2',2,2,'2',2,2,2);
+insert into prefix_journal_entries(journal,userid,modified,text,format,rating,commentt,teacher,timemarked,mailed) values(3,3,3,'3',3,3,'3',3,3,3);
+insert into prefix_journal_entries(journal,userid,modified,text,format,rating,commentt,teacher,timemarked,mailed) values(4,4,4,'4',4,4,'4',4,4,4);
+
+select * from prefix_journal_entries order by 1,2;
+
+rem
+rem Dumping data for table log_display
+rem
+delete from prefix_log_display where module = 'journal';
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'view', 'journal', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'add entry', 'journal', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'update entry', 'journal', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'view responses', 'journal', 'name');
+
+col module format a10
+select * from prefix_log_display where module = 'journal';
index adc08a4a3f9d17e759b33d0460ab7b286a53bd24..dbd61a1d3a649394b97cf009343cd3216f180b9b 100755 (executable)
@@ -1,40 +1,40 @@
-# phpMyAdmin MySQL-Dump\r
-# version 2.2.1\r
-# http://phpwizard.net/phpMyAdmin/\r
-# http://phpmyadmin.sourceforge.net/ (download page)\r
-#\r
-# Host: localhost\r
-# Generation Time: Nov 14, 2001 at 04:43 PM\r
-# Server version: 3.23.36\r
-# PHP Version: 4.0.6\r
-# Database : `moodle`\r
-# --------------------------------------------------------\r
-\r
-#\r
-# Table structure for table `resource`\r
-#\r
-\r
-CREATE TABLE prefix_resource (\r
-  id int(10) unsigned NOT NULL auto_increment,\r
-  course int(10) unsigned NOT NULL default '0',\r
-  name varchar(255) NOT NULL default '',\r
-  type varchar(30) NOT NULL default '',\r
-  reference varchar(255) NOT NULL default '',\r
-  summary text NOT NULL default '',\r
-  alltext text NOT NULL default '',\r
-  popup text NOT NULL default '',\r
-  options varchar(255) NOT NULL default '',\r
-  timemodified int(10) unsigned NOT NULL default '0',\r
-  PRIMARY KEY  (id),\r
-  UNIQUE KEY id (id),\r
-  KEY `course` (`course`)\r
-) TYPE=MyISAM;\r
-\r
-\r
-#\r
-# Dumping data for table `log_display`\r
-#\r
-\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('resource', 'view', 'resource', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('resource', 'update', 'resource', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('resource', 'add', 'resource', 'name');\r
+# phpMyAdmin MySQL-Dump
+# version 2.2.1
+# http://phpwizard.net/phpMyAdmin/
+# http://phpmyadmin.sourceforge.net/ (download page)
+#
+# Host: localhost
+# Generation Time: Nov 14, 2001 at 04:43 PM
+# Server version: 3.23.36
+# PHP Version: 4.0.6
+# Database : `moodle`
+# --------------------------------------------------------
+
+#
+# Table structure for table `resource`
+#
+
+CREATE TABLE prefix_resource (
+  id int(10) unsigned NOT NULL auto_increment,
+  course int(10) unsigned NOT NULL default '0',
+  name varchar(255) NOT NULL default '',
+  type varchar(30) NOT NULL default '',
+  reference varchar(255) NOT NULL default '',
+  summary text NOT NULL default '',
+  alltext text NOT NULL default '',
+  popup text NOT NULL default '',
+  options varchar(255) NOT NULL default '',
+  timemodified int(10) unsigned NOT NULL default '0',
+  PRIMARY KEY  (id),
+  UNIQUE KEY id (id),
+  KEY `course` (`course`)
+) TYPE=MyISAM;
+
+
+#
+# Dumping data for table `log_display`
+#
+
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('resource', 'view', 'resource', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('resource', 'update', 'resource', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('resource', 'add', 'resource', 'name');
index 427e5d31e979d601ac88f6c871e0ec9ea2a8a362..7aa4ba759d534562e7327fa716b50aa6f21bbd33 100755 (executable)
@@ -1,45 +1,45 @@
-rem\r
-rem Table structure for table resource\r
-rem\r
-\r
-drop TABLE prefix_resource;\r
-CREATE TABLE prefix_resource (\r
-  id number(10) primary key,\r
-  course number(10)  default '0' not null,\r
-  name varchar2(255) default '' not null,\r
-  type number(4) default '0' not null,\r
-  reference varchar2(255) default NULL,\r
-  summary varchar2(1024) NOT NULL,\r
-  alltext varchar2(1024) NOT NULL,\r
-  timemodified number(10)  default '0' not null\r
-);\r
-\r
-drop sequence p_resource_seq;\r
-create sequence p_resource_seq;\r
-\r
-create or replace trigger p_resource_trig\r
-  before insert on prefix_resource\r
-  referencing new as new_row\r
-  for each row\r
-  begin\r
-    select p_resource_seq.nextval into :new_row.id from dual;\r
-  end;\r
-.\r
-/\r
-\r
-comment on table prefix_resource is 'table of resources';\r
-\r
-insert into prefix_resource(course,name,type,reference,summary,alltext,timemodified) values(1,'1',1,1,'1','1',1);\r
-insert into prefix_resource(course,name,type,reference,summary,alltext,timemodified) values(2,'2',2,2,'2','2',2);\r
-insert into prefix_resource(course,name,type,reference,summary,alltext,timemodified) values(3,'3',3,3,'3','3',3);\r
-insert into prefix_resource(course,name,type,reference,summary,alltext,timemodified) values(4,'4',4,4,'4','4',4);\r
-\r
-select * from prefix_resource 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 = 'resource';\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('resource', 'view', 'resource', 'name');\r
-select * from prefix_log_display where module = 'resource';\r
+rem
+rem Table structure for table resource
+rem
+
+drop TABLE prefix_resource;
+CREATE TABLE prefix_resource (
+  id number(10) primary key,
+  course number(10)  default '0' not null,
+  name varchar2(255) default '' not null,
+  type number(4) default '0' not null,
+  reference varchar2(255) default NULL,
+  summary varchar2(1024) NOT NULL,
+  alltext varchar2(1024) NOT NULL,
+  timemodified number(10)  default '0' not null
+);
+
+drop sequence p_resource_seq;
+create sequence p_resource_seq;
+
+create or replace trigger p_resource_trig
+  before insert on prefix_resource
+  referencing new as new_row
+  for each row
+  begin
+    select p_resource_seq.nextval into :new_row.id from dual;
+  end;
+.
+/
+
+comment on table prefix_resource is 'table of resources';
+
+insert into prefix_resource(course,name,type,reference,summary,alltext,timemodified) values(1,'1',1,1,'1','1',1);
+insert into prefix_resource(course,name,type,reference,summary,alltext,timemodified) values(2,'2',2,2,'2','2',2);
+insert into prefix_resource(course,name,type,reference,summary,alltext,timemodified) values(3,'3',3,3,'3','3',3);
+insert into prefix_resource(course,name,type,reference,summary,alltext,timemodified) values(4,'4',4,4,'4','4',4);
+
+select * from prefix_resource order by 1,2;
+
+rem
+rem Dumping data for table log_display
+rem
+
+delete from prefix_log_display where module = 'resource';
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('resource', 'view', 'resource', 'name');
+select * from prefix_log_display where module = 'resource';
index 595f4a051e4ab7859daba6f0aa7087284a6d5df1..4599cb07b395b561be7220a4408af459e284b39a 100755 (executable)
-<php\r
-    require_once('../../config.php');\r
-    require_once('locallib.php');\r
-    \r
-    $command = required_param('command', PARAM_ALPHA);\r
-    $sessionid = required_param('session_id', PARAM_ALPHANUM);\r
-    $aiccdata = optional_param('aicc_data', '', PARAM_RAW);\r
-\r
-    require_login();\r
-    \r
-    if (!empty($command) && confirm_sesskey($sessionid)) {\r
-        $command = strtolower($command);\r
-       \r
-        if (isset($SESSION->scorm_scoid)) {\r
-            $scoid = $SESSION->scorm_scoid;\r
-        } else {\r
-            error('Invalid script call');\r
-        }\r
-        $mode = 'normal';\r
-        if (isset($SESSION->scorm_mode)) {\r
-            $mode = $SESSION->scorm_mode;\r
-        }\r
-        $status = 'Not Initialized';\r
-        if (isset($SESSION->scorm_status)) {\r
-            $status = $SESSION->scorm_status;\r
-        }\r
-        if (isset($SESSION->attempt)) {\r
-            $attempt = $SESSION->attempt;\r
-        } else {\r
-            $attempt = 1;\r
-        }\r
-\r
-        if ($sco = get_record('scorm_scoes','id',$scoid)) {\r
-            if (!$scorm = get_record('scorm','id',$sco->scorm)) {\r
-                error('Invalid script call');\r
-            }\r
-        } else {\r
-            error('Invalid script call');\r
-        }\r
-\r
-        if ($scorm = get_record('scorm','id',$sco->scorm)) {\r
-            switch ($command) {\r
-                case 'getparam':\r
-                    if ($status == 'Not Initialized') {\r
-                        $SESSION->scorm_status = 'Running';\r
-                        $status = 'Running';\r
-                    }\r
-                    if ($status != 'Running') {\r
-                        echo "error = 101\nerror_text = Terminated\n";\r
-                    } else {\r
-                        if ($usertrack=scorm_get_tracks($scoid,$USER->id,$attempt)) {\r
-                            $userdata = $usertrack;\r
-                        } else {\r
-                            $userdata->status = '';\r
-                            $userdata->score_raw = '';\r
-                        }\r
-                        $userdata->student_id = $USER->username;\r
-                        $userdata->student_name = $USER->lastname .', '. $USER->firstname;\r
-                        $userdata->mode = $mode;\r
-                        if ($userdata->mode == 'normal') {\r
-                            $userdata->credit = 'credit';\r
-                        } else {\r
-                            $userdata->credit = 'no-credit';\r
-                        } \r
-                \r
-                        if ($sco = get_record('scorm_scoes','id',$scoid)) {\r
-                            $userdata->course_id = $sco->identifier;\r
-                            $userdata->datafromlms = $sco->datafromlms;\r
-                            $userdata->masteryscore = $sco->masteryscore;\r
-                            $userdata->maxtimeallowed = $sco->maxtimeallowed;\r
-                            $userdata->timelimitaction = $sco->timelimitaction;\r
-                               \r
-                            echo "error = 0\nerror_text = Successful\naicc_data=\n";\r
-                            echo "[Core]\n";\r
-                            echo 'Student_ID = '.$userdata->student_id."\n";\r
-                            echo 'Student_Name = '.$userdata->student_name."\n";\r
-                            if (isset($userdata->{'cmi.core.lesson_location'})) {\r
-                                echo 'Lesson_Location = '.$userdata->{'cmi.core.lesson_location'}."\n";\r
-                            } else {\r
-                                echo 'Lesson_Location = '."\n";\r
-                            }\r
-                            echo 'Credit = '.$userdata->credit."\n";\r
-                            if (isset($userdata->status)) {\r
-                                if ($userdata->status == '') {\r
-                                    $userdata->entry = ', ab-initio';\r
-                                } else {\r
-                                    if (isset($userdata->{'cmi.core.exit'}) && ($userdata->{'cmi.core.exit'} == 'suspend')) {\r
-                                        $userdata->entry = ', resume';\r
-                                    } else {\r
-                                        $userdata->entry = '';\r
-                                    }\r
-                                }\r
-                            }\r
-                            if (isset($userdata->{'cmi.core.lesson_status'})) {\r
-                                echo 'Lesson_Status = '.$userdata->{'cmi.core.lesson_status'}.$userdata->entry."\n";\r
-                                $SESSION->scorm_lessonstatus = $userdata->{'cmi.core.lesson_status'};\r
-                            } else {\r
-                                echo 'Lesson_Status = not attempted'.$userdata->entry."\n";\r
-                                $SESSION->scorm_lessonstatus = 'not attempted';\r
-                            }\r
-                            if (isset($userdata->{'cmi.core.score.raw'})) {\r
-                                $max = '';\r
-                                $min = '';\r
-                                if (isset($userdata->{'cmi.core.score.max'}) && !empty($userdata->{'cmi.core.score.max'})) {\r
-                                    $max = ', '.$userdata->{'cmi.core.score.max'};\r
-                                    if (isset($userdata->{'cmi.core.score.min'}) && !empty($userdata->{'cmi.core.score.min'})) {\r
-                                        $min = ', '.$userdata->{'cmi.core.score.min'};\r
-                                    }\r
-                                }\r
-                                echo 'Score = '.$userdata->{'cmi.core.score.raw'}.$max.$min."\n";\r
-                            } else {\r
-                                echo 'Score = '."\n";\r
-                            }\r
-                            if (isset($userdata->{'cmi.core.total_time'})) {\r
-                                echo 'Time = '.$userdata->{'cmi.core.total_time'}."\n";\r
-                            } else {\r
-                                echo 'Time = '.'00:00:00'."\n";\r
-                            }\r
-                            echo 'Lesson_Mode = '.$userdata->mode."\n";\r
-                            if (isset($userdata->{'cmi.suspend_data'})) {\r
-                                echo "[Core_Lesson]\n".$userdata->{'cmi.suspend_data'}."\n";\r
-                            } else {\r
-                                echo "[Core_Lesson]\n"."\n";\r
-                            }\r
-                            echo "[Core_Vendor]\n".$userdata->datafromlms."\n";\r
-                            echo "[Evaluation]\nCourse_ID = {".$userdata->course_id."}\n";\r
-                            echo "[Student_Data]\n";\r
-                            echo 'Mastery_Score = '.$userdata->masteryscore."\n";\r
-                            echo 'Max_Time_Allowed = '.$userdata->maxtimeallowed."\n";\r
-                            echo 'Time_Limit_Action = '.$userdata->timelimitaction."\n";\r
-                        } else {\r
-                            error('Sco not found');\r
-                        }\r
-                    }\r
-                break;\r
-                case 'putparam':\r
-                    if ($status == 'Running') {\r
-                        if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $scorm->course)) {\r
-                            echo "error = 1\nerror_text = Unknown\n"; // No one must see this error message if not hacked\r
-                        }\r
-                        if (!empty($aiccdata) && has_capability('mod/scorm:savetrack', get_context_instance(CONTEXT_MODULE, $cm->id))) {\r
-                            $initlessonstatus = 'not attempted';\r
-                            $lessonstatus = 'not attempted';\r
-                            if (isset($SESSION->scorm_lessonstatus)) {\r
-                                $initlessonstatus = $SESSION->scorm_lessonstatus;\r
-                            }\r
-                            $score = '';\r
-                            $datamodel['lesson_location'] = 'cmi.core.lesson_location';\r
-                            $datamodel['lesson_status'] = 'cmi.core.lesson_status';\r
-                            $datamodel['score'] = 'cmi.core.score.raw';\r
-                            $datamodel['time'] = 'cmi.core.session_time';\r
-                            $datamodel['[core_lesson]'] = 'cmi.suspend_data';\r
-                            $datamodel['[comments]'] = 'cmi.comments';\r
-                            $datarows = explode("\n",$aiccdata);\r
-                            reset($datarows);\r
-                            while ((list(,$datarow) = each($datarows)) !== false) {\r
-                                if (($equal = strpos($datarow, '=')) !== false) {\r
-                                    $element = strtolower(trim(substr($datarow,0,$equal)));\r
-                                    $value = trim(substr($datarow,$equal+1));\r
-                                    if (isset($datamodel[$element])) {\r
-                                        $element = $datamodel[$element];\r
-                                        switch ($element) {\r
-                                            case 'cmi.core.lesson_location':\r
-                                                $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $element, $value);\r
-                                            break;\r
-                                            case 'cmi.core.lesson_status':\r
-                                                $statuses = array(\r
-                                                           'passed' => 'passed',\r
-                                                           'completed' => 'completed',\r
-                                                           'failed' => 'failed',\r
-                                                           'incomplete' => 'incomplete',\r
-                                                           'browsed' => 'browsed',\r
-                                                           'not attempted' => 'not attempted',\r
-                                                           'p' => 'passed',\r
-                                                           'c' => 'completed',\r
-                                                           'f' => 'failed',\r
-                                                           'i' => 'incomplete',\r
-                                                           'b' => 'browsed',\r
-                                                           'n' => 'not attempted'\r
-                                                           );\r
-                                                $exites = array(\r
-                                                           'logout' => 'logout',\r
-                                                           'time-out' => 'time-out',\r
-                                                           'suspend' => 'suspend',\r
-                                                           'l' => 'logout',\r
-                                                           't' => 'time-out',\r
-                                                           's' => 'suspend',\r
-                                                           );\r
-                                                $values = explode(',',$value);\r
-                                                $value = '';\r
-                                                if (count($values) > 1) {\r
-                                                    $value = trim(strtolower($values[1]));\r
-                                                    if (isset($exites[$value])) {\r
-                                                        $value = $exites[$value];\r
-                                                    }\r
-                                                }\r
-                                                if (empty($value) || isset($exites[$value])) {\r
-                                                    $subelement = 'cmi.core.exit';\r
-                                                    $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $subelement, $value);\r
-                                                }\r
-                                                $value = trim(strtolower($values[0]));\r
-                                                if (isset($statuses[$value]) && ($mode == 'normal')) {\r
-                                                    $value = $statuses[$value];\r
-                                                    $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $element, $value);\r
-                                                }\r
-                                                $lessonstatus = $value;\r
-                                            break;\r
-                                            case 'cmi.core.score.raw':\r
-                                                 $values = explode(',',$value);\r
-                                                 if ((count($values) > 1) && ($values[1] >= $values[0]) && is_numeric($values[1])) {\r
-                                                     $subelement = 'cmi.core.score.max';\r
-                                                     $value = trim($values[1]);\r
-                                                     $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $subelement, $value);\r
-                                                     if ((count($values) == 3) && ($values[2] <= $values[0]) && is_numeric($values[2])) {\r
-                                                         $subelement = 'cmi.core.score.min';\r
-                                                         $value = trim($values[2]);\r
-                                                         $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $subelement, $value);\r
-                                                     }\r
-                                                 }\r
-                                              \r
-                                                 $value = '';\r
-                                                 if (is_numeric($values[0])) {\r
-                                                     $value = trim($values[0]);\r
-                                                     $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $element, $value);\r
-                                                 }\r
-                                                 $score = $value;\r
-                                            break;\r
-                                            case 'cmi.core.session_time':\r
-                                                 $SESSION->scorm_session_time = $value;\r
-                                            break;\r
-                                        }\r
-                                    }\r
-                                } else {\r
-                                    if (isset($datamodel[strtolower(trim($datarow))])) {\r
-                                        $element = $datamodel[strtolower(trim($datarow))];\r
-                                        $value = '';\r
-                                        while ((($datarow = current($datarows)) !== false) && (substr($datarow,0,1) != '[')) {\r
-                                            $value .= $datarow;\r
-                                            next($datarows);\r
-                                        }\r
-                                        $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $element, $value);\r
-                                    }\r
-                                }                               \r
-                            }\r
-                            if (($mode == 'browse') && ($initlessonstatus == 'not attempted')){\r
-                                $lessonstatus = 'browsed';\r
-                                $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, 'cmi.core.lesson_status', 'browsed');\r
-                            }\r
-                            if ($mode == 'normal') {\r
-                                if ($lessonstatus == 'completed') {\r
-                                    if (!empty($sco->masteryscore) && !empty($score) && ($score >= $sco->masteryscore)) {\r
-                                        $lessonstatus = 'passed';\r
-                                    } else {\r
-                                        $lessonstatus = 'failed';\r
-                                    }\r
-                                    $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, 'cmi.core.lesson_status', $lessonstatus);\r
-                                }\r
-                            }                  \r
-                        }\r
-                        echo "error = 0\nerror_text = Successful\n";\r
-                    } else if ($status == 'Terminated') {\r
-                        echo "error = 1\nerror_text = Terminated\n";\r
-                    } else {\r
-                        echo "error = 1\nerror_text = Not Initialized\n";\r
-                    }\r
-                break;\r
-                case 'putcomments':\r
-                    if ($status == 'Running') {\r
-                        echo "error = 0\nerror_text = Successful\n";\r
-                    } else if ($status == 'Terminated') {\r
-                        echo "error = 1\nerror_text = Terminated\n";\r
-                    } else {\r
-                        echo "error = 1\nerror_text = Not Initialized\n";\r
-                    }\r
-                break;\r
-                case 'putinteractions':\r
-                    if ($status == 'Running') {\r
-                        echo "error = 0\nerror_text = Successful\n";\r
-                    } else if ($status == 'Terminated') {\r
-                        echo "error = 1\nerror_text = Terminated\n";\r
-                    } else {\r
-                        echo "error = 1\nerror_text = Not Initialized\n";\r
-                    }\r
-                break;\r
-                case 'putobjectives':\r
-                    if ($status == 'Running') {\r
-                        echo "error = 0\nerror_text = Successful\n";\r
-                    } else if ($status == 'Terminated') {\r
-                        echo "error = 1\nerror_text = Terminated\n";\r
-                    } else {\r
-                        echo "error = 1\nerror_text = Not Initialized\n";\r
-                    }\r
-                break;\r
-                case 'putpath':\r
-                    if ($status == 'Running') {\r
-                        echo "error = 0\nerror_text = Successful\n";\r
-                    } else if ($status == 'Terminated') {\r
-                        echo "error = 1\nerror_text = Terminated\n";\r
-                    } else {\r
-                        echo "error = 1\nerror_text = Not Initialized\n";\r
-                    }\r
-                break;\r
-                case 'putperformance':\r
-                    if ($status == 'Running') {\r
-                        echo "error = 0\nerror_text = Successful\n";\r
-                    } else if ($status == 'Terminated') {\r
-                        echo "error = 1\nerror_text = Terminated\n";\r
-                    } else {\r
-                        echo "error = 1\nerror_text = Not Initialized\n";\r
-                    }\r
-                break;\r
-                case 'exitau':\r
-                    if ($status == 'Running') {\r
-                        if (isset($SESSION->scorm_session_time) && ($SESSION->scorm_session_time != '')) {\r
-                            if ($track = get_record_select('scorm_scoes_track',"userid='$USER->id' AND scormid='$scorm->id' AND scoid='$sco->id' AND element='cmi.core.total_time'")) {\r
-                                // Add session_time to total_time\r
-                                $value = scorm_add_time($track->value, $SESSION->scorm_session_time);\r
-                                $track->value = $value;\r
-                                $track->timemodified = time();\r
-                                $id = update_record('scorm_scoes_track',$track);\r
-                            } else {\r
-                                $track->userid = $USER->id;\r
-                                $track->scormid = $scorm->id;\r
-                                $track->scoid = $sco->id;\r
-                                $track->element = 'cmi.core.total_time';\r
-                                $track->value = $SESSION->scorm_session_time;\r
-                                $track->timemodified = time();\r
-                                $id = insert_record('scorm_scoes_track',$track);\r
-                            }\r
-                        }\r
-                        \r
-                        $SESSION->scorm_status = 'Terminated';\r
-                        $SESSION->scorm_session_time = '';\r
-                        echo "error = 0\nerror_text = Successful\n";\r
-                    } else if ($status == 'Terminated') {\r
-                        echo "error = 1\nerror_text = Terminated\n";\r
-                    } else {\r
-                        echo "error = 1\nerror_text = Not Initialized\n";\r
-                    }\r
-                break;\r
-                default:\r
-                    echo "error = 1\nerror_text = Invalid Command\n";\r
-                break;\r
-            }\r
-        }\r
-    } else {\r
-        if (empty($command)) {\r
-            echo "error = 1\nerror_text = Invalid Command\n";\r
-        } else {\r
-            echo "error = 3\nerror_text = Invalid Session ID\n";\r
-        }\r
-    }\r
-?>\r
+<php
+    require_once('../../config.php');
+    require_once('locallib.php');
+    
+    $command = required_param('command', PARAM_ALPHA);
+    $sessionid = required_param('session_id', PARAM_ALPHANUM);
+    $aiccdata = optional_param('aicc_data', '', PARAM_RAW);
+
+    require_login();
+    
+    if (!empty($command) && confirm_sesskey($sessionid)) {
+        $command = strtolower($command);
+       
+        if (isset($SESSION->scorm_scoid)) {
+            $scoid = $SESSION->scorm_scoid;
+        } else {
+            error('Invalid script call');
+        }
+        $mode = 'normal';
+        if (isset($SESSION->scorm_mode)) {
+            $mode = $SESSION->scorm_mode;
+        }
+        $status = 'Not Initialized';
+        if (isset($SESSION->scorm_status)) {
+            $status = $SESSION->scorm_status;
+        }
+        if (isset($SESSION->attempt)) {
+            $attempt = $SESSION->attempt;
+        } else {
+            $attempt = 1;
+        }
+
+        if ($sco = get_record('scorm_scoes','id',$scoid)) {
+            if (!$scorm = get_record('scorm','id',$sco->scorm)) {
+                error('Invalid script call');
+            }
+        } else {
+            error('Invalid script call');
+        }
+
+        if ($scorm = get_record('scorm','id',$sco->scorm)) {
+            switch ($command) {
+                case 'getparam':
+                    if ($status == 'Not Initialized') {
+                        $SESSION->scorm_status = 'Running';
+                        $status = 'Running';
+                    }
+                    if ($status != 'Running') {
+                        echo "error = 101\nerror_text = Terminated\n";
+                    } else {
+                        if ($usertrack=scorm_get_tracks($scoid,$USER->id,$attempt)) {
+                            $userdata = $usertrack;
+                        } else {
+                            $userdata->status = '';
+                            $userdata->score_raw = '';
+                        }
+                        $userdata->student_id = $USER->username;
+                        $userdata->student_name = $USER->lastname .', '. $USER->firstname;
+                        $userdata->mode = $mode;
+                        if ($userdata->mode == 'normal') {
+                            $userdata->credit = 'credit';
+                        } else {
+                            $userdata->credit = 'no-credit';
+                        } 
+                
+                        if ($sco = get_record('scorm_scoes','id',$scoid)) {
+                            $userdata->course_id = $sco->identifier;
+                            $userdata->datafromlms = $sco->datafromlms;
+                            $userdata->masteryscore = $sco->masteryscore;
+                            $userdata->maxtimeallowed = $sco->maxtimeallowed;
+                            $userdata->timelimitaction = $sco->timelimitaction;
+                               
+                            echo "error = 0\nerror_text = Successful\naicc_data=\n";
+                            echo "[Core]\n";
+                            echo 'Student_ID = '.$userdata->student_id."\n";
+                            echo 'Student_Name = '.$userdata->student_name."\n";
+                            if (isset($userdata->{'cmi.core.lesson_location'})) {
+                                echo 'Lesson_Location = '.$userdata->{'cmi.core.lesson_location'}."\n";
+                            } else {
+                                echo 'Lesson_Location = '."\n";
+                            }
+                            echo 'Credit = '.$userdata->credit."\n";
+                            if (isset($userdata->status)) {
+                                if ($userdata->status == '') {
+                                    $userdata->entry = ', ab-initio';
+                                } else {
+                                    if (isset($userdata->{'cmi.core.exit'}) && ($userdata->{'cmi.core.exit'} == 'suspend')) {
+                                        $userdata->entry = ', resume';
+                                    } else {
+                                        $userdata->entry = '';
+                                    }
+                                }
+                            }
+                            if (isset($userdata->{'cmi.core.lesson_status'})) {
+                                echo 'Lesson_Status = '.$userdata->{'cmi.core.lesson_status'}.$userdata->entry."\n";
+                                $SESSION->scorm_lessonstatus = $userdata->{'cmi.core.lesson_status'};
+                            } else {
+                                echo 'Lesson_Status = not attempted'.$userdata->entry."\n";
+                                $SESSION->scorm_lessonstatus = 'not attempted';
+                            }
+                            if (isset($userdata->{'cmi.core.score.raw'})) {
+                                $max = '';
+                                $min = '';
+                                if (isset($userdata->{'cmi.core.score.max'}) && !empty($userdata->{'cmi.core.score.max'})) {
+                                    $max = ', '.$userdata->{'cmi.core.score.max'};
+                                    if (isset($userdata->{'cmi.core.score.min'}) && !empty($userdata->{'cmi.core.score.min'})) {
+                                        $min = ', '.$userdata->{'cmi.core.score.min'};
+                                    }
+                                }
+                                echo 'Score = '.$userdata->{'cmi.core.score.raw'}.$max.$min."\n";
+                            } else {
+                                echo 'Score = '."\n";
+                            }
+                            if (isset($userdata->{'cmi.core.total_time'})) {
+                                echo 'Time = '.$userdata->{'cmi.core.total_time'}."\n";
+                            } else {
+                                echo 'Time = '.'00:00:00'."\n";
+                            }
+                            echo 'Lesson_Mode = '.$userdata->mode."\n";
+                            if (isset($userdata->{'cmi.suspend_data'})) {
+                                echo "[Core_Lesson]\n".$userdata->{'cmi.suspend_data'}."\n";
+                            } else {
+                                echo "[Core_Lesson]\n"."\n";
+                            }
+                            echo "[Core_Vendor]\n".$userdata->datafromlms."\n";
+                            echo "[Evaluation]\nCourse_ID = {".$userdata->course_id."}\n";
+                            echo "[Student_Data]\n";
+                            echo 'Mastery_Score = '.$userdata->masteryscore."\n";
+                            echo 'Max_Time_Allowed = '.$userdata->maxtimeallowed."\n";
+                            echo 'Time_Limit_Action = '.$userdata->timelimitaction."\n";
+                        } else {
+                            error('Sco not found');
+                        }
+                    }
+                break;
+                case 'putparam':
+                    if ($status == 'Running') {
+                        if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $scorm->course)) {
+                            echo "error = 1\nerror_text = Unknown\n"; // No one must see this error message if not hacked
+                        }
+                        if (!empty($aiccdata) && has_capability('mod/scorm:savetrack', get_context_instance(CONTEXT_MODULE, $cm->id))) {
+                            $initlessonstatus = 'not attempted';
+                            $lessonstatus = 'not attempted';
+                            if (isset($SESSION->scorm_lessonstatus)) {
+                                $initlessonstatus = $SESSION->scorm_lessonstatus;
+                            }
+                            $score = '';
+                            $datamodel['lesson_location'] = 'cmi.core.lesson_location';
+                            $datamodel['lesson_status'] = 'cmi.core.lesson_status';
+                            $datamodel['score'] = 'cmi.core.score.raw';
+                            $datamodel['time'] = 'cmi.core.session_time';
+                            $datamodel['[core_lesson]'] = 'cmi.suspend_data';
+                            $datamodel['[comments]'] = 'cmi.comments';
+                            $datarows = explode("\n",$aiccdata);
+                            reset($datarows);
+                            while ((list(,$datarow) = each($datarows)) !== false) {
+                                if (($equal = strpos($datarow, '=')) !== false) {
+                                    $element = strtolower(trim(substr($datarow,0,$equal)));
+                                    $value = trim(substr($datarow,$equal+1));
+                                    if (isset($datamodel[$element])) {
+                                        $element = $datamodel[$element];
+                                        switch ($element) {
+                                            case 'cmi.core.lesson_location':
+                                                $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $element, $value);
+                                            break;
+                                            case 'cmi.core.lesson_status':
+                                                $statuses = array(
+                                                           'passed' => 'passed',
+                                                           'completed' => 'completed',
+                                                           'failed' => 'failed',
+                                                           'incomplete' => 'incomplete',
+                                                           'browsed' => 'browsed',
+                                                           'not attempted' => 'not attempted',
+                                                           'p' => 'passed',
+                                                           'c' => 'completed',
+                                                           'f' => 'failed',
+                                                           'i' => 'incomplete',
+                                                           'b' => 'browsed',
+                                                           'n' => 'not attempted'
+                                                           );
+                                                $exites = array(
+                                                           'logout' => 'logout',
+                                                           'time-out' => 'time-out',
+                                                           'suspend' => 'suspend',
+                                                           'l' => 'logout',
+                                                           't' => 'time-out',
+                                                           's' => 'suspend',
+                                                           );
+                                                $values = explode(',',$value);
+                                                $value = '';
+                                                if (count($values) > 1) {
+                                                    $value = trim(strtolower($values[1]));
+                                                    if (isset($exites[$value])) {
+                                                        $value = $exites[$value];
+                                                    }
+                                                }
+                                                if (empty($value) || isset($exites[$value])) {
+                                                    $subelement = 'cmi.core.exit';
+                                                    $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $subelement, $value);
+                                                }
+                                                $value = trim(strtolower($values[0]));
+                                                if (isset($statuses[$value]) && ($mode == 'normal')) {
+                                                    $value = $statuses[$value];
+                                                    $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $element, $value);
+                                                }
+                                                $lessonstatus = $value;
+                                            break;
+                                            case 'cmi.core.score.raw':
+                                                 $values = explode(',',$value);
+                                                 if ((count($values) > 1) && ($values[1] >= $values[0]) && is_numeric($values[1])) {
+                                                     $subelement = 'cmi.core.score.max';
+                                                     $value = trim($values[1]);
+                                                     $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $subelement, $value);
+                                                     if ((count($values) == 3) && ($values[2] <= $values[0]) && is_numeric($values[2])) {
+                                                         $subelement = 'cmi.core.score.min';
+                                                         $value = trim($values[2]);
+                                                         $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $subelement, $value);
+                                                     }
+                                                 }
+                                              
+                                                 $value = '';
+                                                 if (is_numeric($values[0])) {
+                                                     $value = trim($values[0]);
+                                                     $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $element, $value);
+                                                 }
+                                                 $score = $value;
+                                            break;
+                                            case 'cmi.core.session_time':
+                                                 $SESSION->scorm_session_time = $value;
+                                            break;
+                                        }
+                                    }
+                                } else {
+                                    if (isset($datamodel[strtolower(trim($datarow))])) {
+                                        $element = $datamodel[strtolower(trim($datarow))];
+                                        $value = '';
+                                        while ((($datarow = current($datarows)) !== false) && (substr($datarow,0,1) != '[')) {
+                                            $value .= $datarow;
+                                            next($datarows);
+                                        }
+                                        $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $element, $value);
+                                    }
+                                }                               
+                            }
+                            if (($mode == 'browse') && ($initlessonstatus == 'not attempted')){
+                                $lessonstatus = 'browsed';
+                                $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, 'cmi.core.lesson_status', 'browsed');
+                            }
+                            if ($mode == 'normal') {
+                                if ($lessonstatus == 'completed') {
+                                    if (!empty($sco->masteryscore) && !empty($score) && ($score >= $sco->masteryscore)) {
+                                        $lessonstatus = 'passed';
+                                    } else {
+                                        $lessonstatus = 'failed';
+                                    }
+                                    $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, 'cmi.core.lesson_status', $lessonstatus);
+                                }
+                            }                  
+                        }
+                        echo "error = 0\nerror_text = Successful\n";
+                    } else if ($status == 'Terminated') {
+                        echo "error = 1\nerror_text = Terminated\n";
+                    } else {
+                        echo "error = 1\nerror_text = Not Initialized\n";
+                    }
+                break;
+                case 'putcomments':
+                    if ($status == 'Running') {
+                        echo "error = 0\nerror_text = Successful\n";
+                    } else if ($status == 'Terminated') {
+                        echo "error = 1\nerror_text = Terminated\n";
+                    } else {
+                        echo "error = 1\nerror_text = Not Initialized\n";
+                    }
+                break;
+                case 'putinteractions':
+                    if ($status == 'Running') {
+                        echo "error = 0\nerror_text = Successful\n";
+                    } else if ($status == 'Terminated') {
+                        echo "error = 1\nerror_text = Terminated\n";
+                    } else {
+                        echo "error = 1\nerror_text = Not Initialized\n";
+                    }
+                break;
+                case 'putobjectives':
+                    if ($status == 'Running') {
+                        echo "error = 0\nerror_text = Successful\n";
+                    } else if ($status == 'Terminated') {
+                        echo "error = 1\nerror_text = Terminated\n";
+                    } else {
+                        echo "error = 1\nerror_text = Not Initialized\n";
+                    }
+                break;
+                case 'putpath':
+                    if ($status == 'Running') {
+                        echo "error = 0\nerror_text = Successful\n";
+                    } else if ($status == 'Terminated') {
+                        echo "error = 1\nerror_text = Terminated\n";
+                    } else {
+                        echo "error = 1\nerror_text = Not Initialized\n";
+                    }
+                break;
+                case 'putperformance':
+                    if ($status == 'Running') {
+                        echo "error = 0\nerror_text = Successful\n";
+                    } else if ($status == 'Terminated') {
+                        echo "error = 1\nerror_text = Terminated\n";
+                    } else {
+                        echo "error = 1\nerror_text = Not Initialized\n";
+                    }
+                break;
+                case 'exitau':
+                    if ($status == 'Running') {
+                        if (isset($SESSION->scorm_session_time) && ($SESSION->scorm_session_time != '')) {
+                            if ($track = get_record_select('scorm_scoes_track',"userid='$USER->id' AND scormid='$scorm->id' AND scoid='$sco->id' AND element='cmi.core.total_time'")) {
+                                // Add session_time to total_time
+                                $value = scorm_add_time($track->value, $SESSION->scorm_session_time);
+                                $track->value = $value;
+                                $track->timemodified = time();
+                                $id = update_record('scorm_scoes_track',$track);
+                            } else {
+                                $track->userid = $USER->id;
+                                $track->scormid = $scorm->id;
+                                $track->scoid = $sco->id;
+                                $track->element = 'cmi.core.total_time';
+                                $track->value = $SESSION->scorm_session_time;
+                                $track->timemodified = time();
+                                $id = insert_record('scorm_scoes_track',$track);
+                            }
+                        }
+                        
+                        $SESSION->scorm_status = 'Terminated';
+                        $SESSION->scorm_session_time = '';
+                        echo "error = 0\nerror_text = Successful\n";
+                    } else if ($status == 'Terminated') {
+                        echo "error = 1\nerror_text = Terminated\n";
+                    } else {
+                        echo "error = 1\nerror_text = Not Initialized\n";
+                    }
+                break;
+                default:
+                    echo "error = 1\nerror_text = Invalid Command\n";
+                break;
+            }
+        }
+    } else {
+        if (empty($command)) {
+            echo "error = 1\nerror_text = Invalid Command\n";
+        } else {
+            echo "error = 3\nerror_text = Invalid Session ID\n";
+        }
+    }
+?>
index 6d37834cea718a46686d7d4c2b6ce6a22fa4e7dd..f87ed4caf72a27740e6304e822daca84c6df946e 100644 (file)
@@ -1,74 +1,74 @@
-<?php\r
-\r
-    require_once("../../config.php");\r
-    require_once('locallib.php');\r
-    \r
-    $id = optional_param('id', '', PARAM_INT);       // Course Module ID, or\r
-    $a = optional_param('a', '', PARAM_INT);         // scorm ID\r
-    $scoid = required_param('scoid', PARAM_INT);     // sco ID\r
-    $mode = optional_param('mode', '', PARAM_ALPHA); // navigation mode\r
-    $attempt = required_param('attempt', PARAM_INT); // new attempt\r
-\r
-    if (!empty($id)) {\r
-        if (! $cm = get_coursemodule_from_id('scorm', $id)) {\r
-            error("Course Module ID was incorrect");\r
-        }\r
-        if (! $course = get_record("course", "id", $cm->course)) {\r
-            error("Course is misconfigured");\r
-        }\r
-        if (! $scorm = get_record("scorm", "id", $cm->instance)) {\r
-            error("Course module is incorrect");\r
-        }\r
-    } else if (!empty($a)) {\r
-        if (! $scorm = get_record("scorm", "id", $a)) {\r
-            error("Course module is incorrect");\r
-        }\r
-        if (! $course = get_record("course", "id", $scorm->course)) {\r
-            error("Course is misconfigured");\r
-        }\r
-        if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $course->id)) {\r
-            error("Course Module ID was incorrect");\r
-        }\r
-    } else {\r
-        error('A required parameter is missing');\r
-    }\r
-\r
-    require_login($course->id, false, $cm);\r
-    \r
-    if ($usertrack=scorm_get_tracks($scoid,$USER->id,$attempt)) {\r
-        $userdata = $usertrack;\r
-    } else {\r
-        $userdata->status = '';\r
-        $userdata->score_raw = '';\r
-    }\r
-    $userdata->student_id = addslashes($USER->username);\r
-    $userdata->student_name = addslashes($USER->lastname .', '. $USER->firstname);\r
-    $userdata->mode = 'normal';\r
-    if (isset($mode)) {\r
-        $userdata->mode = $mode;\r
-    }\r
-    if ($userdata->mode == 'normal') {\r
-        $userdata->credit = 'credit';\r
-    } else {\r
-        $userdata->credit = 'no-credit';\r
-    }    \r
-    if ($sco = get_record('scorm_scoes','id',$scoid)) {\r
-        $userdata->datafromlms = $sco->datafromlms;\r
-        $userdata->masteryscore = $sco->masteryscore;\r
-        $userdata->maxtimeallowed = $sco->maxtimeallowed;\r
-        $userdata->timelimitaction = $sco->timelimitaction;\r
-    } else {\r
-        error('Sco not found');\r
-    }\r
-    $scorm->version = strtolower(clean_param($scorm->version, PARAM_SAFEDIR));   // Just to be safe\r
-    if (file_exists($CFG->dirroot.'/mod/scorm/datamodels/'.$scorm->version.'.js.php')) {\r
-        include_once($CFG->dirroot.'/mod/scorm/datamodels/'.$scorm->version.'.js.php');\r
-    } else {\r
-        include_once($CFG->dirroot.'/mod/scorm/datamodels/scorm_12.js.php');\r
-    }\r
-?>\r
-\r
-var errorCode = "0";\r
-function underscore(str) {\r
-    return str.replace(/\./g,"__");\r
-}\r
+<?php
+
+    require_once("../../config.php");
+    require_once('locallib.php');
+    
+    $id = optional_param('id', '', PARAM_INT);       // Course Module ID, or
+    $a = optional_param('a', '', PARAM_INT);         // scorm ID
+    $scoid = required_param('scoid', PARAM_INT);     // sco ID
+    $mode = optional_param('mode', '', PARAM_ALPHA); // navigation mode
+    $attempt = required_param('attempt', PARAM_INT); // new attempt
+
+    if (!empty($id)) {
+        if (! $cm = get_coursemodule_from_id('scorm', $id)) {
+            error("Course Module ID was incorrect");
+        }
+        if (! $course = get_record("course", "id", $cm->course)) {
+            error("Course is misconfigured");
+        }
+        if (! $scorm = get_record("scorm", "id", $cm->instance)) {
+            error("Course module is incorrect");
+        }
+    } else if (!empty($a)) {
+        if (! $scorm = get_record("scorm", "id", $a)) {
+            error("Course module is incorrect");
+        }
+        if (! $course = get_record("course", "id", $scorm->course)) {
+            error("Course is misconfigured");
+        }
+        if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $course->id)) {
+            error("Course Module ID was incorrect");
+        }
+    } else {
+        error('A required parameter is missing');
+    }
+
+    require_login($course->id, false, $cm);
+    
+    if ($usertrack=scorm_get_tracks($scoid,$USER->id,$attempt)) {
+        $userdata = $usertrack;
+    } else {
+        $userdata->status = '';
+        $userdata->score_raw = '';
+    }
+    $userdata->student_id = addslashes($USER->username);
+    $userdata->student_name = addslashes($USER->lastname .', '. $USER->firstname);
+    $userdata->mode = 'normal';
+    if (isset($mode)) {
+        $userdata->mode = $mode;
+    }
+    if ($userdata->mode == 'normal') {
+        $userdata->credit = 'credit';
+    } else {
+        $userdata->credit = 'no-credit';
+    }    
+    if ($sco = get_record('scorm_scoes','id',$scoid)) {
+        $userdata->datafromlms = $sco->datafromlms;
+        $userdata->masteryscore = $sco->masteryscore;
+        $userdata->maxtimeallowed = $sco->maxtimeallowed;
+        $userdata->timelimitaction = $sco->timelimitaction;
+    } else {
+        error('Sco not found');
+    }
+    $scorm->version = strtolower(clean_param($scorm->version, PARAM_SAFEDIR));   // Just to be safe
+    if (file_exists($CFG->dirroot.'/mod/scorm/datamodels/'.$scorm->version.'.js.php')) {
+        include_once($CFG->dirroot.'/mod/scorm/datamodels/'.$scorm->version.'.js.php');
+    } else {
+        include_once($CFG->dirroot.'/mod/scorm/datamodels/scorm_12.js.php');
+    }
+?>
+
+var errorCode = "0";
+function underscore(str) {
+    return str.replace(/\./g,"__");
+}
index aaf38cb8db11dfcb2e0964a348bda10dad54f052..464bc2c27a82780067d09fa28805c55c4a1a10ab 100755 (executable)
-<?php  // $Id$\r
-\r
-    require_once("../../config.php");\r
-    require_once('locallib.php');\r
-    \r
-    $id = optional_param('id', '', PARAM_INT);    // Course Module ID, or\r
-    $a = optional_param('a', '', PARAM_INT);     // SCORM ID\r
-    $b = optional_param('b', '', PARAM_INT);     // SCO ID\r
-    $user = optional_param('user', '', PARAM_INT);  // User ID\r
-\r
-    if (!empty($id)) {\r
-        if (! $cm = get_record("course_modules", "id", $id)) {\r
-            error("Course Module ID was incorrect");\r
-        }\r
-        if (! $course = get_record("course", "id", $cm->course)) {\r
-            error("Course is misconfigured");\r
-        }\r
-        if (! $scorm = get_record("scorm", "id", $cm->instance)) {\r
-            error("Course module is incorrect");\r
-        }\r
-    } else {\r
-        if (!empty($b)) {\r
-            if (! $sco = get_record("scorm_scoes", "id", $b)) {\r
-                error("Scorm activity is incorrect");\r
-            }\r
-            $a = $sco->scorm;\r
-        }\r
-        if (!empty($a)) {\r
-            if (! $scorm = get_record("scorm", "id", $a)) {\r
-                error("Course module is incorrect");\r
-            }\r
-            if (! $course = get_record("course", "id", $scorm->course)) {\r
-                error("Course is misconfigured");\r
-            }\r
-            if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $course->id)) {\r
-                error("Course Module ID was incorrect");\r
-            }\r
-        }\r
-    }\r
-\r
-    require_login($course->id, false, $cm);\r
-    require_capability('mod/scorm:viewgrades', get_context_instance(COTNEXT_MODULE, $cm->id));\r
-\r
-    add_to_log($course->id, "scorm", "report", "cofficientsetting.php?id=$cm->id", "$scorm->id");\r
-\r
-/// Print the page header\r
-    if (empty($noheader)) {\r
-        if ($course->category) {\r
-            $navigation = "<a href=\"../../course/view.php?id=$course->id\">$course->shortname</a> ->";\r
-        } else {\r
-            $navigation = '';\r
-        }\r
-\r
-        $strscorms = get_string("modulenameplural", "scorm");\r
-        $strscorm  = get_string("modulename", "scorm");\r
-        $strreport  = get_string("report", "scorm");\r
-        $strname  = get_string('name');\r
-        $strcoefficient = get_string('coefficient',"scorm");\r
-        $strcoefficient = "Thiet lap he so";\r
-        if (empty($b)) {\r
-            print_header("$course->shortname: ".format_string($scorm->name), "$course->fullname",\r
-                     "$navigation <a href=\"index.php?id=$course->id\">$strscorms</a>\r
-                      -> <a href=\"view.php?id=$cm->id\">".format_string($scorm->name,true)."</a> -> $strcoefficient",\r
-                     "", "", true);\r
-        } else {\r
-            print_header("$course->shortname: ".format_string($scorm->name), "$course->fullname",\r
-                     "$navigation <a href=\"index.php?id=$course->id\">$strscorms</a>\r
-                      -> <a href=\"view.php?id=$cm->id\">".format_string($scorm->name,true)."</a>\r
-              -> <a href=\"report.php?id=$cm->id\">$strreport</a> -> $sco->title",\r
-                     "", "", true);\r
-        }\r
-        print_heading(format_string($scorm->name));\r
-    }\r
-\r
-    $scormpixdir = $CFG->modpixpath.'/scorm/pix';\r
-\r
-    //Phan trinh bay chinh\r
-?>\r
-\r
-  <?php\r
-    $examScoes = get_records_select('scorm_scoes', 'scorm ='.($scorm->id).' and minnormalizedmeasure > -1');\r
-    foreach ($examScoes as $examSco){\r
-        $newcoefficient = optional_param($examSco->id,'',PARAM_INT);\r
-        $sco = get_record('scorm_scoes','scorm',$scorm->id,'id',$examSco->id,'','');\r
-        $sco->score_coefficient = $newcoefficient;\r
-        $ketqua = update_record('scorm_scoes',$sco);\r
-        //echo "Cap nhat $examSco->id voi he so diem ".$newcoefficient."<br>";\r
-    }\r
-\r
-    if ($ketqua)\r
-    {\r
-        echo "".get_string('updatesuccess','scorm');\r
-    }\r
-    else\r
-    {\r
-        echo "".get_string('updatefail','scorm');\r
-    }\r
-\r
-    echo "<br><br><a href=coefficientsetting.php?id=$id>".get_string('back','scorm')."</a>"\r
-?>\r
-<?php\r
-    //ket thuc phan trinh bay chinh\r
-\r
-    if (empty($noheader)) {\r
-        print_footer($course);\r
-    }\r
-?>\r
+<?php  // $Id$
+
+    require_once("../../config.php");
+    require_once('locallib.php');
+    
+    $id = optional_param('id', '', PARAM_INT);    // Course Module ID, or
+    $a = optional_param('a', '', PARAM_INT);     // SCORM ID
+    $b = optional_param('b', '', PARAM_INT);     // SCO ID
+    $user = optional_param('user', '', PARAM_INT);  // User ID
+
+    if (!empty($id)) {
+        if (! $cm = get_record("course_modules", "id", $id)) {
+            error("Course Module ID was incorrect");
+        }
+        if (! $course = get_record("course", "id", $cm->course)) {
+            error("Course is misconfigured");
+        }
+        if (! $scorm = get_record("scorm", "id", $cm->instance)) {
+            error("Course module is incorrect");
+        }
+    } else {
+        if (!empty($b)) {
+            if (! $sco = get_record("scorm_scoes", "id", $b)) {
+                error("Scorm activity is incorrect");
+            }
+            $a = $sco->scorm;
+        }
+        if (!empty($a)) {
+            if (! $scorm = get_record("scorm", "id", $a)) {
+                error("Course module is incorrect");
+            }
+            if (! $course = get_record("course", "id", $scorm->course)) {
+                error("Course is misconfigured");
+            }
+            if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $course->id)) {
+                error("Course Module ID was incorrect");
+            }
+        }
+    }
+
+    require_login($course->id, false, $cm);
+    require_capability('mod/scorm:viewgrades', get_context_instance(COTNEXT_MODULE, $cm->id));
+
+    add_to_log($course->id, "scorm", "report", "cofficientsetting.php?id=$cm->id", "$scorm->id");
+
+/// Print the page header
+    if (empty($noheader)) {
+        if ($course->category) {
+            $navigation = "<a href=\"../../course/view.php?id=$course->id\">$course->shortname</a> ->";
+        } else {
+            $navigation = '';
+        }
+
+        $strscorms = get_string("modulenameplural", "scorm");
+        $strscorm  = get_string("modulename", "scorm");
+        $strreport  = get_string("report", "scorm");
+        $strname  = get_string('name');
+        $strcoefficient = get_string('coefficient',"scorm");
+        $strcoefficient = "Thiet lap he so";
+        if (empty($b)) {
+            print_header("$course->shortname: ".format_string($scorm->name), "$course->fullname",
+                     "$navigation <a href=\"index.php?id=$course->id\">$strscorms</a>
+                      -> <a href=\"view.php?id=$cm->id\">".format_string($scorm->name,true)."</a> -> $strcoefficient",
+                     "", "", true);
+        } else {
+            print_header("$course->shortname: ".format_string($scorm->name), "$course->fullname",
+                     "$navigation <a href=\"index.php?id=$course->id\">$strscorms</a>
+                      -> <a href=\"view.php?id=$cm->id\">".format_string($scorm->name,true)."</a>
+              -> <a href=\"report.php?id=$cm->id\">$strreport</a> -> $sco->title",
+                     "", "", true);
+        }
+        print_heading(format_string($scorm->name));
+    }
+
+    $scormpixdir = $CFG->modpixpath.'/scorm/pix';
+
+    //Phan trinh bay chinh
+?>
+
+  <?php
+    $examScoes = get_records_select('scorm_scoes', 'scorm ='.($scorm->id).' and minnormalizedmeasure > -1');
+    foreach ($examScoes as $examSco){
+        $newcoefficient = optional_param($examSco->id,'',PARAM_INT);
+        $sco = get_record('scorm_scoes','scorm',$scorm->id,'id',$examSco->id,'','');
+        $sco->score_coefficient = $newcoefficient;
+        $ketqua = update_record('scorm_scoes',$sco);
+        //echo "Cap nhat $examSco->id voi he so diem ".$newcoefficient."<br>";
+    }
+
+    if ($ketqua)
+    {
+        echo "".get_string('updatesuccess','scorm');
+    }
+    else
+    {
+        echo "".get_string('updatefail','scorm');
+    }
+
+    echo "<br><br><a href=coefficientsetting.php?id=$id>".get_string('back','scorm')."</a>"
+?>
+<?php
+    //ket thuc phan trinh bay chinh
+
+    if (empty($noheader)) {
+        print_footer($course);
+    }
+?>
index 14c04285902ad62d878eed9e543149bba1ccdd22..deecb00eae8667e80be6ef5103c5c97c85f70491 100755 (executable)
-<?php  // $Id$\r
-\r
-    require_once("../../config.php");\r
-    require_once('locallib.php');\r
-    \r
-    $id = optional_param('id', '', PARAM_INT);    // Course Module ID, or\r
-    $a = optional_param('a', '', PARAM_INT);     // SCORM ID\r
-    $b = optional_param('b', '', PARAM_INT);     // SCO ID\r
-    $user = optional_param('user', '', PARAM_INT);  // User ID\r
-\r
-    if (!empty($id)) {\r
-        if (! $cm = get_record("course_modules", "id", $id)) {\r
-            error("Course Module ID was incorrect");\r
-        }\r
-        if (! $course = get_record("course", "id", $cm->course)) {\r
-            error("Course is misconfigured");\r
-        }\r
-        if (! $scorm = get_record("scorm", "id", $cm->instance)) {\r
-            error("Course module is incorrect");\r
-        }\r
-    } else {\r
-        if (!empty($b)) {\r
-            if (! $sco = get_record("scorm_scoes", "id", $b)) {\r
-                error("Scorm activity is incorrect");\r
-            }\r
-            $a = $sco->scorm;\r
-        }\r
-        if (!empty($a)) {\r
-            if (! $scorm = get_record("scorm", "id", $a)) {\r
-                error("Course module is incorrect");\r
-            }\r
-            if (! $course = get_record("course", "id", $scorm->course)) {\r
-                error("Course is misconfigured");\r
-            }\r
-            if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $course->id)) {\r
-                error("Course Module ID was incorrect");\r
-            }\r
-        }\r
-    }\r
-\r
-    require_login($course->id, false, $cm);\r
-    require_capability('mod/scorm:viewgrades', get_context_instance(COTNEXT_MODULE, $cm->id));\r
-\r
-    add_to_log($course->id, "scorm", "report", "cofficientsetting.php?id=$cm->id", "$scorm->id");\r
-\r
-/// Print the page header\r
-    if (empty($noheader)) {\r
-        if ($course->category) {\r
-            $navigation = "<a href=\"../../course/view.php?id=$course->id\">$course->shortname</a> ->";\r
-        } else {\r
-            $navigation = '';\r
-        }\r
-\r
-        $strscorms = get_string("modulenameplural", "scorm");\r
-        $strscorm  = get_string("modulename", "scorm");\r
-        $strreport  = get_string("report", "scorm");\r
-        $strname  = get_string('name');\r
-        $strcoefficient = get_string('coefficient','scorm');\r
-        if (empty($b)) {\r
-            print_header("$course->shortname: ".format_string($scorm->name), "$course->fullname",\r
-                     "$navigation <a href=\"index.php?id=$course->id\">$strscorms</a>\r
-                      -> <a href=\"view.php?id=$cm->id\">".format_string($scorm->name,true)."</a> -> $strcoefficient",\r
-                     "", "", true);\r
-        } else {\r
-            print_header("$course->shortname: ".format_string($scorm->name), "$course->fullname",\r
-                     "$navigation <a href=\"index.php?id=$course->id\">$strscorms</a>\r
-                      -> <a href=\"view.php?id=$cm->id\">".format_string($scorm->name,true)."</a>\r
-              -> <a href=\"report.php?id=$cm->id\">$strreport</a> -> $sco->title",\r
-                     "", "", true);\r
-        }\r
-        print_heading(format_string($scorm->name));\r
-    }\r
-\r
-    $scormpixdir = $CFG->modpixpath.'/scorm/pix';\r
-\r
-    //Phan trinh bay chinh\r
-?>\r
-<script type="text/javascript">\r
-function validate_form()\r
-{\r
-    return true;\r
-}\r
-</script>\r
-<form name="form" method="post" action="coefficientconfirm.php" onsubmit="return validate_form();" >\r
-  <table width="50%" border="0">\r
-    <tr>\r
-      <td class="scormtableheader"><?php echo(get_string('title','scorm')); ?></td>\r
-      <td class="scormtableheader"><?php echo(get_string('coefficient','scorm')); ?></td>\r
-    </tr>\r
\r
-  <?php\r
-    $examScoes = get_records_select('scorm_scoes', 'scorm ='.($scorm->id).' and minnormalizedmeasure > -1');\r
-    if(!empty($examScoes))\r
-    {\r
-    \r
-        foreach ($examScoes as $examSco){\r
-        echo "<tr><td>";    \r
-        echo "$examSco->identifier.</td><td><input type='text' name='$examSco->id' class='scormtextbox' value=$examSco->score_coefficient /></td></tr><br>";\r
-        }\r
-    }\r
-\r
-?>\r
- </table>\r
-<br>\r
-<input type="hidden" name="id" value="<?php p($id) ?>" />\r
-<input type="submit" value="<?php print_string('savechanges') ?>" />\r
-</form>\r
-<?php\r
-    //ket thuc phan trinh bay chinh\r
-\r
-    if (empty($noheader)) {\r
-        print_footer($course);\r
-    }\r
-?>\r
+<?php  // $Id$
+
+    require_once("../../config.php");
+    require_once('locallib.php');
+    
+    $id = optional_param('id', '', PARAM_INT);    // Course Module ID, or
+    $a = optional_param('a', '', PARAM_INT);     // SCORM ID
+    $b = optional_param('b', '', PARAM_INT);     // SCO ID
+    $user = optional_param('user', '', PARAM_INT);  // User ID
+
+    if (!empty($id)) {
+        if (! $cm = get_record("course_modules", "id", $id)) {
+            error("Course Module ID was incorrect");
+        }
+        if (! $course = get_record("course", "id", $cm->course)) {
+            error("Course is misconfigured");
+        }
+        if (! $scorm = get_record("scorm", "id", $cm->instance)) {
+            error("Course module is incorrect");
+        }
+    } else {
+        if (!empty($b)) {
+            if (! $sco = get_record("scorm_scoes", "id", $b)) {
+                error("Scorm activity is incorrect");
+            }
+            $a = $sco->scorm;
+        }
+        if (!empty($a)) {
+            if (! $scorm = get_record("scorm", "id", $a)) {
+                error("Course module is incorrect");
+            }
+            if (! $course = get_record("course", "id", $scorm->course)) {
+                error("Course is misconfigured");
+            }
+            if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $course->id)) {
+                error("Course Module ID was incorrect");
+            }
+        }
+    }
+
+    require_login($course->id, false, $cm);
+    require_capability('mod/scorm:viewgrades', get_context_instance(COTNEXT_MODULE, $cm->id));
+
+    add_to_log($course->id, "scorm", "report", "cofficientsetting.php?id=$cm->id", "$scorm->id");
+
+/// Print the page header
+    if (empty($noheader)) {
+        if ($course->category) {
+            $navigation = "<a href=\"../../course/view.php?id=$course->id\">$course->shortname</a> ->";
+        } else {
+            $navigation = '';
+        }
+
+        $strscorms = get_string("modulenameplural", "scorm");
+        $strscorm  = get_string("modulename", "scorm");
+        $strreport  = get_string("report", "scorm");
+        $strname  = get_string('name');
+        $strcoefficient = get_string('coefficient','scorm');
+        if (empty($b)) {
+            print_header("$course->shortname: ".format_string($scorm->name), "$course->fullname",
+                     "$navigation <a href=\"index.php?id=$course->id\">$strscorms</a>
+                      -> <a href=\"view.php?id=$cm->id\">".format_string($scorm->name,true)."</a> -> $strcoefficient",
+                     "", "", true);
+        } else {
+            print_header("$course->shortname: ".format_string($scorm->name), "$course->fullname",
+                     "$navigation <a href=\"index.php?id=$course->id\">$strscorms</a>
+                      -> <a href=\"view.php?id=$cm->id\">".format_string($scorm->name,true)."</a>
+              -> <a href=\"report.php?id=$cm->id\">$strreport</a> -> $sco->title",
+                     "", "", true);
+        }
+        print_heading(format_string($scorm->name));
+    }
+
+    $scormpixdir = $CFG->modpixpath.'/scorm/pix';
+
+    //Phan trinh bay chinh
+?>
+<script type="text/javascript">
+function validate_form()
+{
+    return true;
+}
+</script>
+<form name="form" method="post" action="coefficientconfirm.php" onsubmit="return validate_form();" >
+  <table width="50%" border="0">
+    <tr>
+      <td class="scormtableheader"><?php echo(get_string('title','scorm')); ?></td>
+      <td class="scormtableheader"><?php echo(get_string('coefficient','scorm')); ?></td>
+    </tr>
+  <?php
+    $examScoes = get_records_select('scorm_scoes', 'scorm ='.($scorm->id).' and minnormalizedmeasure > -1');
+    if(!empty($examScoes))
+    {
+    
+        foreach ($examScoes as $examSco){
+        echo "<tr><td>";    
+        echo "$examSco->identifier.</td><td><input type='text' name='$examSco->id' class='scormtextbox' value=$examSco->score_coefficient /></td></tr><br>";
+        }
+    }
+
+?>
+ </table>
+<br>
+<input type="hidden" name="id" value="<?php p($id) ?>" />
+<input type="submit" value="<?php print_string('savechanges') ?>" />
+</form>
+<?php
+    //ket thuc phan trinh bay chinh
+
+    if (empty($noheader)) {
+        print_footer($course);
+    }
+?>
index 7a646b5eeb187d99201d8a1462a1b960d0f8102c..076c52036ac5f4e6da36d35037af56e2e39cebbd 100755 (executable)
@@ -1,56 +1,56 @@
-<?php\r
-    require_once('../../config.php');\r
-    require_once('locallib.php');\r
-        \r
-    $id = optional_param('id', '', PARAM_INT);       // Course Module ID, or\r
-    $a = optional_param('a', '', PARAM_INT);         // scorm ID\r
-    $scoid = required_param('scoid', PARAM_INT);  // sco ID\r
-//    $attempt = required_param('attempt', PARAM_INT);  // attempt number\r
-    $attempt = $SESSION->scorm_attempt;\r
-\r
-\r
-    if (!empty($id)) {\r
-        if (! $cm = get_record("course_modules", "id", $id)) {\r
-            error("Course Module ID was incorrect");\r
-        }\r
-        if (! $course = get_record("course", "id", $cm->course)) {\r
-            error("Course is misconfigured");\r
-        }\r
-        if (! $scorm = get_record("scorm", "id", $cm->instance)) {\r
-            error("Course module is incorrect");\r
-        }\r
-    } else if (!empty($a)) {\r
-        if (! $scorm = get_record("scorm", "id", $a)) {\r
-            error("Course module is incorrect");\r
-        }\r
-        if (! $course = get_record("course", "id", $scorm->course)) {\r
-            error("Course is misconfigured");\r
-        }\r
-        if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $course->id)) {\r
-            error("Course Module ID was incorrect");\r
-        }\r
-    } else {\r
-        error('A required parameter is missing');\r
-    }\r
-\r
-    require_login($course->id, false, $cm);\r
-\r
-    if (confirm_sesskey() && (!empty($scoid))) {\r
-        $result = true;\r
-        if (has_capability('mod/scorm:savetrack', get_context_instance(CONTEXT_MODULE,$cm->id))) {\r
-            foreach ($_POST as $element => $value) {\r
-                if (substr($element,0,3) == 'cmi') {\r
-                    $element = str_replace('__','.',$element);\r
-                    $element = preg_replace('/_(\d+)/',".\$1",$element);\r
-                    $result = scorm_insert_track($USER->id, $scorm->id, $scoid, $attempt, $element, $value) && $result;\r
-                }\r
-            }\r
-        }\r
-        if ($result) {\r
-            echo "true\n0";\r
-        } else {\r
-            echo "false\n101";\r
-        }\r
-    }\r
-?>\r
-\r
+<?php
+    require_once('../../config.php');
+    require_once('locallib.php');
+        
+    $id = optional_param('id', '', PARAM_INT);       // Course Module ID, or
+    $a = optional_param('a', '', PARAM_INT);         // scorm ID
+    $scoid = required_param('scoid', PARAM_INT);  // sco ID
+//    $attempt = required_param('attempt', PARAM_INT);  // attempt number
+    $attempt = $SESSION->scorm_attempt;
+
+
+    if (!empty($id)) {
+        if (! $cm = get_record("course_modules", "id", $id)) {
+            error("Course Module ID was incorrect");
+        }
+        if (! $course = get_record("course", "id", $cm->course)) {
+            error("Course is misconfigured");
+        }
+        if (! $scorm = get_record("scorm", "id", $cm->instance)) {
+            error("Course module is incorrect");
+        }
+    } else if (!empty($a)) {
+        if (! $scorm = get_record("scorm", "id", $a)) {
+            error("Course module is incorrect");
+        }
+        if (! $course = get_record("course", "id", $scorm->course)) {
+            error("Course is misconfigured");
+        }
+        if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $course->id)) {
+            error("Course Module ID was incorrect");
+        }
+    } else {
+        error('A required parameter is missing');
+    }
+
+    require_login($course->id, false, $cm);
+
+    if (confirm_sesskey() && (!empty($scoid))) {
+        $result = true;
+        if (has_capability('mod/scorm:savetrack', get_context_instance(CONTEXT_MODULE,$cm->id))) {
+            foreach ($_POST as $element => $value) {
+                if (substr($element,0,3) == 'cmi') {
+                    $element = str_replace('__','.',$element);
+                    $element = preg_replace('/_(\d+)/',".\$1",$element);
+                    $result = scorm_insert_track($USER->id, $scorm->id, $scoid, $attempt, $element, $value) && $result;
+                }
+            }
+        }
+        if ($result) {
+            echo "true\n0";
+        } else {
+            echo "false\n101";
+        }
+    }
+?>
+
index 0fbb5aabd48a34cba2f0d43b92efa6b86994369c..c332b793e8334b3324396533c38d283f44be58c8 100755 (executable)
@@ -1,95 +1,95 @@
-<?php // $Id$\r
-\r
-    require_once("../../config.php");\r
-\r
-    $id = required_param('id', PARAM_INT);   // course id\r
-\r
-    if (!empty($id)) {\r
-        if (! $course = get_record("course", "id", $id)) {\r
-            error("Course ID is incorrect");\r
-        }\r
-    } else {\r
-        error('A required parameter is missing');\r
-    }\r
-\r
-    require_course_login($course);\r
-\r
-    add_to_log($course->id, "scorm", "view all", "index.php?id=$course->id", "");\r
-\r
-    $strscorm = get_string("modulename", "scorm");\r
-    $strscorms = get_string("modulenameplural", "scorm");\r
-    $strweek = get_string("week");\r
-    $strtopic = get_string("topic");\r
-    $strname = get_string("name");\r
-    $strsummary = get_string("summary");\r
-    $strreport = get_string("report",'scorm');\r
-    $strlastmodified = get_string("lastmodified");\r
-\r
-    print_header_simple("$strscorms", "", "$strscorms",\r
-                 "", "", true, "", navmenu($course));\r
-\r
-    if ($course->format == "weeks" or $course->format == "topics") {\r
-        $sortorder = "cw.section ASC";\r
-    } else {\r
-        $sortorder = "m.timemodified DESC";\r
-    }\r
-\r
-    if (! $scorms = get_all_instances_in_course("scorm", $course)) {\r
-        notice("There are no scorms", "../../course/view.php?id=$course->id");\r
-        exit;\r
-    }\r
-\r
-    if ($course->format == "weeks") {\r
-        $table->head  = array ($strweek, $strname, $strsummary, $strreport);\r
-        $table->align = array ("center", "left", "left", "left");\r
-    } else if ($course->format == "topics") {\r
-        $table->head  = array ($strtopic, $strname, $strsummary, $strreport);\r
-        $table->align = array ("center", "left", "left", "left");\r
-    } else {\r
-        $table->head  = array ($strlastmodified, $strname, $strsummary, $strreport);\r
-        $table->align = array ("left", "left", "left", "left");\r
-    }\r
-\r
-    foreach ($scorms as $scorm) {\r
-\r
-        $context = get_context_instance(CONTEXT_MODULE,$scorm->coursemodule);\r
-        $tt = "";\r
-        if ($course->format == "weeks" or $course->format == "topics") {\r
-            if ($scorm->section) {\r
-                $tt = "$scorm->section";\r
-            }\r
-        } else {\r
-            $tt = userdate($scorm->timemodified);\r
-        }\r
-        $report = '&nbsp;';\r
-        if (has_capability('mod/scorm:viewreport', $context)) {\r
-            $trackedusers = get_record('scorm_scoes_track', 'scormid', $scorm->id, '', '', '', '', 'count(distinct(userid)) as c');\r
-            if ($trackedusers->c > 0) {\r
-                $reportshow = '<a href="report.php?a='.$scorm->id.'">'.get_string('viewallreports','scorm',$trackedusers->c).'</a></div>';\r
-            } else {\r
-                $reportshow = get_string('noreports','scorm');\r
-            }\r
-        } else if (has_capability('mod/scorm:viewscores', $context)) {\r
-            require_once('locallib.php');\r
-            $report = scorm_grade_user(get_records('scorm_scoes','scorm',$scorm->id), $USER->id, $scorm->grademethod);\r
-            $reportshow = get_string('score','scorm').": ".$report;       \r
-        }\r
-        if (!$scorm->visible) {\r
-           //Show dimmed if the mod is hidden\r
-           $table->data[] = array ($tt, "<a class=\"dimmed\" href=\"view.php?id=$scorm->coursemodule\">".format_string($scorm->name,true)."</a>",\r
-                                   format_text($scorm->summary),$reportshow);\r
-        } else {\r
-           //Show normal if the mod is visible\r
-           $table->data[] = array ($tt, "<a href=\"view.php?id=$scorm->coursemodule\">".format_string($scorm->name,true)."</a>",\r
-                                   format_text($scorm->summary), $reportshow);\r
-        }\r
-    }\r
-\r
-    echo "<br />";\r
-\r
-    print_table($table);\r
-\r
-    print_footer($course);\r
-\r
-?>\r
-\r
+<?php // $Id$
+
+    require_once("../../config.php");
+
+    $id = required_param('id', PARAM_INT);   // course id
+
+    if (!empty($id)) {
+        if (! $course = get_record("course", "id", $id)) {
+            error("Course ID is incorrect");
+        }
+    } else {
+        error('A required parameter is missing');
+    }
+
+    require_course_login($course);
+
+    add_to_log($course->id, "scorm", "view all", "index.php?id=$course->id", "");
+
+    $strscorm = get_string("modulename", "scorm");
+    $strscorms = get_string("modulenameplural", "scorm");
+    $strweek = get_string("week");
+    $strtopic = get_string("topic");
+    $strname = get_string("name");
+    $strsummary = get_string("summary");
+    $strreport = get_string("report",'scorm');
+    $strlastmodified = get_string("lastmodified");
+
+    print_header_simple("$strscorms", "", "$strscorms",
+                 "", "", true, "", navmenu($course));
+
+    if ($course->format == "weeks" or $course->format == "topics") {
+        $sortorder = "cw.section ASC";
+    } else {
+        $sortorder = "m.timemodified DESC";
+    }
+
+    if (! $scorms = get_all_instances_in_course("scorm", $course)) {
+        notice("There are no scorms", "../../course/view.php?id=$course->id");
+        exit;
+    }
+
+    if ($course->format == "weeks") {
+        $table->head  = array ($strweek, $strname, $strsummary, $strreport);
+        $table->align = array ("center", "left", "left", "left");
+    } else if ($course->format == "topics") {
+        $table->head  = array ($strtopic, $strname, $strsummary, $strreport);
+        $table->align = array ("center", "left", "left", "left");
+    } else {
+        $table->head  = array ($strlastmodified, $strname, $strsummary, $strreport);
+        $table->align = array ("left", "left", "left", "left");
+    }
+
+    foreach ($scorms as $scorm) {
+
+        $context = get_context_instance(CONTEXT_MODULE,$scorm->coursemodule);
+        $tt = "";
+        if ($course->format == "weeks" or $course->format == "topics") {
+            if ($scorm->section) {
+                $tt = "$scorm->section";
+            }
+        } else {
+            $tt = userdate($scorm->timemodified);
+        }
+        $report = '&nbsp;';
+        if (has_capability('mod/scorm:viewreport', $context)) {
+            $trackedusers = get_record('scorm_scoes_track', 'scormid', $scorm->id, '', '', '', '', 'count(distinct(userid)) as c');
+            if ($trackedusers->c > 0) {
+                $reportshow = '<a href="report.php?a='.$scorm->id.'">'.get_string('viewallreports','scorm',$trackedusers->c).'</a></div>';
+            } else {
+                $reportshow = get_string('noreports','scorm');
+            }
+        } else if (has_capability('mod/scorm:viewscores', $context)) {
+            require_once('locallib.php');
+            $report = scorm_grade_user(get_records('scorm_scoes','scorm',$scorm->id), $USER->id, $scorm->grademethod);
+            $reportshow = get_string('score','scorm').": ".$report;       
+        }
+        if (!$scorm->visible) {
+           //Show dimmed if the mod is hidden
+           $table->data[] = array ($tt, "<a class=\"dimmed\" href=\"view.php?id=$scorm->coursemodule\">".format_string($scorm->name,true)."</a>",
+                                   format_text($scorm->summary),$reportshow);
+        } else {
+           //Show normal if the mod is visible
+           $table->data[] = array ($tt, "<a href=\"view.php?id=$scorm->coursemodule\">".format_string($scorm->name,true)."</a>",
+                                   format_text($scorm->summary), $reportshow);
+        }
+    }
+
+    echo "<br />";
+
+    print_table($table);
+
+    print_footer($course);
+
+?>
+
index c1361fc3de7c6ef0c004c0a676fc4156f2dfd341..56db83cd6e52362486b52b155433d536cf2d1b2a 100755 (executable)
-<?php\r
-    require_once("../../config.php");\r
-    require_once('locallib.php');\r
-\r
-    $id = optional_param('id', '', PARAM_INT);       // Course Module ID, or\r
-    $a = optional_param('a', '', PARAM_INT);         // scorm ID\r
-    $scoid = required_param('scoid', PARAM_INT);     // sco ID\r
-\r
-    if (!empty($id)) {\r
-        if (! $cm = get_coursemodule_from_id('scorm', $id)) {\r
-            error("Course Module ID was incorrect");\r
-        }\r
-        if (! $course = get_record("course", "id", $cm->course)) {\r
-            error("Course is misconfigured");\r
-        }\r
-        if (! $scorm = get_record("scorm", "id", $cm->instance)) {\r
-            error("Course module is incorrect");\r
-        }\r
-    } else if (!empty($a)) {\r
-        if (! $scorm = get_record("scorm", "id", $a)) {\r
-            error("Course module is incorrect");\r
-        }\r
-        if (! $course = get_record("course", "id", $scorm->course)) {\r
-            error("Course is misconfigured");\r
-        }\r
-        if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $course->id)) {\r
-            error("Course Module ID was incorrect");\r
-        }\r
-    } else {\r
-        error('A required parameter is missing');\r
-    }\r
-\r
-    require_login($course->id, false, $cm);\r
-    if (!empty($scoid)) {\r
-    //\r
-    // Direct SCO request\r
-    //\r
-        if ($sco = get_record("scorm_scoes","id",$scoid)) {\r
-            if ($sco->launch == '') {\r
-                // Search for the next launchable sco\r
-                if ($scoes = get_records_select("scorm_scoes","scorm=".$scorm->id." AND launch<>'' AND id>".$sco->id,"id ASC")) {\r
-                    $sco = current($scoes);\r
-                }\r
-            }\r
-        }\r
-    }\r
-    //\r
-    // If no sco was found get the first of SCORM package\r
-    //\r
-    if (!isset($sco)) {\r
-        $scoes = get_records_select("scorm_scoes","scorm=".$scorm->id." AND launch<>''","id ASC");\r
-        $sco = current($scoes);\r
-    }\r
-\r
-    //\r
-    // Forge SCO URL\r
-    //\r
-    $connector = '';\r
-    $version = substr($scorm->version,0,4);\r
-    if (!empty($sco->parameters) || ($version == 'AICC')) {\r
-        if (stripos($sco->launch,'?') !== false) {\r
-            $connector = '&';\r
-        } else {\r
-            $connector = '?';\r
-        }\r
-        if (!empty($sco->parameters) && ($sco->parameters[0] == '?')) {\r
-            $sco->parameters = substr($sco->parameters,1);\r
-        }\r
-    }\r
-    \r
-    if ($version == 'AICC') {\r
-        if (!empty($sco->parameters)) {\r
-            $sco->parameters = '&'. $sco->parameters;\r
-        }\r
-        $launcher = $sco->launch.$connector.'aicc_sid='.sesskey().'&aicc_url='.$CFG->wwwroot.'/mod/scorm/type/aicc/aicc.php'.$sco->parameters;\r
-    } else {\r
-        $launcher = $sco->launch.$connector.$sco->parameters;\r
-    }\r
-    \r
-    if (scorm_external_link($sco->launch)) {\r
-        $result = $launcher;\r
-    } else if ($scorm->reference[0] == '#') {\r
-        require_once($repositoryconfigfile);\r
-        $result = $CFG->repositorywebroot.substr($scorm->reference,1).'/'.$sco->launch;\r
-    } else {\r
-        if (basename($scorm->reference) == 'imsmanifest.xml') {\r
-            $basedir = dirname($scorm->reference);\r
-        } else {\r
-            $basedir = 'moddata/scorm/'.$scorm->id;\r
-        }\r
-        if ($CFG->slasharguments) {\r
-            $result = $CFG->wwwroot.'/file.php/'.$scorm->course.'/'.$basedir.'/'.$launcher;\r
-        } else {\r
-            $result = $CFG->wwwroot.'/file.php?file=/'.$scorm->course.'/'.$basedir.'/'.$launcher;\r
-        }\r
-    }\r
-?>\r
-<html>\r
-    <head>\r
-        <title>LoadSCO</title>\r
-        <script language="javascript" type="text/javascript">\r
-        <!--\r
-            setTimeout('document.location = "<?php echo $result ?>";',2000);\r
-        -->\r
-        </script>\r
-        <noscript>\r
-            <meta http-equiv="refresh" content="2;url=<?php echo $result ?>" />\r
-        </noscript> \r
-    </head>\r
-    <body>\r
-        &nbsp;\r
-    </body>\r
-</html>\r
+<?php
+    require_once("../../config.php");
+    require_once('locallib.php');
+
+    $id = optional_param('id', '', PARAM_INT);       // Course Module ID, or
+    $a = optional_param('a', '', PARAM_INT);         // scorm ID
+    $scoid = required_param('scoid', PARAM_INT);     // sco ID
+
+    if (!empty($id)) {
+        if (! $cm = get_coursemodule_from_id('scorm', $id)) {
+            error("Course Module ID was incorrect");
+        }
+        if (! $course = get_record("course", "id", $cm->course)) {
+            error("Course is misconfigured");
+        }
+        if (! $scorm = get_record("scorm", "id", $cm->instance)) {
+            error("Course module is incorrect");
+        }
+    } else if (!empty($a)) {
+        if (! $scorm = get_record("scorm", "id", $a)) {
+            error("Course module is incorrect");
+        }
+        if (! $course = get_record("course", "id", $scorm->course)) {
+            error("Course is misconfigured");
+        }
+        if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $course->id)) {
+            error("Course Module ID was incorrect");
+        }
+    } else {
+        error('A required parameter is missing');
+    }
+
+    require_login($course->id, false, $cm);
+    if (!empty($scoid)) {
+    //
+    // Direct SCO request
+    //
+        if ($sco = get_record("scorm_scoes","id",$scoid)) {
+            if ($sco->launch == '') {
+                // Search for the next launchable sco
+                if ($scoes = get_records_select("scorm_scoes","scorm=".$scorm->id." AND launch<>'' AND id>".$sco->id,"id ASC")) {
+                    $sco = current($scoes);
+                }
+            }
+        }
+    }
+    //
+    // If no sco was found get the first of SCORM package
+    //
+    if (!isset($sco)) {
+        $scoes = get_records_select("scorm_scoes","scorm=".$scorm->id." AND launch<>''","id ASC");
+        $sco = current($scoes);
+    }
+
+    //
+    // Forge SCO URL
+    //
+    $connector = '';
+    $version = substr($scorm->version,0,4);
+    if (!empty($sco->parameters) || ($version == 'AICC')) {
+        if (stripos($sco->launch,'?') !== false) {
+            $connector = '&';
+        } else {
+            $connector = '?';
+        }
+        if (!empty($sco->parameters) && ($sco->parameters[0] == '?')) {
+            $sco->parameters = substr($sco->parameters,1);
+        }
+    }
+    
+    if ($version == 'AICC') {
+        if (!empty($sco->parameters)) {
+            $sco->parameters = '&'. $sco->parameters;
+        }
+        $launcher = $sco->launch.$connector.'aicc_sid='.sesskey().'&aicc_url='.$CFG->wwwroot.'/mod/scorm/type/aicc/aicc.php'.$sco->parameters;
+    } else {
+        $launcher = $sco->launch.$connector.$sco->parameters;
+    }
+    
+    if (scorm_external_link($sco->launch)) {
+        $result = $launcher;
+    } else if ($scorm->reference[0] == '#') {
+        require_once($repositoryconfigfile);
+        $result = $CFG->repositorywebroot.substr($scorm->reference,1).'/'.$sco->launch;
+    } else {
+        if (basename($scorm->reference) == 'imsmanifest.xml') {
+            $basedir = dirname($scorm->reference);
+        } else {
+            $basedir = 'moddata/scorm/'.$scorm->id;
+        }
+        if ($CFG->slasharguments) {
+            $result = $CFG->wwwroot.'/file.php/'.$scorm->course.'/'.$basedir.'/'.$launcher;
+        } else {
+            $result = $CFG->wwwroot.'/file.php?file=/'.$scorm->course.'/'.$basedir.'/'.$launcher;
+        }
+    }
+?>
+<html>
+    <head>
+        <title>LoadSCO</title>
+        <script language="javascript" type="text/javascript">
+        <!--
+            setTimeout('document.location = "<?php echo $result ?>";',2000);
+        -->
+        </script>
+        <noscript>
+            <meta http-equiv="refresh" content="2;url=<?php echo $result ?>" />
+        </noscript> 
+    </head>
+    <body>
+        &nbsp;
+    </body>
+</html>
index 66a8de0f6751f1c1301755b4489f794aff2dce1e..88a86db7953fc517155f2cea6c5fb30c29b4f3cb 100755 (executable)
-<?php\r
-    require_once($CFG->dirroot.'/mod/scorm/configurations.php');\r
-    if (!isset($form->name)) {\r
-        $form->name = '';\r
-    }\r
-    if (!isset($form->reference)) {\r
-        $form->reference = '';\r
-    }\r
-    if (!isset($form->summary)) {\r
-        $form->summary = '';\r
-    }\r
-    if (!isset($form->launch)) {\r
-        $form->launch = '';\r
-    }\r
-    if (!isset($form->auto)) {\r
-        $form->auto = '';\r
-    }\r
-    if (!isset($form->popup)) {\r
-        $form->popup = 0;\r
-    }\r
-    if (!isset($form->datadir)) {\r
-        $form->datadir = '';\r
-    }\r
-    if (!isset($form->maxgrade)) {\r
-        $form->maxgrade = '';\r
-    }\r
-    if (!isset($form->grademethod)) {\r
-        $form->grademethod = 0;\r
-    }\r
-    if (!isset($form->maxattempt)) {\r
-        $form->maxattempt = 1;\r
-    }\r
-    if (!isset($form->whatgrade)) {\r
-        $form->whatgrade = 0;\r
-    }\r
-    if (!isset($form->hidebrowse)) {\r
-        $form->hidebrowse = 0;\r
-    }\r
-    if (!isset($form->hidetoc)) {\r
-        $form->hidetoc = 0;\r
-    }\r
-    if (!isset($form->hidenav)) {\r
-        $form->hidenav = 0;\r
-    }\r
-    if (!isset($form->width)) {\r
-        $form->width = $CFG->scorm_framewidth;\r
-    }\r
-    if ((strpos($form->width,'%') === false) && ($form->width <= 100)) {\r
-        $form->width .= '%';\r
-    }\r
-    if (!isset($form->height)) {\r
-        $form->height = $CFG->scorm_frameheight;\r
-    }\r
-    if ((strpos($form->height,'%') === false) && ($form->height <= 100)) {\r
-        $form->height .= '%';\r
-    }\r
-    if (!isset($form->options) || empty($form->options)) {\r
-        $form->options = $stdoptions;\r
-    }\r
-    $options = explode(',',$form->options);\r
-    $window = new stdClass();\r
-    foreach ($options as $option) {\r
-        list($element,$value) = explode('=',$option);\r
-        $element = trim($element);\r
-        $window->$element = trim($value)==1?'checked':''; \r
-    }\r
-    if (!isset($form->pkgtype)) {\r
-        $form->pkgtype = '';\r
-    }\r
-    $scormid = '';\r
-    if (!empty($form->instance)) {\r
-        $scormid = '&instance='.$form->instance;\r
-    }\r
-    $datadir = '';\r
-    if (!empty($form->datadir)) {\r
-        $datadir = '&datadir='.$form->datadir;\r
-    }\r
-    $sessionkey = '';\r
-    if (!empty($form->sesskey)) {\r
-        $sessionkey = '&sesskey='.$form->sesskey;\r
-    }\r
-\r
-    $strfilename = get_string('coursepacket', 'scorm');\r
-    $strchooseafile = get_string('chooseapacket', 'scorm');\r
-    $strbrowserepository = get_string('browserepository', 'scorm');\r
-    $striframe = get_string('iframe', 'scorm');\r
-    $striframedisplay = get_string('iframedisplay', 'scorm');\r
-    $strnewwindow = get_string('popup', 'scorm');\r
-    $strnewwindowopen = get_string('popupopen', 'scorm');\r
-    $strheight = get_string('height', 'scorm');\r
-    $strwidth = get_string('width', 'scorm');\r
-    $strresizable = get_string('resizable', 'scorm');\r
-    $strscrollbars = get_string('scrollbars', 'scorm');\r
-    $strdirectories = get_string('directories', 'scorm');\r
-    $strlocation = get_string('location', 'scorm');\r
-    $strmenubar = get_string('menubar', 'scorm');\r
-    $strtoolbar = get_string('toolbar', 'scorm');\r
-    $strstatus = get_string('statusbar', 'scorm');\r
-?>\r
-\r
-<script type="text/javascript" src="<?php p($CFG->wwwroot) ?>/mod/scorm/request.js" ></script>\r
-<script type="text/javascript">\r
-    function validate_scorm(theform,filename,confirmed) {\r
-        var confirmedstr = '';\r
-        if (confirmed == true) {\r
-           confirmedstr = '&confirmed=true';\r
-        }\r
-\r
-        var myRequest = NewHttpReq();\r
-        result = DoRequest(myRequest,"<?php p($CFG->wwwroot) ?>/mod/scorm/validate.php","id=<?php p($form->course) ?>&reference="+filename+"<?php echo $sessionkey.$scormid.$datadir ?>");\r
-        //alert(result);\r
-        results = result.split('\n');\r
-        result = '';\r
-        errorlogs = '';\r
-        datadir = '';\r
-        for (i=0;i<results.length;i++) {\r
-            element = results[i].split('=');\r
-            switch(element[0]) {\r
-               case 'result':\r
-                  result = element[1];\r
-               break;\r
-               case 'launch':\r
-                  launch = element[1];\r
-               break;\r
-               case 'datadir':\r
-                  datadir = element[1];\r
-               break;\r
-               case 'pkgtype':\r
-                  pkgtype = element[1];\r
-               break;\r
-               case 'errorlogs':\r
-                   i++;\r
-                   do {\r
-                      errorlogs.concat(results[i]+'\n');\r
-                      i++;\r
-                   } while (i<results.lenght());\r
-\r
-               break;\r
-            }\r
-        }\r
-        if ((result == "found") || (result == "regular")) {\r
-            theform.datadir.value = datadir;\r
-            theform.pkgtype.value = pkgtype;\r
-            theform.launch.value = launch;\r
-            if (theform.mode.value == 'add') {\r
-                theform.parse.value = 1;\r
-            } else if (launch == 0) {\r
-                theform.parse.value = 1;\r
-            }\r
-            return true;\r
-        } else {\r
-            if (result == "confirm") {\r
-                response = confirm("<?php print_string('confirmloosetracks','scorm') ?>");\r
-                if (response == true) {\r
-                    return validate_scorm(theform,filename,true);\r
-                } else {\r
-                    return false;\r
-                }\r
-            } else {\r
-                result = '<?php print_string('validation','scorm') ?>: '+ result + '\n';\r
-                if (errorlogs != '') {\r
-                    result.concat('<?php print_string('errorlogs','scorm') ?>:\n'+errorlogs);\r
-                }\r
-                alert(result);\r
-                return false;\r
-            }\r
-        }\r
-    }\r
-\r
-    function checkscormform (whatcheck,checkvalue,whatset) {\r
-        if (whatcheck.options[whatcheck.selectedIndex].value == checkvalue) {\r
-            whatset.disabled = true;\r
-        } else {\r
-            whatset.disabled = false;\r
-        }\r
-    }\r
-    \r
-    function showhide (id, set) {\r
-        divobj = document.getElementById(id);\r
-        butobj = document.getElementById(id+'button');\r
-        prefobj = document.getElementById(id+'pref');\r
-        if (set == true) {\r
-            if (prefobj.value == '1') {\r
-                divobj.style.display = 'block';\r
-                butobj.value = '<?php print_string('hidesettings') ?>';\r
-            } else {\r
-                divobj.style.display = 'none';\r
-                butobj.value = '<?php print_string('showsettings') ?>...';\r
-            }\r
-        } else {\r
-            if (prefobj.value == '1') {\r
-                divobj.style.display = 'none';\r
-                butobj.value = '<?php print_string('showsettings') ?>...';\r
-                prefobj.value = '0';\r
-            } else {\r
-                divobj.style.display = 'block';\r
-                butobj.value = '<?php print_string('hidesettings') ?>';\r
-                prefobj.value = '1';\r
-            }\r
-        }\r
-    }\r
-</script>\r
-\r
-<form name="form" method="post" action="mod.php?goto=" onsubmit="return validate_scorm(document.form,document.form.reference.value,false,false);">\r
-    <table cellpadding="5">\r
-        <tr valign="top">\r
-            <td align="right"><b><?php print_string('name') ?>:</b></td>\r
-            <td>\r
-                <input type="text" name="name" size="50" value="<?php p($form->name) ?>" alt="<?php print_string('name') ?>" />\r
-            </td>\r
-        </tr>\r
-        <tr valign="top">\r
-            <td align="right"><b><?php print_string('summary') ?>:</b><br />\r
-                <?php helpbutton('summary', get_string('summary'), 'scorm', true, true) ?>\r
-            </td>\r
-            <td>\r
-                <?php print_textarea($usehtmleditor, 10, 50, 680, 400, 'summary', $form->summary); ?>\r
-            </td>\r
-        </tr>\r
-        <tr valign="top">\r
-            <td align="right" nowrap="nowrap">\r
-                <b><?php echo $strfilename?>:</b>\r
-            </td>\r
-            <td>\r
-                <input name="reference" size="50" value="<?php echo $form->reference ?>" alt="<?php echo $strfilename ?>" />&nbsp;\r
-                <?php\r
-                    button_to_popup_window ('/files/index.php?id='.$course->id.'&amp;choose=form.reference',\r
-                                            'coursefiles', $strchooseafile, 500, 750, $strchooseafile);\r
-                    require_once($repositoryconfigfile);\r
-                    if ($CFG->repositoryactivate) {\r
-                        button_to_popup_window ($repositorybrowser.'?choose=form.reference',\r
-                                                'browserepository', $strbrowserepository, 500, 750, $strbrowserepository);\r
-                    }\r
-                    helpbutton('package', get_string('coursepacket', 'scorm'), 'scorm', true);\r
-                ?>\r
-            </td>\r
-        </tr>\r
-        <tr valign="top">\r
-            <td align="right"><b><?php print_string('grademethod', 'scorm') ?>:</b></td>\r
-            <td>\r
-            <?php\r
-                choose_from_menu($SCORM_GRADE_METHOD, 'grademethod', (int) $form->grademethod, '','checkscormform(this,0,document.form.maxgrade);');\r
-                helpbutton('grademethod', get_string('grademethod','scorm'), 'scorm');\r
-            ?>\r
-            </td>\r
-        </tr>\r
-        <tr valign="top">\r
-            <td align="right"><b><?php print_string('maximumgrade') ?>:</b></td>\r
-            <td>\r
-            <?php\r
-                for ($i=100; $i>=1; $i--) {\r
-                    $grades[$i] = $i;\r
-                }\r
-                $disabled = $form->grademethod=='0';\r
-                choose_from_menu($grades, 'maxgrade', (int) $form->maxgrade, '','','0',false,$disabled);\r
-                helpbutton('maxgrade', get_string('maximumgrade'), 'scorm');\r
-            ?>\r
-            </td>\r
-        </tr>\r
-        <tr valign="top">\r
-            <td align="right"><b><?php print_string('maximumattempts','scorm') ?>:</b></td>\r
-            <td>\r
-            <?php\r
-                for ($i=1; $i<=$CFG->scorm_maxattempts; $i++) {\r
-                    if ($i == 1) {\r
-                        $attempts[$i] = $i . ' ' . get_string('attempt','scorm');\r
-                    } else {\r
-                        $attempts[$i] = $i . ' ' . get_string('attempts','scorm');\r
-                    }\r
-                }\r
-                choose_from_menu($attempts, 'maxattempt', (int) $form->maxattempt, get_string('nolimit','scorm'),'checkscormform(this,1,document.form.whatgrade);');\r
-                helpbutton('maxattempt', get_string('maximumattempts','scorm'), 'scorm');\r
-            ?>\r
-            </td>\r
-        </tr>\r
-        <tr valign="top">\r
-            <td align="right"><b><?php print_string('whatgrade','scorm') ?>:</b></td>\r
-            <td>\r
-            <?php\r
-                $disabled = (int) $form->maxattempt === 1;\r
-                choose_from_menu($SCORM_WHAT_GRADE, 'whatgrade', (int) $form->whatgrade, '','','0',false,$disabled);\r
-                helpbutton('whatgrade', get_string('whatgrade','scorm'), 'scorm');\r
-            ?>\r
-            </td>\r
-        </tr>\r
-        <tr><td colspan="2"><hr /></td></tr>\r
-\r
-        <tr>\r
-            <td align="right"><b><?php print_string('advanced', 'scorm') ?>:</b></td>\r
-            <td>\r
-                <input type="button" value="<?php print_string('hidesettings') ?>" id="advancedsettingsbutton" onclick="javascript: return showhide('advancedsettings');" />\r
-                <input type="hidden" name="advancedsettingspref" id="advancedsettingspref" \r
-                       value="<?php echo get_user_preferences('scorm_advancedsettingspref', $CFG->scorm_advancedsettings); ?>" />\r
-                <?php helpbutton('advanced', get_string('advanced', 'scorm'), 'scorm', true) ?>\r
-            </td>\r
-        </tr>\r
-        <tr>\r
-            <td colspan="2">\r
-                <div id="advancedsettings">\r
-                    <table align="center">\r
-                        <tr>\r
-                            <td align="right"><b><?php print_string('autocontinue','scorm') ?>:</b></td>\r
-                            <td>\r
-                            <?php\r
-                                $options = array();\r
-                                $options[0]=get_string('no');\r
-                                $options[1]=get_string('yes');\r
-                                choose_from_menu ($options, 'auto', (int) $form->auto,'');\r
-                                helpbutton('autocontinue', get_string('autocontinue','scorm'), 'scorm', true);\r
-                            ?>\r
-                            </td>\r
-                        </tr>\r
-                        <tr>\r
-                            <td align="right"><b><?php print_string('hidebrowse','scorm') ?>:</b></td>\r
-                            <td>\r
-                            <?php\r
-                                $options = array();\r
-                                $options[0]=get_string('no');\r
-                                $options[1]=get_string('yes');\r
-                                choose_from_menu ($options, 'hidebrowse', (int) $form->hidebrowse, '');\r
-                                helpbutton('browsemode', get_string('hidebrowse','scorm'), 'scorm', true);\r
-                            ?>\r
-                            </td>\r
-                        </tr>\r
-                        <tr>\r
-                            <td align="right"><b><?php print_string('hidetoc','scorm') ?>:</b></td>\r
-                            <td>\r
-                            <?php\r
-                                $options = array();\r
-                                $options[1]=get_string('hidden','scorm');\r
-                                $options[0]=get_string('sided','scorm');\r
-                                $options[2]=get_string('popupmenu','scorm');\r
-                                choose_from_menu ($options, 'hidetoc', (int) $form->hidetoc, '');\r
-                            ?>\r
-                            </td>\r
-                        </tr>\r
-                        <tr>\r
-                            <td align="right"><b><?php print_string('hidenav','scorm') ?>:</b></td>\r
-                            <td>\r
-                            <?php\r
-                                $options = array();\r
-                                $options[0]=get_string('no');\r
-                                $options[1]=get_string('yes');\r
-                                choose_from_menu ($options, 'hidenav', (int) $form->hidenav, '');\r
-                            ?>\r
-                            </td>\r
-                        </tr>\r
-                    </table>\r
-                </div>\r
-            </td>\r
-        </tr>\r
-        <tr>\r
-            <td align="right"><b><?php print_string('window', 'scorm') ?>:</b></td>\r
-            <td>\r
-                <input type="button" value="<?php print_string('hidesettings') ?>" id="windowsettingsbutton" onclick="javascript: return showhide('windowsettings');" />\r
-                <input type="hidden" name="windowsettingspref" id="windowsettingspref" \r
-                       value="<?php echo get_user_preferences('scorm_windowsettingspref', $CFG->scorm_windowsettings); ?>" />\r
-                <?php helpbutton('window', get_string('window', 'scorm'), 'scorm', true) ?>\r
-            </td>\r
-        </tr>\r
-        <tr>\r
-            <td colspan="2">\r
-                <div id="windowsettings">\r
-                    <table align="center">\r
-                        <tr valign="top">\r
-                            <td>\r
-                                <b><?php print_string('stagesize','scorm'); ?></b>\r
-                                <?php helpbutton('size', get_string('stagesize', 'scorm'), 'scorm', true) ?><br />\r
-                                <input name="width" type="text" size="4" value="<?php p($form->width) ?>" alt="<?php p($strwidth) ?>" />\r
-                                <label for="width"><?php p($strwidth) ?></label><br />\r
-                                <input name="height" type="text" size="4" value="<?php p($form->height) ?>" alt="<?php p($strheight) ?>" />\r
-                                <label for="height"><?php p($strheight) ?></label>\r
-                            </td>\r
-                        </tr>\r
-                        <tr valign="top">\r
-                            <td>\r
-                                <script type="text/javascript">\r
-                                    var popupitems = ["<?php echo implode('","',array_keys($SCORM_POPUP_OPTIONS)); ?>"];\r
-                                </script>\r
-                                <br /><b><?php print_string('display','scorm'); ?>:</b><br />\r
-                                <input type="radio" \r
-                                       name="popup"\r
-                                       value="0" alt="<?php p($striframe) ?>" \r
-                                       <?php echo ($form->popup == 0) ? "checked=\"checked\"" : "" ?> \r
-                                       onclick="return lockoptions('form', 'popup[1]', popupitems);"\r
-                                />\r
-                                <b title="<?php p($striframedisplay) ?>"><?php p($striframe) ?></b>\r
-                            </td>\r
-                        </tr>\r
-                        <tr valign="top">\r
-                            <td>\r
-                                <input name="popup" \r
-                                       type="radio" \r
-                                       value="1" \r
-                                       alt="<?php p($strnewwindow)?>" \r
-                                       <?php echo ($form->popup == 1) ? 'checked="checked"' : '' ?>\r
-                                       onclick="return lockoptions('form', 'popup[1]', popupitems);"\r
-                                />\r
-                                <b title="<?php p($strnewwindowopen) ?>"><?php p($strnewwindow) ?></b>\r
-                                <blockquote>\r
-                                    <?php\r
-                                        foreach ($window as $name => $value) {\r
-                                            echo "<input name=\"h$name\" type=\"hidden\" value=\"0\"/>\n";\r
-                                            echo "<input name=\"$name\" type=\"checkbox\" value=\"1\" ".$window->$name." alt=\"$name\" />\n";\r
-                                            $stringname = "str$name";\r
-                                            echo $$stringname."<br />\n";\r
-                                        }\r
-                                    ?>\r
-                                    <script type="text/javascript">\r
-                                        lockoptions('form','popup[1]', popupitems);\r
-                                    </script>\r
-                                </blockquote>\r
-                            </td>\r
-                        </tr>\r
-                    </table>\r
-                </div>\r
-                <script language="javascript" type="text/javascript">\r
-                    showhide('advancedsettings', true);\r
-                    showhide('windowsettings', true);\r
-                </script>\r
-            </td>\r
-        </tr>\r
-    </table>\r
-    <input type="hidden" name="datadir" value="<?php p($form->datadir) ?>" />\r
-    <input type="hidden" name="pkgtype" value="<?php p($form->pkgtype) ?>" />\r
-    <input type="hidden" name="launch"  value="<?php p($form->launch) ?>" />\r
-    <input type="hidden" name="parse"  value="0" />\r
-    <?php\r
-        $scorms = get_all_instances_in_course('scorm', $course);\r
-        $coursescorm = current($scorms);\r
-        if (($course->format == 'scorm') && ((count($scorms) == 0) || ($form->instance == $coursescorm->id))) {\r
-    ?>\r
-    <input type="hidden" name="redirect"       value="yes" />\r
-    <input type="hidden" name="redirecturl"    value="../course/view.php?id=<?php p($form->course) ?>" />    \r
-    <?php\r
-        } \r
-    ?>\r
-    <input type="hidden" name="course"  value="<?php p($form->course) ?>" />\r
-    <input type="hidden" name="sesskey" value="<?php p($form->sesskey) ?>" />\r
-    <input type="hidden" name="section" value="<?php p($form->section) ?>" />\r
-    <input type="hidden" name="module"  value="<?php p($form->module) ?>" />\r
-    <input type="hidden" name="mode"    value="<?php p($form->mode) ?>" />\r
-    <input type="hidden" name="coursemodule"    value="<?php p($form->coursemodule) ?>" />\r
-    <input type="hidden" name="modulename"      value="<?php p($form->modulename) ?>" />\r
-    <input type="hidden" name="instance"        value="<?php p($form->instance) ?>" />\r
-    <center>\r
-        <input type="submit" value="<?php print_string('savechanges') ?>"/>\r
-        <input type="button" name="cancel" value="<?php print_string('cancel') ?>" onclick="document.location='view.php?id=<?php echo $form->course ?>'" />\r
-    </center>\r
-</form>\r
+<?php
+    require_once($CFG->dirroot.'/mod/scorm/configurations.php');
+    if (!isset($form->name)) {
+        $form->name = '';
+    }
+    if (!isset($form->reference)) {
+        $form->reference = '';
+    }
+    if (!isset($form->summary)) {
+        $form->summary = '';
+    }
+    if (!isset($form->launch)) {
+        $form->launch = '';
+    }
+    if (!isset($form->auto)) {
+        $form->auto = '';
+    }
+    if (!isset($form->popup)) {
+        $form->popup = 0;
+    }
+    if (!isset($form->datadir)) {
+        $form->datadir = '';
+    }
+    if (!isset($form->maxgrade)) {
+        $form->maxgrade = '';
+    }
+    if (!isset($form->grademethod)) {
+        $form->grademethod = 0;
+    }
+    if (!isset($form->maxattempt)) {
+        $form->maxattempt = 1;
+    }
+    if (!isset($form->whatgrade)) {
+        $form->whatgrade = 0;
+    }
+    if (!isset($form->hidebrowse)) {
+        $form->hidebrowse = 0;
+    }
+    if (!isset($form->hidetoc)) {
+        $form->hidetoc = 0;
+    }
+    if (!isset($form->hidenav)) {
+        $form->hidenav = 0;
+    }
+    if (!isset($form->width)) {
+        $form->width = $CFG->scorm_framewidth;
+    }
+    if ((strpos($form->width,'%') === false) && ($form->width <= 100)) {
+        $form->width .= '%';
+    }
+    if (!isset($form->height)) {
+        $form->height = $CFG->scorm_frameheight;
+    }
+    if ((strpos($form->height,'%') === false) && ($form->height <= 100)) {
+        $form->height .= '%';
+    }
+    if (!isset($form->options) || empty($form->options)) {
+        $form->options = $stdoptions;
+    }
+    $options = explode(',',$form->options);
+    $window = new stdClass();
+    foreach ($options as $option) {
+        list($element,$value) = explode('=',$option);
+        $element = trim($element);
+        $window->$element = trim($value)==1?'checked':''; 
+    }
+    if (!isset($form->pkgtype)) {
+        $form->pkgtype = '';
+    }
+    $scormid = '';
+    if (!empty($form->instance)) {
+        $scormid = '&instance='.$form->instance;
+    }
+    $datadir = '';
+    if (!empty($form->datadir)) {
+        $datadir = '&datadir='.$form->datadir;
+    }
+    $sessionkey = '';
+    if (!empty($form->sesskey)) {
+        $sessionkey = '&sesskey='.$form->sesskey;
+    }
+
+    $strfilename = get_string('coursepacket', 'scorm');
+    $strchooseafile = get_string('chooseapacket', 'scorm');
+    $strbrowserepository = get_string('browserepository', 'scorm');
+    $striframe = get_string('iframe', 'scorm');
+    $striframedisplay = get_string('iframedisplay', 'scorm');
+    $strnewwindow = get_string('popup', 'scorm');
+    $strnewwindowopen = get_string('popupopen', 'scorm');
+    $strheight = get_string('height', 'scorm');
+    $strwidth = get_string('width', 'scorm');
+    $strresizable = get_string('resizable', 'scorm');
+    $strscrollbars = get_string('scrollbars', 'scorm');
+    $strdirectories = get_string('directories', 'scorm');
+    $strlocation = get_string('location', 'scorm');
+    $strmenubar = get_string('menubar', 'scorm');
+    $strtoolbar = get_string('toolbar', 'scorm');
+    $strstatus = get_string('statusbar', 'scorm');
+?>
+
+<script type="text/javascript" src="<?php p($CFG->wwwroot) ?>/mod/scorm/request.js" ></script>
+<script type="text/javascript">
+    function validate_scorm(theform,filename,confirmed) {
+        var confirmedstr = '';
+        if (confirmed == true) {
+           confirmedstr = '&confirmed=true';
+        }
+
+        var myRequest = NewHttpReq();
+        result = DoRequest(myRequest,"<?php p($CFG->wwwroot) ?>/mod/scorm/validate.php","id=<?php p($form->course) ?>&reference="+filename+"<?php echo $sessionkey.$scormid.$datadir ?>");
+        //alert(result);
+        results = result.split('\n');
+        result = '';
+        errorlogs = '';
+        datadir = '';
+        for (i=0;i<results.length;i++) {
+            element = results[i].split('=');
+            switch(element[0]) {
+               case 'result':
+                  result = element[1];
+               break;
+               case 'launch':
+                  launch = element[1];
+               break;
+               case 'datadir':
+                  datadir = element[1];
+               break;
+               case 'pkgtype':
+                  pkgtype = element[1];
+               break;
+               case 'errorlogs':
+                   i++;
+                   do {
+                      errorlogs.concat(results[i]+'\n');
+                      i++;
+                   } while (i<results.lenght());
+
+               break;
+            }
+        }
+        if ((result == "found") || (result == "regular")) {
+            theform.datadir.value = datadir;
+            theform.pkgtype.value = pkgtype;
+            theform.launch.value = launch;
+            if (theform.mode.value == 'add') {
+                theform.parse.value = 1;
+            } else if (launch == 0) {
+                theform.parse.value = 1;
+            }
+            return true;
+        } else {
+            if (result == "confirm") {
+                response = confirm("<?php print_string('confirmloosetracks','scorm') ?>");
+                if (response == true) {
+                    return validate_scorm(theform,filename,true);
+                } else {
+                    return false;
+                }
+            } else {
+                result = '<?php print_string('validation','scorm') ?>: '+ result + '\n';
+                if (errorlogs != '') {
+                    result.concat('<?php print_string('errorlogs','scorm') ?>:\n'+errorlogs);
+                }
+                alert(result);
+                return false;
+            }
+        }
+    }
+
+    function checkscormform (whatcheck,checkvalue,whatset) {
+        if (whatcheck.options[whatcheck.selectedIndex].value == checkvalue) {
+            whatset.disabled = true;
+        } else {
+            whatset.disabled = false;
+        }
+    }
+    
+    function showhide (id, set) {
+        divobj = document.getElementById(id);
+        butobj = document.getElementById(id+'button');
+        prefobj = document.getElementById(id+'pref');
+        if (set == true) {
+            if (prefobj.value == '1') {
+                divobj.style.display = 'block';
+                butobj.value = '<?php print_string('hidesettings') ?>';
+            } else {
+                divobj.style.display = 'none';
+                butobj.value = '<?php print_string('showsettings') ?>...';
+            }
+        } else {
+            if (prefobj.value == '1') {
+                divobj.style.display = 'none';
+                butobj.value = '<?php print_string('showsettings') ?>...';
+                prefobj.value = '0';
+            } else {
+                divobj.style.display = 'block';
+                butobj.value = '<?php print_string('hidesettings') ?>';
+                prefobj.value = '1';
+            }
+        }
+    }
+</script>
+
+<form name="form" method="post" action="mod.php?goto=" onsubmit="return validate_scorm(document.form,document.form.reference.value,false,false);">
+    <table cellpadding="5">
+        <tr valign="top">
+            <td align="right"><b><?php print_string('name') ?>:</b></td>
+            <td>
+                <input type="text" name="name" size="50" value="<?php p($form->name) ?>" alt="<?php print_string('name') ?>" />
+            </td>
+        </tr>
+        <tr valign="top">
+            <td align="right"><b><?php print_string('summary') ?>:</b><br />
+                <?php helpbutton('summary', get_string('summary'), 'scorm', true, true) ?>
+            </td>
+            <td>
+                <?php print_textarea($usehtmleditor, 10, 50, 680, 400, 'summary', $form->summary); ?>
+            </td>
+        </tr>
+        <tr valign="top">
+            <td align="right" nowrap="nowrap">
+                <b><?php echo $strfilename?>:</b>
+            </td>
+            <td>
+                <input name="reference" size="50" value="<?php echo $form->reference ?>" alt="<?php echo $strfilename ?>" />&nbsp;
+                <?php
+                    button_to_popup_window ('/files/index.php?id='.$course->id.'&amp;choose=form.reference',
+                                            'coursefiles', $strchooseafile, 500, 750, $strchooseafile);
+                    require_once($repositoryconfigfile);
+                    if ($CFG->repositoryactivate) {
+                        button_to_popup_window ($repositorybrowser.'?choose=form.reference',
+                                                'browserepository', $strbrowserepository, 500, 750, $strbrowserepository);
+                    }
+                    helpbutton('package', get_string('coursepacket', 'scorm'), 'scorm', true);
+                ?>
+            </td>
+        </tr>
+        <tr valign="top">
+            <td align="right"><b><?php print_string('grademethod', 'scorm') ?>:</b></td>
+            <td>
+            <?php
+                choose_from_menu($SCORM_GRADE_METHOD, 'grademethod', (int) $form->grademethod, '','checkscormform(this,0,document.form.maxgrade);');
+                helpbutton('grademethod', get_string('grademethod','scorm'), 'scorm');
+            ?>
+            </td>
+        </tr>
+        <tr valign="top">
+            <td align="right"><b><?php print_string('maximumgrade') ?>:</b></td>
+            <td>
+            <?php
+                for ($i=100; $i>=1; $i--) {
+                    $grades[$i] = $i;
+                }
+                $disabled = $form->grademethod=='0';
+                choose_from_menu($grades, 'maxgrade', (int) $form->maxgrade, '','','0',false,$disabled);
+                helpbutton('maxgrade', get_string('maximumgrade'), 'scorm');
+            ?>
+            </td>
+        </tr>
+        <tr valign="top">
+            <td align="right"><b><?php print_string('maximumattempts','scorm') ?>:</b></td>
+            <td>
+            <?php
+                for ($i=1; $i<=$CFG->scorm_maxattempts; $i++) {
+                    if ($i == 1) {
+                        $attempts[$i] = $i . ' ' . get_string('attempt','scorm');
+                    } else {
+                        $attempts[$i] = $i . ' ' . get_string('attempts','scorm');
+                    }
+                }
+                choose_from_menu($attempts, 'maxattempt', (int) $form->maxattempt, get_string('nolimit','scorm'),'checkscormform(this,1,document.form.whatgrade);');
+                helpbutton('maxattempt', get_string('maximumattempts','scorm'), 'scorm');
+            ?>
+            </td>
+        </tr>
+        <tr valign="top">
+            <td align="right"><b><?php print_string('whatgrade','scorm') ?>:</b></td>
+            <td>
+            <?php
+                $disabled = (int) $form->maxattempt === 1;
+                choose_from_menu($SCORM_WHAT_GRADE, 'whatgrade', (int) $form->whatgrade, '','','0',false,$disabled);
+                helpbutton('whatgrade', get_string('whatgrade','scorm'), 'scorm');
+            ?>
+            </td>
+        </tr>
+        <tr><td colspan="2"><hr /></td></tr>
+
+        <tr>
+            <td align="right"><b><?php print_string('advanced', 'scorm') ?>:</b></td>
+            <td>
+                <input type="button" value="<?php print_string('hidesettings') ?>" id="advancedsettingsbutton" onclick="javascript: return showhide('advancedsettings');" />
+                <input type="hidden" name="advancedsettingspref" id="advancedsettingspref" 
+                       value="<?php echo get_user_preferences('scorm_advancedsettingspref', $CFG->scorm_advancedsettings); ?>" />
+                <?php helpbutton('advanced', get_string('advanced', 'scorm'), 'scorm', true) ?>
+            </td>
+        </tr>
+        <tr>
+            <td colspan="2">
+                <div id="advancedsettings">
+                    <table align="center">
+                        <tr>
+                            <td align="right"><b><?php print_string('autocontinue','scorm') ?>:</b></td>
+                            <td>
+                            <?php
+                                $options = array();
+                                $options[0]=get_string('no');
+                                $options[1]=get_string('yes');
+                                choose_from_menu ($options, 'auto', (int) $form->auto,'');
+                                helpbutton('autocontinue', get_string('autocontinue','scorm'), 'scorm', true);
+                            ?>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td align="right"><b><?php print_string('hidebrowse','scorm') ?>:</b></td>
+                            <td>
+                            <?php
+                                $options = array();
+                                $options[0]=get_string('no');
+                                $options[1]=get_string('yes');
+                                choose_from_menu ($options, 'hidebrowse', (int) $form->hidebrowse, '');
+                                helpbutton('browsemode', get_string('hidebrowse','scorm'), 'scorm', true);
+                            ?>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td align="right"><b><?php print_string('hidetoc','scorm') ?>:</b></td>
+                            <td>
+                            <?php
+                                $options = array();
+                                $options[1]=get_string('hidden','scorm');
+                                $options[0]=get_string('sided','scorm');
+                                $options[2]=get_string('popupmenu','scorm');
+                                choose_from_menu ($options, 'hidetoc', (int) $form->hidetoc, '');
+                            ?>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td align="right"><b><?php print_string('hidenav','scorm') ?>:</b></td>
+                            <td>
+                            <?php
+                                $options = array();
+                                $options[0]=get_string('no');
+                                $options[1]=get_string('yes');
+                                choose_from_menu ($options, 'hidenav', (int) $form->hidenav, '');
+                            ?>
+                            </td>
+                        </tr>
+                    </table>
+                </div>
+            </td>
+        </tr>
+        <tr>
+            <td align="right"><b><?php print_string('window', 'scorm') ?>:</b></td>
+            <td>
+                <input type="button" value="<?php print_string('hidesettings') ?>" id="windowsettingsbutton" onclick="javascript: return showhide('windowsettings');" />
+                <input type="hidden" name="windowsettingspref" id="windowsettingspref" 
+                       value="<?php echo get_user_preferences('scorm_windowsettingspref', $CFG->scorm_windowsettings); ?>" />
+                <?php helpbutton('window', get_string('window', 'scorm'), 'scorm', true) ?>
+            </td>
+        </tr>
+        <tr>
+            <td colspan="2">
+                <div id="windowsettings">
+                    <table align="center">
+                        <tr valign="top">
+                            <td>
+                                <b><?php print_string('stagesize','scorm'); ?></b>
+                                <?php helpbutton('size', get_string('stagesize', 'scorm'), 'scorm', true) ?><br />
+                                <input name="width" type="text" size="4" value="<?php p($form->width) ?>" alt="<?php p($strwidth) ?>" />
+                                <label for="width"><?php p($strwidth) ?></label><br />
+                                <input name="height" type="text" size="4" value="<?php p($form->height) ?>" alt="<?php p($strheight) ?>" />
+                                <label for="height"><?php p($strheight) ?></label>
+                            </td>
+                        </tr>
+                        <tr valign="top">
+                            <td>
+                                <script type="text/javascript">
+                                    var popupitems = ["<?php echo implode('","',array_keys($SCORM_POPUP_OPTIONS)); ?>"];
+                                </script>
+                                <br /><b><?php print_string('display','scorm'); ?>:</b><br />
+                                <input type="radio" 
+                                       name="popup"
+                                       value="0" alt="<?php p($striframe) ?>" 
+                                       <?php echo ($form->popup == 0) ? "checked=\"checked\"" : "" ?> 
+                                       onclick="return lockoptions('form', 'popup[1]', popupitems);"
+                                />
+                                <b title="<?php p($striframedisplay) ?>"><?php p($striframe) ?></b>
+                            </td>
+                        </tr>
+                        <tr valign="top">
+                            <td>
+                                <input name="popup" 
+                                       type="radio" 
+                                       value="1" 
+                                       alt="<?php p($strnewwindow)?>" 
+                                       <?php echo ($form->popup == 1) ? 'checked="checked"' : '' ?>
+                                       onclick="return lockoptions('form', 'popup[1]', popupitems);"
+                                />
+                                <b title="<?php p($strnewwindowopen) ?>"><?php p($strnewwindow) ?></b>
+                                <blockquote>
+                                    <?php
+                                        foreach ($window as $name => $value) {
+                                            echo "<input name=\"h$name\" type=\"hidden\" value=\"0\"/>\n";
+                                            echo "<input name=\"$name\" type=\"checkbox\" value=\"1\" ".$window->$name." alt=\"$name\" />\n";
+                                            $stringname = "str$name";
+                                            echo $$stringname."<br />\n";
+                                        }
+                                    ?>
+                                    <script type="text/javascript">
+                                        lockoptions('form','popup[1]', popupitems);
+                                    </script>
+                                </blockquote>
+                            </td>
+                        </tr>
+                    </table>
+                </div>
+                <script language="javascript" type="text/javascript">
+                    showhide('advancedsettings', true);
+                    showhide('windowsettings', true);
+                </script>
+            </td>
+        </tr>
+    </table>
+    <input type="hidden" name="datadir" value="<?php p($form->datadir) ?>" />
+    <input type="hidden" name="pkgtype" value="<?php p($form->pkgtype) ?>" />
+    <input type="hidden" name="launch"  value="<?php p($form->launch) ?>" />
+    <input type="hidden" name="parse"  value="0" />
+    <?php
+        $scorms = get_all_instances_in_course('scorm', $course);
+        $coursescorm = current($scorms);
+        if (($course->format == 'scorm') && ((count($scorms) == 0) || ($form->instance == $coursescorm->id))) {
+    ?>
+    <input type="hidden" name="redirect"       value="yes" />
+    <input type="hidden" name="redirecturl"    value="../course/view.php?id=<?php p($form->course) ?>" />    
+    <?php
+        } 
+    ?>
+    <input type="hidden" name="course"  value="<?php p($form->course) ?>" />
+    <input type="hidden" name="sesskey" value="<?php p($form->sesskey) ?>" />
+    <input type="hidden" name="section" value="<?php p($form->section) ?>" />
+    <input type="hidden" name="module"  value="<?php p($form->module) ?>" />
+    <input type="hidden" name="mode"    value="<?php p($form->mode) ?>" />
+    <input type="hidden" name="coursemodule"    value="<?php p($form->coursemodule) ?>" />
+    <input type="hidden" name="modulename"      value="<?php p($form->modulename) ?>" />
+    <input type="hidden" name="instance"        value="<?php p($form->instance) ?>" />
+    <center>
+        <input type="submit" value="<?php print_string('savechanges') ?>"/>
+        <input type="button" name="cancel" value="<?php print_string('cancel') ?>" onclick="document.location='view.php?id=<?php echo $form->course ?>'" />
+    </center>
+</form>
index ed08701583784b7e8292daeed66c0800803eb56f..3d88b4ad7dcac85355953e8674f5630a0c4cfe6b 100755 (executable)
-<?php \r
-\r
-// Cac ham danh cho viec thuc thi Sequencing\r
-// --------Ket thuc cac ham danh cho viec thuc thi Sequencing ------------\r
-\r
-// Cac ham danh cho viec thuc thi Rollup\r
-\r
-//-----------------------------------------------------\r
-function scorm_rollup_updatestatus($scormid,$scoidchild, $userid)\r
-{\r
-    //$f = "D:\\test.txt";\r
-    //@$ft = fopen($f,"a");\r
-    //fwrite($ft,"\n >>>>> SCO goi Rollup la ".$scoidchild);\r
-    $scochild = get_record("scorm_scoes","id",$scoidchild);\r
-    $scoparent = get_record("scorm_scoes","scorm",$scormid,"identifier",$scochild->parent);\r
-    //Danh sach cac con cua cha\r
-    $scochildren = get_records_select("scorm_scoes","scorm =".$scormid." and parent ='".$scoparent->identifier."'");\r
-    //Lay gia tri last attempt\r
-    //fwrite($ft,"\n >>>>> Bat dau xu ly Rollup SCO cha ".$scoparent->id);\r
-    $attempt = scorm_get_last_attempt($scormid,$userid);\r
-    \r
-    if(!empty($scoparent)){\r
-        $scoid = $scoparent->id;\r
-        $rolluprules = get_record("scorm_sequencing_rolluprules","scormid",$scormid,"scoid",$scoid);\r
-        if (!empty($rolluprules)){\r
-            $idrolluprules = $rolluprules->id;\r
-            $rules = get_records_select('scorm_sequencing_rolluprule','scoid ='.$scoid.'  and rolluprulesid ='. $idrolluprules);\r
-    \r
-            foreach ($rules as $rule){\r
-                $ruleid = $rule->id;\r
-                $ruleConditions = get_record("scorm_sequencing_rollupruleconditions","scoid",$scoid,"rollupruleid",$ruleid);            \r
-                $idruleConditions = $ruleConditions->id;\r
-                $conditions = get_records_select('scorm_sequencing_rolluprulecondition','scoid ='.$scoid.'  and ruleconditionsid ='.$idruleConditions);    \r
-    \r
-                //Truong hop 1: childactivitySet = all\r
-                //                conditioncombination = any\r
-                if (($rule->childactivityset == 'all') && ($ruleConditions->conditioncombination=='any')){\r
-                    foreach($conditions as $condition){\r
-                        $conditionOK = false;   \r
-                        //Condition 1:    condition = attempted         operator = 'noOp'\r
-                        //                Thuc hien rollupaction \r
-                        if (($condition->condition == 'attempted') && ($condition->operator=='noOp')){\r
-                        $conditionOK = true; \r
-                            foreach ($scochildren as $sco){\r
-                                //fwrite($ft,"\n >>>>> Xu ly Rollup voi dieu kien attempt  \n");\r
-                                $usertrack = scorm_get_tracks($sco->id,$userid);\r
-                                if ($usertrack->attempt_status != 'attempted'){\r
-                                    //fwrite($ft,"\n >>>>> Co SCO con chua attempted  \n");\r
-                                    $conditionOK = false;\r
-                                }\r
-                            }\r
-                        }\r
-                        //Condition 2:    condition = attempted         operator = 'not'\r
-                        //                Thuc hien rollupaction \r
-                        if (($condition->condition == 'attempted') && ($condition->operator=='not')){\r
-                        $conditionOK = true; \r
-                            foreach ($scochildren as $sco){\r
-                                //fwrite($ft,"\n >>>>> Xu ly Rollup voi dieu kien not attempt  \n");\r
-                                $usertrack = scorm_get_tracks($sco->id,$userid);\r
-                                if ($usertrack->attempt_status != 'notattempted'){\r
-                                    $conditionOK = false;\r
-                                }\r
-                            }\r
-                        }                    \r
-                        //Condition 3:    condition = satisfied         operator = 'noOp'\r
-                        //                Thuc hien rollupaction \r
-                        if (($condition->condition == 'satisfied') && ($condition->operator=='noOp')){\r
-                        $conditionOK = true; \r
-                            foreach ($scochildren as $sco){\r
-                                $usertrack = scorm_get_tracks($sco->id,$userid);\r
-                                if ($usertrack->satisfied_status != 'satisfied'){\r
-                                    $conditionOK = false;\r
-                                }\r
-                            }\r
-                        }\r
-                        //Condition 4:    condition = satisfied         operator = 'not'\r
-                        //                Thuc hien rollupaction \r
-                        if (($condition->condition == 'satisfied') && ($condition->operator=='not')){\r
-                        $conditionOK = true; \r
-                            foreach ($scochildren as $sco){\r
-                                $usertrack = scorm_get_tracks($sco->id,$userid);\r
-                                if ($usertrack->satisfied_status != 'notSatisfied'){\r
-                                    $conditionOK = false;\r
-                                }\r
-                            }\r
-                        }                    \r
-                        //Condition 5:    condition = completed         operator = 'noOp'\r
-                        //                Thuc hien rollupaction \r
-                        if (($condition->condition == 'completed') && ($condition->operator=='noOp')){\r
-                        $conditionOK = true; \r
-                            foreach ($scochildren as $sco){\r
-                                $usertrack = scorm_get_tracks($sco->id,$userid);\r
-                                if ($usertrack->attempt_status != 'completed'){\r
-                                    $conditionOK = false;\r
-                                }\r
-                            }\r
-                        }    \r
-                        //Condition 6:    condition = completed         operator = 'not'\r
-                        //                Thuc hien rollupaction \r
-                        if (($condition->condition == 'completed') && ($condition->operator=='not')){\r
-                        $conditionOK = true; \r
-                            foreach ($scochildren as $sco){\r
-                                $usertrack = scorm_get_tracks($sco->id,$userid);\r
-                                if ($usertrack->attempt_status != 'notcompleted'){\r
-                                    $conditionOK = false;\r
-                                }\r
-                            }\r
-                        }                                    \r
-                        //Neu dieu kien van dung sau khi xem xet thi thuc hien action\r
-                        if ($conditionOK == true){\r
-                            if ($ruleConditions->rollupruleaction == 'completed')\r
-                            {\r
-                            scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.completion_status','completed');\r
-                            //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi completed cho SCO ".$scoid);\r
-                            }\r
-                            if ($ruleConditions->rollupruleaction == 'satisfied')\r
-                            {\r
-                            scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','passed');\r
-                            //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong  voi satisfied\n");\r
-                            }\r
-                            if ($ruleConditions->rollupruleaction == 'notSatisfied')\r
-                            {\r
-                            scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','failed');\r
-                            //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong  voi notSatisfied\n");\r
-                            }                                                        \r
-                            //echo "<script language='JavaScript'>";\r
-                            //echo "alert('Thuc hien rollup. Trang thai ".$scoparent->identifier." la hoan thanh voi userid".$userid."');";\r
-                            //echo "<script>";\r
-                            \r
-                        }\r
-                    }\r
-                }\r
-                //Ket thuc truong hop 1\r
-                //Truong hop 2: childactivitySet = any\r
-                //                conditioncombination = any\r
-                if (($rule->childactivityset == 'any') && ($ruleConditions->conditioncombination=='any')){\r
-                    $conditionOK = false;  \r
-                    foreach($conditions as $condition){\r
-                        //$conditionOK = false;   \r
-                        //Condition 1:    condition = attempted         operator = 'noOp'\r
-                        //                Thuc hien rollupaction \r
-                        if (($condition->condition == 'attempted') && ($condition->operator=='noOp')){\r
-                        $conditionOK = false; \r
-                            foreach ($scochildren as $sco){\r
-                                $usertrack = scorm_get_tracks($sco->id,$userid);\r
-                                if ($usertrack->attempt_status = 'attempted'){\r
-                                    $conditionOK = true;\r
-                                }\r
-                            }\r
-                        }\r
-                        //Condition 2:    condition = attempted         operator = 'not'\r
-                        //                Thuc hien rollupaction \r
-                        if (($condition->condition == 'attempted') && ($condition->operator=='not')){\r
-                        $conditionOK = false; \r
-                            foreach ($scochildren as $sco){\r
-                                $usertrack = scorm_get_tracks($sco->id,$userid);\r
-                                if ($usertrack->attempt_status = 'notattempted'){\r
-                                    $conditionOK = true;\r
-                                }\r
-                            }\r
-                        }                    \r
-                        //Condition 3:    condition = satisfied         operator = 'noOp'\r
-                        //                Thuc hien rollupaction \r
-                        if (($condition->condition == 'satisfied') && ($condition->operator=='noOp')){\r
-                        $conditionOK = false; \r
-                            foreach ($scochildren as $sco){\r
-                                $usertrack = scorm_get_tracks($sco->id,$userid);\r
-                                if ($usertrack->satisfied_status = 'satisfied'){\r
-                                    $conditionOK = true;\r
-                                }\r
-                            }\r
-                        }\r
-                        //Condition 4:    condition = satisfied         operator = 'not'\r
-                        //                Thuc hien rollupaction \r
-                        if (($condition->condition == 'satisfied') && ($condition->operator=='not')){\r
-                        $conditionOK = false; \r
-                            foreach ($scochildren as $sco){\r
-                                $usertrack = scorm_get_tracks($sco->id,$userid);\r
-                                if ($usertrack->satisfied_status = 'notSatisfied'){\r
-                                    //fwrite($ft,"\n >>>>> Xu ly Rollup voi notSatisfied\n");\r
-                                    $conditionOK = true;\r
-                                }\r
-                            }\r
-                        }                    \r
-                        //Condition 5:    condition = completed         operator = 'noOp'\r
-                        //                Thuc hien rollupaction \r
-                        if (($condition->condition == 'completed') && ($condition->operator=='noOp')){\r
-                        $conditionOK = false; \r
-                            foreach ($scochildren as $sco){\r
-                                $usertrack = scorm_get_tracks($sco->id,$userid);\r
-                                if ($usertrack->attempt_status = 'completed'){\r
-                                    $conditionOK = true;\r
-                                }\r
-                            }\r
-                        }    \r
-                        //Condition 6:    condition = completed         operator = 'not'\r
-                        //                Thuc hien rollupaction \r
-                        if (($condition->condition == 'completed') && ($condition->operator=='not')){\r
-                        $conditionOK = false; \r
-                            foreach ($scochildren as $sco){\r
-                                $usertrack = scorm_get_tracks($sco->id,$userid);\r
-                                if ($usertrack->attempt_status = 'notcompleted'){\r
-                                    $conditionOK = true;\r
-                                }\r
-                            }\r
-                        }                                    \r
-                        //Neu dieu kien van dung sau khi xem xet thi thuc hien action\r
-                        if ($conditionOK == true){\r
-                            if ($ruleConditions->rollupruleaction == 'completed')\r
-                            {\r
-                            scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.completion_status','completed');\r
-                            //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi completed\n");\r
-                            }\r
-                            if ($ruleConditions->rollupruleaction == 'satisfied')\r
-                            {\r
-                            scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','passed');\r
-                            //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong  voi satisfied\n");\r
-                            }\r
-                            if ($ruleConditions->rollupruleaction == 'notSatisfied')\r
-                            {\r
-                            scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','failed');\r
-                            //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong  voi notSatisfied\n");\r
-                            }                                                        \r
-                            //echo "<script language='JavaScript'>";\r
-                            //echo "alert('Thuc hien rollup. Trang thai ".$scoparent->identifier." la hoan thanh voi userid".$userid."');";\r
-                            //echo "<script>";\r
-                            \r
-                        }\r
-                    }\r
-                }\r
-                //Ket thuc truong hop 2\r
-                //Truong hop 3: childactivitySet = any\r
-                //                conditioncombination = all\r
-                if (($rule->childactivityset == 'any') && ($ruleConditions->conditioncombination=='all')){\r
-                    foreach ($scochildren as $sco){\r
-                    $usertrack = scorm_get_tracks($sco->id,$userid);\r
-                    $conditionOK = true;  \r
-                        foreach($conditions as $condition){\r
-                            //Condition 1:    condition = attempted         operator = 'noOp'\r
-                            //                Thuc hien rollupaction \r
-                            if (($condition->condition == 'attempted') && ($condition->operator=='noOp')){\r
-                                if ($usertrack->attempt_status != 'attempted'){\r
-                                    $conditionOK = false;\r
-                                }\r
-                            }\r
-                            //Condition 2:    condition = attempted         operator = 'not'\r
-                            //                Thuc hien rollupaction \r
-                            if (($condition->condition == 'attempted') && ($condition->operator=='not')){\r
-                                if ($usertrack->attempt_status != 'notattempted'){\r
-                                    $conditionOK = false;\r
-                                }\r
-                            }                    \r
-                            //Condition 3:    condition = satisfied         operator = 'noOp'\r
-                            //                Thuc hien rollupaction \r
-                            if (($condition->condition == 'satisfied') && ($condition->operator=='noOp')){\r
-                                if ($usertrack->attempt_status != 'satisfied'){\r
-                                    $conditionOK = false;\r
-                                }\r
-                            }\r
-                            //Condition 4:    condition = satisfied         operator = 'not'\r
-                            //                Thuc hien rollupaction \r
-                            if (($condition->condition == 'satisfied') && ($condition->operator=='not')){\r
-                                if ($usertrack->attempt_status != 'notSatisfied'){\r
-                                    $conditionOK = false;\r
-                                }\r
-                            }                    \r
-                            //Condition 5:    condition = completed         operator = 'noOp'\r
-                            //                Thuc hien rollupaction \r
-                            if (($condition->condition == 'completed') && ($condition->operator=='noOp')){\r
-                                if ($usertrack->attempt_status != 'completed'){\r
-                                    $conditionOK = false;\r
-                                }\r
-                            }    \r
-                            //Condition 6:    condition = completed         operator = 'not'\r
-                            //                Thuc hien rollupaction \r
-                            if (($condition->condition == 'completed') && ($condition->operator=='not')){\r
-                                if ($usertrack->attempt_status != 'notcompleted'){\r
-                                    $conditionOK = false;\r
-                                }\r
-                            }                                    \r
-                            //Neu dieu kien van dung sau khi xem xet thi thuc hien action\r
-                        }\r
-                    }\r
-                    if ($conditionOK == true){\r
-                        if ($ruleConditions->rollupruleaction == 'completed')\r
-                        {\r
-                        scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.completion_status','completed');\r
-                        //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi completed\n");\r
-                        }\r
-                        if ($ruleConditions->rollupruleaction == 'satisfied')\r
-                        {\r
-                        scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','passed');\r
-                        //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong  voi satisfied\n");\r
-                        }\r
-                        if ($ruleConditions->rollupruleaction == 'notSatisfied')\r
-                        {\r
-                        scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','failed');\r
-                        //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong  voi notSatisfied\n");\r
-                        }                                                        \r
-                        //echo "<script language='JavaScript'>";\r
-                        //echo "alert('Thuc hien rollup. Trang thai ".$scoparent->identifier." la hoan thanh voi userid".$userid."');";\r
-                        //echo "<script>";\r
-                        \r
-                    }                    \r
-                }\r
-                //Ket thuc truong hop 3\r
-                //Truong hop 4: childactivitySet = all\r
-                //                conditioncombination = all\r
-                if (($rule->childactivityset == 'all') && ($ruleConditions->conditioncombination=='all')){\r
-                    $conditionOK = true;                \r
-                    foreach ($scochildren as $sco){\r
-                    $usertrack = scorm_get_tracks($sco->id,$userid);\r
-                        foreach($conditions as $condition){\r
-                            //Condition 1:    condition = attempted         operator = 'noOp'\r
-                            //                Thuc hien rollupaction \r
-                            if (($condition->condition == 'attempted') && ($condition->operator=='noOp')){\r
-                                if ($usertrack->attempt_status != 'attempted'){\r
-                                    $conditionOK = false;\r
-                                }\r
-                            }\r
-                            //Condition 2:    condition = attempted         operator = 'not'\r
-                            //                Thuc hien rollupaction \r
-                            if (($condition->condition == 'attempted') && ($condition->operator=='not')){\r
-                                if ($usertrack->attempt_status != 'notattempted'){\r
-                                    $conditionOK = false;\r
-                                }\r
-                            }                    \r
-                            //Condition 3:    condition = satisfied         operator = 'noOp'\r
-                            //                Thuc hien rollupaction \r
-                            if (($condition->condition == 'satisfied') && ($condition->operator=='noOp')){\r
-                                if ($usertrack->attempt_status != 'satisfied'){\r
-                                    $conditionOK = false;\r
-                                }\r
-                            }\r
-                            //Condition 4:    condition = satisfied         operator = 'not'\r
-                            //                Thuc hien rollupaction \r
-                            if (($condition->condition == 'satisfied') && ($condition->operator=='not')){\r
-                                if ($usertrack->attempt_status != 'notSatisfied'){\r
-                                    $conditionOK = false;\r
-                                }\r
-                            }                    \r
-                            //Condition 5:    condition = completed         operator = 'noOp'\r
-                            //                Thuc hien rollupaction \r
-                            if (($condition->condition == 'completed') && ($condition->operator=='noOp')){\r
-                                if ($usertrack->attempt_status != 'completed'){\r
-                                    $conditionOK = false;\r
-                                }\r
-                            }    \r
-                            //Condition 6:    condition = completed         operator = 'not'\r
-                            //                Thuc hien rollupaction \r
-                            if (($condition->condition == 'completed') && ($condition->operator=='not')){\r
-                                if ($usertrack->attempt_status != 'notcompleted'){\r
-                                    $conditionOK = false;\r
-                                }\r
-                            }                                    \r
-                            //Neu dieu kien van dung sau khi xem xet thi thuc hien action\r
-                        }\r
-                    }\r
-                    if ($conditionOK == true){\r
-                        if ($ruleConditions->rollupruleaction == 'completed')\r
-                        {\r
-                        scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.completion_status','completed');\r
-                        //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi completed\n");\r
-                        }\r
-                        if ($ruleConditions->rollupruleaction == 'satisfied')\r
-                        {\r
-                        scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','passed');\r
-                        //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong  voi satisfied\n");\r
-                        }\r
-                        if ($ruleConditions->rollupruleaction == 'notSatisfied')\r
-                        {\r
-                        scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','failed');\r
-                        //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong  voi notSatisfied\n");\r
-                        }                                                        \r
-                        //echo "<script language='JavaScript'>";\r
-                        //echo "alert('Thuc hien rollup. Trang thai ".$scoparent->identifier." la hoan thanh voi userid".$userid."');";\r
-                        //echo "<script>";\r
-                        \r
-                    }                    \r
-                }\r
-                //Ket thuc truong hop 4                                                \r
-            }    \r
-        }\r
-    \r
-        //Thuc hien de qui cho Rollup voi cac muc cha\r
-        $scograndparent = get_record("scorm_scoes","scorm",$scormid,"identifier",$scoparent->parent);\r
-        if (!empty($scograndparent)){\r
-            //fwrite($ft,"\n >>>>> Quay lui Rollup SCO ".$scoparent->id);\r
-            scorm_rollup_updatestatus($scormid,$scoparent->id, $userid);\r
-        }\r
-    }\r
-}\r
-\r
-// --------Ket thuc cac ham danh cho viec thuc thi Rollup -------\r
-\r
-//---------Thuc hien sequencing rule -----------------\r
-function scorm_sequecingrule_implement($scormid,$scoidchild, $userid)\r
-{\r
-    $sequencingResult->rule = '';   //Rule co 3 truong hop exit, pre va post\r
-    $sequencingResult->action = '';\r
-    \r
-    \r
-    $f = "D:\\test.txt";\r
-    @$ft = fopen($f,"a");\r
-    //fwrite($ft,"\n >>>>> Kiem tra Sequencing \n");\r
-\r
-    $scochild = get_record("scorm_scoes","id",$scoidchild);\r
-    $scoparent = get_record("scorm_scoes","scorm",$scormid,"identifier",$scochild->parent);\r
-    //Danh sach cac con cua cha\r
-    $scochildren = get_records_select("scorm_scoes","scorm =".$scormid." and parent ='".$scoparent->identifier."'");\r
-    //Lay gia tri last attempt\r
-    \r
-    $attempt = scorm_get_last_attempt($scormid,$userid);\r
-    \r
-    if(!empty($scoparent)){\r
-        //fwrite($ft,"\n >>>>> Kiem tra Sequencing : Co Parent\n");\r
-    \r
-        $scoid = $scoparent->id;\r
-        //Lay trang thai cua SCO cha\r
-        $usertrack = scorm_get_tracks($scoid,$userid);\r
-        //fwrite($ft,"\n >>>>> Kiem tra Sequencing : id Parent ".$scoid);                \r
-        //fwrite($ft,"\n >>>>> Kiem tra Sequencing : usertrack ".$usertrack->status);                        \r
-        $sequencingrules = get_records_select("scorm_sequencing_ruleconditions","scormid=".$scormid." and scoid=".$scoid);\r
-        if (!empty($sequencingrules)){\r
-            foreach($sequencingrules as $sequencingrule){\r
-                //fwrite($ft,"\n >>>>> Kiem tra Sequencing : Co Sequencing o SCO".$sequencingrule->scoid);        \r
-                \r
-                $idsequencingrule = $sequencingrule->id;\r
-                $ruleconditions = get_records_select('scorm_sequencing_rulecondition','scoid ='.$scoid.'  and ruleconditionsid ='. $idsequencingrule);\r
-        \r
-                $conditionOK = true;\r
-                //Truong hop 1: conditioncombination = all            \r
-                if ($sequencingrule->conditioncombination =='all'){\r
-                    //fwrite($ft,"\n >>>>> Kiem tra Sequencing :conditioncombination la all \n");        \r
-                    $conditionOK = true;\r
-                    //fwrite($ft,"\n >>>>> Usertrack->status la: ".$usertrack->status);\r
-                    foreach ($ruleconditions as $rulecondition){\r
-                        //Neu co mot dieu kien khong thoa man thi se khong dung\r
-                        if (($rulecondition->condition != $usertrack->status)&&($rulecondition->condition != $usertrack->success_status)&&($rulecondition->condition != $usertrack->satisfied_status)){\r
-                            $conditionOK = false;                \r
-                        }\r
-                    }    \r
-                }\r
-                //Truong hop 2: conditioncombination = any                        \r
-                if ($sequencingrule->conditioncombination =='any'){\r
-                    $conditionOK = false;            \r
-                    foreach ($ruleconditions as $rulecondition){\r
-                        //Neu co mot dieu kien thoa man thi se dung\r
-                        if (($rulecondition->condition == $usertrack->status) || ($rulecondition->condition == $usertrack->success_status) || ($rulecondition->condition == $usertrack->satisfied_status) ){\r
-                            $conditionOK = true;                \r
-                        }\r
-                    }    \r
-                }\r
-    \r
-                //fwrite($ft,"\n >>>>> Gia tri conditionOK sau khi kiem tra dk la: ".$conditionOK);\r
-                //Neu dieu kien van dung thi thuc hien Action            \r
-                if ($conditionOK == true){\r
-                    //fwrite($ft,"\n >>>>> Dieu kien Sequencing OK..Thuc hien Action \n");                \r
-                    //Truong hop 1: ExitAction la Exit\r
-                    if ($sequencingrule->exitconditionruleaction=='exit')\r
-                    {\r
-                    //fwrite($ft,"\n >>>>> Xu ly Sequencing thanh cong -- Thuc hien su kien exit \n");\r
-                    echo "<script language='JavaScript'>";\r
-                    echo "alert('Thuc hien sequen. Do Trang thai ".$scoparent->identifier." la hoan thanh. Tien hanh EXIT');";\r
-                    echo "</script>";\r
-                    $sequencingResult->rule = 'exit';\r
-                    $sequencingResult->action = 'exit';                                        \r
-                    }\r
-                    if ($sequencingrule->preconditionruleaction=='disabled')\r
-                    {\r
-                    //fwrite($ft,"\n >>>>> Xu ly Sequencing thanh cong -- Thuc hien su kien disable \n");\r
-                    echo "<script language='JavaScript'>";\r
-                    echo "alert('Thuc hien sequen. Do Trang thai ".$scoparent->identifier." la hoan thanh. Tien hanh Disable');";\r
-                    echo "</script>";                    \r
-                    $sequencingResult->rule = 'pre';\r
-                    $sequencingResult->action = 'disable';                                        \r
-                    \r
-                    }                    \r
-                    \r
-                }\r
-            }\r
-        }\r
-    }\r
-    return $sequencingResult;\r
-}\r
-\r
-function get_sco_after_exit($scoid,$scormid){\r
-    $scochild = get_record("scorm_scoes","id",$scoid);\r
-    $scoparent = get_record("scorm_scoes","scorm",$scormid,"identifier",$scochild->parent);\r
-    $exitscoid = $scoid++;\r
-    $exitscochild = get_record("scorm_scoes","id",$exitscoid,"scorm",$scormid);\r
-    if (empty($exitscochild)){\r
-    //Da ra ngoai vung scoid. Hay day chinh la sco cuoi cung\r
-        return 0;\r
-    }\r
-    else{\r
-        $exitscoparent = get_record("scorm_scoes","scorm",$scormid,"identifier",$exitscochild->parent);\r
-        //Neu chua ra khoi activity do thi tiep tuc\r
-        while ($exitscoparent->id == $scoparent->id){\r
-            $exitscoid++;\r
-            $exitscochild = get_record("scorm_scoes","id",$exitscoid);\r
-                if (empty($exitscochild)){\r
-                //Da ra ngoai vung scoid. Hay day chinh la sco cuoi cung\r
-                return 0;\r
-                }\r
-                else{\r
-                $exitscoparent = get_record("scorm_scoes","scorm",$scormid,"identifier",$exitscochild->parent);\r
-                }\r
-        }\r
-    }\r
-    return $exitscoid;    \r
-}\r
-\r
-?>\r
+<?php 
+
+// Cac ham danh cho viec thuc thi Sequencing
+// --------Ket thuc cac ham danh cho viec thuc thi Sequencing ------------
+
+// Cac ham danh cho viec thuc thi Rollup
+
+//-----------------------------------------------------
+function scorm_rollup_updatestatus($scormid,$scoidchild, $userid)
+{
+    //$f = "D:\\test.txt";
+    //@$ft = fopen($f,"a");
+    //fwrite($ft,"\n >>>>> SCO goi Rollup la ".$scoidchild);
+    $scochild = get_record("scorm_scoes","id",$scoidchild);
+    $scoparent = get_record("scorm_scoes","scorm",$scormid,"identifier",$scochild->parent);
+    //Danh sach cac con cua cha
+    $scochildren = get_records_select("scorm_scoes","scorm =".$scormid." and parent ='".$scoparent->identifier."'");
+    //Lay gia tri last attempt
+    //fwrite($ft,"\n >>>>> Bat dau xu ly Rollup SCO cha ".$scoparent->id);
+    $attempt = scorm_get_last_attempt($scormid,$userid);
+    
+    if(!empty($scoparent)){
+        $scoid = $scoparent->id;
+        $rolluprules = get_record("scorm_sequencing_rolluprules","scormid",$scormid,"scoid",$scoid);
+        if (!empty($rolluprules)){
+            $idrolluprules = $rolluprules->id;
+            $rules = get_records_select('scorm_sequencing_rolluprule','scoid ='.$scoid.'  and rolluprulesid ='. $idrolluprules);
+    
+            foreach ($rules as $rule){
+                $ruleid = $rule->id;
+                $ruleConditions = get_record("scorm_sequencing_rollupruleconditions","scoid",$scoid,"rollupruleid",$ruleid);            
+                $idruleConditions = $ruleConditions->id;
+                $conditions = get_records_select('scorm_sequencing_rolluprulecondition','scoid ='.$scoid.'  and ruleconditionsid ='.$idruleConditions);    
+    
+                //Truong hop 1: childactivitySet = all
+                //                conditioncombination = any
+                if (($rule->childactivityset == 'all') && ($ruleConditions->conditioncombination=='any')){
+                    foreach($conditions as $condition){
+                        $conditionOK = false;   
+                        //Condition 1:    condition = attempted         operator = 'noOp'
+                        //                Thuc hien rollupaction 
+                        if (($condition->condition == 'attempted') && ($condition->operator=='noOp')){
+                        $conditionOK = true; 
+                            foreach ($scochildren as $sco){
+                                //fwrite($ft,"\n >>>>> Xu ly Rollup voi dieu kien attempt  \n");
+                                $usertrack = scorm_get_tracks($sco->id,$userid);
+                                if ($usertrack->attempt_status != 'attempted'){
+                                    //fwrite($ft,"\n >>>>> Co SCO con chua attempted  \n");
+                                    $conditionOK = false;
+                                }
+                            }
+                        }
+                        //Condition 2:    condition = attempted         operator = 'not'
+                        //                Thuc hien rollupaction 
+                        if (($condition->condition == 'attempted') && ($condition->operator=='not')){
+                        $conditionOK = true; 
+                            foreach ($scochildren as $sco){
+                                //fwrite($ft,"\n >>>>> Xu ly Rollup voi dieu kien not attempt  \n");
+                                $usertrack = scorm_get_tracks($sco->id,$userid);
+                                if ($usertrack->attempt_status != 'notattempted'){
+                                    $conditionOK = false;
+                                }
+                            }
+                        }                    
+                        //Condition 3:    condition = satisfied         operator = 'noOp'
+                        //                Thuc hien rollupaction 
+                        if (($condition->condition == 'satisfied') && ($condition->operator=='noOp')){
+                        $conditionOK = true; 
+                            foreach ($scochildren as $sco){
+                                $usertrack = scorm_get_tracks($sco->id,$userid);
+                                if ($usertrack->satisfied_status != 'satisfied'){
+                                    $conditionOK = false;
+                                }
+                            }
+                        }
+                        //Condition 4:    condition = satisfied         operator = 'not'
+                        //                Thuc hien rollupaction 
+                        if (($condition->condition == 'satisfied') && ($condition->operator=='not')){
+                        $conditionOK = true; 
+                            foreach ($scochildren as $sco){
+                                $usertrack = scorm_get_tracks($sco->id,$userid);
+                                if ($usertrack->satisfied_status != 'notSatisfied'){
+                                    $conditionOK = false;
+                                }
+                            }
+                        }                    
+                        //Condition 5:    condition = completed         operator = 'noOp'
+                        //                Thuc hien rollupaction 
+                        if (($condition->condition == 'completed') && ($condition->operator=='noOp')){
+                        $conditionOK = true; 
+                            foreach ($scochildren as $sco){
+                                $usertrack = scorm_get_tracks($sco->id,$userid);
+                                if ($usertrack->attempt_status != 'completed'){
+                                    $conditionOK = false;
+                                }
+                            }
+                        }    
+                        //Condition 6:    condition = completed         operator = 'not'
+                        //                Thuc hien rollupaction 
+                        if (($condition->condition == 'completed') && ($condition->operator=='not')){
+                        $conditionOK = true; 
+                            foreach ($scochildren as $sco){
+                                $usertrack = scorm_get_tracks($sco->id,$userid);
+                                if ($usertrack->attempt_status != 'notcompleted'){
+                                    $conditionOK = false;
+                                }
+                            }
+                        }                                    
+                        //Neu dieu kien van dung sau khi xem xet thi thuc hien action
+                        if ($conditionOK == true){
+                            if ($ruleConditions->rollupruleaction == 'completed')
+                            {
+                            scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.completion_status','completed');
+                            //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi completed cho SCO ".$scoid);
+                            }
+                            if ($ruleConditions->rollupruleaction == 'satisfied')
+                            {
+                            scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','passed');
+                            //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong  voi satisfied\n");
+                            }
+                            if ($ruleConditions->rollupruleaction == 'notSatisfied')
+                            {
+                            scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','failed');
+                            //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong  voi notSatisfied\n");
+                            }                                                        
+                            //echo "<script language='JavaScript'>";
+                            //echo "alert('Thuc hien rollup. Trang thai ".$scoparent->identifier." la hoan thanh voi userid".$userid."');";
+                            //echo "<script>";
+                            
+                        }
+                    }
+                }
+                //Ket thuc truong hop 1
+                //Truong hop 2: childactivitySet = any
+                //                conditioncombination = any
+                if (($rule->childactivityset == 'any') && ($ruleConditions->conditioncombination=='any')){
+                    $conditionOK = false;  
+                    foreach($conditions as $condition){
+                        //$conditionOK = false;   
+                        //Condition 1:    condition = attempted         operator = 'noOp'
+                        //                Thuc hien rollupaction 
+                        if (($condition->condition == 'attempted') && ($condition->operator=='noOp')){
+                        $conditionOK = false; 
+                            foreach ($scochildren as $sco){
+                                $usertrack = scorm_get_tracks($sco->id,$userid);
+                                if ($usertrack->attempt_status = 'attempted'){
+                                    $conditionOK = true;
+                                }
+                            }
+                        }
+                        //Condition 2:    condition = attempted         operator = 'not'
+                        //                Thuc hien rollupaction 
+                        if (($condition->condition == 'attempted') && ($condition->operator=='not')){
+                        $conditionOK = false; 
+                            foreach ($scochildren as $sco){
+                                $usertrack = scorm_get_tracks($sco->id,$userid);
+                                if ($usertrack->attempt_status = 'notattempted'){
+                                    $conditionOK = true;
+                                }
+                            }
+                        }                    
+                        //Condition 3:    condition = satisfied         operator = 'noOp'
+                        //                Thuc hien rollupaction 
+                        if (($condition->condition == 'satisfied') && ($condition->operator=='noOp')){
+                        $conditionOK = false; 
+                            foreach ($scochildren as $sco){
+                                $usertrack = scorm_get_tracks($sco->id,$userid);
+                                if ($usertrack->satisfied_status = 'satisfied'){
+                                    $conditionOK = true;
+                                }
+                            }
+                        }
+                        //Condition 4:    condition = satisfied         operator = 'not'
+                        //                Thuc hien rollupaction 
+                        if (($condition->condition == 'satisfied') && ($condition->operator=='not')){
+                        $conditionOK = false; 
+                            foreach ($scochildren as $sco){
+                                $usertrack = scorm_get_tracks($sco->id,$userid);
+                                if ($usertrack->satisfied_status = 'notSatisfied'){
+                                    //fwrite($ft,"\n >>>>> Xu ly Rollup voi notSatisfied\n");
+                                    $conditionOK = true;
+                                }
+                            }
+                        }                    
+                        //Condition 5:    condition = completed         operator = 'noOp'
+                        //                Thuc hien rollupaction 
+                        if (($condition->condition == 'completed') && ($condition->operator=='noOp')){
+                        $conditionOK = false; 
+                            foreach ($scochildren as $sco){
+                                $usertrack = scorm_get_tracks($sco->id,$userid);
+                                if ($usertrack->attempt_status = 'completed'){
+                                    $conditionOK = true;
+                                }
+                            }
+                        }    
+                        //Condition 6:    condition = completed         operator = 'not'
+                        //                Thuc hien rollupaction 
+                        if (($condition->condition == 'completed') && ($condition->operator=='not')){
+                        $conditionOK = false; 
+                            foreach ($scochildren as $sco){
+                                $usertrack = scorm_get_tracks($sco->id,$userid);
+                                if ($usertrack->attempt_status = 'notcompleted'){
+                                    $conditionOK = true;
+                                }
+                            }
+                        }                                    
+                        //Neu dieu kien van dung sau khi xem xet thi thuc hien action
+                        if ($conditionOK == true){
+                            if ($ruleConditions->rollupruleaction == 'completed')
+                            {
+                            scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.completion_status','completed');
+                            //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi completed\n");
+                            }
+                            if ($ruleConditions->rollupruleaction == 'satisfied')
+                            {
+                            scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','passed');
+                            //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong  voi satisfied\n");
+                            }
+                            if ($ruleConditions->rollupruleaction == 'notSatisfied')
+                            {
+                            scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','failed');
+                            //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong  voi notSatisfied\n");
+                            }                                                        
+                            //echo "<script language='JavaScript'>";
+                            //echo "alert('Thuc hien rollup. Trang thai ".$scoparent->identifier." la hoan thanh voi userid".$userid."');";
+                            //echo "<script>";
+                            
+                        }
+                    }
+                }
+                //Ket thuc truong hop 2
+                //Truong hop 3: childactivitySet = any
+                //                conditioncombination = all
+                if (($rule->childactivityset == 'any') && ($ruleConditions->conditioncombination=='all')){
+                    foreach ($scochildren as $sco){
+                    $usertrack = scorm_get_tracks($sco->id,$userid);
+                    $conditionOK = true;  
+                        foreach($conditions as $condition){
+                            //Condition 1:    condition = attempted         operator = 'noOp'
+                            //                Thuc hien rollupaction 
+                            if (($condition->condition == 'attempted') && ($condition->operator=='noOp')){
+                                if ($usertrack->attempt_status != 'attempted'){
+                                    $conditionOK = false;
+                                }
+                            }
+                            //Condition 2:    condition = attempted         operator = 'not'
+                            //                Thuc hien rollupaction 
+                            if (($condition->condition == 'attempted') && ($condition->operator=='not')){
+                                if ($usertrack->attempt_status != 'notattempted'){
+                                    $conditionOK = false;
+                                }
+                            }                    
+                            //Condition 3:    condition = satisfied         operator = 'noOp'
+                            //                Thuc hien rollupaction 
+                            if (($condition->condition == 'satisfied') && ($condition->operator=='noOp')){
+                                if ($usertrack->attempt_status != 'satisfied'){
+                                    $conditionOK = false;
+                                }
+                            }
+                            //Condition 4:    condition = satisfied         operator = 'not'
+                            //                Thuc hien rollupaction 
+                            if (($condition->condition == 'satisfied') && ($condition->operator=='not')){
+                                if ($usertrack->attempt_status != 'notSatisfied'){
+                                    $conditionOK = false;
+                                }
+                            }                    
+                            //Condition 5:    condition = completed         operator = 'noOp'
+                            //                Thuc hien rollupaction 
+                            if (($condition->condition == 'completed') && ($condition->operator=='noOp')){
+                                if ($usertrack->attempt_status != 'completed'){
+                                    $conditionOK = false;
+                                }
+                            }    
+                            //Condition 6:    condition = completed         operator = 'not'
+                            //                Thuc hien rollupaction 
+                            if (($condition->condition == 'completed') && ($condition->operator=='not')){
+                                if ($usertrack->attempt_status != 'notcompleted'){
+                                    $conditionOK = false;
+                                }
+                            }                                    
+                            //Neu dieu kien van dung sau khi xem xet thi thuc hien action
+                        }
+                    }
+                    if ($conditionOK == true){
+                        if ($ruleConditions->rollupruleaction == 'completed')
+                        {
+                        scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.completion_status','completed');
+                        //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi completed\n");
+                        }
+                        if ($ruleConditions->rollupruleaction == 'satisfied')
+                        {
+                        scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','passed');
+                        //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong  voi satisfied\n");
+                        }
+                        if ($ruleConditions->rollupruleaction == 'notSatisfied')
+                        {
+                        scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','failed');
+                        //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong  voi notSatisfied\n");
+                        }                                                        
+                        //echo "<script language='JavaScript'>";
+                        //echo "alert('Thuc hien rollup. Trang thai ".$scoparent->identifier." la hoan thanh voi userid".$userid."');";
+                        //echo "<script>";
+                        
+                    }                    
+                }
+                //Ket thuc truong hop 3
+                //Truong hop 4: childactivitySet = all
+                //                conditioncombination = all
+                if (($rule->childactivityset == 'all') && ($ruleConditions->conditioncombination=='all')){
+                    $conditionOK = true;                
+                    foreach ($scochildren as $sco){
+                    $usertrack = scorm_get_tracks($sco->id,$userid);
+                        foreach($conditions as $condition){
+                            //Condition 1:    condition = attempted         operator = 'noOp'
+                            //                Thuc hien rollupaction 
+                            if (($condition->condition == 'attempted') && ($condition->operator=='noOp')){
+                                if ($usertrack->attempt_status != 'attempted'){
+                                    $conditionOK = false;
+                                }
+                            }
+                            //Condition 2:    condition = attempted         operator = 'not'
+                            //                Thuc hien rollupaction 
+                            if (($condition->condition == 'attempted') && ($condition->operator=='not')){
+                                if ($usertrack->attempt_status != 'notattempted'){
+                                    $conditionOK = false;
+                                }
+                            }                    
+                            //Condition 3:    condition = satisfied         operator = 'noOp'
+                            //                Thuc hien rollupaction 
+                            if (($condition->condition == 'satisfied') && ($condition->operator=='noOp')){
+                                if ($usertrack->attempt_status != 'satisfied'){
+                                    $conditionOK = false;
+                                }
+                            }
+                            //Condition 4:    condition = satisfied         operator = 'not'
+                            //                Thuc hien rollupaction 
+                            if (($condition->condition == 'satisfied') && ($condition->operator=='not')){
+                                if ($usertrack->attempt_status != 'notSatisfied'){
+                                    $conditionOK = false;
+                                }
+                            }                    
+                            //Condition 5:    condition = completed         operator = 'noOp'
+                            //                Thuc hien rollupaction 
+                            if (($condition->condition == 'completed') && ($condition->operator=='noOp')){
+                                if ($usertrack->attempt_status != 'completed'){
+                                    $conditionOK = false;
+                                }
+                            }    
+                            //Condition 6:    condition = completed         operator = 'not'
+                            //                Thuc hien rollupaction 
+                            if (($condition->condition == 'completed') && ($condition->operator=='not')){
+                                if ($usertrack->attempt_status != 'notcompleted'){
+                                    $conditionOK = false;
+                                }
+                            }                                    
+                            //Neu dieu kien van dung sau khi xem xet thi thuc hien action
+                        }
+                    }
+                    if ($conditionOK == true){
+                        if ($ruleConditions->rollupruleaction == 'completed')
+                        {
+                        scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.completion_status','completed');
+                        //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi completed\n");
+                        }
+                        if ($ruleConditions->rollupruleaction == 'satisfied')
+                        {
+                        scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','passed');
+                        //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong  voi satisfied\n");
+                        }
+                        if ($ruleConditions->rollupruleaction == 'notSatisfied')
+                        {
+                        scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','failed');
+                        //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong  voi notSatisfied\n");
+                        }                                                        
+                        //echo "<script language='JavaScript'>";
+                        //echo "alert('Thuc hien rollup. Trang thai ".$scoparent->identifier." la hoan thanh voi userid".$userid."');";
+                        //echo "<script>";
+                        
+                    }                    
+                }
+                //Ket thuc truong hop 4                                                
+            }    
+        }
+    
+        //Thuc hien de qui cho Rollup voi cac muc cha
+        $scograndparent = get_record("scorm_scoes","scorm",$scormid,"identifier",$scoparent->parent);
+        if (!empty($scograndparent)){
+            //fwrite($ft,"\n >>>>> Quay lui Rollup SCO ".$scoparent->id);
+            scorm_rollup_updatestatus($scormid,$scoparent->id, $userid);
+        }
+    }
+}
+
+// --------Ket thuc cac ham danh cho viec thuc thi Rollup -------
+
+//---------Thuc hien sequencing rule -----------------
+function scorm_sequecingrule_implement($scormid,$scoidchild, $userid)
+{
+    $sequencingResult->rule = '';   //Rule co 3 truong hop exit, pre va post
+    $sequencingResult->action = '';
+    
+    
+    $f = "D:\\test.txt";
+    @$ft = fopen($f,"a");
+    //fwrite($ft,"\n >>>>> Kiem tra Sequencing \n");
+
+    $scochild = get_record("scorm_scoes","id",$scoidchild);
+    $scoparent = get_record("scorm_scoes","scorm",$scormid,"identifier",$scochild->parent);
+    //Danh sach cac con cua cha
+    $scochildren = get_records_select("scorm_scoes","scorm =".$scormid." and parent ='".$scoparent->identifier."'");
+    //Lay gia tri last attempt
+    
+    $attempt = scorm_get_last_attempt($scormid,$userid);
+    
+    if(!empty($scoparent)){
+        //fwrite($ft,"\n >>>>> Kiem tra Sequencing : Co Parent\n");
+    
+        $scoid = $scoparent->id;
+        //Lay trang thai cua SCO cha
+        $usertrack = scorm_get_tracks($scoid,$userid);
+        //fwrite($ft,"\n >>>>> Kiem tra Sequencing : id Parent ".$scoid);                
+        //fwrite($ft,"\n >>>>> Kiem tra Sequencing : usertrack ".$usertrack->status);                        
+        $sequencingrules = get_records_select("scorm_sequencing_ruleconditions","scormid=".$scormid." and scoid=".$scoid);
+        if (!empty($sequencingrules)){
+            foreach($sequencingrules as $sequencingrule){
+                //fwrite($ft,"\n >>>>> Kiem tra Sequencing : Co Sequencing o SCO".$sequencingrule->scoid);        
+                
+                $idsequencingrule = $sequencingrule->id;
+                $ruleconditions = get_records_select('scorm_sequencing_rulecondition','scoid ='.$scoid.'  and ruleconditionsid ='. $idsequencingrule);
+        
+                $conditionOK = true;
+                //Truong hop 1: conditioncombination = all            
+                if ($sequencingrule->conditioncombination =='all'){
+                    //fwrite($ft,"\n >>>>> Kiem tra Sequencing :conditioncombination la all \n");        
+                    $conditionOK = true;
+                    //fwrite($ft,"\n >>>>> Usertrack->status la: ".$usertrack->status);
+                    foreach ($ruleconditions as $rulecondition){
+                        //Neu co mot dieu kien khong thoa man thi se khong dung
+                        if (($rulecondition->condition != $usertrack->status)&&($rulecondition->condition != $usertrack->success_status)&&($rulecondition->condition != $usertrack->satisfied_status)){
+                            $conditionOK = false;                
+                        }
+                    }    
+                }
+                //Truong hop 2: conditioncombination = any                        
+                if ($sequencingrule->conditioncombination =='any'){
+                    $conditionOK = false;            
+                    foreach ($ruleconditions as $rulecondition){
+                        //Neu co mot dieu kien thoa man thi se dung
+                        if (($rulecondition->condition == $usertrack->status) || ($rulecondition->condition == $usertrack->success_status) || ($rulecondition->condition == $usertrack->satisfied_status) ){
+                            $conditionOK = true;                
+                        }
+                    }    
+                }
+    
+                //fwrite($ft,"\n >>>>> Gia tri conditionOK sau khi kiem tra dk la: ".$conditionOK);
+                //Neu dieu kien van dung thi thuc hien Action            
+                if ($conditionOK == true){
+                    //fwrite($ft,"\n >>>>> Dieu kien Sequencing OK..Thuc hien Action \n");                
+                    //Truong hop 1: ExitAction la Exit
+                    if ($sequencingrule->exitconditionruleaction=='exit')
+                    {
+                    //fwrite($ft,"\n >>>>> Xu ly Sequencing thanh cong -- Thuc hien su kien exit \n");
+                    echo "<script language='JavaScript'>";
+                    echo "alert('Thuc hien sequen. Do Trang thai ".$scoparent->identifier." la hoan thanh. Tien hanh EXIT');";
+                    echo "</script>";
+                    $sequencingResult->rule = 'exit';
+                    $sequencingResult->action = 'exit';                                        
+                    }
+                    if ($sequencingrule->preconditionruleaction=='disabled')
+                    {
+                    //fwrite($ft,"\n >>>>> Xu ly Sequencing thanh cong -- Thuc hien su kien disable \n");
+                    echo "<script language='JavaScript'>";
+                    echo "alert('Thuc hien sequen. Do Trang thai ".$scoparent->identifier." la hoan thanh. Tien hanh Disable');";
+                    echo "</script>";                    
+                    $sequencingResult->rule = 'pre';
+                    $sequencingResult->action = 'disable';                                        
+                    
+                    }                    
+                    
+                }
+            }
+        }
+    }
+    return $sequencingResult;
+}
+
+function get_sco_after_exit($scoid,$scormid){
+    $scochild = get_record("scorm_scoes","id",$scoid);
+    $scoparent = get_record("scorm_scoes","scorm",$scormid,"identifier",$scochild->parent);
+    $exitscoid = $scoid++;
+    $exitscochild = get_record("scorm_scoes","id",$exitscoid,"scorm",$scormid);
+    if (empty($exitscochild)){
+    //Da ra ngoai vung scoid. Hay day chinh la sco cuoi cung
+        return 0;
+    }
+    else{
+        $exitscoparent = get_record("scorm_scoes","scorm",$scormid,"identifier",$exitscochild->parent);
+        //Neu chua ra khoi activity do thi tiep tuc
+        while ($exitscoparent->id == $scoparent->id){
+            $exitscoid++;
+            $exitscochild = get_record("scorm_scoes","id",$exitscoid);
+                if (empty($exitscochild)){
+                //Da ra ngoai vung scoid. Hay day chinh la sco cuoi cung
+                return 0;
+                }
+                else{
+                $exitscoparent = get_record("scorm_scoes","scorm",$scormid,"identifier",$exitscochild->parent);
+                }
+        }
+    }
+    return $exitscoid;    
+}
+
+?>
index ea57b3034e3d1a6b920b1ca53e0d5af1866982c2..409a5196bc03e8313268f44fd7f9c9e37bab7251 100644 (file)
@@ -1,83 +1,83 @@
-.structlist  {\r
-  list-style-type: none;\r
-  white-space: nowrap;\r
-  font-size: small;\r
-}\r
-.orgtitle {\r
-  font-weight: bold;\r
-  font-size: small;\r
-}\r
-.mod-scorm .top {\r
-  vertical-align: top;\r
-}\r
-.mod-scorm .left {\r
-  text-align: left;\r
-}\r
-.mod-scorm .center {\r
-  text-align: center;\r
-}\r
-.mod-scorm .right {\r
-  text-align: right;\r
-}\r
-.mod-scorm .scoframe {\r
-\r
-}\r
-\r
-#mod-scorm-player #scormpage {\r
-  position: relative;\r
-  width: 100%;\r
-}\r
-#mod-scorm-player #tocbox {\r
-  position: absolute;\r
-  left: 0px;\r
-  top: 0px;\r
-  width: 19%;\r
-}\r
-#mod-scorm-player #tochead {\r
-  text-align: center;\r
-  font-weight: bold;\r
-}\r
-#mod-scorm-player #scormbox {\r
-  position: absolute;\r
-  right: 0px;\r
-  top: 0px;\r
-}\r
-#mod-scorm-player .toc {\r
-  width: 80%; \r
-  margin-left: 20%; \r
-}\r
-#mod-scorm-player .no-toc {\r
-  width: 100%;\r
-}\r
-#mod-scorm-player #scormobject {\r
- /* border: 1px solid black; */\r
-}\r
-#mod-scorm-player #scormtop {\r
-  position: relative;\r
-  width: 100%;\r
-  height: 30px;\r
-}\r
-#mod-scorm-player #scormbrowse {\r
-  position: absolute;\r
-  left: 5px;\r
-  top: 0px;\r
-}\r
-#mod-scorm-player #scormnav {\r
-  position: absolute;\r
-  right: 5px;\r
-  top: 0px;\r
-}\r
-#mod-scorm-player .structurelist {\r
-  list-style-type: none;\r
-  text-indent:-4ex;\r
-  font-size: small;\r
-}\r
-\r
-#mod-scorm-view .structurehead {\r
-  font-weight: bold;\r
-  text-align: center;\r
-}\r
-#mod-scorm-view .structurelist  {\r
-  list-style-type: none;\r
-  white-space: nowrap;\r
-}\r
+.structlist  {
+  list-style-type: none;
+  white-space: nowrap;
+  font-size: small;
+}
+.orgtitle {
+  font-weight: bold;
+  font-size: small;
+}
+.mod-scorm .top {
+  vertical-align: top;
+}
+.mod-scorm .left {
+  text-align: left;
+}
+.mod-scorm .center {
+  text-align: center;
+}
+.mod-scorm .right {
+  text-align: right;
+}
+.mod-scorm .scoframe {
+
+}
+
+#mod-scorm-player #scormpage {
+  position: relative;
+  width: 100%;
+}
+#mod-scorm-player #tocbox {
+  position: absolute;
+  left: 0px;
+  top: 0px;
+  width: 19%;
+}
+#mod-scorm-player #tochead {
+  text-align: center;
+  font-weight: bold;
+}
+#mod-scorm-player #scormbox {
+  position: absolute;
+  right: 0px;
+  top: 0px;
+}
+#mod-scorm-player .toc {
+  width: 80%; 
+  margin-left: 20%; 
+}
+#mod-scorm-player .no-toc {
+  width: 100%;
+}
+#mod-scorm-player #scormobject {
+ /* border: 1px solid black; */
+}
+#mod-scorm-player #scormtop {
+  position: relative;
+  width: 100%;
+  height: 30px;
+}
+#mod-scorm-player #scormbrowse {
+  position: absolute;
+  left: 5px;
+  top: 0px;
+}
+#mod-scorm-player #scormnav {
+  position: absolute;
+  right: 5px;
+  top: 0px;
+}
+#mod-scorm-player .structurelist {
+  list-style-type: none;
+  text-indent:-4ex;
+  font-size: small;
+}
+
+#mod-scorm-view .structurehead {
+  font-weight: bold;
+  text-align: center;
+}
+#mod-scorm-view .structurelist  {
+  list-style-type: none;
+  white-space: nowrap;
+}
index 260a98a5f31ccc8550e5c81665d5a67452396d4f..196c6e213b7ac46883d19464a14b1ad16f0ebf71 100755 (executable)
@@ -1,29 +1,29 @@
-<?php\r
-    require_once('../../config.php');\r
-    require_once('locallib.php');\r
-\r
-    $id = required_param('id', PARAM_INT);         // course ID\r
-    $scormid = required_param('scorm', PARAM_INT);         // scorm ID\r
-    $scoid = required_param('sco', PARAM_INT);  // suspend sco ID\r
-    $userid = required_param('userid', PARAM_INT);  // user ID\r
-\r
-    $attempt = scorm_get_last_attempt($scormid,$userid);\r
-    $statistic = get_record('scorm_statistic',"scormid",$scormid,"userid",$userid);\r
-    $statisticInput->accesstime = $statistic->accesstime;\r
-    $statisticInput->durationtime = $statistic->durationtime + time()- $statistic->accesstime;\r
-    $statisticInput->status = 'suspend';\r
-    $statisticInput->attemptnumber = $attempt;\r
-    $statisticInput->scormid = $statistic->scormid;\r
-    $statisticInput->userid = $statistic->userid;    \r
-    $statisticid = scorm_insert_statistic($statisticInput);\r
-\r
-    $result = scorm_insert_trackmodel($userid, $scormid, $scoid,$attempt);\r
-    if ($result) {\r
-        echo "<script language='Javascript' type='text/javascript'>";\r
-        echo "location.href='".$CFG->wwwroot." /course/view.php?id=".$id."';";        \r
-        echo "</script>";\r
-    } else {\r
-        echo "Suspend failed";\r
-    }\r
-?>\r
-\r
+<?php
+    require_once('../../config.php');
+    require_once('locallib.php');
+
+    $id = required_param('id', PARAM_INT);         // course ID
+    $scormid = required_param('scorm', PARAM_INT);         // scorm ID
+    $scoid = required_param('sco', PARAM_INT);  // suspend sco ID
+    $userid = required_param('userid', PARAM_INT);  // user ID
+
+    $attempt = scorm_get_last_attempt($scormid,$userid);
+    $statistic = get_record('scorm_statistic',"scormid",$scormid,"userid",$userid);
+    $statisticInput->accesstime = $statistic->accesstime;
+    $statisticInput->durationtime = $statistic->durationtime + time()- $statistic->accesstime;
+    $statisticInput->status = 'suspend';
+    $statisticInput->attemptnumber = $attempt;
+    $statisticInput->scormid = $statistic->scormid;
+    $statisticInput->userid = $statistic->userid;    
+    $statisticid = scorm_insert_statistic($statisticInput);
+
+    $result = scorm_insert_trackmodel($userid, $scormid, $scoid,$attempt);
+    if ($result) {
+        echo "<script language='Javascript' type='text/javascript'>";
+        echo "location.href='".$CFG->wwwroot." /course/view.php?id=".$id."';";        
+        echo "</script>";
+    } else {
+        echo "Suspend failed";
+    }
+?>
+
index 0e5ef6b42adc12adffa00dee510016c782d19981..a618c9bfc8df22b47e1f0dad1449b91e38e310ab 100755 (executable)
-# phpMyAdmin MySQL-Dump\r
-# version 2.2.1\r
-# http://phpwizard.net/phpMyAdmin/\r
-# http://phpmyadmin.sourceforge.net/ (download page)\r
-#\r
-# Host: localhost\r
-# Generation Time: Nov 14, 2001 at 04:39 PM\r
-# Server version: 3.23.36\r
-# PHP Version: 4.0.6\r
-# Database : `moodle`\r
-# --------------------------------------------------------\r
-\r
-#\r
-# Table structure for table `survey`\r
-#\r
-\r
-CREATE TABLE prefix_survey (\r
-  id int(10) unsigned NOT NULL auto_increment,\r
-  course int(10) unsigned NOT NULL default '0',\r
-  template int(10) unsigned NOT NULL default '0',\r
-  days smallint(6) NOT NULL default '0',\r
-  timecreated int(10) unsigned NOT NULL default '0',\r
-  timemodified int(10) unsigned NOT NULL default '0',\r
-  name varchar(255) NOT NULL default '',\r
-  intro text NOT NULL default '',\r
-  questions varchar(255) NOT NULL default '',\r
-  PRIMARY KEY  (id), \r
-  KEY `course` (`course`)\r
-) TYPE=MyISAM COMMENT='all surveys';\r
-\r
-#\r
-# Dumping data for table `survey`\r
-#\r
-\r
-INSERT INTO `prefix_survey` (`id`, `course`, `template`, `days`, `timecreated`, `timemodified`, `name`, `intro`, `questions`) VALUES (1, 0, 0, 0, 985017600, 985017600, 'collesaname', 'collesaintro', '25,26,27,28,29,30,43,44');\r
-INSERT INTO `prefix_survey` (`id`, `course`, `template`, `days`, `timecreated`, `timemodified`, `name`, `intro`, `questions`) VALUES (2, 0, 0, 0, 985017600, 985017600, 'collespname', 'collespintro', '31,32,33,34,35,36,43,44');\r
-INSERT INTO `prefix_survey` (`id`, `course`, `template`, `days`, `timecreated`, `timemodified`, `name`, `intro`, `questions`) VALUES (3, 0, 0, 0, 985017600, 985017600, 'collesapname', 'collesapintro', '37,38,39,40,41,42,43,44');\r
-INSERT INTO `prefix_survey` (`id`, `course`, `template`, `days`, `timecreated`, `timemodified`, `name`, `intro`, `questions`) VALUES (4, 0, 0, 0, 985017600, 985017600, 'attlsname', 'attlsintro', '65,67,68');\r
-INSERT INTO `prefix_survey` (`id`, `course`, `template`, `days`, `timecreated`, `timemodified`, `name`, `intro`, `questions`) VALUES (5, 0, 0, 0, 985017600, 985017600, 'ciqname', 'ciqintro', '69,70,71,72,73');\r
-\r
-\r
-\r
-#\r
-# Table structure for table `survey_analysis`\r
-#\r
-\r
-CREATE TABLE prefix_survey_analysis (\r
-  id int(10) unsigned NOT NULL auto_increment,\r
-  survey int(10) unsigned NOT NULL default '0',\r
-  userid int(10) unsigned NOT NULL default '0',\r
-  notes text NOT NULL default '',\r
-  PRIMARY KEY  (id),\r
-  UNIQUE KEY id (id),\r
-  KEY survey (survey),\r
-  KEY userid (userid)\r
-) TYPE=MyISAM;\r
-\r
-#\r
-# Dumping data for table `survey_analysis`\r
-#\r
-\r
-# --------------------------------------------------------\r
-\r
-#\r
-# Table structure for table `survey_answers`\r
-#\r
-\r
-CREATE TABLE prefix_survey_answers (\r
-  id int(10) unsigned NOT NULL auto_increment,\r
-  userid int(10) unsigned NOT NULL default '0',\r
-  survey int(10) unsigned NOT NULL default '0',\r
-  question int(10) unsigned NOT NULL default '0',\r
-  time int(10) unsigned NOT NULL default '0',\r
-  answer1 text NOT NULL default '',\r
-  answer2 text NOT NULL default '',\r
-  PRIMARY KEY  (id),\r
-  UNIQUE KEY id (id),\r
-  KEY userid (userid),\r
-  KEY survey (survey),\r
-  KEY question (question)\r
-) TYPE=MyISAM;\r
-\r
-#\r
-# Dumping data for table `survey_answers`\r
-#\r
-\r
-# --------------------------------------------------------\r
-\r
-#\r
-# Table structure for table `survey_questions`\r
-#\r
-\r
-CREATE TABLE `prefix_survey_questions` (\r
-  `id` int(10) unsigned NOT NULL auto_increment,\r
-  `text` varchar(255) NOT NULL default '',\r
-  `shorttext` varchar(30) NOT NULL default '',\r
-  `multi` varchar(100) NOT NULL default '',\r
-  `intro` varchar(50) NOT NULL default '',\r
-  `type` tinyint(3) NOT NULL default '0',\r
-  `options` text,\r
-  PRIMARY KEY  (`id`)\r
-) TYPE=MyISAM;\r
-\r
-#\r
-# Dumping data for table `survey_questions`\r
-#\r
-\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (1, 'colles1', 'colles1short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (2, 'colles2', 'colles2short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (3, 'colles3', 'colles3short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (4, 'colles4', 'colles4short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (5, 'colles5', 'colles5short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (6, 'colles6', 'colles6short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (7, 'colles7', 'colles7short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (8, 'colles8', 'colles8short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (9, 'colles9', 'colles9short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (10, 'colles10', 'colles10short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (11, 'colles11', 'colles11short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (12, 'colles12', 'colles12short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (13, 'colles13', 'colles13short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (14, 'colles14', 'colles14short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (15, 'colles15', 'colles15short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (16, 'colles16', 'colles16short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (17, 'colles17', 'colles17short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (18, 'colles18', 'colles18short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (19, 'colles19', 'colles19short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (20, 'colles20', 'colles20short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (21, 'colles21', 'colles21short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (22, 'colles22', 'colles22short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (23, 'colles23', 'colles23short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (24, 'colles24', 'colles24short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (25, 'collesm1', 'collesm1short', '1,2,3,4', 'collesmintro', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (26, 'collesm2', 'collesm2short', '5,6,7,8', 'collesmintro', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (27, 'collesm3', 'collesm3short', '9,10,11,12', 'collesmintro', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (28, 'collesm4', 'collesm4short', '13,14,15,16', 'collesmintro', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (29, 'collesm5', 'collesm5short', '17,18,19,20', 'collesmintro', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (30, 'collesm6', 'collesm6short', '21,22,23,24', 'collesmintro', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (31, 'collesm1', 'collesm1short', '1,2,3,4', 'collesmintro', 2, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (32, 'collesm2', 'collesm2short', '5,6,7,8', 'collesmintro', 2, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (33, 'collesm3', 'collesm3short', '9,10,11,12', 'collesmintro', 2, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (34, 'collesm4', 'collesm4short', '13,14,15,16', 'collesmintro', 2, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (35, 'collesm5', 'collesm5short', '17,18,19,20', 'collesmintro', 2, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (36, 'collesm6', 'collesm6short', '21,22,23,24', 'collesmintro', 2, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (37, 'collesm1', 'collesm1short', '1,2,3,4', 'collesmintro', 3, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (38, 'collesm2', 'collesm2short', '5,6,7,8', 'collesmintro', 3, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (39, 'collesm3', 'collesm3short', '9,10,11,12', 'collesmintro', 3, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (40, 'collesm4', 'collesm4short', '13,14,15,16', 'collesmintro', 3, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (41, 'collesm5', 'collesm5short', '17,18,19,20', 'collesmintro', 3, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (42, 'collesm6', 'collesm6short', '21,22,23,24', 'collesmintro', 3, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (43, 'howlong', '', '', '', 1, 'howlongoptions');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (44, 'othercomments', '', '', '', 0, '');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (64, 'attls20', 'attls20short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (58, 'attls14', 'attls14short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (59, 'attls15', 'attls15short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (60, 'attls16', 'attls16short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (61, 'attls17', 'attls17short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (62, 'attls18', 'attls18short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (63, 'attls19', 'attls19short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (56, 'attls12', 'attls12short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (57, 'attls13', 'attls13short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (55, 'attls11', 'attls11short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (54, 'attls10', 'attls10short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (53, 'attls9', 'attls9short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (52, 'attls8', 'attls8short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (51, 'attls7', 'attls7short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (50, 'attls6', 'attls6short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (49, 'attls5', 'attls5short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (48, 'attls4', 'attls4short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (47, 'attls3', 'attls3short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (45, 'attls1', 'attls1short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (46, 'attls2', 'attls2short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (65, 'attlsm1', 'attlsm1', '45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64', 'attlsmintro', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (67, 'attlsm2', 'attlsm2', '63,62,59,57,55,49,52,50,48,47', 'attlsmintro', -1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (68, 'attlsm3', 'attlsm3', '46,54,45,51,60,53,56,58,61,64', 'attlsmintro', -1, 'scaleagree5');\r
-\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (69, 'ciq1', 'ciq1short', '', '', 0, '');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (70, 'ciq2', 'ciq2short', '', '', 0, '');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (71, 'ciq3', 'ciq3short', '', '', 0, '');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (72, 'ciq4', 'ciq4short', '', '', 0, '');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (73, 'ciq5', 'ciq5short', '', '', 0, '');\r
-\r
-\r
-#\r
-# Dumping data for table `log_display`\r
-#\r
-\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'add', 'survey', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'update', 'survey', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'download', 'survey', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'view form', 'survey', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'view graph', 'survey', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'view report', 'survey', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'submit', 'survey', 'name');\r
+# phpMyAdmin MySQL-Dump
+# version 2.2.1
+# http://phpwizard.net/phpMyAdmin/
+# http://phpmyadmin.sourceforge.net/ (download page)
+#
+# Host: localhost
+# Generation Time: Nov 14, 2001 at 04:39 PM
+# Server version: 3.23.36
+# PHP Version: 4.0.6
+# Database : `moodle`
+# --------------------------------------------------------
+
+#
+# Table structure for table `survey`
+#
+
+CREATE TABLE prefix_survey (
+  id int(10) unsigned NOT NULL auto_increment,
+  course int(10) unsigned NOT NULL default '0',
+  template int(10) unsigned NOT NULL default '0',
+  days smallint(6) NOT NULL default '0',
+  timecreated int(10) unsigned NOT NULL default '0',
+  timemodified int(10) unsigned NOT NULL default '0',
+  name varchar(255) NOT NULL default '',
+  intro text NOT NULL default '',
+  questions varchar(255) NOT NULL default '',
+  PRIMARY KEY  (id), 
+  KEY `course` (`course`)
+) TYPE=MyISAM COMMENT='all surveys';
+
+#
+# Dumping data for table `survey`
+#
+
+INSERT INTO `prefix_survey` (`id`, `course`, `template`, `days`, `timecreated`, `timemodified`, `name`, `intro`, `questions`) VALUES (1, 0, 0, 0, 985017600, 985017600, 'collesaname', 'collesaintro', '25,26,27,28,29,30,43,44');
+INSERT INTO `prefix_survey` (`id`, `course`, `template`, `days`, `timecreated`, `timemodified`, `name`, `intro`, `questions`) VALUES (2, 0, 0, 0, 985017600, 985017600, 'collespname', 'collespintro', '31,32,33,34,35,36,43,44');
+INSERT INTO `prefix_survey` (`id`, `course`, `template`, `days`, `timecreated`, `timemodified`, `name`, `intro`, `questions`) VALUES (3, 0, 0, 0, 985017600, 985017600, 'collesapname', 'collesapintro', '37,38,39,40,41,42,43,44');
+INSERT INTO `prefix_survey` (`id`, `course`, `template`, `days`, `timecreated`, `timemodified`, `name`, `intro`, `questions`) VALUES (4, 0, 0, 0, 985017600, 985017600, 'attlsname', 'attlsintro', '65,67,68');
+INSERT INTO `prefix_survey` (`id`, `course`, `template`, `days`, `timecreated`, `timemodified`, `name`, `intro`, `questions`) VALUES (5, 0, 0, 0, 985017600, 985017600, 'ciqname', 'ciqintro', '69,70,71,72,73');
+
+
+
+#
+# Table structure for table `survey_analysis`
+#
+
+CREATE TABLE prefix_survey_analysis (
+  id int(10) unsigned NOT NULL auto_increment,
+  survey int(10) unsigned NOT NULL default '0',
+  userid int(10) unsigned NOT NULL default '0',
+  notes text NOT NULL default '',
+  PRIMARY KEY  (id),
+  UNIQUE KEY id (id),
+  KEY survey (survey),
+  KEY userid (userid)
+) TYPE=MyISAM;
+
+#
+# Dumping data for table `survey_analysis`
+#
+
+# --------------------------------------------------------
+
+#
+# Table structure for table `survey_answers`
+#
+
+CREATE TABLE prefix_survey_answers (
+  id int(10) unsigned NOT NULL auto_increment,
+  userid int(10) unsigned NOT NULL default '0',
+  survey int(10) unsigned NOT NULL default '0',
+  question int(10) unsigned NOT NULL default '0',
+  time int(10) unsigned NOT NULL default '0',
+  answer1 text NOT NULL default '',
+  answer2 text NOT NULL default '',
+  PRIMARY KEY  (id),
+  UNIQUE KEY id (id),
+  KEY userid (userid),
+  KEY survey (survey),
+  KEY question (question)
+) TYPE=MyISAM;
+
+#
+# Dumping data for table `survey_answers`
+#
+
+# --------------------------------------------------------
+
+#
+# Table structure for table `survey_questions`
+#
+
+CREATE TABLE `prefix_survey_questions` (
+  `id` int(10) unsigned NOT NULL auto_increment,
+  `text` varchar(255) NOT NULL default '',
+  `shorttext` varchar(30) NOT NULL default '',
+  `multi` varchar(100) NOT NULL default '',
+  `intro` varchar(50) NOT NULL default '',
+  `type` tinyint(3) NOT NULL default '0',
+  `options` text,
+  PRIMARY KEY  (`id`)
+) TYPE=MyISAM;
+
+#
+# Dumping data for table `survey_questions`
+#
+
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (1, 'colles1', 'colles1short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (2, 'colles2', 'colles2short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (3, 'colles3', 'colles3short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (4, 'colles4', 'colles4short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (5, 'colles5', 'colles5short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (6, 'colles6', 'colles6short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (7, 'colles7', 'colles7short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (8, 'colles8', 'colles8short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (9, 'colles9', 'colles9short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (10, 'colles10', 'colles10short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (11, 'colles11', 'colles11short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (12, 'colles12', 'colles12short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (13, 'colles13', 'colles13short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (14, 'colles14', 'colles14short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (15, 'colles15', 'colles15short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (16, 'colles16', 'colles16short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (17, 'colles17', 'colles17short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (18, 'colles18', 'colles18short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (19, 'colles19', 'colles19short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (20, 'colles20', 'colles20short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (21, 'colles21', 'colles21short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (22, 'colles22', 'colles22short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (23, 'colles23', 'colles23short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (24, 'colles24', 'colles24short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (25, 'collesm1', 'collesm1short', '1,2,3,4', 'collesmintro', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (26, 'collesm2', 'collesm2short', '5,6,7,8', 'collesmintro', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (27, 'collesm3', 'collesm3short', '9,10,11,12', 'collesmintro', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (28, 'collesm4', 'collesm4short', '13,14,15,16', 'collesmintro', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (29, 'collesm5', 'collesm5short', '17,18,19,20', 'collesmintro', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (30, 'collesm6', 'collesm6short', '21,22,23,24', 'collesmintro', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (31, 'collesm1', 'collesm1short', '1,2,3,4', 'collesmintro', 2, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (32, 'collesm2', 'collesm2short', '5,6,7,8', 'collesmintro', 2, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (33, 'collesm3', 'collesm3short', '9,10,11,12', 'collesmintro', 2, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (34, 'collesm4', 'collesm4short', '13,14,15,16', 'collesmintro', 2, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (35, 'collesm5', 'collesm5short', '17,18,19,20', 'collesmintro', 2, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (36, 'collesm6', 'collesm6short', '21,22,23,24', 'collesmintro', 2, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (37, 'collesm1', 'collesm1short', '1,2,3,4', 'collesmintro', 3, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (38, 'collesm2', 'collesm2short', '5,6,7,8', 'collesmintro', 3, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (39, 'collesm3', 'collesm3short', '9,10,11,12', 'collesmintro', 3, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (40, 'collesm4', 'collesm4short', '13,14,15,16', 'collesmintro', 3, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (41, 'collesm5', 'collesm5short', '17,18,19,20', 'collesmintro', 3, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (42, 'collesm6', 'collesm6short', '21,22,23,24', 'collesmintro', 3, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (43, 'howlong', '', '', '', 1, 'howlongoptions');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (44, 'othercomments', '', '', '', 0, '');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (64, 'attls20', 'attls20short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (58, 'attls14', 'attls14short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (59, 'attls15', 'attls15short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (60, 'attls16', 'attls16short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (61, 'attls17', 'attls17short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (62, 'attls18', 'attls18short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (63, 'attls19', 'attls19short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (56, 'attls12', 'attls12short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (57, 'attls13', 'attls13short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (55, 'attls11', 'attls11short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (54, 'attls10', 'attls10short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (53, 'attls9', 'attls9short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (52, 'attls8', 'attls8short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (51, 'attls7', 'attls7short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (50, 'attls6', 'attls6short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (49, 'attls5', 'attls5short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (48, 'attls4', 'attls4short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (47, 'attls3', 'attls3short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (45, 'attls1', 'attls1short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (46, 'attls2', 'attls2short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (65, 'attlsm1', 'attlsm1', '45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64', 'attlsmintro', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (67, 'attlsm2', 'attlsm2', '63,62,59,57,55,49,52,50,48,47', 'attlsmintro', -1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (68, 'attlsm3', 'attlsm3', '46,54,45,51,60,53,56,58,61,64', 'attlsmintro', -1, 'scaleagree5');
+
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (69, 'ciq1', 'ciq1short', '', '', 0, '');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (70, 'ciq2', 'ciq2short', '', '', 0, '');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (71, 'ciq3', 'ciq3short', '', '', 0, '');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (72, 'ciq4', 'ciq4short', '', '', 0, '');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (73, 'ciq5', 'ciq5short', '', '', 0, '');
+
+
+#
+# Dumping data for table `log_display`
+#
+
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'add', 'survey', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'update', 'survey', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'download', 'survey', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'view form', 'survey', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'view graph', 'survey', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'view report', 'survey', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'submit', 'survey', 'name');
index 105eca6df728804d298514272cb5ece5746b1bbb..ec74b5a277bb33094cdb9d0f3464557f8d45ec8b 100755 (executable)
-rem\r
-rem Table structure for table survey\r
-rem\r
-\r
-drop TABLE prefix_survey;\r
-CREATE TABLE prefix_survey (\r
-  id number(10) primary key,\r
-  course number(10) default '0' not null,\r
-  template number(10) default '0' not null,\r
-  days number(6) default '0' not null,\r
-  timecreated number(10) default '0' not null,\r
-  timemodified number(10) default '0' not null,\r
-  name varchar2(255) default '' not null,\r
-  intro varchar2(1024),\r
-  questions varchar2(255) default NULL\r
-);\r
-\r
-drop sequence p_survey_seq;\r
-create sequence p_survey_seq;\r
-\r
-create or replace trigger p_survey_trig\r
-  before insert on prefix_survey\r
-  referencing new as new_row\r
-  for each row\r
-  begin\r
-    select p_survey_seq.nextval into :new_row.id from dual;\r
-  end;\r
-.\r
-/\r
-\r
-COMMENT on table prefix_survey is 'all surveys';\r
-\r
-INSERT INTO prefix_survey (course, template, days, timecreated, timemodified, name, intro, questions) VALUES (0, 0, 0, 985017600, 985017600, 'collesaname', 'collesaintro', '25,26,27,28,29,30,43,44');\r
-INSERT INTO prefix_survey (course, template, days, timecreated, timemodified, name, intro, questions) VALUES (0, 0, 0, 985017600, 985017600, 'collespname', 'collespintro', '31,32,33,34,35,36,43,44');\r
-INSERT INTO prefix_survey (course, template, days, timecreated, timemodified, name, intro, questions) VALUES (0, 0, 0, 985017600, 985017600, 'collesapname', 'collesapintro', '37,38,39,40,41,42,43,44');\r
-INSERT INTO prefix_survey (course, template, days, timecreated, timemodified, name, intro, questions) VALUES (0, 0, 0, 985017600, 985017600, 'attlsname', 'attlsintro', '65,67,68');\r
-\r
-select * from prefix_survey order by 1,2;\r
-\r
-rem\r
-rem Table structure for table survey_analysis\r
-rem\r
-\r
-drop TABLE prefix_survey_analysis;\r
-CREATE TABLE prefix_survey_analysis (\r
-id number(10) primary key,\r
-survey number(10) default '0' not null,\r
-userid number(10) default '0' not null,\r
-notes varchar2(1024) NOT NULL\r
-\r
-drop sequence p_survey_analysis_seq;\r
-create sequence p_survey_analysis_seq;\r
-\r
-create or replace trigger p_survey_analysis_trig\r
-  before insert on prefix_survey_analysis\r
-  referencing new as new_row\r
-  for each row\r
-  begin\r
-    select p_survey_analysis_seq.nextval into :new_row.id from dual;\r
-  end;\r
-.\r
-/\r
-\r
-);\r
-\r
-comment on table prefix_survey_analysis is 'Survey analysis';\r
-\r
-rem\r
-rem Dumping data for table survey_analysis\r
-rem\r
-\r
-rem --------------------------------------------------------\r
-\r
-rem\r
-rem Table structure for table survey_answers\r
-rem\r
-\r
-drop TABLE prefix_survey_answers;\r
-CREATE TABLE prefix_survey_answers (\r
-id number(10) primary key,\r
-userid number(10) default '0' not null,\r
-survey number(10) default '0' not null,\r
-question number(10) default '0' not null,\r
-time number(10) default NULL,\r
-answer1 varchar2(255) default NULL,\r
-answer2 varchar2(255) default NULL\r
-);\r
-\r
-drop sequence p_survey_answers_seq;\r
-create sequence p_survey_answers_seq;\r
-\r
-create or replace trigger p_survey_answers_trig\r
-before insert on prefix_survey_answers\r
-referencing new as new_row\r
-for each row\r
-begin\r
-  select p_survey_answers_seq.nextval into :new_row.id from dual;\r
-end;\r
-.\r
-/\r
-\r
-\r
-rem\r
-rem Dumping data for table survey_answers\r
-rem\r
-\r
-rem --------------------------------------------------------\r
-\r
-rem\r
-rem Table structure for table survey_questions\r
-rem\r
-\r
-drop TABLE prefix_survey_questions;\r
-CREATE TABLE prefix_survey_questions (\r
-id number(10) primary key,\r
-text varchar2(255) default '' not null,\r
-shorttext varchar2(30) default '' not null,\r
-multi varchar2(100) default '' not null,\r
-intro varchar2(50) default NULL,\r
-type number(3) default '0' not null,\r
-options varchar2(1024)\r
-);\r
-\r
-comment on table prefix_survey_questions is 'structure for survey_questions';\r
-\r
-drop sequence p_survey_questions_seq;\r
-create sequence p_survey_questions_seq;\r
-\r
-create or replace trigger p_survey_questions_trig\r
-  before insert on prefix_survey_questions\r
-  referencing new as new_row\r
-  for each row\r
-  begin\r
-    select p_survey_questions_seq.nextval into :new_row.id from dual;\r
-  end;\r
-.\r
-/\r
-\r
-rem\r
-rem Dumping data for table survey_questions\r
-rem\r
-\r
-INSERT INTO prefix_survey_questions ( text, shorttext, multi, intro, type, options) VALUES ('colles1', 'colles1short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles2', 'colles2short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles3', 'colles3short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles4', 'colles4short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles5', 'colles5short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles6', 'colles6short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles7', 'colles7short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles8', 'colles8short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles9', 'colles9short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ( 'colles10', 'colles10short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ( 'colles11', 'colles11short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ( 'colles12', 'colles12short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ( 'colles13', 'colles13short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles14', 'colles14short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles15', 'colles15short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles16', 'colles16short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles17', 'colles17short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles18', 'colles18short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles19', 'colles19short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles20', 'colles20short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles21', 'colles21short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles22', 'colles22short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles23', 'colles23short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles24', 'colles24short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm1', 'collesm1short', '1,2,3,4', 'collesmintro', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm2', 'collesm2short', '5,6,7,8', 'collesmintro', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm3', 'collesm3short', '9,10,11,12', 'collesmintro', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm4', 'collesm4short', '13,14,15,16', 'collesmintro', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm5', 'collesm5short', '17,18,19,20', 'collesmintro', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm6', 'collesm6short', '21,22,23,24', 'collesmintro', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm1', 'collesm1short', '1,2,3,4', 'collesmintro', 2, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm2', 'collesm2short', '5,6,7,8', 'collesmintro', 2, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm3', 'collesm3short', '9,10,11,12', 'collesmintro', 2, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm4', 'collesm4short', '13,14,15,16', 'collesmintro', 2, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm5', 'collesm5short', '17,18,19,20', 'collesmintro', 2, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm6', 'collesm6short', '21,22,23,24', 'collesmintro', 2, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm1', 'collesm1short', '1,2,3,4', 'collesmintro', 3, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm2', 'collesm2short', '5,6,7,8', 'collesmintro', 3, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm3', 'collesm3short', '9,10,11,12', 'collesmintro', 3, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm4', 'collesm4short', '13,14,15,16', 'collesmintro', 3, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm5', 'collesm5short', '17,18,19,20', 'collesmintro', 3, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm6', 'collesm6short', '21,22,23,24', 'collesmintro', 3, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('howlong', '1', '1', '1', 1, 'howlongoptions');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('othercomments', '1', '1', '1', 0, '');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls20', 'attls20short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls14', 'attls14short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls15', 'attls15short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls16', 'attls16short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls17', 'attls17short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls18', 'attls18short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls19', 'attls19short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls12', 'attls12short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls13', 'attls13short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls11', 'attls11short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls10', 'attls10short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls9', 'attls9short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls8', 'attls8short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls7', 'attls7short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls6', 'attls6short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls5', 'attls5short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls4', 'attls4short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls3', 'attls3short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls1', 'attls1short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls2', 'attls2short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attlsm1', 'attlsm1', '45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64', 'attlsmintro', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attlsm2', 'attlsm2', '63,62,59,57,55,49,52,50,48,47', 'attlsmintro', -1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attlsm3', 'attlsm3', '46,54,45,51,60,53,56,58,61,64', 'attlsmintro', -1, 'scaleagree5');\r
-\r
-rem select * from prefix_survey_questions where text like 'colles%' or text like 'attlsm%'\r
-\r
-col id format 99\r
-select * from prefix_survey_questions;\r
-\r
-\r
-rem\r
-rem Dumping data for table log_display\r
-rem\r
-\r
-delete from prefix_log_display where module = 'survey';\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'download', 'survey', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'view form', 'survey', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'view graph', 'survey', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'view report', 'survey', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'submit', 'survey', 'name');\r
-select * from prefix_log_display where module = 'survey';\r
+rem
+rem Table structure for table survey
+rem
+
+drop TABLE prefix_survey;
+CREATE TABLE prefix_survey (
+  id number(10) primary key,
+  course number(10) default '0' not null,
+  template number(10) default '0' not null,
+  days number(6) default '0' not null,
+  timecreated number(10) default '0' not null,
+  timemodified number(10) default '0' not null,
+  name varchar2(255) default '' not null,
+  intro varchar2(1024),
+  questions varchar2(255) default NULL
+);
+
+drop sequence p_survey_seq;
+create sequence p_survey_seq;
+
+create or replace trigger p_survey_trig
+  before insert on prefix_survey
+  referencing new as new_row
+  for each row
+  begin
+    select p_survey_seq.nextval into :new_row.id from dual;
+  end;
+.
+/
+
+COMMENT on table prefix_survey is 'all surveys';
+
+INSERT INTO prefix_survey (course, template, days, timecreated, timemodified, name, intro, questions) VALUES (0, 0, 0, 985017600, 985017600, 'collesaname', 'collesaintro', '25,26,27,28,29,30,43,44');
+INSERT INTO prefix_survey (course, template, days, timecreated, timemodified, name, intro, questions) VALUES (0, 0, 0, 985017600, 985017600, 'collespname', 'collespintro', '31,32,33,34,35,36,43,44');
+INSERT INTO prefix_survey (course, template, days, timecreated, timemodified, name, intro, questions) VALUES (0, 0, 0, 985017600, 985017600, 'collesapname', 'collesapintro', '37,38,39,40,41,42,43,44');
+INSERT INTO prefix_survey (course, template, days, timecreated, timemodified, name, intro, questions) VALUES (0, 0, 0, 985017600, 985017600, 'attlsname', 'attlsintro', '65,67,68');
+
+select * from prefix_survey order by 1,2;
+
+rem
+rem Table structure for table survey_analysis
+rem
+
+drop TABLE prefix_survey_analysis;
+CREATE TABLE prefix_survey_analysis (
+id number(10) primary key,
+survey number(10) default '0' not null,
+userid number(10) default '0' not null,
+notes varchar2(1024) NOT NULL
+
+drop sequence p_survey_analysis_seq;
+create sequence p_survey_analysis_seq;
+
+create or replace trigger p_survey_analysis_trig
+  before insert on prefix_survey_analysis
+  referencing new as new_row
+  for each row
+  begin
+    select p_survey_analysis_seq.nextval into :new_row.id from dual;
+  end;
+.
+/
+
+);
+
+comment on table prefix_survey_analysis is 'Survey analysis';
+
+rem
+rem Dumping data for table survey_analysis
+rem
+
+rem --------------------------------------------------------
+
+rem
+rem Table structure for table survey_answers
+rem
+
+drop TABLE prefix_survey_answers;
+CREATE TABLE prefix_survey_answers (
+id number(10) primary key,
+userid number(10) default '0' not null,
+survey number(10) default '0' not null,
+question number(10) default '0' not null,
+time number(10) default NULL,
+answer1 varchar2(255) default NULL,
+answer2 varchar2(255) default NULL
+);
+
+drop sequence p_survey_answers_seq;
+create sequence p_survey_answers_seq;
+
+create or replace trigger p_survey_answers_trig
+before insert on prefix_survey_answers
+referencing new as new_row
+for each row
+begin
+  select p_survey_answers_seq.nextval into :new_row.id from dual;
+end;
+.
+/
+
+
+rem
+rem Dumping data for table survey_answers
+rem
+
+rem --------------------------------------------------------
+
+rem
+rem Table structure for table survey_questions
+rem
+
+drop TABLE prefix_survey_questions;
+CREATE TABLE prefix_survey_questions (
+id number(10) primary key,
+text varchar2(255) default '' not null,
+shorttext varchar2(30) default '' not null,
+multi varchar2(100) default '' not null,
+intro varchar2(50) default NULL,
+type number(3) default '0' not null,
+options varchar2(1024)
+);
+
+comment on table prefix_survey_questions is 'structure for survey_questions';
+
+drop sequence p_survey_questions_seq;
+create sequence p_survey_questions_seq;
+
+create or replace trigger p_survey_questions_trig
+  before insert on prefix_survey_questions
+  referencing new as new_row
+  for each row
+  begin
+    select p_survey_questions_seq.nextval into :new_row.id from dual;
+  end;
+.
+/
+
+rem
+rem Dumping data for table survey_questions
+rem
+
+INSERT INTO prefix_survey_questions ( text, shorttext, multi, intro, type, options) VALUES ('colles1', 'colles1short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles2', 'colles2short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles3', 'colles3short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles4', 'colles4short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles5', 'colles5short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles6', 'colles6short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles7', 'colles7short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles8', 'colles8short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles9', 'colles9short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ( 'colles10', 'colles10short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ( 'colles11', 'colles11short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ( 'colles12', 'colles12short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ( 'colles13', 'colles13short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles14', 'colles14short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles15', 'colles15short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles16', 'colles16short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles17', 'colles17short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles18', 'colles18short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles19', 'colles19short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles20', 'colles20short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles21', 'colles21short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles22', 'colles22short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles23', 'colles23short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles24', 'colles24short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm1', 'collesm1short', '1,2,3,4', 'collesmintro', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm2', 'collesm2short', '5,6,7,8', 'collesmintro', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm3', 'collesm3short', '9,10,11,12', 'collesmintro', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm4', 'collesm4short', '13,14,15,16', 'collesmintro', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm5', 'collesm5short', '17,18,19,20', 'collesmintro', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm6', 'collesm6short', '21,22,23,24', 'collesmintro', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm1', 'collesm1short', '1,2,3,4', 'collesmintro', 2, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm2', 'collesm2short', '5,6,7,8', 'collesmintro', 2, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm3', 'collesm3short', '9,10,11,12', 'collesmintro', 2, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm4', 'collesm4short', '13,14,15,16', 'collesmintro', 2, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm5', 'collesm5short', '17,18,19,20', 'collesmintro', 2, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm6', 'collesm6short', '21,22,23,24', 'collesmintro', 2, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm1', 'collesm1short', '1,2,3,4', 'collesmintro', 3, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm2', 'collesm2short', '5,6,7,8', 'collesmintro', 3, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm3', 'collesm3short', '9,10,11,12', 'collesmintro', 3, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm4', 'collesm4short', '13,14,15,16', 'collesmintro', 3, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm5', 'collesm5short', '17,18,19,20', 'collesmintro', 3, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm6', 'collesm6short', '21,22,23,24', 'collesmintro', 3, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('howlong', '1', '1', '1', 1, 'howlongoptions');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('othercomments', '1', '1', '1', 0, '');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls20', 'attls20short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls14', 'attls14short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls15', 'attls15short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls16', 'attls16short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls17', 'attls17short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls18', 'attls18short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls19', 'attls19short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls12', 'attls12short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls13', 'attls13short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls11', 'attls11short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls10', 'attls10short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls9', 'attls9short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls8', 'attls8short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls7', 'attls7short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls6', 'attls6short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls5', 'attls5short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls4', 'attls4short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls3', 'attls3short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls1', 'attls1short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls2', 'attls2short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attlsm1', 'attlsm1', '45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64', 'attlsmintro', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attlsm2', 'attlsm2', '63,62,59,57,55,49,52,50,48,47', 'attlsmintro', -1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attlsm3', 'attlsm3', '46,54,45,51,60,53,56,58,61,64', 'attlsmintro', -1, 'scaleagree5');
+
+rem select * from prefix_survey_questions where text like 'colles%' or text like 'attlsm%'
+
+col id format 99
+select * from prefix_survey_questions;
+
+
+rem
+rem Dumping data for table log_display
+rem
+
+delete from prefix_log_display where module = 'survey';
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'download', 'survey', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'view form', 'survey', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'view graph', 'survey', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'view report', 'survey', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'submit', 'survey', 'name');
+select * from prefix_log_display where module = 'survey';
index b8ccf2a9ebc3a9ddbda0e970c1650dee658c7306..e47a4da724aca0927ef584d887969383e23b108f 100644 (file)
-<?php\r
-\r
-////////////////////////////////////////////////////////////////////////////\r
-/// Blackboard 6.x Format\r
-///\r
-/// This Moodle class provides all functions necessary to import and export\r
-///\r
-///\r
-////////////////////////////////////////////////////////////////////////////\r
-\r
-// Based on default.php, included by ../import.php\r
-\r
-require_once ("$CFG->libdir/xmlize.php");\r
-\r
-class qformat_blackboard_6 extends qformat_default {\r
-    function provide_import() {\r
-        return true;\r
-    }\r
-    \r
-    \r
-    //Function to check and create the needed dir to unzip file to\r
-    function check_and_create_import_dir($unique_code) {\r
-\r
-        global $CFG; \r
-\r
-        $status = $this->check_dir_exists($CFG->dataroot."/temp",true);\r
-        if ($status) {\r
-            $status = $this->check_dir_exists($CFG->dataroot."/temp/bbquiz_import",true);\r
-        }\r
-        if ($status) {\r
-            $status = $this->check_dir_exists($CFG->dataroot."/temp/bbquiz_import/".$unique_code,true);\r
-        }\r
-        \r
-        return $status;\r
-    }\r
-    \r
-    function clean_temp_dir($dir='') {\r
-        // for now we will just say everything happened okay note \r
-        // that a mess may be piling up in $CFG->dataroot/temp/bbquiz_import\r
-        return true;\r
-        \r
-        if ($dir == '') {\r
-            $dir = $this->temp_dir;   \r
-        }\r
-        $slash = "/";\r
-\r
-        // Create arrays to store files and directories\r
-        $dir_files      = array();\r
-        $dir_subdirs    = array();\r
-\r
-        // Make sure we can delete it\r
-        chmod($dir, 0777);\r
-\r
-        if ((($handle = opendir($dir))) == FALSE) {\r
-            // The directory could not be opened\r
-            return false;\r
-        }\r
-\r
-        // Loop through all directory entries, and construct two temporary arrays containing files and sub directories\r
-        while($entry = readdir($handle)) {\r
-            if (is_dir($dir. $slash .$entry) && $entry != ".." && $entry != ".") {\r
-                $dir_subdirs[] = $dir. $slash .$entry;\r
-            }\r
-            else if ($entry != ".." && $entry != ".") {\r
-                $dir_files[] = $dir. $slash .$entry;\r
-            }\r
-        }\r
-\r
-        // Delete all files in the curent directory return false and halt if a file cannot be removed\r
-        for($i=0; $i<count($dir_files); $i++) {\r
-            chmod($dir_files[$i], 0777);\r
-            if (((unlink($dir_files[$i]))) == FALSE) {\r
-                return false;\r
-            }\r
-        }\r
-\r
-        // Empty sub directories and then remove the directory\r
-        for($i=0; $i<count($dir_subdirs); $i++) {\r
-            chmod($dir_subdirs[$i], 0777);\r
-            if ($this->clean_temp_dir($dir_subdirs[$i]) == FALSE) {\r
-                return false;\r
-            }\r
-            else {\r
-                if (rmdir($dir_subdirs[$i]) == FALSE) {\r
-                return false;\r
-                }\r
-            }\r
-        }\r
-\r
-        // Close directory\r
-        closedir($handle);\r
-        if (rmdir($this->temp_dir) == FALSE) {\r
-            return false;    \r
-        }\r
-        // Success, every thing is gone return true\r
-        return true;\r
-    }\r
-    \r
-    //Function to check if a directory exists and, optionally, create it\r
-    function check_dir_exists($dir,$create=false) {\r
-\r
-        global $CFG; \r
-\r
-        $status = true;\r
-        if(!is_dir($dir)) {\r
-            if (!$create) {\r
-                $status = false;\r
-            } else {\r
-                umask(0000);\r
-                $status = mkdir ($dir,$CFG->directorypermissions);\r
-            }\r
-        }\r
-        return $status;\r
-    }\r
-\r
-    function importpostprocess() {\r
-    /// Does any post-processing that may be desired\r
-    /// Argument is a simple array of question ids that \r
-    /// have just been added.\r
-    \r
-        // need to clean up temporary directory\r
-        return $this->clean_temp_dir();\r
-    }\r
-\r
-    function copy_file_to_course($filename) {\r
-        global $CFG;\r
-        global $course;\r
-        $filename = str_replace('\\','/',$filename);\r
-        $fullpath = $this->temp_dir.'/res00001/'.$filename;\r
-        $basename = basename($filename);\r
-    \r
-        $copy_to = $CFG->dataroot.'/'.$course->id.'/bb_import';\r
-        \r
-        if ($this->check_dir_exists($copy_to,true)) {\r
-            if(is_readable($fullpath)) {\r
-                $copy_to.= '/'.$basename;\r
-                if (!copy($fullpath, $copy_to)) {\r
-                    return false;\r
-                }\r
-                else {\r
-                    return $copy_to;\r
-                }\r
-            }\r
-        }\r
-        else {\r
-            return false;   \r
-        }\r
-    }\r
-\r
-    function readdata($filename) {\r
-    /// Returns complete file with an array, one item per line\r
-        global $CFG;\r
-        \r
-        $unique_code = time();\r
-        $temp_dir = $CFG->dataroot."/temp/bbquiz_import/".$unique_code;\r
-        $this->temp_dir = $temp_dir;\r
-        if ($this->check_and_create_import_dir($unique_code)) {\r
-            if(is_readable($filename)) {\r
-                if (!copy($filename, "$temp_dir/bboard.zip")) {\r
-                    error("Could not copy backup file");\r
-                }\r
-                if(unzip_file("$temp_dir/bboard.zip", '', false)) {\r
-                    // assuming that the information is in res0001.dat\r
-                    // after looking at 6 examples this was always the case\r
-                    $q_file = "$temp_dir/res00001.dat";\r
-                    if (is_file($q_file)) {\r
-                        if (is_readable($q_file)) {\r
-                            $filearray = file($q_file);\r
-                            /// Check for Macintosh OS line returns (ie file on one line), and fix\r
-                            if (ereg("\r", $filearray[0]) AND !ereg("\n", $filearray[0])) {\r
-                                return explode("\r", $filearray[0]);\r
-                            } else {\r
-                                return $filearray;\r
-                            }\r
-                            return false;        \r
-                        }\r
-                    }\r
-                    else {\r
-                        error("Could not find question data file in zip");   \r
-                    }\r
-                }\r
-                else {\r
-                    print "filename: $filename<br />tempdir: $temp_dir <br />";\r
-                    error("Could not unzip file.");   \r
-                }\r
-            }\r
-            else {\r
-                error ("Could not read uploaded file");   \r
-            }\r
-        }\r
-        else {\r
-            error("Could not create temporary directory");   \r
-        }\r
-    }\r
-        \r
-    function save_question_options($question) {\r
-        return true; \r
-    }\r
-    \r
-    \r
-    \r
-  function readquestions ($lines) {\r
-    /// Parses an array of lines into an array of questions,\r
-    /// where each item is a question object as defined by\r
-    /// readquestion(). \r
-\r
-    $text = implode($lines, " ");\r
-    $xml = xmlize($text, 0);\r
-\r
-    $raw_questions = $xml['questestinterop']['#']['assessment'][0]['#']['section'][0]['#']['item'];\r
-    $questions = array();\r
-\r
-    foreach($raw_questions as $quest) {\r
-        $question = $this->create_raw_question($quest);\r
-\r
-        switch($question->qtype) {\r
-            case "Matching":\r
-                $this->process_matching($question, $questions);\r
-                break;\r
-            case "Multiple Choice":\r
-                $this->process_mc($question, $questions);\r
-                break;\r
-            case "Essay":\r
-                $this->process_essay($question, $questions);\r
-                break;\r
-            case "Multiple Answer":\r
-                $this->process_ma($question, $questions);\r
-                break;\r
-            case "True/False":\r
-                $this->process_tf($question, $questions);\r
-                break;\r
-            case 'Fill in the Blank':\r
-                $this->process_fblank($question, $questions);\r
-                break;\r
-            default:\r
-                print "Unknown or unhandled question type: \"$question->qtype\"<br />";\r
-                break;\r
-        }\r
-\r
-    }\r
-    return $questions;\r
-  }\r
-\r
-\r
-// creates a cleaner object to deal with for processing into moodle\r
-// the object created is NOT a moodle question object\r
-function create_raw_question($quest) {\r
-    \r
-    $question = $this->defaultquestion();\r
-    $question->qtype = $quest['#']['itemmetadata'][0]['#']['bbmd_questiontype'][0]['#'];\r
-    $presentation->blocks = $quest['#']['presentation'][0]['#']['flow'][0]['#']['flow'];\r
-\r
-    foreach($presentation->blocks as $pblock) {\r
-        \r
-        $block = NULL;\r
-        $block->type = $pblock['@']['class'];\r
-\r
-        switch($block->type) {\r
-            case 'QUESTION_BLOCK':\r
-                $sub_blocks = $pblock['#']['flow'];\r
-                foreach($sub_blocks as $sblock) {\r
-                    //echo "Calling process_block from line 263<br>";\r
-                    $this->process_block($sblock, $block);  \r
-                }\r
-                break;\r
-\r
-            case 'RESPONSE_BLOCK':\r
-                $choices = NULL;\r
-                switch($question->qtype) {\r
-                    case 'Matching':\r
-                        $bb_subquestions = $pblock['#']['flow'];\r
-                        $sub_questions = array();\r
-                        foreach($bb_subquestions as $bb_subquestion) {\r
-                            $sub_question = NULL;\r
-                            $sub_question->ident = $bb_subquestion['#']['response_lid'][0]['@']['ident'];\r
-                            $this->process_block($bb_subquestion['#']['flow'][0], $sub_question);\r
-                            $bb_choices = $bb_subquestion['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'][0]['#']['response_label'];\r
-                            $choices = array();\r
-                            $this->process_choices($bb_choices, $choices);\r
-                            $sub_question->choices = $choices;\r
-                            if (!isset($block->subquestions)) {\r
-                                $block->subquestions = array();\r
-                            }\r
-                            $block->subquestions[] = $sub_question;\r
-                        }\r
-                        break;\r
-                    case 'Multiple Answer':\r
-                        $bb_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'];\r
-                        $choices = array();\r
-                        $this->process_choices($bb_choices, $choices);\r
-                        $block->choices = $choices;\r
-                        break;\r
-                    case 'Essay':\r
-                        // Doesn't apply since the user responds with text input\r
-                        break;\r
-                    case 'Multiple Choice':\r
-                        $mc_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'];\r
-                            foreach($mc_choices as $mc_choice) {\r
-                            $choices = NULL;\r
-                            $choices = $this->process_block($mc_choice, $choices);\r
-                            $block->choices[] = $choices;             \r
-                        }\r
-                        break;\r
-                    case 'Fill in the Blank':\r
-                        // do nothing?\r
-                        break;\r
-                    default:\r
-                        $bb_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'][0]['#']['response_label'];\r
-                        $choices = array();\r
-                        $this->process_choices($bb_choices, $choices);\r
-                        $block->choices = $choices;\r
-                }\r
-                break;\r
-            case 'RIGHT_MATCH_BLOCK':\r
-                $matching_answerset = $pblock['#']['flow'];\r
-                $answerset = array();\r
-                foreach($matching_answerset as $answer) {\r
-                    $this->process_block($answer, $bb_answer);\r
-                    $answerset[] = $bb_answer;\r
-                }\r
-                $block->matching_answerset = $answerset;\r
-                break;\r
-            default:\r
-                print "UNHANDLED PRESENTATION BLOCK";\r
-                break;\r
-        }\r
-        $question->{$block->type} = $block;\r
-    }\r
-    \r
-    // determine response processing \r
-    // there is a section called 'outcomes' that I don't know what to do with\r
-    $resprocessing = $quest['#']['resprocessing'];\r
-    $respconditions = $resprocessing[0]['#']['respcondition'];\r
-    $reponses = array();\r
-    if ($question->qtype == 'Matching') {\r
-        $this->process_matching_responses($respconditions, $responses);\r
-    }\r
-    else {\r
-        $this->process_responses($respconditions, $responses);\r
-    }\r
-    $question->responses = $responses;\r
-    $feedbackset = $quest['#']['itemfeedback'];\r
-    $feedbacks = array();\r
-    $this->process_feedback($feedbackset, $feedbacks);\r
-    $question->feedback = $feedbacks;\r
-    return $question;\r
-}\r
-\r
-function process_block($cur_block, &$block) {\r
-    global $course, $CFG;\r
-\r
-    $cur_type = $cur_block['@']['class'];\r
-    switch($cur_type) {\r
-        case 'FORMATTED_TEXT_BLOCK':\r
-            $block->text = $this->strip_applet_tags_get_mathml($cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#']); \r
-            break;\r
-        case 'FILE_BLOCK':\r
-            //revisit this to make sure it is working correctly\r
-            // Commented out ['matapplication']..., etc. because I \r
-            // noticed that when I imported a new Blackboard 6 file\r
-            // and printed out the block, the tree did not extend past ['material'][0]['#'] - CT 8/3/06\r
-            $block->file = $cur_block['#']['material'][0]['#'];//['matapplication'][0]['@']['uri'];\r
-            if ($block->file != '') {\r
-                // if we have a file copy it to the course dir and adjust its name to be visible over the web.\r
-                $block->file = $this->copy_file_to_course($block->file);\r
-                $block->file = $CFG->wwwroot.'/file.php/'.$course->id.'/bb_import/'.basename($block->file);\r
-            }\r
-            break;\r
-        case 'Block':\r
-            if (isset($cur_block['#']['material'][0]['#']['mattext'][0]['#'])) {\r
-            $block->text = $cur_block['#']['material'][0]['#']['mattext'][0]['#'];\r
-            }\r
-            else if (isset($cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#'])) {\r
-                $block->text = $cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#'];\r
-            }\r
-            else if (isset($cur_block['#']['response_label'])) {\r
-                // this is a response label block\r
-                $sub_blocks = $cur_block['#']['response_label'][0];\r
-                if(!isset($block->ident)) {\r
-                    if(isset($sub_blocks['@']['ident'])) {\r
-                        $block->ident = $sub_blocks['@']['ident'];\r
-                    }\r
-                }\r
-                foreach($sub_blocks['#']['flow_mat'] as $sub_block) {\r
-                    $this->process_block($sub_block, $block);   \r
-                }\r
-            }\r
-            else {\r
-                if (isset($cur_block['#']['flow_mat']) || isset($cur_block['#']['flow'])) {\r
-                    if (isset($cur_block['#']['flow_mat'])) {\r
-                        $sub_blocks = $cur_block['#']['flow_mat'];\r
-                    }\r
-                    elseif (isset($cur_block['#']['flow'])) {\r
-                        $sub_blocks = $cur_block['#']['flow'];\r
-                    }\r
-                   foreach ($sub_blocks as $sblock) {\r
-                        // this will recursively grab the sub blocks which should be of one of the other types\r
-                        $this->process_block($sblock, $block);\r
-                    }\r
-                }\r
-            }\r
-            break;\r
-        case 'LINK_BLOCK':\r
-            // not sure how this should be included\r
-            if (!empty($cur_block['#']['material'][0]['#']['mattext'][0]['@']['uri'])) {\r
-                $block->link = $cur_block['#']['material'][0]['#']['mattext'][0]['@']['uri'];\r
-            }\r
-            else {\r
-               $block->link = '';\r
-            }\r
-            break;    \r
-    }    \r
-    return $block;\r
-}\r
-\r
-function process_choices($bb_choices, &$choices) {\r
-    foreach($bb_choices as $choice) {\r
-            if (isset($choice['@']['ident'])) {\r
-            $cur_choice = $choice['@']['ident'];\r
-        }\r
-        else { //for multiple answer\r
-            $cur_choice = $choice['#']['response_label'][0];//['@']['ident'];\r
-        }\r
-        if (isset($choice['#']['flow_mat'][0])) { //for multiple answer\r
-            $cur_block = $choice['#']['flow_mat'][0];\r
-            // Reset $cur_choice to NULL because process_block is expecting an object\r
-            // for the second argument and not a string, which is what is was set as\r
-            // originally - CT 8/7/06\r
-            $cur_choice = null; \r
-            $this->process_block($cur_block, $cur_choice);\r
-        }\r
-        elseif (isset($choice['#']['response_label'])) {\r
-            // Reset $cur_choice to NULL because process_block is expecting an object\r
-            // for the second argument and not a string, which is what is was set as\r
-            // originally - CT 8/7/06\r
-            $cur_choice = null; \r
-            $this->process_block($choice, $cur_choice);\r
-        }\r
-        $choices[] = $cur_choice;\r
-    }    \r
-}\r
-\r
-function process_matching_responses($bb_responses, &$responses) {\r
-    foreach($bb_responses as $bb_response) {\r
-        $response = NULL;\r
-        if (isset($bb_response['#']['conditionvar'][0]['#']['varequal'])) {\r
-            $response->correct = $bb_response['#']['conditionvar'][0]['#']['varequal'][0]['#'];\r
-            $response->ident = $bb_response['#']['conditionvar'][0]['#']['varequal'][0]['@']['respident'];\r
-        }\r
-        else {\r
-            $response->correct =  'Broken Question?';\r
-            $response->ident = 'Broken Question?';\r
-        }\r
-        $response->feedback = $bb_response['#']['displayfeedback'][0]['@']['linkrefid'];\r
-        $responses[] = $response;\r
-    }\r
-}\r
-\r
-function process_responses($bb_responses, &$responses) {\r
-    foreach($bb_responses as $bb_response) {\r
-        //Added this line to instantiate $response.\r
-        // Without instantiating the $response variable, the same object\r
-        // gets added to the array\r
-        $response = null;\r
-        if (isset($bb_response['@']['title'])) {\r
-                $response->title = $bb_response['@']['title'];    \r
-            }\r
-            else {\r
-                $reponse->title = $bb_response['#']['displayfeedback'][0]['@']['linkrefid'];\r
-            }\r
-            $reponse->ident = array();\r
-            if (isset($bb_response['#']['conditionvar'][0]['#'])){//['varequal'][0]['#'])) {\r
-                $response->ident[0] = $bb_response['#']['conditionvar'][0]['#'];//['varequal'][0]['#'];    \r
-            }\r
-            else if (isset($bb_response['#']['conditionvar'][0]['#']['other'][0]['#'])) {\r
-                $response->ident[0] = $bb_response['#']['conditionvar'][0]['#']['other'][0]['#'];  \r
-            }\r
-            \r
-            if (isset($bb_response['#']['conditionvar'][0]['#']['and'])){//[0]['#'])) {\r
-                $responseset = $bb_response['#']['conditionvar'][0]['#']['and'];//[0]['#']['varequal'];\r
-                foreach($responseset as $rs) {\r
-                    $response->ident[] = $rs['#'];\r
-                    if(!isset($response->feedback) and isset( $rs['@'] ) ) {\r
-                        $response->feedback = $rs['@']['respident'];\r
-                    }    \r
-                }\r
-            }\r
-            else {\r
-                $response->feedback = $bb_response['#']['displayfeedback'][0]['@']['linkrefid'];   \r
-            }\r
-\r
-            // determine what point value to give response\r
-            if (isset($bb_response['#']['setvar'])) {\r
-                switch ($bb_response['#']['setvar'][0]['#']) {\r
-                    case "SCORE.max":\r
-                        $response->fraction = 1;\r
-                        break;\r
-                    default:\r
-                        // I have only seen this being 0 or unset  \r
-                        // there are probably fractional values of SCORE.max, but I'm not sure what they look like\r
-                        $response->fraction = 0;\r
-                        break;\r
-                }\r
-            }\r
-            else {\r
-               // just going to assume this is the case this is probably not correct.\r
-               $response->fraction = 0;\r
-            }\r
-            \r
-            $responses[] = $response;\r
-        }\r
-}\r
-\r
-function process_feedback($feedbackset, &$feedbacks) {\r
-    foreach($feedbackset as $bb_feedback) {\r
-        // Added line $feedback=null so that $feedback does not get reused in the loop\r
-        // and added the the $feedbacks[] array multiple times\r
-        $feedback = null;  \r
-        $feedback->ident = $bb_feedback['@']['ident'];\r
-        if (isset($bb_feedback['#']['flow_mat'][0])) {\r
-            $this->process_block($bb_feedback['#']['flow_mat'][0], $feedback);\r
-        }\r
-        elseif (isset($bb_feedback['#']['solution'][0]['#']['solutionmaterial'][0]['#']['flow_mat'][0])) {\r
-            $this->process_block($bb_feedback['#']['solution'][0]['#']['solutionmaterial'][0]['#']['flow_mat'][0], $feedback);\r
-        }\r
-        $feedbacks[] = $feedback;\r
-    }\r
-}\r
-\r
-//----------------------------------------\r
-// Process True / False Questions\r
-//----------------------------------------\r
-function process_tf($quest, &$questions) {\r
-    $question = $this->defaultquestion();\r
-\r
-    $question->qtype = TRUEFALSE;\r
-    $question->defaultgrade = 1;\r
-    $question->single = 1; // Only one answer is allowed\r
-    $question->image = ""; // No images with this format\r
-    $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);\r
-    // put name in question object\r
-    $question->name = $question->questiontext;\r
-\r
-    // first choice is true, second is false.\r
-    if ($quest->responses[0]->fraction == 1) {\r
-        $correct = true;    \r
-    }\r
-    else {\r
-        $correct = false;   \r
-    }\r
-    \r
-    foreach($quest->feedback as $fb) {\r
-        $fback->{$fb->ident} = $fb->text;   \r
-    }\r
-    \r
-    if ($correct) {  // true is correct\r
-        $question->answer = 1;\r
-        $question->feedbacktrue = addslashes($fback->correct);\r
-        $question->feedbackfalse = addslashes($fback->incorrect);\r
-    } else {  // false is correct\r
-        $question->answer = 0;\r
-        $question->feedbacktrue = addslashes($fback->incorrect);\r
-        $question->feedbackfalse = addslashes($fback->correct);\r
-    }\r
-    $questions[] = $question;\r
-}\r
-\r
-\r
-//----------------------------------------\r
-// Process Fill in the Blank\r
-//----------------------------------------\r
-function process_fblank($quest, &$questions) {\r
-    $question = $this->defaultquestion();\r
-    $question->qtype = SHORTANSWER;\r
-    $question->defaultgrade = 1;\r
-    $question->single = 1;\r
-    $question->usecase = 0;\r
-    $question->image = '';\r
-    $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);\r
-    $question->name = $question->questiontext;\r
-    $answers = array();\r
-    $fractions = array();\r
-    $feedbacks = array();\r
-    \r
-    // extract the feedback\r
-    $feedback = array();\r
-    foreach($quest->feedback as $fback) {\r
-        if (isset($fback->ident)) {\r
-            if ($fback->ident == 'correct' || $fback->ident == 'incorrect') {\r
-                $feedback[$fback->ident] = $fback->text;\r
-            }\r
-        }\r
-    }\r
-    \r
-    foreach($quest->responses as $response) {\r
-        if(isset($response->title)) {\r
-            if (isset($response->ident[0]['varequal'][0]['#'])) {\r
-                //for BB Fill in the Blank, only interested in correct answers\r
-                if ($response->feedback = 'correct') {\r
-                    $answers[] = addslashes($response->ident[0]['varequal'][0]['#']);\r
-                    $fractions[] = 1;\r
-                    if (isset($feedback['correct'])) {\r
-                        $feedbacks[] = addslashes($feedback['correct']);\r
-                    }\r
-                    else {\r
-                        $feedbacks[] = '';\r
-                    }\r
-                }\r
-            }\r
-  \r
-        }\r
-    }\r
-\r
-    //Adding catchall to so that students can see feedback for incorrect answers when they enter something the \r
-    //instructor did not enter\r
-    $answers[] = '*';\r
-    $fractions[] = 0;\r
-    if (isset($feedback['incorrect'])) {\r
-        $feedbacks[] = addslashes($feedback['incorrect']);\r
-    }\r
-    else {\r
-        $feedbacks[] = '';\r
-    }\r
-    \r
-    $question->answer = $answers;\r
-    $question->fraction = $fractions;\r
-    $question->feedback = $feedbacks; // Changed to assign $feedbacks to $question->feedback instead of\r
-\r
-    if (!empty($question)) {\r
-        $questions[] = $question;\r
-    }\r
-\r
-}\r
-\r
-//----------------------------------------\r
-// Process Multiple Choice Questions\r
-//----------------------------------------\r
-function process_mc($quest, &$questions) {\r
-    $question = $this->defaultquestion();\r
-    $question->qtype = MULTICHOICE;\r
-    $question->defaultgrade = 1;\r
-    $question->single = 1;\r
-    $question->image = "";\r
-    $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);\r
-    $question->name = $question->questiontext;\r
-    \r
-    $feedback = array();\r
-    foreach($quest->feedback as $fback) {\r
-        $feedback[$fback->ident] = addslashes($fback->text);\r
-    }\r
\r
-    foreach($quest->responses as $response) {\r
-        if (isset($response->title)) {\r
-            if ($response->title == 'correct') {\r
-                // only one answer possible for this qtype so first index is correct answer\r
-                $correct = $response->ident[0]['varequal'][0]['#'];\r
-            }\r
-        }\r
-        else {\r
-            // fallback method for when the title is not set\r
-            if ($response->feedback == 'correct') {\r
-               // only one answer possible for this qtype so first index is correct answer\r
-               $correct = $response->ident[0]['varequal'][0]['#']; // added [0]['varequal'][0]['#'] to $response->ident - CT 8/9/06\r
-            }\r
-        }\r
-    }\r
-\r
-    $i = 0;\r
-    foreach($quest->RESPONSE_BLOCK->choices as $response) {\r
-        $question->answer[$i] = addslashes($response->text);\r
-        if ($correct == $response->ident) {\r
-            $question->fraction[$i] = 1;\r
-            // this is a bit of a hack to catch the feedback... first we see if a 'correct' feedback exists\r
-            // then specific feedback for this question (maybe this should be switched?, but from my example\r
-            // question pools I have not seen response specific feedback, only correct or incorrect feedback\r
-            if (!empty($feedback['correct'])) {\r
-                $question->feedback[$i] = $feedback['correct'];\r
-            }\r
-            elseif (!empty($feedback[$i])) {\r
-                $question->feedback[$i] = $feedback[$i];\r
-            }\r
-            else {\r
-                // failsafe feedback (should be '' instead?)\r
-                $question->feedback[$i] = "correct";   \r
-            }\r
-        }    \r
-        else {\r
-            $question->fraction[$i] = 0;\r
-            if (!empty($feedback['incorrect'])) {\r
-                $question->feedback[$i] = $feedback['incorrect'];\r
-            }\r
-            elseif (!empty($feedback[$i])) {\r
-                $question->feedback[$i] = $feedback[$i];\r
-            }\r
-            else {\r
-                // failsafe feedback (should be '' instead?)\r
-                $question->feedback[$i] = 'incorrect';\r
-            }\r
-        }\r
-        $i++;\r
-    }\r
-\r
-    if (!empty($question)) {\r
-        $questions[] = $question;\r
-    }\r
-}\r
-\r
-//----------------------------------------\r
-// Process Multiple Choice Questions With Multiple Answers\r
-//----------------------------------------\r
-function process_ma($quest, &$questions) {\r
-    $question = $this->defaultquestion(); // copied this from process_mc\r
-    $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);\r
-    $question->name = $question->questiontext; \r
-    $question->qtype = MULTICHOICE;\r
-    $question->defaultgrade = 1;\r
-    $question->single = 0; // More than one answer allowed\r
-    $question->image = ""; // No images with this format\r
-\r
-    $answers = $quest->responses;\r
-    $correct_answers = array();\r
-    foreach($answers as $answer) {\r
-        if($answer->title == 'correct') {\r
-            $answerset = $answer->ident[0]['and'][0]['#']['varequal'];\r
-            foreach($answerset as $ans) {\r
-                $correct_answers[] = $ans['#'];\r
-            }\r
-        }\r
-    }\r
-    \r
-    foreach ($quest->feedback as $fb) {\r
-        $feedback->{$fb->ident} = addslashes(trim($fb->text));\r
-    }\r
-    \r
-    $correct_answer_count = count($correct_answers);\r
-    $choiceset = $quest->RESPONSE_BLOCK->choices;\r
-    $i = 0;\r
-    foreach($choiceset as $choice) {\r
-        $question->answer[$i] = addslashes(trim($choice->text));\r
-        if (in_array($choice->ident, $correct_answers)) {\r
-            // correct answer\r
-            $question->fraction[$i] = floor(100000/$correct_answer_count)/100000; // strange behavior if we have more than 5 decimal places\r
-            $question->feedback[$i] = $feedback->correct;\r
-        }\r
-        else {\r
-            // wrong answer \r
-            $question->fraction[$i] = 0;\r
-            $question->feedback[$i] = $feedback->incorrect;\r
-        }\r
-        $i++;\r
-    }\r
-\r
-    $questions[] = $question;\r
-}\r
-\r
-//----------------------------------------\r
-// Process Essay Questions\r
-//----------------------------------------\r
-function process_essay($quest, &$questions) {\r
-// this should be rewritten to accomodate moodle 1.6 essay question type eventually\r
-\r
-    if (defined("ESSAY")) {\r
-        // treat as short answer\r
-        $question = $this->defaultquestion(); // copied this from process_mc\r
-        $question->qtype = ESSAY;\r
-        $question->defaultgrade = 1;\r
-        $question->usecase = 0; // Ignore case\r
-        $question->image = ""; // No images with this format\r
-        $question->questiontext = addslashes(trim($quest->QUESTION_BLOCK->text));\r
-        $question->name = $question->questiontext;\r
-    \r
-        print $question->name;\r
-    \r
-        $question->feedback = array();\r
-        // not sure where to get the correct answer from\r
-        foreach($quest->feedback as $feedback) {\r
-            // Added this code to put the possible solution that the\r
-            // instructor gives as the Moodle answer for an essay question\r
-            if ($feedback->ident == 'solution') {\r
-                $question->feedback = $feedback->text;\r
-            }\r
-        }\r
-        //Added because essay/questiontype.php:save_question_option is expecting a \r
-        //fraction property - CT 8/10/06\r
-        $question->fraction[] = 1; \r
-        if (!empty($question)) {\r
-            $questions[]=$question;\r
-        }\r
-    }\r
-    else {\r
-        print "Essay question types are not handled because the quiz question type 'Essay' does not exist in this installation of Moodle<br/>";\r
-        print "&nbsp;&nbsp;&nbsp;&nbsp;Omitted Question: ".$quest->QUESTION_BLOCK->text.'<br/><br/>';\r
-    }\r
-}\r
-\r
-//----------------------------------------\r
-// Process Matching Questions\r
-//----------------------------------------\r
-function process_matching($quest, &$questions) {\r
-    if (defined("RENDEREDMATCH")) {\r
-        $question = $this->defaultquestion($this->defaultquestion());\r
-        $question->valid = true;\r
-        $question->qtype = RENDEREDMATCH;\r
-        $question->defaultgrade = 1;\r
-        $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);\r
-        $question->name = $question->questiontext;\r
-    \r
-        foreach($quest->RESPONSE_BLOCK->subquestions as $qid => $subq) {\r
-            foreach($quest->responses as $rid => $resp) {\r
-                if ($resp->ident == $subq->ident) {\r
-                    $correct = addslashes($resp->correct);\r
-                    $feedback = addslashes($resp->feedback);   \r
-                }\r
-            }\r
-        \r
-            foreach($subq->choices as $cid => $choice) {\r
-                if ($choice == $correct) {\r
-                    $question->subquestions[] = addslashes($subq->text);\r
-                    $question->subanswers[] = addslashes($quest->RIGHT_MATCH_BLOCK->matching_answerset[$cid]->text);\r
-                }\r
-            }\r
-        }\r
-    \r
-        // check format\r
-        $status = true;\r
-        if ( count($quest->RESPONSE_BLOCK->subquestions) > count($quest->RIGHT_MATCH_BLOCK->matching_answerset) || count($question->subquestions) < 2) {\r
-            $status = false;\r
-        }\r
-        else {\r
-            // need to redo to make sure that no two questions have the same answer (rudimentary now)\r
-            foreach($question->subanswers as $qstn) {\r
-                if(isset($previous)) {\r
-                    if ($qstn == $previous) {\r
-                        $status = false;   \r
-                    }                \r
-                }\r
-                $previous = $qstn;\r
-                if ($qstn == '') {\r
-                    $status = false;   \r
-                }\r
-            }\r
-        }\r
-    \r
-        if ($status) {\r
-            $questions[] = $question;   \r
-        }\r
-        else {\r
-            global $course, $CFG;\r
-            print '<table align="center" border="1">';\r
-            print '<tr><td colspan="2" style="background-color:#FF8888;">This matching question is malformed. Please ensure there are no blank answers, no two questions have the same answer, and/or there are correct answers for each question. There must be at least as many subanswers as subquestions, and at least one subquestion.</td></tr>'; \r
-        \r
-            print "<tr><td>Question:</td><td>".$quest->QUESTION_BLOCK->text;\r
-            if (isset($quest->QUESTION_BLOCK->file)) {\r
-                print '<br/><font color="red">There is a subfile contained in the zipfile that has been copied to course files: bb_import/'.basename($quest->QUESTION_BLOCK->file).'</font>';\r
-                if (preg_match('/(gif|jpg|jpeg|png)$/i', $quest->QUESTION_BLOCK->file)) {\r
-                    print '<img src="'.$CFG->wwwroot.'/file.php/'.$course->id.'/bb_import/'.basename($quest->QUESTION_BLOCK->file).'" />';\r
-                }\r
-            }\r
-            print "</td></tr>";\r
-            print "<tr><td>Subquestions:</td><td><ul>";\r
-            foreach($quest->responses as $rs) {\r
-                $correct_responses->{$rs->ident} = $rs->correct;   \r
-            }\r
-            foreach($quest->RESPONSE_BLOCK->subquestions as $subq) {\r
-                print '<li>'.$subq->text.'<ul>';\r
-                foreach($subq->choices as $id=>$choice) {\r
-                    print '<li>';\r
-                    if ($choice == $correct_responses->{$subq->ident}) {\r
-                        print '<font color="green">';\r
-                    }\r
-                    else {\r
-                        print '<font color="red">';\r
-                    }\r
-                    print $quest->RIGHT_MATCH_BLOCK->matching_answerset[$id]->text.'</font></li>';\r
-                }\r
-                print '</ul>';\r
-            }\r
-            print '</ul></td></tr>';\r
-        \r
-            print '<tr><td>Feedback:</td><td><ul>';\r
-            foreach($quest->feedback as $fb) {\r
-                print '<li>'.$fb->ident.': '.$fb->text.'</li>';\r
-            }\r
-            print '</ul></td></tr></table>';\r
-        }\r
-    }\r
-    else {\r
-        print "Matching question types are not handled because the quiz question type 'Rendered Matching' does not exist in this installation of Moodle<br/>";\r
-        print "&nbsp;&nbsp;&nbsp;&nbsp;Omitted Question: ".$quest->QUESTION_BLOCK->text.'<br/><br/>';\r
-    }\r
-}\r
-\r
-\r
-function strip_applet_tags_get_mathml($string) {\r
-    if(stristr($string, '</APPLET>') === FALSE) {\r
-        return $string;    \r
-    }\r
-    else {\r
-        // strip all applet tags keeping stuff before/after and inbetween (if mathml) them\r
-        while (stristr($string, '</APPLET>') !== FALSE) {\r
-            preg_match("/(.*)\<applet.*value=\"(\<math\>.*\<\/math\>)\".*\<\/applet\>(.*)/i",$string, $mathmls);\r
-            $string = $mathmls[1].$mathmls[2].$mathmls[3];\r
-        }\r
-        return $string;    \r
-    }\r
-}\r
-\r
-} // close object\r
-?>\r
+<?php
+
+////////////////////////////////////////////////////////////////////////////
+/// Blackboard 6.x Format
+///
+/// This Moodle class provides all functions necessary to import and export
+///
+///
+////////////////////////////////////////////////////////////////////////////
+
+// Based on default.php, included by ../import.php
+
+require_once ("$CFG->libdir/xmlize.php");
+
+class qformat_blackboard_6 extends qformat_default {
+    function provide_import() {
+        return true;
+    }
+    
+    
+    //Function to check and create the needed dir to unzip file to
+    function check_and_create_import_dir($unique_code) {
+
+        global $CFG; 
+
+        $status = $this->check_dir_exists($CFG->dataroot."/temp",true);
+        if ($status) {
+            $status = $this->check_dir_exists($CFG->dataroot."/temp/bbquiz_import",true);
+        }
+        if ($status) {
+            $status = $this->check_dir_exists($CFG->dataroot."/temp/bbquiz_import/".$unique_code,true);
+        }
+        
+        return $status;
+    }
+    
+    function clean_temp_dir($dir='') {
+        // for now we will just say everything happened okay note 
+        // that a mess may be piling up in $CFG->dataroot/temp/bbquiz_import
+        return true;
+        
+        if ($dir == '') {
+            $dir = $this->temp_dir;   
+        }
+        $slash = "/";
+
+        // Create arrays to store files and directories
+        $dir_files      = array();
+        $dir_subdirs    = array();
+
+        // Make sure we can delete it
+        chmod($dir, 0777);
+
+        if ((($handle = opendir($dir))) == FALSE) {
+            // The directory could not be opened
+            return false;
+        }
+
+        // Loop through all directory entries, and construct two temporary arrays containing files and sub directories
+        while($entry = readdir($handle)) {
+            if (is_dir($dir. $slash .$entry) && $entry != ".." && $entry != ".") {
+                $dir_subdirs[] = $dir. $slash .$entry;
+            }
+            else if ($entry != ".." && $entry != ".") {
+                $dir_files[] = $dir. $slash .$entry;
+            }
+        }
+
+        // Delete all files in the curent directory return false and halt if a file cannot be removed
+        for($i=0; $i<count($dir_files); $i++) {
+            chmod($dir_files[$i], 0777);
+            if (((unlink($dir_files[$i]))) == FALSE) {
+                return false;
+            }
+        }
+
+        // Empty sub directories and then remove the directory
+        for($i=0; $i<count($dir_subdirs); $i++) {
+            chmod($dir_subdirs[$i], 0777);
+            if ($this->clean_temp_dir($dir_subdirs[$i]) == FALSE) {
+                return false;
+            }
+            else {
+                if (rmdir($dir_subdirs[$i]) == FALSE) {
+                return false;
+                }
+            }
+        }
+
+        // Close directory
+        closedir($handle);
+        if (rmdir($this->temp_dir) == FALSE) {
+            return false;    
+        }
+        // Success, every thing is gone return true
+        return true;
+    }
+    
+    //Function to check if a directory exists and, optionally, create it
+    function check_dir_exists($dir,$create=false) {
+
+        global $CFG; 
+
+        $status = true;
+        if(!is_dir($dir)) {
+            if (!$create) {
+                $status = false;
+            } else {
+                umask(0000);
+                $status = mkdir ($dir,$CFG->directorypermissions);
+            }
+        }
+        return $status;
+    }
+
+    function importpostprocess() {
+    /// Does any post-processing that may be desired
+    /// Argument is a simple array of question ids that 
+    /// have just been added.
+    
+        // need to clean up temporary directory
+        return $this->clean_temp_dir();
+    }
+
+    function copy_file_to_course($filename) {
+        global $CFG;
+        global $course;
+        $filename = str_replace('\\','/',$filename);
+        $fullpath = $this->temp_dir.'/res00001/'.$filename;
+        $basename = basename($filename);
+    
+        $copy_to = $CFG->dataroot.'/'.$course->id.'/bb_import';
+        
+        if ($this->check_dir_exists($copy_to,true)) {
+            if(is_readable($fullpath)) {
+                $copy_to.= '/'.$basename;
+                if (!copy($fullpath, $copy_to)) {
+                    return false;
+                }
+                else {
+                    return $copy_to;
+                }
+            }
+        }
+        else {
+            return false;   
+        }
+    }
+
+    function readdata($filename) {
+    /// Returns complete file with an array, one item per line
+        global $CFG;
+        
+        $unique_code = time();
+        $temp_dir = $CFG->dataroot."/temp/bbquiz_import/".$unique_code;
+        $this->temp_dir = $temp_dir;
+        if ($this->check_and_create_import_dir($unique_code)) {
+            if(is_readable($filename)) {
+                if (!copy($filename, "$temp_dir/bboard.zip")) {
+                    error("Could not copy backup file");
+                }
+                if(unzip_file("$temp_dir/bboard.zip", '', false)) {
+                    // assuming that the information is in res0001.dat
+                    // after looking at 6 examples this was always the case
+                    $q_file = "$temp_dir/res00001.dat";
+                    if (is_file($q_file)) {
+                        if (is_readable($q_file)) {
+                            $filearray = file($q_file);
+                            /// Check for Macintosh OS line returns (ie file on one line), and fix
+                            if (ereg("\r", $filearray[0]) AND !ereg("\n", $filearray[0])) {
+                                return explode("\r", $filearray[0]);
+                            } else {
+                                return $filearray;
+                            }
+                            return false;        
+                        }
+                    }
+                    else {
+                        error("Could not find question data file in zip");   
+                    }
+                }
+                else {
+                    print "filename: $filename<br />tempdir: $temp_dir <br />";
+                    error("Could not unzip file.");   
+                }
+            }
+            else {
+                error ("Could not read uploaded file");   
+            }
+        }
+        else {
+            error("Could not create temporary directory");   
+        }
+    }
+        
+    function save_question_options($question) {
+        return true; 
+    }
+    
+    
+    
+  function readquestions ($lines) {
+    /// Parses an array of lines into an array of questions,
+    /// where each item is a question object as defined by
+    /// readquestion(). 
+
+    $text = implode($lines, " ");
+    $xml = xmlize($text, 0);
+
+    $raw_questions = $xml['questestinterop']['#']['assessment'][0]['#']['section'][0]['#']['item'];
+    $questions = array();
+
+    foreach($raw_questions as $quest) {
+        $question = $this->create_raw_question($quest);
+
+        switch($question->qtype) {
+            case "Matching":
+                $this->process_matching($question, $questions);
+                break;
+            case "Multiple Choice":
+                $this->process_mc($question, $questions);
+                break;
+            case "Essay":
+                $this->process_essay($question, $questions);
+                break;
+            case "Multiple Answer":
+                $this->process_ma($question, $questions);
+                break;
+            case "True/False":
+                $this->process_tf($question, $questions);
+                break;
+            case 'Fill in the Blank':
+                $this->process_fblank($question, $questions);
+                break;
+            default:
+                print "Unknown or unhandled question type: \"$question->qtype\"<br />";
+                break;
+        }
+
+    }
+    return $questions;
+  }
+
+
+// creates a cleaner object to deal with for processing into moodle
+// the object created is NOT a moodle question object
+function create_raw_question($quest) {
+    
+    $question = $this->defaultquestion();
+    $question->qtype = $quest['#']['itemmetadata'][0]['#']['bbmd_questiontype'][0]['#'];
+    $presentation->blocks = $quest['#']['presentation'][0]['#']['flow'][0]['#']['flow'];
+
+    foreach($presentation->blocks as $pblock) {
+        
+        $block = NULL;
+        $block->type = $pblock['@']['class'];
+
+        switch($block->type) {
+            case 'QUESTION_BLOCK':
+                $sub_blocks = $pblock['#']['flow'];
+                foreach($sub_blocks as $sblock) {
+                    //echo "Calling process_block from line 263<br>";
+                    $this->process_block($sblock, $block);  
+                }
+                break;
+
+            case 'RESPONSE_BLOCK':
+                $choices = NULL;
+                switch($question->qtype) {
+                    case 'Matching':
+                        $bb_subquestions = $pblock['#']['flow'];
+                        $sub_questions = array();
+                        foreach($bb_subquestions as $bb_subquestion) {
+                            $sub_question = NULL;
+                            $sub_question->ident = $bb_subquestion['#']['response_lid'][0]['@']['ident'];
+                            $this->process_block($bb_subquestion['#']['flow'][0], $sub_question);
+                            $bb_choices = $bb_subquestion['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'][0]['#']['response_label'];
+                            $choices = array();
+                            $this->process_choices($bb_choices, $choices);
+                            $sub_question->choices = $choices;
+                            if (!isset($block->subquestions)) {
+                                $block->subquestions = array();
+                            }
+                            $block->subquestions[] = $sub_question;
+                        }
+                        break;
+                    case 'Multiple Answer':
+                        $bb_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'];
+                        $choices = array();
+                        $this->process_choices($bb_choices, $choices);
+                        $block->choices = $choices;
+                        break;
+                    case 'Essay':
+                        // Doesn't apply since the user responds with text input
+                        break;
+                    case 'Multiple Choice':
+                        $mc_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'];
+                            foreach($mc_choices as $mc_choice) {
+                            $choices = NULL;
+                            $choices = $this->process_block($mc_choice, $choices);
+                            $block->choices[] = $choices;             
+                        }
+                        break;
+                    case 'Fill in the Blank':
+                        // do nothing?
+                        break;
+                    default:
+                        $bb_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'][0]['#']['response_label'];
+                        $choices = array();
+                        $this->process_choices($bb_choices, $choices);
+                        $block->choices = $choices;
+                }
+                break;
+            case 'RIGHT_MATCH_BLOCK':
+                $matching_answerset = $pblock['#']['flow'];
+                $answerset = array();
+                foreach($matching_answerset as $answer) {
+                    $this->process_block($answer, $bb_answer);
+                    $answerset[] = $bb_answer;
+                }
+                $block->matching_answerset = $answerset;
+                break;
+            default:
+                print "UNHANDLED PRESENTATION BLOCK";
+                break;
+        }
+        $question->{$block->type} = $block;
+    }
+    
+    // determine response processing 
+    // there is a section called 'outcomes' that I don't know what to do with
+    $resprocessing = $quest['#']['resprocessing'];
+    $respconditions = $resprocessing[0]['#']['respcondition'];
+    $reponses = array();
+    if ($question->qtype == 'Matching') {
+        $this->process_matching_responses($respconditions, $responses);
+    }
+    else {
+        $this->process_responses($respconditions, $responses);
+    }
+    $question->responses = $responses;
+    $feedbackset = $quest['#']['itemfeedback'];
+    $feedbacks = array();
+    $this->process_feedback($feedbackset, $feedbacks);
+    $question->feedback = $feedbacks;
+    return $question;
+}
+
+function process_block($cur_block, &$block) {
+    global $course, $CFG;
+
+    $cur_type = $cur_block['@']['class'];
+    switch($cur_type) {
+        case 'FORMATTED_TEXT_BLOCK':
+            $block->text = $this->strip_applet_tags_get_mathml($cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#']); 
+            break;
+        case 'FILE_BLOCK':
+            //revisit this to make sure it is working correctly
+            // Commented out ['matapplication']..., etc. because I 
+            // noticed that when I imported a new Blackboard 6 file
+            // and printed out the block, the tree did not extend past ['material'][0]['#'] - CT 8/3/06
+            $block->file = $cur_block['#']['material'][0]['#'];//['matapplication'][0]['@']['uri'];
+            if ($block->file != '') {
+                // if we have a file copy it to the course dir and adjust its name to be visible over the web.
+                $block->file = $this->copy_file_to_course($block->file);
+                $block->file = $CFG->wwwroot.'/file.php/'.$course->id.'/bb_import/'.basename($block->file);
+            }
+            break;
+        case 'Block':
+            if (isset($cur_block['#']['material'][0]['#']['mattext'][0]['#'])) {
+            $block->text = $cur_block['#']['material'][0]['#']['mattext'][0]['#'];
+            }
+            else if (isset($cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#'])) {
+                $block->text = $cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#'];
+            }
+            else if (isset($cur_block['#']['response_label'])) {
+                // this is a response label block
+                $sub_blocks = $cur_block['#']['response_label'][0];
+                if(!isset($block->ident)) {
+                    if(isset($sub_blocks['@']['ident'])) {
+                        $block->ident = $sub_blocks['@']['ident'];
+                    }
+                }
+                foreach($sub_blocks['#']['flow_mat'] as $sub_block) {
+                    $this->process_block($sub_block, $block);   
+                }
+            }
+            else {
+                if (isset($cur_block['#']['flow_mat']) || isset($cur_block['#']['flow'])) {
+                    if (isset($cur_block['#']['flow_mat'])) {
+                        $sub_blocks = $cur_block['#']['flow_mat'];
+                    }
+                    elseif (isset($cur_block['#']['flow'])) {
+                        $sub_blocks = $cur_block['#']['flow'];
+                    }
+                   foreach ($sub_blocks as $sblock) {
+                        // this will recursively grab the sub blocks which should be of one of the other types
+                        $this->process_block($sblock, $block);
+                    }
+                }
+            }
+            break;
+        case 'LINK_BLOCK':
+            // not sure how this should be included
+            if (!empty($cur_block['#']['material'][0]['#']['mattext'][0]['@']['uri'])) {
+                $block->link = $cur_block['#']['material'][0]['#']['mattext'][0]['@']['uri'];
+            }
+            else {
+               $block->link = '';
+            }
+            break;    
+    }    
+    return $block;
+}
+
+function process_choices($bb_choices, &$choices) {
+    foreach($bb_choices as $choice) {
+            if (isset($choice['@']['ident'])) {
+            $cur_choice = $choice['@']['ident'];
+        }
+        else { //for multiple answer
+            $cur_choice = $choice['#']['response_label'][0];//['@']['ident'];
+        }
+        if (isset($choice['#']['flow_mat'][0])) { //for multiple answer
+            $cur_block = $choice['#']['flow_mat'][0];
+            // Reset $cur_choice to NULL because process_block is expecting an object
+            // for the second argument and not a string, which is what is was set as
+            // originally - CT 8/7/06
+            $cur_choice = null; 
+            $this->process_block($cur_block, $cur_choice);
+        }
+        elseif (isset($choice['#']['response_label'])) {
+            // Reset $cur_choice to NULL because process_block is expecting an object
+            // for the second argument and not a string, which is what is was set as
+            // originally - CT 8/7/06
+            $cur_choice = null; 
+            $this->process_block($choice, $cur_choice);
+        }
+        $choices[] = $cur_choice;
+    }    
+}
+
+function process_matching_responses($bb_responses, &$responses) {
+    foreach($bb_responses as $bb_response) {
+        $response = NULL;
+        if (isset($bb_response['#']['conditionvar'][0]['#']['varequal'])) {
+            $response->correct = $bb_response['#']['conditionvar'][0]['#']['varequal'][0]['#'];
+            $response->ident = $bb_response['#']['conditionvar'][0]['#']['varequal'][0]['@']['respident'];
+        }
+        else {
+            $response->correct =  'Broken Question?';
+            $response->ident = 'Broken Question?';
+        }
+        $response->feedback = $bb_response['#']['displayfeedback'][0]['@']['linkrefid'];
+        $responses[] = $response;
+    }
+}
+
+function process_responses($bb_responses, &$responses) {
+    foreach($bb_responses as $bb_response) {
+        //Added this line to instantiate $response.
+        // Without instantiating the $response variable, the same object
+        // gets added to the array
+        $response = null;
+        if (isset($bb_response['@']['title'])) {
+                $response->title = $bb_response['@']['title'];    
+            }
+            else {
+                $reponse->title = $bb_response['#']['displayfeedback'][0]['@']['linkrefid'];
+            }
+            $reponse->ident = array();
+            if (isset($bb_response['#']['conditionvar'][0]['#'])){//['varequal'][0]['#'])) {
+                $response->ident[0] = $bb_response['#']['conditionvar'][0]['#'];//['varequal'][0]['#'];    
+            }
+            else if (isset($bb_response['#']['conditionvar'][0]['#']['other'][0]['#'])) {
+                $response->ident[0] = $bb_response['#']['conditionvar'][0]['#']['other'][0]['#'];  
+            }
+            
+            if (isset($bb_response['#']['conditionvar'][0]['#']['and'])){//[0]['#'])) {
+                $responseset = $bb_response['#']['conditionvar'][0]['#']['and'];//[0]['#']['varequal'];
+                foreach($responseset as $rs) {
+                    $response->ident[] = $rs['#'];
+                    if(!isset($response->feedback) and isset( $rs['@'] ) ) {
+                        $response->feedback = $rs['@']['respident'];
+                    }    
+                }
+            }
+            else {
+                $response->feedback = $bb_response['#']['displayfeedback'][0]['@']['linkrefid'];   
+            }
+
+            // determine what point value to give response
+            if (isset($bb_response['#']['setvar'])) {
+                switch ($bb_response['#']['setvar'][0]['#']) {
+                    case "SCORE.max":
+                        $response->fraction = 1;
+                        break;
+                    default:
+                        // I have only seen this being 0 or unset  
+                        // there are probably fractional values of SCORE.max, but I'm not sure what they look like
+                        $response->fraction = 0;
+                        break;
+                }
+            }
+            else {
+               // just going to assume this is the case this is probably not correct.
+               $response->fraction = 0;
+            }
+            
+            $responses[] = $response;
+        }
+}
+
+function process_feedback($feedbackset, &$feedbacks) {
+    foreach($feedbackset as $bb_feedback) {
+        // Added line $feedback=null so that $feedback does not get reused in the loop
+        // and added the the $feedbacks[] array multiple times
+        $feedback = null;  
+        $feedback->ident = $bb_feedback['@']['ident'];
+        if (isset($bb_feedback['#']['flow_mat'][0])) {
+            $this->process_block($bb_feedback['#']['flow_mat'][0], $feedback);
+        }
+        elseif (isset($bb_feedback['#']['solution'][0]['#']['solutionmaterial'][0]['#']['flow_mat'][0])) {
+            $this->process_block($bb_feedback['#']['solution'][0]['#']['solutionmaterial'][0]['#']['flow_mat'][0], $feedback);
+        }
+        $feedbacks[] = $feedback;
+    }
+}
+
+//----------------------------------------
+// Process True / False Questions
+//----------------------------------------
+function process_tf($quest, &$questions) {
+    $question = $this->defaultquestion();
+
+    $question->qtype = TRUEFALSE;
+    $question->defaultgrade = 1;
+    $question->single = 1; // Only one answer is allowed
+    $question->image = ""; // No images with this format
+    $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);
+    // put name in question object
+    $question->name = $question->questiontext;
+
+    // first choice is true, second is false.
+    if ($quest->responses[0]->fraction == 1) {
+        $correct = true;    
+    }
+    else {
+        $correct = false;   
+    }
+    
+    foreach($quest->feedback as $fb) {
+        $fback->{$fb->ident} = $fb->text;   
+    }
+    
+    if ($correct) {  // true is correct
+        $question->answer = 1;
+        $question->feedbacktrue = addslashes($fback->correct);
+        $question->feedbackfalse = addslashes($fback->incorrect);
+    } else {  // false is correct
+        $question->answer = 0;
+        $question->feedbacktrue = addslashes($fback->incorrect);
+        $question->feedbackfalse = addslashes($fback->correct);
+    }
+    $questions[] = $question;
+}
+
+
+//----------------------------------------
+// Process Fill in the Blank
+//----------------------------------------
+function process_fblank($quest, &$questions) {
+    $question = $this->defaultquestion();
+    $question->qtype = SHORTANSWER;
+    $question->defaultgrade = 1;
+    $question->single = 1;
+    $question->usecase = 0;
+    $question->image = '';
+    $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);
+    $question->name = $question->questiontext;
+    $answers = array();
+    $fractions = array();
+    $feedbacks = array();
+    
+    // extract the feedback
+    $feedback = array();
+    foreach($quest->feedback as $fback) {
+        if (isset($fback->ident)) {
+            if ($fback->ident == 'correct' || $fback->ident == 'incorrect') {
+                $feedback[$fback->ident] = $fback->text;
+            }
+        }
+    }
+    
+    foreach($quest->responses as $response) {
+        if(isset($response->title)) {
+            if (isset($response->ident[0]['varequal'][0]['#'])) {
+                //for BB Fill in the Blank, only interested in correct answers
+                if ($response->feedback = 'correct') {
+                    $answers[] = addslashes($response->ident[0]['varequal'][0]['#']);
+                    $fractions[] = 1;
+                    if (isset($feedback['correct'])) {
+                        $feedbacks[] = addslashes($feedback['correct']);
+                    }
+                    else {
+                        $feedbacks[] = '';
+                    }
+                }
+            }
+  
+        }
+    }
+
+    //Adding catchall to so that students can see feedback for incorrect answers when they enter something the 
+    //instructor did not enter
+    $answers[] = '*';
+    $fractions[] = 0;
+    if (isset($feedback['incorrect'])) {
+        $feedbacks[] = addslashes($feedback['incorrect']);
+    }
+    else {
+        $feedbacks[] = '';
+    }
+    
+    $question->answer = $answers;
+    $question->fraction = $fractions;
+    $question->feedback = $feedbacks; // Changed to assign $feedbacks to $question->feedback instead of
+
+    if (!empty($question)) {
+        $questions[] = $question;
+    }
+
+}
+
+//----------------------------------------
+// Process Multiple Choice Questions
+//----------------------------------------
+function process_mc($quest, &$questions) {
+    $question = $this->defaultquestion();
+    $question->qtype = MULTICHOICE;
+    $question->defaultgrade = 1;
+    $question->single = 1;
+    $question->image = "";
+    $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);
+    $question->name = $question->questiontext;
+    
+    $feedback = array();
+    foreach($quest->feedback as $fback) {
+        $feedback[$fback->ident] = addslashes($fback->text);
+    }
+    foreach($quest->responses as $response) {
+        if (isset($response->title)) {
+            if ($response->title == 'correct') {
+                // only one answer possible for this qtype so first index is correct answer
+                $correct = $response->ident[0]['varequal'][0]['#'];
+            }
+        }
+        else {
+            // fallback method for when the title is not set
+            if ($response->feedback == 'correct') {
+               // only one answer possible for this qtype so first index is correct answer
+               $correct = $response->ident[0]['varequal'][0]['#']; // added [0]['varequal'][0]['#'] to $response->ident - CT 8/9/06
+            }
+        }
+    }
+
+    $i = 0;
+    foreach($quest->RESPONSE_BLOCK->choices as $response) {
+        $question->answer[$i] = addslashes($response->text);
+        if ($correct == $response->ident) {
+            $question->fraction[$i] = 1;
+            // this is a bit of a hack to catch the feedback... first we see if a 'correct' feedback exists
+            // then specific feedback for this question (maybe this should be switched?, but from my example
+            // question pools I have not seen response specific feedback, only correct or incorrect feedback
+            if (!empty($feedback['correct'])) {
+                $question->feedback[$i] = $feedback['correct'];
+            }
+            elseif (!empty($feedback[$i])) {
+                $question->feedback[$i] = $feedback[$i];
+            }
+            else {
+                // failsafe feedback (should be '' instead?)
+                $question->feedback[$i] = "correct";   
+            }
+        }    
+        else {
+            $question->fraction[$i] = 0;
+            if (!empty($feedback['incorrect'])) {
+                $question->feedback[$i] = $feedback['incorrect'];
+            }
+            elseif (!empty($feedback[$i])) {
+                $question->feedback[$i] = $feedback[$i];
+            }
+            else {
+                // failsafe feedback (should be '' instead?)
+                $question->feedback[$i] = 'incorrect';
+            }
+        }
+        $i++;
+    }
+
+    if (!empty($question)) {
+        $questions[] = $question;
+    }
+}
+
+//----------------------------------------
+// Process Multiple Choice Questions With Multiple Answers
+//----------------------------------------
+function process_ma($quest, &$questions) {
+    $question = $this->defaultquestion(); // copied this from process_mc
+    $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);
+    $question->name = $question->questiontext; 
+    $question->qtype = MULTICHOICE;
+    $question->defaultgrade = 1;
+    $question->single = 0; // More than one answer allowed
+    $question->image = ""; // No images with this format
+
+    $answers = $quest->responses;
+    $correct_answers = array();
+    foreach($answers as $answer) {
+        if($answer->title == 'correct') {
+            $answerset = $answer->ident[0]['and'][0]['#']['varequal'];
+            foreach($answerset as $ans) {
+                $correct_answers[] = $ans['#'];
+            }
+        }
+    }
+    
+    foreach ($quest->feedback as $fb) {
+        $feedback->{$fb->ident} = addslashes(trim($fb->text));
+    }
+    
+    $correct_answer_count = count($correct_answers);
+    $choiceset = $quest->RESPONSE_BLOCK->choices;
+    $i = 0;
+    foreach($choiceset as $choice) {
+        $question->answer[$i] = addslashes(trim($choice->text));
+        if (in_array($choice->ident, $correct_answers)) {
+            // correct answer
+            $question->fraction[$i] = floor(100000/$correct_answer_count)/100000; // strange behavior if we have more than 5 decimal places
+            $question->feedback[$i] = $feedback->correct;
+        }
+        else {
+            // wrong answer 
+            $question->fraction[$i] = 0;
+            $question->feedback[$i] = $feedback->incorrect;
+        }
+        $i++;
+    }
+
+    $questions[] = $question;
+}
+
+//----------------------------------------
+// Process Essay Questions
+//----------------------------------------
+function process_essay($quest, &$questions) {
+// this should be rewritten to accomodate moodle 1.6 essay question type eventually
+
+    if (defined("ESSAY")) {
+        // treat as short answer
+        $question = $this->defaultquestion(); // copied this from process_mc
+        $question->qtype = ESSAY;
+        $question->defaultgrade = 1;
+        $question->usecase = 0; // Ignore case
+        $question->image = ""; // No images with this format
+        $question->questiontext = addslashes(trim($quest->QUESTION_BLOCK->text));
+        $question->name = $question->questiontext;
+    
+        print $question->name;
+    
+        $question->feedback = array();
+        // not sure where to get the correct answer from
+        foreach($quest->feedback as $feedback) {
+            // Added this code to put the possible solution that the
+            // instructor gives as the Moodle answer for an essay question
+            if ($feedback->ident == 'solution') {
+                $question->feedback = $feedback->text;
+            }
+        }
+        //Added because essay/questiontype.php:save_question_option is expecting a 
+        //fraction property - CT 8/10/06
+        $question->fraction[] = 1; 
+        if (!empty($question)) {
+            $questions[]=$question;
+        }
+    }
+    else {
+        print "Essay question types are not handled because the quiz question type 'Essay' does not exist in this installation of Moodle<br/>";
+        print "&nbsp;&nbsp;&nbsp;&nbsp;Omitted Question: ".$quest->QUESTION_BLOCK->text.'<br/><br/>';
+    }
+}
+
+//----------------------------------------
+// Process Matching Questions
+//----------------------------------------
+function process_matching($quest, &$questions) {
+    if (defined("RENDEREDMATCH")) {
+        $question = $this->defaultquestion($this->defaultquestion());
+        $question->valid = true;
+        $question->qtype = RENDEREDMATCH;
+        $question->defaultgrade = 1;
+        $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);
+        $question->name = $question->questiontext;
+    
+        foreach($quest->RESPONSE_BLOCK->subquestions as $qid => $subq) {
+            foreach($quest->responses as $rid => $resp) {
+                if ($resp->ident == $subq->ident) {
+                    $correct = addslashes($resp->correct);
+                    $feedback = addslashes($resp->feedback);   
+                }
+            }
+        
+            foreach($subq->choices as $cid => $choice) {
+                if ($choice == $correct) {
+                    $question->subquestions[] = addslashes($subq->text);
+                    $question->subanswers[] = addslashes($quest->RIGHT_MATCH_BLOCK->matching_answerset[$cid]->text);
+                }
+            }
+        }
+    
+        // check format
+        $status = true;
+        if ( count($quest->RESPONSE_BLOCK->subquestions) > count($quest->RIGHT_MATCH_BLOCK->matching_answerset) || count($question->subquestions) < 2) {
+            $status = false;
+        }
+        else {
+            // need to redo to make sure that no two questions have the same answer (rudimentary now)
+            foreach($question->subanswers as $qstn) {
+                if(isset($previous)) {
+                    if ($qstn == $previous) {
+                        $status = false;   
+                    }                
+                }
+                $previous = $qstn;
+                if ($qstn == '') {
+                    $status = false;   
+                }
+            }
+        }
+    
+        if ($status) {
+            $questions[] = $question;   
+        }
+        else {
+            global $course, $CFG;
+            print '<table align="center" border="1">';
+            print '<tr><td colspan="2" style="background-color:#FF8888;">This matching question is malformed. Please ensure there are no blank answers, no two questions have the same answer, and/or there are correct answers for each question. There must be at least as many subanswers as subquestions, and at least one subquestion.</td></tr>'; 
+        
+            print "<tr><td>Question:</td><td>".$quest->QUESTION_BLOCK->text;
+            if (isset($quest->QUESTION_BLOCK->file)) {
+                print '<br/><font color="red">There is a subfile contained in the zipfile that has been copied to course files: bb_import/'.basename($quest->QUESTION_BLOCK->file).'</font>';
+                if (preg_match('/(gif|jpg|jpeg|png)$/i', $quest->QUESTION_BLOCK->file)) {
+                    print '<img src="'.$CFG->wwwroot.'/file.php/'.$course->id.'/bb_import/'.basename($quest->QUESTION_BLOCK->file).'" />';
+                }
+            }
+            print "</td></tr>";
+            print "<tr><td>Subquestions:</td><td><ul>";
+            foreach($quest->responses as $rs) {
+                $correct_responses->{$rs->ident} = $rs->correct;   
+            }
+            foreach($quest->RESPONSE_BLOCK->subquestions as $subq) {
+                print '<li>'.$subq->text.'<ul>';
+                foreach($subq->choices as $id=>$choice) {
+                    print '<li>';
+                    if ($choice == $correct_responses->{$subq->ident}) {
+                        print '<font color="green">';
+                    }
+                    else {
+                        print '<font color="red">';
+                    }
+                    print $quest->RIGHT_MATCH_BLOCK->matching_answerset[$id]->text.'</font></li>';
+                }
+                print '</ul>';
+            }
+            print '</ul></td></tr>';
+        
+            print '<tr><td>Feedback:</td><td><ul>';
+            foreach($quest->feedback as $fb) {
+                print '<li>'.$fb->ident.': '.$fb->text.'</li>';
+            }
+            print '</ul></td></tr></table>';
+        }
+    }
+    else {
+        print "Matching question types are not handled because the quiz question type 'Rendered Matching' does not exist in this installation of Moodle<br/>";
+        print "&nbsp;&nbsp;&nbsp;&nbsp;Omitted Question: ".$quest->QUESTION_BLOCK->text.'<br/><br/>';
+    }
+}
+
+
+function strip_applet_tags_get_mathml($string) {
+    if(stristr($string, '</APPLET>') === FALSE) {
+        return $string;    
+    }
+    else {
+        // strip all applet tags keeping stuff before/after and inbetween (if mathml) them
+        while (stristr($string, '</APPLET>') !== FALSE) {
+            preg_match("/(.*)\<applet.*value=\"(\<math\>.*\<\/math\>)\".*\<\/applet\>(.*)/i",$string, $mathmls);
+            $string = $mathmls[1].$mathmls[2].$mathmls[3];
+        }
+        return $string;    
+    }
+}
+
+} // close object
+?>
index ec82e58960a3d62ab08155124f1b922614b1eb47..27524957902a8248bc186952274f2fdbf7fdae8e 100644 (file)
-<?xml version="1.0" ?>\r
-<activityset setno="2">\r
-       <title>Maths</title>\r
-       <questions>\r
-               <question type="multiChoice">\r
-                       <text>The ages, in years, of 10 horses in a field were 3,  3,  4,  5,  7,  7,  7,  8,  8,  8,&lt;p&gt;\r
-Which one of the following is true?</text>\r
-                       <award>1</award>\r
-                       <hint>mean = (3+3+4+5+7+7+7+8+8+8)/10 = 6&lt;p&gt;\r
-median = 7 i.e the middle number&lt;p&gt;\r
-range = 8-3 = 5</hint>\r
-                       <answer>\r
-                               <option correct="yes">median &gt; mean &gt; range</option>\r
-                               <option correct="no">mean = median</option>\r
-                               <option correct="no">mean &gt; median &gt; range</option>\r
-                               <option correct="no">median &gt; range &gt; mean</option>\r
-                       </answer>\r
-               </question>\r
-               <question type="multiChoice">\r
-                       <text>At a college, students are given a points score calculated from their GCSE grades.&lt;p&gt;\r
-Someone with 4 A grades and 4 B grades gains a score of 36 points.&lt;br&gt;Someone with 2 A grades and 4 B grades gains a score of 26 points.&lt;br&gt;Someone with 3 A grades and 3 B grades would have a score of</text>\r
-                       <award>1</award>\r
-                       <hint>4A + 4B = 36 and 2A + 4B = 26&lt;p&gt;solving simultaneously gives A = 5 and B = 4</hint>\r
-                       <answer>\r
-                               <option correct="yes">27 points</option>\r
-                               <option correct="no">21 points</option>\r
-                               <option correct="no">30 points</option>\r
-                               <option correct="no">31 points</option>\r
-                       </answer>\r
-               </question>\r
-               <question type="multiChoice">\r
-                       <text>A sequence consists of adding the previous three terms together to form the next term. The first three terms of the sequence are 1, 2, 3.&lt;p&gt;\r
-What is the sixth term in the sequence?</text>\r
-                       <award>1</award>\r
-                       <hint>1, 2, 3, 6, 11, ...</hint>\r
-                       <answer>\r
-                               <option correct="yes">20</option>\r
-                               <option correct="no">6</option>\r
-                               <option correct="no">11</option>\r
-                               <option correct="no">13</option>\r
-                       </answer>\r
-               </question>\r
-               <question type="multiChoice">\r
-                       <text>The value of an item is described as decreasing exponentially. Which description below best matches this statement?</text>\r
-                       <award>1</award>\r
-                       <hint>No hint - you either know this or you don't!</hint>\r
-                       <answer>\r
-                               <option correct="yes">The value falls by a smaller amount each year.</option>\r
-                               <option correct="no">The value falls by the same amount each year.</option>\r
-                               <option correct="no">The value falls by the same amount each year for a while, and then remains constant.</option>\r
-                               <option correct="no">The value falls by a larger amount each year.</option>\r
-                       </answer>\r
-               </question>\r
-               <question type="multiChoice">\r
-                       <text>Consider the statement&lt;p&gt;\r
-&quot;Schools with high numbers of pupils on free school meals do not do well in league tables.&quot;&lt;p&gt;\r
-Which of the following statements follows logically from the one above?</text>\r
-                       <award>1</award>\r
-                       <hint>Factors other than the number of pupils on free school meals affect how well a school does in league tables.</hint>\r
-                       <answer>\r
-                               <option correct="yes">Schools which do well in league tables do not have high numbers of pupils on free school meals.</option>\r
-                               <option correct="no">Schools with low numbers of pupils on free school meals do well in league tables.</option>\r
-                               <option correct="no">Making all pupils pay for school meals will improve league table results.</option>\r
-                               <option correct="no">Schools which do not do well in league tables have high numbers of pupils on free school meals.</option>\r
-                       </answer>\r
-               </question>\r
-               <question type="multiChoice">\r
-                       <text>The force between two point electric charges is inversely proportional to the square of their distance apart. What effect does doubling this distance have on the force?</text>\r
-                       <award>1</award>\r
-                       <hint>Inversely proportional means that increasing the distance decreases the force.&lt;br&gt;2 squared gives 4.</hint>\r
-                       <answer>\r
-                               <option correct="yes">The force decreases by a factor of four.</option>\r
-                               <option correct="no">The force is halved.</option>\r
-                               <option correct="no">The force is doubled.</option>\r
-                               <option correct="no">The force increases by a factor of four.</option>\r
-                       </answer>\r
-               </question>\r
-               <question type="multiChoice">\r
-                       <text>Two of the five playing cards that Colin has are aces. He shuffles the five cards, then puts them face down on the table. Madge takes a card and then another. The probability that she now has &lt;b&gt;both&lt;/b&gt; of the aces is</text>\r
-                       <award>1</award>\r
-                       <hint>2/5 x 1/4</hint>\r
-                       <answer>\r
-                               <option correct="yes">1/10</option>\r
-                               <option correct="no">4/25</option>\r
-                               <option correct="no">1/5</option>\r
-                               <option correct="no">2/5</option>\r
-                       </answer>\r
-               </question>\r
-               <question type="multiChoice">\r
-                       <text>A college's guidelines say that classes must have a minimum of 12 students and a maximum of 20 students. For what numbers of students studying a particular subject is it impossible to run classes without breaking the guidelines?</text>\r
-                       <award>1</award>\r
-                       <hint>between 12 and 20 students - one class&lt;br&gt;\r
-between 24 and 36 students - two classes&lt;br&gt;\r
-between 36 and 40 students - two classes</hint>\r
-                       <answer>\r
-                               <option correct="yes">between 20 and 24 students</option>\r
-                               <option correct="no">between 12 and 20 students</option>\r
-                               <option correct="no">between 24 and 36 students</option>\r
-                               <option correct="no">between 36 and 40 students</option>\r
-                       </answer>\r
-               </question>\r
-               <question type="multiChoice">\r
-                       <text>The ages of two friends are in the ratio 3:4. In 8 years time their ages will be in the ratio 5:6. How old are they now?</text>\r
-                       <award>1</award>\r
-                       <hint>(12+8):(16+8) = 20:24 = 5:6</hint>\r
-                       <answer>\r
-                               <option correct="yes">12, 16</option>\r
-                               <option correct="no">3, 4</option>\r
-                               <option correct="no">6, 8</option>\r
-                               <option correct="no">9, 12</option>\r
-                       </answer>\r
-               </question>\r
-               <question type="multiChoice">\r
-                       <text>A heavy construction vehicle travels for 40 minutes between sites, at an average speed of 16 km per second. The distance between sites is</text>\r
-                       <award>1</award>\r
-                       <hint>16/60 x 40</hint>\r
-                       <answer>\r
-                               <option correct="yes">10.7 km</option>\r
-                               <option correct="no">2.5 km</option>\r
-                               <option correct="no">6.4 km</option>\r
-                               <option correct="no">38.4 km</option>\r
-                       </answer>\r
-               </question>\r
-               <question type="multianswerchoice">\r
-                       <text>Which of the following are features of a Virtual Learning Environment? (Select all that apply)</text>\r
-                       <hint />\r
-                       <answer>\r
-                               <option correct="yes" award="1" deduct="0">course resources are available from home and from college</option>\r
-                               <option correct="yes" award="1" deduct="0">forums enable collaborative work</option>\r
-                               <option correct="yes" award="1" deduct="0">assessments can give instant feedback</option>\r
-                               <option correct="yes" award="1" deduct="0">course progress is recorded</option>\r
-                               <option correct="no" award="1" deduct="0">kettle is put on automatically for tea/coffee</option>\r
-                       </answer>\r
-               </question>\r
-               <question type="multianswerchoice">\r
-                       <text>Which of the following may a Virtual Learning Environment be used for? (Select all that apply)</text>\r
-                       <hint />\r
-                       <answer>\r
-                               <option correct="yes" award="1" deduct="1">delivering a course online</option>\r
-                               <option correct="yes" award="1" deduct="1">supporting face-to-face teaching</option>\r
-                               <option correct="no" award="1" deduct="0">as a complete replacement for teachers</option>\r
-                       </answer>\r
-               </question>\r
-       </questions>\r
-</activityset>\r
+<?xml version="1.0" ?>
+<activityset setno="2">
+       <title>Maths</title>
+       <questions>
+               <question type="multiChoice">
+                       <text>The ages, in years, of 10 horses in a field were 3,  3,  4,  5,  7,  7,  7,  8,  8,  8,&lt;p&gt;
+Which one of the following is true?</text>
+                       <award>1</award>
+                       <hint>mean = (3+3+4+5+7+7+7+8+8+8)/10 = 6&lt;p&gt;
+median = 7 i.e the middle number&lt;p&gt;
+range = 8-3 = 5</hint>
+                       <answer>
+                               <option correct="yes">median &gt; mean &gt; range</option>
+                               <option correct="no">mean = median</option>
+                               <option correct="no">mean &gt; median &gt; range</option>
+                               <option correct="no">median &gt; range &gt; mean</option>
+                       </answer>
+               </question>
+               <question type="multiChoice">
+                       <text>At a college, students are given a points score calculated from their GCSE grades.&lt;p&gt;
+Someone with 4 A grades and 4 B grades gains a score of 36 points.&lt;br&gt;Someone with 2 A grades and 4 B grades gains a score of 26 points.&lt;br&gt;Someone with 3 A grades and 3 B grades would have a score of</text>
+                       <award>1</award>
+                       <hint>4A + 4B = 36 and 2A + 4B = 26&lt;p&gt;solving simultaneously gives A = 5 and B = 4</hint>
+                       <answer>
+                               <option correct="yes">27 points</option>
+                               <option correct="no">21 points</option>
+                               <option correct="no">30 points</option>
+                               <option correct="no">31 points</option>
+                       </answer>
+               </question>
+               <question type="multiChoice">
+                       <text>A sequence consists of adding the previous three terms together to form the next term. The first three terms of the sequence are 1, 2, 3.&lt;p&gt;
+What is the sixth term in the sequence?</text>
+                       <award>1</award>
+                       <hint>1, 2, 3, 6, 11, ...</hint>
+                       <answer>
+                               <option correct="yes">20</option>
+                               <option correct="no">6</option>
+                               <option correct="no">11</option>
+                               <option correct="no">13</option>
+                       </answer>
+               </question>
+               <question type="multiChoice">
+                       <text>The value of an item is described as decreasing exponentially. Which description below best matches this statement?</text>
+                       <award>1</award>
+                       <hint>No hint - you either know this or you don't!</hint>
+                       <answer>
+                               <option correct="yes">The value falls by a smaller amount each year.</option>
+                               <option correct="no">The value falls by the same amount each year.</option>
+                               <option correct="no">The value falls by the same amount each year for a while, and then remains constant.</option>
+                               <option correct="no">The value falls by a larger amount each year.</option>
+                       </answer>
+               </question>
+               <question type="multiChoice">
+                       <text>Consider the statement&lt;p&gt;
+&quot;Schools with high numbers of pupils on free school meals do not do well in league tables.&quot;&lt;p&gt;
+Which of the following statements follows logically from the one above?</text>
+                       <award>1</award>
+                       <hint>Factors other than the number of pupils on free school meals affect how well a school does in league tables.</hint>
+                       <answer>
+                               <option correct="yes">Schools which do well in league tables do not have high numbers of pupils on free school meals.</option>
+                               <option correct="no">Schools with low numbers of pupils on free school meals do well in league tables.</option>
+                               <option correct="no">Making all pupils pay for school meals will improve league table results.</option>
+                               <option correct="no">Schools which do not do well in league tables have high numbers of pupils on free school meals.</option>
+                       </answer>
+               </question>
+               <question type="multiChoice">
+                       <text>The force between two point electric charges is inversely proportional to the square of their distance apart. What effect does doubling this distance have on the force?</text>
+                       <award>1</award>
+                       <hint>Inversely proportional means that increasing the distance decreases the force.&lt;br&gt;2 squared gives 4.</hint>
+                       <answer>
+                               <option correct="yes">The force decreases by a factor of four.</option>
+                               <option correct="no">The force is halved.</option>
+                               <option correct="no">The force is doubled.</option>
+                               <option correct="no">The force increases by a factor of four.</option>
+                       </answer>
+               </question>
+               <question type="multiChoice">
+                       <text>Two of the five playing cards that Colin has are aces. He shuffles the five cards, then puts them face down on the table. Madge takes a card and then another. The probability that she now has &lt;b&gt;both&lt;/b&gt; of the aces is</text>
+                       <award>1</award>
+                       <hint>2/5 x 1/4</hint>
+                       <answer>
+                               <option correct="yes">1/10</option>
+                               <option correct="no">4/25</option>
+                               <option correct="no">1/5</option>
+                               <option correct="no">2/5</option>
+                       </answer>
+               </question>
+               <question type="multiChoice">
+                       <text>A college's guidelines say that classes must have a minimum of 12 students and a maximum of 20 students. For what numbers of students studying a particular subject is it impossible to run classes without breaking the guidelines?</text>
+                       <award>1</award>
+                       <hint>between 12 and 20 students - one class&lt;br&gt;
+between 24 and 36 students - two classes&lt;br&gt;
+between 36 and 40 students - two classes</hint>
+                       <answer>
+                               <option correct="yes">between 20 and 24 students</option>
+                               <option correct="no">between 12 and 20 students</option>
+                               <option correct="no">between 24 and 36 students</option>
+                               <option correct="no">between 36 and 40 students</option>
+                       </answer>
+               </question>
+               <question type="multiChoice">
+                       <text>The ages of two friends are in the ratio 3:4. In 8 years time their ages will be in the ratio 5:6. How old are they now?</text>
+                       <award>1</award>
+                       <hint>(12+8):(16+8) = 20:24 = 5:6</hint>
+                       <answer>
+                               <option correct="yes">12, 16</option>
+                               <option correct="no">3, 4</option>
+                               <option correct="no">6, 8</option>
+                               <option correct="no">9, 12</option>
+                       </answer>
+               </question>
+               <question type="multiChoice">
+                       <text>A heavy construction vehicle travels for 40 minutes between sites, at an average speed of 16 km per second. The distance between sites is</text>
+                       <award>1</award>
+                       <hint>16/60 x 40</hint>
+                       <answer>
+                               <option correct="yes">10.7 km</option>
+                               <option correct="no">2.5 km</option>
+                               <option correct="no">6.4 km</option>
+                               <option correct="no">38.4 km</option>
+                       </answer>
+               </question>
+               <question type="multianswerchoice">
+                       <text>Which of the following are features of a Virtual Learning Environment? (Select all that apply)</text>
+                       <hint />
+                       <answer>
+                               <option correct="yes" award="1" deduct="0">course resources are available from home and from college</option>
+                               <option correct="yes" award="1" deduct="0">forums enable collaborative work</option>
+                               <option correct="yes" award="1" deduct="0">assessments can give instant feedback</option>
+                               <option correct="yes" award="1" deduct="0">course progress is recorded</option>
+                               <option correct="no" award="1" deduct="0">kettle is put on automatically for tea/coffee</option>
+                       </answer>
+               </question>
+               <question type="multianswerchoice">
+                       <text>Which of the following may a Virtual Learning Environment be used for? (Select all that apply)</text>
+                       <hint />
+                       <answer>
+                               <option correct="yes" award="1" deduct="1">delivering a course online</option>
+                               <option correct="yes" award="1" deduct="1">supporting face-to-face teaching</option>
+                               <option correct="no" award="1" deduct="0">as a complete replacement for teachers</option>
+                       </answer>
+               </question>
+       </questions>
+</activityset>
index c095ac7f5a754270ab6c19b8d11dd3e75ad72c30..6471b6b491701986a1f05a2a65291534c953571d 100644 (file)
@@ -1,7 +1,7 @@
-- Ajouter un espace après un symbole <= s'il préfixe une parenthèse ouvrante.\r
-- Gérer 'and', 'or', ... comme &&, ||\r
-- Ne pas mettre de '$' sur les @param si aucun nom de variable n'esp spécifié.\r
-- Ajouter OneTrueBrace pour les if, while, for, else ... (Gustavo Carreno <gcarreno@netvisao.pt>, Richard Bateman <richard@randyb.byu.edu>, Yaroslav Shvetsov <yaro@totaldesign.ru>, Chris Small <chris@owta.net>)\r
-- Remove blank lines (Sergio Marchesini <smarques@tin.it>)\r
-- Forcer une ligne vide après une déclaration de fonction (Richard Bateman <richard@randyb.byu.edu>)\r
-\r
+- Ajouter un espace apr�s un symbole <= s'il pr�fixe une parenth�se ouvrante.
+- G�rer 'and', 'or', ... comme &&, ||
+- Ne pas mettre de '$' sur les @param si aucun nom de variable n'esp sp�cifi�.
+- Ajouter OneTrueBrace pour les if, while, for, else ... (Gustavo Carreno <gcarreno@netvisao.pt>, Richard Bateman <richard@randyb.byu.edu>, Yaroslav Shvetsov <yaro@totaldesign.ru>, Chris Small <chris@owta.net>)
+- Remove blank lines (Sergio Marchesini <smarques@tin.it>)
+- Forcer une ligne vide apr�s une d�claration de fonction (Richard Bateman <richard@randyb.byu.edu>)
+
index 31dcfe3fa4df3859304da29d4e1d224ba4140520..af4c20105ffe60471ae242da2b34281b45707b64 100644 (file)
@@ -1,47 +1,47 @@
-<?php  // $Id$\r
-       // expired.php - called by hive when the session has expired.\r
-\r
-    require('../../config.php');\r
-\r
-    require('lib.php');\r
-\r
-    require_login();\r
-\r
-    //MW theres no easy way to log in seamlessly. We need the users unhashed password.\r
-    // It's a security risk to carry that in $SESSION so we put up login form.\r
-    print_header();\r
-    notify('Your session has expired. Please log in again.'); \r
-?>\r
-      <form action="login.php" method="post" name="login" id="login">\r
-        <table border="0" align="center">\r
-        <tr>\r
-          <td width="80%">\r
-            <table align="center" class="loginform">\r
-              <tr class="username">\r
-                <td align="right" class="c0">\r
-                  <?php print_string("username") ?>:\r
-                </td>\r
-                <td class="c1">\r
-                  <input type="text" name="username" size="15" value="<?php p($frm->username) ?>" alt="<?php print_string("username") ?>" />\r
-                </td>\r
-              </tr>\r
-              <tr class="password">\r
-                <td align="right" class="c0">\r
-                  <?php print_string("password") ?>:\r
-                </td>\r
-                <td class="c1">\r
-                  <input type="password" name="password" size="15" value="" alt="<?php print_string("password") ?>" />\r
-                </td>\r
-              </tr>\r
-            </table>\r
-          </td>\r
-          <td width="20%">\r
-            <input type="submit" value="<?php print_string("login") ?>" />\r
-          </td>\r
-        </tr>\r
-        </table>\r
-      </form>\r
-<br />\r
-<?php\r
-    close_window_button();\r
-?>\r
+<?php  // $Id$
+       // expired.php - called by hive when the session has expired.
+
+    require('../../config.php');
+
+    require('lib.php');
+
+    require_login();
+
+    //MW theres no easy way to log in seamlessly. We need the users unhashed password.
+    // It's a security risk to carry that in $SESSION so we put up login form.
+    print_header();
+    notify('Your session has expired. Please log in again.'); 
+?>
+      <form action="login.php" method="post" name="login" id="login">
+        <table border="0" align="center">
+        <tr>
+          <td width="80%">
+            <table align="center" class="loginform">
+              <tr class="username">
+                <td align="right" class="c0">
+                  <?php print_string("username") ?>:
+                </td>
+                <td class="c1">
+                  <input type="text" name="username" size="15" value="<?php p($frm->username) ?>" alt="<?php print_string("username") ?>" />
+                </td>
+              </tr>
+              <tr class="password">
+                <td align="right" class="c0">
+                  <?php print_string("password") ?>:
+                </td>
+                <td class="c1">
+                  <input type="password" name="password" size="15" value="" alt="<?php print_string("password") ?>" />
+                </td>
+              </tr>
+            </table>
+          </td>
+          <td width="20%">
+            <input type="submit" value="<?php print_string("login") ?>" />
+          </td>
+        </tr>
+        </table>
+      </form>
+<br />
+<?php
+    close_window_button();
+?>
index 90c123d0c945deadf296e042d250c750d102dfb1..758d603d844ce8380bc8c8c00b90cc9c087c3f24 100755 (executable)
@@ -1,79 +1,79 @@
-<?php  // $Id$\r
-       // Logs into Hive from HarvestRoad and stores session ID in Moodle session\r
-       // Martin Dougiamas, Moodle\r
-       //\r
-       // Example CFG variables to make this work:\r
-\r
-       // $CFG->sso          = 'hive';\r
-       // $CFG->hiveprotocol = 'http';\r
-       // $CFG->hiveport     = '80';\r
-       // $CFG->hivehost     = 'turkey.harvestroad.com.au';\r
-       // $CFG->hivepath     = '/cgi-bin/hive/hive.cgi';\r
-       // $CFG->hivecbid     = '28';\r
-\r
-function sso_user_login($username, $password) {\r
-\r
-    global $CFG, $SESSION;\r
-\r
-    include($CFG->libdir.'/snoopy/Snoopy.class.inc');\r
-\r
-    if (empty($CFG->hivehost)) {\r
-        return false;   // Hive config variables not configured yet\r
-    }\r
-\r
-/// Set up Snoopy\r
-\r
-    $snoopy = new Snoopy;\r
-\r
-    $submit_url = $CFG->hiveprotocol .'://'. $CFG->hivehost .':'. $CFG->hiveport .''. $CFG->hivepath ;\r
-\r
-    $submit_vars['HIVE_UNAME']  = $username;\r
-    $submit_vars['HIVE_UPASS']  = $password;\r
-    $submit_vars['HIVE_ENDUSER']= $username;\r
-    $submit_vars['HIVE_REQ']    = '2112';\r
-    $submit_vars['HIVE_REF']    = 'hin:hive@API Login 3';\r
-    $submit_vars['HIVE_RET']    = 'ORG';\r
-    $submit_vars['HIVE_REM']    = '';\r
-    $submit_vars['HIVE_PROD']   = '0';\r
-    $submit_vars['HIVE_USERIP'] = getremoteaddr();\r
-\r
-\r
-/// We use POST to call Hive with a bit more security\r
-    $snoopy->submit($submit_url,$submit_vars);\r
-\r
-/// Extract HIVE_SESSION from headers\r
-\r
-    foreach ($snoopy->headers as $header) {\r
-        if (strpos($header, 'HIVE_SESSION=') !== false) {\r
-            $header = explode('HIVE_SESSION=', $header);\r
-            if (count($header) > 1) {\r
-                $cookie = explode(';', $header[1]);\r
-                $cookie = $cookie[0];\r
-                $SESSION->HIVE_SESSION = $cookie;\r
-                return true;\r
-            }\r
-        }\r
-    }\r
-\r
-/// Try again with the guest username and password\r
-\r
-    $submit_vars['HIVE_UNAME']  = $CFG->hiveusername;\r
-    $submit_vars['HIVE_UPASS']  = $CFG->hivepassword;\r
-    $submit_vars['HIVE_ENDUSER']= $CFG->hiveusername;\r
-    $snoopy->submit($submit_url,$submit_vars);\r
-    foreach ($snoopy->headers as $header) {\r
-        if (strpos($header, 'HIVE_SESSION=') !== false) {\r
-            $header = explode('HIVE_SESSION=', $header);\r
-            if (count($header) > 1) {\r
-                $cookie = explode(';', $header[1]);\r
-                $cookie = $cookie[0];\r
-                $SESSION->HIVE_SESSION = $cookie;\r
-                return true;\r
-            }\r
-        }\r
-    }\r
-\r
-    return false;  // No cookie found\r
-}\r
-\r
-?>\r
+<?php  // $Id$
+       // Logs into Hive from HarvestRoad and stores session ID in Moodle session
+       // Martin Dougiamas, Moodle
+       //
+       // Example CFG variables to make this work:
+
+       // $CFG->sso          = 'hive';
+       // $CFG->hiveprotocol = 'http';
+       // $CFG->hiveport     = '80';
+       // $CFG->hivehost     = 'turkey.harvestroad.com.au';
+       // $CFG->hivepath     = '/cgi-bin/hive/hive.cgi';
+       // $CFG->hivecbid     = '28';
+
+function sso_user_login($username, $password) {
+
+    global $CFG, $SESSION;
+
+    include($CFG->libdir.'/snoopy/Snoopy.class.inc');
+
+    if (empty($CFG->hivehost)) {
+        return false;   // Hive config variables not configured yet
+    }
+
+/// Set up Snoopy
+
+    $snoopy = new Snoopy;
+
+    $submit_url = $CFG->hiveprotocol .'://'. $CFG->hivehost .':'. $CFG->hiveport .''. $CFG->hivepath ;
+
+    $submit_vars['HIVE_UNAME']  = $username;
+    $submit_vars['HIVE_UPASS']  = $password;
+    $submit_vars['HIVE_ENDUSER']= $username;
+    $submit_vars['HIVE_REQ']    = '2112';
+    $submit_vars['HIVE_REF']    = 'hin:hive@API Login 3';
+    $submit_vars['HIVE_RET']    = 'ORG';
+    $submit_vars['HIVE_REM']    = '';
+    $submit_vars['HIVE_PROD']   = '0';
+    $submit_vars['HIVE_USERIP'] = getremoteaddr();
+
+
+/// We use POST to call Hive with a bit more security
+    $snoopy->submit($submit_url,$submit_vars);
+
+/// Extract HIVE_SESSION from headers
+
+    foreach ($snoopy->headers as $header) {
+        if (strpos($header, 'HIVE_SESSION=') !== false) {
+            $header = explode('HIVE_SESSION=', $header);
+            if (count($header) > 1) {
+                $cookie = explode(';', $header[1]);
+                $cookie = $cookie[0];
+                $SESSION->HIVE_SESSION = $cookie;
+                return true;
+            }
+        }
+    }
+
+/// Try again with the guest username and password
+
+    $submit_vars['HIVE_UNAME']  = $CFG->hiveusername;
+    $submit_vars['HIVE_UPASS']  = $CFG->hivepassword;
+    $submit_vars['HIVE_ENDUSER']= $CFG->hiveusername;
+    $snoopy->submit($submit_url,$submit_vars);
+    foreach ($snoopy->headers as $header) {
+        if (strpos($header, 'HIVE_SESSION=') !== false) {
+            $header = explode('HIVE_SESSION=', $header);
+            if (count($header) > 1) {
+                $cookie = explode(';', $header[1]);
+                $cookie = $cookie[0];
+                $SESSION->HIVE_SESSION = $cookie;
+                return true;
+            }
+        }
+    }
+
+    return false;  // No cookie found
+}
+
+?>
index cc83319ed3292ba6887e2e5a9f435e0432c044aa..5bd14c38668ccbd7d2da30dfb34528a71eb63a00 100644 (file)
@@ -1,23 +1,23 @@
-<?php  // $Id$\r
-       // login.php - action of the login form put up by expired.php.\r
-\r
-    require('../../config.php');\r
-\r
-    require('lib.php');\r
-\r
-    require_login();\r
-\r
-    // get the login data \r
-    $frm = data_submitted('');\r
-\r
-    // log back into Hive\r
-    if (sso_user_login($frm->username, $frm->password)) {  \r
-\r
-        /// reopen Hive\r
-        redirect($CFG->wwwroot.'/mod/resource/type/repository/hive/openlitebrowse.php');\r
-    } else {\r
-        redirect($CFG->wwwroot.'/sso/hive/expired.php');\r
-    }\r
-\r
-?>\r
-\r
+<?php  // $Id$
+       // login.php - action of the login form put up by expired.php.
+
+    require('../../config.php');
+
+    require('lib.php');
+
+    require_login();
+
+    // get the login data 
+    $frm = data_submitted('');
+
+    // log back into Hive
+    if (sso_user_login($frm->username, $frm->password)) {  
+
+        /// reopen Hive
+        redirect($CFG->wwwroot.'/mod/resource/type/repository/hive/openlitebrowse.php');
+    } else {
+        redirect($CFG->wwwroot.'/sso/hive/expired.php');
+    }
+
+?>
+
index 5d282681945982673ff81c207468d693a8a7772e..5e54d21397b87a2f2878cdc8d1b6f1326ee1dae7 100644 (file)
@@ -1,42 +1,42 @@
-ACTIVITY MODULES\r
-----------------\r
-\r
-These are main modules in Moodle, allowing various activities.\r
-\r
-\r
-Each of these modules contains a number of expected components:\r
-\r
-  mod.html: a form to setup/update a module instance\r
-\r
-  version.php: defines some meta-info and provides upgrading code\r
-\r
-  icon.gif: a 16x16 icon for the module\r
-\r
-  db/mysql.sql: an SQL dump of all the required db tables and data\r
\r
-  index.php: a page to list all instances in a course\r
-\r
-  view.php: a page to view a particular instance\r
-\r
-  lib.php: any/all functions defined by the module should be in here.\r
-         constants should be defined using MODULENAME_xxxxxx\r
-         functions should be defined using modulename_xxxxxx\r
-\r
-         There are a number of standard functions:\r
-\r
-         modulename_add_instance()\r
-         modulename_update_instance()\r
-         modulename_delete_instance()\r
-\r
-         modulename_user_complete()\r
-         modulename_user_outline()\r
-\r
-         modulename_cron()\r
-\r
-         modulename_print_recent_activity()\r
-\r
-\r
-If you are a developer and interested in developing new Modules see:\r
-  \r
-   Moodle Documentation:  http://moodle.org/doc\r
-   Moodle Community:      http://moodle.org/community\r
+ACTIVITY MODULES
+----------------
+
+These are main modules in Moodle, allowing various activities.
+
+
+Each of these modules contains a number of expected components:
+
+  mod.html: a form to setup/update a module instance
+
+  version.php: defines some meta-info and provides upgrading code
+
+  icon.gif: a 16x16 icon for the module
+
+  db/mysql.sql: an SQL dump of all the required db tables and data
+  index.php: a page to list all instances in a course
+
+  view.php: a page to view a particular instance
+
+  lib.php: any/all functions defined by the module should be in here.
+         constants should be defined using MODULENAME_xxxxxx
+         functions should be defined using modulename_xxxxxx
+
+         There are a number of standard functions:
+
+         modulename_add_instance()
+         modulename_update_instance()
+         modulename_delete_instance()
+
+         modulename_user_complete()
+         modulename_user_outline()
+
+         modulename_cron()
+
+         modulename_print_recent_activity()
+
+
+If you are a developer and interested in developing new Modules see:
+  
+   Moodle Documentation:  http://moodle.org/doc
+   Moodle Community:      http://moodle.org/community
index 1fcab4a10e96ee5c7d6ee7fb615ecc0a99da7c5b..7a6efee85b5dda255bc42b84537cbee22692ae1c 100644 (file)
-/*\r
-       cssQuery, version 2.0.2 (2005-08-19)\r
-       Copyright: 2004-2005, Dean Edwards (http://dean.edwards.name/)\r
-       License: http://creativecommons.org/licenses/LGPL/2.1/\r
-*/\r
-\r
-// the following functions allow querying of the DOM using CSS selectors\r
-var cssQuery = function() {\r
-var version = "2.0.2";\r
-\r
-// -----------------------------------------------------------------------\r
-// main query function\r
-// -----------------------------------------------------------------------\r
-\r
-var $COMMA = /\s*,\s*/;\r
-var cssQuery = function($selector, $$from) {\r
-try {\r
-       var $match = [];\r
-       var $useCache = arguments.callee.caching && !$$from;\r
-       var $base = ($$from) ? ($$from.constructor == Array) ? $$from : [$$from] : [document];\r
-       // process comma separated selectors\r
-       var $$selectors = parseSelector($selector).split($COMMA), i;\r
-       for (i = 0; i < $$selectors.length; i++) {\r
-               // convert the selector to a stream\r
-               $selector = _toStream($$selectors[i]);\r
-               // faster chop if it starts with id (MSIE only)\r
-               if (isMSIE && $selector.slice(0, 3).join("") == " *#") {\r
-                       $selector = $selector.slice(2);\r
-                       $$from = _msie_selectById([], $base, $selector[1]);\r
-               } else $$from = $base;\r
-               // process the stream\r
-               var j = 0, $token, $filter, $arguments, $cacheSelector = "";\r
-               while (j < $selector.length) {\r
-                       $token = $selector[j++];\r
-                       $filter = $selector[j++];\r
-                       $cacheSelector += $token + $filter;\r
-                       // some pseudo-classes allow arguments to be passed\r
-                       //  e.g. nth-child(even)\r
-                       $arguments = "";\r
-                       if ($selector[j] == "(") {\r
-                               while ($selector[j++] != ")" && j < $selector.length) {\r
-                                       $arguments += $selector[j];\r
-                               }\r
-                               $arguments = $arguments.slice(0, -1);\r
-                               $cacheSelector += "(" + $arguments + ")";\r
-                       }\r
-                       // process a token/filter pair use cached results if possible\r
-                       $$from = ($useCache && cache[$cacheSelector]) ?\r
-                               cache[$cacheSelector] : select($$from, $token, $filter, $arguments);\r
-                       if ($useCache) cache[$cacheSelector] = $$from;\r
-               }\r
-               $match = $match.concat($$from);\r
-       }\r
-       delete cssQuery.error;\r
-       return $match;\r
-} catch ($error) {\r
-       cssQuery.error = $error;\r
-       return [];\r
-}};\r
-\r
-// -----------------------------------------------------------------------\r
-// public interface\r
-// -----------------------------------------------------------------------\r
-\r
-cssQuery.toString = function() {\r
-       return "function cssQuery() {\n  [version " + version + "]\n}";\r
-};\r
-\r
-// caching\r
-var cache = {};\r
-cssQuery.caching = false;\r
-cssQuery.clearCache = function($selector) {\r
-       if ($selector) {\r
-               $selector = _toStream($selector).join("");\r
-               delete cache[$selector];\r
-       } else cache = {};\r
-};\r
-\r
-// allow extensions\r
-var modules = {};\r
-var loaded = false;\r
-cssQuery.addModule = function($name, $script) {\r
-       if (loaded) eval("$script=" + String($script));\r
-       modules[$name] = new $script();;\r
-};\r
-\r
-// hackery\r
-cssQuery.valueOf = function($code) {\r
-       return $code ? eval($code) : this;\r
-};\r
-\r
-// -----------------------------------------------------------------------\r
-// declarations\r
-// -----------------------------------------------------------------------\r
-\r
-var selectors = {};\r
-var pseudoClasses = {};\r
-// a safari bug means that these have to be declared here\r
-var AttributeSelector = {match: /\[([\w-]+(\|[\w-]+)?)\s*(\W?=)?\s*([^\]]*)\]/};\r
-var attributeSelectors = [];\r
-\r
-// -----------------------------------------------------------------------\r
-// selectors\r
-// -----------------------------------------------------------------------\r
-\r
-// descendant selector\r
-selectors[" "] = function($results, $from, $tagName, $namespace) {\r
-       // loop through current selection\r
-       var $element, i, j;\r
-       for (i = 0; i < $from.length; i++) {\r
-               // get descendants\r
-               var $subset = getElementsByTagName($from[i], $tagName, $namespace);\r
-               // loop through descendants and add to results selection\r
-               for (j = 0; ($element = $subset[j]); j++) {\r
-                       if (thisElement($element) && compareNamespace($element, $namespace))\r
-                               $results.push($element);\r
-               }\r
-       }\r
-};\r
-\r
-// ID selector\r
-selectors["#"] = function($results, $from, $id) {\r
-       // loop through current selection and check ID\r
-       var $element, j;\r
-       for (j = 0; ($element = $from[j]); j++) if ($element.id == $id) $results.push($element);\r
-};\r
-\r
-// class selector\r
-selectors["."] = function($results, $from, $className) {\r
-       // create a RegExp version of the class\r
-       $className = new RegExp("(^|\\s)" + $className + "(\\s|$)");\r
-       // loop through current selection and check class\r
-       var $element, i;\r
-       for (i = 0; ($element = $from[i]); i++)\r
-               if ($className.test($element.className)) $results.push($element);\r
-};\r
-\r
-// pseudo-class selector\r
-selectors[":"] = function($results, $from, $pseudoClass, $arguments) {\r
-       // retrieve the cssQuery pseudo-class function\r
-       var $test = pseudoClasses[$pseudoClass], $element, i;\r
-       // loop through current selection and apply pseudo-class filter\r
-       if ($test) for (i = 0; ($element = $from[i]); i++)\r
-               // if the cssQuery pseudo-class function returns "true" add the element\r
-               if ($test($element, $arguments)) $results.push($element);\r
-};\r
-\r
-// -----------------------------------------------------------------------\r
-// pseudo-classes\r
-// -----------------------------------------------------------------------\r
-\r
-pseudoClasses["link"] = function($element) {\r
-       var $document = getDocument($element);\r
-       if ($document.links) for (var i = 0; i < $document.links.length; i++) {\r
-               if ($document.links[i] == $element) return true;\r
-       }\r
-};\r
-\r
-pseudoClasses["visited"] = function($element) {\r
-       // can't do this without jiggery-pokery\r
-};\r
-\r
-// -----------------------------------------------------------------------\r
-// DOM traversal\r
-// -----------------------------------------------------------------------\r
-\r
-// IE5/6 includes comments (LOL) in it's elements collections.\r
-// so we have to check for this. the test is tagName != "!". LOL (again).\r
-var thisElement = function($element) {\r
-       return ($element && $element.nodeType == 1 && $element.tagName != "!") ? $element : null;\r
-};\r
-\r
-// return the previous element to the supplied element\r
-//  previousSibling is not good enough as it might return a text or comment node\r
-var previousElementSibling = function($element) {\r
-       while ($element && ($element = $element.previousSibling) && !thisElement($element)) continue;\r
-       return $element;\r
-};\r
-\r
-// return the next element to the supplied element\r
-var nextElementSibling = function($element) {\r
-       while ($element && ($element = $element.nextSibling) && !thisElement($element)) continue;\r
-       return $element;\r
-};\r
-\r
-// return the first child ELEMENT of an element\r
-//  NOT the first child node (though they may be the same thing)\r
-var firstElementChild = function($element) {\r
-       return thisElement($element.firstChild) || nextElementSibling($element.firstChild);\r
-};\r
-\r
-var lastElementChild = function($element) {\r
-       return thisElement($element.lastChild) || previousElementSibling($element.lastChild);\r
-};\r
-\r
-// return child elements of an element (not child nodes)\r
-var childElements = function($element) {\r
-       var $childElements = [];\r
-       $element = firstElementChild($element);\r
-       while ($element) {\r
-               $childElements.push($element);\r
-               $element = nextElementSibling($element);\r
-       }\r
-       return $childElements;\r
-};\r
-\r
-// -----------------------------------------------------------------------\r
-// browser compatibility\r
-// -----------------------------------------------------------------------\r
-\r
-// all of the functions in this section can be overwritten. the default\r
-//  configuration is for IE. The functions below reflect this. standard\r
-//  methods are included in a separate module. It would probably be better\r
-//  the other way round of course but this makes it easier to keep IE7 trim.\r
-\r
-var isMSIE = true;\r
-\r
-var isXML = function($element) {\r
-       var $document = getDocument($element);\r
-       return (typeof $document.mimeType == "unknown") ?\r
-               /\.xml$/i.test($document.URL) :\r
-               Boolean($document.mimeType == "XML Document");\r
-};\r
-\r
-// return the element's containing document\r
-var getDocument = function($element) {\r
-       return $element.ownerDocument || $element.document;\r
-};\r
-\r
-var getElementsByTagName = function($element, $tagName) {\r
-       return ($tagName == "*" && $element.all) ? $element.all : $element.getElementsByTagName($tagName);\r
-};\r
-\r
-var compareTagName = function($element, $tagName, $namespace) {\r
-       if ($tagName == "*") return thisElement($element);\r
-       if (!compareNamespace($element, $namespace)) return false;\r
-       if (!isXML($element)) $tagName = $tagName.toUpperCase();\r
-       return $element.tagName == $tagName;\r
-};\r
-\r
-var compareNamespace = function($element, $namespace) {\r
-       return !$namespace || ($namespace == "*") || ($element.scopeName == $namespace);\r
-};\r
-\r
-var getTextContent = function($element) {\r
-       return $element.innerText;\r
-};\r
-\r
-function _msie_selectById($results, $from, id) {\r
-       var $match, i, j;\r
-       for (i = 0; i < $from.length; i++) {\r
-               if ($match = $from[i].all.item(id)) {\r
-                       if ($match.id == id) $results.push($match);\r
-                       else if ($match.length != null) {\r
-                               for (j = 0; j < $match.length; j++) {\r
-                                       if ($match[j].id == id) $results.push($match[j]);\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       return $results;\r
-};\r
-\r
-// for IE5.0\r
-if (![].push) Array.prototype.push = function() {\r
-       for (var i = 0; i < arguments.length; i++) {\r
-               this[this.length] = arguments[i];\r
-       }\r
-       return this.length;\r
-};\r
-\r
-// -----------------------------------------------------------------------\r
-// query support\r
-// -----------------------------------------------------------------------\r
-\r
-// select a set of matching elements.\r
-// "from" is an array of elements.\r
-// "token" is a character representing the type of filter\r
-//  e.g. ">" means child selector\r
-// "filter" represents the tag name, id or class name that is being selected\r
-// the function returns an array of matching elements\r
-var $NAMESPACE = /\|/;\r
-function select($$from, $token, $filter, $arguments) {\r
-       if ($NAMESPACE.test($filter)) {\r
-               $filter = $filter.split($NAMESPACE);\r
-               $arguments = $filter[0];\r
-               $filter = $filter[1];\r
-       }\r
-       var $results = [];\r
-       if (selectors[$token]) {\r
-               selectors[$token]($results, $$from, $filter, $arguments);\r
-       }\r
-       return $results;\r
-};\r
-\r
-// -----------------------------------------------------------------------\r
-// parsing\r
-// -----------------------------------------------------------------------\r
-\r
-// convert css selectors to a stream of tokens and filters\r
-//  it's not a real stream. it's just an array of strings.\r
-var $STANDARD_SELECT = /^[^\s>+~]/;\r
-var $$STREAM = /[\s#.:>+~()@]|[^\s#.:>+~()@]+/g;\r
-function _toStream($selector) {\r
-       if ($STANDARD_SELECT.test($selector)) $selector = " " + $selector;\r
-       return $selector.match($$STREAM) || [];\r
-};\r
-\r
-var $WHITESPACE = /\s*([\s>+~(),]|^|$)\s*/g;\r
-var $IMPLIED_ALL = /([\s>+~,]|[^(]\+|^)([#.:@])/g;\r
-var parseSelector = function($selector) {\r
-       return $selector\r
-       // trim whitespace\r
-       .replace($WHITESPACE, "$1")\r
-       // e.g. ".class1" --> "*.class1"\r
-       .replace($IMPLIED_ALL, "$1*$2");\r
-};\r
-\r
-var Quote = {\r
-       toString: function() {return "'"},\r
-       match: /^('[^']*')|("[^"]*")$/,\r
-       test: function($string) {\r
-               return this.match.test($string);\r
-       },\r
-       add: function($string) {\r
-               return this.test($string) ? $string : this + $string + this;\r
-       },\r
-       remove: function($string) {\r
-               return this.test($string) ? $string.slice(1, -1) : $string;\r
-       }\r
-};\r
-\r
-var getText = function($text) {\r
-       return Quote.remove($text);\r
-};\r
-\r
-var $ESCAPE = /([\/()[\]?{}|*+-])/g;\r
-function regEscape($string) {\r
-       return $string.replace($ESCAPE, "\\$1");\r
-};\r
-\r
-// -----------------------------------------------------------------------\r
-// modules\r
-// -----------------------------------------------------------------------\r
-\r
-// -------- >>      insert modules here for packaging       << -------- \\\r
-\r
-loaded = true;\r
-\r
-// -----------------------------------------------------------------------\r
-// return the query function\r
-// -----------------------------------------------------------------------\r
-\r
-return cssQuery;\r
-\r
-}(); // cssQuery\r
+/*
+       cssQuery, version 2.0.2 (2005-08-19)
+       Copyright: 2004-2005, Dean Edwards (http://dean.edwards.name/)
+       License: http://creativecommons.org/licenses/LGPL/2.1/
+*/
+
+// the following functions allow querying of the DOM using CSS selectors
+var cssQuery = function() {
+var version = "2.0.2";
+
+// -----------------------------------------------------------------------
+// main query function
+// -----------------------------------------------------------------------
+
+var $COMMA = /\s*,\s*/;
+var cssQuery = function($selector, $$from) {
+try {
+       var $match = [];
+       var $useCache = arguments.callee.caching && !$$from;
+       var $base = ($$from) ? ($$from.constructor == Array) ? $$from : [$$from] : [document];
+       // process comma separated selectors
+       var $$selectors = parseSelector($selector).split($COMMA), i;
+       for (i = 0; i < $$selectors.length; i++) {
+               // convert the selector to a stream
+               $selector = _toStream($$selectors[i]);
+               // faster chop if it starts with id (MSIE only)
+               if (isMSIE && $selector.slice(0, 3).join("") == " *#") {
+                       $selector = $selector.slice(2);
+                       $$from = _msie_selectById([], $base, $selector[1]);
+               } else $$from = $base;
+               // process the stream
+               var j = 0, $token, $filter, $arguments, $cacheSelector = "";
+               while (j < $selector.length) {
+                       $token = $selector[j++];
+                       $filter = $selector[j++];
+                       $cacheSelector += $token + $filter;
+                       // some pseudo-classes allow arguments to be passed
+                       //  e.g. nth-child(even)
+                       $arguments = "";
+                       if ($selector[j] == "(") {
+                               while ($selector[j++] != ")" && j < $selector.length) {
+                                       $arguments += $selector[j];
+                               }
+                               $arguments = $arguments.slice(0, -1);
+                               $cacheSelector += "(" + $arguments + ")";
+                       }
+                       // process a token/filter pair use cached results if possible
+                       $$from = ($useCache && cache[$cacheSelector]) ?
+                               cache[$cacheSelector] : select($$from, $token, $filter, $arguments);
+                       if ($useCache) cache[$cacheSelector] = $$from;
+               }
+               $match = $match.concat($$from);
+       }
+       delete cssQuery.error;
+       return $match;
+} catch ($error) {
+       cssQuery.error = $error;
+       return [];
+}};
+
+// -----------------------------------------------------------------------
+// public interface
+// -----------------------------------------------------------------------
+
+cssQuery.toString = function() {
+       return "function cssQuery() {\n  [version " + version + "]\n}";
+};
+
+// caching
+var cache = {};
+cssQuery.caching = false;
+cssQuery.clearCache = function($selector) {
+       if ($selector) {
+               $selector = _toStream($selector).join("");
+               delete cache[$selector];
+       } else cache = {};
+};
+
+// allow extensions
+var modules = {};
+var loaded = false;
+cssQuery.addModule = function($name, $script) {
+       if (loaded) eval("$script=" + String($script));
+       modules[$name] = new $script();;
+};
+
+// hackery
+cssQuery.valueOf = function($code) {
+       return $code ? eval($code) : this;
+};
+
+// -----------------------------------------------------------------------
+// declarations
+// -----------------------------------------------------------------------
+
+var selectors = {};
+var pseudoClasses = {};
+// a safari bug means that these have to be declared here
+var AttributeSelector = {match: /\[([\w-]+(\|[\w-]+)?)\s*(\W?=)?\s*([^\]]*)\]/};
+var attributeSelectors = [];
+
+// -----------------------------------------------------------------------
+// selectors
+// -----------------------------------------------------------------------
+
+// descendant selector
+selectors[" "] = function($results, $from, $tagName, $namespace) {
+       // loop through current selection
+       var $element, i, j;
+       for (i = 0; i < $from.length; i++) {
+               // get descendants
+               var $subset = getElementsByTagName($from[i], $tagName, $namespace);
+               // loop through descendants and add to results selection
+               for (j = 0; ($element = $subset[j]); j++) {
+                       if (thisElement($element) && compareNamespace($element, $namespace))
+                               $results.push($element);
+               }
+       }
+};
+
+// ID selector
+selectors["#"] = function($results, $from, $id) {
+       // loop through current selection and check ID
+       var $element, j;
+       for (j = 0; ($element = $from[j]); j++) if ($element.id == $id) $results.push($element);
+};
+
+// class selector
+selectors["."] = function($results, $from, $className) {
+       // create a RegExp version of the class
+       $className = new RegExp("(^|\\s)" + $className + "(\\s|$)");
+       // loop through current selection and check class
+       var $element, i;
+       for (i = 0; ($element = $from[i]); i++)
+               if ($className.test($element.className)) $results.push($element);
+};
+
+// pseudo-class selector
+selectors[":"] = function($results, $from, $pseudoClass, $arguments) {
+       // retrieve the cssQuery pseudo-class function
+       var $test = pseudoClasses[$pseudoClass], $element, i;
+       // loop through current selection and apply pseudo-class filter
+       if ($test) for (i = 0; ($element = $from[i]); i++)
+               // if the cssQuery pseudo-class function returns "true" add the element
+               if ($test($element, $arguments)) $results.push($element);
+};
+
+// -----------------------------------------------------------------------
+// pseudo-classes
+// -----------------------------------------------------------------------
+
+pseudoClasses["link"] = function($element) {
+       var $document = getDocument($element);
+       if ($document.links) for (var i = 0; i < $document.links.length; i++) {
+               if ($document.links[i] == $element) return true;
+       }
+};
+
+pseudoClasses["visited"] = function($element) {
+       // can't do this without jiggery-pokery
+};
+
+// -----------------------------------------------------------------------
+// DOM traversal
+// -----------------------------------------------------------------------
+
+// IE5/6 includes comments (LOL) in it's elements collections.
+// so we have to check for this. the test is tagName != "!". LOL (again).
+var thisElement = function($element) {
+       return ($element && $element.nodeType == 1 && $element.tagName != "!") ? $element : null;
+};
+
+// return the previous element to the supplied element
+//  previousSibling is not good enough as it might return a text or comment node
+var previousElementSibling = function($element) {
+       while ($element && ($element = $element.previousSibling) && !thisElement($element)) continue;
+       return $element;
+};
+
+// return the next element to the supplied element
+var nextElementSibling = function($element) {
+       while ($element && ($element = $element.nextSibling) && !thisElement($element)) continue;
+       return $element;
+};
+
+// return the first child ELEMENT of an element
+//  NOT the first child node (though they may be the same thing)
+var firstElementChild = function($element) {
+       return thisElement($element.firstChild) || nextElementSibling($element.firstChild);
+};
+
+var lastElementChild = function($element) {
+       return thisElement($element.lastChild) || previousElementSibling($element.lastChild);
+};
+
+// return child elements of an element (not child nodes)
+var childElements = function($element) {
+       var $childElements = [];
+       $element = firstElementChild($element);
+       while ($element) {
+               $childElements.push($element);
+               $element = nextElementSibling($element);
+       }
+       return $childElements;
+};
+
+// -----------------------------------------------------------------------
+// browser compatibility
+// -----------------------------------------------------------------------
+
+// all of the functions in this section can be overwritten. the default
+//  configuration is for IE. The functions below reflect this. standard
+//  methods are included in a separate module. It would probably be better
+//  the other way round of course but this makes it easier to keep IE7 trim.
+
+var isMSIE = true;
+
+var isXML = function($element) {
+       var $document = getDocument($element);
+       return (typeof $document.mimeType == "unknown") ?
+               /\.xml$/i.test($document.URL) :
+               Boolean($document.mimeType == "XML Document");
+};
+
+// return the element's containing document
+var getDocument = function($element) {
+       return $element.ownerDocument || $element.document;
+};
+
+var getElementsByTagName = function($element, $tagName) {
+       return ($tagName == "*" && $element.all) ? $element.all : $element.getElementsByTagName($tagName);
+};
+
+var compareTagName = function($element, $tagName, $namespace) {
+       if ($tagName == "*") return thisElement($element);
+       if (!compareNamespace($element, $namespace)) return false;
+       if (!isXML($element)) $tagName = $tagName.toUpperCase();
+       return $element.tagName == $tagName;
+};
+
+var compareNamespace = function($element, $namespace) {
+       return !$namespace || ($namespace == "*") || ($element.scopeName == $namespace);
+};
+
+var getTextContent = function($element) {
+       return $element.innerText;
+};
+
+function _msie_selectById($results, $from, id) {
+       var $match, i, j;
+       for (i = 0; i < $from.length; i++) {
+               if ($match = $from[i].all.item(id)) {
+                       if ($match.id == id) $results.push($match);
+                       else if ($match.length != null) {
+                               for (j = 0; j < $match.length; j++) {
+                                       if ($match[j].id == id) $results.push($match[j]);
+                               }
+                       }
+               }
+       }
+       return $results;
+};
+
+// for IE5.0
+if (![].push) Array.prototype.push = function() {
+       for (var i = 0; i < arguments.length; i++) {
+               this[this.length] = arguments[i];
+       }
+       return this.length;
+};
+
+// -----------------------------------------------------------------------
+// query support
+// -----------------------------------------------------------------------
+
+// select a set of matching elements.
+// "from" is an array of elements.
+// "token" is a character representing the type of filter
+//  e.g. ">" means child selector
+// "filter" represents the tag name, id or class name that is being selected
+// the function returns an array of matching elements
+var $NAMESPACE = /\|/;
+function select($$from, $token, $filter, $arguments) {
+       if ($NAMESPACE.test($filter)) {
+               $filter = $filter.split($NAMESPACE);
+               $arguments = $filter[0];
+               $filter = $filter[1];
+       }
+       var $results = [];
+       if (selectors[$token]) {
+               selectors[$token]($results, $$from, $filter, $arguments);
+       }
+       return $results;
+};
+
+// -----------------------------------------------------------------------
+// parsing
+// -----------------------------------------------------------------------
+
+// convert css selectors to a stream of tokens and filters
+//  it's not a real stream. it's just an array of strings.
+var $STANDARD_SELECT = /^[^\s>+~]/;
+var $$STREAM = /[\s#.:>+~()@]|[^\s#.:>+~()@]+/g;
+function _toStream($selector) {
+       if ($STANDARD_SELECT.test($selector)) $selector = " " + $selector;
+       return $selector.match($$STREAM) || [];
+};
+
+var $WHITESPACE = /\s*([\s>+~(),]|^|$)\s*/g;
+var $IMPLIED_ALL = /([\s>+~,]|[^(]\+|^)([#.:@])/g;
+var parseSelector = function($selector) {
+       return $selector
+       // trim whitespace
+       .replace($WHITESPACE, "$1")
+       // e.g. ".class1" --> "*.class1"
+       .replace($IMPLIED_ALL, "$1*$2");
+};
+
+var Quote = {
+       toString: function() {return "'"},
+       match: /^('[^']*')|("[^"]*")$/,
+       test: function($string) {
+               return this.match.test($string);
+       },
+       add: function($string) {
+               return this.test($string) ? $string : this + $string + this;
+       },
+       remove: function($string) {
+               return this.test($string) ? $string.slice(1, -1) : $string;
+       }
+};
+
+var getText = function($text) {
+       return Quote.remove($text);
+};
+
+var $ESCAPE = /([\/()[\]?{}|*+-])/g;
+function regEscape($string) {
+       return $string.replace($ESCAPE, "\\$1");
+};
+
+// -----------------------------------------------------------------------
+// modules
+// -----------------------------------------------------------------------
+
+// -------- >>      insert modules here for packaging       << -------- \\
+
+loaded = true;
+
+// -----------------------------------------------------------------------
+// return the query function
+// -----------------------------------------------------------------------
+
+return cssQuery;
+
+}(); // cssQuery
index 7b2cd2646f5801b0f68012f4abcd818adc9e7492..a6e138189b85381876b8c2c25690694980511a8d 100644 (file)
-\r
-/**\r
- * ====================================================================\r
- * About\r
- * ====================================================================\r
- * Sarissa is an ECMAScript library acting as a cross-browser wrapper for native XML APIs.\r
- * The library supports Gecko based browsers like Mozilla and Firefox,\r
- * Internet Explorer (5.5+ with MSXML3.0+), Konqueror, Safari and a little of Opera\r
- * @version 0.9.6.1\r
- * @author: Manos Batsis, mailto: mbatsis at users full stop sourceforge full stop net\r
- * ====================================================================\r
- * Licence\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 version 2 or\r
- * the GNU Lesser General Public License version 2.1 as published by\r
- * the Free Software Foundation (your choice between the two).\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- * GNU General Public License or GNU Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * or GNU Lesser General Public License along with this program; if not,\r
- * write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
- * or visit http://www.gnu.org\r
- *\r
- */\r
-/**\r
- * <p>Sarissa is a utility class. Provides "static" methods for DOMDocument and \r
- * XMLHTTP objects, DOM Node serializatrion to XML strings and other goodies.</p>\r
- * @constructor\r
- */\r
-function Sarissa(){};\r
-/** @private */\r
-Sarissa.PARSED_OK = "Document contains no parsing errors";\r
-/**\r
- * Tells you whether transformNode and transformNodeToObject are available. This functionality\r
- * is contained in sarissa_ieemu_xslt.js and is deprecated. If you want to control XSLT transformations\r
- * use the XSLTProcessor\r
- * @deprecated\r
- * @type boolean\r
- */\r
-Sarissa.IS_ENABLED_TRANSFORM_NODE = false;\r
-/**\r
- * tells you whether XMLHttpRequest (or equivalent) is available\r
- * @type boolean\r
- */\r
-Sarissa.IS_ENABLED_XMLHTTP = false;\r
-/**\r
- * tells you whether selectNodes/selectSingleNode is available\r
- * @type boolean\r
- */\r
-Sarissa.IS_ENABLED_SELECT_NODES = false;\r
-var _sarissa_iNsCounter = 0;\r
-var _SARISSA_IEPREFIX4XSLPARAM = "";\r
-var _SARISSA_HAS_DOM_IMPLEMENTATION = document.implementation && true;\r
-var _SARISSA_HAS_DOM_CREATE_DOCUMENT = _SARISSA_HAS_DOM_IMPLEMENTATION && document.implementation.createDocument;\r
-var _SARISSA_HAS_DOM_FEATURE = _SARISSA_HAS_DOM_IMPLEMENTATION && document.implementation.hasFeature;\r
-var _SARISSA_IS_MOZ = _SARISSA_HAS_DOM_CREATE_DOCUMENT && _SARISSA_HAS_DOM_FEATURE;\r
-var _SARISSA_IS_SAFARI = (navigator.userAgent && navigator.vendor && (navigator.userAgent.toLowerCase().indexOf("applewebkit") != -1 || navigator.vendor.indexOf("Apple") != -1));\r
-var _SARISSA_IS_IE = document.all && window.ActiveXObject && navigator.userAgent.toLowerCase().indexOf("msie") > -1  && navigator.userAgent.toLowerCase().indexOf("opera") == -1;\r
-if(!window.Node || !window.Node.ELEMENT_NODE){\r
-    var Node = {ELEMENT_NODE: 1, ATTRIBUTE_NODE: 2, TEXT_NODE: 3, CDATA_SECTION_NODE: 4, ENTITY_REFERENCE_NODE: 5,  ENTITY_NODE: 6, PROCESSING_INSTRUCTION_NODE: 7, COMMENT_NODE: 8, DOCUMENT_NODE: 9, DOCUMENT_TYPE_NODE: 10, DOCUMENT_FRAGMENT_NODE: 11, NOTATION_NODE: 12};\r
-};\r
-\r
-// IE initialization\r
-if(_SARISSA_IS_IE){\r
-    // for XSLT parameter names, prefix needed by IE\r
-    _SARISSA_IEPREFIX4XSLPARAM = "xsl:";\r
-    // used to store the most recent ProgID available out of the above\r
-    var _SARISSA_DOM_PROGID = "";\r
-    var _SARISSA_XMLHTTP_PROGID = "";\r
-    /**\r
-     * Called when the Sarissa_xx.js file is parsed, to pick most recent\r
-     * ProgIDs for IE, then gets destroyed.\r
-     * @param idList an array of MSXML PROGIDs from which the most recent will be picked for a given object\r
-     * @param enabledList an array of arrays where each array has two items; the index of the PROGID for which a certain feature is enabled\r
-     */\r
-    pickRecentProgID = function (idList, enabledList){\r
-        // found progID flag\r
-        var bFound = false;\r
-        for(var i=0; i < idList.length && !bFound; i++){\r
-            try{\r
-                var oDoc = new ActiveXObject(idList[i]);\r
-                o2Store = idList[i];\r
-                bFound = true;\r
-                for(var j=0;j<enabledList.length;j++)\r
-                    if(i <= enabledList[j][1])\r
-                        Sarissa["IS_ENABLED_"+enabledList[j][0]] = true;\r
-            }catch (objException){\r
-                // trap; try next progID\r
-            };\r
-        };\r
-        if (!bFound)\r
-            throw "Could not retreive a valid progID of Class: " + idList[idList.length-1]+". (original exception: "+e+")";\r
-        idList = null;\r
-        return o2Store;\r
-    };\r
-    // pick best available MSXML progIDs\r
-    _SARISSA_DOM_PROGID = pickRecentProgID(["Msxml2.DOMDocument.5.0", "Msxml2.DOMDocument.4.0", "Msxml2.DOMDocument.3.0", "MSXML2.DOMDocument", "MSXML.DOMDocument", "Microsoft.XMLDOM"], [["SELECT_NODES", 2],["TRANSFORM_NODE", 2]]);\r
-    _SARISSA_XMLHTTP_PROGID = pickRecentProgID(["Msxml2.XMLHTTP.5.0", "Msxml2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"], [["XMLHTTP", 4]]);\r
-    _SARISSA_THREADEDDOM_PROGID = pickRecentProgID(["Msxml2.FreeThreadedDOMDocument.5.0", "MSXML2.FreeThreadedDOMDocument.4.0", "MSXML2.FreeThreadedDOMDocument.3.0"]);\r
-    _SARISSA_XSLTEMPLATE_PROGID = pickRecentProgID(["Msxml2.XSLTemplate.5.0", "Msxml2.XSLTemplate.4.0", "MSXML2.XSLTemplate.3.0"], [["XSLTPROC", 2]]);\r
-    // we dont need this anymore\r
-    pickRecentProgID = null;\r
-    //============================================\r
-    // Factory methods (IE)\r
-    //============================================\r
-    // see non-IE version\r
-    Sarissa.getDomDocument = function(sUri, sName){\r
-        var oDoc = new ActiveXObject(_SARISSA_DOM_PROGID);\r
-        // if a root tag name was provided, we need to load it in the DOM\r
-        // object\r
-        if (sName){\r
-            // if needed, create an artifical namespace prefix the way Moz\r
-            // does\r
-            if (sUri){\r
-                oDoc.loadXML("<a" + _sarissa_iNsCounter + ":" + sName + " xmlns:a" + _sarissa_iNsCounter + "=\"" + sUri + "\" />");\r
-                // don't use the same prefix again\r
-                ++_sarissa_iNsCounter;\r
-            }\r
-            else\r
-                oDoc.loadXML("<" + sName + "/>");\r
-        };\r
-        return oDoc;\r
-    };\r
-    // see non-IE version   \r
-    Sarissa.getParseErrorText = function (oDoc) {\r
-        var parseErrorText = Sarissa.PARSED_OK;\r
-        if(oDoc.parseError != 0){\r
-            parseErrorText = "XML Parsing Error: " + oDoc.parseError.reason + \r
-                "\nLocation: " + oDoc.parseError.url + \r
-                "\nLine Number " + oDoc.parseError.line + ", Column " + \r
-                oDoc.parseError.linepos + \r
-                ":\n" + oDoc.parseError.srcText +\r
-                "\n";\r
-            for(var i = 0;  i < oDoc.parseError.linepos;i++){\r
-                parseErrorText += "-";\r
-            };\r
-            parseErrorText +=  "^\n";\r
-        };\r
-        return parseErrorText;\r
-    };\r
-    // see non-IE version\r
-    Sarissa.setXpathNamespaces = function(oDoc, sNsSet) {\r
-        oDoc.setProperty("SelectionLanguage", "XPath");\r
-        oDoc.setProperty("SelectionNamespaces", sNsSet);\r
-    };   \r
-    /**\r
-     * Basic implementation of Mozilla's XSLTProcessor for IE. \r
-     * Reuses the same XSLT stylesheet for multiple transforms\r
-     * @constructor\r
-     */\r
-    XSLTProcessor = function(){\r
-        this.template = new ActiveXObject(_SARISSA_XSLTEMPLATE_PROGID);\r
-        this.processor = null;\r
-    };\r
-    /**\r
-     * Impoprts the given XSLT DOM and compiles it to a reusable transform\r
-     * @argument xslDoc The XSLT DOMDocument to import\r
-     */\r
-    XSLTProcessor.prototype.importStylesheet = function(xslDoc){\r
-        // convert stylesheet to free threaded\r
-        var converted = new ActiveXObject(_SARISSA_THREADEDDOM_PROGID); \r
-        converted.loadXML(xslDoc.xml);\r
-        this.template.stylesheet = converted;\r
-        this.processor = this.template.createProcessor();\r
-        // (re)set default param values\r
-        this.paramsSet = new Array();\r
-    };\r
-    /**\r
-     * Transform the given XML DOM\r
-     * @argument sourceDoc The XML DOMDocument to transform\r
-     * @return The transformation result as a DOM Document\r
-     */\r
-    XSLTProcessor.prototype.transformToDocument = function(sourceDoc){\r
-        this.processor.input = sourceDoc;\r
-        var outDoc = new ActiveXObject(_SARISSA_DOM_PROGID);\r
-        this.processor.output = outDoc; \r
-        this.processor.transform();\r
-        return outDoc;\r
-    };\r
-    /**\r
-     * Set global XSLT parameter of the imported stylesheet\r
-     * @argument nsURI The parameter namespace URI\r
-     * @argument name The parameter base name\r
-     * @argument value The new parameter value\r
-     */\r
-    XSLTProcessor.prototype.setParameter = function(nsURI, name, value){\r
-        /* nsURI is optional but cannot be null */\r
-        if(nsURI){\r
-            this.processor.addParameter(name, value, nsURI);\r
-        }else{\r
-            this.processor.addParameter(name, value);\r
-        };\r
-        /* update updated params for getParameter */\r
-        if(!this.paramsSet[""+nsURI]){\r
-            this.paramsSet[""+nsURI] = new Array();\r
-        };\r
-        this.paramsSet[""+nsURI][name] = value;\r
-    };\r
-    /**\r
-     * Gets a parameter if previously set by setParameter. Returns null\r
-     * otherwise\r
-     * @argument name The parameter base name\r
-     * @argument value The new parameter value\r
-     * @return The parameter value if reviously set by setParameter, null otherwise\r
-     */\r
-    XSLTProcessor.prototype.getParameter = function(nsURI, name){\r
-        nsURI = nsURI || "";\r
-        if(nsURI in this.paramsSet && name in this.paramsSet[nsURI]){\r
-            return this.paramsSet[nsURI][name];\r
-        }else{\r
-            return null;\r
-        };\r
-    };\r
-}\r
-else{ /* end IE initialization, try to deal with real browsers now ;-) */\r
-    if(_SARISSA_HAS_DOM_CREATE_DOCUMENT){\r
-        /**\r
-         * <p>Ensures the document was loaded correctly, otherwise sets the\r
-         * parseError to -1 to indicate something went wrong. Internal use</p>\r
-         * @private\r
-         */\r
-        Sarissa.__handleLoad__ = function(oDoc){\r
-            if (!oDoc.documentElement || oDoc.documentElement.tagName == "parsererror")\r
-                oDoc.parseError = -1;\r
-            Sarissa.__setReadyState__(oDoc, 4);\r
-        };\r
-        /**\r
-        * <p>Attached by an event handler to the load event. Internal use.</p>\r
-        * @private\r
-        */\r
-        _sarissa_XMLDocument_onload = function(){\r
-            Sarissa.__handleLoad__(this);\r
-        };\r
-        /**\r
-         * <p>Sets the readyState property of the given DOM Document object.\r
-         * Internal use.</p>\r
-         * @private\r
-         * @argument oDoc the DOM Document object to fire the\r
-         *          readystatechange event\r
-         * @argument iReadyState the number to change the readystate property to\r
-         */\r
-        Sarissa.__setReadyState__ = function(oDoc, iReadyState){\r
-            oDoc.readyState = iReadyState;\r
-            if (oDoc.onreadystatechange != null && typeof oDoc.onreadystatechange == "function")\r
-                oDoc.onreadystatechange();\r
-        };\r
-        Sarissa.getDomDocument = function(sUri, sName){\r
-            var oDoc = document.implementation.createDocument(sUri?sUri:"", sName?sName:"", null);\r
-            oDoc.addEventListener("load", _sarissa_XMLDocument_onload, false);\r
-            return oDoc;\r
-        };\r
-        if(window.XMLDocument){\r
-            /**\r
-            * <p>Emulate IE's onreadystatechange attribute</p>\r
-            */\r
-            XMLDocument.prototype.onreadystatechange = null;\r
-            /**\r
-            * <p>Emulates IE's readyState property, which always gives an integer from 0 to 4:</p>\r
-            * <ul><li>1 == LOADING,</li>\r
-            * <li>2 == LOADED,</li>\r
-            * <li>3 == INTERACTIVE,</li>\r
-            * <li>4 == COMPLETED</li></ul>\r
-            */\r
-            XMLDocument.prototype.readyState = 0;\r
-            /**\r
-            * <p>Emulate IE's parseError attribute</p>\r
-            */\r
-            XMLDocument.prototype.parseError = 0;\r
-\r
-            // NOTE: setting async to false will only work with documents\r
-            // called over HTTP (meaning a server), not the local file system,\r
-            // unless you are using Moz 1.4+.\r
-            // BTW the try>catch block is for 1.4; I haven't found a way to check if\r
-            // the property is implemented without\r
-            // causing an error and I dont want to use user agent stuff for that...\r
-            var _SARISSA_SYNC_NON_IMPLEMENTED = false;// ("async" in XMLDocument.prototype) ? false: true;\r
-            /**\r
-            * <p>Keeps a handle to the original load() method. Internal use and only\r
-            * if Mozilla version is lower than 1.4</p>\r
-            * @private\r
-            */\r
-            XMLDocument.prototype._sarissa_load = XMLDocument.prototype.load;\r
-\r
-            /**\r
-            * <p>Overrides the original load method to provide synchronous loading for\r
-            * Mozilla versions prior to 1.4, using an XMLHttpRequest object (if\r
-            * async is set to false)</p>\r
-            * @returns the DOM Object as it was before the load() call (may be  empty)\r
-            */\r
-            XMLDocument.prototype.load = function(sURI) {\r
-                var oDoc = document.implementation.createDocument("", "", null);\r
-                Sarissa.copyChildNodes(this, oDoc);\r
-                this.parseError = 0;\r
-                Sarissa.__setReadyState__(this, 1);\r
-                try {\r
-                    if(this.async == false && _SARISSA_SYNC_NON_IMPLEMENTED) {\r
-                        var tmp = new XMLHttpRequest();\r
-                        tmp.open("GET", sURI, false);\r
-                        tmp.send(null);\r
-                        Sarissa.__setReadyState__(this, 2);\r
-                        Sarissa.copyChildNodes(tmp.responseXML, this);\r
-                        Sarissa.__setReadyState__(this, 3);\r
-                    }\r
-                    else {\r
-                        this._sarissa_load(sURI);\r
-                    };\r
-                }\r
-                catch (objException) {\r
-                    this.parseError = -1;\r
-                }\r
-                finally {\r
-                    if(this.async == false){\r
-                        Sarissa.__handleLoad__(this);\r
-                    };\r
-                };\r
-                return oDoc;\r
-            };\r
-            \r
-            \r
-        }//if(window.XMLDocument)\r
-        else if(document.implementation && document.implementation.hasFeature && document.implementation.hasFeature('LS', '3.0')){\r
-            Document.prototype.async = true;\r
-            Document.prototype.onreadystatechange = null;\r
-            Document.prototype.parseError = 0;\r
-            Document.prototype.load = function(sURI) {\r
-                var parser = document.implementation.createLSParser(this.async ? document.implementation.MODE_ASYNCHRONOUS : document.implementation.MODE_SYNCHRONOUS, null);\r
-                if(this.async){\r
-                    var self = this;\r
-                    parser.addEventListener("load", \r
-                        function(e) { \r
-                            self.readyState = 4;\r
-                            Sarissa.copyChildNodes(e.newDocument, self.documentElement, false);\r
-                            self.onreadystatechange.call(); \r
-                        }, \r
-                        false); \r
-                };\r
-                try {\r
-                    var oDoc = parser.parseURI(sURI);\r
-                }\r
-                catch(e){\r
-                    this.parseError = -1;\r
-                };\r
-                if(!this.async)\r
-                   Sarissa.copyChildNodes(oDoc, this.documentElement, false);\r
-                return oDoc;\r
-            };\r
-            /**\r
-            * <p>Factory method to obtain a new DOM Document object</p>\r
-            * @argument sUri the namespace of the root node (if any)\r
-            * @argument sUri the local name of the root node (if any)\r
-            * @returns a new DOM Document\r
-            */\r
-            Sarissa.getDomDocument = function(sUri, sName){\r
-                return document.implementation.createDocument(sUri?sUri:"", sName?sName:"", null);\r
-            };        \r
-        };\r
-    };//if(_SARISSA_HAS_DOM_CREATE_DOCUMENT)\r
-};\r
-//==========================================\r
-// Common stuff\r
-//==========================================\r
-if(!window.DOMParser){\r
-    /*\r
-    * DOMParser is a utility class, used to construct DOMDocuments from XML strings\r
-    * @constructor\r
-    */\r
-    DOMParser = function() {\r
-    };\r
-    if(_SARISSA_IS_SAFARI){\r
-        /** \r
-        * Construct a new DOM Document from the given XMLstring\r
-        * @param sXml the given XML string\r
-        * @param contentType the content type of the document the given string represents (one of text/xml, application/xml, application/xhtml+xml). \r
-        * @return a new DOM Document from the given XML string\r
-        */\r
-        DOMParser.prototype.parseFromString = function(sXml, contentType){\r
-            if(contentType.toLowerCase() != "application/xml"){\r
-                throw "Cannot handle content type: \"" + contentType + "\"";\r
-            };\r
-            var xmlhttp = new XMLHttpRequest();\r
-            xmlhttp.open("GET", "data:text/xml;charset=utf-8," + encodeURIComponent(str), false);\r
-            xmlhttp.send(null);\r
-            return xmlhttp.responseXML;\r
-        };\r
-    }else if(Sarissa.getDomDocument && Sarissa.getDomDocument() && "loadXML" in Sarissa.getDomDocument()){\r
-        DOMParser.prototype.parseFromString = function(sXml, contentType){\r
-            var doc = Sarissa.getDomDocument();\r
-            doc.loadXML(sXml);\r
-            return doc;\r
-        };\r
-    };\r
-};\r
-\r
-if(window.XMLHttpRequest){\r
-    Sarissa.IS_ENABLED_XMLHTTP = true;\r
-}\r
-else if(_SARISSA_IS_IE){\r
-    /**\r
-     * Emulate XMLHttpRequest\r
-     * @constructor\r
-     */\r
-    XMLHttpRequest = function() {\r
-        return new ActiveXObject(_SARISSA_XMLHTTP_PROGID);\r
-    };\r
-    Sarissa.IS_ENABLED_XMLHTTP = true;\r
-};\r
-\r
-if(!window.document.importNode && _SARISSA_IS_IE){\r
-    try{\r
-        /**\r
-        * Implements importNode for the current window document in IE using innerHTML.\r
-        * Testing showed that DOM was multiple times slower than innerHTML for this,\r
-        * sorry folks. If you encounter trouble (who knows what IE does behind innerHTML)\r
-        * please gimme a call.\r
-        * @param oNode the Node to import\r
-        * @param bChildren whether to include the children of oNode\r
-        * @returns the imported node for further use\r
-        */\r
-        window.document.importNode = function(oNode, bChildren){\r
-            var importNode = document.createElement("div");\r
-            if(bChildren)\r
-                importNode.innerHTML = Sarissa.serialize(oNode);\r
-            else\r
-                importNode.innerHTML = Sarissa.serialize(oNode.cloneNode(false));\r
-            return importNode.firstChild;\r
-        };\r
-        }catch(e){};\r
-};\r
-if(!Sarissa.getParseErrorText){\r
-    /**\r
-     * <p>Returns a human readable description of the parsing error. Usefull\r
-     * for debugging. Tip: append the returned error string in a &lt;pre&gt;\r
-     * element if you want to render it.</p>\r
-     * <p>Many thanks to Christian Stocker for the initial patch.</p>\r
-     * @argument oDoc The target DOM document\r
-     * @returns The parsing error description of the target Document in\r
-     *          human readable form (preformated text)\r
-     */\r
-    Sarissa.getParseErrorText = function (oDoc){\r
-        var parseErrorText = Sarissa.PARSED_OK;\r
-        if(oDoc && oDoc.parseError && oDoc.parseError != 0){\r
-            /*moz*/\r
-            if(oDoc.documentElement.tagName == "parsererror"){\r
-                parseErrorText = oDoc.documentElement.firstChild.data;\r
-                parseErrorText += "\n" +  oDoc.documentElement.firstChild.nextSibling.firstChild.data;\r
-            }/*konq*/\r
-            else{\r
-                parseErrorText = Sarissa.getText(oDoc.documentElement);/*.getElementsByTagName("h1")[0], false) + "\n";\r
-                parseErrorText += Sarissa.getText(oDoc.documentElement.getElementsByTagName("body")[0], false) + "\n";\r
-                parseErrorText += Sarissa.getText(oDoc.documentElement.getElementsByTagName("pre")[0], false);*/\r
-            };\r
-        };\r
-        return parseErrorText;\r
-    };\r
-};\r
-Sarissa.getText = function(oNode, deep){\r
-    var s = "";\r
-    var nodes = oNode.childNodes;\r
-    for(var i=0; i < nodes.length; i++){\r
-        var node = nodes[i];\r
-        var nodeType = node.nodeType;\r
-        if(nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE){\r
-            s += node.data;\r
-        }else if(deep == true\r
-                    && (nodeType == Node.ELEMENT_NODE\r
-                        || nodeType == Node.DOCUMENT_NODE\r
-                        || nodeType == Node.DOCUMENT_FRAGMENT_NODE)){\r
-            s += Sarissa.getText(node, true);\r
-        };\r
-    };\r
-    return s;\r
-};\r
-if(window.XMLSerializer){\r
-    /**\r
-     * <p>Factory method to obtain the serialization of a DOM Node</p>\r
-     * @returns the serialized Node as an XML string\r
-     */\r
-    Sarissa.serialize = function(oDoc){\r
-        var s = null;\r
-        if(oDoc){\r
-            s = oDoc.innerHTML?oDoc.innerHTML:(new XMLSerializer()).serializeToString(oDoc);\r
-        };\r
-        return s;\r
-    };\r
-}else{\r
-    if(Sarissa.getDomDocument && (Sarissa.getDomDocument("","foo", null)).xml){\r
-        // see non-IE version\r
-        Sarissa.serialize = function(oDoc) {\r
-            var s = null;\r
-            if(oDoc){\r
-                s = oDoc.innerHTML?oDoc.innerHTML:oDoc.xml;\r
-            };\r
-            return s;\r
-        };\r
-        /**\r
-         * Utility class to serialize DOM Node objects to XML strings\r
-         * @constructor\r
-         */\r
-        XMLSerializer = function(){};\r
-        /**\r
-         * Serialize the given DOM Node to an XML string\r
-         * @param oNode the DOM Node to serialize\r
-         */\r
-        XMLSerializer.prototype.serializeToString = function(oNode) {\r
-            return oNode.xml;\r
-        };\r
-    };\r
-};\r
-\r
-/**\r
- * strips tags from a markup string\r
- */\r
-Sarissa.stripTags = function (s) {\r
-    return s.replace(/<[^>]+>/g,"");\r
-};\r
-/**\r
- * <p>Deletes all child nodes of the given node</p>\r
- * @argument oNode the Node to empty\r
- */\r
-Sarissa.clearChildNodes = function(oNode) {\r
-    // need to check for firstChild due to opera 8 bug with hasChildNodes\r
-    while(oNode.firstChild){\r
-        oNode.removeChild(oNode.firstChild);\r
-    };\r
-};\r
-/**\r
- * <p> Copies the childNodes of nodeFrom to nodeTo</p>\r
- * <p> <b>Note:</b> The second object's original content is deleted before \r
- * the copy operation, unless you supply a true third parameter</p>\r
- * @argument nodeFrom the Node to copy the childNodes from\r
- * @argument nodeTo the Node to copy the childNodes to\r
- * @argument bPreserveExisting whether to preserve the original content of nodeTo, default is false\r
- */\r
-Sarissa.copyChildNodes = function(nodeFrom, nodeTo, bPreserveExisting) {\r
-    if((!nodeFrom) || (!nodeTo)){\r
-        throw "Both source and destination nodes must be provided";\r
-    };\r
-    if(!bPreserveExisting){\r
-        Sarissa.clearChildNodes(nodeTo);\r
-    };\r
-    var ownerDoc = nodeTo.nodeType == Node.DOCUMENT_NODE ? nodeTo : nodeTo.ownerDocument;\r
-    var nodes = nodeFrom.childNodes;\r
-    if(ownerDoc.importNode && (!_SARISSA_IS_IE)) {\r
-        for(var i=0;i < nodes.length;i++) {\r
-            nodeTo.appendChild(ownerDoc.importNode(nodes[i], true));\r
-        };\r
-    }\r
-    else{\r
-        for(var i=0;i < nodes.length;i++) {\r
-            nodeTo.appendChild(nodes[i].cloneNode(true));\r
-        };\r
-    };\r
-};\r
-\r
-/**\r
- * <p> Moves the childNodes of nodeFrom to nodeTo</p>\r
- * <p> <b>Note:</b> The second object's original content is deleted before \r
- * the move operation, unless you supply a true third parameter</p>\r
- * @argument nodeFrom the Node to copy the childNodes from\r
- * @argument nodeTo the Node to copy the childNodes to\r
- * @argument bPreserveExisting whether to preserve the original content of nodeTo, default is\r
- */ \r
-Sarissa.moveChildNodes = function(nodeFrom, nodeTo, bPreserveExisting) {\r
-    if((!nodeFrom) || (!nodeTo)){\r
-        throw "Both source and destination nodes must be provided";\r
-    };\r
-    if(!bPreserveExisting){\r
-        Sarissa.clearChildNodes(nodeTo);\r
-    };\r
-    var nodes = nodeFrom.childNodes;\r
-    // if within the same doc, just move, else copy and delete\r
-    if(nodeFrom.ownerDocument == nodeTo.ownerDocument){\r
-        while(nodeFrom.firstChild){\r
-            nodeTo.appendChild(nodeFrom.firstChild);\r
-        };\r
-    }else{\r
-        var ownerDoc = nodeTo.nodeType == Node.DOCUMENT_NODE ? nodeTo : nodeTo.ownerDocument;\r
-        if(ownerDoc.importNode && (!_SARISSA_IS_IE)) {\r
-           for(var i=0;i < nodes.length;i++) {\r
-               nodeTo.appendChild(ownerDoc.importNode(nodes[i], true));\r
-           };\r
-        }else{\r
-           for(var i=0;i < nodes.length;i++) {\r
-               nodeTo.appendChild(nodes[i].cloneNode(true));\r
-           };\r
-        };\r
-        Sarissa.clearChildNodes(nodeFrom);\r
-    };\r
-};\r
-\r
-/** \r
- * <p>Serialize any object to an XML string. All properties are serialized using the property name\r
- * as the XML element name. Array elements are rendered as <code>array-item</code> elements, \r
- * using their index/key as the value of the <code>key</code> attribute.</p>\r
- * @argument anyObject the object to serialize\r
- * @argument objectName a name for that object\r
- * @return the XML serializationj of the given object as a string\r
- */\r
-Sarissa.xmlize = function(anyObject, objectName, indentSpace){\r
-    indentSpace = indentSpace?indentSpace:'';\r
-    var s = indentSpace  + '<' + objectName + '>';\r
-    var isLeaf = false;\r
-    if(!(anyObject instanceof Object) || anyObject instanceof Number || anyObject instanceof String \r
-        || anyObject instanceof Boolean || anyObject instanceof Date){\r
-        s += Sarissa.escape(""+anyObject);\r
-        isLeaf = true;\r
-    }else{\r
-        s += "\n";\r
-        var itemKey = '';\r
-        var isArrayItem = anyObject instanceof Array;\r
-        for(var name in anyObject){\r
-            s += Sarissa.xmlize(anyObject[name], (isArrayItem?"array-item key=\""+name+"\"":name), indentSpace + "   ");\r
-        };\r
-        s += indentSpace;\r
-    };\r
-    return s += (objectName.indexOf(' ')!=-1?"</array-item>\n":"</" + objectName + ">\n");\r
-};\r
-\r
-/** \r
- * Escape the given string chacters that correspond to the five predefined XML entities\r
- * @param sXml the string to escape\r
- */\r
-Sarissa.escape = function(sXml){\r
-    return sXml.replace(/&/g, "&amp;")\r
-        .replace(/</g, "&lt;")\r
-        .replace(/>/g, "&gt;")\r
-        .replace(/"/g, "&quot;")\r
-        .replace(/'/g, "&apos;");\r
-};\r
-\r
-/** \r
- * Unescape the given string. This turns the occurences of the predefined XML \r
- * entities to become the characters they represent correspond to the five predefined XML entities\r
- * @param sXml the string to unescape\r
- */\r
-Sarissa.unescape = function(sXml){\r
-    return sXml.replace(/&apos;/g,"'")\r
-        .replace(/&quot;/g,"\"")\r
-        .replace(/&gt;/g,">")\r
-        .replace(/&lt;/g,"<")\r
-        .replace(/&amp;/g,"&");\r
-};\r
+
+/**
+ * ====================================================================
+ * About
+ * ====================================================================
+ * Sarissa is an ECMAScript library acting as a cross-browser wrapper for native XML APIs.
+ * The library supports Gecko based browsers like Mozilla and Firefox,
+ * Internet Explorer (5.5+ with MSXML3.0+), Konqueror, Safari and a little of Opera
+ * @version 0.9.6.1
+ * @author: Manos Batsis, mailto: mbatsis at users full stop sourceforge full stop net
+ * ====================================================================
+ * Licence
+ * ====================================================================
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or
+ * the GNU Lesser General Public License version 2.1 as published by
+ * the Free Software Foundation (your choice between the two).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License or GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * or GNU Lesser General Public License along with this program; if not,
+ * write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * or visit http://www.gnu.org
+ *
+ */
+/**
+ * <p>Sarissa is a utility class. Provides "static" methods for DOMDocument and 
+ * XMLHTTP objects, DOM Node serializatrion to XML strings and other goodies.</p>
+ * @constructor
+ */
+function Sarissa(){};
+/** @private */
+Sarissa.PARSED_OK = "Document contains no parsing errors";
+/**
+ * Tells you whether transformNode and transformNodeToObject are available. This functionality
+ * is contained in sarissa_ieemu_xslt.js and is deprecated. If you want to control XSLT transformations
+ * use the XSLTProcessor
+ * @deprecated
+ * @type boolean
+ */
+Sarissa.IS_ENABLED_TRANSFORM_NODE = false;
+/**
+ * tells you whether XMLHttpRequest (or equivalent) is available
+ * @type boolean
+ */
+Sarissa.IS_ENABLED_XMLHTTP = false;
+/**
+ * tells you whether selectNodes/selectSingleNode is available
+ * @type boolean
+ */
+Sarissa.IS_ENABLED_SELECT_NODES = false;
+var _sarissa_iNsCounter = 0;
+var _SARISSA_IEPREFIX4XSLPARAM = "";
+var _SARISSA_HAS_DOM_IMPLEMENTATION = document.implementation && true;
+var _SARISSA_HAS_DOM_CREATE_DOCUMENT = _SARISSA_HAS_DOM_IMPLEMENTATION && document.implementation.createDocument;
+var _SARISSA_HAS_DOM_FEATURE = _SARISSA_HAS_DOM_IMPLEMENTATION && document.implementation.hasFeature;
+var _SARISSA_IS_MOZ = _SARISSA_HAS_DOM_CREATE_DOCUMENT && _SARISSA_HAS_DOM_FEATURE;
+var _SARISSA_IS_SAFARI = (navigator.userAgent && navigator.vendor && (navigator.userAgent.toLowerCase().indexOf("applewebkit") != -1 || navigator.vendor.indexOf("Apple") != -1));
+var _SARISSA_IS_IE = document.all && window.ActiveXObject && navigator.userAgent.toLowerCase().indexOf("msie") > -1  && navigator.userAgent.toLowerCase().indexOf("opera") == -1;
+if(!window.Node || !window.Node.ELEMENT_NODE){
+    var Node = {ELEMENT_NODE: 1, ATTRIBUTE_NODE: 2, TEXT_NODE: 3, CDATA_SECTION_NODE: 4, ENTITY_REFERENCE_NODE: 5,  ENTITY_NODE: 6, PROCESSING_INSTRUCTION_NODE: 7, COMMENT_NODE: 8, DOCUMENT_NODE: 9, DOCUMENT_TYPE_NODE: 10, DOCUMENT_FRAGMENT_NODE: 11, NOTATION_NODE: 12};
+};
+
+// IE initialization
+if(_SARISSA_IS_IE){
+    // for XSLT parameter names, prefix needed by IE
+    _SARISSA_IEPREFIX4XSLPARAM = "xsl:";
+    // used to store the most recent ProgID available out of the above
+    var _SARISSA_DOM_PROGID = "";
+    var _SARISSA_XMLHTTP_PROGID = "";
+    /**
+     * Called when the Sarissa_xx.js file is parsed, to pick most recent
+     * ProgIDs for IE, then gets destroyed.
+     * @param idList an array of MSXML PROGIDs from which the most recent will be picked for a given object
+     * @param enabledList an array of arrays where each array has two items; the index of the PROGID for which a certain feature is enabled
+     */
+    pickRecentProgID = function (idList, enabledList){
+        // found progID flag
+        var bFound = false;
+        for(var i=0; i < idList.length && !bFound; i++){
+            try{
+                var oDoc = new ActiveXObject(idList[i]);
+                o2Store = idList[i];
+                bFound = true;
+                for(var j=0;j<enabledList.length;j++)
+                    if(i <= enabledList[j][1])
+                        Sarissa["IS_ENABLED_"+enabledList[j][0]] = true;
+            }catch (objException){
+                // trap; try next progID
+            };
+        };
+        if (!bFound)
+            throw "Could not retreive a valid progID of Class: " + idList[idList.length-1]+". (original exception: "+e+")";
+        idList = null;
+        return o2Store;
+    };
+    // pick best available MSXML progIDs
+    _SARISSA_DOM_PROGID = pickRecentProgID(["Msxml2.DOMDocument.5.0", "Msxml2.DOMDocument.4.0", "Msxml2.DOMDocument.3.0", "MSXML2.DOMDocument", "MSXML.DOMDocument", "Microsoft.XMLDOM"], [["SELECT_NODES", 2],["TRANSFORM_NODE", 2]]);
+    _SARISSA_XMLHTTP_PROGID = pickRecentProgID(["Msxml2.XMLHTTP.5.0", "Msxml2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"], [["XMLHTTP", 4]]);
+    _SARISSA_THREADEDDOM_PROGID = pickRecentProgID(["Msxml2.FreeThreadedDOMDocument.5.0", "MSXML2.FreeThreadedDOMDocument.4.0", "MSXML2.FreeThreadedDOMDocument.3.0"]);
+    _SARISSA_XSLTEMPLATE_PROGID = pickRecentProgID(["Msxml2.XSLTemplate.5.0", "Msxml2.XSLTemplate.4.0", "MSXML2.XSLTemplate.3.0"], [["XSLTPROC", 2]]);
+    // we dont need this anymore
+    pickRecentProgID = null;
+    //============================================
+    // Factory methods (IE)
+    //============================================
+    // see non-IE version
+    Sarissa.getDomDocument = function(sUri, sName){
+        var oDoc = new ActiveXObject(_SARISSA_DOM_PROGID);
+        // if a root tag name was provided, we need to load it in the DOM
+        // object
+        if (sName){
+            // if needed, create an artifical namespace prefix the way Moz
+            // does
+            if (sUri){
+                oDoc.loadXML("<a" + _sarissa_iNsCounter + ":" + sName + " xmlns:a" + _sarissa_iNsCounter + "=\"" + sUri + "\" />");
+                // don't use the same prefix again
+                ++_sarissa_iNsCounter;
+            }
+            else
+                oDoc.loadXML("<" + sName + "/>");
+        };
+        return oDoc;
+    };
+    // see non-IE version   
+    Sarissa.getParseErrorText = function (oDoc) {
+        var parseErrorText = Sarissa.PARSED_OK;
+        if(oDoc.parseError != 0){
+            parseErrorText = "XML Parsing Error: " + oDoc.parseError.reason + 
+                "\nLocation: " + oDoc.parseError.url + 
+                "\nLine Number " + oDoc.parseError.line + ", Column " + 
+                oDoc.parseError.linepos + 
+                ":\n" + oDoc.parseError.srcText +
+                "\n";
+            for(var i = 0;  i < oDoc.parseError.linepos;i++){
+                parseErrorText += "-";
+            };
+            parseErrorText +=  "^\n";
+        };
+        return parseErrorText;
+    };
+    // see non-IE version
+    Sarissa.setXpathNamespaces = function(oDoc, sNsSet) {
+        oDoc.setProperty("SelectionLanguage", "XPath");
+        oDoc.setProperty("SelectionNamespaces", sNsSet);
+    };   
+    /**
+     * Basic implementation of Mozilla's XSLTProcessor for IE. 
+     * Reuses the same XSLT stylesheet for multiple transforms
+     * @constructor
+     */
+    XSLTProcessor = function(){
+        this.template = new ActiveXObject(_SARISSA_XSLTEMPLATE_PROGID);
+        this.processor = null;
+    };
+    /**
+     * Impoprts the given XSLT DOM and compiles it to a reusable transform
+     * @argument xslDoc The XSLT DOMDocument to import
+     */
+    XSLTProcessor.prototype.importStylesheet = function(xslDoc){
+        // convert stylesheet to free threaded
+        var converted = new ActiveXObject(_SARISSA_THREADEDDOM_PROGID); 
+        converted.loadXML(xslDoc.xml);
+        this.template.stylesheet = converted;
+        this.processor = this.template.createProcessor();
+        // (re)set default param values
+        this.paramsSet = new Array();
+    };
+    /**
+     * Transform the given XML DOM
+     * @argument sourceDoc The XML DOMDocument to transform
+     * @return The transformation result as a DOM Document
+     */
+    XSLTProcessor.prototype.transformToDocument = function(sourceDoc){
+        this.processor.input = sourceDoc;
+        var outDoc = new ActiveXObject(_SARISSA_DOM_PROGID);
+        this.processor.output = outDoc; 
+        this.processor.transform();
+        return outDoc;
+    };
+    /**
+     * Set global XSLT parameter of the imported stylesheet
+     * @argument nsURI The parameter namespace URI
+     * @argument name The parameter base name
+     * @argument value The new parameter value
+     */
+    XSLTProcessor.prototype.setParameter = function(nsURI, name, value){
+        /* nsURI is optional but cannot be null */
+        if(nsURI){
+            this.processor.addParameter(name, value, nsURI);
+        }else{
+            this.processor.addParameter(name, value);
+        };
+        /* update updated params for getParameter */
+        if(!this.paramsSet[""+nsURI]){
+            this.paramsSet[""+nsURI] = new Array();
+        };
+        this.paramsSet[""+nsURI][name] = value;
+    };
+    /**
+     * Gets a parameter if previously set by setParameter. Returns null
+     * otherwise
+     * @argument name The parameter base name
+     * @argument value The new parameter value
+     * @return The parameter value if reviously set by setParameter, null otherwise
+     */
+    XSLTProcessor.prototype.getParameter = function(nsURI, name){
+        nsURI = nsURI || "";
+        if(nsURI in this.paramsSet && name in this.paramsSet[nsURI]){
+            return this.paramsSet[nsURI][name];
+        }else{
+            return null;
+        };
+    };
+}
+else{ /* end IE initialization, try to deal with real browsers now ;-) */
+    if(_SARISSA_HAS_DOM_CREATE_DOCUMENT){
+        /**
+         * <p>Ensures the document was loaded correctly, otherwise sets the
+         * parseError to -1 to indicate something went wrong. Internal use</p>
+         * @private
+         */
+        Sarissa.__handleLoad__ = function(oDoc){
+            if (!oDoc.documentElement || oDoc.documentElement.tagName == "parsererror")
+                oDoc.parseError = -1;
+            Sarissa.__setReadyState__(oDoc, 4);
+        };
+        /**
+        * <p>Attached by an event handler to the load event. Internal use.</p>
+        * @private
+        */
+        _sarissa_XMLDocument_onload = function(){
+            Sarissa.__handleLoad__(this);
+        };
+        /**
+         * <p>Sets the readyState property of the given DOM Document object.
+         * Internal use.</p>
+         * @private
+         * @argument oDoc the DOM Document object to fire the
+         *          readystatechange event
+         * @argument iReadyState the number to change the readystate property to
+         */
+        Sarissa.__setReadyState__ = function(oDoc, iReadyState){
+            oDoc.readyState = iReadyState;
+            if (oDoc.onreadystatechange != null && typeof oDoc.onreadystatechange == "function")
+                oDoc.onreadystatechange();
+        };
+        Sarissa.getDomDocument = function(sUri, sName){
+            var oDoc = document.implementation.createDocument(sUri?sUri:"", sName?sName:"", null);
+            oDoc.addEventListener("load", _sarissa_XMLDocument_onload, false);
+            return oDoc;
+        };
+        if(window.XMLDocument){
+            /**
+            * <p>Emulate IE's onreadystatechange attribute</p>
+            */
+            XMLDocument.prototype.onreadystatechange = null;
+            /**
+            * <p>Emulates IE's readyState property, which always gives an integer from 0 to 4:</p>
+            * <ul><li>1 == LOADING,</li>
+            * <li>2 == LOADED,</li>
+            * <li>3 == INTERACTIVE,</li>
+            * <li>4 == COMPLETED</li></ul>
+            */
+            XMLDocument.prototype.readyState = 0;
+            /**
+            * <p>Emulate IE's parseError attribute</p>
+            */
+            XMLDocument.prototype.parseError = 0;
+
+            // NOTE: setting async to false will only work with documents
+            // called over HTTP (meaning a server), not the local file system,
+            // unless you are using Moz 1.4+.
+            // BTW the try>catch block is for 1.4; I haven't found a way to check if
+            // the property is implemented without
+            // causing an error and I dont want to use user agent stuff for that...
+            var _SARISSA_SYNC_NON_IMPLEMENTED = false;// ("async" in XMLDocument.prototype) ? false: true;
+            /**
+            * <p>Keeps a handle to the original load() method. Internal use and only
+            * if Mozilla version is lower than 1.4</p>
+            * @private
+            */
+            XMLDocument.prototype._sarissa_load = XMLDocument.prototype.load;
+
+            /**
+            * <p>Overrides the original load method to provide synchronous loading for
+            * Mozilla versions prior to 1.4, using an XMLHttpRequest object (if
+            * async is set to false)</p>
+            * @returns the DOM Object as it was before the load() call (may be  empty)
+            */
+            XMLDocument.prototype.load = function(sURI) {
+                var oDoc = document.implementation.createDocument("", "", null);
+                Sarissa.copyChildNodes(this, oDoc);
+                this.parseError = 0;
+                Sarissa.__setReadyState__(this, 1);
+                try {
+                    if(this.async == false && _SARISSA_SYNC_NON_IMPLEMENTED) {
+                        var tmp = new XMLHttpRequest();
+                        tmp.open("GET", sURI, false);
+                        tmp.send(null);
+                        Sarissa.__setReadyState__(this, 2);
+                        Sarissa.copyChildNodes(tmp.responseXML, this);
+                        Sarissa.__setReadyState__(this, 3);
+                    }
+                    else {
+                        this._sarissa_load(sURI);
+                    };
+                }
+                catch (objException) {
+                    this.parseError = -1;
+                }
+                finally {
+                    if(this.async == false){
+                        Sarissa.__handleLoad__(this);
+                    };
+                };
+                return oDoc;
+            };
+            
+            
+        }//if(window.XMLDocument)
+        else if(document.implementation && document.implementation.hasFeature && document.implementation.hasFeature('LS', '3.0')){
+            Document.prototype.async = true;
+            Document.prototype.onreadystatechange = null;
+            Document.prototype.parseError = 0;
+            Document.prototype.load = function(sURI) {
+                var parser = document.implementation.createLSParser(this.async ? document.implementation.MODE_ASYNCHRONOUS : document.implementation.MODE_SYNCHRONOUS, null);
+                if(this.async){
+                    var self = this;
+                    parser.addEventListener("load", 
+                        function(e) { 
+                            self.readyState = 4;
+                            Sarissa.copyChildNodes(e.newDocument, self.documentElement, false);
+                            self.onreadystatechange.call(); 
+                        }, 
+                        false); 
+                };
+                try {
+                    var oDoc = parser.parseURI(sURI);
+                }
+                catch(e){
+                    this.parseError = -1;
+                };
+                if(!this.async)
+                   Sarissa.copyChildNodes(oDoc, this.documentElement, false);
+                return oDoc;
+            };
+            /**
+            * <p>Factory method to obtain a new DOM Document object</p>
+            * @argument sUri the namespace of the root node (if any)
+            * @argument sUri the local name of the root node (if any)
+            * @returns a new DOM Document
+            */
+            Sarissa.getDomDocument = function(sUri, sName){
+                return document.implementation.createDocument(sUri?sUri:"", sName?sName:"", null);
+            };        
+        };
+    };//if(_SARISSA_HAS_DOM_CREATE_DOCUMENT)
+};
+//==========================================
+// Common stuff
+//==========================================
+if(!window.DOMParser){
+    /*
+    * DOMParser is a utility class, used to construct DOMDocuments from XML strings
+    * @constructor
+    */
+    DOMParser = function() {
+    };
+    if(_SARISSA_IS_SAFARI){
+        /** 
+        * Construct a new DOM Document from the given XMLstring
+        * @param sXml the given XML string
+        * @param contentType the content type of the document the given string represents (one of text/xml, application/xml, application/xhtml+xml). 
+        * @return a new DOM Document from the given XML string
+        */
+        DOMParser.prototype.parseFromString = function(sXml, contentType){
+            if(contentType.toLowerCase() != "application/xml"){
+                throw "Cannot handle content type: \"" + contentType + "\"";
+            };
+            var xmlhttp = new XMLHttpRequest();
+            xmlhttp.open("GET", "data:text/xml;charset=utf-8," + encodeURIComponent(str), false);
+            xmlhttp.send(null);
+            return xmlhttp.responseXML;
+        };
+    }else if(Sarissa.getDomDocument && Sarissa.getDomDocument() && "loadXML" in Sarissa.getDomDocument()){
+        DOMParser.prototype.parseFromString = function(sXml, contentType){
+            var doc = Sarissa.getDomDocument();
+            doc.loadXML(sXml);
+            return doc;
+        };
+    };
+};
+
+if(window.XMLHttpRequest){
+    Sarissa.IS_ENABLED_XMLHTTP = true;
+}
+else if(_SARISSA_IS_IE){
+    /**
+     * Emulate XMLHttpRequest
+     * @constructor
+     */
+    XMLHttpRequest = function() {
+        return new ActiveXObject(_SARISSA_XMLHTTP_PROGID);
+    };
+    Sarissa.IS_ENABLED_XMLHTTP = true;
+};
+
+if(!window.document.importNode && _SARISSA_IS_IE){
+    try{
+        /**
+        * Implements importNode for the current window document in IE using innerHTML.
+        * Testing showed that DOM was multiple times slower than innerHTML for this,
+        * sorry folks. If you encounter trouble (who knows what IE does behind innerHTML)
+        * please gimme a call.
+        * @param oNode the Node to import
+        * @param bChildren whether to include the children of oNode
+        * @returns the imported node for further use
+        */
+        window.document.importNode = function(oNode, bChildren){
+            var importNode = document.createElement("div");
+            if(bChildren)
+                importNode.innerHTML = Sarissa.serialize(oNode);
+            else
+                importNode.innerHTML = Sarissa.serialize(oNode.cloneNode(false));
+            return importNode.firstChild;
+        };
+        }catch(e){};
+};
+if(!Sarissa.getParseErrorText){
+    /**
+     * <p>Returns a human readable description of the parsing error. Usefull
+     * for debugging. Tip: append the returned error string in a &lt;pre&gt;
+     * element if you want to render it.</p>
+     * <p>Many thanks to Christian Stocker for the initial patch.</p>
+     * @argument oDoc The target DOM document
+     * @returns The parsing error description of the target Document in
+     *          human readable form (preformated text)
+     */
+    Sarissa.getParseErrorText = function (oDoc){
+        var parseErrorText = Sarissa.PARSED_OK;
+        if(oDoc && oDoc.parseError && oDoc.parseError != 0){
+            /*moz*/
+            if(oDoc.documentElement.tagName == "parsererror"){
+                parseErrorText = oDoc.documentElement.firstChild.data;
+                parseErrorText += "\n" +  oDoc.documentElement.firstChild.nextSibling.firstChild.data;
+            }/*konq*/
+            else{
+                parseErrorText = Sarissa.getText(oDoc.documentElement);/*.getElementsByTagName("h1")[0], false) + "\n";
+                parseErrorText += Sarissa.getText(oDoc.documentElement.getElementsByTagName("body")[0], false) + "\n";
+                parseErrorText += Sarissa.getText(oDoc.documentElement.getElementsByTagName("pre")[0], false);*/
+            };
+        };
+        return parseErrorText;
+    };
+};
+Sarissa.getText = function(oNode, deep){
+    var s = "";
+    var nodes = oNode.childNodes;
+    for(var i=0; i < nodes.length; i++){
+        var node = nodes[i];
+        var nodeType = node.nodeType;
+        if(nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE){
+            s += node.data;
+        }else if(deep == true
+                    && (nodeType == Node.ELEMENT_NODE
+                        || nodeType == Node.DOCUMENT_NODE
+                        || nodeType == Node.DOCUMENT_FRAGMENT_NODE)){
+            s += Sarissa.getText(node, true);
+        };
+    };
+    return s;
+};
+if(window.XMLSerializer){
+    /**
+     * <p>Factory method to obtain the serialization of a DOM Node</p>
+     * @returns the serialized Node as an XML string
+     */
+    Sarissa.serialize = function(oDoc){
+        var s = null;
+        if(oDoc){
+            s = oDoc.innerHTML?oDoc.innerHTML:(new XMLSerializer()).serializeToString(oDoc);
+        };
+        return s;
+    };
+}else{
+    if(Sarissa.getDomDocument && (Sarissa.getDomDocument("","foo", null)).xml){
+        // see non-IE version
+        Sarissa.serialize = function(oDoc) {
+            var s = null;
+            if(oDoc){
+                s = oDoc.innerHTML?oDoc.innerHTML:oDoc.xml;
+            };
+            return s;
+        };
+        /**
+         * Utility class to serialize DOM Node objects to XML strings
+         * @constructor
+         */
+        XMLSerializer = function(){};
+        /**
+         * Serialize the given DOM Node to an XML string
+         * @param oNode the DOM Node to serialize
+         */
+        XMLSerializer.prototype.serializeToString = function(oNode) {
+            return oNode.xml;
+        };
+    };
+};
+
+/**
+ * strips tags from a markup string
+ */
+Sarissa.stripTags = function (s) {
+    return s.replace(/<[^>]+>/g,"");
+};
+/**
+ * <p>Deletes all child nodes of the given node</p>
+ * @argument oNode the Node to empty
+ */
+Sarissa.clearChildNodes = function(oNode) {
+    // need to check for firstChild due to opera 8 bug with hasChildNodes
+    while(oNode.firstChild){
+        oNode.removeChild(oNode.firstChild);
+    };
+};
+/**
+ * <p> Copies the childNodes of nodeFrom to nodeTo</p>
+ * <p> <b>Note:</b> The second object's original content is deleted before 
+ * the copy operation, unless you supply a true third parameter</p>
+ * @argument nodeFrom the Node to copy the childNodes from
+ * @argument nodeTo the Node to copy the childNodes to
+ * @argument bPreserveExisting whether to preserve the original content of nodeTo, default is false
+ */
+Sarissa.copyChildNodes = function(nodeFrom, nodeTo, bPreserveExisting) {
+    if((!nodeFrom) || (!nodeTo)){
+        throw "Both source and destination nodes must be provided";
+    };
+    if(!bPreserveExisting){
+        Sarissa.clearChildNodes(nodeTo);
+    };
+    var ownerDoc = nodeTo.nodeType == Node.DOCUMENT_NODE ? nodeTo : nodeTo.ownerDocument;
+    var nodes = nodeFrom.childNodes;
+    if(ownerDoc.importNode && (!_SARISSA_IS_IE)) {
+        for(var i=0;i < nodes.length;i++) {
+            nodeTo.appendChild(ownerDoc.importNode(nodes[i], true));
+        };
+    }
+    else{
+        for(var i=0;i < nodes.length;i++) {
+            nodeTo.appendChild(nodes[i].cloneNode(true));
+        };
+    };
+};
+
+/**
+ * <p> Moves the childNodes of nodeFrom to nodeTo</p>
+ * <p> <b>Note:</b> The second object's original content is deleted before 
+ * the move operation, unless you supply a true third parameter</p>
+ * @argument nodeFrom the Node to copy the childNodes from
+ * @argument nodeTo the Node to copy the childNodes to
+ * @argument bPreserveExisting whether to preserve the original content of nodeTo, default is
+ */ 
+Sarissa.moveChildNodes = function(nodeFrom, nodeTo, bPreserveExisting) {
+    if((!nodeFrom) || (!nodeTo)){
+        throw "Both source and destination nodes must be provided";
+    };
+    if(!bPreserveExisting){
+        Sarissa.clearChildNodes(nodeTo);
+    };
+    var nodes = nodeFrom.childNodes;
+    // if within the same doc, just move, else copy and delete
+    if(nodeFrom.ownerDocument == nodeTo.ownerDocument){
+        while(nodeFrom.firstChild){
+            nodeTo.appendChild(nodeFrom.firstChild);
+        };
+    }else{
+        var ownerDoc = nodeTo.nodeType == Node.DOCUMENT_NODE ? nodeTo : nodeTo.ownerDocument;
+        if(ownerDoc.importNode && (!_SARISSA_IS_IE)) {
+           for(var i=0;i < nodes.length;i++) {
+               nodeTo.appendChild(ownerDoc.importNode(nodes[i], true));
+           };
+        }else{
+           for(var i=0;i < nodes.length;i++) {
+               nodeTo.appendChild(nodes[i].cloneNode(true));
+           };
+        };
+        Sarissa.clearChildNodes(nodeFrom);
+    };
+};
+
+/** 
+ * <p>Serialize any object to an XML string. All properties are serialized using the property name
+ * as the XML element name. Array elements are rendered as <code>array-item</code> elements, 
+ * using their index/key as the value of the <code>key</code> attribute.</p>
+ * @argument anyObject the object to serialize
+ * @argument objectName a name for that object
+ * @return the XML serializationj of the given object as a string
+ */
+Sarissa.xmlize = function(anyObject, objectName, indentSpace){
+    indentSpace = indentSpace?indentSpace:'';
+    var s = indentSpace  + '<' + objectName + '>';
+    var isLeaf = false;
+    if(!(anyObject instanceof Object) || anyObject instanceof Number || anyObject instanceof String 
+        || anyObject instanceof Boolean || anyObject instanceof Date){
+        s += Sarissa.escape(""+anyObject);
+        isLeaf = true;
+    }else{
+        s += "\n";
+        var itemKey = '';
+        var isArrayItem = anyObject instanceof Array;
+        for(var name in anyObject){
+            s += Sarissa.xmlize(anyObject[name], (isArrayItem?"array-item key=\""+name+"\"":name), indentSpace + "   ");
+        };
+        s += indentSpace;
+    };
+    return s += (objectName.indexOf(' ')!=-1?"</array-item>\n":"</" + objectName + ">\n");
+};
+
+/** 
+ * Escape the given string chacters that correspond to the five predefined XML entities
+ * @param sXml the string to escape
+ */
+Sarissa.escape = function(sXml){
+    return sXml.replace(/&/g, "&amp;")
+        .replace(/</g, "&lt;")
+        .replace(/>/g, "&gt;")
+        .replace(/"/g, "&quot;")
+        .replace(/'/g, "&apos;");
+};
+
+/** 
+ * Unescape the given string. This turns the occurences of the predefined XML 
+ * entities to become the characters they represent correspond to the five predefined XML entities
+ * @param sXml the string to unescape
+ */
+Sarissa.unescape = function(sXml){
+    return sXml.replace(/&apos;/g,"'")
+        .replace(/&quot;/g,"\"")
+        .replace(/&gt;/g,">")
+        .replace(/&lt;/g,"<")
+        .replace(/&amp;/g,"&");
+};
 // 
\ No newline at end of file
index 36b0afc6d564f86e35be0980542ec409789a3278..9dfd6aa04bdbdc38ce72de16486636a01a02b013 100755 (executable)
@@ -1,4 +1,4 @@
-/* make some small fonts a little bigger */\r
-.logininfo, .helplink, .minicalendar *, .link, .footer {\r
-  font-size: 9pt !important;\r
-}\r
+/* make some small fonts a little bigger */
+.logininfo, .helplink, .minicalendar *, .link, .footer {
+  font-size: 9pt !important;
+}