// CTF records script by Bukz
const ignore_time_records_lessthan 2500
check2init this_player_CTF_score_record 0
check2init this_player_CTF_shortest_score_record 0
const FLAG_ACTIONS [STOLEN DROPPED LOST RETURNED SCORED KTFSCORE FAILSCORE RESET]
loop i (listlen $FLAG_ACTIONS) [
flagalias = (format FLAG_%1 (at $FLAG_ACTIONS $i))
const $flagalias $i
addListOnQuit $flagalias
]
checkinit onSpawn [ if (= $arg1 (player1 cn)) [ this_player_CTF_score = 0; this_player_CTF_initial_pickup_time = 0; this_player_CTF_score_time = 0; this_player_CTF_dropped = 0; old_CTF_shortest_record = $this_player_CTF_shortest_score_record ] ]
checkinit onFlag [
if (&& (= $arg2 (player1 cn)) (= $gamemode (modenum ctf))) [
if (&& (= $arg1 $FLAG_STOLEN) (! $this_player_CTF_dropped)) [
this_player_CTF_initial_pickup_time = (millis)
] [
if (= $arg1 $FLAG_DROPPED) [
this_player_CTF_dropped = 1
] [
if (= $arg1 $FLAG_LOST) [
this_player_CTF_dropped = 0
] [
if (= $arg1 $FLAG_SCORED) [
this_player_CTF_score_time = (millis)
+= this_player_CTF_score 1
this_player_CTF_dropped = 0
timetoscore = (- $this_player_CTF_score_time $this_player_CTF_initial_pickup_time)
if (&& (>= $timetoscore $ignore_time_records_lessthan) (|| (< $timetoscore $this_player_CTF_shortest_score_record) (! $this_player_CTF_shortest_score_record))) [
this_player_CTF_shortest_score_record = $timetoscore
]
]
]
]
]
]
]
checkinit onKill [ if (&& (= $arg2 (player1 cn)) (= $gamemode (modenum ctf))) checkCTFrecords ]
const checkCTFrecords [
if (> $this_player_CTF_score $this_player_CTF_score_record) [
echo (red)NEW (green)RECORD! (white)Most CTF flags scored in a single life: $this_player_CTF_score
this_player_CTF_score_record = $this_player_CTF_score
]
if (|| (< $this_player_CTF_shortest_score_record $old_CTF_shortest_record) (|| (! $this_player_CTF_shortest_score_record) (! $old_CTF_shortest_record))) [
echo (red)NEW (green)RECORD! (white)Shortest time spent carrying a CTF flag which you scored: (divf $this_player_CTF_shortest_score_record 1000) seconds
]
]
addListOnQuit [ignore_time_records_lessthan FLAG_ACTIONS flagalias this_player_CTF_score this_player_CTF_initial_pickup_time this_player_CTF_score_time this_player_CTF_dropped old_CTF_shortest_record checkCTFrecords]
// do while by Bukz
// Syntax:
// do [
// // body of code here
// // can span multiple lines/statements
// ] while [ (expression) ]
do = [
targ1 = $arg1
targ2 = $arg2
targ3 = $arg3
if (strcmp $targ2 while) [
execute $targ1
tmpExpression = (concat [bool =] $targ3)
execute $tmpExpression
if (!= $bool 0) [
do $targ1 while $targ3
]
]
]
// for by Bukz (requires parsestring & parsestring framework)
persistidents 0
const dofor [
execute $code
execute $codestr
tstr = (concat [bool =] $exprstr)
execute $tstr
if (!= $bool 0) dofor
]
const for [
if (> $numargs 1) [
data = $arg1
code = $arg2
forceinit [initstr exprstr codestr] []
numsc = (findAllCharacterPositions $data [;])
if (&& (!= $numsc -1) (= (listlen $numsc) 2)) [
sc1 = (at $numsc 0)
sc2 = (at $numsc 1)
initstr = (trimAllUnnecessaryWhitespace (substr $data 0 $sc1))
exprstr = (trimAllUnnecessaryWhitespace (substr $data (+ $sc1 1) (- $sc2 (+ $sc1 1))))
codestr = (trimAllUnnecessaryWhitespace (substr $data (+ $sc2 1)))
execute $initstr
tstr = (concat [bool =] $exprstr)
execute $tstr
if (!= $bool 0) dofor
]
]
]
persistidents 1
// for [i = 0; (< $i 10); ++ i] [echo $i]
// Headshot records script by Bukz
check2init this_player_headshot_record 0
check2init this_player_noscope_record 0
checkinit onSpawn [ if (= $arg1 (player1 cn)) [ this_player_headshots = 0; this_player_noscopes = 0 ] ]
checkinit onKill [
if (&& (= $arg1 (player1 cn)) (!= $arg1 $arg2)) [
if (&& (curmodeattr team) (!= (player1 team) (player $arg2 team))) [
if (&& (= $arg3 $SNIPER) (!= $arg4 0)) [
if (! (player1 scoping)) [ += this_player_noscopes 1 ]
+= this_player_headshots 1
]
]
] [
if (= $arg2 (player1 cn)) [
checkHeadshotRecords
]
]
]
const checkHeadshotRecords [
if (> $this_player_headshots $this_player_headshot_record) [
echo (red)NEW (green)RECORD! (white)Most headshots in a single life: $this_player_headshots
this_player_headshot_record = $this_player_headshots
]
if (> $this_player_noscopes $this_player_noscope_record) [
echo (red)NEW (green)RECORD! (white)Most no-scope headshots in a single life: $this_player_noscopes
this_player_noscope_record = $this_player_noscopes
]
]
addListOnQuit [this_player_headshots this_player_noscopes checkHeadshotRecords]
// Hotkeys script by Bukz
persistidents 0
const HIGHEST_KEYMAP_CODE 320
// loops through all mapped keys (except mouse "keys") and injects code into their binds
loop hkl $HIGHEST_KEYMAP_CODE [
tkey = (findkey $hkl)
if (!= $tkey -255) [
keya = (format key%1down $tkey)
add2bind $tkey (format "%1 = 1; onrelease [ %1 = 0 ]" $keya)
addListOnQuit $keya
]
]
// function to determine if a key is currently being held down, e.g. echo (keydown BACKSPACE) // output: 0 or 1
const keydown [
istrue = 0
if $numargs [
akey = (format key%1down $arg1)
if (checkalias $akey) [ if (!= (getalias $akey) 0) [ istrue = 1 ] ]
]
return $istrue
]
// function to create the actual hotkeys, injects code into the last keybind of the hotkey sequence
const hotkey [
if (= $numargs 3) [
add2bind (toupper $arg2) (format "if (keydown %1) [ %2 ]" (toupper $arg1) $arg3)
] [
if (= $numargs 4) [
add2bind (toupper $arg3) (format "if (&& (keydown %1) (keydown %2)) [ %3 ]" (toupper $arg1) (toupper $arg2) $arg4)
] [
// theres a very good chance hotkey sequences > 3 keys in length will not work on -ANY- keyboard/OS, but we'll try to support up to 9 keys anyways...
if (= $numargs 5) [
add2bind (toupper $arg4) (format "if (&& (&& (keydown %1) (keydown %2)) (keydown %3)) [ %4 ]" (toupper $arg1) (toupper $arg2) (toupper $arg3) $arg5)
] [
if (= $numargs 6) [
add2bind (toupper $arg5) (format "if (&& (&& (keydown %1) (keydown %2)) (&& (keydown %3) (keydown %4))) [ %5 ]" (toupper $arg1) (toupper $arg2) (toupper $arg3) (toupper $arg4) $arg6)
] [
if (= $numargs 7) [
add2bind (toupper $arg6) (format "if (&& (&& (&& (keydown %1) (keydown %2)) (&& (keydown %3) (keydown %4))) (keydown %5)) [ %6 ]" (toupper $arg1) (toupper $arg2) (toupper $arg3) (toupper $arg4) (toupper $arg5) $arg7)
] [
if (= $numargs 8) [
add2bind (toupper $arg7) (format "if (&& (&& (&& (keydown %1) (keydown %2)) (&& (keydown %3) (keydown %4))) (&& (keydown %5) (keydown %6))) [ %7 ]" (toupper $arg1) (toupper $arg2) (toupper $arg3) (toupper $arg4) (toupper $arg5) (toupper $arg6) $arg8)
] [
if (= $numargs 9) [
add2bind (toupper $arg8) (format "if (&& (&& (&& (keydown %1) (keydown %2)) (&& (keydown %3) (keydown %4))) (&& (&& (keydown %5) (keydown %6)) (keydown %7))) [ %8 ]" (toupper $arg1) (toupper $arg2) (toupper $arg3) (toupper $arg4) (toupper $arg5) (toupper $arg6) (toupper $arg7) $arg9)
] [
if (= $numargs 10) [
add2bind (toupper $arg9) (format "if (&& (&& (&& (keydown %1) (keydown %2)) (&& (keydown %3) (keydown %4))) (&& (&& (keydown %5) (keydown %6)) (&& (keydown %7) (keydown %8)))) [ %9 ]" (toupper $arg1) (toupper $arg2) (toupper $arg3) (toupper $arg4) (toupper $arg5) (toupper $arg6) (toupper $arg7) (toupper $arg8) $arg10)
]
]
]
]
]
]
]
]
]
persistidents 1
// hotkey LALT F4 suicide
// hotkey LALT 1 [
// echo You have the LALT key pressed.
// onrelease [ echo You released the 1 key. ]
// ]
// hotkey LALT J K [
// echo You have the LALT key and the J key pressed.
// onrelease [ echo You released the K key. ]
// ]
// Killstreak records script by Bukz
check2init this_player_killstreak_record 0
checkinit onSpawn [ if (= $arg1 (player1 cn)) [ this_player_killstreak = 0 ] ]
checkinit onKill [
if (&& (= $arg1 (player1 cn)) (!= $arg1 $arg2)) [
if (&& (curmodeattr team) (!= (player1 team) (player $arg2 team))) [
+= this_player_killstreak 1
] [ += this_player_killstreak 1 ]
] [
if (= $arg2 (player1 cn)) [
checkKillStreakRecord
]
]
]
const checkKillStreakRecord [
if (> $this_player_killstreak $this_player_killstreak_record) [
echo (red)NEW (green)RECORD! (white)Highest killstreak in a single life: $this_player_killstreak
this_player_killstreak_record = $this_player_killstreak
]
]
addListOnQuit [this_player_killstreak checkKillStreakRecord]
// CubeScript map triggers by Bukz
persistidents 0
// $arg1 = map to add a trigger for
// $arg2 = unique trigger name
// $arg3 = trigger zone (a list of 2 points on a grid: "82 84 56 58" for example, 82 = minX, 84 = maxX, 56 = minY 58 = maxY, indicating a trigger zone of 2x2 cubes)
// $arg4 = trigger action (cubescript to execute upon player1 entering the trigger zone)
// $arg5 = action when not in trigger zone
addmaptrigger = [
maptoadd = $arg1
triggername = $arg2
triggerzone = $arg3
triggeraction = $arg4
nottriggeraction = $arg5
check2init (format %1_triggers $maptoadd) []
if (! (strstr (MDArray_Get_All_Subarray_Names (format %1_triggers $maptoadd)) $triggername)) [
// trigger doesn't exist
MDArray_New_Subarray (format %1_triggers $maptoadd) $triggername (concat (addpunct $triggerzone) (addpunct $triggeraction) (addpunct $nottriggeraction))
]
]
doMapTriggers = [
curmaptriggers = (MDArray_Get_All_Subarray_Names (format %1_triggers (curmap 1)))
if (listlen $curmaptriggers) [
loop cmt (listlen $curmaptriggers) [
curtrigger = (MDArray_Get (format %1_triggers (curmap 1)) (at $curmaptriggers $cmt) -1)
curzone = (at $curtrigger 0)
if (&& (checkrange (player1 x) (at $curzone 0) (at $curzone 1)) (checkrange (player1 y) (at $curzone 2) (at $curzone 3))) [
execute (at $curtrigger 1)
] [ execute (at $curtrigger 2) ]
]
]
sleep 0 doMapTriggers
]
checkinit mapstartalways [ if (checkalias (format %1_triggers (curmap 1))) doMapTriggers ]
persistidents 1
// parsestring by Bukz
const breakparse [ parsebreak = 1 ]
const doparse [
parselen = (strlen $strtoparse)
loop dpl $parselen [
if $parsebreak break [
if $parsebackwards [
$charcontainer = (substr $strtoparse (- (- $parselen $dpl) 1) 1)
(format __%1 $charcontainer) = (- (- $parselen $dpl) 1)
] [
$charcontainer = (substr $strtoparse $dpl 1)
(format __%1 $charcontainer) = $dpl
]
execute $parsecode
]
]
]
const parsestring [
if (> $numargs 2) [
strtoparse = $arg1
charcontainer = $arg2
parsecode = $arg3
if (> $numargs 3) [
parsebackwards = $arg4
] [ parsebackwards = 0 ]
parsebreak = 0
doparse
]
]
addListOnQuit [breakparse parsebreak doparse parselen strtoparse parsebackwards charcontainer dpl parsecode parsestring]
// parsestring framework by Bukz
persistidents 0
// make helpful consts for use with (testchar)
const CHARACTERTESTS [ISDIGIT ISALPHA ISALNUM ISLOWERCASE ISUPPERCASE ISCHAR ISPUNCT ISWHITESPACE]
loop cel (listlen $CHARACTERTESTS) [
const (at $CHARACTERTESTS $cel) $cel
addListOnQuit (at $CHARACTERTESTS $cel)
]
// string manip helper functions below
//
// trimAllUnnecessaryWhitespace - Returns a modified string after removing any unnecessary leading and trailing whitespace from the original.
// $arg1 = string to modify
const trimAllUnnecessaryWhitespace [
strtotrim = $arg1
forceinit [charsbegin charsend] -1
parsestring $strtotrim tch [
if (! (testchar $tch $ISWHITESPACE)) [
charsbegin = $__tch
breakparse
]
]
parsestring $strtotrim thc [
if (! (testchar $thc $ISWHITESPACE)) [
charsend = $__thc
breakparse
]
] 1
if (&& (&& (!= $charsbegin -1) (!= $charsend -1)) (!= $charsbegin $charsend)) [
return (substr $strtotrim $charsbegin (- (+ $charsend 1) $charsbegin))
] [ return $strtotrim ]
]
// trimAllWhitespace - Returns a modified string after removing any whitespace characters from the original.
// $arg1 = string to modify
const trimAllWhitespace [
strtotrim = $arg1
trimmedstr = []
parsestring $strtotrim twh [
if (! (testchar $twh $ISWHITESPACE)) [
trimmedstr = (concatword $trimmedstr $twh)
]
]
return $trimmedstr
]
// capitalizeFirst - Returns a modified string with the first character capitalized. (if possible)
// $arg1 = string to modify
// Warning: Also trims all unnecessary leading and trailing whitespace.
const capitalizeFirst [
strtomanip = (trimAllUnnecessaryWhitespace $arg1)
manipedstr = []
parsestring $strtomanip cfc [
if $__cfc breakparse [
if (testchar $cfc $ISALPHA) [
manipedstr = (concatword $manipedstr (toupper $cfc))
] [ manipedstr = (concatword $manipedstr $cfc) ]
]
]
if (testchar $manipedstr $ISUPPERCASE) [
return (concatword $manipedstr (substr $strtomanip 1))
] [ return $strtomanip ]
]
// useful generic parsing functions below
//
// isCharList - Returns a boolean value (0 or 1) indicating whether or not the specified list is a simple list of character data. (every element's strlen == 1)
// $arg1 = list to check
const isCharList [
isch = 1
if (! (listlen $arg1)) [ isch = 0 ] [
loop icl (listlen $arg1) [
if (!= (strlen (at $arg1 $icl)) 1) [
isch = 0
]
]
]
return $isch
]
// replacechar - Returns a string with a single character replaced with a new one.
// $arg1 = string to modify
// $arg2 = character position (integer) to modify in the string
// $arg3 = new character to replace $arg2 position with
const replacechar [
strtomod = $arg1
charpos = $arg2
newch = $arg3
moddedstr = []
if (&& (&& (strlen $strtomod) (= (strlen $newch) 1)) (&& (> $charpos -1) (< $charpos (strlen $strtomod)))) [
parsestring $strtomod rcp [
if (= $charpos $__rcp) [
moddedstr = (concatword $moddedstr $newch)
] [ moddedstr = (concatword $moddedstr $rcp) ]
]
return $moddedstr
] [ return $strtomod ]
]
// findAllCharacterPositions - Returns a list of character positions (integers) in a string that match a specified character.
// $arg1 = string to inspect
// $arg2 = character to search for
const findAllCharacterPositions [
haystackstr = $arg1
needlechar = $arg2
needlepositions = []
parsestring $haystackstr hsl [
if (strcmp $hsl $needlechar) [ add2list needlepositions $__hsl ]
]
if (listlen $needlepositions) [ return $needlepositions ] [
return -1
]
]
// replaceAllCharacters - Returns a string with multiple characters replaced with new ones.
// $arg1 = string to modify
// $arg2 = list of character positions (integers) to modify
// $arg3 = list of new characters to replace $arg2 positions with
// Warning: Lists $arg2 and $arg3 must be the exact same length.
const replaceAllCharacters [
strtoreplace = $arg1
charstoreplace = $arg2
newchars = $arg3
replacedstr = $strtoreplace
charlistlen = (listlen $newchars)
if (&& (= (listlen $charstoreplace) $charlistlen) (isCharList $newchars)) [
loop ral $charlistlen [
replacedstr = (replacechar $replacedstr (at $charstoreplace $ral) (at $newchars $ral))
]
return $replacedstr
] [ return $strtoreplace ]
]
persistidents 1
// Smooth sniper scope zoom with mouse wheel script by Bukz
persistidents 0
const ZOOM_SMOOTH 1 // set to 0 to disable smooth zooming
const ZOOM_SMOOTH_MILLIS_BETWEEN_CHANGES 15 // milliseconds between scopefov changes for smooth zooming
const ZOOM_DEFAULT_SCOPEFOV 50 // default scopefov for when you first scope in
const ZOOM_SCOPEFOV_INCREMENT 10 // change scopefov by this much on every tick of the mouse wheel
const isany [ bool = 0; looplist $arg2 ia [ if (strcmp $ia $arg1) [ bool = 1; break ] ]; return $bool ]
const validscopefov [ return (checkrange $arg1 5 60) ]
const doscope [
if (! $numargs) [
scopefov $ZOOM_DEFAULT_SCOPEFOV
setscope 1
onrelease [ setscope 0 ]
] [
newfov = -1
if (isany $arg1 [in 1 +]) [
oper = -
newfov = (- $scopefov $ZOOM_SCOPEFOV_INCREMENT)
dif = (- $scopefov $newfov)
] [
if (isany $arg1 [out 0 -]) [
oper = +
newfov = (+ $scopefov $ZOOM_SCOPEFOV_INCREMENT)
dif = (- $newfov $scopefov)
]
]
if (validscopefov $newfov) [
if $ZOOM_SMOOTH [
loop sf $dif [
sleep (* $ZOOM_SMOOTH_MILLIS_BETWEEN_CHANGES $sf) [
newfov = ($oper $scopefov 1)
if (validscopefov $newfov) [ scopefov $newfov ]
]
]
] [ scopefov $newfov ]
]
]
]
altaction_5 = doscope
delta_game_0 = [
if (&& (= (curweapon) $SNIPER) (player1 scoping)) [
if (= $arg1 1) [ doscope + ] [ doscope - ]
] [
if (= $arg1 1) [ shiftweapon 1 ] [ shiftweapon -1 ]
]
]
persistidents 1
// strswitch by Bukz
persistidents 0
trimallunnecessarywhitespace = [
oldstr = $arg1
charsbegin = 0
charsend = 0
loop kal (strlen $oldstr) [
curchar = (substr $oldstr $kal 1)
if (testchar $curchar 7) continue [
charsbegin = $kal
break
]
]
loop kal (strlen $oldstr) [
curchar = (substr $oldstr (- (- (strlen $oldstr) $kal) 1) 1)
if (testchar $curchar 7) continue [
charsend = (- (- (strlen $oldstr) $kal) 1)
break
]
]
if (!= $charsbegin $charsend) [
return (substr $oldstr $charsbegin (- (+ $charsend 1) $charsbegin))
] [ return $oldstr ]
]
strswitch = [
tofind = $arg1
loop ssl (- $numargs 1) [
tmpargcontent = (getalias (format arg%1 (+ $ssl 2)))
if (strlen $tmpargcontent) [
casepos = (findlist $tmpargcontent case)
if (!= $casepos -1) [
casename = (at $tmpargcontent (+ $casepos 1))
if (strcmp $tofind $casename) [
caseplusname = (format [case %1] $casename)
codetoexecute = (strreplace $tmpargcontent $caseplusname [])
execute (trimallunnecessarywhitespace $codetoexecute)
]
]
]
]
]
persistidents 1
// Weapon accuracies script by Bukz
onMapStr = []
looplist $WEAPONS i [
attackalias = (format player1_%1attacks $i)
hitalias = (format player1_%1hits $i)
add2list onMapStr (format [%1 = 0;] $attackalias)
add2list onMapStr (format [%1 = 0;] $hitalias)
addListOnQuit $attackalias
addListOnQuit $hitalias
]
checkinit mapstartalways $onMapStr
checkinit onAttack [ += (format player1_%1attacks (at $WEAPONS $arg1)) 1 ]
checkinit onHit [
if (&& (= $arg1 (player1 cn)) (!= $arg1 $arg2)) [
if (&& (curmodeattr team) (!= (player1 team) (player $arg2 team))) [ // don't increment team damage hits
+= (format player1_%1hits (at $WEAPONS $arg4)) 1
] [ += (format player1_%1hits (at $WEAPONS $arg4)) 1 ]
]
]
const getAccuracy [
if (&& $numargs (checkrange $arg1 0 (- $NUM_WEAPONS 1))) [
curweap = (at $WEAPONS $arg1)
curattacks = (getalias (format player1_%1attacks $curweap))
curhits = (getalias (format player1_%1hits $curweap))
curaccuracy = (*f (divf $curhits $curattacks) 100)
return $curaccuracy
] [ return -1 ]
]
const printAccuracy [ echo (format [%1: %2%3 (%4/%5)] $curweap $curaccuracy (addpunct [] $PERCENT) $curhits $curattacks) ]
const showAccuracies [
if (&& $numargs (!= (getAccuracy $arg1) -1)) [
printAccuracy
] [
loop i $NUM_WEAPONS [
if (= $i $CPISTOL) continue [ // cpistol is still not fully implemented
getAccuracy $i
printAccuracy
]
]
]
]
addListOnQuit [onMapStr attackalias hitalias getAccuracy printAccuracy showAccuracies curweap curattacks curhits curaccuracy]
// Smooth sniper scope zoom with mouse wheel script by Bukz (1104)
ZOOM_SMOOTH = 1 // set to 0 to disable smooth zooming
ZOOM_SMOOTH_MILLIS_BETWEEN_CHANGES = 15 // milliseconds between scopefov changes for smooth zooming
ZOOM_DEFAULT_SCOPEFOV = 50 // default scopefov for when you first scope in
ZOOM_SCOPEFOV_INCREMENT = 10 // change scopefov by this much on every tick of the mouse wheel
isany = [ bool = 0; loop ia (listlen $arg2) [ if (strcmp (at $arg2 $ia) $arg1) [ bool = 1 ] ]; result $bool ]
checkrange = [ if (&& (>=f $arg1 $arg2) (<=f $arg1 $arg3)) [ result 1 ] [ result 0 ] ]
validscopefov = [ result (checkrange $arg1 5 60) ]
player1scoping = 0
doscope = [
if (! $numargs) [
scopefov $ZOOM_DEFAULT_SCOPEFOV
setscope 1
player1scoping = 1
onrelease [ setscope 0; player1scoping = 0 ]
] [
newfov = -1
if (isany $arg1 [in 1 +]) [
oper = -
newfov = (- $scopefov $ZOOM_SCOPEFOV_INCREMENT)
dif = (- $scopefov $newfov)
] [
if (isany $arg1 [out 0 -]) [
oper = +
newfov = (+ $scopefov $ZOOM_SCOPEFOV_INCREMENT)
dif = (- $newfov $scopefov)
]
]
if (validscopefov $newfov) [
if $ZOOM_SMOOTH [
loop sf $dif [
sleep (* $ZOOM_SMOOTH_MILLIS_BETWEEN_CHANGES $sf) [
newfov = ($oper $scopefov 1)
if (validscopefov $newfov) [ scopefov $newfov ]
]
]
] [ scopefov $newfov ]
]
]
]
altaction_5 = doscope
delta_game_0 = [
if (&& (= (curweapon) 5) $player1scoping) [
if (= $arg1 1) [ doscope + ] [ doscope - ]
] [
if (= $arg1 1) [ shiftweapon 1 ] [ shiftweapon -1 ]
]
]