<?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;
} 

?>
