PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i5h-3LL

HOME


5h-3LL 1.0
DIR: /srv/http/vyvoj.adent.cz/vyvoj/moodle_esf_vz/mod/hotpot
/srv/http/vyvoj.adent.cz/vyvoj/moodle_esf_vz/mod/hotpot/
Upload File:
Current File : /srv/http/vyvoj.adent.cz/vyvoj/moodle_esf_vz/mod/hotpot/lib.php
<?PHP  // $Id: lib.php,v 1.66.2.7 2007/06/26 12:04:00 gbateson Exp $

//////////////////////////////////
/// CONFIGURATION settings

if (!isset($CFG->hotpot_showtimes)) {
    set_config("hotpot_showtimes", 0);
}
if (!isset($CFG->hotpot_excelencodings)) {
    set_config("hotpot_excelencodings", "");
}

//////////////////////////////////
/// CONSTANTS and GLOBAL VARIABLES

$CFG->hotpotroot = "$CFG->dirroot/mod/hotpot";
$CFG->hotpottemplate = "$CFG->hotpotroot/template";
if (!empty($_SERVER['HTTP_USER_AGENT'])) {
    $CFG->hotpotismobile = preg_match('/Alcatel|ATTWS|DoCoMo|Doris|Hutc3G|J-PHONE|Java|KDDI|KGT|LGE|MOT|Nokia|portalmmm|ReqwirelessWeb|SAGEM|SHARP|SIE-|SonyEricsson|Teleport|UP\.Browser|UPG1|Wapagsim/', $_SERVER['HTTP_USER_AGENT']);
} else {
    $CFG->hotpotismobile = false;
}

define("HOTPOT_JS", "$CFG->wwwroot/mod/hotpot/hotpot-full.js");

define("HOTPOT_NO",  "0");
define("HOTPOT_YES", "1");

define ("HOTPOT_TEXTSOURCE_QUIZ", "0");
define ("HOTPOT_TEXTSOURCE_FILENAME", "1");
define ("HOTPOT_TEXTSOURCE_FILEPATH", "2");
define ("HOTPOT_TEXTSOURCE_SPECIFIC", "3");

define("HOTPOT_LOCATION_COURSEFILES", "0");
define("HOTPOT_LOCATION_SITEFILES",   "1");

$HOTPOT_LOCATION = array (
    HOTPOT_LOCATION_COURSEFILES => get_string("coursefiles"),
    HOTPOT_LOCATION_SITEFILES   => get_string("sitefiles"),
);

define("HOTPOT_OUTPUTFORMAT_BEST",     "1");
define("HOTPOT_OUTPUTFORMAT_V3",      "10");
define("HOTPOT_OUTPUTFORMAT_V4",      "11");
define("HOTPOT_OUTPUTFORMAT_V5",      "12");
define("HOTPOT_OUTPUTFORMAT_V5_PLUS", "13");
define("HOTPOT_OUTPUTFORMAT_V6",      "14");
define("HOTPOT_OUTPUTFORMAT_V6_PLUS", "15");
define("HOTPOT_OUTPUTFORMAT_FLASH",   "20");
define("HOTPOT_OUTPUTFORMAT_MOBILE",  "30");

$HOTPOT_OUTPUTFORMAT = array (
    HOTPOT_OUTPUTFORMAT_BEST    => get_string("outputformat_best", "hotpot"),
    HOTPOT_OUTPUTFORMAT_V6_PLUS => get_string("outputformat_v6_plus", "hotpot"),
    HOTPOT_OUTPUTFORMAT_V6      => get_string("outputformat_v6", "hotpot"),
    HOTPOT_OUTPUTFORMAT_V5_PLUS => get_string("outputformat_v5_plus", "hotpot"),
    HOTPOT_OUTPUTFORMAT_V5      => get_string("outputformat_v5", "hotpot"),
    HOTPOT_OUTPUTFORMAT_V4      => get_string("outputformat_v4", "hotpot"),
    HOTPOT_OUTPUTFORMAT_V3      => get_string("outputformat_v3", "hotpot"),
    HOTPOT_OUTPUTFORMAT_FLASH   => get_string("outputformat_flash", "hotpot"),
    HOTPOT_OUTPUTFORMAT_MOBILE  => get_string("outputformat_mobile", "hotpot"),
);
$HOTPOT_OUTPUTFORMAT_DIR = array (
    HOTPOT_OUTPUTFORMAT_V6_PLUS => 'v6',
    HOTPOT_OUTPUTFORMAT_V6      => 'v6',
    HOTPOT_OUTPUTFORMAT_V5_PLUS => 'v5',
    HOTPOT_OUTPUTFORMAT_V5      => 'v5',
    HOTPOT_OUTPUTFORMAT_V4      => 'v4',
    HOTPOT_OUTPUTFORMAT_V3      => 'v3',
    HOTPOT_OUTPUTFORMAT_FLASH   => 'flash',
    HOTPOT_OUTPUTFORMAT_MOBILE  => 'mobile',
);
foreach ($HOTPOT_OUTPUTFORMAT_DIR as $format=>$dir) {
    if (is_file("$CFG->hotpottemplate/$dir.php") && is_dir("$CFG->hotpottemplate/$dir")) {
        // do nothing ($format is available)
    } else {
        // $format is not available, so remove it
        unset($HOTPOT_OUTPUTFORMAT[$format]);
        unset($HOTPOT_OUTPUTFORMAT_DIR[$format]);
    }
}
define("HOTPOT_NAVIGATION_BAR",     "1");
define("HOTPOT_NAVIGATION_FRAME",   "2");
define("HOTPOT_NAVIGATION_IFRAME",  "3");
define("HOTPOT_NAVIGATION_BUTTONS", "4");
define("HOTPOT_NAVIGATION_GIVEUP",  "5");
define("HOTPOT_NAVIGATION_NONE",    "6");

$HOTPOT_NAVIGATION = array (
    HOTPOT_NAVIGATION_BAR     => get_string("navigation_bar", "hotpot"),
    HOTPOT_NAVIGATION_FRAME   => get_string("navigation_frame", "hotpot"),
    HOTPOT_NAVIGATION_IFRAME  => get_string("navigation_iframe", "hotpot"),
    HOTPOT_NAVIGATION_BUTTONS => get_string("navigation_buttons", "hotpot"),
    HOTPOT_NAVIGATION_GIVEUP  => get_string("navigation_give_up", "hotpot"),
    HOTPOT_NAVIGATION_NONE    => get_string("navigation_none", "hotpot"),
);

define("HOTPOT_JCB",    "1");
define("HOTPOT_JCLOZE", "2");
define("HOTPOT_JCROSS", "3");
define("HOTPOT_JMATCH", "4");
define("HOTPOT_JMIX",   "5");
define("HOTPOT_JQUIZ",  "6");
define("HOTPOT_TEXTOYS_RHUBARB",   "7");
define("HOTPOT_TEXTOYS_SEQUITUR",  "8");

$HOTPOT_QUIZTYPE = array(
    HOTPOT_JCB    => 'JCB',
    HOTPOT_JCLOZE => 'JCloze',
    HOTPOT_JCROSS => 'JCross',
    HOTPOT_JMATCH => 'JMatch',
    HOTPOT_JMIX   => 'JMix',
    HOTPOT_JQUIZ  => 'JQuiz',
    HOTPOT_TEXTOYS_RHUBARB  => 'Rhubarb',
    HOTPOT_TEXTOYS_SEQUITUR => 'Sequitur'
);

define("HOTPOT_JQUIZ_MULTICHOICE", "1");
define("HOTPOT_JQUIZ_SHORTANSWER", "2");
define("HOTPOT_JQUIZ_HYBRID",      "3");
define("HOTPOT_JQUIZ_MULTISELECT", "4");

define("HOTPOT_GRADEMETHOD_HIGHEST", "1");
define("HOTPOT_GRADEMETHOD_AVERAGE", "2");
define("HOTPOT_GRADEMETHOD_FIRST",   "3");
define("HOTPOT_GRADEMETHOD_LAST",    "4");

$HOTPOT_GRADEMETHOD = array (
    HOTPOT_GRADEMETHOD_HIGHEST => get_string("gradehighest", "quiz"),
    HOTPOT_GRADEMETHOD_AVERAGE => get_string("gradeaverage", "quiz"),
    HOTPOT_GRADEMETHOD_FIRST   => get_string("attemptfirst", "quiz"),
    HOTPOT_GRADEMETHOD_LAST    => get_string("attemptlast",  "quiz"),
);

define("HOTPOT_STATUS_INPROGRESS", "1");
define("HOTPOT_STATUS_TIMEDOUT",   "2");
define("HOTPOT_STATUS_ABANDONED",  "3");
define("HOTPOT_STATUS_COMPLETED",  "4");

$HOTPOT_STATUS = array (
    HOTPOT_STATUS_INPROGRESS => get_string("inprogress", "hotpot"),
    HOTPOT_STATUS_TIMEDOUT   => get_string("timedout",   "hotpot"),
    HOTPOT_STATUS_ABANDONED  => get_string("abandoned",  "hotpot"),
    HOTPOT_STATUS_COMPLETED  => get_string("completed",  "hotpot"),
);

define("HOTPOT_FEEDBACK_NONE", "0");
define("HOTPOT_FEEDBACK_WEBPAGE", "1");
define("HOTPOT_FEEDBACK_FORMMAIL", "2");
define("HOTPOT_FEEDBACK_MOODLEFORUM", "3");
define("HOTPOT_FEEDBACK_MOODLEMESSAGING", "4");

$HOTPOT_FEEDBACK = array (
    HOTPOT_FEEDBACK_NONE => get_string("feedbacknone", "hotpot"),
    HOTPOT_FEEDBACK_WEBPAGE => get_string("feedbackwebpage",  "hotpot"),
    HOTPOT_FEEDBACK_FORMMAIL => get_string("feedbackformmail", "hotpot"),
    HOTPOT_FEEDBACK_MOODLEFORUM => get_string("feedbackmoodleforum", "hotpot"),
    HOTPOT_FEEDBACK_MOODLEMESSAGING => get_string("feedbackmoodlemessaging", "hotpot"),
);
if (empty($CFG->messaging)) { // Moodle 1.4 (and less)
    unset($HOTPOT_FEEDBACK[HOTPOT_FEEDBACK_MOODLEMESSAGING]);
}

define("HOTPOT_DISPLAYNEXT_QUIZ",   "0");
define("HOTPOT_DISPLAYNEXT_COURSE", "1");
define("HOTPOT_DISPLAYNEXT_INDEX",  "2");

/**
 * If start and end date for the quiz are more than this many seconds apart
 * they will be represented by two separate events in the calendar
 */
define("HOTPOT_MAX_EVENT_LENGTH", "432000");   // 5 days maximum

//////////////////////////////////
/// CORE FUNCTIONS


// possible return values:
//    false:
//        display moderr.html (if exists) OR "Could not update" and return to couse view
//    string:
//        display as error message and return to course view
//  true (or non-zero number):
//        continue to $hotpot->redirect (if set) OR hotpot/view.php (to displsay quiz)

// $hotpot is an object containing the values of the form in mod.html
// i.e. all the fields in the 'hotpot' table, plus the following:
//  $hotpot->course       : an id in the 'course' table
//  $hotpot->coursemodule : an id in the 'course_modules' table
//  $hotpot->section      : an id in the 'course_sections' table
//  $hotpot->module       : an id in the 'modules' table
//  $hotpot->modulename   : always 'hotpot'
//  $hotpot->instance     : an id in the 'hotpot' table
//  $hotpot->mode         : 'add' or 'update'
//  $hotpot->sesskey      : unique string required for Moodle's session management

function hotpot_add_instance(&$hotpot) {
    if (hotpot_set_form_values($hotpot)) {
        if ($result = insert_record('hotpot', $hotpot)) {
            $hotpot->id = $result;
            hotpot_update_events($hotpot);
        }
    } else {
        $result=  false;
    }
    return $result;
}

function hotpot_update_instance(&$hotpot) {
    if (hotpot_set_form_values($hotpot)) {
        $hotpot->id = $hotpot->instance;
        if ($result = update_record('hotpot', $hotpot)) {
            hotpot_update_events($hotpot);
        }
    } else {
        $result=  false;
    }
    return $result;
}
function hotpot_update_events($hotpot) {

    // remove any previous calendar events for this hotpot
    delete_records('event', 'modulename', 'hotpot', 'instance', $hotpot->id);

    $event = new stdClass();
    $event->description = addslashes($hotpot->summary);
    $event->courseid    = $hotpot->course;
    $event->groupid     = 0;
    $event->userid      = 0;
    $event->modulename  = 'hotpot';
    $event->instance    = $hotpot->id;
    $event->timestart   = $hotpot->timeopen;
    if ($cm = get_coursemodule_from_id('hotpot', $hotpot->id)) {
        $event->visible = hotpot_is_visible($cm);
    } else {
        $event->visible = 1;
    }

    if ($hotpot->timeclose && $hotpot->timeopen) {
        // we have both a start and an end date
        $event->eventtype   = 'open';
        $event->timeduration = ($hotpot->timeclose - $hotpot->timeopen);

        if ($event->timeduration > HOTPOT_MAX_EVENT_LENGTH) {  /// Long durations create two events
    
            $event->name          = addslashes($hotpot->name).' ('.get_string('hotpotopens', 'hotpot').')';
            $event->timeduration  = 0;
            add_event($event);
    
            $event->timestart    = $hotpot->timeclose;
            $event->eventtype    = 'close';
            $event->name         = addslashes($hotpot->name).' ('.get_string('hotpotcloses', 'hotpot').')';
            unset($event->id);
            add_event($event);
        } else { // single event with duration
            $event->name        = $hotpot->name;
            add_event($event);
        }
    } elseif ($hotpot->timeopen) { // only an open date
        $event->name          = addslashes($hotpot->name).' ('.get_string('hotpotopens', 'hotpot').')';
        $event->eventtype   = 'open';
        $event->timeduration = 0;
        add_event($event);
    } elseif ($hotpot->timeclose) { // only a closing date
        $event->name         = addslashes($hotpot->name).' ('.get_string('hotpotcloses', 'hotpot').')';
        $event->timestart    = $hotpot->timeclose;
        $event->eventtype    = 'close';
        $event->timeduration = 0;
        add_event($event);
    }
}

function hotpot_set_form_values(&$hotpot) {
    $ok = true;
    $hotpot->errors = array(); // these will be reported by moderr.html

    if (empty($hotpot->reference)) {
        $ok = false;
        $hotpot->errors['reference']= get_string('error_nofilename', 'hotpot');
    }

    if ($hotpot->studentfeedbackurl=='http://') {
        $hotpot->studentfeedbackurl = '';
    }

    if (empty($hotpot->studentfeedbackurl)) {
        switch ($hotpot->studentfeedback) {
            case HOTPOT_FEEDBACK_WEBPAGE:
                $ok = false;
                $hotpot->errors['studentfeedbackurl']= get_string('error_nofeedbackurlwebpage', 'hotpot');
            break;
            case HOTPOT_FEEDBACK_FORMMAIL:
                $ok = false;
                $hotpot->errors['studentfeedbackurl']= get_string('error_nofeedbackurlformmail', 'hotpot');
            break;
        }
    }

    $time = time();
    $hotpot->timecreated = $time;
    $hotpot->timemodified = $time;

    if (empty($hotpot->enabletimeopen)) {
        $hotpot->timeopen = 0;
    } else {
        $hotpot->timeopen = make_timestamp(
            $hotpot->openyear, $hotpot->openmonth, $hotpot->openday,
            $hotpot->openhour, $hotpot->openminute, 0
        );
    }

    if (empty($hotpot->enabletimeclose)) {
        $hotpot->timeclose = 0;
    } else {
        $hotpot->timeclose = make_timestamp(
            $hotpot->closeyear, $hotpot->closemonth, $hotpot->closeday,
            $hotpot->closehour, $hotpot->closeminute, 0
        );
    }

    if ($hotpot->quizchain==HOTPOT_YES) {
        switch ($hotpot->mode) {
            case 'add':
                $ok = hotpot_add_chain($hotpot);
            break;
            case 'update':
                $ok = hotpot_update_chain($hotpot);
            break;
        }
    } else { // $hotpot->quizchain==HOTPOT_NO
        hotpot_set_name_summary_reference($hotpot);
    }

    switch ($hotpot->displaynext) {
        // N.B. redirection only works for Moodle 1.5+
        case HOTPOT_DISPLAYNEXT_COURSE:
            $hotpot->redirect = true;
            $hotpot->redirecturl = "view.php?id=$hotpot->course";
            break;
        case HOTPOT_DISPLAYNEXT_INDEX:
            $hotpot->redirect = true;
            $hotpot->redirecturl = "../mod/hotpot/index.php?id=$hotpot->course";
            break;
        default:
            // use Moodle default action (i.e. go on to display the hotpot quiz)
    }

    // if ($ok && $hotpot->setdefaults) {
    if ($ok) {
        set_user_preference('hotpot_timeopen', $hotpot->timeopen);
        set_user_preference('hotpot_timeclose', $hotpot->timeclose);
        set_user_preference('hotpot_navigation', $hotpot->navigation);
        set_user_preference('hotpot_outputformat', $hotpot->outputformat);
        set_user_preference('hotpot_studentfeedback', $hotpot->studentfeedback);
        set_user_preference('hotpot_studentfeedbackurl', $hotpot->studentfeedbackurl);
        set_user_preference('hotpot_forceplugins', $hotpot->forceplugins);
        set_user_preference('hotpot_shownextquiz', $hotpot->shownextquiz);
        set_user_preference('hotpot_review', $hotpot->review);
        set_user_preference('hotpot_grade', $hotpot->grade);
        set_user_preference('hotpot_grademethod', $hotpot->grademethod);
        set_user_preference('hotpot_attempts', $hotpot->attempts);
        set_user_preference('hotpot_subnet', $hotpot->subnet);
        set_user_preference('hotpot_displaynext', $hotpot->displaynext);
        if ($hotpot->mode=='add') {
            set_user_preference('hotpot_quizchain', $hotpot->quizchain);
            set_user_preference('hotpot_namesource', $hotpot->namesource);
            set_user_preference('hotpot_summarysource', $hotpot->summarysource);
        }
    }
    return $ok;
}
function hotpot_get_chain(&$cm) {
    // get details of course_modules in this section
    $course_module_ids = get_field('course_sections', 'sequence', 'id', $cm->section);
    if (empty($course_module_ids)) {
        $hotpot_modules = array();
    } else {
        $hotpot_modules = get_records_select('course_modules', "id IN ($course_module_ids) AND module=$cm->module");
        if (empty($hotpot_modules)) {
            $hotpot_modules = array();
        }
    }

    // get ids of hotpot modules in this section
    $ids = array();
    foreach ($hotpot_modules as $hotpot_module) {
        $ids[] = $hotpot_module->instance;
    }

    // get details of hotpots in this section
    if (empty($ids)) {
        $hotpots = array();
    } else {
        $hotpots = get_records_list('hotpot', 'id', implode(',', $ids));
    }

    $found = false;
    $chain = array();

    // loop through course_modules in this section
    $ids = explode(',', $course_module_ids);
    foreach ($ids as $id) {

        // check this course_module is a hotpot activity
        if (isset($hotpot_modules[$id])) {

            // store details of this course module and hotpot activity
            $hotpot_id = $hotpot_modules[$id]->instance;
            $chain[$id] = &$hotpot_modules[$id];
            $chain[$id]->hotpot = &$hotpots[$hotpot_id];

            // set $found, if this is the course module we're looking for
            if (isset($cm->coursemodule)) {
                if ($id==$cm->coursemodule) {
                    $found = true;
                }
            } else {
                if ($id==$cm->id) {
                    $found = true;
                }
            }

            // is this the end of a chain
            if (empty($hotpots[$hotpot_id]->shownextquiz)) {
                if ($found) {
                    break; // out of loop
                } else {
                    // restart chain (target cm has not been found yet)
                    $chain = array();
                }
            }
        }
    } // end foreach $ids

    return $found ? $chain : false;
}
function hotpot_is_visible(&$cm) {
    if (!isset($cm->sectionvisible)) {
        if ($section = get_record('course_sections', 'id', $cm->section)) {
            $cm->sectionvisible = $section->visible;
        } else {
            error('Course module record contains invalid section');
        }
    }

    if (empty($cm->sectionvisible)) {
        $visible = HOTPOT_NO;
    } else {
        $visible = HOTPOT_YES;
        if (empty($cm->visible)) {
            if ($chain = hotpot_get_chain($cm)) {
                $startofchain = array_shift($chain);
                $visible = $startofchain->visible;
            }
        }
    }
    return $visible;
}
function hotpot_add_chain(&$hotpot) {
/// add a chain of hotpot actiivities

    global $CFG, $course;

    $ok = true;
    $hotpot->names = array();
    $hotpot->summaries = array();
    $hotpot->references = array();

    $xml_quiz = new hotpot_xml_quiz($hotpot, false, false, false, false, false);

    if (isset($xml_quiz->error)) {
        $hotpot->errors['reference'] = $xml_quiz->error;
        $ok = false;

    } else if (is_dir($xml_quiz->filepath)) {

        // get list of hotpot files in this folder
        if ($dh = @opendir($xml_quiz->filepath)) {
            while ($file = @readdir($dh)) {
                if (preg_match('/\.(jbc|jcl|jcw|jmt|jmx|jqz|htm|html)$/', $file)) {
                    $hotpot->references[] = "$xml_quiz->reference/$file";
                }
            }
            closedir($dh);

            // get titles
            foreach ($hotpot->references as $i=>$reference) {
                $filepath = $xml_quiz->fileroot.'/'.$reference;
                hotpot_get_titles_and_next_ex($hotpot, $filepath);
                $hotpot->names[$i] = $hotpot->exercisetitle;
                $hotpot->summaries[$i] = $hotpot->exercisesubtitle;
            }

        } else {
            $ok = false;
            $hotpot->errors['reference'] = get_string('error_couldnotopenfolder', 'hotpot', $hotpot->reference);
        }

    } else if (is_file($xml_quiz->filepath)) {

        $filerootlength = strlen($xml_quiz->fileroot) + 1;

        while ($xml_quiz->filepath) {
            hotpot_get_titles_and_next_ex($hotpot, $xml_quiz->filepath, true);
            $hotpot->names[] = $hotpot->exercisetitle;
            $hotpot->summaries[] = $hotpot->exercisesubtitle;
            $hotpot->references[] = substr($xml_quiz->filepath, $filerootlength);

            if ($hotpot->nextexercise) {
                $filepath = $xml_quiz->fileroot.'/'.$xml_quiz->filesubdir.$hotpot->nextexercise;

                // check file is not already in chain
                $reference = substr($filepath, $filerootlength);
                if (in_array($reference, $hotpot->references)) {
                    $filepath = '';
                }
            } else {
                $filepath = '';
            }
            if ($filepath && file_exists($filepath) && is_file($filepath) && is_readable($filepath)) {
                $xml_quiz->filepath = $filepath;
            } else {
                $xml_quiz->filepath = false; // finish while loop
            }
        } // end while

    } else {
        $ok = false;
        $hotpot->errors['reference'] = get_string('error_notfileorfolder', 'hotpot', $hotpot->reference);
    }

    if (empty($hotpot->references) && empty($hotpot->errors['reference'])) {
        $ok = false;
        $hotpot->errors['reference'] = get_string('error_noquizzesfound', 'hotpot', $hotpot->reference);
    }

    if ($ok) {
        $hotpot->visible = HOTPOT_YES;

        if (trim($hotpot->name)=='') {
            $hotpot->name = get_string("modulename", $hotpot->modulename);
        }
        $hotpot->specificname = $hotpot->name;
        $hotpot->specificsummary = $hotpot->summary;

        // add all except last activity in chain

        $i_max = count($hotpot->references)-1;
        for ($i=0; $i<$i_max; $i++) {

            hotpot_set_name_summary_reference($hotpot, $i);
            $hotpot->reference = addslashes($hotpot->reference);

            if (!$hotpot->instance = insert_record("hotpot", $hotpot)) {
                error("Could not add a new instance of $hotpot->modulename", "view.php?id=$hotpot->course");
            }

            // store (hotpot table) id of start of chain
            if ($i==0) {
                $hotpot->startofchain = $hotpot->instance;
            }

            if (isset($course->groupmode)) {
                $hotpot->groupmode = $course->groupmode;
            }

            if (! $hotpot->coursemodule = add_course_module($hotpot)) {
                error("Could not add a new course module");
            }
            if (! $sectionid = add_mod_to_section($hotpot) ) {
                error("Could not add the new course module to that section");
            }

            if (! set_field("course_modules", "section", $sectionid, "id", $hotpot->coursemodule)) {
                error("Could not update the course module with the correct section");
            }

            add_to_log($hotpot->course, "course", "add mod",
                "../mod/$hotpot->modulename/view.php?id=$hotpot->coursemodule",
                "$hotpot->modulename $hotpot->instance"
            );
            add_to_log($hotpot->course, $hotpot->modulename, "add",
                "view.php?id=$hotpot->coursemodule",
                "$hotpot->instance", $hotpot->coursemodule
            );

            // hide tail of chain
            if ($hotpot->shownextquiz==HOTPOT_YES) {
                $hotpot->visible = HOTPOT_NO;
            }
        } // end for ($hotpot->references)

        // settings for final activity in chain
        hotpot_set_name_summary_reference($hotpot, $i);
        $hotpot->reference = addslashes($hotpot->references[$i]);
        $hotpot->shownextquiz = HOTPOT_NO;

        if (isset($hotpot->startofchain)) {
            // redirection only works for Moodle 1.5+
            $hotpot->redirect = true;
            $hotpot->redirecturl = "$CFG->wwwroot/mod/hotpot/view.php?hp=$hotpot->startofchain";
        }
    } // end if $ok

    return $ok;
}
function hotpot_set_name_summary_reference(&$hotpot, $chain_index=NULL) {

    $xml_quiz = NULL;

    $textfields = array('name', 'summary');
    foreach ($textfields as $textfield) {

        $textsource = $textfield.'source';

        // are we adding a chain?
        if (isset($chain_index)) {

            switch ($hotpot->$textsource) {
                case HOTPOT_TEXTSOURCE_QUIZ:
                    if ($textfield=='name') {
                        $hotpot->exercisetitle = $hotpot->names[$chain_index];
                    } else if ($textfield=='summary') {
                        $hotpot->exercisesubtitle = $hotpot->summaries[$chain_index];
                    }
                    break;
                case HOTPOT_TEXTSOURCE_SPECIFIC:
                    $specifictext = 'specific'.$textfield;
                    if (empty($hotpot->$specifictext) && trim($hotpot->$specifictext)=='') {
                        $hotpot->$textfield = '';
                    } else {
                        $hotpot->$textfield = $hotpot->$specifictext.' ('.($chain_index+1).')';
                    }
                    break;
            }
            $hotpot->reference = $hotpot->references[$chain_index];
        }

        if ($hotpot->$textsource==HOTPOT_TEXTSOURCE_QUIZ) {
            if (empty($xml_quiz) && !isset($chain_index)) {
                $xml_quiz = new hotpot_xml_quiz($hotpot, false, false, false, false, false);
                hotpot_get_titles_and_next_ex($hotpot, $xml_quiz->filepath);
            }
            if ($textfield=='name') {
                $hotpot->$textfield = addslashes($hotpot->exercisetitle);
            } else if ($textfield=='summary') {
                $hotpot->$textfield = addslashes($hotpot->exercisesubtitle);
            }
        }
        switch ($hotpot->$textsource) {
            case HOTPOT_TEXTSOURCE_FILENAME:
                $hotpot->$textfield = basename($hotpot->reference);
                break;
            case HOTPOT_TEXTSOURCE_FILEPATH:
                $hotpot->$textfield = '';
                // continue to next lines
            default:
                if (empty($hotpot->$textfield)) {
                    $hotpot->$textfield = str_replace('/', ' ', $hotpot->reference);
                }
        } // end switch
    } // end foreach
}
function hotpot_get_titles_and_next_ex(&$hotpot, $filepath, $get_next=false) {

    $hotpot->exercisetitle = '';
    $hotpot->exercisesubtitle = '';
    $hotpot->nextexercise = '';

    // read the quiz file source
    if ($source = file_get_contents($filepath)) {

        $next = '';
        $title = '';
        $subtitle = '';

        if (preg_match('|\.html?$|', $filepath)) {
            // html file
            if (preg_match('|<h2[^>]*class="ExerciseTitle"[^>]*>(.*?)</h2>|is', $source, $matches)) {
                $title = trim(strip_tags($matches[1]));
            }
            if (empty($title)) {
                if (preg_match('|<title[^>]*>(.*?)</title>|is', $source, $matches)) {
                    $title = trim(strip_tags($matches[1]));
                }
            }
            if (preg_match('|<h3[^>]*class="ExerciseSubtitle"[^>]*>(.*?)</h3>|is', $source, $matches)) {
                $subtitle = trim(strip_tags($matches[1]));
            }
            if ($get_next) {
                if (preg_match('|<div[^>]*class="NavButtonBar"[^>]*>(.*?)</div>|is', $source, $matches)) {
                    $navbuttonbar = $matches[1];
                    if (preg_match_all('|<button[^>]*class="NavButton"[^>]*onclick="'."location='([^']*)'".'[^"]*"[^>]*>|is', $navbuttonbar, $matches)) {
                        $lastbutton = count($matches[0])-1;
                        $next = $matches[1][$lastbutton];
                    }
                }
            }

        } else {
            // xml file (...maybe)
            $xml_tree = new hotpot_xml_tree($source);
            $xml_tree->filetype = '';

            $keys = array_keys($xml_tree->xml);
            foreach ($keys as $key) {
                if (preg_match('/^(hotpot|textoys)-(\w+)-file$/i', $key, $matches)) {
                    $xml_tree->filetype = 'xml';
                    $xml_tree->xml_root = "['$key']['#']";
                    $xml_tree->quiztype = strtolower($matches[2]);
                    break;
                }
            }
            if ($xml_tree->filetype=='xml') {

                $title = strip_tags($xml_tree->xml_value('data,title'));
                $subtitle = $xml_tree->xml_value('hotpot-config-file,'.$xml_tree->quiztype.',exercise-subtitle');

                if ($get_next) {
                    $include = $xml_tree->xml_value('hotpot-config-file,global,include-next-ex');
                    if (!empty($include)) {
                        $next = $xml_tree->xml_value("hotpot-config-file,$xml_tree->quiztype,next-ex-url");
                        if (is_array($next)) {
                            $next = $next[0]; // in case "next-ex-url" was repeated in the xml file
                        }
                    }
                }
            }
        }

        $hotpot->nextexercise = $next;
        $hotpot->exercisetitle = (empty($title) || is_array($title)) ? basename($filepath) : $title;
        $hotpot->exercisesubtitle = (empty($subtitle) || is_array($subtitle)) ? $hotpot->exercisetitle : $subtitle;
    }
}
function hotpot_get_all_instances_in_course($modulename, $course) {
/// called from index.php

    global $CFG;
    $instances = array();

    if (isset($CFG->release) && substr($CFG->release, 0, 3)>=1.2) {
        $groupmode = 'cm.groupmode,';
    } else {
        $groupmode = '';
    }

    $query = "
        SELECT
            cm.id AS coursemodule,
            cm.course AS course,
            cm.module AS module,
            cm.instance AS instance,
            -- cm.section AS section,
            cm.visible AS visible,
            $groupmode
            -- cs.section AS sectionnumber,
            cs.section AS section,
            cs.sequence AS sequence,
            cs.visible AS sectionvisible,
            thismodule.*
        FROM
            {$CFG->prefix}course_modules cm,
            {$CFG->prefix}course_sections cs,
            {$CFG->prefix}modules m,
            {$CFG->prefix}$modulename thismodule
        WHERE
            m.name = '$modulename' AND
            m.id = cm.module AND
            cm.course = '$course->id' AND
            cm.section = cs.id AND
            cm.instance = thismodule.id
    ";
    if ($rawmods = get_records_sql($query)) {

        // cache $isteacher setting
        
        $isteacher = has_capability('mod/hotpot:viewreport', get_context_instance(CONTEXT_MODULE, $course->id));

        $explodesection = array();
        $order = array();

        foreach ($rawmods as $rawmod) {

            if (empty($explodesection[$rawmod->section])) {
                $explodesection[$rawmod->section] = true;

                $coursemodules = explode(',', $rawmod->sequence);
                foreach ($coursemodules as $i=>$coursemodule) {
                    $order[$coursemodule] = sprintf('%d.%04d', $rawmod->section, $i);
                }
            }

            if ($isteacher) {
                $visible = true;
            } else if ($modulename=='hotpot') {
                $visible = hotpot_is_visible($rawmod);
            } else {
                $visible = $rawmod->visible;
            }

            if ($visible) {
                $instances[$order[$rawmod->coursemodule]] = $rawmod;
            }

        } // end foreach $modinfo

        ksort($instances);
        $instances = array_values($instances);
    }

    return $instances;
}

function hotpot_update_chain(&$hotpot) {
/// update a chain of hotpot actiivities

    $ok = true;
    if ($hotpot_modules = hotpot_get_chain($hotpot)) {

        // skip updating of these fields
        $skipfields = array('id', 'course', 'name', 'reference', 'summary', 'shownextquiz');
        $fields = array();

        foreach ($hotpot_modules as $hotpot_module) {

            if ($hotpot->instance==$hotpot_module->id) {
                // don't need to update this hotpot

            } else {
                // shortcut to hotpot record
                $thishotpot = &$hotpot_module->hotpot;

                // get a list of fields to update (first time only)
                if (empty($fields)) {
                    $fields = array_keys(get_object_vars($thishotpot));
                }

                // assume update is NOT required
                $require_update = false;

                // update field values (except $skipfields)
                foreach($fields as $field) {
                    if (in_array($field, $skipfields) || $thishotpot->$field==$hotpot->$field) {
                        // update not required for this field
                    } else {
                        $require_update = true;
                        $thishotpot->$field = $hotpot->$field;
                    }
                }

                // update $thishotpot, if required
                if ($require_update && !update_record("hotpot", $thishotpot)) {
                    error("Could not update the $hotpot->modulename", "view.php?id=$hotpot->course");
                }
            }
        } // end foreach $ids
    }
    return $ok;
}
function hotpot_delete_instance($id) {
/// Given an ID of an instance of this module,
/// this function will permanently delete the instance
/// and any data that depends on it.

    $result = false;
    if (delete_records("hotpot", "id", "$id")) {
        $result = true;
        delete_records("hotpot_questions", "hotpot", "$id");
        if ($attempts = get_records_select("hotpot_attempts", "hotpot='$id'")) {
            $ids = implode(',', array_keys($attempts));
            delete_records_select("hotpot_attempts",  "id IN ($ids)");
            delete_records_select("hotpot_details",   "attempt IN ($ids)");
            delete_records_select("hotpot_responses", "attempt IN ($ids)");
        }
         // remove calendar events for this hotpot
        delete_records('event', 'modulename', 'hotpot', 'instance', $id);
   }
    return $result;
}
function hotpot_delete_and_notify($table, $select, $strtable) {
    $count = max(0, count_records_select($table, $select));
    if ($count) {
        delete_records_select($table, $select);
        $count -= max(0, count_records_select($table, $select));
        if ($count) {
            notify(get_string('deleted')." $count x $strtable");
        }
    }
}

function hotpot_user_complete($course, $user, $mod, $hotpot) {
/// Print a detailed representation of what a  user has done with
/// a given particular instance of this module, for user activity reports.

    $report = hotpot_user_outline($course, $user, $mod, $hotpot);
    if (empty($report)) {
        print get_string("noactivity", "hotpot");
    } else {
        $date = userdate($report->time, get_string('strftimerecentfull'));
        print $report->info.' '.get_string('mostrecently').': '.$date;
    }
    return true;
}

function hotpot_user_outline($course, $user, $mod, $hotpot) {
/// Return a small object with summary information about what a
/// user has done with a given particular instance of this module
/// Used for user activity reports.
/// $report->time = the time they did it
/// $report->info = a short text description

    $report = NULL;
    if ($records = get_records_select("hotpot_attempts", "hotpot='$hotpot->id' AND userid='$user->id'", "timestart ASC", "*")) {
        $report = new stdClass();
        $scores = array();
        foreach ($records as $record){
            if (empty($report->time)) {
                $report->time = $record->timestart;
            }
            $scores[] = hotpot_format_score($record);
        }
        if (empty($scores)) {
            $report->time = 0;
            $report->info = get_string('noactivity', 'hotpot');
        } else {
            $report->info = get_string('score', 'quiz').': '.implode(', ', $scores);
        }
    }
    return $report;
}

function hotpot_format_score($record, $undefined='&nbsp;') {
    if (isset($record->score)) {
        $score = $record->score;
    } else {
        $score = $undefined;
    }
    return $score;
}

function hotpot_format_status($record, $undefined='&nbsp;') {
    global $HOTPOT_STATUS;

    if (isset($record->status) || isset($HOTPOT_STATUS[$record->status])) {
        $status = $HOTPOT_STATUS[$record->status];
    } else {
        $status = $undefined;
    }
    return $status;
}

function hotpot_print_recent_activity($course, $isteacher, $timestart) {
/// Given a course and a time, this module should find recent activity
/// that has occurred in hotpot activities and print it out.
/// Return true if there was output, or false is there was none.

    global $CFG;
    $result = false;

    $records = get_records_sql("
        SELECT
            h.id AS id,
            h.name AS name,
            COUNT(*) AS count_attempts
        FROM
            {$CFG->prefix}hotpot h,
            {$CFG->prefix}hotpot_attempts a
        WHERE
            h.course = $course->id
            AND h.id = a.hotpot
            AND a.id = a.clickreportid
            AND a.starttime > $timestart
        GROUP BY
            h.id, h.name
    ");
    // note that PostGreSQL requires h.name in the GROUP BY clause

    if($records) {
        $names = array();
        foreach ($records as $id => $record){
            if ($cm = get_coursemodule_from_instance('hotpot', $record->id, $course->id)) {
                $context = get_context_instance(CONTEXT_MODULE, $cm->id);
                
                if (has_capability('mod/hotpot:viewreport', $context)) {
                    $href = "$CFG->wwwroot/mod/hotpot/view.php?hp=$id";
                    $name = '&nbsp;<a href="'.$href.'">'.$record->name.'</a>';
                    if ($record->count_attempts > 1) {
                        $name .= " ($record->count_attempts)";
                    }
                    $names[] = $name;
                }
            }
        }
        if (count($names) > 0) {
            print_headline(get_string('modulenameplural', 'hotpot').':');

            if ($CFG->version >= 2005050500) { // Moodle 1.5+
                echo '<div class="head"><div class="name">'.implode('<br />', $names).'</div></div>';
            } else { // Moodle 1.4.x (or less)
                echo '<font size="1">'.implode('<br />', $names).'</font>';
            }
            $result = true;
        }
    }
    return $result;  //  True if anything was printed, otherwise false
}

function hotpot_get_recent_mod_activity(&$activities, &$index, $sincetime, $courseid, $cmid="", $userid="", $groupid="") {
// Returns all quizzes since a given time.

    global $CFG;

    // If $cmid or $userid are specified, then this restricts the results
    $cm_select = empty($cmid) ? "" : " AND cm.id = '$cmid'";
    $user_select = empty($userid) ? "" : " AND u.id = '$userid'";

    $records = get_records_sql("
        SELECT
            a.*,
            h.name, h.course,
            cm.instance, cm.section,
            u.firstname, u.lastname, u.picture
        FROM
            {$CFG->prefix}hotpot_attempts a,
            {$CFG->prefix}hotpot h,
            {$CFG->prefix}course_modules cm,
            {$CFG->prefix}user u
        WHERE
            a.timefinish > '$sincetime'
            AND a.id = a.clickreportid
            AND a.userid = u.id $user_select
            AND a.hotpot = h.id $cm_select
            AND cm.instance = h.id
            AND cm.course = '$courseid'
            AND h.course = cm.course
        ORDER BY
            a.timefinish ASC
    ");

    if (!empty($records)) {
        foreach ($records as $record) {
            if (empty($groupid) || ismember($groupid, $record->userid)) {

                unset($activity);

                $activity->type = "hotpot";
                $activity->defaultindex = $index;
                $activity->instance = $record->hotpot;

                $activity->name = $record->name;
                $activity->section = $record->section;

                $activity->content->attemptid = $record->id;
                $activity->content->attempt = $record->attempt;
                $activity->content->score = $record->score;
                $activity->content->timestart = $record->timestart;
                $activity->content->timefinish = $record->timefinish;

                $activity->user->userid = $record->userid;
                $activity->user->fullname = fullname($record);
                $activity->user->picture = $record->picture;

                $activity->timestamp = $record->timefinish;

                $activities[] = $activity;

                $index++;
            }
        } // end foreach
    }
}

function hotpot_print_recent_mod_activity($activity, $course, $detail=false) {
/// Basically, this function prints the results of "hotpot_get_recent_activity"

    global $CFG, $THEME, $USER;

    print '<table border="0" cellpadding="3" cellspacing="0">';

    print '<tr><td bgcolor="'.$THEME->cellcontent2.'" class="forumpostpicture" width="35" valign="top">';
    print_user_picture($activity->user->userid, $course, $activity->user->picture);
    print '</td><td width="100%"><font size="2">';

    if ($detail) {
        // activity icon
        $src = "$CFG->modpixpath/$activity->type/icon.gif";
        print '<img src="'.$src.'" class="icon" alt="'.$activity->type.'" /> ';

        // link to activity
        $href = "$CFG->wwwroot/mod/hotpot/view.php?hp=$activity->instance";
        print '<a href="'.$href.'">'.$activity->name.'</a> - ';
    }
    if (has_capability('mod/hotpot:viewreport',get_context_instance(CONTEXT_COURSE, $course))) {
        // score (with link to attempt details)
        $href = "$CFG->wwwroot/mod/hotpot/review.php?hp=$activity->instance&attempt=".$activity->content->attemptid;
        print '<a href="'.$href.'">('.hotpot_format_score($activity->content).')</a> ';

        // attempt number
        print get_string('attempt', 'quiz').' - '.$activity->content->attempt.'<br />';
    }

    // link to user
    $href = "$CFG->wwwroot/user/view.php?id=$activity->user->userid&course=$course";
    print '<a href="'.$href.'">'.$activity->user->fullname.'</a> ';

    // time and date
    print ' - ' . userdate($activity->timestamp);

    // duration
    $duration = format_time($activity->content->timestart - $activity->content->timefinish);
    print " &nbsp; ($duration)";

    print "</font></td></tr>";
    print "</table>";
}

function hotpot_cron () {
/// Function to be run periodically according to the moodle cron
/// This function searches for things that need to be done, such
/// as sending out mail, toggling flags etc ...

    global $CFG;

    return true;
}

function hotpot_grades($hotpotid) {
/// Must return an array of grades for a given instance of this module,
/// indexed by user.  It also returns a maximum allowed grade.

    $hotpot = get_record('hotpot', 'id', $hotpotid);
    $return->grades = hotpot_get_grades($hotpot);
    $return->maxgrade = $hotpot->grade;

    return $return;
}
function hotpot_get_grades($hotpot, $user_ids='') {
    global $CFG;

    $grades = array();

    $weighting = $hotpot->grade / 100;
    $precision = hotpot_get_precision($hotpot);

    // set the SQL string to determine the $grade
    $grade = "";
    switch ($hotpot->grademethod) {
        case HOTPOT_GRADEMETHOD_HIGHEST:
            $grade = "ROUND(MAX(score) * $weighting, $precision) AS grade";
            break;
        case HOTPOT_GRADEMETHOD_AVERAGE:
            // the 'AVG' function skips abandoned quizzes, so use SUM(score)/COUNT(id)
            $grade = "ROUND(SUM(score)/COUNT(id) * $weighting, $precision) AS grade";
            break;
        case HOTPOT_GRADEMETHOD_FIRST:
            $grade = "ROUND(score * $weighting, $precision)";
            $grade = sql_concat('timestart', "'_'", $grade);
            $grade = "MIN($grade) AS grade";
            break;
        case HOTPOT_GRADEMETHOD_LAST:
            $grade = "ROUND(score * $weighting, $precision)";
            $grade = sql_concat('timestart', "'_'", $grade);
            $grade = "MAX($grade) AS grade";
            break;
    }

    if ($grade) {
        $userid_condition = empty($user_ids) ? '' : "AND userid IN ($user_ids) ";
        $grades = get_records_sql_menu("
            SELECT userid, $grade
            FROM {$CFG->prefix}hotpot_attempts
            WHERE timefinish>0 AND hotpot='$hotpot->id' $userid_condition
            GROUP BY userid
        ");
        if ($grades) {
            if ($hotpot->grademethod==HOTPOT_GRADEMETHOD_FIRST || $hotpot->grademethod==HOTPOT_GRADEMETHOD_LAST) {
                // remove left hand characters in $grade (up to and including the underscore)
                foreach ($grades as $userid=>$grade) {
                    $grades[$userid] = substr($grades[$userid], strpos($grades[$userid], '_')+1);
                }
            }
        }
    }

    return $grades;
}
function hotpot_get_precision(&$hotpot) {
    return ($hotpot->grademethod==HOTPOT_GRADEMETHOD_AVERAGE || $hotpot->grade<100) ? 1 : 0;
}

function hotpot_get_participants($hotpotid) {
//Must return an array of user ids who are participants
//for a given instance of hotpot. Must include every user involved
//in the instance, independient of his role (student, teacher, admin...)
//See other modules as example.
    global $CFG;

    return get_records_sql("
        SELECT DISTINCT
            u.id, u.id
        FROM
            {$CFG->prefix}user u,
            {$CFG->prefix}hotpot_attempts a
        WHERE
            u.id = a.userid
            AND a.hotpot = '$hotpotid'
    ");
}

function hotpot_scale_used ($hotpotid, $scaleid) {
//This function returns if a scale is being used by one hotpot
//it it has support for grading and scales. Commented code should be
//modified if necessary. See forum, glossary or journal modules
//as reference.

    $report = false;

    //$rec = get_record("hotpot","id","$hotpotid","scale","-$scaleid");
    //
    //if (!empty($rec)  && !empty($scaleid)) {
    //  $report = true;
    //}

    return $report;
}

//////////////////////////////////////////////////////////
/// Any other hotpot functions go here.
/// Each of them must have a name that starts with hotpot


function hotpot_add_attempt($hotpotid) {
    global $db, $CFG, $USER;

    // get start time of this attempt
    $time = time();

    // set all previous "in progress" attempts at this quiz to "abandoned"
    if ($attempts = get_records_select('hotpot_attempts', "hotpot='$hotpotid' AND userid='$USER->id' AND status='".HOTPOT_STATUS_INPROGRESS."'")) {
        foreach ($attempts as $attempt) {
            if ($attempt->timefinish==0) {
                $attempt->timefinish = $time;
            }
            if ($attempt->clickreportid==0) {
                $attempt->clickreportid = $attempt->id;
            }
            $attempt->status = HOTPOT_STATUS_ABANDONED;
            update_record('hotpot_attempts', $attempt);
        }
    }    

    // create and add new attempt record
    $attempt = new stdClass();
    $attempt->hotpot = $hotpotid;
    $attempt->userid = $USER->id;
    $attempt->attempt = hotpot_get_next_attempt($hotpotid);
    $attempt->timestart = $time;

    return insert_record("hotpot_attempts", $attempt);
}
function hotpot_get_next_attempt($hotpotid) {
    global $USER;

    // get max attempt so far
    $i = count_records_select('hotpot_attempts', "hotpot='$hotpotid' AND userid='$USER->id'", 'MAX(attempt)');

    return empty($i) ? 1 : ($i+1);
}
function hotpot_get_question_name($question) {
    $name = '';
    if (isset($question->text)) {
        $name = hotpot_strings($question->text);
    }
    if (empty($name)) {
        $name = $question->name;
    }
    return $name;
}
function hotpot_strings($ids) {

    // array of ids of empty strings
    static $HOTPOT_EMPTYSTRINGS;

    if (!isset($HOTPOT_EMPTYSTRINGS)) { // first time only
        // get ids of empty strings
        $emptystrings = get_records_select('hotpot_strings', 'LENGTH(TRIM(string))=0');
        $HOTPOT_EMPTYSTRINGS = empty($emptystrings) ? array() : array_keys($emptystrings);
    }

    $strings = array();
    if (!empty($ids)) {
        $ids = explode(',', $ids);
        foreach ($ids as $id) {
            if (!in_array($id, $HOTPOT_EMPTYSTRINGS)) {
                $strings[] = hotpot_string($id);
            }
        }
    }
    return implode(',', $strings);
}
function hotpot_string($id) {
    return get_field('hotpot_strings', 'string', 'id', $id);
}

//////////////////////////////////////////////////////////////////////////////////////
/// the class definitions to handle XML trees

// get the standard XML parser supplied with Moodle
require_once("$CFG->libdir/xmlize.php");

// get the default class for hotpot quiz templates
require_once("$CFG->hotpottemplate/default.php");

class hotpot_xml_tree {
    function hotpot_xml_tree($str, $xml_root='') {
        if (empty($str)) {
            $this->xml =  array();
        } else {
            if (empty($CFG->unicodedb)) {
                $str = utf8_encode($str);
            }
            $this->xml =  xmlize($str, 0);
        }
        $this->xml_root = $xml_root;
    }
    function xml_value($tags, $more_tags="[0]['#']") {

        $tags = empty($tags) ? '' : "['".str_replace(",", "'][0]['#']['", $tags)."']";
        eval('$value = &$this->xml'.$this->xml_root.$tags.$more_tags.';');

        if (is_string($value)) {
            if (empty($CFG->unicodedb)) {
                $value = utf8_decode($value);
            }

            // decode angle brackets
            $value = strtr($value, array('&#x003C;'=>'<', '&#x003E;'=>'>', '&#x0026;'=>'&'));

            // remove white space between <table>, <ul|OL|DL> and <OBJECT|EMBED> parts
            // (so it doesn't get converted to <br />)
            $htmltags = '('
            .   'TABLE|/?CAPTION|/?COL|/?COLGROUP|/?TBODY|/?TFOOT|/?THEAD|/?TD|/?TH|/?TR'
            .   '|OL|UL|/?LI'
            .   '|DL|/?DT|/?DD'
            .   '|EMBED|OBJECT|APPLET|/?PARAM'
            //. '|SELECT|/?OPTION'
            //. '|FIELDSET|/?LEGEND'
            //. '|FRAMESET|/?FRAME'
            .   ')'
            ;

            $space = '(\s|(<br[^>]*>))+';
            $search = '#(<'.$htmltags.'[^>]*'.'>)'.$space.'(?='.'<)#is';
            $value = preg_replace($search, '\\1', $value);

            // replace remaining newlines with <br />
            $value = str_replace("\n", '<br />', $value);

            // encode unicode characters as HTML entities
            // (in particular, accented charaters that have not been encoded by HP)

            // unicode characters can be detected by checking the hex value of a character
            //  00 - 7F : ascii char (roman alphabet + punctuation)
            //  80 - BF : byte 2, 3 or 4 of a unicode char
            //  C0 - DF : 1st byte of 2-byte char
            //  E0 - EF : 1st byte of 3-byte char
            //  F0 - FF : 1st byte of 4-byte char
            // if the string doesn't match the above, it might be
            //  80 - FF : single-byte, non-ascii char
            $search = '#('.'[\xc0-\xdf][\x80-\xbf]'.'|'.'[\xe0-\xef][\x80-\xbf]{2}'.'|'.'[\xf0-\xff][\x80-\xbf]{3}'.'|'.'[\x80-\xff]'.')#se';
            $value = preg_replace($search, "hotpot_utf8_to_html_entity('\\1')", $value);
        }
        return $value;
    }
    function xml_values($tags) {
        $i = 0;
        $values = array();
        while ($value = $this->xml_value($tags, "[$i]['#']")) {
            $values[$i++] = $value;
        }
        return $values;
    }
    function obj_value(&$obj, $name) {
        return is_object($obj) ? @$obj->$name : (is_array($obj) ? @$obj[$name] : NULL);
    }
    function encode_cdata(&$str, $tag) {

        // conversion tables
        static $HTML_ENTITIES = array(
            '&apos;' => "'",
            '&quot;' => '"',
            '&lt;'   => '<',
            '&gt;'   => '>',
            '&amp;'  => '&',
        );
        static $ILLEGAL_STRINGS = array(
            "\r\n"  => '&lt;br /&gt;',
            "\r"    => '&lt;br /&gt;',
            "\n"    => '&lt;br /&gt;',
            '['     => '&#91;',
            ']'     => '&#93;'
        );

        // extract the $tag from the $str(ing), if possible
        $pattern = '|(^.*<'.$tag.'[^>]*)(>.*<)(/'.$tag.'>.*$)|is';
        if (preg_match($pattern, $str, $matches)) {

            // encode problematic CDATA chars and strings
            $matches[2] = strtr($matches[2], $ILLEGAL_STRINGS);

            // if there are any ampersands in "open text"
            // surround them by CDATA start and end markers
            // (and convert HTML entities to plain text)
            $search = '/>([^<]*&[^<]*)</e';
            $replace = '"><![CDATA[".strtr("$1", $HTML_ENTITIES)."]]><"';
            $matches[2] = preg_replace($search, $replace, $matches[2]);

            $str = $matches[1].$matches[2].$matches[3];
        }
    }
}

class hotpot_xml_quiz extends hotpot_xml_tree {

    // constructor function
    function hotpot_xml_quiz(&$obj, $read_file=true, $parse_xml=true, $convert_urls=true, $report_errors=true, $create_html=true) {
        // obj can be the $_GET array or a form object/array

        global $CFG, $HOTPOT_OUTPUTFORMAT, $HOTPOT_OUTPUTFORMAT_DIR;

        // check xmlize functions are available
        if (! function_exists("xmlize")) {
            error('xmlize functions are not available');
        }

        $this->read_file = $read_file;
        $this->parse_xml = $parse_xml;
        $this->convert_urls = $convert_urls;
        $this->report_errors = $report_errors;
        $this->create_html = $create_html;

        // extract fields from $obj
        //  course     : the course id
        //  reference   : the filename within the files folder
        //  location     : "site" files folder or "course" files folder
        //  navigation   : type of navigation required in quiz
        //  forceplugins : force Moodle compatible media players
        $this->course = $this->obj_value($obj, 'course');
        $this->reference = $this->obj_value($obj, 'reference');
        $this->location = $this->obj_value($obj, 'location');
        $this->navigation = $this->obj_value($obj, 'navigation');
        $this->forceplugins = $this->obj_value($obj, 'forceplugins');

        // can't continue if there is no course or reference
        if (empty($this->course) || empty($this->reference)) {
            $this->error = get_string('error_nocourseorfilename', 'hotpot');
            if ($this->report_errors) {
                error($this->error);
            }
            return;
        }

        $this->course_homeurl = "$CFG->wwwroot/course/view.php?id=$this->course";

        // set filedir, filename and filepath
        switch ($this->location) {
            case HOTPOT_LOCATION_SITEFILES:
                $site = get_site();
                $this->filedir = $site->id;
                break;

            case HOTPOT_LOCATION_COURSEFILES:
            default:
                $this->filedir = $this->course;
                break;
        }
        $this->filesubdir = dirname($this->reference);
        if ($this->filesubdir=='.') {
            $this->filesubdir = '';
        }
        if ($this->filesubdir) {
            $this->filesubdir .= '/';
        }
        $this->filename = basename($this->reference);
        $this->fileroot = "$CFG->dataroot/$this->filedir";
        $this->filepath = "$this->fileroot/$this->reference";

        // read the file, if required
        if ($this->read_file) {

            if (!file_exists($this->filepath) || !is_readable($this->filepath)) {
                $this->error = get_string('error_couldnotopensourcefile', 'hotpot', $this->filepath);
                if ($this->report_errors) {
                    error($this->error, $this->course_homeurl);
                }
                return;
            }

            // read in the XML source
            $this->source = file_get_contents($this->filepath);

            // convert relative URLs to absolute URLs
            if ($this->convert_urls) {
                $this->hotpot_convert_relative_urls($this->source);
            }

            $this->html = '';
            $this->quiztype = '';
            $this->outputformat = 0;

            // is this an html file?
            if (preg_match('|\.html?$|', $this->filename)) {

                $this->filetype = 'html';
                $this->html = &$this->source;

                // relative URLs in stylesheets
                $search = '|'.'(<style[^>]*>)'.'(.*?)'.'(</style>)'.'|ise';
                $replace = "stripslashes('\\1').hotpot_convert_stylesheets_urls('".$this->get_baseurl()."','".$this->reference."','\\2'.'\\3')";
                $this->source = preg_replace($search, $replace, $this->source);

                // relative URLs in "PreloadImages(...);"
                $search = '|'.'(?<='.'PreloadImages'.'\('.')'."([^)]+?)".'(?='.'\);'.')'.'|se';
                $replace = "hotpot_convert_preloadimages_urls('".$this->get_baseurl()."','".$this->reference."','\\1')";
                $this->source = preg_replace($search, $replace, $this->source);

                // relative URLs in <button class="NavButton" ... onclick="location='...'">
                $search = '|'.'(?<='.'onclick="'."location='".')'."([^']*)".'(?='."'; return false;".'")'.'|ise';
                $replace = "hotpot_convert_navbutton_url('".$this->get_baseurl()."','".$this->reference."','\\1','".$this->course."')";
                $this->source = preg_replace($search, $replace, $this->source);

                // relative URLs in <a ... onclick="window.open('...')...">...</a>
                $search = '|'.'(?<='.'onclick="'."window.open\\('".')'."([^']*)".'(?='."'\\);return false;".'")'.'|ise';
                $replace = "hotpot_convert_url('".$this->get_baseurl()."','".$this->reference."','\\1')";
                $this->source = preg_replace($search, $replace, $this->source);

            } else {

                // relative URLs in <a ... onclick="window.open('...')...">...</a>
                $search = '|'.'(?<='.'onclick=&quot;'."window.open\\(&apos;".')'."(.*?)".'(?='."&apos;\\);return false;".'&quot;)'.'|ise';
                $replace = "hotpot_convert_url('".$this->get_baseurl()."','".$this->reference."','\\1')";
                $this->source = preg_replace($search, $replace, $this->source);

                if ($this->parse_xml) {

                    $this->filetype = 'xml';

                    // encode "gap fill" text in JCloze exercise
                    $this->encode_cdata($this->source, 'gap-fill');

                    // convert source to xml tree
                    $this->hotpot_xml_tree($this->source);

                    $keys = array_keys($this->xml);
                    foreach ($keys as $key) {
                        if (preg_match('/^(hotpot|textoys)-(\w+)-file$/i', $key, $matches)) {
                            $this->quiztype = strtolower($matches[2]);
                            $this->xml_root = "['$key']['#']";
                            break;
                        }
                    }
                }

                if ($this->create_html) {

                    // set the real output format from the requested output format
                    $this->real_outputformat = $this->obj_value($obj, 'outputformat');
                    $this->draganddrop = '';
                    if (
                        empty($this->real_outputformat) ||
                        $this->real_outputformat==HOTPOT_OUTPUTFORMAT_BEST ||
                        empty($HOTPOT_OUTPUTFORMAT_DIR[$this->real_outputformat])
                    ) {
                        if ($CFG->hotpotismobile && isset($HOTPOT_OUTPUTFORMAT_DIR[HOTPOT_OUTPUTFORMAT_MOBILE])) {
                                $this->real_outputformat = HOTPOT_OUTPUTFORMAT_MOBILE;
                        } else { // PC
                            if ($this->quiztype=='jmatch' || $this->quiztype=='jmix') {
                                $this->real_outputformat = HOTPOT_OUTPUTFORMAT_V6_PLUS;
                            } else {
                                $this->real_outputformat = HOTPOT_OUTPUTFORMAT_V6;
                            }
                        }
                    }

                    if ($this->real_outputformat==HOTPOT_OUTPUTFORMAT_V6_PLUS) {
                        if ($this->quiztype=='jmatch' || $this->quiztype=='jmix') {
                            $this->draganddrop = 'd'; // prefix for templates (can also be "f" ?)
                        }
                        $this->real_outputformat = HOTPOT_OUTPUTFORMAT_V6;
                    }

                    // set path(s) to template
                    $this->template_dir = $HOTPOT_OUTPUTFORMAT_DIR[$this->real_outputformat];
                    $this->template_dirpath = $CFG->hotpottemplate.'/'.$this->template_dir;
                    $this->template_filepath = $CFG->hotpottemplate.'/'.$this->template_dir.'.php';

                    // check template class exists
                    if (!file_exists($this->template_filepath) || !is_readable($this->template_filepath)) {
                        $this->error = get_string('error_couldnotopentemplate', 'hotpot', $this->template_dir);
                        if ($this->report_errors) {
                            error($this->error, $this->course_homeurl);
                        }
                        return;
                    }

                    // get default and output-specfic template classes
                    include($this->template_filepath);

                    // create html (using the template for the specified output format)
                    $this->template = new hotpot_xml_quiz_template($this);
                    $this->html = &$this->template->html;

                } // end $this->create_html
            } // end if html/xml file
        } // end if $this->read_file
    } // end constructor function

    function hotpot_convert_relative_urls(&$str) {
        $tagopen = '(?:(<)|(&lt;)|(&amp;#x003C;))'; // left angle bracket
        $tagclose = '(?(2)>|(?(3)&gt;|(?(4)&amp;#x003E;)))'; //  right angle bracket (to match left angle bracket)

        $space = '\s+'; // at least one space
        $anychar = '(?:[^>]*?)'; // any character

        $quoteopen = '("|&quot;|&amp;quot;)'; // open quote
        $quoteclose = '\\5'; //  close quote (to match open quote)

        $replace = "hotpot_convert_relative_url('".$this->get_baseurl()."', '".$this->reference."', '\\1', '\\6', '\\7')";

        $tags = array('script'=>'src', 'link'=>'href', 'a'=>'href','img'=>'src','param'=>'value', 'object'=>'data', 'embed'=>'src');
        foreach ($tags as $tag=>$attribute) {
            if ($tag=='param') {
                $url = '\S+?\.\S+?'; // must include a filename and have no spaces
            } else {
                $url = '.*?';
            }
            $search = "%($tagopen$tag$space$anychar$attribute=$quoteopen)($url)($quoteclose$anychar$tagclose)%ise";
            $str = preg_replace($search, $replace, $str);
        }
    }

    function get_baseurl() {
        // set the url base (first time only)
        if (!isset($this->baseurl)) {
            global $CFG;
            if ($CFG->slasharguments) {
                $this->baseurl = "$CFG->wwwroot/file.php/$this->filedir/";
            } else {
                $this->baseurl = "$CFG->wwwroot/file.php?file=/$this->filedir/";
            }
        }
        return $this->baseurl;
    }


    // insert forms and messages

    function remove_nav_buttons() {
        $search = '#<!-- Begin(Top|Bottom)NavButtons -->(.*?)<!-- End(Top|Bottom)NavButtons -->#s';
        $this->html = preg_replace($search, '', $this->html);
    }
    function insert_script($src=HOTPOT_JS) {
        $script = '<script src="'.$src.'" type="text/javascript"></script>'."\n";
        $this->html = preg_replace('|</head>|i', $script.'</head>', $this->html, 1);
    }
    function insert_submission_form($attemptid, $startblock, $endblock, $keep_contents=false) {
        $form_name = 'store';
        $form_fields = ''
        .   '<input type="hidden" name="attemptid" value="'.$attemptid.'" />'
        .   '<input type="hidden" name="starttime" value="" />'
        .   '<input type="hidden" name="endtime" value="" />'
        .   '<input type="hidden" name="mark" value="" />'
        .   '<input type="hidden" name="detail" value="" />'
        .   '<input type="hidden" name="status" value="" />'
        ;
        $this->insert_form($startblock, $endblock, $form_name, $form_fields, $keep_contents);
    }
    function insert_giveup_form($attemptid, $startblock, $endblock, $keep_contents=false) {
        $form_name = ''; // no <form> tag will be generated
        $form_fields = ''
        .   '<button onclick="Finish('.HOTPOT_STATUS_ABANDONED.')" class="FuncButton" '
        .   'onfocus="FuncBtnOver(this)" onblur="FuncBtnOut(this)" '
        .   'onmouseover="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" '
        .   'onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)">'
        .   get_string('giveup', 'hotpot').'</button>'
        ;
        $this->insert_form($startblock, $endblock, $form_name, $form_fields, $keep_contents, true);
    }
    function insert_form($startblock, $endblock, $form_name, $form_fields, $keep_contents, $center=false) {
        global $CFG;
        $search = '#('.preg_quote($startblock).')(.*?)('.preg_quote($endblock).')#s';
        $replace = $form_fields;
        if ($keep_contents) {
            $replace .= '\\2';
        }
        if ($form_name) {
            $replace = '<form action="'.$CFG->wwwroot.'/mod/hotpot/attempt.php" method="post" name="'.$form_name.'"'.$CFG->frametarget.'>'.$replace.'</form>';
        }
        if ($center) {
            $replace = '<div style="margin-left:auto; margin-right:auto; text-align: center;">'.$replace.'</div>';
        }
        $replace = '\\1'.$replace.'\\3';
        $this->html = preg_replace($search, $replace, $this->html, 1);
    }
    function insert_message($start_str, $message, $color='red', $align='center') {
        $message = '<p align="'.$align.'" style="text-align:'.$align.'"><b><font color="'.$color.'">'.$message."</font></b></p>\n";
        $this->html = preg_replace('|'.preg_quote($start_str).'|', $start_str.$message, $this->html, 1);
    }

    function adjust_media_urls() {

        if ($this->forceplugins) {

            // make sure the Moodle media plugin is available
            global $CFG;
            include_once "$CFG->dirroot/filter/mediaplugin/filter.php";

            // exclude swf files from the filter
            //$CFG->filter_mediaplugin_ignore_swf = true;

            $space = '\s(?:.+\s)?';
            $quote = '["'."']?"; // single, double, or no quote

            // patterns to media files types and paths
            $filetype = "avi|mpeg|mpg|mp3|mov|wmv";
            $filepath = ".*?\.($filetype)";

            $tagopen = '(?:(<)|(\\\\u003C))'; // left angle-bracket (uses two parenthese)
            $tagclose = '(?(1)>|(?(2)\\\\u003E))'; // right angle-bracket (to match the left one)
            $tagreopen = '(?(1)<|(?(2)\\\\u003C))'; // another left angle-bracket (to match the first one)

            // pattern to match <PARAM> tags which contain the file path
            //  wmp        : url
            //  quicktime  : src
            //  realplayer : src
            //  flash      : movie (doesn't need replacing)
            $param_url = "/{$tagopen}param{$space}name=$quote(?:movie|src|url)$quote{$space}value=$quote($filepath)$quote.*?$tagclose/is";

            // pattern to match <a> tags which link to multimedia files
            $link_url = "/{$tagopen}a{$space}href=$quote($filepath)$quote.*?$tagclose.*?$tagreopen\/A$tagclose/is";

            // extract <object> tags
            preg_match_all("/{$tagopen}object\s.*?{$tagclose}(.*?){$tagreopen}\/object{$tagclose}/is", $this->html, $objects);

            $i_max = count($objects[0]);
            for ($i=0; $i<$i_max; $i++) {

                // extract URL from <PARAM> or <A> 
                $url = '';
                if (preg_match($param_url, $objects[3][$i], $matches) || preg_match($link_url, $objects[3][$i], $matches)) {
                    $url = $matches[3];
                }

                if ($url) {
                    // strip inner tags (e.g. <embed>)
                    $txt = preg_replace("/$tagopen.*?$tagclose/", '', $objects[3][$i]);

                    // if url is in the query string, remove the leading characters
                    $url = preg_replace('/^[^?]*\?([^=]+=[^&]*&)*[^=]+=([^&]*)$/', '$2', $url, 1);
                    $link = '<a href="'.$url.'">'.$txt.'</a>';

                    $new_object = mediaplugin_filter($this->filedir, $link);
                    $new_object = str_replace($link, '', $new_object);
                    $new_object = str_replace('&amp;', '&', $new_object);

                    $this->html = str_replace($objects[0][$i], $new_object, $this->html);
                }
            }
        }
    }

} // end class

function hotpot_convert_stylesheets_urls($baseurl, $reference, $css, $stripslashes=true) {
    if ($stripslashes) {
        $css = stripslashes($css);
    }
    $search = '|'.'(?<='.'url'.'\('.')'."(.+?)".'(?='.'\)'.')'.'|ise';
    $replace = "hotpot_convert_url('".$baseurl."','".$reference."','\\1')";
    return preg_replace($search, $replace, $css);
}
function hotpot_convert_preloadimages_urls($baseurl, $reference, $urls, $stripslashes=true) {
    if ($stripslashes) {
        $urls = stripslashes($urls);
    }
    $search = '|(?<=["'."'])([^,'".'"]*?)(?=["'."'])|ise";
    $replace = "hotpot_convert_url('".$baseurl."','".$reference."','\\1')";
    return preg_replace($search, $replace, $urls);
}
function hotpot_convert_navbutton_url($baseurl, $reference, $url, $course, $stripslashes=true) {
    global $CFG;

    if ($stripslashes) {
        $url = stripslashes($url);
    }
    $url = hotpot_convert_url($baseurl, $reference, $url, false);

    // is this a $url for another hotpot in this course ?
    if (preg_match("|^$baseurl(.*)$|", $url, $matches)) {
        if ($records = get_records_select('hotpot', "course='$course' AND reference='".$matches[1]."'")) {
            $ids = array_keys($records);
            $url = "$CFG->wwwroot/mod/hotpot/view.php?hp=".$ids[0];
        }
    }

    return $url;
}

function hotpot_convert_relative_url($baseurl, $reference, $opentag, $url, $closetag, $stripslashes=true) {
    if ($stripslashes) {
        $opentag = stripslashes($opentag);
        $url = stripslashes($url);
        $closetag = stripslashes($closetag);
    }

    // catch <PARAM name="FlashVars" value="TheSound=soundfile.mp3">
    //  ampersands can appear as "&", "&amp;" or "&amp;#x0026;amp;"
    if (preg_match('|^'.'\w+=[^&]+'.'('.'&((amp;#x0026;)?amp;)?'.'\w+=[^&]+)*'.'$|', $url)) {
        $query = $url;
        $url = '';
        $fragment = '';

    // parse the $url into $matches
    //  [1] path
    //  [2] query string, if any
    //  [3] anchor fragment, if any
    } else if (preg_match('|^'.'([^?]*)'.'((?:\\?[^#]*)?)'.'((?:#.*)?)'.'$|', $url, $matches)) {
        $url = $matches[1];
        $query = $matches[2];
        $fragment = $matches[3];

    // these appears to be no query or fragment in this url
    } else {
        $query = '';
        $fragment = '';
    }

    if ($url) {
        $url = hotpot_convert_url($baseurl, $reference, $url, false);
    }

    if ($query) {
        $search = '#'.'(file|src|thesound)='."([^&]+)".'#ise';
        $replace = "'\\1='.hotpot_convert_url('".$baseurl."','".$reference."','\\2')";
        $query = preg_replace($search, $replace, $query);
    }

    $url = $opentag.$url.$query.$fragment.$closetag;

    return $url;
}

function hotpot_convert_url($baseurl, $reference, $url, $stripslashes=true) {
    // maintain a cache of converted urls
    static $HOTPOT_RELATIVE_URLS = array();

    if ($stripslashes) {
        $url = stripslashes($url);
    }

    // is this an absolute url? (or javascript pseudo url)
    if (preg_match('%^(http://|/|javascript:)%i', $url)) {
        // do nothing

    // has this relative url already been converted?
    } else if (isset($HOTPOT_RELATIVE_URLS[$url])) {
        $url = $HOTPOT_RELATIVE_URLS[$url];

    } else {
        $relativeurl = $url;

        // get the subdirectory, $dir, of the quiz $reference
        $dir = dirname($reference);

        // allow for leading "./" and "../"
        while (preg_match('|^(\.{1,2})/(.*)$|', $url, $matches)) {
            if ($matches[1]=='..') {
                $dir = dirname($dir);
            }
            $url = $matches[2];
        }

        // add subdirectory, $dir, to $baseurl, if necessary
        if ($dir && $dir<>'.') {
            $baseurl .= "$dir/";
        }

        // prefix $url with $baseurl
        $url = "$baseurl$url";

        // add url to cache
        $HOTPOT_RELATIVE_URLS[$relativeurl] = $url;
    }
    return $url;
}

// ===================================================
// function for adding attempt questions and responses
// ===================================================

function hotpot_add_attempt_details(&$attempt) {

    // encode ampersands so that HTML entities are preserved in the XML parser
    // N.B. ampersands inside <![CDATA[ ]]> blocks do NOT need to be encoded

    $old = &$attempt->details; // shortcut to "old" details
    $new = '';
    $str_start = 0;
    while (($cdata_start = strpos($old, '<![CDATA[', $str_start)) && ($cdata_end = strpos($old, ']]>', $cdata_start))) {
        $cdata_end += 3;
        $new .= str_replace('&', '&amp;', substr($old, $str_start, $cdata_start-$str_start)).substr($old, $cdata_start, $cdata_end-$cdata_start);
        $str_start = $cdata_end;
    }
    $new .= str_replace('&', '&amp;', substr($old, $str_start));
    unset($old);

    // parse the attempt details as xml
    $details = new hotpot_xml_tree($new, "['hpjsresult']['#']");

    $num = -1;
    $q_num = -1;
    $question = NULL;
    $reponse = NULL;

    $i = 0;
    $tags = 'fields,field';

    while (($field="[$i]['#']") && $details->xml_value($tags, $field)) {

        $name = $details->xml_value($tags, $field."['fieldname'][0]['#']");
        $data = $details->xml_value($tags, $field."['fielddata'][0]['#']");

        // parse the field name into $matches
        //  [1] quiz type
        //  [2] attempt detail name
        if (preg_match('/^(\w+?)_(\w+)$/', $name, $matches)) {
            $quiztype = strtolower($matches[1]);
            $name = strtolower($matches[2]);

            // parse the attempt detail $name into $matches
            //  [1] question number
            //  [2] question detail name
            if (preg_match('/^q(\d+)_(\w+)$/', $name, $matches)) {
                $num = $matches[1];
                $name = strtolower($matches[2]);
                $data = addslashes($data);

                // adjust JCross question numbers
                if (preg_match('/^(across|down)(.*)$/', $name, $matches)) {
                    $num .= '_'.$matches[1]; // e.g. 01_across, 02_down
                    $name = $matches[2];
                    if (substr($name, 0, 1)=='_') {
                        $name = substr($name, 1); // remove leading '_'
                    }
                }

                // is this a new question (or the first one)?
                if ($q_num<>$num) {

                    // add previous question and response, if any
                    hotpot_add_response($attempt, $question, $response);

                    // initialize question object
                    $question = NULL;
                    $question->name = '';
                    $question->text = '';
                    $question->hotpot = $attempt->hotpot;

                    // initialize response object
                    $response = NULL;
                    $response->attempt = $attempt->id;

                    // update question number
                    $q_num = $num;
                }

                // adjust field name and value, and set question type
                // (may not be necessary one day)
                hotpot_adjust_response_field($quiztype, $question, $num, $name, $data);

                // add $data to the question/response details
                switch ($name) {
                    case 'name':
                    case 'type':
                        $question->$name = $data;
                        break;
                    case 'text':
                        $question->$name = hotpot_string_id($data);
                        break;

                    case 'correct':
                    case 'ignored':
                    case 'wrong':
                        $response->$name = hotpot_string_ids($data);
                        break;

                    case 'score':
                    case 'weighting':
                    case 'hints':
                    case 'clues':
                    case 'checks':
                        $response->$name = intval($data);
                        break;
                }

            } else { // attempt details

                // adjust field name and value
                hotpot_adjust_response_field($quiztype, $question, $num='', $name, $data);

                // add $data to the attempt details
                if ($name=='penalties') {
                    $attempt->$name = intval($data);
                }
            }
        }

        $i++;
    } // end while

    // add the final question and response, if any
    hotpot_add_response($attempt, $question, $response);
}
function hotpot_add_response(&$attempt, &$question, &$response) {
    global $db, $next_url;

    $loopcount = 1;

    $looping = isset($question) && isset($question->name) && isset($response);
    while ($looping) {

        if ($loopcount==1) {
            $questionname = $question->name;
        }

        $question->md5key = md5($question->name);
        if (!$question->id = get_field('hotpot_questions', 'id', 'hotpot', $attempt->hotpot, 'md5key', $question->md5key, 'name', $question->name)) {
            // add question record
            if (!$question->id = insert_record('hotpot_questions', $question)) {
                error("Could not add question record (attempt_id=$attempt->id): ".$db->ErrorMsg(), $next_url);
            }
        }

        if (record_exists('hotpot_responses', 'attempt', $attempt->id, 'question', $question->id)) {
            // there is already a response to this question for this attempt
            // probably because this quiz has two questions with the same text
            //  e.g. Which one of these answers is correct?

            // To workaround this, we create new question names
            //  e.g. Which one of these answers is correct? (2)
            // until we get a question name for which there is no response yet on this attempt

            $loopcount++;
            $question->name = "$questionname ($loopcount)";

            // This method fails to correctly identify questions in
            // quizzes which allow questions to be shuffled or omitted.
            // As yet, there is no workaround for such cases.

        } else {
            $response->question = $question->id;

            // add response record
            if(!$response->id = insert_record('hotpot_responses', $response)) {
                error("Could not add response record (attempt_id=$attempt->id, question_id=$question->id): ".$db->ErrorMsg(), $next_url);
            }

            // we can stop looping now
            $looping = false;
        }
    } // end while
}
function hotpot_adjust_response_field($quiztype, &$question, &$num, &$name, &$data) {
    switch ($quiztype) {
        case 'jbc':
            $question->type = HOTPOT_JCB;
            switch ($name) {
                case 'right':
                    $name = 'correct';
                break;
            }
            break;
        case 'jcloze':
            $question->type = HOTPOT_JCLOZE;
            if (is_numeric($num)) {
                $question->name = $num;
            }
            switch ($name) {
                case 'penalties':
                    if (is_numeric($num)) {
                        $name = 'checks';
                        if (is_numeric($data)) {
                            $data++;
                        }
                    }
                    break;
                case 'clue_shown':
                    $name = 'clues';
                    $data = ($data=='YES' ? 1 : 0);
                    break;
                case 'clue_text':
                    $name = 'text';
                    break;
            }
            break;
        case 'jcross':
            $question->type = HOTPOT_JCROSS;
            $question->name = $num;
            switch ($name) {
                case '': // HotPot v2.0.x
                    $name = 'correct';
                    break;
                case 'clue':
                    $name = 'text';
                    break;
            }
            break;
        case 'jmatch':
            $question->type = HOTPOT_JMATCH;
            switch ($name) {
                case 'attempts':
                    $name = 'penalties';
                    if (is_numeric($data) && $data>0) {
                        $data--;
                    }
                break;
                case 'lhs':
                    $name = 'name';
                break;
                case 'rhs':
                    $name = 'correct';
                break;
            }
            break;
        case 'jmix':
            $question->type = HOTPOT_JMIX;
            $question->name = $num;
            switch ($name) {
                // keep these in for "restore" of courses
                // which were backed up with HotPot v2.0.x
                case 'wrongguesses':
                    $name = 'checks';
                    if (is_numeric($data)) {
                        $data++;
                    }
                break;
                case 'right':
                    $name = 'correct';
                break;
            }
            break;
            break;
        case 'jquiz':
            switch ($name) {
                case 'type':
                    $data = HOTPOT_JQUIZ;
                    switch ($data) {
                        case 'multiple-choice':
                            $data .= '.'.HOTPOT_JQUIZ_MULTICHOICE;
                        break;
                        case 'short-answer':
                            $data .= '.'.HOTPOT_JQUIZ_SHORTANSWER;
                        break;
                        case 'hybrid':
                            $data .= '.'.HOTPOT_JQUIZ_HYBRID;
                        break;
                        case 'multi-select':
                            $data .= '.'.HOTPOT_JQUIZ_MULTISELECT;
                        case 'n/a':
                        default:
                            // do nothing more
                        break;
                    }
                break;
                case 'question':
                    $name = 'name';
                break;
            }
            break;

        case 'rhubarb':
            $question->type = HOTPOT_TEXTOYS_RHUBARB;
            if (empty($question->name)) {
                $question->name = $num;
            }
            break;

        case 'sequitur':
            $question->type = HOTPOT_TEXTOYS_SEQUITUR;
            break;
    }
}
function hotpot_string_ids($field_value) {
    $ids = array();
    $strings = explode(',', $field_value);
    foreach($strings as $str) {
        if ($id = hotpot_string_id($str)) {
            $ids[] = $id;
        }
    }
    return implode(',', $ids);
}
function hotpot_string_id($str) {
    $id = '';
    if (isset($str) && $str<>'') {

        // get the id from the table if it is already there
        $md5key = md5($str);
        if (!$id = get_field('hotpot_strings', 'id', 'md5key', $md5key, 'string', $str)) {

            // create a string record
            $record = new stdClass();
            $record->string = $str;
            $record->md5key = $md5key;

            // try and add the new string record
            if (!$id = insert_record('hotpot_strings', $record)) {
                global $db;
                error("Could not add string record for '".htmlspecialchars($str)."': ".$db->ErrorMsg());
            }
        }
    }
    return $id;
}

function hotpot_get_view_actions() {
    return array('view','view all','report');
}

function hotpot_get_post_actions() {
    return array('attempt','review','submit');
}

if (!function_exists('file_get_contents')) {
    // add this function for php version<4.3
    function file_get_contents($filepath) {
        $contents = file($filepath);
        if (is_array($contents)) {
             $contents = implode('', $contents);
        }
        return $contents;
    }
}
if (!function_exists('html_entity_decode')) {
    // add this function for php version<4.3
    function html_entity_decode($str) {
        $t = get_html_translation_table(HTML_ENTITIES);
        $t = array_flip($t);
        return strtr($str, $t);
    }

}

// required for Moodle 1.x
if (!isset($CFG->pixpath)) {
    $CFG->pixpath = "$CFG->wwwroot/pix";
}

if (!function_exists('fullname')) {
    // add this function for Moodle 1.x
    function fullname($user) {
        return "$user->firstname $user->lastname";
    }
}
if (!function_exists('get_user_preferences')) {
    // add this function for Moodle 1.x
    function get_user_preferences($name=NULL, $default=NULL, $userid=NULL) {
        return $default;
    }
}
if (!function_exists('set_user_preference')) {
    // add this function for Moodle 1.x
    function set_user_preference($name, $value, $otheruser=NULL) {
        return false;
    }
}
if (!function_exists('get_coursemodule_from_id')) {
    // add this function for Moodle < 1.5.4
    function get_coursemodule_from_id($modulename, $cmid, $courseid=0) {
        global $CFG;
        return get_record_sql("
            SELECT 
                cm.*, m.name, md.name as modname
            FROM 
                {$CFG->prefix}course_modules cm,
                {$CFG->prefix}modules md,
                {$CFG->prefix}$modulename m
            WHERE 
                ".($courseid ? "cm.course = '$courseid' AND " : '')."
                cm.id = '$cmid' AND
                cm.instance = m.id AND
                md.name = '$modulename' AND
                md.id = cm.module
        ");
    }
}
if (!function_exists('get_coursemodule_from_instance')) {
    // add this function for Moodle < 1.5.4
    function get_coursemodule_from_instance($modulename, $instance, $courseid=0) {
        global $CFG;
        return get_record_sql("
            SELECT 
                cm.*, m.name, md.name as modname
            FROM 
                {$CFG->prefix}course_modules cm,
                {$CFG->prefix}modules md,
                {$CFG->prefix}$modulename m
            WHERE 
                ".($courseid ? "cm.course = '$courseid' AND" : '')."
                cm.instance = m.id AND
                md.name = '$modulename' AND
                md.id = cm.module AND
                m.id = '$instance'
        ");
    }
}
function hotpot_utf8_to_html_entity($char) {
    // http://www.zend.com/codex.php?id=835&single=1

    // array used to figure what number to decrement from character order value
    // according to number of characters used to map unicode to ascii by utf-8
    static $HOTPOT_UTF8_DECREMENT = array(
        1=>0, 2=>192, 3=>224, 4=>240
    );

    // the number of bits to shift each character by
    static $HOTPOT_UTF8_SHIFT = array(
        1=>array(0=>0),
        2=>array(0=>6,  1=>0),
        3=>array(0=>12, 1=>6,  2=>0),
        4=>array(0=>18, 1=>12, 2=>6, 3=>0)
    );

    $dec = 0;
    $len = strlen($char);
    for ($pos=0; $pos<$len; $pos++) {
        $ord = ord ($char{$pos});
        $ord -= ($pos ? 128 : $HOTPOT_UTF8_DECREMENT[$len]);
        $dec += ($ord << $HOTPOT_UTF8_SHIFT[$len][$pos]);
    }
    return '&#x'.sprintf('%04X', $dec).';';
}

function hotpot_print_show_links($course, $location, $reference, $actions='', $spacer=' &nbsp; ', $new_window=false) {
    global $CFG;
    if (is_string($actions)) {
        if (empty($actions)) {
            $actions = 'showxmlsource,showxmltree,showhtmlsource';
        }
        $actions = explode(',', $actions);
    }
    $strenterafilename = get_string('enterafilename', 'hotpot');
    $html = <<<END_OF_SCRIPT
<script type="text/javascript">
//<![CDATA[
    function setLink(lnk) {
        var form = document.forms['form'];
        return setLinkAttribute(lnk, 'reference', form) && setLinkAttribute(lnk, 'location', form);
    }
    function setLinkAttribute(lnk, name, form) {
        // set link attribute value using
        // f(orm) name and e(lement) name

        var r = true; // result

        var obj = (form) ? form.elements[name] : null;
        if (obj) {
            r = false;
            var v = getObjValue(obj);
            if (v=='') {
                alert('$strenterafilename');
            } else {
                var s = lnk.href;
                var i = s.indexOf('?');
                if (i>=0) {
                    i = s.indexOf(name+'=', i+1);
                    if (i>=0) {
                        i += name.length+1;
                        var ii = s.indexOf('&', i);
                        if (ii<0) {
                            ii = s.length;
                        }
                        lnk.href = s.substring(0, i) + v + s.substring(ii);
                        r = true;
                    }
                }
            }
        }
        return r;
    }
    function getObjValue(obj) {
        var v = ''; // the value
        var t = (obj && obj.type) ? obj.type : "";
        if (t=="text" || t=="textarea" || t=="hidden") {
            v = obj.value;
        } else if (t=="select-one" || t=="select-multiple") {
            var l = obj.options.length;
            for (var i=0; i<l; i++) {
                if (obj.options[i].selected) {
                    v += (v=="" ? "" : ",") + obj.options[i].value;
                }
            }
        }
        return v;
    }
    function getDir(s) {
        if (s.charAt(0)!='/') {
            s = '/' + s;
        }
        var i = s.lastIndexOf('/');
        return s.substring(0, i);
    }
//]]>
</script>
END_OF_SCRIPT;

    foreach ($actions as $action) {
        $html .= $spacer
        .   '<a href="'
        .           $CFG->wwwroot.'/mod/hotpot/show.php'
        .           '?course='.$course.'&location='.$location.'&reference='.urlencode($reference).'&action='.$action
        .       '"'
        .       ' onclick="return setLink(this);"'
        .       ($new_window ? ' target="_blank"' : '')
        .   '>'.get_string($action, 'hotpot').'</a>'
        ;
    }
    print '<span class="helplink">'.$html.'</span>';
}

?>