Logic Dictionary: Difference between revisions

From Lifeguide Wiki
Jump to navigation Jump to search
No edit summary
 
(190 intermediate revisions by 11 users not shown)
Line 1: Line 1:
This page includes a basic break down of all the different logic commands available in the authoring tool along with basic examples to illustrate.
A quick reference guide to LifeGuide logic. For more detailed information, please refer to the '''How to...''' Guide.


Key Commands (text in red) and Commands (text in pink) should be written as they appear in the examples.
It is important to insert '''Next''' buttons on your pages (instead of '''Jump''' buttons) whenever possible in order for your logic to work correctly. If you show a page and have a vital line of logic written after you show that page (such as randomisation or saving logic), or have error messages on that page, your intervention will not work correctly if you use a '''Jump''' button - you will jump to another page and skip parts of the logic in your logic file and Error Messages section.


= Key commands (red) =
'''Tip for new users:''' many of the examples below use a variable called <code>username</code> to represent the identifier of the currently logged-in end-user. Older interventions created this variable manually near the top of the logic file (see [[#set|<code>set</code>]]). Current best practice is to use the built-in [[#currentuser|<code>currentuser()</code>]] function instead, which always returns the identifier of whoever is currently logged in, with nothing to set up first - simply use <code>currentuser()</code> anywhere you see <code>username</code> in an example below.
 
'''How to read the examples below:''' where a command takes information in brackets, e.g. <code>savevalue(username, "valuename", value)</code>, each item inside the brackets is called an '''argument''', and the commas separate one argument from the next. Most entries below list what each argument means and what you should put there. Text written in quotation marks (e.g. <code>"seconds"</code>) must be typed exactly as shown, including the quotation marks themselves - this tells the intervention you mean a fixed piece of text, not a variable.
 
=A=
 
== <code> add </code> ==
 
'''add''' can also be written as '''sum''' or '''+'''. It adds two or more numbers together - for example, several numeric responses, or scores you have calculated earlier in the logic.
 
<code>add (value1, value2, value3, ...)</code>
 
* '''value1, value2, ...''' - the numbers you want to add together. Each one can be a plain number, an interaction response (e.g. <code>page1.interaction1</code>), or a variable you have already calculated (e.g. <code>score1</code>). You can list as many as you need, separated by commas.
 
'''Example 1'''
 
This can be used to perform a calculation using the end-user's responses to specific numeric value interactions:
 
<code>set score1 to add (page1.interaction1, page1.interaction2, page1.interaction3)</code>
 
'''Example 2'''
 
The '''add''' or '''sum''' commands can also be used to calculate variables that have been set earlier in the session:
 
<code>set overallscore to sum (score1, score2, score3)</code>
 
If you only ever need to add or subtract exactly two numbers, you can use <code>+</code> and <code>-</code> instead, for example:
 
<code>set score to (100 - page1.interaction1)</code>
 
Make sure you leave a space on either side of the <code>-</code> symbol.


== <code> after </code> ==
== <code> after </code> ==


The <code>after</code> key command is used after a page to perform functions that relate to that page.
'''after''' lets you run logic once a particular page has been shown to the end-user - for example, to check their answers and decide which page to send them to next.
 
<code>after pagename if (condition) goto nextpage</code>
 
* '''pagename''' - the page this logic relates to. The logic will run once the end-user has been shown this page and clicked Next.
* '''condition''' - (optional) something that must be true for the rest of the line to happen, e.g. a response given on that page. You can leave this out if you always want the logic to run.
* '''nextpage''' - the page to send the end-user to if the condition is true.
 
You will use the '''after''' command regularly. It is most often combined with '''if''' and '''goto''', as above, but any command in this dictionary can be used after a page in the same way.
 
'''Example 1'''
 
<code>after page1 if (page1.interaction1 = "yes") goto page3
show page 2
show page3</code>
 
In the above example, the end-user will be directed to '''page3''' if they answered '''yes''' to '''interaction1''' on '''page1'''. If they answered anything else, they will carry on to the next line of logic and will see '''page2'''.
 
'''Note:''' if you use '''after''' with '''goto''', the page you send the user to (in the example above, '''page3''') should '''not''' be the very next page in your logic - it needs to be a page further down, as shown above. Otherwise the end-user would see that page twice.
 
== <code> and </code> ==
 
'''and''' can also be written as '''&&'''. It combines two or more conditions into one, and is only true when '''every''' condition inside it is true. It is commonly used to:
* check that several responses have been given before showing tailored feedback
* combine several checks into a single line of logic after a page
 
<code>and (condition1, condition2, ...)</code>
 
* '''condition1, condition2, ...''' - the individual conditions to check, separated by commas. You can list two or more. '''and''' is only true if '''all''' of them are true.
 
'''Example 1'''
 
<code>show page6 if (and(page3.exercise = "yes", page3.intensity = "moderate", page3.frequency = "three"))</code>
 
End-users will be shown page6 only if they selected '''yes''' for the interaction '''exercise''' on '''page3''', '''moderate''' for '''intensity''' on '''page3''', '''and''' '''three''' for '''frequency''' on '''page3'''. If any one of those three answers is different, page6 will not be shown.
 
'''Example 2'''
 
<code>after login_successful if (and( not(hasseen(currentuser(), "q_demographics")), (isempty (loadvalue(currentuser(), "baselinecomplete"))) )) goto q_intro </code>
 
End-users will be shown '''q_intro''' if both of the following are true: they have not seen page '''q_demographics''', '''and''' the variable '''baselinecomplete''' is empty (i.e. it hasn't been saved yet, because they haven't finished the baseline questionnaire).
 
== <code> append </code> ==
 
'''append''' joins two or more pieces of text (and/or variables) together into a single, longer piece of text. A "piece of text" - also called a '''string''' - is anything written between quotation marks, such as <code>"session1"</code>, or a variable that already holds text.
 
<code>append (part1, part2, part3, ...)</code>
 
* '''part1, part2, ...''' - the pieces of text or variables you want to join together, in the order you want them joined, separated by commas. You can list as many as you need.
 
'''append''' is most often used with '''sendemail''' and '''cancelemail''', to build a unique name for each email (see below), but it is useful anywhere you need to combine text.
 
'''Example 1'''
 
<code>sendemail (append(currentuser(),"user_reg1"), currentuser(), "StressLess - Session 1 is ready", append("Dear ", loadvalue (currentuser(), "personsname"), "\n\n", reg_part1, reg_part2), 10) </code>
 
In this example, '''append''' is used twice:
 
*to join the current end-user's identifier onto a fixed piece of text, so that the email's name is unique to that end-user:
<code>append (currentuser(),"user_reg1")</code>
 
*to build the text of the email out of several separate pieces:
<code>append ("Dear ", loadvalue (currentuser(), "personsname"), "\n\n", reg_part1, reg_part2)</code>
 
<code>\n\n</code> is a special code that means "start a new paragraph" in the email.
 
'''Example 2'''
 
<code>cancelemail (append("user_regs2rem", currentuser()), currentuser()) </code>


The <code>after</code> key command is an important command to learn. It is likely that you will use this command quite regularly in your intervention logic. The most common way of using the after key command is with the <code>if</code> and <code>goto</code> key commands in the following formula:
Here, '''append''' joins a fixed label onto the end-user's identifier, to rebuild the same unique email name that was used when the email was first set up:
<code>append ("user_regs1", currentuser())</code>


<code>show page1</code>
'''Example 3'''
 
'''append''' is not only useful for emails - it can also combine interaction responses, and the result can be saved with '''savevalue''':
 
<code>set fullname to append(registration.firstname, " ",registration.surname)
savevalue(currentuser(),"fullname", fullname)
</code>
 
This takes the responses given to the '''firstname''' and '''surname''' interactions on the '''registration''' page and combines them (with a space in between) into a single variable called '''fullname'''.
 
''Important:'' every item you pass to '''append''' must be a variable or a piece of text in quotation marks (even a single space, like " "). If you forget the quotation marks around plain text, it may not work.
 
'''Example 4'''
 
In this example, we add extra information onto a value that has already been saved, rather than replacing it:
 
<code>savevalue(currentuser(), "oldgoals","RESULTS_") if isempty(loadvalue(currentuser(),"oldgoals"))
set oldgoals to loadvalue(currentuser(),"oldgoals")
savevalue(currentuser(), "oldgoals", (append(oldgoals,"_", printtime(currenttime(),"dMy"),"_", goalsetpage.newgoal)))</code>
 
First, if the variable "oldgoals" doesn't exist yet, we create it and save a starting value. We then load whatever is currently stored in "oldgoals". Finally, we save "oldgoals" again, appending today's date and the new goal (from the page "goalsetpage") onto the end of whatever was already there. Underscores are used to separate each piece of data so it stays readable. Over time, this builds up a single variable that looks like this:
 
"RESULTS_181016_firstgoal_191016_secondgoal_221016_thirdgoal"
 
== <code> authenticateuser </code> ==
 
'''authenticateuser''' checks that a username (or email address) and password entered by an end-user match a registered account. It is used together with [[#makenewuser|<code>makenewuser</code>]], which is the command that creates the account in the first place, and is normally written directly after the logic that shows your login page.
 
<code>authenticateuser (username, password)</code>
 
* '''username''' - the page.interaction where the end-user typed their username or email address, e.g. <code>login.username</code>.
* '''password''' - the page.interaction where the end-user typed their password, e.g. <code>login.password</code>.
 
'''authenticateuser''' can be used either in the main logic file, or inside a page's '''Error Messages''' tab.
 
'''Example 1'''


<code>after page1 if (any_commands_you_want_to_relate_to_this_page) goto page2</code>
<code>show login
after login if (authenticateuser (login.username, login.password)) goto login_confirmation
show login_fail
show login_confirmation </code>


'''Example'''
Here the logic is written in the logic file. If the username and password entered on the login page match a registered account, the end-user is sent to '''login_confirmation'''. If not, they will see the '''login_fail''' page.


<code>after page1 if (page1.interaction1 = "yes") goto page2</code>
'''Example 2'''


In this example the end-user will be directed to page2 if they have answered 'yes' to 'interaction1' on page1.
<code>show err1 if (isempty(username))
show err2 if (not(authenticateuser(username, password)))</code>


As will be seen throughout this dictionary any command can be used with the <code>after</code> key command.
Here the logic is written in the '''Error Messages''' tab of the login page itself. If the username and password entered do not match a registered account, the end-user sees the error message '''err2''' and cannot move on to the next page.


=B=
== <code> begin </code> ==
== <code> begin </code> ==


The <code>begin</code> key command is always used with the <code>end</code> key command
'''begin''' marks the start of a named section of logic, and is always paired with an [[#end|<code>end</code>]] command that marks where the section finishes.
 
<code>begin sectionname</code>


If your intervention has separate sessions or groups (e.g. different weekly sessions in your behavioural intervention, or a different set of pages for different user groups) then splitting your pages into sections can make it easier for you to organise parts of your intervention and find sections easily.  
* '''sectionname''' - a name you choose for this section, e.g. <code>session1</code>. It must be different from any page or object name already used in your intervention.


Things to remember when splitting you intervention into sections:
If your intervention has separate sessions or groups (e.g. different weekly sessions, or different sets of pages for different study arms), grouping the related logic into a named section can make your logic file much easier to navigate.


* If you begin a section, you should always end the section.
A few things to remember:
* All the logic related to the section must be between begin sectionname and end
* Every '''begin''' must have a matching '''end'''.
* The name of the section should not be the same as any unique name that has been given to an object or page in your intervention.
* All the logic that belongs to the section must sit between its '''begin''' and '''end'''.
* As you can only ever end the section that you are currently in you do not need to write the section name after end.
* You only ever need to close the section you are currently in, so you do not write the section's name after '''end''' - just <code>end</code> on its own.


'''Example 1'''  
'''Example 1'''


<code> begin session1 </code>
<code> begin session1 </code>
Line 46: Line 187:
<code>end </code>
<code>end </code>


This will begin session1, show page1 and page2, and will end session1. All the pages related to session1 (page1 and page2) are between begin session1 and end.
This begins the section '''session1''', shows '''page1''' and '''page2''', then ends '''session1'''. Both pages sit between '''begin session1''' and '''end''', so they belong to that section.


'''Example 2 Beginning and ending a section within another section'''
'''Example 2 - Beginning and ending a section within another section'''


<code> begin stress</code>
<code> begin stress</code>
Line 70: Line 211:
<code>end </code>
<code>end </code>


This will begin the section stress.  
This begins the outer section '''stress'''. Inside it, the section '''causes''' begins, showing '''page1''' and '''page2'''; the first '''end''' closes '''causes'''. Then the section '''relieve''' begins, showing '''page3''' and '''page4'''; the next '''end''' closes '''relieve'''. The final '''end''' closes the outer section, '''stress'''.
The section causes will then begin and page1 and page2 in the section causes will be shown.
he first end will end the section causes.  
The section relieve will then begin and page3 and page4 will be shown.
The next end will end the ection relieve. The final end will end the section stress.


== <code> end </code> ==
=C=


See <code>begin</code>
== <code> cancelemail </code> ==


== <code> for </code> ==
'''cancelemail''' stops an email that was previously scheduled with [[#sendemail|<code>sendemail</code>]] from being sent, as long as it hasn't gone out yet. You might use this to:
* stop a reminder email if the end-user has already done the thing the reminder was about (e.g. logging in for a session)
* stop a "nudge" email to a study coordinator if the end-user has since completed the questionnaire it was chasing


The <code>for</code> key command is used with the <code>save</code> and <code>graph</code> key commands.
<code>cancelemail (uniquename, emailaddress)</code>


== <code> goto </code> ==
* '''uniquename''' - must exactly match the unique name that was used when the email was originally set up with '''sendemail''' (this is usually built with <code>append(currentuser(), "some_label")</code> - see the examples below).
* '''emailaddress''' - the address the (now cancelled) email would otherwise have been sent to.


The <code>goto</code> key command always follows the <code>after</code> key command. See above.
'''Example 1'''


== <code> graph </code> ==
<code>cancelemail(append(currentuser(), "email_session2r"), currentuser())</code>


The <code>graph</code> key command is used when you have used the graph interaction. It is used to plot the information given by end-users to the graph.
This cancels the email '''email_session2r''' for the current end-user. '''append''' rebuilds the same unique name (end-user identifier + '''email_session2r''') that was used to schedule the email in the first place.


This key command always follows the same formula and requires users to set up a user account.
'''Example 2'''


<code>graph value to "data variable determined on the graph interaction" for unique_identifier_for_the_end-user_e.g._a_username</code>
<code>cancelemail(append(currentuser(),"q1_notcomplete"), "study@test.ac.uk")</code>


Another line of logic is then needed for the page where the graph occurs. This will also always follow the same formula:
This cancels the email '''q1_notcomplete''' that was due to be sent to '''study@test.ac.uk''' (a fixed address, rather than the end-user's own address).


<code>set pagename.graph-1 to graph "data variable determined on the graph interaction" for username</code>
== <code> cancelsms </code> ==


Here, pagename.graph-1 is the automatically generated name of the graph that has been put on the page where the graph occurs.
'''cancelsms''' stops a text message that was previously scheduled with [[#sendtext|<code>sendtext</code>]] from being sent, as long as it hasn't gone out yet. It works the same way as '''cancelemail''', but for text messages.


''' Example1'''
<code>after pagename if cancelsms ("uniquename", phonenumber) goto nextpage</code>


In this example the number entered in the interaction ‘kg’ on the page ‘progresschart’ will be used as the data for the “weight” variable for the graph. The variable username has been set earlier in the logic as the unique identifier for the end-user (see the <code>set</code> key command for more information).
* '''"uniquename"''' - must exactly match the unique name used when the text message was originally scheduled with '''sendtext'''.
* '''phonenumber''' - the phone number the (now cancelled) text message would otherwise have been sent to.


<code>show progresschart
== <code> changepassword </code> ==
graph progresschart.kg to "weight" for username</code>


Later in the logic the following line is needed after the page where the graph occurs:
'''changepassword''' lets an already-registered end-user change their password, as long as they can enter their current password correctly.


<code>show weightgraph
<code>changepassword (username, oldpassword, newpassword)</code>
set weightgraph.graph-1 to graph "weight" for username</code>


A full tutorial for using graphs will soon be available.
* '''username''' - the identifier for the end-user changing their password. Use <code>currentuser()</code>.
* '''oldpassword''' - the page.interaction where they entered their current password.
* '''newpassword''' - the page.interaction where they entered their new, chosen password.


== <code> if </code> ==
Please see the LifeGuide Community Website for a tutorial intervention showing how to build the pages and logic for this.


The <code>if</code> key command is always used with the <code>set</code> or <code>after</code> key commands.
'''Example 1'''


== <code> load </code> ==
<code> after passworddetails if changepassword (currentuser(), passworddetails.old, passworddetails.new) goto confirmchange</code>


The <code>load </code> command is always used with the save command.
This changes the end-user's password, as long as their current password is entered correctly into the interaction called '''old''' on the page '''passworddetails''', and their new password is entered into the interaction called '''new''' on the same page.


== <code> named </code> ==
== <code> checkemailvalidity </code> ==


Use this key command to re-show a page you have already shown.
'''checkemailvalidity''' does a basic check that an email address entered by an end-user contains an @ symbol.


For example, if you had a page that you need to keep showing back to your end-users you could use the <code>named</code> key command as so (note that in the example below the line [etc, etc] has been used to indicate that there would be other lines of logic here):
<code>checkemailvalidity (interactionname)</code>


'''Example'''
* '''interactionname''' - the interaction where the end-user typed their email address, e.g. <code>email</code>.


<code>show page1</code>
This command is normally used together with an error message, written in the '''Error Messages''' tab (please see [[Adding Error Messages]] for more information about writing error messages).


[etc, etc]
'''Example 1'''


<code>show page1 named page2</code>  
<code> show invalidemail if (not (checkemailvalidity (email)))</code>


[etc, etc]
'''invalidemail''' is the name of an error message, shown when the interaction called '''email''' on this page doesn't contain a valid-looking address.


<code>show page1 named page3</code>
== <code> checkphonenumbervalidity </code> ==


'''checkphonenumbervalidity''' checks that a mobile number entered by an end-user begins with '''+44''' or '''0'''.


== <code> save </code> ==
<code>checkphonenumbervalidity (interactionname)</code>
The <code> save </code> key command allows you to save the responses that an end-user enters on a page. This can then be loaded using the <code> load </code> key command onto another page to re-show it to your end-user. The save and load commands can be used across sessions and requires end-users to have registered a user account.


Example:
* '''interactionname''' - the interaction where the end-user typed their phone number, e.g. <code>phone</code>.


<code> show page1</code>
This command is normally used with an error message (please see [[Adding error messages]] for more information).
<code> save page1 for username</code>


Then, later on in the logic (either in the same session or a later session) the following logic would be used:
'''Example 1'''


<code> show page20</code>
<code> show invalidnumber if (not (checkphonenumbervalidity (phone)))</code>
<code> set default page20.interaction2 to load page1.interaction1 for username</code>


So, in the first part of this logic page1 is saved for the end-user. Then when they get to page20 in the intervention the response that they entered on interaction1 on page1 will be reshown to them on interaction2 on page20.
'''invalidnumber''' is the name of the error message, shown when the interaction called '''phone''' on this page doesn't look like a valid number.


== <code> saveandload </code> ==
This check is designed for UK phone numbers only. If your study needs to accept international numbers, you will need to write your own error message logic instead.


This key command can be used after a page that includes interactions so that if an end-user moves away from that page and then comes back to it, the page will automatically show them what they entered the last time they were on that page. This line of logic would simply be written as so:
== <code> checkuserenabled </code> ==


<code> show page1</code>
'''checkuserenabled''' checks whether a user's account is currently '''enabled'''. An account can become disabled if, for example, a researcher disables it manually (e.g. because a participant has withdrawn from a study, or their account needs to be temporarily suspended).


<code>saveandload page1 for username </code>
<code>checkuserenabled (usernameoremail)</code>


Any interaction on page1 would then be saved and loaded each time the end-user comes back to that page.
* '''usernameoremail''' - the identifier to check - usually the page.interaction where the end-user entered their username or email address while logging in.


== <code> set </code> ==
'''checkuserenabled''' is most often used together with '''authenticateuser''' as part of your login logic, so that a user is only let in if they have entered the correct details '''and''' their account is still enabled.
 
The <code>set</code> key command can be used to set variables within the logic or for performing calculations.


'''Example 1'''
'''Example 1'''


The most common use of setting variables will be to set a username for the user. Many of the logic commands such as <code>save</code> will need a username to be set. This will need to be done at the start of your logic file.
<code>show login
after login if (and(authenticateuser (login.username, login.password), checkuserenabled (login.username))) goto login_confirmation
show login_fail
show login_confirmation </code>


<code>Set username to login.loginuname</code>
The end-user is only directed to '''login_confirmation''' if the username and password they entered are correct '''and''' their account is enabled. If either check fails, they are shown the '''login_fail''' page.


This will set the variable username to whatever the end-user enters into the interaction uniquely named loginuname on the login page. The word username can then be used any time throughout the logic to mean whatever the person entered in that interaction.
== <code> checkuserexists </code> ==


'''Example 2'''
'''checkuserexists''' checks whether a username or email address has already been registered with the intervention - for example, to stop someone signing up twice with the same details.


The <code>set</code> key command can also be used to set a variable based on how end-users respond to certain interactions. This can then be used to tailor the intervention based on this variable.
<code>checkuserexists (usernameoremail)</code>


<code>show page1</code>
* '''usernameoremail''' - the interaction where the end-user typed the username or email address you want to check, e.g. <code>email</code>.


<code>set condition1 to and (page1.chooseoptions contains "optiona", page1.chooseoptions contains "optiond")</code>
This command is often used with an error message (please see the '''How to''' guide for details on how to write error messages).


<code>after page1 if condition1 goto page3</code>
'''Example 1'''


So in example 2, the variable ‘condition1’ is set if end-users select options a and d from the interaction ‘chooseoptions’ on page1. Then those that are in this condition are sent to page 3 where they will receive tailored information based on the options they selected.
<code>show registeredemail if (checkuserexists (email))</code>


'''Example 3'''
'''registeredemail''' is the name of the error message shown if the end-user enters an email address (into the interaction called '''email''') that is already registered to another user.


In this example, the <code>set</code> key command is used to set a score based on the calculation that follows. In this calculation the number that the end-user selects in the interaction ‘dailyexercise’ on page1 is multiplied by 5 to create their exercise score
== <code> comparetimes </code> ==


<code>set exercisescore to (page1.dailyexercise * 5)</code>
'''comparetimes''' works out the difference between two points in time, and converts that difference into whichever unit you choose (seconds, minutes, hours, days, weeks or months).


== <code> show </code> ==
<code>comparetimes (time1, time2, "unit")</code>


The <code>show</code> key command is the first and most important logic command you will need to know. It is also probably the most common one that you will use.
* '''time1''' - the earlier point in time you are comparing, e.g. a time you saved previously with <code>loadvalue(currentuser(), "sometime")</code>.
* '''time2''' - the later point in time you are comparing, e.g. <code>currenttime()</code>.
* '''"unit"''' - what you want the difference measured in: <code>"seconds"</code>, <code>"minutes"</code>, <code>"hours"</code>, <code>"days"</code>, <code>"weeks"</code> or <code>"months"</code> (don't forget the '''s''' at the end of each one).


This key command shows each of the pages that you have created. Pages will be shown in the order they are mentioned in the logic. When an end-user clicks on a Next button on a page, they will be moved to the next page written in the logic.
The result is '''time2''' minus '''time1''', converted into the unit you chose - so it will normally be a positive number if '''time2''' is later than '''time1'''.


'''Example 1'''
'''Example 1'''


<code>show page1</code>
This example shows how '''comparetimes''' can be used to control end-users' access to different sessions or pages within an intervention.
 
There is no need to create your own <code>username</code> variable before using '''comparetimes''' - simply use <code>currentuser()</code> wherever you need to identify the end-user (see [[#currentuser|<code>currentuser()</code>]]).
 
The order of your logic matters when using '''comparetimes''':
 
'''1.''' Show the page users see before they are directed to a particular session (e.g. "mainpage"):
 
<code>show</code> mainpage


<code>show page2</code>
'''2.''' Write the logic that sends the user to a particular session or page, depending on how much time has passed:


<code>show page3</code>
<code>after</code> mainpage <code>if</code> ( <code>comparetimes</code> ( <code>loadvalue</code> ( currentuser(), <code>"session4time"</code>) , <code>currenttime</code> ( ), <code>"seconds"</code> ) <code>>=</code> 120 ) <code>goto</code> endpage


<code>show page4</code>
This says: if at least 120 seconds (two minutes) have passed since the value <code>"session4time"</code> was saved, send the user to '''endpage'''.


In the example above the end-user will first be presented with the page uniquely named ‘page1’. Then, when they click on the next button on page1 they will see the page called ‘page2’. This is followed by ‘page3’ and finally ‘page4’.
<code>after</code> mainpage <code>if</code> ( <code>comparetimes</code> ( <code>loadvalue</code> ( currentuser(), <code>"session3time"</code> ), <code>currenttime</code> ( ), <code>"seconds"</code> ) <code>>=</code> 120 ) <code>goto</code> session4


'''Note:''' Before you can preview your intervention you will need to have the show key command in the logic file for each page you want to view.
This says: if at least two minutes have passed since '''session3''' was completed, let the user continue to '''session4'''.


As the logic requires you to use unique names for each page in your logic, you can only use the show key command once for each page. However, see the <code>named</code> key command above for how to re-show the same page to users.
<code>after mainpage if ( comparetimes ( loadvalue ( currentuser(), "session3time" ), currenttime ( ), "seconds" ) <= 120 ) goto waitpage</code>


You can also reshow pages to your end-user by using a jump button on a previous page.  
This says: if less than two minutes have passed since '''session3''' was completed, send the user to a '''waitpage''' instead, since they cannot continue yet.


== <code> to </code> ==
Repeat this pattern for every session or page you want to control access to. The variables <code>"session3time"</code> and <code>"session4time"</code> are created in step 3, below.


The <code>to</code> key command is used with the <code>set</code> key command to set variables.
'''3.''' Finally, show the individual pages or sessions, and record the time each one was completed:


=Commands (pink)=
<code>show</code> waitpage


== <code> add </code> ==
<code>show</code> session3


The <code>add</code> command is used when performing calculations in the logic. This may also be written as <code>sum</code> or <code>+</code>.
<code>after</code> session3 <code>if</code> ( <code>savevalue</code> ( currentuser(), <code>"session3time"</code>,
<code>currenttime</code> ( ) ) )<code>goto</code> session3end


'''Example 1'''
<code>show</code> session3end


This can be used to perform a calculation using the end-user's responses to specific numeric value interactions:
Using [[#currenttime|<code>currenttime</code>]], this saves a new variable, <code>"session3time"</code>, recording the moment the user completed session3. This is the value that '''comparetimes''' will read back in step 2.


<code>set score1 to add (page1.interaction1, page1.interaction2, page1.interaction3)</code>
So, altogether, this example compares the time a user completed a section of the intervention with the current time, to decide whether enough time has passed to let them continue.


'''Example 2'''
'''Example 2'''


The <code>add</code> or <code>sum</code> commands can also be used to calculate variables that have been set earlier in the session:
In this example we use '''comparetimes''' to break the time until Christmas 2016 down into weeks, days, hours, minutes and seconds, so it can be displayed to the user in a friendly way.


<code>set overallscore to sum (score1, score2, score3)</code>
<code>set timenow to (currenttime())
set christmas to (1482624000)
 
set weeks to (comparetimes(timenow,christmas,"weeks"))
set days to (comparetimes(timenow,christmas,"days"))
set hrs to (comparetimes(timenow,christmas,"hours"))
set mins to (comparetimes(timenow,christmas,"minutes"))
 
set days2 to (days - (weeks*7))
set hrs2 to (hrs - (days*24))
set mins2 to (mins - (hrs*60))
set secs to ((christmas - timenow) - (mins*60))
</code>
 
This first uses '''comparetimes''' to work out the '''total''' difference between now and Christmas in weeks, in days, in hours and in minutes. But we don't want to display "total days" or "total hours" - we want a friendly breakdown, like a countdown timer would show (e.g. "2 weeks, 3 days, 4 hours...").
 
To do that, we take the total number of days and subtract the days already counted in the weeks figure, so what's left is less than 7. We do the same for hours (subtracting whole days) and minutes (subtracting whole hours).
 
For seconds, we simply take the raw difference between '''christmas''' and '''timenow''' and subtract the whole minutes we've already counted - there's no need to use '''comparetimes''' for this step, because '''currenttime''' is already measured in seconds.
 
To display the countdown on a page, the following logic can be used:
 
<code>show intro
set intro.hrs to hrs2
set intro.mins to mins2
set intro.secs to secs
set intro.days to days2
set intro.weeks to weeks
</code>
 
== <code> contains </code> ==


== <code> and </code> ==
'''contains''' is used with multiple-choice interactions, to check whether one particular option was among those an end-user selected.


The <code>and</code> command can be used for a number of reasons:
<code>interactionname contains "value"</code>


# If there is more than one response that is involved in presenting tailored advice to end-users, i.e. if one response and another response is needed to show feedback to an end-user.
* '''interactionname''' - the multiple-choice interaction to check, e.g. <code>page1.exercise</code>.
# If you need to perform a number of logic commands after a page
* '''"value"''' - the '''Unique Response Name''' of the option you're checking for, in quotation marks.


'''Example 1'''
'''Example 1'''


<code>show page6 if (and(page3.exercise = "yes", page3.intensity = "moderate", page3.frequency = "three"))</code>
<code> after page1 if (page1.exercise contains "none") goto page4</code>
 
The end-user is directed to '''page4''' if '''none''' was one of the options they selected for the interaction '''exercise''' on '''page1'''.
 
'''Example 2'''
 
<code> after page1 if (or( page1.exercise contains "1day", page1.exercise contains "2days" )) goto page4</code>
 
The end-user is shown '''page4''' if they selected either '''1day''' or '''2days''' for the interaction '''exercise''' on '''page1'''.
 
== <code> converttointeger </code> ==


End-users will be shown pagename6 if they selected yes to the interaction exercise on page3, moderate to the interaction intensity on page3 and three to the interaction frequency on page3.
Interactions where an end-user types in a number - such as a text-entry interaction asking for someone's age - store the response as text (a series of characters), not as a number. This means the response can't reliably be used with comparison commands (<code>morethan</code>, <code>lessthan</code>, etc.) or calculation commands (<code>add</code>, <code>multiply</code>, etc.) until it has been converted into a whole number. '''converttointeger''' does this conversion for you.


== <code> append </code> ==
<code>converttointeger (interactionname)</code>


The <code>append</code> command allows you to attach strings of logic together or to attach a variable within a string.
* '''interactionname''' - the text-entry interaction whose response you want to convert, e.g. <code>signup.age</code>. The response should only contain digits (a whole number) for the conversion to work correctly.


'''Example 1'''
'''Example 1'''


In this example the append function is used to attach a person's username (which has been set in a previous part of the logic) to the text used in an email message:
<code>show screening_fail if (converttointeger(signup.age) < 18)</code>


<code>after login if sendemail ("welcomeemail", login.uname, "Welcome to the lifestyle study", append ("Thank you for registering for the study", username, "remember to chart your progress everyday"), 60) goto page1</code>
This shows the error message '''screening_fail''' if the number entered into the text-entry interaction '''age''' on the '''signup''' page converts to less than '''18'''.


== <code> authenticateuser </code> ==
'''Example 2'''
 
<code>savevalue(currentuser(), "age_years", converttointeger(signup.age))</code>
 
This converts the text response given to the '''age''' interaction into a whole number, and saves it as the variable '''age_years''' for the current end-user, so it can be used in calculations later in the intervention.
 
== <code> countif </code> ==
 
'''countif''' counts how many of a list of conditions are currently true - for example, how many interactions on a page an end-user has filled in.


This is important logic for ensuring that a user is registered with the intervention and is usually found after the login page.  
<code>countif (condition1, condition2, ...)</code>


The <code>authenticateuser</code> command can be used in the logic (intervention.lgil) file or in the error message logic.
* '''condition1, condition2, ...''' - the conditions to check, separated by commas. '''countif''' returns the number of these that are true.


'''Example'''
'''Example'''


<code>after login if (authenticateuser (login.username, login.password)) goto page1</code>
<code>after page1 if (countif( not(isempty(page1.interaction1)), not(isempty(page1.interaction2)), not(isempty(page1.interaction3)), not(isempty(page1.interaction4)) ) < 3) goto page4</code>
 
This checks four interactions on '''page1''' and counts how many of them have '''not''' been left empty (i.e. how many the end-user has answered). If they have answered fewer than 3 of the 4, they are directed to '''page4'''.
 
== <code> currenttime </code> ==
 
'''currenttime()''' returns the date and time at the exact moment it runs. It takes no arguments - it is always written with empty brackets, <code>currenttime()</code>, which tells the intervention this is a function rather than a variable you have created yourself.
 
You can use '''currenttime''' to record when something happened (by saving it), or to compare against a time you saved earlier (using [[#comparetimes|<code>comparetimes</code>]]).
 
'''1.''' There is no need to create your own username variable before using '''currenttime''' - simply use <code>currentuser()</code> wherever you need to identify the end-user (see [[#currentuser|<code>currentuser()</code>]]).
 
'''2.''' To save the time a user completes a particular section of your intervention (in this example, "session 3"):
 
<code>show session3</code>
 
<code>after session3 if ( savevalue ( currentuser(), "session3time", currenttime ( ) ) )goto session3end</code>
 
<code>show session3end</code>
 
This saves the moment the user completes the session3 page as a new variable called <code>"session3time"</code>.


So in the example above the details that the end-user enters into username and password interactions on the login page will be used to check that they are a registered user.
'''3.''' '''currenttime''' can also be used as a reference point to compare against, which is particularly useful for putting time controls on when users can access particular sessions (see also [[#comparetimes|<code>comparetimes</code>]]):


== <code> cancelemail </code> ==
<code>after mainpage if ( comparetimes ( loadvalue ( currentuser(), "session3time" ), currenttime ( ), "minutes" ) >= 120 ) goto session4</code>


This command is used to cancel an email that has already been set up earlier on in the logic. For example if you set up e-mail reminders for people to login to upcoming sessions in the intervention then you will need to then cancel them if they subsequently login before the e-mail is due to be sent out.
This lets the user continue to session 4 if it has been at least two hours since they completed session 3.


This command uses the same basic formula:
<code>after mainpage if ( comparetimes ( loadvalue ( currentuser(), "session3time" ), currenttime ( ), "minutes" ) <= 120 ) goto waitpage</code>


<code> after pagename if cancelemail ("unique name for email", e-mail address) goto nextpage</code>
This sends the user to a "waitpage" instead, if less than two hours have passed since they completed session 3.


'''Example'''
'''currentuser()''' and '''midnight()''' work the same way as '''currenttime()''' - all three are functions that take no arguments, so they are always written with empty brackets.


<code>after session2welcome if cancelemail ("session 2 reminder", login.email) goto session2page1</code>
== <code> currentuser </code> ==


== <code> cancelsms </code> ==
'''currentuser()''' returns the identifier (i.e. the username) of whichever end-user is currently logged in to the intervention. It takes no arguments - it is always written with empty brackets, <code>currentuser()</code>. It can be used anywhere you would otherwise need a username variable - for example with <code>savevalue</code>, <code>loadvalue</code>, <code>sendemail</code>, <code>hasseen</code> and most other commands that refer to a specific end-user.


This command cancels an SMS message that has already been set up earlier on in the logic.
'''Best practice:''' older interventions had to create their own <code>username</code> variable near the top of the logic file, by loading it from the login or signup page (see [[#set|<code>set</code>]], Example 1). '''currentuser()''' removes the need for this step, because it always refers to whichever end-user is logged in at that point in the intervention - there is nothing to set up first. This is now the recommended way to refer to the current end-user throughout your logic.


It uses a similar basic formula that is used for cancelling emails except it uses the <code>cancelsms</code> command and a phone number:
'''Note:''' '''currentuser()''' only returns a sensible result once someone has actually logged in (for example, after '''authenticateuser''' or '''makenewuser''' has run successfully). Using it on a page shown before login, such as the login page itself, will not identify anyone.


<code> after pagename if cancelsms ("unique name for sms message", phonenumber) goto nextpage</code>
'''Example 1'''


== <code> changepassword </code> ==
<code>savevalue(currentuser(), "session1complete", "yes")</code>


This command enables users to change their password. The formula for using this command would be:
This saves the variable '''session1complete''' for whichever end-user is currently logged in - there is no need to set up a separate username variable first.


<code> after pagename1 if changepassword (username, pagename1.name_of_interaction_for_entering_old_password, pagename1.name_of_interaction_for_entering_new_password) goto pagename2</code>
'''Example 2'''


'''Example'''
<code>show welcome
set welcome.firstname to loadvalue(currentuser(), "firstname")</code>


<code> after passworddetails if changepassword (username, passworddetails.old, passworddetails.new) goto confirmchange</code>
This loads the value '''firstname''' that was previously saved for the current end-user, and displays it on the page '''welcome''' in place of the word 'firstname'.


== <code> checkemailvalidity </code> ==
=D=


Checks that the e-mail that a user has entered is valid (i.e. contains an @ symbol).
== <code> decimalplaces </code> ==


This command is often used in an error message (please refer to the [http:www.lifeguideonline.org/releases/documentation researcher help manual] for details of writing error messages).
'''decimalplaces''' rounds a number to a specified number of digits after the decimal point. For example, it would round 6.6666666 to 6.67 if you asked for 2 decimal places, or to 6.6667 for 4 decimal places. If you want to round to a whole number (0 decimal places), the simpler [[#round|<code>round</code>]] command can be used instead.


'''Example'''
<code>decimalplaces (number, decimalplacecount)</code>


<code> show invalidemail if (not (checkemailvalidity (email)))</code>
* '''number''' - the number (or a variable/calculation that produces a number) you want to shorten.
* '''decimalplacecount''' - how many digits you want to keep after the decimal point.


In this example 'invalidemail' is the name of the error message and 'email' is the name of the interaction on this page where the end-user would enter their e-mail address.  
You cannot use '''decimalplaces''' to abbreviate whole numbers to a number of significant figures (e.g. turning 1,234,567 into 1,234,600) by asking for a negative number of decimal places - a negative number here is simply treated as 0. To round a whole number like this, use '''round''' instead (see Example 3 of [[#round|<code>round</code>]]).


== <code> checkphonenumbervalidity </code> ==
'''Example 1'''


Checks that the mobile number that a user has entered is valid (i.e. begins with +44 or 07).
In this example we shorten a long decimal number to 4 decimal places.


This command is often used in an error message (please refer to the [http:www.lifeguideonline.org/releases/documentation researcher help manual] for details of writing error messages).
<code>set numberpi to decimalplaces(3.1415926,4)</code>


'''Example'''
This sets the value of '''numberpi''' to 3.1416.


<code> show invalidenumber if (not (checkphonenumbervalidity (phone)))</code>
'''Example 2'''


In this example 'invalidnumber' is the name of the error message and 'phone' is the name of the interaction on this page where the end-user would enter their phone number.  
In this example we calculate the area of a circle and return the answer to 2 decimal places.


Please note that this logic is only set up to work with UK based numbers. Researchers will need to create their own phone number validator for international numbers or arrange this with a member of the LifeGuide team.
<code>show circle_page


== <code> checkuserenabled </code> ==
set cradius to circle_page.radius


== <code> checkuserexists </code> ==
set pi to 3.14159


This command would check whether an email address or username has already been registered for the intervention (i.e. if the details that have been entered is already registered with another user). This command is often used with an error message (please refer to the [http://www.lifeguideonline.org/releases/documentation researcher help manual] for details of writing error messages).
set carea to ((cradius*cradius)*pi)


'''Example'''
set careashort to decimalplaces(carea,2)


<code>show registeredemail if (checkuserexists (email))</code>
show results_page


In this example registeredemail is the name of the error message that would show if what they person enters in the 'email' interaction has already been registered.
set results_page.circle to careashort


== <code> comparetimes </code> ==
</code>


== <code> contains </code> ==
First we get the radius from the user's response on '''circle_page'''. Then we set the value of pi. Then we calculate the area of the circle using the formula area = pi × (radius × radius). We then shorten the result to 2 decimal places for display, while still keeping the full, unrounded value stored in '''carea''' in case we want to use it in further calculations later (like the volume of a cylinder). On '''results_page''' we show the user the area of the circle, to 2 decimal places.


This command is used with multiple choice interactions. It can be used to check if users have chosen a specific response in a multiple choice interaction and then show them tailored information based on this.
== <code> default </code> ==


'''Example'''
'''default''' sets an interaction on a page to show a previously saved value, so the end-user sees their earlier answer already filled in. It is used together with the [[#save|<code>save</code>]] command - see '''save''' for an example.


<code> after page1 if (page1.exercise contains "nodays") goto page4</code>
To recall information the end-user entered earlier on the '''same''' page (rather than a different page or session), use [[#saveandload|<code>saveandload</code>]] instead.


In this example the enduser would be directed to page 4 if they selected had selected the option that they had not done any exercise on any day in the past week (i.e. they selected the response 'no days'.
== <code> deletevalue </code> ==


== <code> countif </code> ==
'''deletevalue''' removes a value that was previously saved with [[#savevalue|<code>savevalue</code>]]. This is useful when you want to clear a saved value so a fresh answer can be stored later in the intervention - for example, because an end-user is updating information about themselves that can change over time.


This command can be used to count how many interactions an end-user has filled in.
<code>deletevalue (username, "valuename")</code>


'''Example'''
* '''username''' - the end-user whose saved value you want to remove. Use <code>currentuser()</code>.
* '''"valuename"''' - the exact name that was used when the value was originally saved with '''savevalue''', in quotation marks.


<code>after page1 if (countif (not (isempty (page1.interaction1))), (not (isempty (page1.interaction2))), (not (isempty (page1.interaction3))), (not (isempty (page1.interaction4)))) <3) goto page4</code>
'''Example 1'''


This example counts how many interactions on page1 that the enduser fills in. If they respond to less than 3 of the interactions they will be directed to page4 of the interaction.
<code>deletevalue(currentuser(), "currentgoal")
savevalue(currentuser(), "currentgoal", goalpage.newgoal)</code>


== <code> currenttime </code> ==
This deletes the previously saved value '''currentgoal''' for the current end-user, before saving a new response to the same variable. Deleting the old value first ensures that only the most recent goal is stored, rather than the new value being added alongside the old one.


== <code> divide </code> ==
== <code> divide </code> ==


This is used when performing calculations. The symbol <code>/</code> can also be used.
'''divide''' is used when performing calculations. The symbol <code>/</code> can also be used instead.
 
<code>value1 / value2</code>
 
* '''value1''' - the number being divided (the dividend).
* '''value2''' - the number to divide it by (the divisor).


'''Example 1'''
'''Example 1'''
Line 379: Line 607:
<code> set score1 to (page1.interaction1 / page1.interaction2)</code>
<code> set score1 to (page1.interaction1 / page1.interaction2)</code>


score1 would be the result of dividing the response given in interaction 1 by the response given in interaction 2.
'''score1''' is the result of dividing the response given for '''interaction1''' by the response given for '''interaction2'''.


'''Example 2'''
'''Example 2'''
Line 385: Line 613:
<code> set overallscore to (score1 / score2)</code>
<code> set overallscore to (score1 / score2)</code>


In this example the overallscore is calculated by dividing score1 by score2 where score1 and score2 have already been calculated elsewhere in the logic.
Here, '''overallscore''' is calculated by dividing '''score1''' by '''score2''', where both have already been calculated elsewhere in the logic.
 
=E=
 
== <code> else </code> ==
 
'''else''' is used only together with [[#if|<code>if</code>]]. It lets you specify something to do when the '''if''' condition on the line above is '''not''' met.
 
<code>if not(or(isempty(page1.q1),isempty(page1.q2))) set page1_complete to 1
 
else set page1_complete to 0</code>
 
This checks whether both interactions on '''page1''' have been answered. If they have, '''page1_complete''' is set to 1. The '''else''' line then sets '''page1_complete''' to 0 if they have '''not''' both been answered.
 
== <code> end </code> ==
 
'''end''' closes a section that was opened with [[#begin|<code>begin</code>]]. Please see '''begin''' for details and examples. '''end''' takes no arguments - you never need to repeat the section's name, since it always closes whichever section is currently open.
 
=F=
 
== <code> for </code> ==
 
'''for''' is used together with the [[#save|<code>save</code>]] and [[#graph|<code>graph</code>]] commands, to say which end-user a page or a piece of graph data belongs to (e.g. <code>save page1 for currentuser()</code>). See those entries for full examples.
 
=G=
 
== <code> getuserid </code> ==
 
'''getuserid''' returns the database ID for a user - a number that LifeGuide generates automatically and that is unique to each account on that server. This can be useful if you need a short, unique identifier for a user without referring to their username or email address directly. It can also be included in your data export by ticking the '''User Number''' box when you export your data.
 
<code>getuserid (username)</code>
 
* '''username''' - the end-user whose database ID you want. Use <code>currentuser()</code>.
 
'''Example 1'''
 
<code>getuserid(currentuser())</code>
 
== <code> goto</code> ==
 
'''goto''' is always used together with the [[#after|<code>after</code>]] command. It tells the logic which page to send the end-user to next.
 
<code>after pagename if (condition) goto nextpage</code>
 
* '''nextpage''' - the page the end-user should be sent to when the condition is true. See '''after''' for a full explanation and examples.
 
== <code> graph </code> ==
 
'''graph''' is used together with the graph interaction, to plot information given by end-users onto a graph - for example, showing someone their weight or mood over time.


It always follows the same two-part pattern, and requires end-users to have a registered account.
'''1.''' Wherever you collect the data you want to plot, record it with:
<code>graph interactionvalue to "variablename" for username</code>
* '''interactionvalue''' - the response you want to plot, written as <code>page.interaction</code> (e.g. <code>progresschart.kg</code>).
* '''"variablename"''' - a name you choose for this piece of data, in quotation marks. Use the same name every time you record data for the same graph.
* '''username''' - the end-user this data point belongs to. Use <code>currentuser()</code>.
'''2.''' On the page where the graph interaction itself is shown, add a line to tell it which data to display:
<code>set pagename.graph-1 to graph "variablename" for username</code>
Here, '''pagename.graph-1''' is the name LifeGuide automatically gives to a graph interaction (you can check the exact name in the interaction's properties), and '''"variablename"''' must match the name used when the data was recorded in step 1.
'''Example 1'''
In this example, the number entered into the interaction '''kg''' on the page '''progresschart''' is recorded as the data for a graph variable called "weight".
<code>show progresschart
graph progresschart.kg to "weight" for currentuser()</code>
Later in the logic, on the page where the graph is actually displayed:
<code>show weightgraph
set weightgraph.graph-1 to graph "weight" for currentuser()</code>
A full tutorial for using graphs will soon be available.
=H=
== <code> hasseen </code> ==
== <code> hasseen </code> ==


<code>hasseen</code> is used to show end-users pages based on what they have or have not seen before.  
'''hasseen''' checks whether an end-user has already been shown a particular page, so you can tailor what they see next based on their previous visits.
 
<code>hasseen (username, "pagename", scope)</code>
 
* '''username''' - the end-user to check. Use <code>currentuser()</code>.
* '''"pagename"''' - the unique name of the page you want to check, in quotation marks.
* '''scope''' - (optional, only relevant if your intervention uses sessions - see below) leave this out entirely to check previous sessions only, or write <code>"true"</code> to include the current session, or <code>"this"</code> to check the current session only.
 
'''Tip:''' if your intervention has more than one session, we recommend using [[#savevalue|<code>savevalue</code>]] and [[#loadvalue|<code>loadvalue</code>]] instead of '''hasseen''', since saved values can be corrected after your intervention has gone live if something goes wrong, whereas page-view history cannot.


'''Example 1'''
'''Example 1'''


If you wanted to show end-users a different page each time they logged in depending on what sessions they had seen before you may use the hasseen command like so:
If you want to show end-users a different page each time they log in, depending on which sessions they have already seen, you can use '''hasseen''' like this:


<code>show login</code>
<code>show login</code>


<code>show s1welcome if (not(hasseen (username, "s1welcome")))</code>
<code>show s1welcome if (not(hasseen (currentuser(), "s1welcome")))</code>
<code>show s2welcome if (not(hasseen (username, "s2welcome")))</code>
 
<code>show s3welcome if (not(hasseen (usernme, "s3welcome")))</code>
<code>show s2welcome if (not(hasseen (currentuser(), "s2welcome")))</code>
 
<code>show s3welcome if (not(hasseen (currentuser(), "s3welcome")))</code>
 
The first time someone logs in, they will see '''s1welcome'''. The next time, because they have already seen '''s1welcome''', the logic skips that line and shows '''s2welcome''' instead, since they have not yet seen it.


This would mean that the first time they login they would see the session 1 welcome page which is labelled s1welcome. The next time they log in, because they have already seen the s1welcome page the logic will skip that line of logic and show them s2welcome because they have not yet seen the s2welcome page.
'''Example 2'''
 
'''hasseen''' can also be used without '''not''', to tailor the intervention for users who '''have''' already seen a page.
 
<code>show s1_feeback2 if (hasseen (currentuser(), "s1_feedback1")))</code>
 
<code>show s1_feeback3 if (hasseen (currentuser(), "s1_feedback2")))</code>
 
===Using hasseen in sessions===
 
If your intervention is split into sessions, the '''scope''' argument controls which sessions '''hasseen''' looks at:
 
<code> show session2.interaction1 if (hasseen (currentuser(), "session1final"))</code>
 
With no third argument, this shows '''interaction1''' if the end-user has seen '''session1final''' in any '''previous''' session (but not the one they're currently in).
 
<code> show session2.interaction1 if (hasseen (currentuser(), "session1final", "true"))</code>
 
Adding <code>"true"</code> shows '''interaction1''' if the end-user has seen '''session1final''' in '''any''' session, including the current one.
 
<code> show session2.interaction1 if (hasseen (currentuser(), "session1final", "this"))</code>
 
Adding <code>"this"</code> shows '''interaction1''' only if the end-user has seen '''session1final''' earlier in the '''current''' session.
 
== <code> hmacencode </code> ==
 
'''hmacencode''' is an advanced command that scrambles (encrypts) a piece of text so it cannot be read. There is no way to reverse this and get the original text back (it cannot be decrypted) - its main use is to check that data passed from one intervention to another has not been tampered with or corrupted along the way.
 
<code>hmacencode (text, secretkey)</code>
 
* '''text''' - the piece of text you want to encode, in quotation marks (or a variable containing text).
* '''secretkey''' - a password-like piece of text, shared between the systems that need to check the data, used to scramble it.
 
<code>set encoded to hmacencode("This message is encoded", "secret")</code>
 
=I=
 
== <code> if </code> ==
 
'''if''' is always used together with another command (e.g. '''after''', '''show''', '''set'''). It is followed by a '''condition''' - something that can only be true or false, such as <code>page1.interaction1 = "yes"</code>. The command in front of '''if''' is only carried out when that condition is true.
 
<code>command if (condition)</code>
 
* '''condition''' - the thing being checked. This is often built using other commands from this dictionary, such as '''and''', '''or''', '''not''', '''isempty''' or a comparison like <code>=</code>, <code><</code> or <code>>=</code>.


== <code> isempty </code> ==
== <code> isempty </code> ==


This command checks if an interaction is empty.
'''isempty''' checks whether an end-user has given '''any''' response to an interaction - in other words, whether it has been left blank.


'''Example1'''
<code>isempty (interactionname)</code>
 
* '''interactionname''' - the interaction to check, e.g. <code>page1.interaction1</code>.
 
'''Example 1'''


<code>after page1 if (isempty (page1.interaction1)) goto page4</code>
<code>after page1 if (isempty (page1.interaction1)) goto page4</code>


The end-user would be directed to page4 if they did not enter anything in interaction1 on page1.
The end-user is directed to '''page4''' if they left '''interaction1''' on '''page1''' blank.


'''Example2'''
'''Example 2'''


<code>set none if (isempty (page1.interaction1))</code>
<code>set none if (isempty (page1.interaction1))</code>


If the end-user does not enter anything in interaction1 on page1 they would be set to the condition 'none'.
If the end-user leaves '''interaction1''' on '''page1''' blank, the variable '''none''' is set.
 
=L=
 
== <code> load </code> ==
 
'''load''' is always used together with [[#save|<code>save</code>]], to bring back a page's saved responses so they can be shown again. Please see '''save''' for details and an example.


== <code> or </code> ==
== <code> loadvalue </code> ==
 
'''loadvalue''' retrieves a value that was previously stored with [[#savevalue|<code>savevalue</code>]].
 
<code>loadvalue (username, "valuename")</code>
 
* '''username''' - the end-user whose data you want to retrieve. Use <code>currentuser()</code>.
* '''"valuename"''' - the exact name that was used when the value was saved with '''savevalue''', in quotation marks.
 
Please see [[#savevalue|<code>savevalue</code>]] for full examples of saving and loading values together.
 
== <code> loggedin </code> ==
 
'''loggedin()''' checks whether there is currently a logged-in end-user. It takes no arguments - it is always written with empty brackets, <code>loggedin()</code>. It returns '''true''' if someone is logged in, and '''false''' if not. This is useful for tailoring pages or navigation depending on whether someone is browsing your intervention as a registered, logged-in user - for example, to skip the login page for someone who is already logged in, or to hide content that should only be seen once someone has logged in.
 
'''Example 1'''
 
<code>show login
after login if (loggedin()) goto welcome_back
show login_fail
show welcome_back</code>
 
This directs the end-user straight to '''welcome_back''' if they are already logged in (for example, if they still have an active session from earlier), skipping the need to log in again.
 
'''Example 2'''


The <code>or</code> command is used in much the same way as the <code>and</code>. It can be used to check if a user has responded in particular ways to an interaction (or number of interactions):
<code>show help_page
show help_page.membersonly if (loggedin())</code>


<code> after page1 if (or (page1.interaction1 = "none", page1.interaction1 = "sometimes")) goto page3</code>
This shows the feedback box '''membersonly''' on '''help_page''' only to end-users who are currently logged in.


== <code> lessthan </code> ==
== <code> lessthan </code> ==


This command can be used when performing calculations in the logic to check if one value is lower than another. The symbol <code><</code> can also be used.  
'''lessthan''' compares two values. The symbol <code><</code> can also be used instead.
 
<code>value1 lessthan value2</code> (or <code>value1 < value2</code>)
 
* '''value1''' - the first value.
* '''value2''' - the value it's being compared against. The condition is true when '''value1''' is smaller than '''value2'''.
 
This is used both for:
* comparing numbers, e.g. interaction responses or calculated scores
* comparing time, e.g. checking that less than a certain amount of time has passed since a previous session
 
'''Example 1'''


<code>set condition1 if (page1.interaction1 < page1.interaction2) </code>
<code>set condition1 if (page1.interaction1 < page1.interaction2) </code>
'''Example 2'''
<code>after login if (comparetimes (loadvalue(currentuser(), "session1_time"), currenttime(), "seconds" ) < 86400)</code>


== <code> lessthanequal </code> ==
== <code> lessthanequal </code> ==


This command can be used when performing calculations in the logic to check if one value is lower than or equal to another. The symbol <code> <= </code> can also be used.  
'''lessthanequal''' works the same way as '''lessthan''', but is also true when the two values are equal. The symbol <code><=</code> can also be used instead.
 
<code>value1 lessthanequal value2</code> (or <code>value1 <= value2</code>)
 
* '''value1''' - the first value.
* '''value2''' - the value it's being compared against. The condition is true when '''value1''' is smaller than, or equal to, '''value2'''.
 
'''Example 1'''


<code>set condition1 if (page1.interaction1 <= page1.interaction2) </code>
<code>set condition1 if (page1.interaction1 <= page1.interaction2) </code>


== <code> loadvalue </code> ==
'''Example 2'''
 
<code>after login if (comparetimes (loadvalue(currentuser(), "session1_time"), currenttime(), "seconds" ) <= 86400)</code>
 
=M=


== <code> makenewuser </code> ==
== <code> makenewuser </code> ==


The <code>makenewuser</code> is very important; it is used to set up an [[account]] for the user using a username (or e-mail address) and password.  
'''makenewuser''' creates a new registered account for an end-user, using a username (or email address) and password that they choose.
 
<code>makenewuser (username, password)</code>
 
* '''username''' - the page.interaction containing the identifier the end-user will log in with, e.g. <code>signup.signup_username</code>.
* '''password''' - the page.interaction containing their chosen password, e.g. <code>signup.signup_password</code>. This interaction should always be set to the '''password''' interaction type in its properties panel - if it isn't, the password will be visible as the end-user types it, and will not be stored securely, which can leave users unable to log in later.
 
'''makenewuser''' both creates the account '''and''' signs the end-user in at the same time, so there is no need to also call [[#authenticateuser|<code>authenticateuser</code>]] straight afterwards.


'''Example'''
'''Example'''
Line 447: Line 877:
<code>show signup</code>
<code>show signup</code>


<code>after signup if (makenewuser(signup.signup_username, signup.signup_password)) goto thankyou</code>
<code>makenewuser(signup.signup_username, signup.signup_password)</code>
 
The information the end-user enters into the '''signup_username''' and '''signup_password''' interactions is used to create their account.
 
'''Tip:''' if you create accounts using an identifier other than a real email address (for example, a study ID), you can still associate a real email address with the account afterwards using [[#setemail|<code>setemail</code>]], so that commands like '''sendemail''' and '''resetpassword''' work correctly.
 
== <code> midnight </code> ==
 
'''midnight()''' is similar to [[#currenttime|<code>currenttime()</code>]], but returns the time at midnight at the '''start''' of today, rather than right now. It takes no arguments - it is always written with empty brackets, <code>midnight()</code>. It's useful for scheduling something at a specific time of day, such as sending an email at 7am, one week after someone registers.
 
<code>set delay7am to + (midnight(), 25200, (-1 * currenttime()))</code>
 
This sets a variable called '''delay7am''' to: today's midnight, plus 25200 seconds, minus the time right now.
 
For example, at 10:30am on 2/9/2016, this would be 1472774400 + 25200 - 1472812200 = -12600.
 
Place this logic near the top of your logic file with your other '''set''' lines, or immediately before the '''sendemail''' logic that uses it.


So in the example above the information that the end-user enters into the interactions 'signup_username' and 'signup_password' is used to create a user account.  
'''delay7am''' can be replaced with a variable name of your choice. '''25200''' is the number of seconds since midnight that you want (in this case, 7 hours = 7am - you can change this to schedule a different time of day).
 
Your email logic would then look something like this:
 
<code> sendemail (append(currentuser(),"welcome_email"),currentuser(),"You have successfully registered to Stress Less", append("Dear ", loadvalue (currentuser(), "firstname"), "\n\n", welcome), (delay7am+604800)) </code>
 
Because '''delay7am''' will be a '''negative''' number if the current time is already past 7am, you need to add at least one full day (in seconds) on top of it before using it as a delay - in the example above, one week (604800 seconds) has been added.
 
Remember to allow for the UK's clock changes between GMT and BST, and for time differences between the UK and other countries, if this matters for your study.


== <code> morethan </code> ==
== <code> morethan </code> ==


This command can be used when performing calculations in the logic to check if one value is higher than another. The symbol <code> > </code> can also be used.  
'''morethan''' compares two values. The symbol <code>></code> can also be used instead.
 
<code>value1 morethan value2</code> (or <code>value1 > value2</code>)
 
* '''value1''' - the first value.
* '''value2''' - the value it's being compared against. The condition is true when '''value1''' is bigger than '''value2'''.
 
'''Example 1'''


<code>set condition2 if (page1.interaction1 > page1.interaction2) </code>
<code>set condition2 if (page1.interaction1 > page1.interaction2) </code>
'''condition2''' is set if the value given for '''interaction1''' is greater than the value given for '''interaction2'''.


== <code> morethanequal </code> ==
== <code> morethanequal </code> ==


This command can be used when performing calculations in the logic to check if one value is higher than or equal to another. The symbol <code> >= </code> can also be used.  
'''morethanequal''' works the same way as '''morethan''', but is also true when the two values are equal. The symbol <code>>=</code> can also be used instead.
 
<code>value1 morethanequal value2</code> (or <code>value1 >= value2</code>)
 
* '''value1''' - the first value.
* '''value2''' - the value it's being compared against. The condition is true when '''value1''' is bigger than, or equal to, '''value2'''.
 
'''Example 1'''


<code>set condition2 if (page1.interaction1 >= page1.interaction2) </code>
<code>set condition2 if (page1.interaction1 >= page1.interaction2) </code>
'''condition2''' is set if '''interaction1''' is greater than or equal to '''interaction2'''.


== <code> multiply </code> ==
== <code> multiply </code> ==


This command can be used when performing calculations to multiply one value by another. The symbol <code> * </code> may also be used. This value may be taken from an end-user's response to an interaction:
'''multiply''' is used to multiply one value by another. The symbol <code>*</code> can also be used instead.
 
<code>value1 * value2</code>
 
* '''value1''' and '''value2''' - the two numbers to multiply together. Each can come from an end-user's response to an interaction, or from a calculation performed elsewhere in the logic.


'''Example 1'''
'''Example 1'''


<code>set score1 to (page1.interaction1 * page1.interaction2)</code>
<code>set score1 to (page1.interaction1 * page1.interaction2)</code>
The response to '''interaction1''' is multiplied by the response to '''interaction2''', and the result is saved as '''score1'''.


'''Example 2'''
'''Example 2'''


The value may be taken from the calculations performed elsewhere in the logic: E.g.:
<code> set overallscore to (score1 * score2) </code>
 
Here, '''score1''' and '''score2''' were already calculated earlier in the logic, and are multiplied together to give '''overallscore'''.
 
=N=
 
== <code> named </code> ==
 
'''named''' lets you re-show a page you have already shown once, under a new alias.
 
<code>show pagename named alias</code>
 
* '''pagename''' - the page you have already created and shown earlier in your logic.
* '''alias''' - a new, unique name for this repeat showing of the page. This is '''not''' a separate page you need to create - it is simply a label that lets your logic refer to this particular instance of showing '''pagename''' again.
 
'''Example 1'''
 
<code>show page1</code>
 
[etc, etc]
 
<code>show page1 named page2</code>


<code> set overallscore to (score1 * score2) </code>
[etc, etc]
 
<code>show page1 named page3</code>
 
(Here, <code>[etc, etc]</code> stands in for other lines of logic that would appear in a real intervention.) This shows the same page, '''page1''', three times over the course of the intervention - once under its own name, then again labelled '''page2''', then again labelled '''page3'''.


== <code> not </code> ==
== <code> not </code> ==


The <code>not</code> command is used to refer to a response which had not been selected.
'''not''' reverses whether a condition is treated as true or false - a condition that would normally be true becomes false, and vice versa.
 
<code>not (condition)</code>
 
* '''condition''' - the condition to reverse.


'''Example 1'''
'''Example 1'''
Line 485: Line 992:
<code>set condition1 if (not (page1.interaction1 = "yes"))</code>
<code>set condition1 if (not (page1.interaction1 = "yes"))</code>


So condition1 would be set for this user if they did not select the "yes" response in interaction1. We can then use this condition to tailor the rest of the intervention that the end-user sees.
'''condition1''' is set if the end-user did '''not''' select '''yes''' for '''interaction1'''. This condition can then be used to tailor the rest of the intervention.


'''Note''': Do not confuse the <code>not</code> command with the <code>isempty</code> command. <code>not</code> is used to refer to a specific response to an interaction that has not been chosen. <code>isempty</code> is used to refer to an interaction that an end-user has not answered.
'''Note''': don't confuse '''not''' with [[#isempty|<code>isempty</code>]]. '''not''' refers to a specific response '''not''' being chosen; '''isempty''' refers to an interaction that hasn't been answered at all. The two can be combined to check for "an answer was given, and it wasn't blank":


<code>not</code> and <code>isempty</code> can be used together to refer to an interaction that is not empty (i.e. something has been entered).
'''Examples 2 and 3'''


<code> after page1 if (not (isempty (page1.interaction1))) goto page5</code>
<code> after page1 if (not (isempty (page1.interaction1))) goto page5</code>


Or
Or:


<code> set condition1 if (not (isempty (page1.interaction1)))</code>
<code> set condition1 if (not (isempty (page1.interaction1)))</code>
=O=
== <code> or </code> ==
'''or''' can also be written as '''||'''. It combines two or more conditions into one, and is true if '''any''' one (or more) of them is true. It works the same way as [[#and|<code>and</code>]], but only needs one condition to succeed rather than all of them.
<code>or (condition1, condition2, ...)</code>
* '''condition1, condition2, ...''' - the individual conditions to check, separated by commas. You can list two or more. '''or''' is true if '''at least one''' of them is true.
'''Example 1'''
<code> show page1
after page1 if (or (page1.interaction1 = "none", page1.interaction1 = "sometimes")) goto page3</code>
This shows '''page3''' if the response to '''interaction1''' on '''page1''' was '''either''' '''none''' '''or''' '''sometimes'''.
'''Example 2'''
<code>savevalue(currentuser(), "sport", "cardio") if (or( page1.interaction1 = "running", page2.interaction2 = "swimming"))</code>
This saves the variable '''sport''' if the end-user selected '''running''' for '''interaction1''' on '''page1''', '''or''' '''swimming''' for '''interaction2''' on '''page2''' (or both).
=P=
== <code> parsedate </code> ==
'''parsedate''' converts a date that has been entered or stored as text (for example, a response to a date-entry interaction) into a time value that can be used with commands such as [[#comparetimes|<code>comparetimes</code>]] and [[#currenttime|<code>currenttime</code>]].
<code>parsedate (datestring, "format")</code>
* '''datestring''' - the interaction response (or variable) containing the date as text, e.g. <code>signup.date_of_birth</code>.
* '''"format"''' - describes how that text is laid out, using the same letters as [[#printtime|<code>printtime</code>]] (see the table under '''printtime''' for the full list) - for example, <code>"yyyy-MM-dd"</code> for a date written like 1990-05-21.
'''Example 1'''
<code>set dob to parsedate(signup.date_of_birth, "yyyy-MM-dd")</code>
This converts the response given to the '''date_of_birth''' interaction on the '''signup''' page - entered in the format '''yyyy-MM-dd''', e.g. "1990-05-21" - into a time value, stored as the variable '''dob'''.
'''Example 2'''
<code>show screening_fail if (comparetimes(parsedate(signup.date_of_birth, "yyyy-MM-dd"), currenttime(), "days") < 6570)</code>
This shows the error message '''screening_fail''' if fewer than '''6570''' days (approximately 18 years) have passed between the date of birth entered by the end-user and now - for example, to screen out end-users who are under 18.


== <code> patternmatch </code> ==
== <code> patternmatch </code> ==


'''patternmatch''' checks whether the text an end-user has typed into a text-entry interaction matches a pattern you define - for example, a study code in a specific format.
<code>patternmatch ("pattern", interactionname)</code>
* '''"pattern"''' - the pattern of characters to match against, in quotation marks, written using '''Regular Expressions''' (see the table below for the basics).
* '''interactionname''' - the text-entry interaction whose response you want to check, e.g. <code>password</code>.
Some regular expression basics are described below - for more detailed information, you can find guides to "Regular Expressions" online.
{| class="wikitable"
!Character !! Example !! Comment
|-
|a
|a
|match a single lower-case character. Can be any character except <code>.?+*[]\^$()&#124;{}</code>
|-
|A
|A
|match a single upper-case character.
|-
|abc
|abc
|match the exact sequence of characters
|-
|.
|a
|. means any character
|-
|a?
|a
|? means zero or one of the preceding character
|-
|a*
|aaa
| * means any number of the preceding character
|-
|a+
|aaaa
| + means one or more of the preceding character
|-
|[abc]+
|cab
|[] means any character between the brackets
|-
|[^abc]+
|fed
|^ in a [] means none of the characters between the brackets
|-
|[0-9]
|1
|match any number between this range
|-
|[A-Z]
|LIFEGUIDE
|match any uppercase letter between this range
|-
|[a-z]
|lifeguide
|match any lowercase letter between this range
|-
|[A-Za-z]+
|LifeGuide
|Any uppercase or lowercase letters
|-
|a(bc)+d
|abcbcbcd
|() groups things together
|-
|ab&#124;cd
|cd
|&#124; means 'or'
|}
'''Example 1'''
This function is useful if you have assigned each participant in your study a different code, which they must enter correctly in order to take part - this ensures that only people who have been invited can gain access to the intervention. To do this, write an error message on the page containing your text-entry interaction, e.g.
<code> show nomatch if( not( patternmatch( "study[0-9][0-9]id[0-9][0-9]", password ) ) ) </code>
Here, the error message named '''nomatch''' is shown to users if the text they enter into the interaction named '''password''' doesn't fit the pattern in the square brackets. The pattern used here means a code shaped like '''studyxxidxx''', where each '''x''' is any digit from 0 to 9.
See also [[Adding Error Messages]] (example 7).
'''Example 2'''
'''patternmatch''' can also be used to direct users to specific conditions, sections or pages within an intervention, e.g.
<code> show page1 if (patternmatch("[0-9][0-9]a[0-9][0-9]", interaction1)) </code>
<code> show page2 if (patternmatch("[0-9][0-9]b[0-9][0-9]", interaction1)) </code>
Here, if a user enters a code shaped like xx'''a'''xx (where each x is a digit), they see '''page 1'''. If they enter xx'''b'''xx, they see '''page 2'''.
Instead of 0-9, you could use [a-z] to require any letter from a to z, or [a-z0-9] to allow either a letter or a number.
'''Note:''' '''patternmatch''' is case sensitive. '''[a-z]''' only matches lowercase letters, '''[A-Z]''' only matches uppercase letters, and '''[a-zA-Z]''' matches either.
[[Category: patternmatch]]


== <code> printtime </code> ==
== <code> printtime </code> ==


The <code>printtime</code> converts a value from a number to a string
'''printtime''' formats a time value so it can be displayed to the end-user as a readable date or time.
 
<code>printtime (timevalue, "format")</code>
 
* '''timevalue''' - the time you want to display, usually <code>currenttime()</code> or a time you've loaded with <code>loadvalue(...)</code>.
* '''"format"''' - describes how you want the time or date to look, built from the letters in the table below (e.g. <code>"H:m d-M-y"</code>).
 
The letters that can be used to build a format are:
 
{| class="wikitable"
|-
! Letter !! Description !! Example
|-
| G      || Era designator      || AD
|-
| y      || Year in two digits      || 01
|-
| yyyy      || Year in four digits      || 2001
|-
| M      || Month in year      || 7
|-
| MMMM      || Month in year      || July
|-
| d      || Day in month      || 10
|-
| h    || Hour in A.M./P.M.      || (1~12) 12
|-
| H      || Hour in day      || (0~23) 22
|-
| m      || Minute in hour    || 30
|-
| s      || Second in minute    || 55
|-
| E      || Day in week      || Tues
|-
| EEEE      || Day in week      || Tuesday
|-
| D    || Day in year      || 360
|-
| F      || Day of week in month  || 2 (second Wed. in July)
|-
| w      || Week in year    || 40
|-
| W      || Week in month    || 1
|-
| a      || A.M./P.M. marker    || PM
|-
| k      || Hour in day (1~24)  || 24
|-
| K    || Hour in A.M./P.M. (0~11)  || 10
|}
 
For digits, e.g. minutes, '''use the number of letters for the number of digits you want to display'''. For example, '''9:01:07''' should be written as <code>h:mm:ss</code>
 
''Advanced users, please see more options on [http://docs.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html#month Java SimpleDateFormat].''
 
'''printtime''' cannot display the difference between two times if that difference is greater than one day - to display a difference between two times, use '''comparetimes''' instead (see [[#comparetimes|<code>comparetimes</code>]], Example 2).
 
'''Example 1'''
 
This example shows how you can use '''printtime''' and '''currenttime''' together, to display the time and date a user is shown a specific page:
 
<code>show welcome</code>
 
<code>set welcome.time to printtime (currenttime (), "H:m d-M-y")</code>
 
Here, the word 'time' on the page '''welcome''' has been set as a variable. This displays the hour, minute, day, month and year at which the user is shown '''welcome''', in place of the word 'time'.
 
'''Example 2'''
 
This example shows how to mix your own words in with '''printtime''' and store the result as a user variable.
 
<code>set midnighttext to printtime (currenttime(), "'When you registered, it was 'H'hrs and 'm' minutes and 's' seconds since midnight'")
 
savevalue(currentuser(), "midnighttext", midnighttext)</code>
 
To add your own words or values in between the '''printtime''' format letters, wrap them in single quotes, as shown above. The output of '''printtime''' can be stored or saved like any other user variable, but note that it is always stored as text - it cannot be used in further number calculations.
 
'''Example 3'''
 
This example shows how to display particular times or dates you have saved earlier in your logic, such as when a user signed up and when they last logged back in.
 
<code>show signup</code>
 
<code>after signup if (and (makenewuser (signup.name, signup.password), savevalue(currentuser(), "currentlogintime", currenttime()))) goto welcome</code>
 
The first part of this logic sets up an account for the user, using the username (signup.name) and password (signup.password) they chose (see [[makenewuser]]). The second part uses '''currenttime''' to save the time the user signed up, as the variable <code>"currentlogintime"</code>.
 
<code>show welcome</code>
 
<code>set welcome.signuptime to printtime(loadvalue(currentuser(), "currentlogintime"), "H:m d-M-y")</code>
 
This displays the date and time the user signed up, on the page '''welcome''', in place of the word 'signuptime'.
 
<code>show login</code>
 
<code>after login if (and(savevalue(currentuser(), "lastlogintime", loadvalue(currentuser(), "currentlogintime")), savevalue(currentuser(), "currentlogintime", currenttime()))) goto loginhistory</code>
 
The first part of this reuses the variable <code>"currentlogintime"</code> to create a new variable, <code>"lastlogintime"</code> - so whatever time was previously stored as "when they signed up or last logged in" now becomes "when they '''last''' logged in". The second part then saves a fresh <code>"currentlogintime"</code>, recording that they have logged back in right now.
 
<code>show loginhistory</code>
 
<code>set loginhistory.lastlogintime to printtime (loadvalue(currentuser(), "lastlogintime"), "H:m d-M-y")</code>
 
<code>set loginhistory.currentlogintime to printtime (loadvalue(currentuser(), "currentlogintime"), "H:m d-M-y")</code>
 
This displays both the time the user last logged in ("lastlogintime") and the time they are logging in right now ("currentlogintime"), on the page '''loginhistory'''.
 
'''Example 4'''
 
In this example, a time saved in a previous session is loaded, and one week (in seconds) is added to it:
 
<code>savevalue (currentuser(), "goaltime", midnight())</code>
 
<code>show examplepage</code>
 
<code>set examplepage.weeklater to printtime((loadvalue(currentuser(),"goaltime")+delay), "E, d/M/y")</code>
 
The output of this might be '''Tue, 09/08/2016''', a week after the time the goal was set.
 
=R=


== <code> randomnumber </code> ==
== <code> randomnumber </code> ==


This command allows you to randomise your users into different groups and always follows the same formula:
'''randomnumber''' returns a random whole number within a range you choose, which is commonly used to randomly assign end-users into different groups.


<code> after page1 if (randomnumber (lowestvalue , highestvalue) = value) goto page3</code>
<code>randomnumber (lowestvalue, highestvalue)</code>
 
* '''lowestvalue''' - the smallest number that could be returned.
* '''highestvalue''' - the largest number that could be returned.
 
<code>after page1 if (randomnumber (lowestvalue, highestvalue) = value) goto page3</code>


For example:
For example:
Line 518: Line 1,294:
<code> show page3</code>
<code> show page3</code>


Thus, users that are randomised to group 1 will be directed to page3. Those that are randomised to group 0 will carry on to page2.
Here, end-users randomly assigned the number 1 are directed to '''page3'''; those assigned 0 carry on to '''page2'''.


A full tutorial for randomisation is available in the LifeGuide Researcher Help Manual.
A full tutorial on randomisation is available in the LifeGuide Researcher Help Manual.


== <code> replaceall </code> ==
== <code> replaceall </code> ==


This command can be used to do text replacements inside a string.
'''replaceall''' searches through a piece of text and replaces every occurrence of one thing with another.
 
<code>replaceall ("find", "replacewith", sourcetext)</code>
 
* '''"find"''' - the character(s) or text you want to search for, in quotation marks.
* '''"replacewith"''' - the character(s) or text to put in its place, in quotation marks.
* '''sourcetext''' - the text (or interaction response, or variable) to search within. This does not need quotation marks if it's a variable or interaction response.
 
'''Example 1'''
 
<code>replaceall ("c", "b", "caked car")</code>
 
This replaces every '''c''' in the text with '''b''', changing '''caked car''' into '''baked bar'''.
 
'''Example 2'''
 
This example shows a workaround for displaying a single-choice interaction's response back to the end-user. A workaround is needed because it is the '''Unique Response Name''' (not the response text shown on screen) that gets saved, and that would otherwise be shown back to the user.
 
<code>savevalue (currentuser(), "s1_home", replaceall("_", " ", s1_whattodo1.home)) if (or( s1_fatigue.home = "Other_aspects_of_home_life", s1_fatigue.home = "I_find_it_hard_doing_things_around_the_house",s1_fatigue.home = "I_cannot_get_out_and_about_the_way_I_used_to" ))</code>
 
This is specific to a drop-down single-choice interaction, where you want to show the response chosen for the interaction '''home''' on page '''s1_fatigue''' back to the end-user. Every underscore ('''_''') in the '''Unique Response Name''' is replaced with a space, so it reads naturally when shown back to the user.
 
You can then use feedback boxes and a container to show the response on a later page:
 
<code>show s1_fatigue2.home1 if (s1_fatigue.home = "Other_aspects_of_home_life")
show s1_fatigue2.home2 if (s1_fatigue.home = "I_find_it_hard_doing_things_around_the_house")
show s1_fatigue2.home3 if (s1_fatigue.home = "I_cannot_get_out_and_about_the_way_I_used_to")</code>
 
'''home1''' is a feedback textbox shown on '''s1_fatigue2''' if '''Other_aspects_of_home_life''' was chosen for the interaction '''home''' on page '''s1_fatigue'''.
 
== <code> resetpassword </code> ==
 
'''resetpassword''' lets an end-user reset a forgotten password. A new, temporary password is emailed to them, which they can use to log in - you can then add further pages to let them choose a new, memorable password once logged in.
 
<code>resetpassword (emailinteraction)</code>
 
* '''emailinteraction''' - the interaction where the end-user entered the email address registered to their account.
 
'''Example 1'''
 
<code>after resetpass if (resetpassword(resetpass.email)) goto resetpass_confirm </code>
 
This resets the end-user's password, as long as they enter a registered email address into the text-entry box called '''email''', and shows them the '''resetpass_confirm''' page.
 
Please see the '''Changing and resetting users passwords''' tutorial intervention on the LifeGuide Community Website for a full demo of how this logic is used.
 
== <code> round </code> ==
 
'''round''' rounds a number to the nearest whole number. For example, 5.49 rounds down to 5, and 5.5 rounds up to 6. This is useful for presenting calculated values (such as a quiz score) in a clean, whole-number form. To round to a set number of decimal places instead of a whole number, use [[#decimalplaces|<code>decimalplaces</code>]].
 
<code>round (number)</code>
 
* '''number''' - the number (or a variable/calculation that produces a number) you want to round.
 
'''Example 1'''
 
In this example we calculate 100 divided by 3 (33.333333). When we display it to the user on '''examplepage''' we want it to show 33.
 
<code>set exactthird to (100/3)
 
set approxthird to round(exactthird)
 
show examplepage
 
set examplepage.number to approxthird</code>
 
'''Example 2'''
 
In this example we mark a 3-item true/false quiz and present the score as a percentage.
 
<code>
show exp
 
if exp.question1="true" set q1 to 1
 
if exp.question1="false" set q1 to 0
 
if exp.question2="true" set q2 to 0
 
if exp.question2="false" set q2 to 1
 
if exp.question3="true" set q2 to 1
 
if exp.question3="false" set q2 to 0
 
set totalscore to (sum(q1,q2,q3))
 
set scorepercent to ((totalscore/3)*100)
 
set scoreround to round(scorepercent)
 
show results_page
 
set results_page.score to scoreround
 
</code>
 
First we mark the quiz, giving each question a score of 1 (correct) or 0 (incorrect). We add the scores together using '''sum'''. To turn this into a percentage, we divide the total by three and multiply by 100. We then round the result and display it to the user on '''results_page'''.
 
'''Example 3'''
 
In this example we round a large number to the nearest hundred.
 
<code>set largenumber to 1234567
 
set roundnumber to round(largenumber/100)
 
set largenumbertwo to (roundnumber*100)</code>
 
This takes 1,234,567, divides it by 100 to get 12,345.67, rounds that to the nearest whole number (12,346), then multiplies it back up by 100, giving a final result of 1,234,600.
 
=S=
 
== <code> save </code> ==
 
'''save''' stores all the responses an end-user gave on a page, so they can be shown again later using [[#load|<code>load</code>]] - either on another page in the same session, or in a future session. This requires end-users to have a registered account.
 
<code>save pagename for username</code>
 
* '''pagename''' - the page whose responses you want to store.
* '''username''' - the end-user this data belongs to. Use <code>currentuser()</code>.


'''Example'''
'''Example'''


In the following example the <code>replaceall</code> command is used to replace all the 'a's in a string to 'b's. So this would change 'I like apples a lot' to 'I like bpples b lot'
<code> show page1</code>
 
<code> save page1 for currentuser()</code>
 
Later in the logic (either in the same session, or a future one):
 
<code> show page20</code>
 
<code> set default page20.interaction2 to load page1.interaction1 for currentuser()</code>
 
* '''page1.interaction1''' - the previously-saved response you want to bring back.
* '''currentuser()''' - the end-user whose saved response you want.
 
So, '''page1''' is saved for the end-user in the first part of this logic. Then, when they reach '''page20''', the response they gave earlier for '''interaction1''' on '''page1''' is shown again, this time in '''interaction2''' on '''page20'''.
 
== <code> saveandload </code> ==
 
'''saveandload''' is used on a page that contains interactions. If the end-user clicks Next and then comes back to that same page later, it automatically shows them the responses they gave the last time they were there.
 
<code>saveandload pagename for username</code>
 
* '''pagename''' - the page whose responses should be remembered.
* '''username''' - the end-user this data belongs to. Use <code>currentuser()</code>.
 
'''Example 1'''
 
<code>show page1
 
saveandload page1 for currentuser()</code>
 
Every interaction on '''page1''' will be saved, and shown again automatically, each time the end-user returns to that page.
 
== <code> set </code> ==
 
'''set''' stores a value in a variable, which you can then refer to elsewhere in your logic. It is also used to perform calculations.
 
<code>set variablename to value</code>
 
* '''variablename''' - the name you choose for this variable.
* '''value''' - what you want to store: plain text (in quotation marks), a number, an interaction response, or the result of another command.
 
'''Example 1'''
 
Older interventions commonly used '''set''' to create a variable representing the current end-user's identifier, e.g.:
 
<code>set username to login.loginuname</code>
 
This sets the variable '''username''' to whatever the end-user typed into the interaction uniquely named '''loginuname''' (usually an email address) on the login page.
 
'''Current best practice is to skip this step entirely and use [[#currentuser|<code>currentuser()</code>]] directly''' wherever you need to identify the current end-user, instead of creating your own username variable. You may still see the pattern above in older interventions.
 
'''Example 2'''
 
You can also use '''set''' to store timing values, such as how many seconds are in a day, as named variables. This makes it easy to switch between short test timings and real timings, and reduces the risk of mistakes.
 
In this example, '''twelvemonth''' is set to the number of seconds in 12 months:
 
<code>set twelvemonth to "31536000"</code>
 
You can then use this in your login logic:
 
<code>after login if (comparetimes(loadvalue(currentuser(),"baselinetime"), currenttime(),"seconds") >= twelvemonth) goto studyfinished </code>
 
This shows the page '''studyfinished''' if it has been more than 12 months since '''baselinetime'''.
 
'''Example 3'''
 
You can also '''set''' fixed pieces of text, such as an email address, so you don't have to type it out repeatedly - for example, the study coordinator's email address:
 
<code>set studyemail to "study@soton.ac.uk" </code>
 
Place this logic near the top of your logic file. This way, if the study coordinator's email address ever changes, you only have to update it in one place.
 
You can also '''set''' the text and timings used in emails:
 
<code>set 3monthemail to "Thank you for taking part in The Reactivate Study. It is now time to complete your 3 month questionnaire. Your answers are very important to us. Please use the following link to login:\n\nwww.webaddress.co.uk\n\nIf you have any questions about the study, or no longer wish to participate, please contact us on study@soton.ac.uk\n\nFrom The Reactivate Team."</code>
 
<code>set oneday to "86400"
set oneweek to "604800"</code>
 
The advantages of setting text like this are:
* It's easy to change - you only have to update one line, rather than hunting through your whole logic file for every place the text appears.
* It's easy to find, since these lines are usually kept together near the top of the logic file.
 
Please see [[#sendemail|<code>sendemail</code>]] for more information on how to write email logic.
 
'''Example 4'''
 
'''set''' can also create a variable based on how an end-user responds to an interaction, which you can then use to tailor the rest of the intervention.
 
<code>show page1</code>
 
<code>set condition1 to and (page1.chooseoptions contains "optiona", page1.chooseoptions contains "optionc")</code>
 
<code>after page1 if condition1 goto page3</code>
 
Here, '''condition1''' is set if the end-user selects both '''optiona''' '''and''' '''optionc''' from the interaction '''chooseoptions''' on '''page1'''. Anyone in this condition is then sent to page 3, where they receive tailored information based on the options they chose.
 
'''Example 5'''
 
In this example, '''set''' is used to calculate a score. The number the end-user selects for the interaction 'dailyexercise' on page1 is multiplied by 5 to create their exercise score:
 
<code>set exercisescore to (page1.dailyexercise * 5)</code>
 
== <code> setemail </code> ==
 
'''setemail''' sets or updates the email address associated with a user's account. This is useful if you create accounts using an identifier other than a real email address (e.g. a study ID, using [[#makenewuser|<code>makenewuser</code>]]), but still want a real email address linked to the account - for example, so that '''sendemail''' and '''resetpassword''' work correctly for that user.
 
<code>setemail (username, emailaddress)</code>
 
* '''username''' - the account to update. Use <code>currentuser()</code>.
* '''emailaddress''' - the interaction where the end-user entered their real email address.
 
'''Example 1'''
 
<code>show signup
makenewuser(signup.studyid, signup.password)
setemail(currentuser(), signup.email_address)</code>
 
This creates a new user account using the '''studyid''' and '''password''' entered on the '''signup''' page, then sets the email address for that account to whatever was entered into the '''email_address''' interaction on the same page.
 
== <code> saveuniquevalue </code> ==
 
'''saveuniquevalue''' works in the same way as [[#savevalue|<code>savevalue</code>]], but with one extra check: if the value being saved is not unique (i.e. another end-user has already saved the exact same value for the same variable name), it returns '''false''' instead of saving it. You can use this to stop an end-user continuing until they enter a genuinely unique value, such as a study ID.
 
<code>saveuniquevalue (username, "valuename", value)</code>
 
* '''username''' - the end-user this data belongs to. Use <code>currentuser()</code>.
* '''"valuename"''' - a name you choose for this piece of data, in quotation marks.
* '''value''' - the response to check and save, e.g. an interaction response.
 
'''Example 1'''
 
To save a variable entered by an end-user, while checking it is unique:
 
<code>saveuniquevalue(currentuser(), "studyid", page1.interaction1)</code>
 
'''Example 2'''
 
If an end-user enters a value that turns out '''not''' to be unique, you can still let them continue with the intervention, while alerting the study coordinator by email:


<code>replaceall ("a", "b", "I like apples a lot")</code>
<code> after registration if (and(not(saveuniquevalue(currentuser(), "studyid", registration.interaction1)), sendemail( append(currentuser(),"not_unique"), "study@soton.ac.uk", "Participant - not unique", append("Participant ", loadvalue (currentuser(), "idnumber"), "has entered information that is not unique."),10) )) goto registrationfinish </code>


== <code> resetpassword </code> ==
For more information on '''saveuniquevalue''', [[How to check whether users have entered a unique value, e.g. Study ID code|please click here]].
 
[[Category: saveuniquevalue]]


== <code> savevalue </code> ==
== <code> savevalue </code> ==


The savevalue command allows you to save a variable for a username that can then be loaded again in later sessions.
'''savevalue''' stores a piece of information against a specific end-user's account, so it can be loaded again later - in the same session, or in a future one. Your end-users need to have a registered account for this to work.
 
<code>savevalue (username, "valuename", value)</code>
 
* '''username''' - the end-user this data belongs to. Use <code>currentuser()</code>.
* '''"valuename"''' - a name you choose for this piece of data, in quotation marks. This becomes the column heading for this data in your exported study data.
* '''value''' - the information to store. This can be plain text (in quotation marks), a number, an interaction response (e.g. <code>page1.interaction1</code>), or the result of another command (e.g. <code>currenttime()</code>).
 
Common uses include:
* creating and saving a new piece of information about a user
* saving a response an end-user has given to an interaction
* saving the current time
* marking a questionnaire or session as 'complete'
 
'''Example 1 - Create and save a text variable'''
 
<code>savevalue(currentuser(), "group", "web_support")</code>
 
This saves the text '''web_support''' as the variable '''group''' for the current end-user. '''group''' will be the column heading for this data in your '''User data''' export.
 
To load this value again later in your logic, use [[#loadvalue|<code>loadvalue</code>]] with the same variable name, '''group''':
 
<code>after page5 if (loadvalue(currentuser(), "group") = "web_support") goto page10</code>
 
'''Example 2 - Create and save a numeric variable'''
 
<code>savevalue(currentuser(), "work", 1)</code>
 
This saves the number '''1''' as the variable '''work'''. Again, '''work''' becomes the column heading for this data in your '''User data''' export.
 
You can use this to show feedback on a page in a later session:
 
<code>show s1area.summary if (loadvalue (currentuser(), "work")>0) </code>
 
This shows the feedback '''summary''' on page '''s1area''' if the variable '''work''' is greater than '''0'''.
 
'''Example 3 - Save a response an end-user has given to an interaction'''
 
<code>savevalue(currentuser(), "s1_fatigue", page1.interaction1)</code>
 
This saves the response given for '''interaction1''' on '''page1''' as the variable '''s1_fatigue''', for the current end-user.
 
To load this later in your logic:
 
<code>set page5.fatigue_score to loadvalue (currentuser(),"s1_fatigue")</code>
 
This loads '''s1_fatigue''' and displays it in the text box '''fatigue_score''' on '''page5'''. For this to work, '''fatigue_score''' needs to be [[How to set text as a printed variable| set as a printed variable]].
 
'''Example 4 - Save the current time'''
 
<code>savevalue(currentuser(), "s1_time", currenttime())</code>
 
This saves the current time as the variable '''s1_time'''.
 
You can load this later in your logic - for example, to stop end-users seeing session 2 until a week has passed:
 
<code>after login_successful if (comparetimes(loadvalue(currentuser(), "s1_time"), currenttime(), "seconds" ) > 604800) goto s2_welcome</code>
 
'''Example 5 - Mark a questionnaire or session as complete'''
 
<code>savevalue(currentuser(), "baselinecomplete", "yes")</code>
 
This creates the variable '''baselinecomplete''' and saves '''yes'''. You could also use a number instead, if you prefer:
 
<code>savevalue(currentuser(), "baselinecomplete", "1")</code>
 
You can then check this later in your logic, to see whether an end-user has completed their baseline questionnaire:
 
<code>after login_successful if (and( hasseen(currentuser(), "qintro"), (isempty(loadvalue(currentuser(), "baselinecomplete"))) )) goto q_notcomplete </code>
 
This shows the page '''q_notcomplete''' if the end-user has seen '''qintro''', but '''baselinecomplete''' is still empty (meaning they haven't yet finished the baseline questionnaire).
 
'''Tip:''' if you need to clear a saved value so a fresh answer can be stored, use [[#deletevalue|<code>deletevalue</code>]] before saving the new one.


== <code> sendemail </code> ==
== <code> sendemail </code> ==


This is the command for setting up e-mails to send out to the end-user at specific points in the intervention. The function for sending out an e-mail always uses the same basic formula:
'''sendemail''' schedules an email to be sent to an end-user (or anyone else, such as a study coordinator) at a chosen point in the intervention.


<code>after pagename1 if sendemail("unique name for e-mail", e-mail address, "Subject message for e-mail", "E-mail content", number in seconds indicating how long after the end-user views pagename1 that you want the e-mail sent out) goto pagename2</code>
<code>sendemail (uniquename, emailaddress, "subject", "content", delayinseconds)</code>


'''Example'''
* '''uniquename''' - a name that must be '''different for every email you send'''. Because many end-users will trigger the same line of logic, this is normally built with <code>append(currentuser(), "some_label")</code>, so each end-user gets their own unique version of the name. If you skip this and just use a fixed name, only the very first email sent with that name will go out - all later ones with the same name will be treated as duplicates and won't be sent.
* '''emailaddress''' - who the email should go to. This is often <code>currentuser()</code> (if end-users register with their email address), or a fixed address in quotation marks, such as <code>"study@example.ac.uk"</code>.
* '''"subject"''' - the email's subject line, in quotation marks.
* '''"content"''' - the body of the email, in quotation marks (this is often built up using '''append'''). Use <code>\n\n</code> to start a new paragraph.
* '''delayinseconds''' - how long to wait, in seconds, after the end-user reaches the page this logic is attached to, before the email is sent. Use a small number like <code>10</code> to send it almost immediately.
 
'''Example 1'''


<code>after page1 if sendemail("welcomeemail", login.email, "welcome to the intervention", "Thank you for registering for the lifestyle intervention. Please remember to check back regularly for more information.", 60) goto page1</code>
<code>sendemail (append(currentuser(),"welcome_email"),currentuser(),"You have successfully registered to Stress Less", append("Dear ", loadvalue (currentuser(), "firstname"), "\n\n", welcome), 10)</code>


In this example a welcome email will be sent to the e-mail address that the end-user has entered on the login page 60 seconds after they have clicked away from the page.  
Here, <code>append(currentuser(),"welcome_email")</code> builds the unique name for this email, by joining the end-user's identifier onto the label '''welcome_email'''. This matters because, without '''append''', every end-user's email would share the exact same name ('''welcome_email''') - only the first one sent would count as unique, and every other end-user's copy would be silently skipped.


A full tutorial is available for [[Sending Emails]] including details of how to send e-mails to a researcher or healthcare professional instead of the end-user.
A full tutorial is available for [[Sending Emails]], including details of how to send emails to a researcher or healthcare professional instead of the end-user.


== <code> sendtext </code> ==
== <code> sendtext </code> ==


This is the command for sending sms text messages to an end-user. It uses a similar basic formula as the command for sending email messages. The only differences are:
'''sendtext''' schedules an SMS text message to be sent to an end-user. It works in a similar way to '''sendemail''', with a few differences:
* it uses the end-user's mobile phone number instead of an e-mail address
* it uses the end-user's mobile phone number instead of an email address
* it does not need a subject message
* it doesn't need a subject line
* there is a restriction for how long a text message can be
* there is a limit on how long the message can be


<code>after page1 if sendsms ("welcometext", login.phone, "Thank you for registering for the lifestyle intervention. Please remember to check back regularly for more information.", 60) goto page1</code>
<code>sendtext ("uniquename", phonenumber, "message", delayinseconds)</code>


'''Note:''' You will need to set up an sms account for your intervention before you can send sms messages. See [[LifeGuide Community Website FAQs]] for more information.
* '''"uniquename"''' - a name that must be different for every text message, in the same way as for '''sendemail''' (usually built with <code>append(currentuser(), "some_label")</code>).
* '''phonenumber''' - the interaction (or variable) containing the end-user's mobile number.
* '''"message"''' - the text of the message, in quotation marks.
* '''delayinseconds''' - how long to wait, in seconds, before the message is sent.
 
<code>after page1 if sendtext ("welcometext", login.phone, "Thank you for registering for the lifestyle intervention. Please remember to check back regularly for more information.", 60) goto page1</code>
 
'''Note:''' you will need to set up an SMS account for your intervention before you can send text messages. See [[LifeGuide Community Website FAQs]] for more information.


== <code> stringlength </code> ==
== <code> stringlength </code> ==
'''stringlength''' tells you how many characters an end-user has typed into a free-text interaction.
<code>stringlength (interactionname)</code>
* '''interactionname''' - the free-text interaction to check, e.g. <code>username</code> (here, "username" is just the name given to this particular text box on the page - it is unrelated to the <code>currentuser()</code> identifier discussed elsewhere in this dictionary).
This is useful if, for example, you want end-users to create usernames of a specific minimum length. To use it, write an error message:
<code>show namemessage if (stringlength (username) < 5)</code>
Here, the error message '''namemessage''' is shown to users who have entered fewer than 5 characters into the interaction called '''username'''.
[[Category:Stringlength]]
[[Category:Error Messages]]


== <code> sum </code> ==
== <code> sum </code> ==


See <code>add</code>
Please see [[#add|<code>add</code>]].
 
== <code> show </code> ==
 
'''show''' is the first logic command you will need to know, and probably the one you will use most often. It displays each of your pages, in the order they are written in the logic - when an end-user clicks Next on a page, they move on to whichever page is written next.
 
<code>show pagename</code>
 
* '''pagename''' - the page to display next.
 
'''Example 1'''
 
<code>show page1
 
show page2
 
show page3
 
show page4</code>
 
Here, the end-user first sees '''page1'''. When they click Next, they see '''page2''', then '''page3''', and finally '''page4'''.
 
'''Note:''' before you can preview your intervention, every page must appear in a '''show''' command in the logic file at least once.
 
Because pages must have unique names, you can only write '''show pagename''' once for each page - but you '''can''' show the same page again later using [[#named|<code>named</code>]], or by using a Jump button on an earlier page.
 
=T=


== <code> timesincelogin </code> ==
== <code> timesincelogin </code> ==
'''timesincelogin''' tells you how much time has passed since an end-user last logged into the intervention.
<code>timesincelogin (username, "unit")</code>
* '''username''' - the end-user to check. Use <code>currentuser()</code>.
* '''"unit"''' - what you want the result measured in: <code>"seconds"</code>, <code>"minutes"</code>, <code>"hours"</code>, <code>"days"</code>, <code>"weeks"</code> or <code>"months"</code>.
There is no need to create your own username variable first - simply use <code>currentuser()</code> (see [[#currentuser|<code>currentuser()</code>]]).
'''Example'''
'''1.''' Show the page where you want to display how long it's been since the end-user last logged in (e.g. "time"):
<code> show </code> time
'''2.''' On that page, create a variable to hold the value (e.g. "secs"), using the 'set as variable' function, then set it using '''timesincelogin''':
<code> set </code> time.secs to <code> timesincelogin </code> (currentuser(), <code> "seconds"</code>)
This shows the end-user, on the page named "time", how many seconds have passed since they last logged in. You can repeat this step using <code>"minutes"</code>, <code>"hours"</code>, <code>"days"</code>, <code>"weeks"</code> or <code>"months"</code> instead, to display the same information in a different unit.
== <code> to </code> ==
'''to''' is used together with the [[#set|<code>set</code>]] command, as in <code>set variablename to value</code>. See '''set''' for full details and examples.
=U=
== <code> urlencode </code> ==
'''urlencode''' converts a piece of text into a form that is safe to use inside a web address (URL). This is an advanced command, needed only when you are building a dynamic URL (i.e. one that includes a variable that might contain spaces or symbols).
<code>urlencode (string)</code>
* '''string''' - the piece of text (often a variable) you want to make URL-safe.
Certain characters (such as ? and &) have special meaning inside a URL and must be converted into a different format so they don't break the link (for example, the '''&''' symbol becomes '''%26'''). '''urlencode''' takes care of this for you.
URL encoding is a common, standard technique - you can find more information here: http://en.wikipedia.org/wiki/Percent-encoding
[[Category: Error Messages]]

Latest revision as of 13:03, 22 July 2026

A quick reference guide to LifeGuide logic. For more detailed information, please refer to the How to... Guide.

It is important to insert Next buttons on your pages (instead of Jump buttons) whenever possible in order for your logic to work correctly. If you show a page and have a vital line of logic written after you show that page (such as randomisation or saving logic), or have error messages on that page, your intervention will not work correctly if you use a Jump button - you will jump to another page and skip parts of the logic in your logic file and Error Messages section.

Tip for new users: many of the examples below use a variable called username to represent the identifier of the currently logged-in end-user. Older interventions created this variable manually near the top of the logic file (see set). Current best practice is to use the built-in currentuser() function instead, which always returns the identifier of whoever is currently logged in, with nothing to set up first - simply use currentuser() anywhere you see username in an example below.

How to read the examples below: where a command takes information in brackets, e.g. savevalue(username, "valuename", value), each item inside the brackets is called an argument, and the commas separate one argument from the next. Most entries below list what each argument means and what you should put there. Text written in quotation marks (e.g. "seconds") must be typed exactly as shown, including the quotation marks themselves - this tells the intervention you mean a fixed piece of text, not a variable.

A

add

add can also be written as sum or +. It adds two or more numbers together - for example, several numeric responses, or scores you have calculated earlier in the logic.

add (value1, value2, value3, ...)

  • value1, value2, ... - the numbers you want to add together. Each one can be a plain number, an interaction response (e.g. page1.interaction1), or a variable you have already calculated (e.g. score1). You can list as many as you need, separated by commas.

Example 1

This can be used to perform a calculation using the end-user's responses to specific numeric value interactions:

set score1 to add (page1.interaction1, page1.interaction2, page1.interaction3)

Example 2

The add or sum commands can also be used to calculate variables that have been set earlier in the session:

set overallscore to sum (score1, score2, score3)

If you only ever need to add or subtract exactly two numbers, you can use + and - instead, for example:

set score to (100 - page1.interaction1)

Make sure you leave a space on either side of the - symbol.

after

after lets you run logic once a particular page has been shown to the end-user - for example, to check their answers and decide which page to send them to next.

after pagename if (condition) goto nextpage

  • pagename - the page this logic relates to. The logic will run once the end-user has been shown this page and clicked Next.
  • condition - (optional) something that must be true for the rest of the line to happen, e.g. a response given on that page. You can leave this out if you always want the logic to run.
  • nextpage - the page to send the end-user to if the condition is true.

You will use the after command regularly. It is most often combined with if and goto, as above, but any command in this dictionary can be used after a page in the same way.

Example 1

after page1 if (page1.interaction1 = "yes") goto page3 show page 2 show page3

In the above example, the end-user will be directed to page3 if they answered yes to interaction1 on page1. If they answered anything else, they will carry on to the next line of logic and will see page2.

Note: if you use after with goto, the page you send the user to (in the example above, page3) should not be the very next page in your logic - it needs to be a page further down, as shown above. Otherwise the end-user would see that page twice.

and

and can also be written as &&. It combines two or more conditions into one, and is only true when every condition inside it is true. It is commonly used to:

  • check that several responses have been given before showing tailored feedback
  • combine several checks into a single line of logic after a page

and (condition1, condition2, ...)

  • condition1, condition2, ... - the individual conditions to check, separated by commas. You can list two or more. and is only true if all of them are true.

Example 1

show page6 if (and(page3.exercise = "yes", page3.intensity = "moderate", page3.frequency = "three"))

End-users will be shown page6 only if they selected yes for the interaction exercise on page3, moderate for intensity on page3, and three for frequency on page3. If any one of those three answers is different, page6 will not be shown.

Example 2

after login_successful if (and( not(hasseen(currentuser(), "q_demographics")), (isempty (loadvalue(currentuser(), "baselinecomplete"))) )) goto q_intro

End-users will be shown q_intro if both of the following are true: they have not seen page q_demographics, and the variable baselinecomplete is empty (i.e. it hasn't been saved yet, because they haven't finished the baseline questionnaire).

append

append joins two or more pieces of text (and/or variables) together into a single, longer piece of text. A "piece of text" - also called a string - is anything written between quotation marks, such as "session1", or a variable that already holds text.

append (part1, part2, part3, ...)

  • part1, part2, ... - the pieces of text or variables you want to join together, in the order you want them joined, separated by commas. You can list as many as you need.

append is most often used with sendemail and cancelemail, to build a unique name for each email (see below), but it is useful anywhere you need to combine text.

Example 1

sendemail (append(currentuser(),"user_reg1"), currentuser(), "StressLess - Session 1 is ready", append("Dear ", loadvalue (currentuser(), "personsname"), "\n\n", reg_part1, reg_part2), 10)

In this example, append is used twice:

  • to join the current end-user's identifier onto a fixed piece of text, so that the email's name is unique to that end-user:

append (currentuser(),"user_reg1")

  • to build the text of the email out of several separate pieces:

append ("Dear ", loadvalue (currentuser(), "personsname"), "\n\n", reg_part1, reg_part2)

\n\n is a special code that means "start a new paragraph" in the email.

Example 2

cancelemail (append("user_regs2rem", currentuser()), currentuser())

Here, append joins a fixed label onto the end-user's identifier, to rebuild the same unique email name that was used when the email was first set up: append ("user_regs1", currentuser())

Example 3

append is not only useful for emails - it can also combine interaction responses, and the result can be saved with savevalue:

set fullname to append(registration.firstname, " ",registration.surname) savevalue(currentuser(),"fullname", fullname)

This takes the responses given to the firstname and surname interactions on the registration page and combines them (with a space in between) into a single variable called fullname.

Important: every item you pass to append must be a variable or a piece of text in quotation marks (even a single space, like " "). If you forget the quotation marks around plain text, it may not work.

Example 4

In this example, we add extra information onto a value that has already been saved, rather than replacing it:

savevalue(currentuser(), "oldgoals","RESULTS_") if isempty(loadvalue(currentuser(),"oldgoals")) set oldgoals to loadvalue(currentuser(),"oldgoals") savevalue(currentuser(), "oldgoals", (append(oldgoals,"_", printtime(currenttime(),"dMy"),"_", goalsetpage.newgoal)))

First, if the variable "oldgoals" doesn't exist yet, we create it and save a starting value. We then load whatever is currently stored in "oldgoals". Finally, we save "oldgoals" again, appending today's date and the new goal (from the page "goalsetpage") onto the end of whatever was already there. Underscores are used to separate each piece of data so it stays readable. Over time, this builds up a single variable that looks like this:

"RESULTS_181016_firstgoal_191016_secondgoal_221016_thirdgoal"

authenticateuser

authenticateuser checks that a username (or email address) and password entered by an end-user match a registered account. It is used together with makenewuser, which is the command that creates the account in the first place, and is normally written directly after the logic that shows your login page.

authenticateuser (username, password)

  • username - the page.interaction where the end-user typed their username or email address, e.g. login.username.
  • password - the page.interaction where the end-user typed their password, e.g. login.password.

authenticateuser can be used either in the main logic file, or inside a page's Error Messages tab.

Example 1

show login after login if (authenticateuser (login.username, login.password)) goto login_confirmation show login_fail show login_confirmation

Here the logic is written in the logic file. If the username and password entered on the login page match a registered account, the end-user is sent to login_confirmation. If not, they will see the login_fail page.

Example 2

show err1 if (isempty(username)) show err2 if (not(authenticateuser(username, password)))

Here the logic is written in the Error Messages tab of the login page itself. If the username and password entered do not match a registered account, the end-user sees the error message err2 and cannot move on to the next page.

B

begin

begin marks the start of a named section of logic, and is always paired with an end command that marks where the section finishes.

begin sectionname

  • sectionname - a name you choose for this section, e.g. session1. It must be different from any page or object name already used in your intervention.

If your intervention has separate sessions or groups (e.g. different weekly sessions, or different sets of pages for different study arms), grouping the related logic into a named section can make your logic file much easier to navigate.

A few things to remember:

  • Every begin must have a matching end.
  • All the logic that belongs to the section must sit between its begin and end.
  • You only ever need to close the section you are currently in, so you do not write the section's name after end - just end on its own.

Example 1

begin session1

show page1

show page2

end

This begins the section session1, shows page1 and page2, then ends session1. Both pages sit between begin session1 and end, so they belong to that section.

Example 2 - Beginning and ending a section within another section

begin stress

begin causes

show page1

show page2

end

begin relieve

show page3

show page4

end

end

This begins the outer section stress. Inside it, the section causes begins, showing page1 and page2; the first end closes causes. Then the section relieve begins, showing page3 and page4; the next end closes relieve. The final end closes the outer section, stress.

C

cancelemail

cancelemail stops an email that was previously scheduled with sendemail from being sent, as long as it hasn't gone out yet. You might use this to:

  • stop a reminder email if the end-user has already done the thing the reminder was about (e.g. logging in for a session)
  • stop a "nudge" email to a study coordinator if the end-user has since completed the questionnaire it was chasing

cancelemail (uniquename, emailaddress)

  • uniquename - must exactly match the unique name that was used when the email was originally set up with sendemail (this is usually built with append(currentuser(), "some_label") - see the examples below).
  • emailaddress - the address the (now cancelled) email would otherwise have been sent to.

Example 1

cancelemail(append(currentuser(), "email_session2r"), currentuser())

This cancels the email email_session2r for the current end-user. append rebuilds the same unique name (end-user identifier + email_session2r) that was used to schedule the email in the first place.

Example 2

cancelemail(append(currentuser(),"q1_notcomplete"), "study@test.ac.uk")

This cancels the email q1_notcomplete that was due to be sent to study@test.ac.uk (a fixed address, rather than the end-user's own address).

cancelsms

cancelsms stops a text message that was previously scheduled with sendtext from being sent, as long as it hasn't gone out yet. It works the same way as cancelemail, but for text messages.

after pagename if cancelsms ("uniquename", phonenumber) goto nextpage

  • "uniquename" - must exactly match the unique name used when the text message was originally scheduled with sendtext.
  • phonenumber - the phone number the (now cancelled) text message would otherwise have been sent to.

changepassword

changepassword lets an already-registered end-user change their password, as long as they can enter their current password correctly.

changepassword (username, oldpassword, newpassword)

  • username - the identifier for the end-user changing their password. Use currentuser().
  • oldpassword - the page.interaction where they entered their current password.
  • newpassword - the page.interaction where they entered their new, chosen password.

Please see the LifeGuide Community Website for a tutorial intervention showing how to build the pages and logic for this.

Example 1

after passworddetails if changepassword (currentuser(), passworddetails.old, passworddetails.new) goto confirmchange

This changes the end-user's password, as long as their current password is entered correctly into the interaction called old on the page passworddetails, and their new password is entered into the interaction called new on the same page.

checkemailvalidity

checkemailvalidity does a basic check that an email address entered by an end-user contains an @ symbol.

checkemailvalidity (interactionname)

  • interactionname - the interaction where the end-user typed their email address, e.g. email.

This command is normally used together with an error message, written in the Error Messages tab (please see Adding Error Messages for more information about writing error messages).

Example 1

show invalidemail if (not (checkemailvalidity (email)))

invalidemail is the name of an error message, shown when the interaction called email on this page doesn't contain a valid-looking address.

checkphonenumbervalidity

checkphonenumbervalidity checks that a mobile number entered by an end-user begins with +44 or 0.

checkphonenumbervalidity (interactionname)

  • interactionname - the interaction where the end-user typed their phone number, e.g. phone.

This command is normally used with an error message (please see Adding error messages for more information).

Example 1

show invalidnumber if (not (checkphonenumbervalidity (phone)))

invalidnumber is the name of the error message, shown when the interaction called phone on this page doesn't look like a valid number.

This check is designed for UK phone numbers only. If your study needs to accept international numbers, you will need to write your own error message logic instead.

checkuserenabled

checkuserenabled checks whether a user's account is currently enabled. An account can become disabled if, for example, a researcher disables it manually (e.g. because a participant has withdrawn from a study, or their account needs to be temporarily suspended).

checkuserenabled (usernameoremail)

  • usernameoremail - the identifier to check - usually the page.interaction where the end-user entered their username or email address while logging in.

checkuserenabled is most often used together with authenticateuser as part of your login logic, so that a user is only let in if they have entered the correct details and their account is still enabled.

Example 1

show login after login if (and(authenticateuser (login.username, login.password), checkuserenabled (login.username))) goto login_confirmation show login_fail show login_confirmation

The end-user is only directed to login_confirmation if the username and password they entered are correct and their account is enabled. If either check fails, they are shown the login_fail page.

checkuserexists

checkuserexists checks whether a username or email address has already been registered with the intervention - for example, to stop someone signing up twice with the same details.

checkuserexists (usernameoremail)

  • usernameoremail - the interaction where the end-user typed the username or email address you want to check, e.g. email.

This command is often used with an error message (please see the How to guide for details on how to write error messages).

Example 1

show registeredemail if (checkuserexists (email))

registeredemail is the name of the error message shown if the end-user enters an email address (into the interaction called email) that is already registered to another user.

comparetimes

comparetimes works out the difference between two points in time, and converts that difference into whichever unit you choose (seconds, minutes, hours, days, weeks or months).

comparetimes (time1, time2, "unit")

  • time1 - the earlier point in time you are comparing, e.g. a time you saved previously with loadvalue(currentuser(), "sometime").
  • time2 - the later point in time you are comparing, e.g. currenttime().
  • "unit" - what you want the difference measured in: "seconds", "minutes", "hours", "days", "weeks" or "months" (don't forget the s at the end of each one).

The result is time2 minus time1, converted into the unit you chose - so it will normally be a positive number if time2 is later than time1.

Example 1

This example shows how comparetimes can be used to control end-users' access to different sessions or pages within an intervention.

There is no need to create your own username variable before using comparetimes - simply use currentuser() wherever you need to identify the end-user (see currentuser()).

The order of your logic matters when using comparetimes:

1. Show the page users see before they are directed to a particular session (e.g. "mainpage"):

show mainpage

2. Write the logic that sends the user to a particular session or page, depending on how much time has passed:

after mainpage if ( comparetimes ( loadvalue ( currentuser(), "session4time") , currenttime ( ), "seconds" ) >= 120 ) goto endpage

This says: if at least 120 seconds (two minutes) have passed since the value "session4time" was saved, send the user to endpage.

after mainpage if ( comparetimes ( loadvalue ( currentuser(), "session3time" ), currenttime ( ), "seconds" ) >= 120 ) goto session4

This says: if at least two minutes have passed since session3 was completed, let the user continue to session4.

after mainpage if ( comparetimes ( loadvalue ( currentuser(), "session3time" ), currenttime ( ), "seconds" ) <= 120 ) goto waitpage

This says: if less than two minutes have passed since session3 was completed, send the user to a waitpage instead, since they cannot continue yet.

Repeat this pattern for every session or page you want to control access to. The variables "session3time" and "session4time" are created in step 3, below.

3. Finally, show the individual pages or sessions, and record the time each one was completed:

show waitpage

show session3

after session3 if ( savevalue ( currentuser(), "session3time", currenttime ( ) ) )goto session3end

show session3end

Using currenttime, this saves a new variable, "session3time", recording the moment the user completed session3. This is the value that comparetimes will read back in step 2.

So, altogether, this example compares the time a user completed a section of the intervention with the current time, to decide whether enough time has passed to let them continue.

Example 2

In this example we use comparetimes to break the time until Christmas 2016 down into weeks, days, hours, minutes and seconds, so it can be displayed to the user in a friendly way.

set timenow to (currenttime()) set christmas to (1482624000)

set weeks to (comparetimes(timenow,christmas,"weeks")) set days to (comparetimes(timenow,christmas,"days")) set hrs to (comparetimes(timenow,christmas,"hours")) set mins to (comparetimes(timenow,christmas,"minutes"))

set days2 to (days - (weeks*7)) set hrs2 to (hrs - (days*24)) set mins2 to (mins - (hrs*60)) set secs to ((christmas - timenow) - (mins*60))

This first uses comparetimes to work out the total difference between now and Christmas in weeks, in days, in hours and in minutes. But we don't want to display "total days" or "total hours" - we want a friendly breakdown, like a countdown timer would show (e.g. "2 weeks, 3 days, 4 hours...").

To do that, we take the total number of days and subtract the days already counted in the weeks figure, so what's left is less than 7. We do the same for hours (subtracting whole days) and minutes (subtracting whole hours).

For seconds, we simply take the raw difference between christmas and timenow and subtract the whole minutes we've already counted - there's no need to use comparetimes for this step, because currenttime is already measured in seconds.

To display the countdown on a page, the following logic can be used:

show intro set intro.hrs to hrs2 set intro.mins to mins2 set intro.secs to secs set intro.days to days2 set intro.weeks to weeks

contains

contains is used with multiple-choice interactions, to check whether one particular option was among those an end-user selected.

interactionname contains "value"

  • interactionname - the multiple-choice interaction to check, e.g. page1.exercise.
  • "value" - the Unique Response Name of the option you're checking for, in quotation marks.

Example 1

after page1 if (page1.exercise contains "none") goto page4

The end-user is directed to page4 if none was one of the options they selected for the interaction exercise on page1.

Example 2

after page1 if (or( page1.exercise contains "1day", page1.exercise contains "2days" )) goto page4

The end-user is shown page4 if they selected either 1day or 2days for the interaction exercise on page1.

converttointeger

Interactions where an end-user types in a number - such as a text-entry interaction asking for someone's age - store the response as text (a series of characters), not as a number. This means the response can't reliably be used with comparison commands (morethan, lessthan, etc.) or calculation commands (add, multiply, etc.) until it has been converted into a whole number. converttointeger does this conversion for you.

converttointeger (interactionname)

  • interactionname - the text-entry interaction whose response you want to convert, e.g. signup.age. The response should only contain digits (a whole number) for the conversion to work correctly.

Example 1

show screening_fail if (converttointeger(signup.age) < 18)

This shows the error message screening_fail if the number entered into the text-entry interaction age on the signup page converts to less than 18.

Example 2

savevalue(currentuser(), "age_years", converttointeger(signup.age))

This converts the text response given to the age interaction into a whole number, and saves it as the variable age_years for the current end-user, so it can be used in calculations later in the intervention.

countif

countif counts how many of a list of conditions are currently true - for example, how many interactions on a page an end-user has filled in.

countif (condition1, condition2, ...)

  • condition1, condition2, ... - the conditions to check, separated by commas. countif returns the number of these that are true.

Example

after page1 if (countif( not(isempty(page1.interaction1)), not(isempty(page1.interaction2)), not(isempty(page1.interaction3)), not(isempty(page1.interaction4)) ) < 3) goto page4

This checks four interactions on page1 and counts how many of them have not been left empty (i.e. how many the end-user has answered). If they have answered fewer than 3 of the 4, they are directed to page4.

currenttime

currenttime() returns the date and time at the exact moment it runs. It takes no arguments - it is always written with empty brackets, currenttime(), which tells the intervention this is a function rather than a variable you have created yourself.

You can use currenttime to record when something happened (by saving it), or to compare against a time you saved earlier (using comparetimes).

1. There is no need to create your own username variable before using currenttime - simply use currentuser() wherever you need to identify the end-user (see currentuser()).

2. To save the time a user completes a particular section of your intervention (in this example, "session 3"):

show session3

after session3 if ( savevalue ( currentuser(), "session3time", currenttime ( ) ) )goto session3end

show session3end

This saves the moment the user completes the session3 page as a new variable called "session3time".

3. currenttime can also be used as a reference point to compare against, which is particularly useful for putting time controls on when users can access particular sessions (see also comparetimes):

after mainpage if ( comparetimes ( loadvalue ( currentuser(), "session3time" ), currenttime ( ), "minutes" ) >= 120 ) goto session4

This lets the user continue to session 4 if it has been at least two hours since they completed session 3.

after mainpage if ( comparetimes ( loadvalue ( currentuser(), "session3time" ), currenttime ( ), "minutes" ) <= 120 ) goto waitpage

This sends the user to a "waitpage" instead, if less than two hours have passed since they completed session 3.

currentuser() and midnight() work the same way as currenttime() - all three are functions that take no arguments, so they are always written with empty brackets.

currentuser

currentuser() returns the identifier (i.e. the username) of whichever end-user is currently logged in to the intervention. It takes no arguments - it is always written with empty brackets, currentuser(). It can be used anywhere you would otherwise need a username variable - for example with savevalue, loadvalue, sendemail, hasseen and most other commands that refer to a specific end-user.

Best practice: older interventions had to create their own username variable near the top of the logic file, by loading it from the login or signup page (see set, Example 1). currentuser() removes the need for this step, because it always refers to whichever end-user is logged in at that point in the intervention - there is nothing to set up first. This is now the recommended way to refer to the current end-user throughout your logic.

Note: currentuser() only returns a sensible result once someone has actually logged in (for example, after authenticateuser or makenewuser has run successfully). Using it on a page shown before login, such as the login page itself, will not identify anyone.

Example 1

savevalue(currentuser(), "session1complete", "yes")

This saves the variable session1complete for whichever end-user is currently logged in - there is no need to set up a separate username variable first.

Example 2

show welcome set welcome.firstname to loadvalue(currentuser(), "firstname")

This loads the value firstname that was previously saved for the current end-user, and displays it on the page welcome in place of the word 'firstname'.

D

decimalplaces

decimalplaces rounds a number to a specified number of digits after the decimal point. For example, it would round 6.6666666 to 6.67 if you asked for 2 decimal places, or to 6.6667 for 4 decimal places. If you want to round to a whole number (0 decimal places), the simpler round command can be used instead.

decimalplaces (number, decimalplacecount)

  • number - the number (or a variable/calculation that produces a number) you want to shorten.
  • decimalplacecount - how many digits you want to keep after the decimal point.

You cannot use decimalplaces to abbreviate whole numbers to a number of significant figures (e.g. turning 1,234,567 into 1,234,600) by asking for a negative number of decimal places - a negative number here is simply treated as 0. To round a whole number like this, use round instead (see Example 3 of round).

Example 1

In this example we shorten a long decimal number to 4 decimal places.

set numberpi to decimalplaces(3.1415926,4)

This sets the value of numberpi to 3.1416.

Example 2

In this example we calculate the area of a circle and return the answer to 2 decimal places.

show circle_page

set cradius to circle_page.radius

set pi to 3.14159

set carea to ((cradius*cradius)*pi)

set careashort to decimalplaces(carea,2)

show results_page

set results_page.circle to careashort

First we get the radius from the user's response on circle_page. Then we set the value of pi. Then we calculate the area of the circle using the formula area = pi × (radius × radius). We then shorten the result to 2 decimal places for display, while still keeping the full, unrounded value stored in carea in case we want to use it in further calculations later (like the volume of a cylinder). On results_page we show the user the area of the circle, to 2 decimal places.

default

default sets an interaction on a page to show a previously saved value, so the end-user sees their earlier answer already filled in. It is used together with the save command - see save for an example.

To recall information the end-user entered earlier on the same page (rather than a different page or session), use saveandload instead.

deletevalue

deletevalue removes a value that was previously saved with savevalue. This is useful when you want to clear a saved value so a fresh answer can be stored later in the intervention - for example, because an end-user is updating information about themselves that can change over time.

deletevalue (username, "valuename")

  • username - the end-user whose saved value you want to remove. Use currentuser().
  • "valuename" - the exact name that was used when the value was originally saved with savevalue, in quotation marks.

Example 1

deletevalue(currentuser(), "currentgoal") savevalue(currentuser(), "currentgoal", goalpage.newgoal)

This deletes the previously saved value currentgoal for the current end-user, before saving a new response to the same variable. Deleting the old value first ensures that only the most recent goal is stored, rather than the new value being added alongside the old one.

divide

divide is used when performing calculations. The symbol / can also be used instead.

value1 / value2

  • value1 - the number being divided (the dividend).
  • value2 - the number to divide it by (the divisor).

Example 1

set score1 to (page1.interaction1 / page1.interaction2)

score1 is the result of dividing the response given for interaction1 by the response given for interaction2.

Example 2

set overallscore to (score1 / score2)

Here, overallscore is calculated by dividing score1 by score2, where both have already been calculated elsewhere in the logic.

E

else

else is used only together with if. It lets you specify something to do when the if condition on the line above is not met.

if not(or(isempty(page1.q1),isempty(page1.q2))) set page1_complete to 1

else set page1_complete to 0

This checks whether both interactions on page1 have been answered. If they have, page1_complete is set to 1. The else line then sets page1_complete to 0 if they have not both been answered.

end

end closes a section that was opened with begin. Please see begin for details and examples. end takes no arguments - you never need to repeat the section's name, since it always closes whichever section is currently open.

F

for

for is used together with the save and graph commands, to say which end-user a page or a piece of graph data belongs to (e.g. save page1 for currentuser()). See those entries for full examples.

G

getuserid

getuserid returns the database ID for a user - a number that LifeGuide generates automatically and that is unique to each account on that server. This can be useful if you need a short, unique identifier for a user without referring to their username or email address directly. It can also be included in your data export by ticking the User Number box when you export your data.

getuserid (username)

  • username - the end-user whose database ID you want. Use currentuser().

Example 1

getuserid(currentuser())

goto

goto is always used together with the after command. It tells the logic which page to send the end-user to next.

after pagename if (condition) goto nextpage

  • nextpage - the page the end-user should be sent to when the condition is true. See after for a full explanation and examples.

graph

graph is used together with the graph interaction, to plot information given by end-users onto a graph - for example, showing someone their weight or mood over time.

It always follows the same two-part pattern, and requires end-users to have a registered account.

1. Wherever you collect the data you want to plot, record it with:

graph interactionvalue to "variablename" for username

  • interactionvalue - the response you want to plot, written as page.interaction (e.g. progresschart.kg).
  • "variablename" - a name you choose for this piece of data, in quotation marks. Use the same name every time you record data for the same graph.
  • username - the end-user this data point belongs to. Use currentuser().

2. On the page where the graph interaction itself is shown, add a line to tell it which data to display:

set pagename.graph-1 to graph "variablename" for username

Here, pagename.graph-1 is the name LifeGuide automatically gives to a graph interaction (you can check the exact name in the interaction's properties), and "variablename" must match the name used when the data was recorded in step 1.

Example 1

In this example, the number entered into the interaction kg on the page progresschart is recorded as the data for a graph variable called "weight".

show progresschart graph progresschart.kg to "weight" for currentuser()

Later in the logic, on the page where the graph is actually displayed:

show weightgraph set weightgraph.graph-1 to graph "weight" for currentuser()

A full tutorial for using graphs will soon be available.

H

hasseen

hasseen checks whether an end-user has already been shown a particular page, so you can tailor what they see next based on their previous visits.

hasseen (username, "pagename", scope)

  • username - the end-user to check. Use currentuser().
  • "pagename" - the unique name of the page you want to check, in quotation marks.
  • scope - (optional, only relevant if your intervention uses sessions - see below) leave this out entirely to check previous sessions only, or write "true" to include the current session, or "this" to check the current session only.

Tip: if your intervention has more than one session, we recommend using savevalue and loadvalue instead of hasseen, since saved values can be corrected after your intervention has gone live if something goes wrong, whereas page-view history cannot.

Example 1

If you want to show end-users a different page each time they log in, depending on which sessions they have already seen, you can use hasseen like this:

show login

show s1welcome if (not(hasseen (currentuser(), "s1welcome")))

show s2welcome if (not(hasseen (currentuser(), "s2welcome")))

show s3welcome if (not(hasseen (currentuser(), "s3welcome")))

The first time someone logs in, they will see s1welcome. The next time, because they have already seen s1welcome, the logic skips that line and shows s2welcome instead, since they have not yet seen it.

Example 2

hasseen can also be used without not, to tailor the intervention for users who have already seen a page.

show s1_feeback2 if (hasseen (currentuser(), "s1_feedback1")))

show s1_feeback3 if (hasseen (currentuser(), "s1_feedback2")))

Using hasseen in sessions

If your intervention is split into sessions, the scope argument controls which sessions hasseen looks at:

show session2.interaction1 if (hasseen (currentuser(), "session1final"))

With no third argument, this shows interaction1 if the end-user has seen session1final in any previous session (but not the one they're currently in).

show session2.interaction1 if (hasseen (currentuser(), "session1final", "true"))

Adding "true" shows interaction1 if the end-user has seen session1final in any session, including the current one.

show session2.interaction1 if (hasseen (currentuser(), "session1final", "this"))

Adding "this" shows interaction1 only if the end-user has seen session1final earlier in the current session.

hmacencode

hmacencode is an advanced command that scrambles (encrypts) a piece of text so it cannot be read. There is no way to reverse this and get the original text back (it cannot be decrypted) - its main use is to check that data passed from one intervention to another has not been tampered with or corrupted along the way.

hmacencode (text, secretkey)

  • text - the piece of text you want to encode, in quotation marks (or a variable containing text).
  • secretkey - a password-like piece of text, shared between the systems that need to check the data, used to scramble it.

set encoded to hmacencode("This message is encoded", "secret")

I

if

if is always used together with another command (e.g. after, show, set). It is followed by a condition - something that can only be true or false, such as page1.interaction1 = "yes". The command in front of if is only carried out when that condition is true.

command if (condition)

  • condition - the thing being checked. This is often built using other commands from this dictionary, such as and, or, not, isempty or a comparison like =, < or >=.

isempty

isempty checks whether an end-user has given any response to an interaction - in other words, whether it has been left blank.

isempty (interactionname)

  • interactionname - the interaction to check, e.g. page1.interaction1.

Example 1

after page1 if (isempty (page1.interaction1)) goto page4

The end-user is directed to page4 if they left interaction1 on page1 blank.

Example 2

set none if (isempty (page1.interaction1))

If the end-user leaves interaction1 on page1 blank, the variable none is set.

L

load

load is always used together with save, to bring back a page's saved responses so they can be shown again. Please see save for details and an example.

loadvalue

loadvalue retrieves a value that was previously stored with savevalue.

loadvalue (username, "valuename")

  • username - the end-user whose data you want to retrieve. Use currentuser().
  • "valuename" - the exact name that was used when the value was saved with savevalue, in quotation marks.

Please see savevalue for full examples of saving and loading values together.

loggedin

loggedin() checks whether there is currently a logged-in end-user. It takes no arguments - it is always written with empty brackets, loggedin(). It returns true if someone is logged in, and false if not. This is useful for tailoring pages or navigation depending on whether someone is browsing your intervention as a registered, logged-in user - for example, to skip the login page for someone who is already logged in, or to hide content that should only be seen once someone has logged in.

Example 1

show login after login if (loggedin()) goto welcome_back show login_fail show welcome_back

This directs the end-user straight to welcome_back if they are already logged in (for example, if they still have an active session from earlier), skipping the need to log in again.

Example 2

show help_page show help_page.membersonly if (loggedin())

This shows the feedback box membersonly on help_page only to end-users who are currently logged in.

lessthan

lessthan compares two values. The symbol < can also be used instead.

value1 lessthan value2 (or value1 < value2)

  • value1 - the first value.
  • value2 - the value it's being compared against. The condition is true when value1 is smaller than value2.

This is used both for:

  • comparing numbers, e.g. interaction responses or calculated scores
  • comparing time, e.g. checking that less than a certain amount of time has passed since a previous session

Example 1

set condition1 if (page1.interaction1 < page1.interaction2)

Example 2

after login if (comparetimes (loadvalue(currentuser(), "session1_time"), currenttime(), "seconds" ) < 86400)

lessthanequal

lessthanequal works the same way as lessthan, but is also true when the two values are equal. The symbol <= can also be used instead.

value1 lessthanequal value2 (or value1 <= value2)

  • value1 - the first value.
  • value2 - the value it's being compared against. The condition is true when value1 is smaller than, or equal to, value2.

Example 1

set condition1 if (page1.interaction1 <= page1.interaction2)

Example 2

after login if (comparetimes (loadvalue(currentuser(), "session1_time"), currenttime(), "seconds" ) <= 86400)

M

makenewuser

makenewuser creates a new registered account for an end-user, using a username (or email address) and password that they choose.

makenewuser (username, password)

  • username - the page.interaction containing the identifier the end-user will log in with, e.g. signup.signup_username.
  • password - the page.interaction containing their chosen password, e.g. signup.signup_password. This interaction should always be set to the password interaction type in its properties panel - if it isn't, the password will be visible as the end-user types it, and will not be stored securely, which can leave users unable to log in later.

makenewuser both creates the account and signs the end-user in at the same time, so there is no need to also call authenticateuser straight afterwards.

Example

show signup

makenewuser(signup.signup_username, signup.signup_password)

The information the end-user enters into the signup_username and signup_password interactions is used to create their account.

Tip: if you create accounts using an identifier other than a real email address (for example, a study ID), you can still associate a real email address with the account afterwards using setemail, so that commands like sendemail and resetpassword work correctly.

midnight

midnight() is similar to currenttime(), but returns the time at midnight at the start of today, rather than right now. It takes no arguments - it is always written with empty brackets, midnight(). It's useful for scheduling something at a specific time of day, such as sending an email at 7am, one week after someone registers.

set delay7am to + (midnight(), 25200, (-1 * currenttime()))

This sets a variable called delay7am to: today's midnight, plus 25200 seconds, minus the time right now.

For example, at 10:30am on 2/9/2016, this would be 1472774400 + 25200 - 1472812200 = -12600.

Place this logic near the top of your logic file with your other set lines, or immediately before the sendemail logic that uses it.

delay7am can be replaced with a variable name of your choice. 25200 is the number of seconds since midnight that you want (in this case, 7 hours = 7am - you can change this to schedule a different time of day).

Your email logic would then look something like this:

sendemail (append(currentuser(),"welcome_email"),currentuser(),"You have successfully registered to Stress Less", append("Dear ", loadvalue (currentuser(), "firstname"), "\n\n", welcome), (delay7am+604800))

Because delay7am will be a negative number if the current time is already past 7am, you need to add at least one full day (in seconds) on top of it before using it as a delay - in the example above, one week (604800 seconds) has been added.

Remember to allow for the UK's clock changes between GMT and BST, and for time differences between the UK and other countries, if this matters for your study.

morethan

morethan compares two values. The symbol > can also be used instead.

value1 morethan value2 (or value1 > value2)

  • value1 - the first value.
  • value2 - the value it's being compared against. The condition is true when value1 is bigger than value2.

Example 1

set condition2 if (page1.interaction1 > page1.interaction2)

condition2 is set if the value given for interaction1 is greater than the value given for interaction2.

morethanequal

morethanequal works the same way as morethan, but is also true when the two values are equal. The symbol >= can also be used instead.

value1 morethanequal value2 (or value1 >= value2)

  • value1 - the first value.
  • value2 - the value it's being compared against. The condition is true when value1 is bigger than, or equal to, value2.

Example 1

set condition2 if (page1.interaction1 >= page1.interaction2)

condition2 is set if interaction1 is greater than or equal to interaction2.

multiply

multiply is used to multiply one value by another. The symbol * can also be used instead.

value1 * value2

  • value1 and value2 - the two numbers to multiply together. Each can come from an end-user's response to an interaction, or from a calculation performed elsewhere in the logic.

Example 1

set score1 to (page1.interaction1 * page1.interaction2)

The response to interaction1 is multiplied by the response to interaction2, and the result is saved as score1.

Example 2

set overallscore to (score1 * score2)

Here, score1 and score2 were already calculated earlier in the logic, and are multiplied together to give overallscore.

N

named

named lets you re-show a page you have already shown once, under a new alias.

show pagename named alias

  • pagename - the page you have already created and shown earlier in your logic.
  • alias - a new, unique name for this repeat showing of the page. This is not a separate page you need to create - it is simply a label that lets your logic refer to this particular instance of showing pagename again.

Example 1

show page1

[etc, etc]

show page1 named page2

[etc, etc]

show page1 named page3

(Here, [etc, etc] stands in for other lines of logic that would appear in a real intervention.) This shows the same page, page1, three times over the course of the intervention - once under its own name, then again labelled page2, then again labelled page3.

not

not reverses whether a condition is treated as true or false - a condition that would normally be true becomes false, and vice versa.

not (condition)

  • condition - the condition to reverse.

Example 1

set condition1 if (not (page1.interaction1 = "yes"))

condition1 is set if the end-user did not select yes for interaction1. This condition can then be used to tailor the rest of the intervention.

Note: don't confuse not with isempty. not refers to a specific response not being chosen; isempty refers to an interaction that hasn't been answered at all. The two can be combined to check for "an answer was given, and it wasn't blank":

Examples 2 and 3

after page1 if (not (isempty (page1.interaction1))) goto page5

Or:

set condition1 if (not (isempty (page1.interaction1)))

O

or

or can also be written as ||. It combines two or more conditions into one, and is true if any one (or more) of them is true. It works the same way as and, but only needs one condition to succeed rather than all of them.

or (condition1, condition2, ...)

  • condition1, condition2, ... - the individual conditions to check, separated by commas. You can list two or more. or is true if at least one of them is true.

Example 1

show page1 after page1 if (or (page1.interaction1 = "none", page1.interaction1 = "sometimes")) goto page3

This shows page3 if the response to interaction1 on page1 was either none or sometimes.

Example 2

savevalue(currentuser(), "sport", "cardio") if (or( page1.interaction1 = "running", page2.interaction2 = "swimming"))

This saves the variable sport if the end-user selected running for interaction1 on page1, or swimming for interaction2 on page2 (or both).

P

parsedate

parsedate converts a date that has been entered or stored as text (for example, a response to a date-entry interaction) into a time value that can be used with commands such as comparetimes and currenttime.

parsedate (datestring, "format")

  • datestring - the interaction response (or variable) containing the date as text, e.g. signup.date_of_birth.
  • "format" - describes how that text is laid out, using the same letters as printtime (see the table under printtime for the full list) - for example, "yyyy-MM-dd" for a date written like 1990-05-21.

Example 1

set dob to parsedate(signup.date_of_birth, "yyyy-MM-dd")

This converts the response given to the date_of_birth interaction on the signup page - entered in the format yyyy-MM-dd, e.g. "1990-05-21" - into a time value, stored as the variable dob.

Example 2

show screening_fail if (comparetimes(parsedate(signup.date_of_birth, "yyyy-MM-dd"), currenttime(), "days") < 6570)

This shows the error message screening_fail if fewer than 6570 days (approximately 18 years) have passed between the date of birth entered by the end-user and now - for example, to screen out end-users who are under 18.

patternmatch

patternmatch checks whether the text an end-user has typed into a text-entry interaction matches a pattern you define - for example, a study code in a specific format.

patternmatch ("pattern", interactionname)

  • "pattern" - the pattern of characters to match against, in quotation marks, written using Regular Expressions (see the table below for the basics).
  • interactionname - the text-entry interaction whose response you want to check, e.g. password.

Some regular expression basics are described below - for more detailed information, you can find guides to "Regular Expressions" online.

Character Example Comment
a a match a single lower-case character. Can be any character except .?+*[]\^$()|{}
A A match a single upper-case character.
abc abc match the exact sequence of characters
. a . means any character
a? a ? means zero or one of the preceding character
a* aaa * means any number of the preceding character
a+ aaaa + means one or more of the preceding character
[abc]+ cab [] means any character between the brackets
[^abc]+ fed ^ in a [] means none of the characters between the brackets
[0-9] 1 match any number between this range
[A-Z] LIFEGUIDE match any uppercase letter between this range
[a-z] lifeguide match any lowercase letter between this range
[A-Za-z]+ LifeGuide Any uppercase or lowercase letters
a(bc)+d abcbcbcd () groups things together
ab|cd cd | means 'or'

Example 1

This function is useful if you have assigned each participant in your study a different code, which they must enter correctly in order to take part - this ensures that only people who have been invited can gain access to the intervention. To do this, write an error message on the page containing your text-entry interaction, e.g.

show nomatch if( not( patternmatch( "study[0-9][0-9]id[0-9][0-9]", password ) ) )

Here, the error message named nomatch is shown to users if the text they enter into the interaction named password doesn't fit the pattern in the square brackets. The pattern used here means a code shaped like studyxxidxx, where each x is any digit from 0 to 9.

See also Adding Error Messages (example 7).

Example 2

patternmatch can also be used to direct users to specific conditions, sections or pages within an intervention, e.g.

show page1 if (patternmatch("[0-9][0-9]a[0-9][0-9]", interaction1))

show page2 if (patternmatch("[0-9][0-9]b[0-9][0-9]", interaction1))

Here, if a user enters a code shaped like xxaxx (where each x is a digit), they see page 1. If they enter xxbxx, they see page 2.

Instead of 0-9, you could use [a-z] to require any letter from a to z, or [a-z0-9] to allow either a letter or a number.

Note: patternmatch is case sensitive. [a-z] only matches lowercase letters, [A-Z] only matches uppercase letters, and [a-zA-Z] matches either.

printtime

printtime formats a time value so it can be displayed to the end-user as a readable date or time.

printtime (timevalue, "format")

  • timevalue - the time you want to display, usually currenttime() or a time you've loaded with loadvalue(...).
  • "format" - describes how you want the time or date to look, built from the letters in the table below (e.g. "H:m d-M-y").

The letters that can be used to build a format are:

Letter Description Example
G Era designator AD
y Year in two digits 01
yyyy Year in four digits 2001
M Month in year 7
MMMM Month in year July
d Day in month 10
h Hour in A.M./P.M. (1~12) 12
H Hour in day (0~23) 22
m Minute in hour 30
s Second in minute 55
E Day in week Tues
EEEE Day in week Tuesday
D Day in year 360
F Day of week in month 2 (second Wed. in July)
w Week in year 40
W Week in month 1
a A.M./P.M. marker PM
k Hour in day (1~24) 24
K Hour in A.M./P.M. (0~11) 10

For digits, e.g. minutes, use the number of letters for the number of digits you want to display. For example, 9:01:07 should be written as h:mm:ss

Advanced users, please see more options on Java SimpleDateFormat.

printtime cannot display the difference between two times if that difference is greater than one day - to display a difference between two times, use comparetimes instead (see comparetimes, Example 2).

Example 1

This example shows how you can use printtime and currenttime together, to display the time and date a user is shown a specific page:

show welcome

set welcome.time to printtime (currenttime (), "H:m d-M-y")

Here, the word 'time' on the page welcome has been set as a variable. This displays the hour, minute, day, month and year at which the user is shown welcome, in place of the word 'time'.

Example 2

This example shows how to mix your own words in with printtime and store the result as a user variable.

set midnighttext to printtime (currenttime(), "'When you registered, it was 'H'hrs and 'm' minutes and 's' seconds since midnight'")

savevalue(currentuser(), "midnighttext", midnighttext)

To add your own words or values in between the printtime format letters, wrap them in single quotes, as shown above. The output of printtime can be stored or saved like any other user variable, but note that it is always stored as text - it cannot be used in further number calculations.

Example 3

This example shows how to display particular times or dates you have saved earlier in your logic, such as when a user signed up and when they last logged back in.

show signup

after signup if (and (makenewuser (signup.name, signup.password), savevalue(currentuser(), "currentlogintime", currenttime()))) goto welcome

The first part of this logic sets up an account for the user, using the username (signup.name) and password (signup.password) they chose (see makenewuser). The second part uses currenttime to save the time the user signed up, as the variable "currentlogintime".

show welcome

set welcome.signuptime to printtime(loadvalue(currentuser(), "currentlogintime"), "H:m d-M-y")

This displays the date and time the user signed up, on the page welcome, in place of the word 'signuptime'.

show login

after login if (and(savevalue(currentuser(), "lastlogintime", loadvalue(currentuser(), "currentlogintime")), savevalue(currentuser(), "currentlogintime", currenttime()))) goto loginhistory

The first part of this reuses the variable "currentlogintime" to create a new variable, "lastlogintime" - so whatever time was previously stored as "when they signed up or last logged in" now becomes "when they last logged in". The second part then saves a fresh "currentlogintime", recording that they have logged back in right now.

show loginhistory

set loginhistory.lastlogintime to printtime (loadvalue(currentuser(), "lastlogintime"), "H:m d-M-y")

set loginhistory.currentlogintime to printtime (loadvalue(currentuser(), "currentlogintime"), "H:m d-M-y")

This displays both the time the user last logged in ("lastlogintime") and the time they are logging in right now ("currentlogintime"), on the page loginhistory.

Example 4

In this example, a time saved in a previous session is loaded, and one week (in seconds) is added to it:

savevalue (currentuser(), "goaltime", midnight())

show examplepage

set examplepage.weeklater to printtime((loadvalue(currentuser(),"goaltime")+delay), "E, d/M/y")

The output of this might be Tue, 09/08/2016, a week after the time the goal was set.

R

randomnumber

randomnumber returns a random whole number within a range you choose, which is commonly used to randomly assign end-users into different groups.

randomnumber (lowestvalue, highestvalue)

  • lowestvalue - the smallest number that could be returned.
  • highestvalue - the largest number that could be returned.

after page1 if (randomnumber (lowestvalue, highestvalue) = value) goto page3

For example:

after page1 if (randomnumber (0, 1) = 1) goto page3

show page2

show page3

Here, end-users randomly assigned the number 1 are directed to page3; those assigned 0 carry on to page2.

A full tutorial on randomisation is available in the LifeGuide Researcher Help Manual.

replaceall

replaceall searches through a piece of text and replaces every occurrence of one thing with another.

replaceall ("find", "replacewith", sourcetext)

  • "find" - the character(s) or text you want to search for, in quotation marks.
  • "replacewith" - the character(s) or text to put in its place, in quotation marks.
  • sourcetext - the text (or interaction response, or variable) to search within. This does not need quotation marks if it's a variable or interaction response.

Example 1

replaceall ("c", "b", "caked car")

This replaces every c in the text with b, changing caked car into baked bar.

Example 2

This example shows a workaround for displaying a single-choice interaction's response back to the end-user. A workaround is needed because it is the Unique Response Name (not the response text shown on screen) that gets saved, and that would otherwise be shown back to the user.

savevalue (currentuser(), "s1_home", replaceall("_", " ", s1_whattodo1.home)) if (or( s1_fatigue.home = "Other_aspects_of_home_life", s1_fatigue.home = "I_find_it_hard_doing_things_around_the_house",s1_fatigue.home = "I_cannot_get_out_and_about_the_way_I_used_to" ))

This is specific to a drop-down single-choice interaction, where you want to show the response chosen for the interaction home on page s1_fatigue back to the end-user. Every underscore (_) in the Unique Response Name is replaced with a space, so it reads naturally when shown back to the user.

You can then use feedback boxes and a container to show the response on a later page:

show s1_fatigue2.home1 if (s1_fatigue.home = "Other_aspects_of_home_life") show s1_fatigue2.home2 if (s1_fatigue.home = "I_find_it_hard_doing_things_around_the_house") show s1_fatigue2.home3 if (s1_fatigue.home = "I_cannot_get_out_and_about_the_way_I_used_to")

home1 is a feedback textbox shown on s1_fatigue2 if Other_aspects_of_home_life was chosen for the interaction home on page s1_fatigue.

resetpassword

resetpassword lets an end-user reset a forgotten password. A new, temporary password is emailed to them, which they can use to log in - you can then add further pages to let them choose a new, memorable password once logged in.

resetpassword (emailinteraction)

  • emailinteraction - the interaction where the end-user entered the email address registered to their account.

Example 1

after resetpass if (resetpassword(resetpass.email)) goto resetpass_confirm

This resets the end-user's password, as long as they enter a registered email address into the text-entry box called email, and shows them the resetpass_confirm page.

Please see the Changing and resetting users passwords tutorial intervention on the LifeGuide Community Website for a full demo of how this logic is used.

round

round rounds a number to the nearest whole number. For example, 5.49 rounds down to 5, and 5.5 rounds up to 6. This is useful for presenting calculated values (such as a quiz score) in a clean, whole-number form. To round to a set number of decimal places instead of a whole number, use decimalplaces.

round (number)

  • number - the number (or a variable/calculation that produces a number) you want to round.

Example 1

In this example we calculate 100 divided by 3 (33.333333). When we display it to the user on examplepage we want it to show 33.

set exactthird to (100/3)

set approxthird to round(exactthird)

show examplepage

set examplepage.number to approxthird

Example 2

In this example we mark a 3-item true/false quiz and present the score as a percentage.

show exp

if exp.question1="true" set q1 to 1

if exp.question1="false" set q1 to 0

if exp.question2="true" set q2 to 0

if exp.question2="false" set q2 to 1

if exp.question3="true" set q2 to 1

if exp.question3="false" set q2 to 0

set totalscore to (sum(q1,q2,q3))

set scorepercent to ((totalscore/3)*100)

set scoreround to round(scorepercent)

show results_page

set results_page.score to scoreround

First we mark the quiz, giving each question a score of 1 (correct) or 0 (incorrect). We add the scores together using sum. To turn this into a percentage, we divide the total by three and multiply by 100. We then round the result and display it to the user on results_page.

Example 3

In this example we round a large number to the nearest hundred.

set largenumber to 1234567

set roundnumber to round(largenumber/100)

set largenumbertwo to (roundnumber*100)

This takes 1,234,567, divides it by 100 to get 12,345.67, rounds that to the nearest whole number (12,346), then multiplies it back up by 100, giving a final result of 1,234,600.

S

save

save stores all the responses an end-user gave on a page, so they can be shown again later using load - either on another page in the same session, or in a future session. This requires end-users to have a registered account.

save pagename for username

  • pagename - the page whose responses you want to store.
  • username - the end-user this data belongs to. Use currentuser().

Example

show page1

save page1 for currentuser()

Later in the logic (either in the same session, or a future one):

show page20

set default page20.interaction2 to load page1.interaction1 for currentuser()

  • page1.interaction1 - the previously-saved response you want to bring back.
  • currentuser() - the end-user whose saved response you want.

So, page1 is saved for the end-user in the first part of this logic. Then, when they reach page20, the response they gave earlier for interaction1 on page1 is shown again, this time in interaction2 on page20.

saveandload

saveandload is used on a page that contains interactions. If the end-user clicks Next and then comes back to that same page later, it automatically shows them the responses they gave the last time they were there.

saveandload pagename for username

  • pagename - the page whose responses should be remembered.
  • username - the end-user this data belongs to. Use currentuser().

Example 1

show page1

saveandload page1 for currentuser()

Every interaction on page1 will be saved, and shown again automatically, each time the end-user returns to that page.

set

set stores a value in a variable, which you can then refer to elsewhere in your logic. It is also used to perform calculations.

set variablename to value

  • variablename - the name you choose for this variable.
  • value - what you want to store: plain text (in quotation marks), a number, an interaction response, or the result of another command.

Example 1

Older interventions commonly used set to create a variable representing the current end-user's identifier, e.g.:

set username to login.loginuname

This sets the variable username to whatever the end-user typed into the interaction uniquely named loginuname (usually an email address) on the login page.

Current best practice is to skip this step entirely and use currentuser() directly wherever you need to identify the current end-user, instead of creating your own username variable. You may still see the pattern above in older interventions.

Example 2

You can also use set to store timing values, such as how many seconds are in a day, as named variables. This makes it easy to switch between short test timings and real timings, and reduces the risk of mistakes.

In this example, twelvemonth is set to the number of seconds in 12 months:

set twelvemonth to "31536000"

You can then use this in your login logic:

after login if (comparetimes(loadvalue(currentuser(),"baselinetime"), currenttime(),"seconds") >= twelvemonth) goto studyfinished

This shows the page studyfinished if it has been more than 12 months since baselinetime.

Example 3

You can also set fixed pieces of text, such as an email address, so you don't have to type it out repeatedly - for example, the study coordinator's email address:

set studyemail to "study@soton.ac.uk"

Place this logic near the top of your logic file. This way, if the study coordinator's email address ever changes, you only have to update it in one place.

You can also set the text and timings used in emails:

set 3monthemail to "Thank you for taking part in The Reactivate Study. It is now time to complete your 3 month questionnaire. Your answers are very important to us. Please use the following link to login:\n\nwww.webaddress.co.uk\n\nIf you have any questions about the study, or no longer wish to participate, please contact us on study@soton.ac.uk\n\nFrom The Reactivate Team."

set oneday to "86400" set oneweek to "604800"

The advantages of setting text like this are:

  • It's easy to change - you only have to update one line, rather than hunting through your whole logic file for every place the text appears.
  • It's easy to find, since these lines are usually kept together near the top of the logic file.

Please see sendemail for more information on how to write email logic.

Example 4

set can also create a variable based on how an end-user responds to an interaction, which you can then use to tailor the rest of the intervention.

show page1

set condition1 to and (page1.chooseoptions contains "optiona", page1.chooseoptions contains "optionc")

after page1 if condition1 goto page3

Here, condition1 is set if the end-user selects both optiona and optionc from the interaction chooseoptions on page1. Anyone in this condition is then sent to page 3, where they receive tailored information based on the options they chose.

Example 5

In this example, set is used to calculate a score. The number the end-user selects for the interaction 'dailyexercise' on page1 is multiplied by 5 to create their exercise score:

set exercisescore to (page1.dailyexercise * 5)

setemail

setemail sets or updates the email address associated with a user's account. This is useful if you create accounts using an identifier other than a real email address (e.g. a study ID, using makenewuser), but still want a real email address linked to the account - for example, so that sendemail and resetpassword work correctly for that user.

setemail (username, emailaddress)

  • username - the account to update. Use currentuser().
  • emailaddress - the interaction where the end-user entered their real email address.

Example 1

show signup makenewuser(signup.studyid, signup.password) setemail(currentuser(), signup.email_address)

This creates a new user account using the studyid and password entered on the signup page, then sets the email address for that account to whatever was entered into the email_address interaction on the same page.

saveuniquevalue

saveuniquevalue works in the same way as savevalue, but with one extra check: if the value being saved is not unique (i.e. another end-user has already saved the exact same value for the same variable name), it returns false instead of saving it. You can use this to stop an end-user continuing until they enter a genuinely unique value, such as a study ID.

saveuniquevalue (username, "valuename", value)

  • username - the end-user this data belongs to. Use currentuser().
  • "valuename" - a name you choose for this piece of data, in quotation marks.
  • value - the response to check and save, e.g. an interaction response.

Example 1

To save a variable entered by an end-user, while checking it is unique:

saveuniquevalue(currentuser(), "studyid", page1.interaction1)

Example 2

If an end-user enters a value that turns out not to be unique, you can still let them continue with the intervention, while alerting the study coordinator by email:

after registration if (and(not(saveuniquevalue(currentuser(), "studyid", registration.interaction1)), sendemail( append(currentuser(),"not_unique"), "study@soton.ac.uk", "Participant - not unique", append("Participant ", loadvalue (currentuser(), "idnumber"), "has entered information that is not unique."),10) )) goto registrationfinish

For more information on saveuniquevalue, please click here.

savevalue

savevalue stores a piece of information against a specific end-user's account, so it can be loaded again later - in the same session, or in a future one. Your end-users need to have a registered account for this to work.

savevalue (username, "valuename", value)

  • username - the end-user this data belongs to. Use currentuser().
  • "valuename" - a name you choose for this piece of data, in quotation marks. This becomes the column heading for this data in your exported study data.
  • value - the information to store. This can be plain text (in quotation marks), a number, an interaction response (e.g. page1.interaction1), or the result of another command (e.g. currenttime()).

Common uses include:

  • creating and saving a new piece of information about a user
  • saving a response an end-user has given to an interaction
  • saving the current time
  • marking a questionnaire or session as 'complete'

Example 1 - Create and save a text variable

savevalue(currentuser(), "group", "web_support")

This saves the text web_support as the variable group for the current end-user. group will be the column heading for this data in your User data export.

To load this value again later in your logic, use loadvalue with the same variable name, group:

after page5 if (loadvalue(currentuser(), "group") = "web_support") goto page10

Example 2 - Create and save a numeric variable

savevalue(currentuser(), "work", 1)

This saves the number 1 as the variable work. Again, work becomes the column heading for this data in your User data export.

You can use this to show feedback on a page in a later session:

show s1area.summary if (loadvalue (currentuser(), "work")>0)

This shows the feedback summary on page s1area if the variable work is greater than 0.

Example 3 - Save a response an end-user has given to an interaction

savevalue(currentuser(), "s1_fatigue", page1.interaction1)

This saves the response given for interaction1 on page1 as the variable s1_fatigue, for the current end-user.

To load this later in your logic:

set page5.fatigue_score to loadvalue (currentuser(),"s1_fatigue")

This loads s1_fatigue and displays it in the text box fatigue_score on page5. For this to work, fatigue_score needs to be set as a printed variable.

Example 4 - Save the current time

savevalue(currentuser(), "s1_time", currenttime())

This saves the current time as the variable s1_time.

You can load this later in your logic - for example, to stop end-users seeing session 2 until a week has passed:

after login_successful if (comparetimes(loadvalue(currentuser(), "s1_time"), currenttime(), "seconds" ) > 604800) goto s2_welcome

Example 5 - Mark a questionnaire or session as complete

savevalue(currentuser(), "baselinecomplete", "yes")

This creates the variable baselinecomplete and saves yes. You could also use a number instead, if you prefer:

savevalue(currentuser(), "baselinecomplete", "1")

You can then check this later in your logic, to see whether an end-user has completed their baseline questionnaire:

after login_successful if (and( hasseen(currentuser(), "qintro"), (isempty(loadvalue(currentuser(), "baselinecomplete"))) )) goto q_notcomplete

This shows the page q_notcomplete if the end-user has seen qintro, but baselinecomplete is still empty (meaning they haven't yet finished the baseline questionnaire).

Tip: if you need to clear a saved value so a fresh answer can be stored, use deletevalue before saving the new one.

sendemail

sendemail schedules an email to be sent to an end-user (or anyone else, such as a study coordinator) at a chosen point in the intervention.

sendemail (uniquename, emailaddress, "subject", "content", delayinseconds)

  • uniquename - a name that must be different for every email you send. Because many end-users will trigger the same line of logic, this is normally built with append(currentuser(), "some_label"), so each end-user gets their own unique version of the name. If you skip this and just use a fixed name, only the very first email sent with that name will go out - all later ones with the same name will be treated as duplicates and won't be sent.
  • emailaddress - who the email should go to. This is often currentuser() (if end-users register with their email address), or a fixed address in quotation marks, such as "study@example.ac.uk".
  • "subject" - the email's subject line, in quotation marks.
  • "content" - the body of the email, in quotation marks (this is often built up using append). Use \n\n to start a new paragraph.
  • delayinseconds - how long to wait, in seconds, after the end-user reaches the page this logic is attached to, before the email is sent. Use a small number like 10 to send it almost immediately.

Example 1

sendemail (append(currentuser(),"welcome_email"),currentuser(),"You have successfully registered to Stress Less", append("Dear ", loadvalue (currentuser(), "firstname"), "\n\n", welcome), 10)

Here, append(currentuser(),"welcome_email") builds the unique name for this email, by joining the end-user's identifier onto the label welcome_email. This matters because, without append, every end-user's email would share the exact same name (welcome_email) - only the first one sent would count as unique, and every other end-user's copy would be silently skipped.

A full tutorial is available for Sending Emails, including details of how to send emails to a researcher or healthcare professional instead of the end-user.

sendtext

sendtext schedules an SMS text message to be sent to an end-user. It works in a similar way to sendemail, with a few differences:

  • it uses the end-user's mobile phone number instead of an email address
  • it doesn't need a subject line
  • there is a limit on how long the message can be

sendtext ("uniquename", phonenumber, "message", delayinseconds)

  • "uniquename" - a name that must be different for every text message, in the same way as for sendemail (usually built with append(currentuser(), "some_label")).
  • phonenumber - the interaction (or variable) containing the end-user's mobile number.
  • "message" - the text of the message, in quotation marks.
  • delayinseconds - how long to wait, in seconds, before the message is sent.

after page1 if sendtext ("welcometext", login.phone, "Thank you for registering for the lifestyle intervention. Please remember to check back regularly for more information.", 60) goto page1

Note: you will need to set up an SMS account for your intervention before you can send text messages. See LifeGuide Community Website FAQs for more information.

stringlength

stringlength tells you how many characters an end-user has typed into a free-text interaction.

stringlength (interactionname)

  • interactionname - the free-text interaction to check, e.g. username (here, "username" is just the name given to this particular text box on the page - it is unrelated to the currentuser() identifier discussed elsewhere in this dictionary).

This is useful if, for example, you want end-users to create usernames of a specific minimum length. To use it, write an error message:

show namemessage if (stringlength (username) < 5)

Here, the error message namemessage is shown to users who have entered fewer than 5 characters into the interaction called username.

sum

Please see add.

show

show is the first logic command you will need to know, and probably the one you will use most often. It displays each of your pages, in the order they are written in the logic - when an end-user clicks Next on a page, they move on to whichever page is written next.

show pagename

  • pagename - the page to display next.

Example 1

show page1

show page2

show page3

show page4

Here, the end-user first sees page1. When they click Next, they see page2, then page3, and finally page4.

Note: before you can preview your intervention, every page must appear in a show command in the logic file at least once.

Because pages must have unique names, you can only write show pagename once for each page - but you can show the same page again later using named, or by using a Jump button on an earlier page.

T

timesincelogin

timesincelogin tells you how much time has passed since an end-user last logged into the intervention.

timesincelogin (username, "unit")

  • username - the end-user to check. Use currentuser().
  • "unit" - what you want the result measured in: "seconds", "minutes", "hours", "days", "weeks" or "months".

There is no need to create your own username variable first - simply use currentuser() (see currentuser()).

Example

1. Show the page where you want to display how long it's been since the end-user last logged in (e.g. "time"):

show time

2. On that page, create a variable to hold the value (e.g. "secs"), using the 'set as variable' function, then set it using timesincelogin:

set time.secs to timesincelogin (currentuser(), "seconds")

This shows the end-user, on the page named "time", how many seconds have passed since they last logged in. You can repeat this step using "minutes", "hours", "days", "weeks" or "months" instead, to display the same information in a different unit.

to

to is used together with the set command, as in set variablename to value. See set for full details and examples.

U

urlencode

urlencode converts a piece of text into a form that is safe to use inside a web address (URL). This is an advanced command, needed only when you are building a dynamic URL (i.e. one that includes a variable that might contain spaces or symbols).

urlencode (string)

  • string - the piece of text (often a variable) you want to make URL-safe.

Certain characters (such as ? and &) have special meaning inside a URL and must be converted into a different format so they don't break the link (for example, the & symbol becomes %26). urlencode takes care of this for you.

URL encoding is a common, standard technique - you can find more information here: http://en.wikipedia.org/wiki/Percent-encoding