/************************************************************************* 
 **                                                                     ** 
 **                           D M A S T R                               ** 
 **                          -------------                              ** 
 **                                                                     ** 
 **         Original PDP-11 macro assembler version written by:         ** 
 **                 Kenneth Forster and Rod Dickinson                   ** 
 **             at Monash University, Victoria, Australia               ** 
 **                                                                     ** 
 **                    DOS C version written by:                        ** 
 **                 Kenneth Forster and Mike Durham                     ** 
 **           With additional assistance from Kevin Ackley              ** 
 **                                                                     ** 
 **     Turbo Graphic version and Enhanced Experimenter's Display by:   ** 
 **                       Jonathan C. Forster                           ** 
 **                  at the University of Arizona                       ** 
 **                                                                     ** 
 **                  Win32 and DirectX version by:                      ** 
 **                       Jonathan C. Forster                           ** 
 **                                                                     ** 
 *************************************************************************/


 
 
DMDX is the Win32 DirectX based version of DMASTR, a display system used in psychological, linguistic and other laboratories around the world to measure reaction times to visual and auditory stimuli.  
 
This introduction covers things from the very simplest use of DMDX through some of the most complex things possible with it however it can't demonstrate the use of other media such as bitmap graphics, audio and digital video -- for them you will have to see the regular help. The beginner may only want to look at the first few screens of it, others will probably want to see everything in here if for no other reason than to get an idea of the range of things DMDX can do -- and even then we don't begin to cover all of what's possible, the sky's pretty much the limit... 
 
If you want to jump ahead to the instruction section you can press
I
or to get to the scrambling section you can hit S
or for the positioning section you can hit P
or for the 1 of N responses / mouse based input section you can hit 1
or for the sentence reading using branching / simple counter section you can hit B or O
or for the rating / calling section you can hit R
or for the typing / more complex counter section you can hit C
or for the macro / multi-scramble / indexed branching / continue clock on section you can hit M, X or N
or for the test mode / tachistoscopic acid test section you can hit T or A.

 
 
Basic Introduction


 
 
DMASTR's input is primarily a binary response paradigm and when DMTG (the Turbo Graphic DOS version of DMASTR) introduced the keyboard as a response device (prior to that custom switches wired up to an interface card were used) we decided to use the shift keys as the default response keys and the space bar as a request and there were no particular problems beyond the timing issues inherent to a device that polls a column of it's keys at a time (typical keyboards can have 15 milliseconds or more of variability) and when DMDX (the Win32 version of DMASTR) was introduced running under Windows 95 I suspect initially things were still OK, however at some point Microsoft decided to add a feature called Sticky Keys (Wikipedia claims it was with Windows 95 but I think it was later as we certainly didn't notice it till some time later) where hitting a shift key five times in a row fires up a dialog about enabling it. This obviously needs to be disabled so you might want to do that now by hitting ESC and exiting DMDX and then hitting one of the shift keys five times and following the dialog tree down to where you can tell it to go away and never rear it's ugly head again…

 
 
DMDX is controlled by a script we refer to as an item file, this introduction being a special example run with the Introduction button, normally you would browse to an item file and click Run and DMDX will start executing it and we refer to that as running a job. The Diagnostic options are to run the file as quickly as possible without subject responses to debug an item file, the Unicode option is for item files that have Unicode characters in them and the Syntax Check button parses the file without displaying anything to check for syntax and other errors. Once an item file is running ESC is used to either stop the job and save the data if the job has run to completion or to abort the job if it hasn't run to completion. 
 
Item files in DMDX are Rich Text Files with the extension .RTF and it's pretty much WYSIWYG although there are countless options covered in the help to modify the display. The first line of the item file is referred to as the parameter line and it can be extended to cover multiple lines with the extended parameters keyword
<ep> and with the end of parameters keyword <eop> when the parameters are dispensed with. There is one non-optional parameter that must be specified and that is the frame duration that specifies how long a single display element of an item (a "frame") is displayed for, either in tics (usually 1/60th of a second) or approximately in milliseconds (it will be converted to tics internally).

 
 
The parameter line for this item file is something like:
 
<ep> <id #keyboard> <vm desktop> <cr>
<fd 10> <dwc 255,255,96> <dbc 32,64,128> <eop>
 
Here we've specified that the input device to be used for this job is the #keyboard device that doesn't use names and instead uses button numbers and works under all circumstances (the standard default keyboard device is less useful when the system language is not English). We've also made sure to the use the desktop video mode and we've also specified that the job should run continuously with <cr> and not stop for a request after every item. On the second line we've specified the default display duration is 10 tics or about 1/6th of a second (if you wanted to specify that duration in milliseconds you'd use <msfd 166>). We've also set the default writing color along with the default background color (normally it's black on white, this coloring scheme is a tribute to the original Borland Turbo C compiler that was used to create DMTG back in 1989 when such coloring schemes where trendy). 
 
Note that when I wrote that paragraph the parameter line was in fact as shown, these days it is quite a bit more complicated as more and more features were added to this introduction however I have no intention of getting into such deep things this early on if at all.

 
 
Normally after the parameters some instructions would be given but we'll get to that once we cover some more basic item structure details. The standard task for DMDX is a binary response lexical decision task and a generic example of an item in one is:
 
+101 * "target";
 
A special note about this introduction is that in order to display double quotes (") and semi-colons (;) I'm using full width versions of those characters found in Asian fonts as otherwise there's no way DMDX can display them so the spacing of these displays is going to be a little liberal (for instance there are no spaces between those brackets earlier in this sentence). Of course if you happen to be reading the version of the introduction that appears in the help where I've turned all the full width characters into normal ones the spacing will of course be normal...
 
The first element in an item is the Correct Response indicator, or CR indicator, here we've specified that the right shift key is the correct response key with a
+, if the correct response was the left key a - CR indicator would be used (other CR indicators are = for any, ^ for none, ! to make the whole item a comment and ~ to skip the display of this item). If there was no response to be gathered (for example in an instruction) the CR indicator can be skipped.

 
 
+101 * "target";
 
Next up is the item number (here it's 101) that is used to identify responses in the .AZK data file DMDX produces when the data is saved at the completion of the run (not when it's aborted) and cannot exceed 2^31 (2147483648). 
 
By default DMDX will stop after each item and wait for a request (by default that's the space bar for the
#keyboard device we're using) unless continuous running has been used (which we have with <cr> in the parameters), however when the item number is zero DMDX will always wait for a request to dismiss that item (by inference it's an instruction). 
 
After the item number the individual display frames of the item follow although in our basic example there is just one frame. The first element of the frame is the asterisk clock on indicator that turns the subject response clock on when that frame is displayed. Following that is the text that will be displayed in double quotes followed by the item terminator semicolon. The next screen will execute this and two more similar items and you can respond with the left or right shift key or if you don't the item will time out after 4 seconds (the
<Timeout> parameter can be used to override the default 4000 ms).

 
 
You'll notice that after each item DMDX provided feedback for each response, if you didn't want that feedback can be turned off in the parameters with the no feedback keyword <nfb> or if you wanted the display cleared after the response but no feedback per se you could use the clear feedback keyword <clfb> or if you wanted the target left on the screen but also wanted feedback you could use the feedback only clears behind keyword <fbocb> or if you only wanted wrong feedback you could use the wrong feedback only keyword <wfbo> or if you didn't like the reaction time being displayed it could be suppressed with the no feedback time keyword <nfbt> and if you wanted different feedback entirely it can be specified as well with <cfb>, <wfb> and/or <tlfb> (see the help, for instance google "DMDX tlfb"). 
 
Of course just presenting a single word and leaving it on the screen isn't very interesting so you might want to erase it by putting a frame separator (/) in there before the semicolon and because we haven't specified a unique frame duration for the first frame it would be displayed for the default frame duration of 10 tics and then be erased:
 
+201 * "target" / ; 
 
Note the order of the components of a frame generally isn't significant (the exception being when they contain tests used in conditional branching) whereas the order of the frames in an item is very definitely significant. The next display will present three of these items.

 
 
And of course even that's totally tame, so maybe we want to do some masked prime presentation with a fixation point: 
 
+301 <msfd 1500> "++" / "##########" / <fd 3> "prime" / * "target" / ;
 
Here we've used the millisecond frame duration keyword to make the fixation point stay on the screen for 1.5 seconds and we've specified the prime should be displayed for three tics (50 ms on most displays), the other frames will pick up the default frame duration of 10 tics (the mask and target). The timing of that last blank frame is different in that when DMDX displays a frame (which takes one tic) and there are no more frames to be displayed in the item it goes about whatever it is that needs doing next (waiting for a response or request or preparing the next item), it doesn't wait around for the frame's implicit duration (here 10 tics). Even if you explicitly put a duration in there it will be ignored as all a duration does is specify the time that the next frame would be displayed at -- if there's no next frame it has no effect.
 
The next display will present three of these items.

 
 
And there are countless other options like <bmp> or <wav> that makes the text of the frame be used as a bitmap or wave file name to be displayed or played instead of the text iteself being displayed what to speak of <dv> for playing digital video which can be seen in the demos: 
 
http://psy1.psych.arizona.edu/~jforster/dmdx/demos.zip
http://psy1.psych.arizona.edu/~jforster/dmdx/DVDEMO.ZIP  
 
Also in the too complicated to demo here bracket DMDX will also happily drive two monitors, one for the subject and one for the experimenter (use TimeDX's Video Driver selection to select the subject's display device), it'll even send the experimenter's display data to another machine running the Monitor program (see TimeDX's Network Setup command). Both of which greatly facilitate Naming Tasks where the experimenter is deciding if a subject's response is correct or not (see DMDX's
<NamingTaskNegation> keyword). DMDX can also send signals to other machines with <output> be they fMRI or EKG/EMG or what have you over a parallel cable (see TimeDX's PIO Test). You can also do remote testing over the internet with DMDX. You bundle DMDX up with WinRAR and it's SFX self extracting ability along with your item file and my poster.exe HTTP data posting program and a batch file to post the data to the UnloadAZK4web CGI-BIN running on psy1 and as long as your subjects are willing to use Windows computers you're gathering data from all over the globe -- see the Remote Testing section in the help, you'll want to use the Luxury Yacht solution...

 
 
Instruction Section


 
 
While a slash / is our temporal separator there is one instance where it isn't and it becomes more of a spatial separator and that's when the leading frame's duration is zero and here you'd wind up with two frames scheduled at the same time and indeed when the second frame doesn't erase the first this is in fact a very useful thing, say, in the case of instructions where you want more than one line of text on the screen at once. So useful in fact there's a special variant of the frame separator and it's the comma , which is exactly eqivalent to <fd 0> / <noerase> (or in classic Dmastr syntax using switches %0 / ! should you be so inclined) and it becomes a real spatial separator when you use the <line> keyword (or @ switch) to specify which line on the screen you want the text displayed on (where line zero's bottom is the middle of the screen). While there are better options for instructions that we'll get to shortly classic instructions might be something like this: 
 
0 "Instructions are items with an item number" <line -1>, 
"of zero and are usually dismissed by a request",
 
"(which is by default the space bar) unless the" <line 1>, 
"<continue> keyword or C switch has been used..." <line 2>;

 
 
Instructions are items with an item number
of zero and are usually dismissed by a request
(which is by default the space bar) unless the
<continue> keyword or C switch has been used...

 
 
As noted instructions used to be a bit of pain once one moved beyond a fairly terse level of instruction as one would have to guess how much text could fit on a line and re-wrapping stuff when you edited them could get tedious until I added the <inst> keyword to automatically format paragraphs. Here one specifies a bounding box on the screen (using fractions of the screen height and width) and one makes each word and it's following space a frame and uses the comma frame delimiter to merge them all together like this: 
 
0 <inst .1, .1, .92 hardmargin>  
"
Lorem ", "ipsum ", "dolor ", "sit ", "amet, ", "ne ", "ubique ", "ridens ", "voluptaria ", "his, ", "in ", "augue ", "debet ", "facilisi ", "duo. ", "Oratio ", "assentior ", "sea ", "no, ", "eu ", "docendi ", "fastidii ", "iudicabit ", "mei. ", "Suas ", "rationibus ", "efficiendi ", "in ", "mei. ", "Vel ", "sonet ", "elitr ", "deleniti ", "an.",  
<inst esc> "Hit the space bar to continue..." <line 12>; 
 
When creating these <inst> items I like to type my sentences out normally then do a search and replace on all the spaces in them with [space]",[space]" thus automating the process. The hardmargin option makes DMDX issue a new line before any frame that would cross the right margin as opposed to the default behavior of doing so after it crosses the margin -- trust me, this is better.

 
 
Lorem ipsum dolor sit amet, ne ubique ridens voluptaria his, in augue debet facilisi duo. Oratio assentior sea no, eu docendi fastidii iudicabit mei. Suas rationibus efficiendi in mei. Vel sonet elitr deleniti an.

 
 
At the end of that instruction you'll notice the frame with <inst esc> in it, here we're escaping the positioning of that line from the normal <inst> rules and falling back on traditional mechanisms explicitly placing the space bar message on the 12th line of the display (zero being the middle, negative going up and positive down the screen).  
 
And in addition to
<inst esc> you can also put <inst nl> in to force a new line at that point and if you wanted a blank line you'd put another frame with another newline: 
 
0 <inst .1, .1, .92 hardmargin>  
"
Lorem ", "ipsum ", "dolor ", "sit ", "amet, ", "ne ", "ubique ", "ridens ", "voluptaria ", "his, ", "in ", "augue ", "debet ", "facilisi ", "duo. ", <inst nl>, <inst nl>, "Oratio ", "assentior ", "sea ", "no, ", "eu ", "docendi ", "fastidii ", "iudicabit ", "mei. ", <inst nl>, <inst nl>, "Suas ", "rationibus ", "efficiendi ", "in ", "mei. ", <inst nl>, <inst nl>, "Vel ", "sonet ", "elitr ", "deleniti ", "an.",  
<inst esc> "Hit the space bar to continue..." <line 12>; 
 
These days you can put hardmargin in the parameters with <inst hardmargin> and then it's active everywhere and doesn't need continual invocation like this introduction has.

 
 
Lorem ipsum dolor sit amet, ne ubique ridens voluptaria his, in augue debet facilisi duo.  
 
Oratio assentior sea no, eu docendi fastidii iudicabit mei.  
 
Suas rationibus efficiendi in mei.  
 
Vel sonet elitr deleniti an.

 
 
Speaking of positioning things in instructions you could also use <xy> instead of <line> and feed it some screen coordinates if you didn't want to use line based positioning, but you'd also want to activate <xyjustification center> otherwise you'd have to calculate offsets from the coordinates of the top left corner of that text -- more than a little challenging when you also want that centered but of course the positioning of <inst> is itself dependent on <xyjustification lefttop> (or leftbottom if you have different sized fonts in there like I do in these instructions) so you have to turn on <xyjustification framebyframe> to allow it to be set on a frame by frame basis instead of it's default item by item setting. 
 
So let's say we wanted instructions with an instructional image in the middle of the screen with text above and below it (I'll be using a Unicode character as I can't use images in the introduction but you get the idea). Here we'd have to use a bunch of new lines between our text segments and some guestimation as there's no other way to get
<inst> aligned frames positioned (you can't have two <inst> keywords in a single item with different bounding boxes). 
 
One thing to bear in mind here is that if you put the frame that uses
<xyjustification center> in the middle of the item like I do you have to invoke <xyjustification lefttop> before the following text so <inst> positioning resumes correctly (<inst> with centered justification is very bad).

 
 
0 <xyjustification framebyframe> <xyjustification lefttop> <inst .1, .1, .92>  
"
Mel ", "ut ", "nonumy ", "deleniti ", "suavitate, ", "vix ", "id ", "utinam ", "eirmod ", "reformidans. ", "Corpora ", "consetetur ", "mei ", "ne, ", "ut ", "ferri ", "justo ", "eam. ", "Cum ", "cu ", "stet ", "recusabo, ", "sit ", "utroque ", "tractatos ", "percipitur ", "ut, ", "ad ", "usu ", "partem ", "habemus. ", "Assentior ", "percipitur ", "ut ", "vim. ", "Ad ", "admodum ", "accusata ", "eos. ", "Vero ", "integre ", "his ", "ad, ", "agam ", "facilis ", "eam ", "ut. ", "Ius ", "ut ", "feugiat ", "alienum ", "menandri, ", "ut ", "sit ", "bonorum ", "dolorem ", "patrioque, ", "detracto ", "praesent ", "dignissim ", "ad ", "quo." <inst nl>, <inst nl>, <inst nl>, <inst nl>, <inst nl>, <inst nl>, <inst nl>, 
 
<inst esc> <fm 5> "Ω" <xyjustification center> <xy .5,.5>, 
 
<xyjustification lefttop> "
Esse ", "urbanitas ", "cu ", "sed, ", "scaevola ", "partiendo ", "necessitatibus ", "pro ", "an. ", "Duo ", "at ", "tollit ", "eripuit ", "facilisi. ", "Eum ", "sonet ", "hendrerit ", "democritum ", "an, ", "ad ", "affert ", "aeterno ", "cum. ", "Urbanitas ", "definitiones ", "ei ", "ius."
<inst esc> "Hit the space bar to continue..." @12;

 
 
Item files can contain comments and there are two varieties of them. The first is the keyword variant where any keyword (be it in the parameters or items) that begins with a ! becomes a comment. This is a convenient way to temporarily stop a keyword from having any effect, I will often use it to disable branch diagnostics in the parameter line for example when I might want to turn it on again later: 
 
<fd 10> <!branchdiagnostics> 
 
The other form of a comment is the CR version of it where any item that begins with a ! becomes a comment and all of it's contents up until the semi-colon is ignored: 
 
! this is a comment; 
 
It should be noted that like all items a comment can extend over multiple lines and is not a line based thing, a trap people seem to fall for a lot. So in the following the first line doesn't end in a semi-colon and instead the second line (that should be an item) is now a part of the first line's comment: 
 
! this is a comment 
+101 * "target" / ;

 
 
Scrambling Section


 
 
DMDX can randomize the order of items presented with its scrambling routines invoked with the scramble parameter <scramble>. The scramble parameter determines the size of the blocks scramble moves items around in, the block size being needed to prevent situations where any number of items from the same condition could be presented sequentially. If you don't care the value 1 or the number of items in the file will do, they function equivalently. The simplest possible item file with a scramble would then look something like this: 

<fd 10> <scramble 1> 
+101 * "target A" / ; 
+102 * "target B" / ; 
+103 * "target C" / ; 
 
A typical run with the above item file might produce: 

<fd 10> 
+101 * "target A" / ; 
+103 * "target C" / ; 
+102 * "target B"/ ;

 
 
A more typical case would be where you had two conditions, let's say there are three items in each and we want to limit the presentation of items in one condition to two in a row. Here you'd specify a scramble parameter of two and you'd interleave the two sets of items: 

<fd 10> <scramble 2> 
+101 * "target A" / ; 
+201 * "target a" / ; 
+102 * "target B" / ; 
+202 * "target b" / ; 
+103 * "target C" / ; 
+203 * "target c" / ; 
 
Here each block of two items would be considered individually, because we've just got two items they would either be swapped with each other or not and then the blocks of two would be moved randomly in the file and the results might look like this: 

<fd 10> 
+202 * "target b" / ; 
+102 * "target B" / ; 
+203 * "target c" / ; 
+103 * "target C" / ; 
+101 * "target A" / ; 
+201 * "target a" / ;

 
 
The results of any given scramble are available in the text file called scrambled.itm that should be in the folder the item file was in. 
 
Of course an item file with no instructions or an ending message isn't realistic (indeed you can't collect data from the last item in an item file so at the very least an ending message is essential) and of course those messages shouldn't be moved with the items as they're scrambled. So there are fixed blocks that are delimited by pairs of dollars symbols (dollars in quoted text segments aren't seen by scramble): 

<fd 10> <scramble 1> 
$ 0 "Instructions";$ 
+101 * "target A" / ; 
+102 * "target B" / ; 
+103 * "target C" / ; 
$ 0 "The End";$ 
 
Note the positioning of dollars are unaffected by white space so you could just as easily have this instead: 


0 "Instructions"; 
$

 
 
Next up we might have the case where you have pre-test items and post-test items and don't want them mixed up with each other yet still want them scrambled within their own section. Here we have the scramble emit command, a backslash \ by itself at the start of a line (if it occurs anywhere else it will be ignored, primarily because it's a valid path name character). What it does is force scramble to stop reading input and scramble everything read to that point and then start reading more input to scramble: 

<fd 10> <scramble 1> 
$ 0 "Pre-test instructions";$ 
+101 * "target A" / ; 
+102 * "target B" / ; 
+103 * "target C" / ; 
$ 0 "Post-test instructions";$ 

+101 * "target A" / ; 
+102 * "target B" / ; 
+103 * "target C" / ; 
$ 0 "The End";$

 
 
Often times items have to occur in pairs or other groups of sequential items and for this there's a grouping factor parameter <Grouping> that will treat any given specified group size of items as if they were one item for the purposes of calculating the number of items in a block and items are not scrambled within the group.  

<fd 10> <scramble 1> <grouping 2> 
+101 * "target Aa" / ; 
+102 * "target Ab" / ; 
+201 * "target Ba" / ; 
+202 * "target Bb" / ; 
+301 * "target Ca" / ; 
+302 * "target Cb" / ; 
 
A typical run with the above item file might produce: 

<fd 10> 
+101 * "target Aa" / ; 
+102 * "target Ab" / ; 
+301 * "target Ca" / ; 
+302 * "target Cb" / ; 
+201 * "target Ba" / ; 
+202 * "target Bb" / ;

 
 
It's worth noting that if you remove the <scramble> parameter and then run the item file without removing the dollars delimiters and backslash emit commands you'll get syntax errors as they're removed by the scramble routines and if scramble isn't activated it's not going to remove them and while we could get DMDX to ignore them traditionally that's not the case. 
 
There are a couple of other scramble parameters like the
<ScrambleSeed> parameter that primes the random number generator to always produce the same sequence of numbers for any given seed thus always producing the same item order. There's also a variant of the grouping parameter called the <VariableGrouping> parameter allowing flexible groups of items where as long as they are (a) sequential in the item file and (b) when their item numbers are divided by the variable grouping parameter their item numbers are identical. There is one trick I should mention should you not be able to use variable grouping yet have different numbers of items in your groups and that is to use a grouping factor of whatever the largest group of items is and pad all the others with empty comments !; that DMDX will skip over in minimal time yet because they're items they satisfy scramble's needs.

 
 
Positioning Section


 
 
Perhaps a better demonstration for <xy> is in a multi-target item where you want to have four elements in the quadrants of the screen and the task is to decide if a target in the center of the screen matches or not: 
 
-401 <xyjustification center> <msfd 1500> "++" <dfm 5> / "1" <xy .25, .25> , "2" <xy .75, .25> , "3" <xy .25, .75> , "4" <xy .75, .75> , <fd 6> * "5" <xy .5, .5> / <dfm 1> ;
 
Because the task is to identify if the number in the center of the screen appears in the corners as well our CR indicator is - because the correct answer is no, the 5 is not at the corners. Next up we're specifying that the justification should reference the center of the image so that they're all nicely positioned and we don't have to bend over backwards figuring out what coordinates to use. We've also used <dfm> to set the font multipliers to 5 to make the numbers nice and big (the trick with <dfm> being to use it in the frame before you want it active as it only affects following frames). We've specified the duration of the center frame as 6 tics (~100 ms) as when you're merging frames together the duration must go in the last frame of the sequence. We also want to set the default font multipliers back to 1 so the feedback is at it's normal size...

 
 
Note that we could avoid using the default font multipliers (<dfm>) and instead put an individual multiplier in each frame that we wanted larger with <fm>, pick your poison, sometimes you have lots of frames and it's tedious to multiply them all individually and it's better to use <dfm> and deal with its eccentricities of only having an effect in following frames and other times <fm> is the clear winner, this one's a borderline case (and yes, I've thought about changing that behavior, so now <dfm>, <dbm>, <dbgc> and <dwc> all have a STAT option that makes them take effect in the frame they're used in): 
 
-401 <xyjustification center> <msfd 1500> "++" / <fm 5> "1" <xy .25, .25> , <fm 5> "2" <xy .75, .25> , <fm 5> "3" <xy .25, .75> , <fm 5> "4" <xy .75, .75> , <fd 6> * <fm 5> "5" <xy .5, .5> / ;

 
 
1 of N Responses Section


 
 
While DMDX's standard mode is a binary response paradigm it is easy enough to extend to 1 of N being correct (usually it's 1 of N but there can just as easily be more than one correct response) and doing such a task involves mapping and unmapping signals for each different response to be gathered. While this is a little tedious it is nonetheless eminently doable. So let's say our task is to identify the missing number in a grid of four rapidly presented numbers from the previous example by pressing one of the 1 through 5 keys. 
 
+501 <xyjustification center> <msfd 1500> "++" <dfm 5> <umpr> <umnr> <mnr +#2> <mnr +#3> <mnr +#4> <mnr +#5> <mpr +#6> / "1" <xy .25, .25>, "2" <xy .75, .25>, "3" <xy .25, .75>, "4" <xy .75, .75> * / <dfm 1>;

 
 
+501 <xyjustification center> <msfd 1500> "++" <dfm 5> <umpr> <umnr> <mnr +#2> <mnr +#3> <mnr +#4> <mnr +#5> <mpr +#6> / "1" <xy .25, .25>, "2" <xy .75, .25>, "3" <xy .25, .75>, "4" <xy .75, .75> * / <dfm 1>; 
 
First thing that's different from our previous item is that these items are always going to have a + CR indicator, we're coding the correctness directly in the item which brings up the second difference, it unmaps the previous positive response keys and the negative ones as with each item in 1 of N tasks the correct key(s) will change (almost) every time with <umpr> <umnr>. After that we map the five response keys to either the positive keys with <mpr> or the negative keys with <mnr>. Because we're using the international #keyboard device the 1 key is the #2 button (you can find out what number a key is in TimeDX's Input Test) and because we're interested in the depression of the key rather than its release it's the +#2 signal. Other than that we don't have a central frame any more but that's just our experiment design and has nothing to do with the 1 of N task.

 
 
In order to demonstrate the many different things that DMDX can do this introduction has to chain from one item file to another with <chain> and <lastframe> because parameters set one way for one paradigm are often exclusive to other paradigms and the only way to get DMDX to use new or different parameters is to get it to load a new item file.  
 
Normally users of DMDX don't have to worry about this as they choose one mode of operation and rarely need a single experiment to use more than one but here it's unavoidable and for most users transparent barring a small delay as the new item file is loaded as when using the Direct3D renderer found in Windows 8 and later OSes there's an option to preserve the display with
<chain preservevm itemfile> however users of Windows 7 and earlier OSes will experience a momentary flicker of the display as DMDX switches back to the desktop display. So if you're using an earlier OS sorry about the flickering you're about to see, it'll happen several more times throughout this introduction.

 
 
Another example of one of many inputs is a Stroop test, at least one that's not using a vocal response anyway and while people have done Stroop tests before with four colored keys on the keyboard it's hampered by having to remember which key is which color. Which brings us to the <2Did> parameter that allows us to use the mouse for a point and click interface. Here we can present our Stroop probes and have the subject click on the correctly colored box. 
 
First up we have changes to our parameter line and because we don't want those changes active for the whole introduction we've chained to another item file (with
<chain>) to allow us to set up a <2Did> input device mapping for just this section:
 
<2Did mouse blue,.3,.7,.4,.82 green,.4,.7,.5,.82 red,.5,.7,.6,.82 yellow,.6,.7,.7,.82 clipcursor,.3,.7,.7,.82> <dwc 255,255,255> <dbc 0,0,0> 
 
Here we've told DMDX we want to use the mouse so DMDX has turned the mouse cursor back on and we've defined four areas of the screen that will be our buttons to click on (coordinate order is left, top, right, bottom and here we've used fractions of the screen width and height where the top left corner of the screen is 0,0 and the bottom right is 1,1). We've also defined an area of the screen that will clip the cursor's movement to limit the amount of time people might be dragging the mouse around.

 
 
Because this item file will be manipulating color we've also changed the background color to black and the writing color to white with <dwc 255,255,255> <dbc 0,0,0> which brings up another special DMDX gotcha and that is the tender issue of <RTFcolorOverride>. Because the usual color of text in an RTF file is black and more specifically the color of DMDX's feedback is also black when you set the background black you can't see either of them, black on black being black... So one is forced to specify the writing color as well and once you've done that DMDX is ignoring the color of the text throughout and you're using the writing color keyword <wc> everywhere. If there was a logical solution (other than using a white background) I'd have used it, I like putting the color in the RTF file and not dealing with RGB triplets. 
 
+802 <fm 2> * <wc 0,128,0> "blue" <umpr> <umnr> 
<mnr +blue> <mpr +green> <mnr +red> <mnr +yellow>,  
<dfm 4 STAT> <xy .35,.75> <wc 0,0,255> "
", <xy .45,.75> <wc 0,128,0> "", <xy .55,.75> <wc 255,0,0> "", <xy .65,.75> <wc 255,255,0> "" <dfm 1>; 
 
So here we're displaying the bold "blue" frame in green with <wc 0,128,0> twice it's usual size with <fm 2> and then doing the same sort of mapping thing done in the previous example with <mpr> and <mnr> only this time we're using the names we assigned regions of the screen to in the <2Did> parameter keyword on the previous page with the correct button being the green one.

 
 
+802 <fm 2> * <wc 0,128,0> "blue" <umpr> <umnr> 
<mnr +blue> <mpr +green> <mnr +red> <mnr +yellow>,  
<dfm 4 STAT> <xy .35,.75> <wc 0,0,255> "
", <xy .45,.75> <wc 0,128,0> "", <xy .55,.75> <wc 255,0,0> "", <xy .65,.75> <wc 255,255,0> "" <dfm 1>; 
 
After mapping our responses we're displaying four square box characters (gotta love Unicode, there's some wild stuff out there) colored the right way across the screen for the subject to click on that line up with the named regions we defined in our <2Did> parameter earlier. Last but not least we set the font multipliers back to 1 for the feedback. We use a <dfm STAT> to set the font multipliers for the four boxes so it takes effect immediately for the first blue box and we use the delayed <dfm> at the end so (a) the yellow box is the right size and (b) the feedback that follows will be the right size. There's also a <xyjustification center> in the setup for these items (not shown). 
 
Following are four of these Stroop items, click on the colored box that's the color of the text. While this example may not be scientifically useful because of the delay in mouse positioning now that DMDX handles Windows Touch touch screen devices it actually stands a chance of being usable so I exported it using the windowstouch device and stuffed it in a file named
"2Did windowstouch.rtf"in the demos: 
 
http://psy1.psych.arizona.edu/~jforster/dmdx/demos.zip

 
 


 
 
Sentence Reading Section


 
 
While other more brute force methods to present sentence reading tasks in DMDX exist they are greatly facilitated by the progressive X keyword <px> where you give it an initial X coordinate to start at and the first word of the sentence and then following items present the rest of the words with the continue progressive X keyword <cpx>
 
+701 <nfb> <px .2> * "Hickory "; 
-702 <delay 2> <cpx> * ! "dickory "; 
+703 <delay 2> <cpx> * ! "dock, "; 
+704 <delay 2> <cpx> * ! "the "; 
+705 <delay 2> <cpx> * ! "mouse "; 
+706 <delay 2> <cpx> * ! "ran "; 
+707 <delay 2> <cpx> * ! "up "; 
+708 <delay 2> <cpx> * ! "the "; 
+709 <delay 2> <cpx> * ! "clock ";

 
 
+701 <nfb> <px .2> * "Hickory "; 
-702 <delay 2> <cpx> * ! "dickory "; 
+703 <delay 2> <cpx> * ! "dock, "; 
+704 <delay 2> <cpx> * ! "the "; 
+705 <delay 2> <cpx> * ! "mouse "; 
+706 <delay 2> <cpx> * ! "ran "; 
+707 <delay 2> <cpx> * ! "up "; 
+708 <delay 2> <cpx> * ! "the "; 
+709 <delay 2> <cpx> * ! "clock "; 
 
New elements here are using <delay 2> to make the next word pop onto the screen almost immediately as opposed to taking the default 48 tic (or 800 ms) delay to do so. Note we don't want to use <delay 0> as that will produce display errors as there's no way DMDX can have something up at the same time as it's parsing it. Also we've used the legacy <NoErase> switch ! to stop the items erasing what was already on the screen.  
 
Here our task is to identify whether the last word presented is a real word or not.

 
 
Of course we've got feedback turned off because it would screw up our display when it erases the screen and even though one can in fact use the feedback only clears behind keyword <fbocb> and in addition restrict it to wrong feedback only with <wfbo> you'd find that feedback when displayed screws up the progressive X coordinate tracking… What you'd have to do is use <x> instead of <px> and <cpx> and re-present the whole sentence each frame and we're not going there because even if you do all of that you're still left with the situation where once an incorrect response has been given the rest of the sentence is immaterial. 
 
Instead we'll use some branching to jump out of our sentence block and provide a bit of feedback only on mistakes. 
 
+701 <nfb> <px .2> * "Hickory " <biw 2>; 
-702 <delay 2> <cpx> * ! "dickory " <biw 2>; 
+703 <delay 2> <cpx> * ! "dock, " <biw 2>; 
+704 <delay 2> <cpx> * ! "the " <biw 2>; 
+705 <delay 2> <cpx> * ! "mouse " <biw 2>; 
+706 <delay 2> <cpx> * ! "ran " <biw 2>; 
+707 <delay 2> <cpx> * ! "up " <biw 2>; 
+708 <delay 2> <cpx> * ! "the " <biw 2>; 
+709 <delay 2> <cpx> * ! "clock " <biw 2>; 
~1 <bu 3>; 
2 <delay 2> "- - - W r o n g - - -" <fd 32> <line 2> / ; 
~3;

 
 
+701 <nfb> <px .2> * "Hickory " <biw 2>; 
-702 <delay 2> <cpx> * ! "dickory " <biw 2>; 
+703 <delay 2> <cpx> * ! "dock, " <biw 2>; 
+704 <delay 2> <cpx> * ! "the " <biw 2>; 
+705 <delay 2> <cpx> * ! "mouse " <biw 2>; 
+706 <delay 2> <cpx> * ! "ran " <biw 2>; 
+707 <delay 2> <cpx> * ! "up " <biw 2>; 
+708 <delay 2> <cpx> * ! "the " <biw 2>; 
+709 <delay 2> <cpx> * ! "clock " <biw 2>; 
~1 <bu 3>; 
2 <delay 2> "- - - W r o n g - - -" <fd 32> <line 2> / ; 
~3; 
 
So here we've added a branch if wrong to item 2 <biw 2> to each item and there's three items at the end of our group of items that presents this sentence that can be duplicated for each sentence group that handle the wrong response from the previous items. If the subject successfully responds to each item DMDX would fall through to item 1 and we don't want it to spew our Wrong message so it skips over item 2 to item 3 with the branch unconditionally <bu 3> keyword. Item 3 is just a dummy target for our jump (if we didn't use a dummy item we'd have to know what the item number of the first item in the next sentence group is and if we're scrambling items that's impossible). Otherwise a wrong response branches to item 2 and it has the same sort of look and feel of the usual wrong feedback that's displayed for 32 tics (or half a second or so).

 
 
Simple Counter Section


 
 
Another somewhat common thing to want to do is to have some sort of time limit or other sort of condition that needs checking every item. Here we use a subroutine and a call in every item to that subroutine to check the condition. In order to have a time limit for the total item file we'll make use of a special token in DMDX's expression evaluator that lets us see what the current millisecond time is and stop the item file if we go beyond a time out based on that: 
 
0 "Limited total time." <bu 840>; 
~810 <bi 830, c1 .lt. millisectime>; 
~1 <return>; 
830 <lastframe> "Time's up."; 
~840 <set c1 = millisectime + 10000>; 
+8100 * "target" / <call -810>; 
+8110 * "target" / <call -810>;  
+8120 * "target" / <call -810>; 
+8130 * "target" / <call -810>;  
0 "Finished under time limit."; 
 
First off we have an unconditional branch over our subroutine with <bu 840> so it doesn't get executed as the item file commences, if we didn't do that we'd get an error about there being a return without a corresponding call. DMDX will then skip over our subroutine and execute item 840 that sets counter 1 to the time that's 10 seconds in the future which we'll check the time against in the subroutine. After that each item then gathers a response and then calls item 810 that does the check and if we somehow manage to rip through those four items in under 10 seconds we'll get the finished under the time limit message.

 
 
~810 <bi 830, c1 .lt. millisectime>; 
~1 <return>; 
830 <lastframe> "Time's up."; 
 
Our actual subroutine's items all begin with tilde skip display CR indicators ~ so that they execute with almost no delay (microseconds on modern machines) with the exception of item 830 where we actually want DMDX to display something. While we're getting a little ahead of ourselves in this introduction by using the branch if keyword <bi> here (it's covered in more detail later in the more complex counter section) I'm in a chicken and egg situation here where I need a more sophisticated feature in order to show off a simpler one so please excuse the hand waving... Item 810 starts off by checking if the remembered time in counter 1 from the start of the task's execution in item 840 is less than the current time (ie we've gone too long) and if so branches to item 830 otherwise it falls through to the next item that returns control back to the item after whichever one it was that called the subroutine at 810. Item 830 then has the <lastframe> keyword in it that makes DMDX stop execution after displaying the time's up message. 
 
I would note that for the purposes of our demonstration I won't actually be using the <lastframe> option as we want the rest of the introduction to execute and indeed have to go to some lengths to unwind the stack but that's beyond the scope of our subject…

 
 
Limited total time.

 
 
Finished under time limit.

 
 
Alternatively a recent request was to stop an item file if a subject has four wrong responses in a row. Here instead of a counter storing the time we should stop at we'll use a counter to count the number of wrong responses in a row, setting it back to zero on a correct response and stopping when it gets over our threshold: 
 
0 "Limited wrong responses in a row." <set c1 = 0> <bu 940>; 
~910 <biw 920>; 
~1 <set c1 = 0> <return>; 
~920 <inc c1> <bi 930, c1 .gt. 3>; 
~1 <return>; 
930 <lastframe> "Too many errors."; 
~940; 
+8200 * "target 1" / <call -910>; 
+8210 * "target 2" / <call -910>;  
+8220 * "target 3" / <call -910>; 
+8230 * "target 4" / <call -910>;  
+8240 * "target 5" / <call -910>; 
+8250 * "target 6" / <call -910>;  
+8260 * "target 7" / <call -910>; 
+8270 * "target 8" / <call -910>; 
0 "Not too many errors."; 
 
As you can see, the only substantial difference from the previous example is in the decision making subroutine (we do set our count of wrong responses to zero at the start with <set c1 = 0> as all counters must be initialized before any use otherwise an error will be thrown).

 
 
~910 <biw 920>; 
~1 <set c1 = 0> <return>; 
~920 <inc c1> <bi 930, c1 .gt. 3>; 
~1 <return>; 
930 <lastframe> "Too many errors."; 
 
To implement our task the first thing our subroutine is going to do is a branch if the subject's response was wrong to item 920 with <biw 920> because we want to do different things based on the correctness of the response. If the response was in fact correct that branch won't get taken and DMDX will fall through to the following item that will set our count of wrong responses back to zero with <set c1 = 0> and then return to the response gathering items. Otherwise when the response is wrong counter 1 gets incremented with <inc c1> and then we test whether it's more than 3 and branch to item 930 if so with <bi 930, c1 .gt. 3>. Otherwise we fall through to a <return> back to the response gathering items. Lastly we have item 930 catching too many wrong responses in a row that stops execution after tossing the appropriate message. 
 
I would note that item 920 has one of those rare frames where the order of the components of a frame matter, if that
<inc c1> occurred after the <bi 930, c1 .gt. 3> then you'd have to make five wrong responses in a row before the experiment would be halted.

 
 
Limited wrong responses in a row.

 
 
Not too many errors.

 
 
Rating Section


 
 
Usually rating tasks are best done with <zil> <zor> <zol> item files as when DMDX is generating a .ZIL data file it automatically emits the name of the key that was struck and given that this item file is not a <zil> file but is instead an <azk> item file we've chained out to yet another introduction item file with the aforementioned parameters: <zil> for zillions of responses (usually recorded for the entire subject time out interval), <zor> for just one zillion response (making it more like an <azk> item file that proceeds once a response is received) and <zol> to make all the zillion output take only one line per item instead of a number of them (makes it easier to import into Excel for instance). A typical line of output in a .ZIL file generated with an item file that has <zil> <zor> <zol> in it's parameters might look like this (where the 3 key was hit):
 
Item 601, 3302.43 3302.43,+#4
 
Versus a typical line of an .AZK data file:
 
601 3302.43
 
I would note that importing .AZK or <zil> <zor> <zol> .ZIL data files into Excel is greatly facilitated by running them through AZK2CSV in the DMDX utilities available here:
 
http://psy1.psych.arizona.edu/~jforster/dmdx/dmdxutils.zip

 
 
All up our .ZIL rating item file looks something like this: 
 
<ep> <zil> <zor> <zol> <id #keyboard> <vm desktop> <cr>
<fd 10> <dwc 255,255,96> <dbc 32,64,128>  
<vzk +#2> <vzk +#3> <vzk +#4> <vzk +#5> <vzk +#6> <eop>
 
0 "Some instructions" <t 15000> <clfb> <umnr> <umpr> <mpr +#2> <mpr +#3> <mpr +#4> <mpr +#5> <mpr +#6> ;
 
+601 <inst .1, .1, .92 hardmargin> "
Lorem ", "ipsum ", "dolor ", "sit ", "amet, ", "ne ", "ubique ", "ridens ", "voluptaria ", "his, ", "in ", "augue ", "debet ", "facilisi ", "duo. ", "Oratio ", "assentior ", "sea ", "no, ", "eu ", "docendi ", "fastidii ", "iudicabit ", "mei. ", "Suas ", "rationibus ", "efficiendi ", "in ", "mei. ", "Vel ", "sonet ", "elitr ", "deleniti ", "an.",  
<inst esc> "Please rate the text on the scale below:",  
<inst esc> "1----2----3----4----5" <line 3>,  
<inst esc> "dislike neutral like " <line 4> * ;

 
 
Another feature of running DMDX in zillions of responses mode is any signal from the mapped input devices will be emitted into the output which is not necessarily what one wants so in addition to the <zil> <zor> <zol> parameters one should also validate the keys one intends to use: 
 
<vzk +#2> <vzk +#3> <vzk +#4> <vzk +#5> <vzk +#6>  
 
Here we're validating the main keyboard keys 1 through 5 that are confusingly numbered 2 through 6, thanks IBM. Other than validating zillion response keys that's about it for special setup with <zil> <zor> <zol> rating files. After that we might have some instructions that also sets up conditions likely to be the same for all our rating items: 
 
0 "Some instructions" <t 15000> <clfb> <umnr> <umpr> <mpr +#2> <mpr +#3> <mpr +#4> <mpr +#5> <mpr +#6> ;
 
First up we're setting the time limit for responses to 15 seconds with <t 15000> as rating tasks rarely need to be done in the default 4 second time out. After that we're making the feedback clear with <clfb> as all our responses are positive ones so we don't want the regular correct/incorrect feedback logic but we don't want to just suppress feedback completely with <nfb> as without some break between items it can be unobvious that a new rating has begun.

 
 
0 "Some instructions" <t 15000> <clfb> <umnr> <umpr> <mpr +#2> <mpr +#3> <mpr +#4> <mpr +#5> <mpr +#6> ;
 
And after we set the feedback up we unmap the default negative response keys with <umnr> as well as the positive response ones with <umpr> and then we map our five keys as positive response keys with five <mpr> keywords. 
 
For our task we'll have people rate whether they like a passage of text and display a Likert scale: 
 
+601 <inst .1, .1, .92 hardmargin> "Lorem ", "ipsum ", "dolor ", "sit ", "amet, ", "ne ", "ubique ", "ridens ", "voluptaria ", "his, ", "in ", "augue ", "debet ", "facilisi ", "duo. ", "Oratio ", "assentior ", "sea ", "no, ", "eu ", "docendi ", "fastidii ", "iudicabit ", "mei. ", "Suas ", "rationibus ", "efficiendi ", "in ", "mei. ", "Vel ", "sonet ", "elitr ", "deleniti ", "an.",  
<inst esc> "Please rate the text on the scale below:",  
<inst esc> "1----2----3----4----5" <line 3>,  
<inst esc> "dislike neutral like " <line 4> * ; 
 
Beyond the slight tweak of using an <inst> keyword in a data gathering item pretty much everything here has been shown in this introduction before.

 
 


 
 
Well that's a little flat, to liven it up a bit we can toss a bit of animation in there for a feedback feel however doing so means adding subroutines and using a multiway call on the key struck which is 90% of the work to do ratings in an <azk> file so we might as well do that. 
 
<ep> <id #keyboard> <vm desktop> <cr>
<fd 10> <dwc 255,255,96> <dbc 32,64,128> <eop>
 
~1 <dfd 32>
<bu 1>;
9101 <delay 2> <emit rated 1> "1--------------------" @3 / <return>; 
9102 <delay 2> <emit rated 2> "-----2---------------" @3 / <return>; 
9103 <delay 2> <emit rated 3> "----------3----------" @3 / <return>; 
9104 <delay 2> <emit rated 4> "---------------4-----" @3 / <return>; 
9105 <delay 2> <emit rated 5> "--------------------5" @3 / <return>; 
9106 <delay 2> <emit no rating> "No Response" @3 / <return>; 
~1;
 
0 "Some instructions" <t 15000> <nfb> <umnr> <umpr> <mpr +#2> <mpr +#3> <mpr +#4> <mpr +#5> <mpr +#6> ;
 
+601 <inst .1, .1, .92 hardmargin> "
Lorem ", "ipsum ", "dolor ", "sit ", "amet, ", "ne ", "ubique ", "ridens ", "voluptaria ", "his, ", "in ", "augue ", "debet ", "facilisi ", "duo. ", ...
<inst esc> "Please rate the text on the scale below:",
 
<inst esc> "1----2----3----4----5" <line 3>,  
<inst esc> "dislike neutral like " <line 4> *
<mwc +#2,-9101 +#3,-9102 +#4,-9103 +#5,-9104 +#6,-9105 cinr,-9106>;

 
 
So first up are our six stub subroutines that will be used to decipher which of the five positive responses was made when we prompt for a rating on our 5 point scale (the sixth is to handle no response being made): 
 
~1 <dfd 32> <bu 1>;
9101 <delay 2> <emit rated 1> "1--------------------" @3 / <return>; 
9102 <delay 2> <emit rated 2> "-----2---------------" @3 / <return>; 
9103 <delay 2> <emit rated 3> "----------3----------" @3 / <return>; 
9104 <delay 2> <emit rated 4> "---------------4-----" @3 / <return>; 
9105 <delay 2> <emit rated 5> "--------------------5" @3 / <return>; 
9106 <delay 2> <emit no rating> "No Response" @3 / <return>; 
~1;
 
You'll notice that the pair of item 1s is used to make DMDX branch over these stubs when it executes the item file as we only want these to be called from our rating item. 
 
I also changed the default display duration to 32 tics (the usual feedback duration) with
<dfd 32> otherwise the feedback disappearing in the 10 tics of the default frame duration of this item file is a little ineffective.

 
 
9105 <delay 2> <emit rated 5> "--------------------5" @3 / <return>; 
 
Because we're not gathering responses in these items similar to an instruction we've removed the + or - CR indicator. We've also tossed a <delay 2> in there so the feedback happens as quickly as possible after the rating keypress, without it it's a bit disjointed with the default delay in an item's display being 48 tics or about 800 ms on most machines.  
 
Next up because we're no longer generating a
<zil> data file our item file will be responsible for distinguishing which of the five ratings were made and for that we emit the text relevant to a particular rating into the data file. A quick note about <emit> and that is you can't use something like <emit 1> for rating one as emit's primary purpose is to emit a counter's value so putting <emit 1> in there will generate an error complaining about the use of an uninitialized counter, oops...

 
 
Whereas the output .ZIL data file from our previous example will have data in it like this (assuming we responded 2 1 3):
 
Item 601, 2695.24 2695.24,+#3
Item 602, 320.48 320.48,+#2
Item 603, 364.44 364.44,+#4
 
Our .AZK data file will have data in it like this with our emitted data in comments (assuming we responded the same way):
 
611 1090.41
! rated 2
612 907.40
! rated 1
613 365.57
! rated 3

 
 
Back to our .AZK rating item file: 
 
9105 <delay 2> <emit rated 5> "--------------------5" @3 / <return>; 
 
Lastly we have a <return> that returns control to the item that follows the one that called that item.  
 
After that there are instructions like the
<zil> <zor> rating example that also sets some things up: 
 
0 "Some instructions" <t 15000> <nfb> <umnr> <umpr> <mpr +#2> <mpr +#3> <mpr +#4> <mpr +#5> <mpr +#6> ;
 
Only difference here is we're turning feedback off this time with <nfb> because we'll be generating that ourselves.

 
 
+601 <inst .1, .1, .92 hardmargin> "Lorem ", "ipsum ", "dolor ", "sit ", "amet, ", "ne ", "ubique ", "ridens ", "voluptaria ", "his, ", "in ", "augue ", "debet ", "facilisi ", "duo. ", ...
<inst esc> "Please rate the text on the scale below:",
 
<inst esc> "1----2----3----4----5" <line 3>,  
<inst esc> "dislike neutral like " <line 4> *
<mwc +#2,-9101 +#3,-9102 +#4,-9103 +#5,-9104 +#6,-9105 cinr,-9106>; 
 
Similar to the <zil> <zor> rating task the only difference in our data gathering item is our multiway call <mwc> where we're feeding it signal names and item numbers it should call if that key was hit with the exception of the last pair that's using the call if no response keyword cinr to catch the last possible case. The item numbers are negative because we're telling DMDX to go look for those items before the item that's calling them, you could leave the sign out and DMDX would just take a little longer to process the call.

 
 
DMDX can also use touchscreens instead of the mouse in the earlier Stroop example using <2did windowstouch>, see "2Did windowstouch.rtf" in the demos: 
 
http://psy1.psych.arizona.edu/~jforster/dmdx/demos.zip  
 
Additionally it can use the mouse as a continuous rating device should you wish to gather ratings on video clips as detailed in the
<2did> help as well as demoed in dvRatingsDialdemo.rtf in the digital video demo: 
 
http://psy1.psych.arizona.edu/~jforster/dmdx/DVDEMO.ZIP  
 
DMDX can also collect typed responses using a modification of the zillion input mode called zillion typed responses invoked with
<ztr> for simple Roman characters or the more sophisticated <prose> should you need to use an .AZK data file that's good for gathering multiple typed words that should work in an international setting with the right sort of local fonts in the item file that includes the ability to back space and edit text across multiple lines. While I won't get into <prose> here (it's detailed in the help) given the local font concerns in international situations (meaning I suspect I'd have trouble building an item file that worked properly in all situations for a demo) <ztr> offers us the occasion to get a little bit deeper into counters and expressions.

 
 
More Complex Counter Section


 
 
For a typing task free from international non-roman character set considerations it occurred to me that I could demo the Subtract 7 task I set up years ago where the idea is to stress a subject out by making them have to subtract 7 from a given number repeatedly. Here we can use the zillion typed response <ztr> mode and only worry about numeric keys (be they on the main keyboard or the numeric keypad) and use some counters and branching for a nice introduction to procedural item files as well. 
 
Usually one would be validating keys for a
<zil> job but <ztr> is a little special in that it validates the roman characters and numeric keys as well as the numeric keypad keys on both the keyboard device and more relevant to us, the #keyboard international device as well so we don't need to worry about <vzk> -- unless of course we have to invalidate the roman keys because we only want numeric keys available, however I'm not going there as that's at least 24 keys of invalidating and it would be easier just to invalidate all the keys with <izk> and then validate just the numeric ones and the Subtract 7 task is supposed to be a stressor anyway so fat fingering stuff can just cause a bit more stress…

 
 
So the additions to our parameter line are <zil> <ztr> <ntl> <fbocb> <zekn +#156> <zekn +#28> where <zil> gets us the zillion response mode, <ztr> gets us the zillion typing mode, <ntl> turns on DMDX's no time limit mode (a little more elegant that just setting the time limit to a really big value), <fbocb> that stops feedback from clearing the whole screen and has it only clearing behind the feedback when it's active (not that we're using feedback per se in the classic DMDX sense however <ztr> uses the feedback mechanism to display the typed characters) so our subtract seven prompt can remain on the screen and lastly <zekn +#156> <zekn +#28> that allows people to use the numeric keypad enter key as well as the main one if they so desire. 
 
Speaking of things staying on the screen I will point out that our Subtract 7 task only keeps it's prompt on the screen for a single iteration or until an error is made (so they have to keep the number to subtract 7 from their mind, a much more difficult and stressful task) which makes it's structure a little more complicated as we'll need one loop that prompts the subject and keeps prompting them if they get it wrong and another that doesn't prompt them once they get it right and keeps on not prompting them till they get it wrong again.

 
 
0 "Subtract 7" <randomize> <set c1 = 777 + (random 223)> <mpr +#28> <mpr +#156>; 
~1 <set c2 = millisectime + 30000>; 
~100 <bi 999, c1 .lt. 7>; 
~1 <bi 999, millisectime .gt. c2>; 
+101 * "Subtract 7 from " <appendcounter 1>; 
~1 <set c1 = c1 - 7> <bi 200, c1 .eq. atoizilliontext>; 
~102 ; 
0 <delay 2> <ln -1> "Wrong." , "The correct answer is " <apc 1> <bu 100>; 
~200 <bi 999, c1 .lt. 7>; 
~1 <bi 999, millisectime .gt. c2>; 
+201 *; 
~1 <set c1 = c1 - 7> <bi 102, c1 .ne. atoizilliontext>; 
~1 <bi 200, lastrt .le. 4000>; 
1 <msfd 1000> "Please try and respond quicker" / <bu 200>; 
999 "Time's up!"; 
 
So here for the first time our DMDX item file is starting to look like a real program as all those items with the tilde skip display CR indicator are tests and branches implementing our task.

 
 
0 "Subtract 7" <randomize> <set c1 = 777 + (random 223)> <mpr +#28> <mpr +#156>; 
 
In our initial instruction we're randomizing the random number generator (otherwise it would feed us the same sequence every time) and we're setting counter number 1 to 777 plus some random number between zero and 222 so that each subject gets to do a slightly different task or (God forbid) they have to do it a second time. This counter is going to be the target number they have to type in for each iteration of our task. We've also added the enter keys as a positive responses so we can see how long they were typing for and ask them to speed it up if they're too slow. 
 
~1 <set c2 = millisectime + 30000>; 
 
In our first purely procedural item we setting a second counter up to be the time limit in the task. As demonstrated previously expressions in DMDX have a number of special tokens, we'll be using a few here and the first one is the millisecond time at the time that expression was evaluated. Because I'm not a sadist I'm only exposing you to a 30 second task (from the time you dismiss the initial instruction), usually this would be a 5 minute task and that 30000 would be 300000.

 
 
~100 <bi 999, c1 .lt. 7>; 
~1 <bi 999, millisectime .gt. c2>; 
 
Item 100 is the start of our bifurcated loop fetching numbers from the subject and there will be branches back to this item from later in the task. Next we have the branch if <bi> keyword where DMDX takes a target item number and an expression and if the expression is true (non-zero) at item parse time it will take the branch to that item number. While DMDX has a number of different branching keywords they were added before <bi> was and these days almost all of my general purpose branching is done with <bi> because it is so much more flexible -- for instance in addition to the usual arithmetic operators you have the logical operators .LT., .GT., .LE., .GE. (less than, greater than, less than or equal to and greater than or equal to), .EQ., .NE., (equal to and not equal to), .AND. (logical AND) and last but not least .OR. (logical OR, see the <SetCounter> documentation for full list of the operators and their associativity). However what the original branches lack in flexibility they make up for in utility because they are evaluated after the subject has a made a response making them very useful if you're going to have decisions made on the subject's response in every item as opposed to a subroutine, whereas here with <bi> it's evaluated at item parse time before the display and response. With a skip display CR indicator in a subroutine the difference is moot but without it unawareness of that difference can be maddening. For reference the original branches are branch if counter less than or equal <bicLE>, branch if counter greater than <bicGT>, branch if correct <bic>, branch if wrong <biw>, branch if no response <binr> and the branches on error rate <bierLE> and <bierGT>.

 
 
Back to our example at hand: 
 
~100 <bi 999, c1 .lt. 7>; 
~1 <bi 999, millisectime .gt. c2>; 
 
Here we're checking if (a) we've run out numbers for them to type by checking if counter 1 is less than seven and (b) if time has expired and we should bail out of the task (item 999 being the end of it). 
 
+101 * "Subtract 7 from " <appendcounter 1>; 
 
Speaking of bifurcation this first part of our loop is the part that actually prompts the subject, the later part that starts at item 200 is the other half that doesn't prompt them.  
 
Here we're turning the clock on with the legacy asterisk switch and gathering a response, it being a
<zil> task all the keystrokes hit here will be saved into the data file but we don't care about that because we've got <ztr> turned on and are only interested in it's interpretation of those keystrokes (more on that in a bit). So item 101 has to prompt the subject for the number they're supposed to subtract seven from and it does that by using <appendcounter> and passing it counter 1 and it will add whatever text it is that represents that number to the end of the text in the frame <appendcounter> occurs in.

 
 
<ztr> tasks present the typed text on the feedback line (by default line 2, if we wanted another line we could change it with the feedback line keyword <fbl N>) and because we've specified feedback only clear behind with <fbocb> earlier on it's not erasing our prompt displaying the number to subtract 7 from.  
 
~1 <set c1 = c1 - 7> <bi 200, c1 .eq. atoizilliontext>; 
 
Following item 101 that gets the input (terminated by the enter key) we have another procedural item that subtracts seven from counter 1 and then branches to the other half of our bifurcated loop (item 200) that won't prompt the subject if they got it right by testing whether the new value of counter 1 is equal to the second of our special expression tokens we'll be using in this task, atoizilliontext which is as you can guess the numeric value of the most recently typed in <zil> input (atoi being a classic C routine that converts an ASCII string to an integer).

 
 
~102 ; 
0 <delay 2> <ln -1> "Wrong." , "The correct answer is " <apc 1> <bu 100>; 
 
After that we have a stub item 102 that's a landing point for the second half of our bifurcated loop when the subject types the wrong number in. In addition if they got the number wrong in item 101 DMDX will fall through to this instruction as well informing the user they got it wrong and telling them the right number and then branching back to the first half of our bifurcated loop at item 100 that will prompt them for the next number in the series.

 
 
~200 <bi 999, c1 .lt. 7>; 
~1 <bi 999, millisectime .gt. c2>; 
+201 *; 
~1 <set c1 = c1 - 7> <bi 102, c1 .ne. atoizilliontext>; 
~1 <bi 200, lastrt .le. 4000>; 
1 <msfd 1000> "Please try and respond quicker" / <bu 200>; 
999 "Time's up!"; 
 
Lastly we have the second half of our bifurcated loop that has the same logic in it as the first half only it's the unprompted version of it that when they get it wrong branches back to item 102 in the first prompted half of the task. What is different is that we've got extra logic that checks the overall typing time. Because we've got the enter key mapped as a positive response it's the only response the standard DMDX response logic will see and so the lastrt token in an expression will have the total typing time in it and we can test if that's less than four seconds and if not flash up a respond quicker message for a second. 
 
For your added convenience I've added logic to the task (not shown) that picks up you hitting the left shift key as a negative response to abort the task rather than make you sit through the whole 30 seconds unless you really want to.

 
 
Subtract 7

 
 
Aborted

 
 
There is one more keyword that's worth talking about at this point and that's the <BranchDiagnostics> keyword. While developing a branching item file figuring just what hit the fan when can be a bit of a problem, turning the branch diagnostics on takes much of the guesswork out of it -- not all of it but as much as I reasonably can. With this you can activate pretty extensive diagnostic spew in your data file (be it a .ZIL file or an .AZK one) and additionally the diagnostic data can be copied out of DMDX using the Copy button on the run dialog (it's also available in the diagnostics.txt file that's usually in your temporary directory) that also contains the DMDX dialog messages so you can actually see which item is executed (as long as it's not a skip display item). Whenever a branch is taken or considered or a counter or macro is modified a comment about it will be spewed. In addition when counters are referenced in an expression their value is also spewed. 
 
I would note you probably want to turn the diagnostics off once you get the item file working, I usually leave the keyword in the file in case I ever have to turn them back on but just put a
! at the start of the keyword like this <!BranchDiagnostics> to make it a keyword comment -- or you could just turn branch diagnostics off with <BranchDiagnostics 0> (<BranchDiagnostics> is equivalent to <BranchDiagnostics 1> which applies to all keywords so <nfb 0> turns off no feedback for instance so feedback is no longer suppressed).

 
 
In the following displays I've included a run through this Subtract 7 task, where I've answered correctly within the time limit twice and again a third time however I take too long and it nags me to speed up and then I respond again where I've answered incorrectly so am prompted by item 101 to enter the last one which I get correct but then have been timed out for the end of the task. First up is the (somewhat edited) contents of diagnostics.txt, after that will be the .ZIL file. 
 
DMDX is running in auto mode (automatically determined raster sync) 
D3D Video Mode 1920,1080,24,59 
Item File <introduction4.rtf> 
EXPERIMENT READY 
Preparation A 0.02ms, B 0.00ms 
0 <BranchDiagnostics> "Subtract 7" <randomize> <set c1 = 777 + (random 223)> <mpr +#28> <mpr +#156>; 
Counter 1 has value 984 
Preparation A 6.12ms, B 6.85ms 
~1 <set c2 = millisectime + 30000>; 
Counter 2 has value 45420 
~100 <bi 999, c1 .lt. 7>; 
Counter 1 referenced, has value 984 
BranchIf exp (0) to item 999 not taken 
~1 <bi 999, millisectime .gt. c2>; 
Counter 2 referenced, has value 45420 
BranchIf exp (0) to item 999 not taken 
+101 * "Subtract 7 from " <appendcounter 1>;
The initial prompted input request 
Item 101 RT 6286.32 -- Error Rate 0% 
Preparation A 5.40ms, B 1.86ms 
~1 <set c1 = c1 - 7> <bi 200, c1 .eq. atoizilliontext>; 
Counter 1 referenced, has value 984 
Counter 1 has value 977 
Counter 1 referenced, has value 977 
BranchIf exp (1) to item 200 taken 
~200 <bi 999, c1 .lt. 7>; 
Counter 1 referenced, has value 977 
BranchIf exp (0) to item 999 not taken

 
 
~1 <bi 999, millisectime .gt. c2>; 
Counter 2 referenced, has value 45420 
BranchIf exp (0) to item 999 not taken 
+201 *;
The first unprompted input request 
Item 201 RT 3051.90 -- Error Rate 0% 
Preparation A 1.45ms, B 0.21ms 
~1 <set c1 = c1 - 7> <bi 102, c1 .ne. atoizilliontext>; 
Counter 1 referenced, has value 977 
Counter 1 has value 970 
Counter 1 referenced, has value 970 
BranchIf exp (0) to item 102 not taken 
~1 <bi 200, lastrt .le. 4000>; 
BranchIf exp (1) to item 200 taken 
Using buffered location for branch to item 200 after not finding it forwards 
~200 <bi 999, c1 .lt. 7>; 
Counter 1 referenced, has value 970 
BranchIf exp (0) to item 999 not taken 
~1 <bi 999, millisectime .gt. c2>; 
Counter 2 referenced, has value 45420 
BranchIf exp (0) to item 999 not taken 
+201 *;
The second unprompted input request that I take too long on 
Item 201 RT 6723.35 -- Error Rate 0% 
Preparation A 1.43ms, B 0.07ms 
~1 <set c1 = c1 - 7> <bi 102, c1 .ne. atoizilliontext>; 
Counter 1 referenced, has value 970 
Counter 1 has value 963 
Counter 1 referenced, has value 963 
BranchIf exp (0) to item 102 not taken 
~1 <bi 200, lastrt .le. 4000>; 
BranchIf exp (0) to item 200 not taken 
1 <msfd 1000> "Please try and respond quicker" / <bu 200>; 
Preparation A 1.44ms, B 1.03ms 
Unconditional branch to item 200 
Using buffered location for branch to item 200 after not finding it forwards 
~200 <bi 999, c1 .lt. 7>; 
Counter 1 referenced, has value 963 
BranchIf exp (0) to item 999 not taken 
~1 <bi 999, millisectime .gt. c2>; 
Counter 2 referenced, has value 45420 
BranchIf exp (0) to item 999 not taken

 
 
+201 *;
The third unprompted input request that I get wrong 
Item 201 RT 5707.61 -- Error Rate 0% 
Preparation A 1.42ms, B 0.03ms 
~1 <set c1 = c1 - 7> <bi 102, c1 .ne. atoizilliontext>; 
Counter 1 referenced, has value 963 
Counter 1 has value 956 
Counter 1 referenced, has value 956 
BranchIf exp (1) to item 102 taken 
Using buffered location for branch to item 102 after not finding it forwards 
~102 ; 
0 <delay 2> <ln -1> "Wrong." , "The correct answer is " <appendcounter 1> <bu 100>; 
Preparation A 1.44ms, B 1.64ms 
Unconditional branch to item 100 
Using buffered location for branch to item 100 after not finding it forwards 
~100 <bi 999, c1 .lt. 7>; 
Counter 1 referenced, has value 956 
BranchIf exp (0) to item 999 not taken 
~1 <bi 999, millisectime .gt. c2>; 
Counter 2 referenced, has value 45420 
BranchIf exp (0) to item 999 not taken 
+101 * "Subtract 7 from " <appendcounter 1>;
Having got the last one wrong we switch back to prompted input 
Item 101 RT 3635.90 -- Error Rate 0% 
Preparation A 4.70ms, B 1.73ms 
~1 <set c1 = c1 - 7> <bi 200, c1 .eq. atoizilliontext>; 
Counter 1 referenced, has value 956 
Counter 1 has value 949 
Counter 1 referenced, has value 949 
BranchIf exp (1) to item 200 taken 
~200 <bi 999, c1 .lt. 7>; 
Counter 1 referenced, has value 949 
BranchIf exp (0) to item 999 not taken 
~1 <bi 999, millisectime .gt. c2>;
And now we've taken more than 30 seconds so we bomb out 
Counter 2 referenced, has value 45420 
BranchIf exp (1) to item 999 taken 
~999; 
0 "Time's up!"; 
Preparation A 1.82ms, B 0.76ms

 
 
And here is the .ZIL data file from that run:  
 
! DMDX is running in auto mode (automatically determined raster sync) 
! D3D Video Mode 1920,1080,24,59 
! Item File <D:\dx5\DMDX\introduction4.rtf> 
! Counter 1 has value 984 
! Counter 2 has value 45420 
! Counter 1 referenced, has value 984 
! BranchIf exp (0) to item 999 not taken 
! Counter 2 referenced, has value 45420 
! BranchIf exp (0) to item 999 not taken 
Item 101, (977) 3504.37,+#73 4290.32,+#71 5530.36,+#71 6286.32,+#28
The initial prompted input request 
! Counter 1 referenced, has value 984 
! Counter 1 has value 977 
! Counter 1 referenced, has value 977 
! BranchIf exp (1) to item 200 taken 
! Counter 1 referenced, has value 977 
! BranchIf exp (0) to item 999 not taken 
! Counter 2 referenced, has value 45420 
! BranchIf exp (0) to item 999 not taken 
Item 201, (970) 1557.88,+#73 1804.22,+#71 2163.89,+#82 3051.90,+#156
The first unprompted input request 
! Counter 1 referenced, has value 977 
! Counter 1 has value 970 
! Counter 1 referenced, has value 970 
! BranchIf exp (0) to item 102 not taken 
! BranchIf exp (1) to item 200 taken 
! Using buffered location for branch to item 200 after not finding it forwards 
! Counter 1 referenced, has value 970 
! BranchIf exp (0) to item 999 not taken 
! Counter 2 referenced, has value 45420 
! BranchIf exp (0) to item 999 not taken

 
 
Item 201, (963) 2337.26,+#73 3173.31,+#77 4185.27,+#81 6723.35,+#156
The second unprompted input request 
! Counter 1 referenced, has value 970 
! Counter 1 has value 963 
! Counter 1 referenced, has value 963 
! BranchIf exp (0) to item 102 not taken 
! BranchIf exp (0) to item 200 not taken 
! Unconditional branch to item 200 
! Using buffered location for branch to item 200 after not finding it forwards 
! Counter 1 referenced, has value 963 
! BranchIf exp (0) to item 999 not taken 
! Counter 2 referenced, has value 45420 
! BranchIf exp (0) to item 999 not taken 
Item 201, (955) 4309.27,+#73 4639.29,+#76 4793.29,+#76 5707.61,+#156
The third unprompted input request that I get wrong 
! Counter 1 referenced, has value 963 
! Counter 1 has value 956 
! Counter 1 referenced, has value 956 
! BranchIf exp (1) to item 102 taken 
! Using buffered location for branch to item 102 after not finding it forwards 
! Unconditional branch to item 100 
! Using buffered location for branch to item 100 after not finding it forwards 
! Counter 1 referenced, has value 956 
! BranchIf exp (0) to item 999 not taken 
! Counter 2 referenced, has value 45420 
! BranchIf exp (0) to item 999 not taken 
Item 101, (949) 1537.88,+#73 2017.82,+#75 2535.99,+#73 3635.90,+#156
Having got the last one wrong we switch back to prompted input 
! Counter 1 referenced, has value 956 
! Counter 1 has value 949 
! Counter 1 referenced, has value 949 
! BranchIf exp (1) to item 200 taken 
! Counter 1 referenced, has value 949 
! BranchIf exp (0) to item 999 not taken 
! Counter 2 referenced, has value 45420
And now we've taken more than 30 seconds so we bomb out 
! BranchIf exp (1) to item 999 taken

 
 


 
 
Macro Section


 
 
The final frontier of DMDX scripting is the use of macros. Here you can assign a text string to a token and have it expand at a later date in the item file with <macro token string>. The token comes in one of two forms, it's either a legacy single character (so <macro t string> for instance) or it's a dot delimited string itself that's 40 characters or less in length (so <macro .token. string>). To invoke the macro and have it expand to it's string value it's token is preceded by a tilde (so ~t or ~.token.).
 
There are all sorts of limitations, confounds and commands that I'm not going to try and enumerate here, instead you can dig them out of the macro section in the help. The big thing to bear in mind with macros is that you can't define a macro in the same item that it's expanded in as the definition is parsed after the expansion is done when the item is read. Seeing as that's something I almost always forget and get tripped up by I put a warning in the syntax check about the use and definition of a macro in the same item. Of course the times I'm not forgetting about it I actually want to modify a macro in the same item it's defined in (as in the cases where I want to redefine a macro in terms of it's prior value say) so there's a macro command to stop the syntax check warnings about it and it is
<macro yikwid> (Yes I Know What I'm Doing).

 
 
Another point about macros is that you can't put a keyword in a keyword so if you're looking to have keywords expand in a macro you'll have to use the old DMTG version of a macro definition and for that reason that tends to be the way I almost always use macros. The original DMTG switch based definition syntax is MtDstringD where t is the token and D is some arbitrary delimiter character that you choose that isn't in the string you want expanded (typically I'll use a plus sign). That token can be either a single character or the dot delimited version as in M.token.DstringD.  
 
There are countless things macros are useful for, not the least of which is bypassing DMDX's limitations (say a keyword that doesn't take a counter for a parameter -- more on this later) to iterating over counters, the sky's the limit. Here we're going to use macros and scrambling to expand the earlier positioning example to randomly move the corner stimuli around and we're going to use shapes instead of numbers and the task will be to decide if the outlined character in the middle occurred in the corners. 
 
The way we're going to do it is by having four macros for the corners and we're going to scramble the content items around them with a
<scramble 1> in the parameters and some judicious dollars signs pinning down the items that need to be fixed in place.

 
 
$~1 mO+.tl.+;$ 
~1 m~O+ "
" <emit square> +; 
$~1 mO+.tr.+;$ 
~1 m~O+ "
" <emit circle> +; 
$~1 mO+.bl.+;$ 
~1 m~O+ "
" <emit triangle> +; 
$~1 mO+.br.+;$ 
~1 m~O+ "◆" <emit diamond> +; 
$-1001 <msfd 1500> "++" <xy .5, .5> / <dfm 4 stat> ~.tl. <xy .25, .25> , ~.tr. <xy .75, .25> , ~.bl. <xy .25, .75> , ~.br. <xy .75, .75>, "
" <xy .5, .5> * / <dfm 1> ;$ 

 
The item 1s surrounded by dollars are fixed blocks that set up which macro the following item will define by setting macro O to the token name for each corner (Top Left, Top Right etc) and the scramble shuffles those other items around them so that any given shape will wind up in any given corner. Additionally our corner macros also emit the name of the shape that went in that corner so the data file will have a record of which shape went where -- not so relevant for this example but the original this example came from has many more corner displays shuffled across many presentations, here we've got a back slash after each set so they don't intermix which is why we're going to have a multi-scramble demonstration following this...

 
 
So as noted our RT gathering item order is going to remain fixed and that's not a good thing so we enter the dreaded world of multi-scrambling where you can pass an item file through the scramble routines any number of times as long as you're smart enough to figure out how to get the later scramble parameters to stay where you want them after the earlier passes through scramble. We're going to want a first scramble that does everything our existing scramble does and then a second scramble with a grouping factor of 9 to change the relative order of the RT gathering items with these additions to the parameter line <mss 1,1> <mss 2,1> <msg 2,9>. First off we have <mss 1,1> that tells the multi-scramble routines that on iteration one the scramble block size should be one, then we have <mss 2,1> that similarly indicates that the second scramble should also have a block size of one and lastly we have <msg 2,9> that specifies the grouping factor for the second scramble should be nine.
 
We'll be replacing the dollar delimiters with
<ms# 1> which means on iteration one of our multi-scramble those keywords will become $ symbols, likewise we'll be replacing the back slashes with <ms\ 1> as on iteration one we just want to mix up the corner resources to build the next 1000 series RT gathering item. Fortunately for us our second iteration of the multi-scramble is about as straight forward as multi-scrambling gets because it's just a grouping factor, no need for extra keywords to do "interesting" things, all we'd have to do is nest our instructions in pairs of fixed block delimiters like this to make sure they don't move in either iteration one or iteration two of the multi-scramble:
 
<ms# 1> <ms# 2> 0 "Instructions";<ms# 2> <ms# 1>

 
 
And this is what our macro controlled corner shuffling set of items winds up looking like with multi-scramble keywords in it: 
 
<ms# 1> ~1 mO+.tl.+;<ms# 1> 
~1 m~O+ "
" <emit square> +; 
<ms# 1> ~1 mO+.tr.+;<ms# 1> 
~1 m~O+ "
" <emit circle> +; 
<ms# 1> ~1 mO+.bl.+;<ms# 1> 
~1 m~O+ "
" <emit triangle> +; 
<ms# 1> ~1 mO+.br.+;<ms# 1> 
~1 m~O+ "◆" <emit diamond> +; 
<ms# 1> -1101 <msfd 1500> "++" <xy .5, .5> / <dfm 4 stat> ~.tl. <xy .25, .25> , ~.tr. <xy .75, .25> , ~.bl. <xy .25, .75> , ~.br. <xy .75, .75>, "
" <xy .5, .5> * / <dfm 1> ;<ms# 1> 
<ms\ 1>

 
 


 
 
Indexed Branching Section


 
 
Another thing that becomes possible with macros is selecting elements from a list for, say, a faux Ultimatum task, albeit with the use of indexed branching. Here one sets up a list of items that set a macro to some value and then use an indexed branch into that list to select just one element. The list can be scrambled if you need to select every one of them in random order or more simply a random number can be used to select one randomly with the caveat that not all elements are guaranteed to be used and that there's no control on how many times one of those elements may be reused. 
 
In the original Ultimatum task all the offers were kept in a list and then each offer was selected from it after it was scrambled, that example is in the help (google
"DMDX dynamic item content" and click the Ultimatum Game link) so we're not going to go into that here. Instead we'll present our simplified Ultimatum task that just keeps upping the tally till you decline an offer. 
 
~1 <bu 6998>; 
~6999 <macro set o = ((random 10) + 1) * 2> <set c1 = (random 4) + 6900> <ib c1>; 
~6900 <macro m Bob> <return>; 
~6901 <macro m Jim> <return>; 
~6902 <macro m Sue> <return>; 
~6903 <macro m Mary> <return>; 
~6998 <nfb> <set c2 = 0> <call -6999>; 
~1 <bu 6801>; 
~6800 <set c2 = c2 + (~o / 2)> <call -6999>; 
+6801 <line -5> "You have $" <apc c2>, <line -1> "~m offers $~o", <line 1> "Do you accept it?" * <bic -6800>;

 
 
~6999 <macro set o = ((random 10) + 1) * 2> <set c1 = (random 4) + 6900> <ib c1>; 
~6900 <macro m Bob> <return>; 
~6901 <macro m Jim> <return>; 
~6902 <macro m Sue> <return>; 
~6903 <macro m Mary> <return>; 
 
Here in the heart of our faux Ultimatum task we have a subroutine to both come up with an offer amount and a name of a sham conspirator to offer it. The first half of item 6999 sets macro O to the characters that represent an offer from $2 through $20 (I'm cheating by keeping offers even so then when the offer is split we don't have to deal with fractions of a dollar) with <macro set o = ((random 10) + 1) * 2>. After that an indexed branch jumps to one of the next four items that set macro M to some name. An indexed branch takes a counter and branches to the item that matches that counter's value so the first of our name element items is 6900 so we take 6900 plus some random number between zero and three and that selects for one of our four name selection items with <set c1 = (random 4) + 6900>. After that the indexed branch itself uses counter 1 as it's destination with <ib c1>.

 
 
~6998 <nfb> <set c2 = 0> <call -6999>; 
~1 <bu 6801>; 
~6800 <set c2 = c2 + (~o / 2)> <call -6999>; 
+6801 <line -5> "You have $" <apc c2>, <line -1> "~m offers $~o", <line 1> "Do you accept it?" * <bic -6800>; 
 
Following the subroutine we have our somewhat convoluted offer logic, convoluted because we want to have the subject start off with a balance of zero and would also like to have the branch if correct keyword <bic -6800> loop around and detect both the end of our example and not have to have another item following that updating the subject's balance. The interesting and different thing here is that we're using macros inside a text segment with "~m offers $~o" so when we defined them earlier we didn't put double quotes around them (not to mention the fact that doing so would screw up our balance updater <set c2 = c2 + (~o / 2)>), worse this item file is a Unicode one and may in fact be the first file to ever use Unicode macros in a text segment -- fortunately it appears to work so we're all good, all that hard work I put into that logic pays off, yay! The trick with using macros in a text segment is that Word (in particular) will put RTF control words in between the tilde ~ and the macro name if you edit it after having typed it and that will stop DMDX's macro code from seeing your macro definition -- even if it looks good to your eye (the macro code is at too lower level to strip RTF codes and I'm not really willing to try and design logic to handle it). Instead if you notice a macro being ignored in a text segment you can either re-type it or pour your item file through WordPad which will strip out the Word stupidities.

 
 
Continue Clock On Section


 
 
As mentioned earlier macros are a convenient way of getting around some of the limitations DMDX has. For instance while a number of keywords take counters for parameters most of them do not and while I could add a ton of code to DMDX to parse for counters everywhere for the few instances that exist where it's actually needed using macros to get around the limitation is pretty painless these days. 
 
In order to demonstrate this I thought I'd have a display gradually changing colors and as I was building it I rapidly realized a smoothly changing thing was about five times more complex than I needed and cut it back to this one that has the occasional discontinuity (hopefully infrequently enough to not induce epilepsy in anyone) but it's only about three times more complex than needed… 
 
So what we're going to do is setup a bunch of macros for the RGB values to plug into a background color
<bgc> keyword and a writing color <wc> keyword and a bunch of random deltas for those values and then loop around like crazy updating the display till a response is made. All in all 13 macros when 2 would have done but it's more interesting this way so what the hell.

 
 
~1 mc+<co>+ <t 20> <mpr +#57> <nfb> <macro yikwid> 
<md .wcR. 255> <md .wcG. 255> <md .wcB. 96> 
<md .bgR. 32> <md .bgG. 64> <md .bgB. 128> 
<macro set .wcRd. = (random 9) - 4> 
<macro set .wcGd. = (random 9) - 4> 
<macro set .wcBd. = (random 9) - 4> 
<macro set .bgRd. = (random 9) - 4> 
<macro set .bgGd. = (random 9) - 4> 
<macro set .bgBd. = (random 9) - 4> <xyjustification center>; 
+2 <delay 2> <wc ~.wcR., ~.wcG., ~.wcB.> <bgc ~.bgR., ~.bgG., ~.bgB.>  
<fm 6> "
DMDX" ~c <xy .5, .5> 
<macro set .wcR. = (~.wcR. + ~.wcRd.) & 255> 
<macro set .wcG. = (~.wcG. + ~.wcGd.) & 255> 
<macro set .wcB. = (~.wcB. + ~.wcBd.) & 255> 
<macro set .bgR. = (~.bgR. + ~.bgRd.) & 255> 
<macro set .bgG. = (~.bgG. + ~.bgGd.) & 255> 
<macro set .bgB. = (~.bgB. + ~.bgBd.) & 255> 
mc+<cco>+ <binr -2>; 
 
Here I've used a mix of legacy single character macro names (c for the clock on) and more readable ones to distinguish Writing Color from BackGround and the RGB values and Deltas for those.

 
 
~1 mc+<co>+ <t 20> <mpr +#57> <nfb> <macro yikwid> 
<md .wcR. 255> <md .wcG. 255> <md .wcB. 96> 
<md .bgR. 32> <md .bgG. 64> <md .bgB. 128> 
 
In the first half of our setup item because we're going to use the continue clock on capability <cco> that will catch any keystrokes made between items that might otherwise get missed and because you can't start with <cco> we're using macro c to flip from <co> (the keyword version of the * switch) initially to <cco> for the rest of the executions.  
 
We set an nice low time limit so the colors will change with some alacrity (because we're using
<cco> we don't have to worry about giving the subject a reasonable window to respond in as we'll catch the keystroke no matter when it's hit). We've also mapped the space bar as a positive response so you can dismiss the display as if it was an instruction. You'll notice that later on we're setting macros in the same item as we're using them so we're using <macro yikwid> to suppress the syntax warnings. 
 
After that we set up three macros for the writing color RGB values and three more for the background that match the colors of the display.

 
 
<macro set .wcRd. = (random 9) - 4> 
<macro set .wcGd. = (random 9) - 4> 
<macro set .wcBd. = (random 9) - 4> 
<macro set .bgRd. = (random 9) - 4> 
<macro set .bgGd. = (random 9) - 4> 
<macro set .bgBd. = (random 9) - 4> <xyjustification center>; 
 
In the second half of our setup item we setup some random deltas for the various RGB values we set up just beforehand with <macro set>. Here a macro instead of being set to a string what's on the right of the equals sign is passed to DMDX's expression evaluator (see the Set Counter help) and then the result is converted to an ASCII string and assigned to that macro. There are some foibles with that expression evaluator, I've looked at it long and hard (I didn't write it, Bob Brodt did in 1985) and one particular part of it is irremediable, other things I've fixed. Fortunately the worst of it is it's functions where the syntax isn't func(value) like almost every other place in the universe, instead it's (func value). I suspect some of it's associativity is also suspect so I tend to bracket almost everything whenever there's the slightest doubt. Here we generate a random number between 0 and 8 and then subtract four from it to give us a -4 to 4 range (typical screens aren't going to see much finer color gradients than a delta of 4 but these sum across iterations so have cumulative effect unless the delta winds up being zero in which case it doesn't change, too bad, it doesn't affect our display unless by the wildest chances we wound up with six of them but I don't think pseudo random number generators are capable of such).

 
 
+2 <delay 2> <wc ~.wcR., ~.wcG., ~.wcB.> <bgc ~.bgR., ~.bgG., ~.bgB.>  
<fm 6> "
DMDX" ~c <xy .5, .5> 
<macro set .wcR. = (~.wcR. + ~.wcRd.) & 255> 
<macro set .wcG. = (~.wcG. + ~.wcGd.) & 255> 
<macro set .wcB. = (~.wcB. + ~.wcBd.) & 255> 
<macro set .bgR. = (~.bgR. + ~.bgRd.) & 255> 
<macro set .bgG. = (~.bgG. + ~.bgGd.) & 255> 
<macro set .bgB. = (~.bgB. + ~.bgBd.) & 255> 
mc+<cco>+ <binr -2>; 
 
Next we have our colorific item that sets a nice low delay to once again facilitate our animation and then we have our <wc> and <bgc> keywords taking their RGB values from the macros set up earlier. Following that we transform our RGB values by the deltas set up earlier so when it gets executed next time around the colors will be slightly different with the <macro set> keyword carefully using a binary "and" to keep the resulting value in the range 0..255 that is a valid RGB value. 
 
Last but far from least we're changing macro
c to be the continue clock on variant that will catch keystrokes made as DMDX is between items and then we're telling DMDX to branch if no response is made back to the most recent occurrence of item 2 because this item file uses <bb2mr> (not shown) that tells DMDX when branching backwards to branch to the most recent occurrence of an item, not the first occurrence (which is the default behavior coined when DMTG was written in the late eighties).

 
 
More for my own edification than anything else I went ahead and made a version of that that doesn't have the discontinuities when the gun values hit their limits and instead reverses the deltas and it turns out to be a nice demonstration of the power of macros combined with counters because we have to use counters for our gun values and deltas so we can have macros control a general routine to catch the guns going out of bounds (unless I'm being particularly obtuse I don't think there's a way to get a macro to select for another macro):
 
~1 mc+<co>+ <t 10> <mpr +#57> <nfb> <macro yikwid> 
<set c10 = 255> <set c11 = 255> <set c12 = 96> 
<set c13 = 32> <set c14 = 64> <set c15 = 128> 
<macro set .wcR. = c10> <macro set .wcG. = c11> <macro set .wcB. = c12> 
<macro set .bgR. = c13> <macro set .bgG. = c14> <macro set .bgB. = c15> 
<set c20 = (random 9) - 4> <set c21 = (random 9) - 4> <set c22 = (random 9) - 4> 
<set c23 = (random 9) - 4> <set c24 = (random 9) - 4> <set c25 = (random 9) - 4>  
<xyjustification center> <bu 2>; 
~8 <set c~.gv. = c~.gv. + c~.gd.>  
<bi 9, (c~.gv. .le. 255) .and. (c~.gv. .ge. 0)>; 
~1 <set c~.gd. = c~.gd. * -1> <set c~.gv. = c~.gv. + c~.gd.>; 
~9 <return>; 
+2 <delay 2> <wc ~.wcR., ~.wcG., ~.wcB.> <bgc ~.bgR., ~.bgG., ~.bgB.> <fm 6> "
DM " <xy .5, .5> , <wc ~.wcB., ~.wcR., ~.wcG.> <bgc ~.bgR., ~.bgG., ~.bgB.> <fm 6> " DX" ~c <xy .5, .5>; 
~3 <md .gv. 10> <md .gd. 20> <call -8>; 
~1 <macro set .wcR. = c10>; 
~1 <md .gv. 11> <md .gd. 21> <call -8>; 
~1 <macro set .wcG. = c11>; 
~1 <md .gv. 12> <md .gd. 22> <call -8>; 
~1 <macro set .wcB. = c12>; 
~1 <md .gv. 13> <md .gd. 23> <call -8>; 
~1 <macro set .bgR. = c13>; 
~1 <md .gv. 14> <md .gd. 24> <call -8>; 
~1 <macro set .bgG. = c14>; 
~1 <md .gv. 15> <md .gd. 25> <call -8>; 
~1 <macro set .bgB. = c15> mc+<cco>+ <binr -2>;

 
 
~8 <set c~.gv. = c~.gv. + c~.gd.>  
<bi 9, (c~.gv. .le. 255) .and. (c~.gv. .ge. 0)>; 
~1 <set c~.gd. = c~.gd. * -1> <set c~.gv. = c~.gv. + c~.gd.>; 
~9 <return>; 
 
Here you can see the juicy part of that program where we have a subroutine at item 8 that manipulates counters and which counters are manipulated is based on the contents of two macros, .gv. that selects the counter for the gun value and .gd. that selects for the gun delta value. It's called by the later item pairs starting at item 3: 
 
~3 <md .gv. 10> <md .gd. 20> <call -8>; 
~1 <macro set .wcR. = c10>; 
 
Each pair selects a gun value counter and gun delta counter, calls item 8 to iterate the gun value and reverse the delta if it runs out of bounds (and back the gun value back in bounds) and then sets our original gun value macro to the corresponding manipulated gun value counter so it can be passed to <wc> or <bgc> as our original pure macro version did, only this time I tarted it up a bit by making the DM and DX characters different colors: 
 
+2 <delay 2> <wc ~.wcR., ~.wcG., ~.wcB.> <bgc ~.bgR., ~.bgG., ~.bgB.> <fm 6> "DM " <xy .5, .5> , <wc ~.wcB., ~.wcR., ~.wcG.> <bgc ~.bgR., ~.bgG., ~.bgB.> <fm 6> " DX" ~c <xy .5, .5>;

 
 
+2 <delay 2> <wc ~.wcR., ~.wcG., ~.wcB.> <bgc ~.bgR., ~.bgG., ~.bgB.> <fm 6> "DM " <xy .5, .5> , <wc ~.wcB., ~.wcR., ~.wcG.> <bgc ~.bgR., ~.bgG., ~.bgB.> <fm 6> " DX" ~c <xy .5, .5>; 
 
Here I've got the gun values for DM mixed up for DX, the problem with wanting to have two colors used in one frame is that the only way you can do that is by using the RTF WYSIWYG features and coloring the individual letters as you please but of course doing that is incompatible with using <wc> so you have to split the different colored sections up into separate frames and merge them all together with commas and use spaces where the different colored letters appear and of course that only works with mono-spaced fonts and here I want the DX in Arial so I've had to fudge it a bit using three spaces, seems to line up nicely on my machines anyway...

 
 
Macros really crack open the door of what's possible with DMDX, in addition to what I've outlined here you can do things like treat a range of counters as an array and iterate over it (see the Iterating counters section in the macro documentation, there's also an older example in the Probabilistic Selection Task example in the Dynamic Item content section written before the <macro set> operation was done so it uses a subroutine to set a macro equal to a counter, <macro set> makes it much easier these days). On top that using the push and pop macro operations you can directly manipulate macros as strings (see the anagram task in the macro documentation). 
 
Of course once you're doing something as complicated as either of those examples one rapidly runs into the need to nest calls which is of course verboten unless you specifically allow it by telling DMDX to create a call stack with the
<callstack> parameter. I tend to only use just as much stack as I anticipate the item file needing (so if I only have one set of nested calls I'll only use <callstack 2>) so that if I forget a return or what have you DMDX will be able to throw an error clueing me in before too much hair gets lost. 
 
And always remember when all hell breaks loose and it's hit the fan turning the branch diagnostics on with
<branchdiagnostics> can really pull it out of the fire...

 
 
Test Mode Section


 
 
DMDX has several test modes built into it. This section is a little technical, if you want to just blow by it by hitting the space bar feel free. 
 
First up is the Display Test Mode (
<testmode 1>) where while waiting for a request DMDX displays the millisecond time, the count of video retraces, the refresh interval based on those two values and then a bunch of error values (more on them below) followed by an indication of whether the video raster is being tracked relentlessly or whether DMDX has geared back to relaxed tracking of it because the video drivers are failing to handle DMDX's relentless tracking. The error tracking values are pretty much only a concern if you see Critical Errors occurring, these days (especially with the Direct3D renderer) you can happily have a constant stream of Timed Out retraces. I would note that a lot of machines will toss a few Critical Errors as the item file starts executing and these can be ignored. 
 
To find out more see the TimeDX Time Video Mode discussion in the help. When you're done watching it hit the space bar.

 
 
Test Mode 1


 
 
Next up is the Millisecond Callback Latency test (<testmode 2>) where while waiting for a request DMDX displays a test screen with information about the millisecond callback latencies. Currently a particular routine, called millisec() should be called by the OS every millisecond, it is responsible for polling input devices and turning clocks on and dispatching sound event related tasks. With Win32 not being a real time OS this does not in fact occur at exact millisecond intervals, this test mode allows one to see exactly what latencies are involved. Obviously if you care about millisecond accurate RTs you're going to want to run DMDX on a machine where the SD of these latencies is well under a millisecond. 
 
When you're done watching it hit the space bar.

 
 
Test Mode 2


 
 
While there are a number of other test modes we're going to skip ahead to test mode 13, the Present() time test as the others either require external test hardware or are totally arcane and pretty much only used by me to ascertain how well the code is functioning. When DMDX is using the Direct3D rendering path and is waiting for a request and there is no active display it displays a test screen with information about the time the Direct3D function Present() took to setup the next frame's display. These times should never be more than a few milliseconds and if one is in the order of or longer than the refresh rate there should be a corresponding display error thrown. If used with the original DirectDraw rendering path times will be the time spent calling Flip() till it actually flipped the display. 
 
If you're really keen there are more test mode scripts here: 
 
http://psy1.psych.arizona.edu/~jforster/dmdx/testmodes/ 
 
When you're done watching it hit the space bar.

 
 
Test Mode 13


 
 
Tachistoscopic Acid Test Section


 
 
And of course as those test modes are operating they're not operating in a particularly stressful environment, for that I use a test I refer to as the Tachistoscopic Acid Test and it's proven it's mettle a number of times, notably by detecting that I needed to write a new Direct3D renderer when Windows 8 was released when everything else looked OK. For this test we present 30 numbered frames across the screen for a single tic a piece (so the whole sequence takes a half second on most machines). With a bit of practice one can train one's eyes to see the individual numbers and detect any variation in the rate of their display (indicating display errors as the correct display is totally smooth).
 
~888 <dfd 1> <dfm 1> mc+<co>+ <t 600> <macro yikwid> <mpr +#57> <nfb>;  
+1 ~c ~m <x .06> "1" / ~m <x .0893> "2" / ~m <x .1186> "3" / ~m <x .1479> "4" / ~m <x .1772> "5" / ~m <x .2066> "6" / ~m <x .2351> "7" / ~m <x .2652> "8" / ~m <x .2945> "9" / ~m <x .3238> "10" / ~m <x .3531> "11" / ~m <x .3824> "12" / ~m <x .4117> "13" / ~m <x .4410> "14" / ~m <x .4703> "15" / ~m <x .4997> "16" / ~m <x .5290> "17" / ~m <x .5583> "18" / ~m <x .5876> "19" / ~m <x .6169> "20" / ~m <x .6462> "21" / ~m <x .6755> "22" / ~m <x .7048> "23" / ~m <x .7341> "24" / ~m <x .7634> "25" / ~m <x .7928> "26" / ~m <x .8220> "27" / ~m <x .8514> "28" / ~m <x .8807> "29" / ~m <x .91> "30" mc+<cco>+ <binr -1>; 
 
Macro m in our relatively low stress test is defined as nothing with mm++. When you're done watching it hit the space bar and test mode 1 will run for a bit to see if your machine ran into problems running the acid test. After that it will go through the same sequence but then switch to test mode 13.

 
 
Test Mode 1

 
 
Test Mode 13

 
 
And if you are feeling chuffed that your machine survived all that we can do the same tests but manipulate a much larger section of the screen by merging those numeric frames with a couple of dots at the corners of the screen putting 400 fold or so more work into the equation by defining macro m in the above like this mm+<xy .1,.1> ".",<xy .9,.9>".",+
 
When you're done watching it hit the space bar and test mode 1 will run for a bit to see if your machine ran into problems running the acid test. After that it will go through the same sequence but then switch to test mode 13.

 
 
Test Mode 1

 
 
Test Mode 13

 
 
DMDX can use AMD FreeSync and NVIDIA G-SYNC displays with the freesync modifier to the <videomode> keyword allowing arbitrary millisecond presentation internals down to the native refresh interval (usually 7 ms or so). It can also drive NVIDIA's 3D Vision stereoscopic goggles with the nvidia3D modifier. 
 
In addition to the scrambling routines outlined earlier if you've
really got a death-wish and your scrambling needs aren't met by those relatively simple routines (say you have two or more sets of items that need scrambling) the Multi-Scramble routines have almost limitless capability and there are more examples in the the help. If that doesn't get it DMDX can also present items repeatedly or in any sort of order using branching with counters and/or macros as detailed in the Dynamic Item content notes. 
 
DMDX can run infant attention studies with the
<lookingtime> keyword, it can drive fMRI based experiments with <recordclockontime> and <id pio12> with <output> and as of version 6.1.0.0 DMDX can send TCP/IP packets to other machines or other applications on the local machine to control devices such as the Gazepoint eye tracker using their Open Gaze API with <id tcpip> and <send>. Generally there's almost no limit to what it can do, given that it's Turing Complete, worst case you get to learn a bit of low level programming.

 
 
DMDX has it's own data analysis package, ANALYZE, that can perform ANOVAs or produce .CSV files for mixed effect analysis. Other utilities like AZK2CSV that facilitate porting data to programs that read .CSV files like Excel are also available along with ANALYZE here:
 
http://psy1.psych.arizona.edu/~jforster/dmdx/dmdxutils.zip 
 
DMDX itself is available here:
 
http://psy1.psych.arizona.edu/~jforster/dmdx/DMDX.ZIP 
 
Please note that we distribute this software as is, with no guarantees as to its reliability. It may not be redistributed for sale.
 
The DMASTR software is distributed free of charge, and we ask only that you acknowledge use of the system in publications (e.g.,
"The experiment was run using the DMASTR software (DMDX) developed at Monash University and at the University of Arizona by K.I.Forster and J.C.Forster."). You can also cite our DMDX paper: DMDX: A Windows display program with millisecond accuracy. Forster, K.I. & Forster, J.C. Behavior Research Methods, Instruments, & Computers (2003) 35: 116. https://doi.org/10.3758/BF03195503

 
 
Although the software has been in constant use for more than 20 years, it is constantly evolving, and hence there is always the possibility that new releases may contain bugs. We do not assume any legal responsibility for the software, but we do assume the responsibility of advising you as rapidly as possible of any bugs that we do detect. For this reason, it is important that you get your name onto the user list serv if you plan to use the system on a regular basis. To do so:
 
1: Send a message to
list@list. arizona. edu from the address you want to subscribe to the list.
 
2: In the subject line of your message, type in:
subscribe dmdx Firstname Name (replace 'Firstname Name' by your own first name and name).
 
Once your subscription is confirmed posts can be made to
dmdx@list.arizona.edu. Please don't send attachments to the list. Your subscription should also be manageable by pointing your browser at:  
 
https://list.arizona.edu/sympa/info/dmdx

 
 

That's the end (hit ESC to exit) 
 
If you save the data it will probably wind up in the temporary directory with the name introduction.azk and because the introduction is chained one full run of data will be spread over three or more subjects in introduction.azk, the stroop section will be in introduction2.azk, the <zil> <zor> rating section will be in introduction3.zil, the <zil> <ztr> subtract 7 stressor will be in introduction4.zil and the macro section will be in introduction5.azk. And yes, chaining stuff complicates data saving, if we were actually gathering real data with such a file use of the subject ID becomes almost mandatory.
 
And if you really need to see what this item file looks like (the text is available in the help's How To Use It section) use a resource editor and pull resources 112, 113, 114, 115 and 116 from DMDX.EXE -- none of which I recommend, this file is exceeding hard to parse in places with all it's SimSun full width quotes.