<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>http://celtic.lti.tools/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Admin</id>
	<title>ceLTIc wiki - User contributions [en-gb]</title>
	<link rel="self" type="application/atom+xml" href="http://celtic.lti.tools/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Admin"/>
	<link rel="alternate" type="text/html" href="http://celtic.lti.tools/wiki/Special:Contributions/Admin"/>
	<updated>2026-05-15T14:57:37Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.35.2</generator>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=LTI/Best_Practice/References&amp;diff=28</id>
		<title>LTI/Best Practice/References</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=LTI/Best_Practice/References&amp;diff=28"/>
		<updated>2019-12-19T13:41:08Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;&amp;lt;span id=&amp;quot;BLTIS&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[BLTIS]&lt;br /&gt;
: George Kroner, ''BLTI Sandwich'', [http://projects.oscelot.org/gf/project/blti-sandwich/ http://projects.oscelot.org/gf/project/blti-sandwich/]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;ceLTIc-A&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[ceLTIc-A]&lt;br /&gt;
: ceLTIc Project, ''WordPress and user scope'', March 2013, [http://www.celtic-project.org/Project_blog/2013/03/WordPress_and_user_scope http://www.celtic-project.org/Project_blog/2013/03/WordPress_and_user_scope]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;ceLTIc-B&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[ceLTIc-B]&lt;br /&gt;
: ceLTIc Project, ''Extending LTI functionality in Learn 9'', September 2012, [http://www.celtic-project.org/Project_blog/2012/09/Extending_LTI_functionality_in/ http://www.celtic-project.org/Project_blog/2012/09/Extending_LTI_functionality_in]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;ceLTIc-C&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[ceLTIc-C]&lt;br /&gt;
: ceLTIc Project, ''WebPA dashboard'', September 2012, [http://www.celtic-project.org/Project_blog/2012/09/WebPA_dashboard/ http://www.celtic-project.org/Project_blog/2012/09/WebPA_dashboard]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;ceLTIc-D&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[ceLTIc-D]&lt;br /&gt;
: ceLTIc Project, ''Evaluating apps: the quick way with LTI'', April 2013, [http://www.celtic-project.org/Project_blog/2013/04/Evaluating_apps_the_quick_way http://www.celtic-project.org/Project_blog/2013/04/Evaluating_apps_the_quick_way]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;ceLTIc-E&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[ceLTIc-E]&lt;br /&gt;
: ceLTIc Project, ''A Learning Experience – P3P and Cookie Blocking'', November 2012, [http://www.celtic-project.org/Project_blog/2012/11/A_Learning_Experience_P3P_and http://www.celtic-project.org/Project_blog/2012/11/A_Learning_Experience_P3P_and]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;ceLTIc-F&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[ceLTIc-F]&lt;br /&gt;
: ceLTIc Project, ''Parasitic tool providers'', January 2013, [http://www.celtic-project.org/Project_blog/2013/01/Parasitic_tool_providers http://www.celtic-project.org/Project_blog/2013/01/Parasitic_tool_providers]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;ceLTIc-G&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[ceLTIc-G]&lt;br /&gt;
: ceLTIc Project, ''Using an XML tool descriptor'', January 2013, [http://www.celtic-project.org/Project_blog/2013/01/Using_an_XML_tool_descriptor http://www.celtic-project.org/Project_blog/2013/01/Using_an_XML_tool_descriptor]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;ceLTIc-H&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[ceLTIc-H]&lt;br /&gt;
: ceLTIc Project, ''Synchronising group data'', December 2012, [http://www.celtic-project.org/Project_blog/2012/12/Synchronising_group_data http://www.celtic-project.org/Project_blog/2012/12/Synchronising_group_data]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;ceLTIc-I&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[ceLTIc-I]&lt;br /&gt;
: ceLTIc Project, ''Rating with Outcomes'', June 2013, [http://www.celtic-project.org/Project_blog/2013/06/Ratings_with_Outcomes http://www.celtic-project.org/Project_blog/2013/06/Ratings_with_Outcomes]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;ceLTIc-J&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[ceLTIc-J]&lt;br /&gt;
: ceLTIc Project, ''Using LTI to enable collaboration'', November 2011, [http://www.celtic-project.org/Project_blog/2011/11/Using_LTI_to_enable http://www.celtic-project.org/Project_blog/2011/11/Using_LTI_to_enable]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;IMS-A&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[IMS-A]&lt;br /&gt;
: IMS Global Learning Consortium, ''Learning Tools Interoperability'', [http://www.imsglobal.org/lti/ http://www.imsglobal.org/lti/]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;IMS-B&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[IMS-B]&lt;br /&gt;
: IMS Global Learning Consortium, ''Learning Tools Interoperability Implementation Guide, Final Version 1.1.1'', [http://www.imsglobal.org/LTI/v1p1p1/ltiIMGv1p1p1.html http://www.imsglobal.org/LTI/v1p1p1/ltiIMGv1p1p1.html]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;IMS-C&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[IMS-C]&lt;br /&gt;
: IMS Global Learning Consortium, ''Context memberships service'', [http://developers.imsglobal.org/ext_membership.html http://developers.imsglobal.org/ext_membership.html]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;IMS-D&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[IMS-D]&lt;br /&gt;
: IMS Global Learning Consortium, ''Learning Tools Interoperability Implementation Guide, Public Draft Version 1.2'', [http://www.imsglobal.org/lti/ltiv1p2pd/ltiIMGv1p2pd.html http://www.imsglobal.org/lti/ltiv1p2pd/ltiIMGv1p2pd.html]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;IMS-E&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[IMS-E]&lt;br /&gt;
: Charles Severance and Stephen P Vickers, IMS Global Learning Consortium, ''LTI, SAML, and Federated ID – Oh My!'', [http://developers.imsglobal.org/LI2012-lti-saml.pdf http://developers.imsglobal.org/LI2012-lti-saml.pdf]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;IMS-F&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[IMS-F]&lt;br /&gt;
: IMS Global Learning Consortium, ''Content-Item Message'', [http://www.imsglobal.org/lti/ltiv1p2pd/ltiCIMv1p0pd.html http://www.imsglobal.org/lti/ltiv1p2pd/ltiCIMv1p0pd.html]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;IMS-G&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[IMS-G]&lt;br /&gt;
: IMS Global Learning Consortium, ''Learning Information Services'', [http://www.imsglobal.org/lis/ http://www.imsglobal.org/lis/]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;OAuth-A&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[OAuth-A]&lt;br /&gt;
: IETF, ''OAuth 1.0 Protocol'', [http://tools.ietf.org/html/rfc5849 http://tools.ietf.org/html/rfc5849]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;OAuth-B&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[OAuth-B]&lt;br /&gt;
: OAuth, ''Code'', [http://oauth.net/code/ http://oauth.net/code/]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;SPVSP-A&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[SPVSP-A]&lt;br /&gt;
: SPV Software Products, ''LTI Connector for WordPress'', [http://www.spvsoftwareproducts.com/php/wordpress-lti/ http://www.spvsoftwareproducts.com/php/wordpress-lti/]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;SPVSP-B&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[SPVSP-B]&lt;br /&gt;
: SPV Software Products, ''BasicLTI PowerLink'', [http://www.spvsoftwareproducts.com/powerlinks/basiclti/ http://www.spvsoftwareproducts.com/powerlinks/basiclti/]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;SPVSP-C&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[SPVSP-C]&lt;br /&gt;
: SPV Software Products, ''BasicLTI Building Block'', [http://www.spvsoftwareproducts.com/bb/basiclti/ http://www.spvsoftwareproducts.com/bb/basiclti/]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;SPVSP-D&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[SPVSP-D]&lt;br /&gt;
: SPV Software Products, ''LTI Connector for WebPA 2'', [http://www.spvsoftwareproducts.com/php/webpa-lti/ http://www.spvsoftwareproducts.com/php/webpa-lti/]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;SPVSP-E&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[SPVSP-E]&lt;br /&gt;
: SPV Software Products, ''PHP LTI Tool Provider class'', [http://www.spvsoftwareproducts.com/php/lti_tool_provider/ http://www.spvsoftwareproducts.com/php/lti_tool_provider/]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;SPVSP-F&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[SPVSP-F]&lt;br /&gt;
: SPV Software Products, ''Java LTI Tool Provider package'', [http://www.spvsoftwareproducts.com/java/lti_tool_provider/ http://www.spvsoftwareproducts.com/java/lti_tool_provider/]&lt;br /&gt;
;&amp;lt;span id=&amp;quot;WebPA&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;[WebPA]&lt;br /&gt;
: Centre for Engineering and Design Education, Loughborough University, ''WebPA (on-line peer assessment tool)'', [http://webpaproject.lboro.ac.uk/ http://webpaproject.lboro.ac.uk/]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=MediaWiki:Mainpage&amp;diff=25</id>
		<title>MediaWiki:Mainpage</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=MediaWiki:Mainpage&amp;diff=25"/>
		<updated>2014-09-18T04:17:08Z</updated>

		<summary type="html">&lt;p&gt;Admin: Created page with &amp;quot;ceLTIc wiki&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;ceLTIc wiki&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=ceLTIc_wiki&amp;diff=24</id>
		<title>ceLTIc wiki</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=ceLTIc_wiki&amp;diff=24"/>
		<updated>2014-09-18T04:06:04Z</updated>

		<summary type="html">&lt;p&gt;Admin: Added link to LTI Best Practice Guide&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The [http://celtic-project.org/ Creating Environments for Learning using Tightly Integrated Components (ceLTIc) project] came out of a [http://www.jisc.ac.uk/ JISC]-funded project in 2010.  Its broad aim is to raise awareness of the IMS Learning Tools Interoperability&amp;amp;reg; (LTI&amp;amp;reg;) within the education community by demonstrating its benefits for integrating learning applications within on-line course environments.  Further JISC funding in 2012/13 was used to demonstrate the use of LTI for providing shared services across multiple institutions and foster a network and toolsets for developers.  For further information see the project website.&lt;br /&gt;
&lt;br /&gt;
== Contents ==&lt;br /&gt;
[[LTI/Best Practice|Learning Tools Interoperability (LTI): A Best Practice Guide]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=ceLTIc_wiki&amp;diff=23</id>
		<title>ceLTIc wiki</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=ceLTIc_wiki&amp;diff=23"/>
		<updated>2014-09-18T04:03:04Z</updated>

		<summary type="html">&lt;p&gt;Admin: Protected &amp;quot;ceLTIc wiki&amp;quot; ([Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite))&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The [http://celtic-project.org/ Creating Environments for Learning using Tightly Integrated Components (ceLTIc) project] came out of a [http://www.jisc.ac.uk/ JISC]-funded project in 2010.  Its broad aim is to raise awareness of the IMS Learning Tools Interoperability&amp;amp;reg; (LTI&amp;amp;reg;) within the education community by demonstrating its benefits for integrating learning applications within on-line course environments.  Further JISC funding in 2012/13 was used to demonstrate the use of LTI for providing shared services across multiple institutions and foster a network and toolsets for developers.  For further information see the project website.&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=LTI/Best_Practice&amp;diff=22</id>
		<title>LTI/Best Practice</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=LTI/Best_Practice&amp;diff=22"/>
		<updated>2014-09-18T03:52:55Z</updated>

		<summary type="html">&lt;p&gt;Admin: Protected &amp;quot;LTI/Best Practice&amp;quot; ([Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite))&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;'''''Learning Tools Interoperability&amp;lt;sup&amp;gt;&amp;amp;reg;&amp;lt;/sup&amp;gt; (LTI&amp;lt;sup&amp;gt;&amp;amp;reg;&amp;lt;/sup&amp;gt;): A Best Practice Guide'''''&lt;br /&gt;
&lt;br /&gt;
based on the [http://ltiapps.net/guide/best_practice original report] written by&lt;br /&gt;
&lt;br /&gt;
''Stephen P Vickers''&amp;lt;br /&amp;gt;''Simon Booth''&lt;br /&gt;
&lt;br /&gt;
for&lt;br /&gt;
&lt;br /&gt;
[http://celtic-project.org ceLTIc:developers Project]&lt;br /&gt;
&lt;br /&gt;
August 2014&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Contents ==&lt;br /&gt;
&lt;br /&gt;
# [[LTI/Best Practice/Introduction|Introduction]]&lt;br /&gt;
## Terminology&lt;br /&gt;
## LTI Releases&lt;br /&gt;
# [[LTI/Best Practice/Issues for Developers|Issues for Developers]]&lt;br /&gt;
## Anatomy of a launch request&lt;br /&gt;
## Launch parameters&lt;br /&gt;
## Security&lt;br /&gt;
## Receiving a launch request&lt;br /&gt;
## Identity values&lt;br /&gt;
## Roles&lt;br /&gt;
## CSS&lt;br /&gt;
## Override interface&lt;br /&gt;
## Branding&lt;br /&gt;
## Course archive/restore/copy&lt;br /&gt;
## Class libraries&lt;br /&gt;
## Browser issues&lt;br /&gt;
# [[LTI/Best Practice/Issues for System Administrators|Issues for System Administrators]]&lt;br /&gt;
## Tool requirements&lt;br /&gt;
## Configuring tools (XML)&lt;br /&gt;
## Verifying connections&lt;br /&gt;
## Course archive/restore/copy&lt;br /&gt;
## Mapping VLE/LTI roles&lt;br /&gt;
# [[LTI/Best Practice/Issues for Teachers and Students|Issues for Teachers and Students]]&lt;br /&gt;
## Number of links per course&lt;br /&gt;
## Pre-populating enrolments and groups&lt;br /&gt;
## Managing outcomes&lt;br /&gt;
## Re-using content&lt;br /&gt;
## Sharing content&lt;br /&gt;
## Mapping VLE/LTI roles&lt;br /&gt;
## &amp;quot;Dummy&amp;quot; users&lt;br /&gt;
# [[LTI/Best Practice/Issues for Service Providers|Issues for Service Providers]]&lt;br /&gt;
## Service level agreements&lt;br /&gt;
## Upgrades&lt;br /&gt;
## Backups&lt;br /&gt;
* [[LTI/Best Practice/References|References]]&lt;br /&gt;
&lt;br /&gt;
== Case studies ==&lt;br /&gt;
# [[LTI/Best Practice/Issues for Developers#CS1|WebPA launch requests]]&lt;br /&gt;
# [[LTI/Best Practice/Issues for Developers#CS2|User scope in WordPress]]&lt;br /&gt;
# [[LTI/Best Practice/Issues for Developers#CS3|Custom parameters supported by WebPA]]&lt;br /&gt;
# [[LTI/Best Practice/Issues for System Administrators#CS4|Testing mode]]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
You are welcome, even encouraged, to contribute your own experiences and best practices to this document.  Just sign up for an account and use the discussion option on each page, or edit the page directly with your content.&lt;br /&gt;
&lt;br /&gt;
''Learning Tools Interoperability and LTI are registered trademarks of IMS Global Learning Consortium, Inc. in the United States and/or other countries.''&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=LTI/Best_Practice/References&amp;diff=21</id>
		<title>LTI/Best Practice/References</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=LTI/Best_Practice/References&amp;diff=21"/>
		<updated>2014-09-18T03:52:45Z</updated>

		<summary type="html">&lt;p&gt;Admin: Protected &amp;quot;LTI/Best Practice/References&amp;quot; ([Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite))&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;{{anchor|BLTIS}}[BLTIS]&lt;br /&gt;
: George Kroner, ''BLTI Sandwich'', [http://projects.oscelot.org/gf/project/blti-sandwich/ http://projects.oscelot.org/gf/project/blti-sandwich/]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|ceLTIc-A}}[ceLTIc-A]&lt;br /&gt;
: ceLTIc Project, ''WordPress and user scope'', March 2013, [http://www.celtic-project.org/Project_blog/2013/03/WordPress_and_user_scope http://www.celtic-project.org/Project_blog/2013/03/WordPress_and_user_scope]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|ceLTIc-B}}[ceLTIc-B]&lt;br /&gt;
: ceLTIc Project, ''Extending LTI functionality in Learn 9'', September 2012, [http://www.celtic-project.org/Project_blog/2012/09/Extending_LTI_functionality_in/ http://www.celtic-project.org/Project_blog/2012/09/Extending_LTI_functionality_in]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|ceLTIc-C}}[ceLTIc-C]&lt;br /&gt;
: ceLTIc Project, ''WebPA dashboard'', September 2012, [http://www.celtic-project.org/Project_blog/2012/09/WebPA_dashboard/ http://www.celtic-project.org/Project_blog/2012/09/WebPA_dashboard]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|ceLTIc-D}}[ceLTIc-D]&lt;br /&gt;
: ceLTIc Project, ''Evaluating apps: the quick way with LTI'', April 2013, [http://www.celtic-project.org/Project_blog/2013/04/Evaluating_apps_the_quick_way http://www.celtic-project.org/Project_blog/2013/04/Evaluating_apps_the_quick_way]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|ceLTIc-E}}[ceLTIc-E]&lt;br /&gt;
: ceLTIc Project, ''A Learning Experience – P3P and Cookie Blocking'', November 2012, [http://www.celtic-project.org/Project_blog/2012/11/A_Learning_Experience_P3P_and http://www.celtic-project.org/Project_blog/2012/11/A_Learning_Experience_P3P_and]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|ceLTIc-F}}[ceLTIc-F]&lt;br /&gt;
: ceLTIc Project, ''Parasitic tool providers'', January 2013, [http://www.celtic-project.org/Project_blog/2013/01/Parasitic_tool_providers http://www.celtic-project.org/Project_blog/2013/01/Parasitic_tool_providers]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|ceLTIc-G}}[ceLTIc-G]&lt;br /&gt;
: ceLTIc Project, ''Using an XML tool descriptor'', January 2013, [http://www.celtic-project.org/Project_blog/2013/01/Using_an_XML_tool_descriptor http://www.celtic-project.org/Project_blog/2013/01/Using_an_XML_tool_descriptor]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|ceLTIc-H}}[ceLTIc-H]&lt;br /&gt;
: ceLTIc Project, ''Synchronising group data'', December 2012, [http://www.celtic-project.org/Project_blog/2012/12/Synchronising_group_data http://www.celtic-project.org/Project_blog/2012/12/Synchronising_group_data]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|ceLTIc-I}}[ceLTIc-I]&lt;br /&gt;
: ceLTIc Project, ''Rating with Outcomes'', June 2013, [http://www.celtic-project.org/Project_blog/2013/06/Ratings_with_Outcomes http://www.celtic-project.org/Project_blog/2013/06/Ratings_with_Outcomes]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|ceLTIc-J}}[ceLTIc-J]&lt;br /&gt;
: ceLTIc Project, ''Using LTI to enable collaboration'', November 2011, [http://www.celtic-project.org/Project_blog/2011/11/Using_LTI_to_enable http://www.celtic-project.org/Project_blog/2011/11/Using_LTI_to_enable]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|IMS-A}}[IMS-A]&lt;br /&gt;
: IMS Global Learning Consortium, ''Learning Tools Interoperability'', [http://www.imsglobal.org/lti/ http://www.imsglobal.org/lti/]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|IMS-B}}[IMS-B]&lt;br /&gt;
: IMS Global Learning Consortium, ''Learning Tools Interoperability Implementation Guide, Final Version 1.1.1'', [http://www.imsglobal.org/LTI/v1p1p1/ltiIMGv1p1p1.html http://www.imsglobal.org/LTI/v1p1p1/ltiIMGv1p1p1.html]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|IMS-C}}[IMS-C]&lt;br /&gt;
: IMS Global Learning Consortium, ''Context memberships service'', [http://developers.imsglobal.org/ext_membership.html http://developers.imsglobal.org/ext_membership.html]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|IMS-D}}[IMS-D]&lt;br /&gt;
: IMS Global Learning Consortium, ''Learning Tools Interoperability Implementation Guide, Public Draft Version 1.2'', [http://www.imsglobal.org/lti/ltiv1p2pd/ltiIMGv1p2pd.html http://www.imsglobal.org/lti/ltiv1p2pd/ltiIMGv1p2pd.html]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|IMS-E}}[IMS-E]&lt;br /&gt;
: Charles Severance and Stephen P Vickers, IMS Global Learning Consortium, ''LTI, SAML, and Federated ID – Oh My!'', [http://developers.imsglobal.org/LI2012-lti-saml.pdf http://developers.imsglobal.org/LI2012-lti-saml.pdf]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|IMS-F}}[IMS-F]&lt;br /&gt;
: IMS Global Learning Consortium, ''Content-Item Message'', [http://www.imsglobal.org/lti/ltiv1p2pd/ltiCIMv1p0pd.html http://www.imsglobal.org/lti/ltiv1p2pd/ltiCIMv1p0pd.html]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|IMS-G}}[IMS-G]&lt;br /&gt;
: IMS Global Learning Consortium, ''Learning Information Services'', [http://www.imsglobal.org/lis/ http://www.imsglobal.org/lis/]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|OAuth-A}}[OAuth-A]&lt;br /&gt;
: IETF, ''OAuth 1.0 Protocol'', [http://tools.ietf.org/html/rfc5849 http://tools.ietf.org/html/rfc5849]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|OAuth-B}}[OAuth-B]&lt;br /&gt;
: OAuth, ''Code'', [http://oauth.net/code/ http://oauth.net/code/]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|SPVSP-A}}[SPVSP-A]&lt;br /&gt;
: SPV Software Products, ''LTI Connector for WordPress'', [http://www.spvsoftwareproducts.com/php/wordpress-lti/ http://www.spvsoftwareproducts.com/php/wordpress-lti/]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|SPVSP-B}}[SPVSP-B]&lt;br /&gt;
: SPV Software Products, ''BasicLTI PowerLink'', [http://www.spvsoftwareproducts.com/powerlinks/basiclti/ http://www.spvsoftwareproducts.com/powerlinks/basiclti/]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|SPVSP-C}}[SPVSP-C]&lt;br /&gt;
: SPV Software Products, ''BasicLTI Building Block'', [http://www.spvsoftwareproducts.com/bb/basiclti/ http://www.spvsoftwareproducts.com/bb/basiclti/]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|SPVSP-D}}[SPVSP-D]&lt;br /&gt;
: SPV Software Products, ''LTI Connector for WebPA 2'', [http://www.spvsoftwareproducts.com/php/webpa-lti/ http://www.spvsoftwareproducts.com/php/webpa-lti/]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|SPVSP-E}}[SPVSP-E]&lt;br /&gt;
: SPV Software Products, ''PHP LTI Tool Provider class'', [http://www.spvsoftwareproducts.com/php/lti_tool_provider/ http://www.spvsoftwareproducts.com/php/lti_tool_provider/]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|SPVSP-F}}[SPVSP-F]&lt;br /&gt;
: SPV Software Products, ''Java LTI Tool Provider package'', [http://www.spvsoftwareproducts.com/java/lti_tool_provider/ http://www.spvsoftwareproducts.com/java/lti_tool_provider/]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|WebPA}}[WebPA]&lt;br /&gt;
: Centre for Engineering and Design Education, Loughborough University, ''WebPA (on-line peer assessment tool)'', [http://webpaproject.lboro.ac.uk/ http://webpaproject.lboro.ac.uk/]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=LTI/Best_Practice/References&amp;diff=20</id>
		<title>LTI/Best Practice/References</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=LTI/Best_Practice/References&amp;diff=20"/>
		<updated>2014-09-18T03:52:25Z</updated>

		<summary type="html">&lt;p&gt;Admin: Version from the original PDF document&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;;{{anchor|BLTIS}}[BLTIS]&lt;br /&gt;
: George Kroner, ''BLTI Sandwich'', [http://projects.oscelot.org/gf/project/blti-sandwich/ http://projects.oscelot.org/gf/project/blti-sandwich/]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|ceLTIc-A}}[ceLTIc-A]&lt;br /&gt;
: ceLTIc Project, ''WordPress and user scope'', March 2013, [http://www.celtic-project.org/Project_blog/2013/03/WordPress_and_user_scope http://www.celtic-project.org/Project_blog/2013/03/WordPress_and_user_scope]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|ceLTIc-B}}[ceLTIc-B]&lt;br /&gt;
: ceLTIc Project, ''Extending LTI functionality in Learn 9'', September 2012, [http://www.celtic-project.org/Project_blog/2012/09/Extending_LTI_functionality_in/ http://www.celtic-project.org/Project_blog/2012/09/Extending_LTI_functionality_in]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|ceLTIc-C}}[ceLTIc-C]&lt;br /&gt;
: ceLTIc Project, ''WebPA dashboard'', September 2012, [http://www.celtic-project.org/Project_blog/2012/09/WebPA_dashboard/ http://www.celtic-project.org/Project_blog/2012/09/WebPA_dashboard]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|ceLTIc-D}}[ceLTIc-D]&lt;br /&gt;
: ceLTIc Project, ''Evaluating apps: the quick way with LTI'', April 2013, [http://www.celtic-project.org/Project_blog/2013/04/Evaluating_apps_the_quick_way http://www.celtic-project.org/Project_blog/2013/04/Evaluating_apps_the_quick_way]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|ceLTIc-E}}[ceLTIc-E]&lt;br /&gt;
: ceLTIc Project, ''A Learning Experience – P3P and Cookie Blocking'', November 2012, [http://www.celtic-project.org/Project_blog/2012/11/A_Learning_Experience_P3P_and http://www.celtic-project.org/Project_blog/2012/11/A_Learning_Experience_P3P_and]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|ceLTIc-F}}[ceLTIc-F]&lt;br /&gt;
: ceLTIc Project, ''Parasitic tool providers'', January 2013, [http://www.celtic-project.org/Project_blog/2013/01/Parasitic_tool_providers http://www.celtic-project.org/Project_blog/2013/01/Parasitic_tool_providers]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|ceLTIc-G}}[ceLTIc-G]&lt;br /&gt;
: ceLTIc Project, ''Using an XML tool descriptor'', January 2013, [http://www.celtic-project.org/Project_blog/2013/01/Using_an_XML_tool_descriptor http://www.celtic-project.org/Project_blog/2013/01/Using_an_XML_tool_descriptor]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|ceLTIc-H}}[ceLTIc-H]&lt;br /&gt;
: ceLTIc Project, ''Synchronising group data'', December 2012, [http://www.celtic-project.org/Project_blog/2012/12/Synchronising_group_data http://www.celtic-project.org/Project_blog/2012/12/Synchronising_group_data]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|ceLTIc-I}}[ceLTIc-I]&lt;br /&gt;
: ceLTIc Project, ''Rating with Outcomes'', June 2013, [http://www.celtic-project.org/Project_blog/2013/06/Ratings_with_Outcomes http://www.celtic-project.org/Project_blog/2013/06/Ratings_with_Outcomes]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|ceLTIc-J}}[ceLTIc-J]&lt;br /&gt;
: ceLTIc Project, ''Using LTI to enable collaboration'', November 2011, [http://www.celtic-project.org/Project_blog/2011/11/Using_LTI_to_enable http://www.celtic-project.org/Project_blog/2011/11/Using_LTI_to_enable]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|IMS-A}}[IMS-A]&lt;br /&gt;
: IMS Global Learning Consortium, ''Learning Tools Interoperability'', [http://www.imsglobal.org/lti/ http://www.imsglobal.org/lti/]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|IMS-B}}[IMS-B]&lt;br /&gt;
: IMS Global Learning Consortium, ''Learning Tools Interoperability Implementation Guide, Final Version 1.1.1'', [http://www.imsglobal.org/LTI/v1p1p1/ltiIMGv1p1p1.html http://www.imsglobal.org/LTI/v1p1p1/ltiIMGv1p1p1.html]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|IMS-C}}[IMS-C]&lt;br /&gt;
: IMS Global Learning Consortium, ''Context memberships service'', [http://developers.imsglobal.org/ext_membership.html http://developers.imsglobal.org/ext_membership.html]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|IMS-D}}[IMS-D]&lt;br /&gt;
: IMS Global Learning Consortium, ''Learning Tools Interoperability Implementation Guide, Public Draft Version 1.2'', [http://www.imsglobal.org/lti/ltiv1p2pd/ltiIMGv1p2pd.html http://www.imsglobal.org/lti/ltiv1p2pd/ltiIMGv1p2pd.html]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|IMS-E}}[IMS-E]&lt;br /&gt;
: Charles Severance and Stephen P Vickers, IMS Global Learning Consortium, ''LTI, SAML, and Federated ID – Oh My!'', [http://developers.imsglobal.org/LI2012-lti-saml.pdf http://developers.imsglobal.org/LI2012-lti-saml.pdf]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|IMS-F}}[IMS-F]&lt;br /&gt;
: IMS Global Learning Consortium, ''Content-Item Message'', [http://www.imsglobal.org/lti/ltiv1p2pd/ltiCIMv1p0pd.html http://www.imsglobal.org/lti/ltiv1p2pd/ltiCIMv1p0pd.html]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|IMS-G}}[IMS-G]&lt;br /&gt;
: IMS Global Learning Consortium, ''Learning Information Services'', [http://www.imsglobal.org/lis/ http://www.imsglobal.org/lis/]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|OAuth-A}}[OAuth-A]&lt;br /&gt;
: IETF, ''OAuth 1.0 Protocol'', [http://tools.ietf.org/html/rfc5849 http://tools.ietf.org/html/rfc5849]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|OAuth-B}}[OAuth-B]&lt;br /&gt;
: OAuth, ''Code'', [http://oauth.net/code/ http://oauth.net/code/]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|SPVSP-A}}[SPVSP-A]&lt;br /&gt;
: SPV Software Products, ''LTI Connector for WordPress'', [http://www.spvsoftwareproducts.com/php/wordpress-lti/ http://www.spvsoftwareproducts.com/php/wordpress-lti/]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|SPVSP-B}}[SPVSP-B]&lt;br /&gt;
: SPV Software Products, ''BasicLTI PowerLink'', [http://www.spvsoftwareproducts.com/powerlinks/basiclti/ http://www.spvsoftwareproducts.com/powerlinks/basiclti/]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|SPVSP-C}}[SPVSP-C]&lt;br /&gt;
: SPV Software Products, ''BasicLTI Building Block'', [http://www.spvsoftwareproducts.com/bb/basiclti/ http://www.spvsoftwareproducts.com/bb/basiclti/]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|SPVSP-D}}[SPVSP-D]&lt;br /&gt;
: SPV Software Products, ''LTI Connector for WebPA 2'', [http://www.spvsoftwareproducts.com/php/webpa-lti/ http://www.spvsoftwareproducts.com/php/webpa-lti/]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|SPVSP-E}}[SPVSP-E]&lt;br /&gt;
: SPV Software Products, ''PHP LTI Tool Provider class'', [http://www.spvsoftwareproducts.com/php/lti_tool_provider/ http://www.spvsoftwareproducts.com/php/lti_tool_provider/]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|SPVSP-F}}[SPVSP-F]&lt;br /&gt;
: SPV Software Products, ''Java LTI Tool Provider package'', [http://www.spvsoftwareproducts.com/java/lti_tool_provider/ http://www.spvsoftwareproducts.com/java/lti_tool_provider/]&lt;br /&gt;
&lt;br /&gt;
;{{anchor|WebPA}}[WebPA]&lt;br /&gt;
: Centre for Engineering and Design Education, Loughborough University, ''WebPA (on-line peer assessment tool)'', [http://webpaproject.lboro.ac.uk/ http://webpaproject.lboro.ac.uk/]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=LTI/Best_Practice/Issues_for_Service_Providers&amp;diff=19</id>
		<title>LTI/Best Practice/Issues for Service Providers</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=LTI/Best_Practice/Issues_for_Service_Providers&amp;diff=19"/>
		<updated>2014-09-18T03:51:42Z</updated>

		<summary type="html">&lt;p&gt;Admin: Version from the original PDF document&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This section discusses issues relevant to hosting providers seeking to deliver a service using a tool provider application.&lt;br /&gt;
&lt;br /&gt;
== Service level agreements ==&lt;br /&gt;
One of the benefits of LTI is that is enables applications to be shared across multiple tool consumers. These may belong to the same institution, or be servicing institutions from across the globe. A consequence of this is that, as the service provider, it makes it difficult to predict service levels when the load from other customers can impact the quality of service being delivered. It may take experience of the application and infrastructure which can quickly adapt to changing loads to ensure that customers are satisfied.&lt;br /&gt;
&lt;br /&gt;
== Upgrades ==&lt;br /&gt;
Whilst running a single instance of an application for multiple customers has efficiency gains in terms of maintenance and support, it would normally also mean that every customer must use the same version. Moreover, any move to a new version will be at the same time for all users. Whilst it might be technically possible to build an application such that a single server could continue to run multiple versions, with each customer upgrading independently, the cost of doing so may outweigh the savings of using a multi-tenanted environment and no examples of such an approach are known. In fact, products like Canvas show that institutions are willing to accept cloud-based solutions and have the upgrade cycle dictated to them by the supplier.&lt;br /&gt;
&lt;br /&gt;
== Backups ==&lt;br /&gt;
Since a single instance of the application may be supporting multiple customers, a backup of the application (source code and database) will not easily enable an individual customer to have their state restored to a particular point in time. Nor is it straightforward to provide a customer with a backup to access separately; for example, for performing analytics or when moving to a different service provider. In this case, tool providers should consider implementing import and export functionality for individual tool consumers; this could even be made available to anyone launching with the System Administrator role.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;comments /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=LTI/Best_Practice/Issues_for_Teachers_and_Students&amp;diff=18</id>
		<title>LTI/Best Practice/Issues for Teachers and Students</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=LTI/Best_Practice/Issues_for_Teachers_and_Students&amp;diff=18"/>
		<updated>2014-09-18T03:51:00Z</updated>

		<summary type="html">&lt;p&gt;Admin: Version from the original PDF document&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Issues for Teachers/Students =&lt;br /&gt;
This section discusses issues relevant to teachers and students seeking to use LTI tool providers as part of their on-line courses.&lt;br /&gt;
&lt;br /&gt;
== Number of links per course ==&lt;br /&gt;
Typically a link to a tool provider is added to a content area of a course within a tool consumer in a similar way to adding any other form of content. There is no reason for teachers and students to know that a link is actually connecting them to externally-served content; it should form just another part of a seamless on-line course environment. Whilst the behaviour of following each link is dependent upon the implementation by the tool provider, the normal expectation is that they would act as unique connections to separate resources/activities. Thus, for example, if the tool provider is a quizzing application, adding a new link should add a new quiz to the course. The consumer key and resource link ID passed when a link is launched allow the tool provider to keep each link separate from others added to the same course, in other courses in the same tool consumer, and from those added to any other tool consumer around the globe.&lt;br /&gt;
&lt;br /&gt;
== Pre-populating enrolments and groups ==&lt;br /&gt;
Since the details about the user can be securely passed when they click the link, the tool provider is able to create/update any user accounts required at its end at the time of the launch request. Thus, there is no need for the external system to be pre-provisioned with users; they can be added &amp;quot;on-the-fly&amp;quot;. LTI does not, however, provide a mechanism for sharing group memberships defined within the tool consumer. The closest solution is an extension to the unofficial memberships service which includes group information; this has been used for WebPA which, as a peer assessment tool, requires a teacher to have details of all the students so that assessments can be created and each student assigned to a group. [[LTI/Best Practice/References#ceLTIc-H|[ceLTIc-H]]]&lt;br /&gt;
&lt;br /&gt;
== Managing outcomes ==&lt;br /&gt;
Many tool providers involve assessable activities and use the Outcomes service to return a grade to the column in the tool consumer's gradebook associated with the link added to a course. Only grade values between 0 and 1 (inclusive) can be passed, but most gradebooks would display this value as a percentage. In some cases teachers (or administrators) have the option to specify the number of points possible so that the grade can be displayed as a score. For example, with a points possible of 60, when a grade of 0.7 is returned it would be displayed to users as 42.&lt;br /&gt;
&lt;br /&gt;
Grades may be returned from a tool provider as a result of an action by the student, or by the teacher, or as part of an automated (possibly regular) process. Once a student has launched a link their cell in the associated gradebook column falls under the control of the tool provider and can be updated at its discretion.&lt;br /&gt;
&lt;br /&gt;
Whilst the LTI specification requires that a grade be transmitted as a value between 0 and 1, it need not represent a score. Some tool providers may associate the values with other meanings. For example, 0 may represent that a student has started an activity with 1 representing completion. The sample Ratings application uses the grade to represent the proportion of the items available which have been rated by the student. [[LTI/Best Practice/References#ceLTIc-I|[ceLTIc-I]]]&lt;br /&gt;
&lt;br /&gt;
== Re-using content ==&lt;br /&gt;
Each launch link added to a course is identified by a unique ID. A tool provider will typically use this ID to associate the link with an activity/resource/work space. If a link in a course is copied the copy will have a different ID and hence the association made by the tool provider will be lost. However, some tool providers encapsulate the association within the launch URL (which would, therefore, be unique for each link) or as a custom parameter, in which cases the connection need not be lost by being copied.&lt;br /&gt;
&lt;br /&gt;
== Sharing content ==&lt;br /&gt;
With each link having a unique ID, a tool provider will normally treat them as entirely separate connections. However, there are situations where It could be beneficial for more than one link to be associated with the same activity; for example:&lt;br /&gt;
&lt;br /&gt;
* in order to allow multiple entry points from within a course;&lt;br /&gt;
* when an activity involves students from different courses or different tool consumers, even different institutions.&lt;br /&gt;
&lt;br /&gt;
There is nothing specifically within the LTI specification to enable such scenarios, but tool providers may provide a mechanism for doing so, such as a custom parameter. Such functionality has been incorporated into the open source PHP and Java class libraries which will automatically allow additional links to appear to the tool provider as if they have been launched from a primary link. [[LTI/Best Practice/References#ceLTIc-J|[ceLTIc-J]]] Check the documentation for the tool provider to see if this functionality is available, as is the case for the LTI connectors for WordPress [[LTI/Best Practice/References#SPVSP-A|[SPVSP-A]]] and WebPA [[LTI/Best Practice/References#SPVSP-D|[SPVSP-D]]].&lt;br /&gt;
&lt;br /&gt;
== Mapping VLE/LTI roles ==&lt;br /&gt;
Most tool consumers allow users to be given a variety of roles within a course, such as:&lt;br /&gt;
&lt;br /&gt;
* course administrator;&lt;br /&gt;
* course builder;&lt;br /&gt;
* instructor;&lt;br /&gt;
* teaching assistant;&lt;br /&gt;
* learner;&lt;br /&gt;
* guest.&lt;br /&gt;
&lt;br /&gt;
A tool provider may not support such a rich set of roles or, if it does, may not have the same view of the importance of the roles. In particular, a teaching assistant role can vary widely between institutions in terms of the level of responsibility and access they are given to courses. Some tool consumers provide a mechanism for mapping course roles onto LTI roles but, otherwise, the tool provider may allow some control over roles and permissions via a configuration page available to instructors (or administrators). However, in many cases only roles of instructor and learner are supported so there may be issues as to whether course builders, teaching assistants and guests are given the desired level of access.&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Dummy&amp;quot; users ==&lt;br /&gt;
Many VLEs offer users the ability to view the system as if they had a different role; commonly this is used to allow a teacher to preview their course as a student would see it. If the teacher takes a test in this mode, the VLE may be clever enough to also exclude their marks when generating class statistics. At least in some implementations, this is achieved by generating a new user account which is used during this time.&lt;br /&gt;
&lt;br /&gt;
So what does this mean for LTI connections added to a course. Well, the first thing is that there are no known implementations which actually inform the tool provider that the user who has performed the launch is not a real account. This means that tool providers cannot distinguish their activity from that of real users, hence this may distort the class numbers and statistics. It may also be the case that the user_id parameter is not changed, but merely the user's role will have changed from Instructor to Learner, for example. A tool provider always needs to be vigilant for users changing roles, but in cases like this the change is merely temporary and short-lived. There are, however, some VLEs which do use a different ID for these &amp;quot;dummy&amp;quot; user accounts, however, in the case of Blackboard Learn 9, their recommended practice is for a new account to be created every time the teacher selected the student preview mode. In this case, the number of &amp;quot;dummy&amp;quot; user accounts received by a tool provider could be quite large.&lt;br /&gt;
&lt;br /&gt;
As a teacher, you should be aware that your preview account will not be recognised as such by a tool provider. If this has a side effect on class statistics or licence fees, then it may be advisable to avoid launching LTI connections when using this feature.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;comments /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=LTI/Best_Practice/Issues_for_System_Administrators&amp;diff=17</id>
		<title>LTI/Best Practice/Issues for System Administrators</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=LTI/Best_Practice/Issues_for_System_Administrators&amp;diff=17"/>
		<updated>2014-09-18T03:50:16Z</updated>

		<summary type="html">&lt;p&gt;Admin: Version from the original PDF document&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This section discusses issues relevant to system administrators for tool consumers seeking to make LTI tool providers available to their users.&lt;br /&gt;
&lt;br /&gt;
== Tool requirements ==&lt;br /&gt;
The addition of an LTI-based tool to a VLE should involve the same type of due diligence process as for any other learning application. This includes:&lt;br /&gt;
&lt;br /&gt;
* checking that its functionality meets needs and is compatible with existing infrastructure;&lt;br /&gt;
* agreeing the SLA, licence agreement and any licence fee;&lt;br /&gt;
* ensuring it complies with policies such as data privacy.&lt;br /&gt;
&lt;br /&gt;
In order to properly assess the last of these, a system administrator needs to know what data is being passed between the VLE (tool consumer) and the tool. The LTI specification has no required parameters involving personal data, but does support the sharing of user IDs, names, email addresses and roles, as well as data about the link and course from which the launch originated. The tool consumer should have options to turn on and off the passing of such data, but it may not be easy to determine which parameters are required for the successful use of the tool provider, or when the inclusion of a particular parameter may provide enhanced functionality to users. It would be very helpful if the documentation provided by tool providers included the following to assist system administrators in knowing how to configure the link and understand the consequences of their use:&lt;br /&gt;
&lt;br /&gt;
* which launch parameters not required by the LTI specification are required for a successful launch;&lt;br /&gt;
* which launch parameters are not required, but their presence gives enhanced functionality to users;&lt;br /&gt;
* which LTI roles are supported and what privileges are given to users with each role (this is particularly important if the TeachingAssistant role is supported as it is the one which is most likely to vary in level of privilege given to it by different institutions).&lt;br /&gt;
&lt;br /&gt;
If such information is not readily available, then the best approach would be to start by turning off all the available options for passing context/resource/user data and only turn them on if a launch request fails or to improve the user experience.&lt;br /&gt;
&lt;br /&gt;
== Configuring tools (XML) ==&lt;br /&gt;
The LTI specification does provide a mechanism for defining a connection to a tool provider using XML and some tool consumer implementations provide this option within their UI (e.g. the open source LTI building block for Blackboard Learn 9 and Canvas by Instructure). This XML can be used to specify:&lt;br /&gt;
&lt;br /&gt;
* title;&lt;br /&gt;
* description;&lt;br /&gt;
* launch URL (including an optional URL for secure connections);&lt;br /&gt;
* custom parameters;&lt;br /&gt;
* URL for an icon (including an optional URL for secure connections);&lt;br /&gt;
* details about the vendor: code, name description, URL, contact email address.&lt;br /&gt;
&lt;br /&gt;
In addition to these details extension sections may be defined for settings specific to individual platforms. For example, an extensions section with a platform name of &amp;quot;learn&amp;quot; is used by the open source LTI building block to enable all the configuration settings to be specified in the XML (e.g. which parameters should be passed, which value to use for a context ID, etc.). [[LTI/Best Practice/References#ceLTIc-G|[ceLTIc-G]]] It can, therefore, make it very convenient for customers to be supplied with an XML description of tool providers (or a URL to such an XML file) and can reduce problems with transcription errors. However, not all tool consumers adopt the format provided in the LTI specification; for example, Canvas expects XML with a root node named &amp;lt;code&amp;gt;cartridge_basiclti_link&amp;lt;/code&amp;gt; rather than &amp;lt;code&amp;gt;basic_lti_link&amp;lt;/code&amp;gt;. In addition the XML used by Canvas fails to validate because elements are not in the correct order, a new element (&amp;lt;code&amp;gt;options&amp;lt;/code&amp;gt;) is introduced, and a required element (&amp;lt;code&amp;gt;vendor&amp;lt;/code&amp;gt;) is omitted. Hence it is not possible, at present, for a single version of an XML description of a tool provider to be defined for use with any tool consumer. So be prepared to request a specific variation for your own needs or edit the XML provided.&lt;br /&gt;
&lt;br /&gt;
== Verifying connections ==&lt;br /&gt;
{{anchor|CS4}}&lt;br /&gt;
{{Infobox&lt;br /&gt;
|title = Case Study 4 - Testing mode&lt;br /&gt;
|titlestyle = background-color: #fff; color: #000;&lt;br /&gt;
|bodystyle = background-color: #008080; color: #fff;&lt;br /&gt;
|datastyle = text-align: left;&lt;br /&gt;
|data1 = Any tool providers built using the PHP or Java LTI Tool Provider class libraries support a custom parameter of &amp;quot;debug=true&amp;quot; which causes more detailed error messages to be returned on failed launch requests.&lt;br /&gt;
}}&lt;br /&gt;
After configuring a new LTI tool, it is good practice to verify that it works. There is no mechanism in the specification for assisting with this; it is normally a matter of adding the tool to a course and trying a launch. Some tool consumer implementations may provide a launch option from the tool configuration page to make this easier. The main purpose of the test at this point is to verify the URL, key and secret used to configure the tool; if any of these items is entered incorrectly any attempt to launch the tool should fail. (Note that LTI 2 should overcome this issue as the configuration of tools is undertaken as a negotiation between the tool provider and tool consumer servers, without the risk of human error in entering launch parameters.) However, a failed launch request may also occur if:&lt;br /&gt;
&lt;br /&gt;
* the tool provider has not yet set up the details on their system;&lt;br /&gt;
* the consumer key has not been enabled by the tool provider;&lt;br /&gt;
* the consumer key is only valid for a specific time period and the current time is not within that period;&lt;br /&gt;
* the launch request does not include sufficient data to support the requirements of the tool provider;&lt;br /&gt;
* the length of a parameter exceeds the tool provider's acceptable limit.&lt;br /&gt;
&lt;br /&gt;
Hopefully, the tool provider returns a detailed reason for any errors which arise as a log entry for the tool consumer, or has an option to display such messages as part of a &amp;quot;testing mode&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Course archive/restore/copy ==&lt;br /&gt;
When a course containing a link to an LTI tool is copied, for example, the link in the new course will have a different value for the &amp;lt;code&amp;gt;resource_link_id&amp;lt;/code&amp;gt; parameter when launched. This means that a tool provider will see this as a launch from a new link but without appreciating that it originated from an existing link so that, for example, an option to duplicate the content from the original link could be offered. Tool providers may have a mechanism in place for trying to handle this situation, but system administrators should be aware the any archive/restore or copy actions which take place on the tool consumer system, are not automatically replicated by tool providers and so some manual intervention may be required. This is an important aspect to test when investigating new tool providers.&lt;br /&gt;
&lt;br /&gt;
== Mapping VLE/LTI roles ==&lt;br /&gt;
LTI uses the LIS [[LTI/Best Practice/References#IMS-G|[IMS-G]]] vocabulary for user roles. These are likely to be different from those available within a course so a tool consumer will implement some form of mapping from course roles to LTI roles. This mapping need not be on a one-to-one basis, though typically it is. The mapping may be a static implementation applied to all LTI launches for all tool providers, or it may be configurable for each tool provider or even each resource link. The key for a system administrator is to ensure that, as far as they are able, users are given an LTI role appropriate to the tool provider and their course role. If the mapping is static and cannot be altered, then a review of the tool provider to ensure that users are given sufficient privileges within the tool provider and not given privileges which are not appropriate to their course role.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;comments /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=LTI/Best_Practice/Introduction&amp;diff=16</id>
		<title>LTI/Best Practice/Introduction</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=LTI/Best_Practice/Introduction&amp;diff=16"/>
		<updated>2014-09-18T03:49:39Z</updated>

		<summary type="html">&lt;p&gt;Admin: Added comments area&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Learning Tools Interoperability (LTI) specification was first released by the IMS Global Learning Consortium as Basic LTI in May 2010 [[LTI/Best Practice/References#IMS-A|[IMS-A]]] (and is now referred to as LTI 1.0). Since that time it has become well adopted as a simple but effective mechanism for integrating third party content and products with virtual learning environments (VLEs). For example, it is now part of the core product for all major VLEs, including Moodle, Blackboard Learn 9, Desire2Learn and Canvas from Instructure.&lt;br /&gt;
&lt;br /&gt;
The purpose of this document is to provide you with a detailed exploration of how LTI works and the issues which arise so as to give you guidance on good practice, if not, best practice. The document contains sections relating to all the main parties involved in delivering learning experiences to students:&lt;br /&gt;
&lt;br /&gt;
* developers;&lt;br /&gt;
* VLE administrators;&lt;br /&gt;
* teachers;&lt;br /&gt;
* service providers.&lt;br /&gt;
&lt;br /&gt;
Please provide feedback based on your own experiences to help improve the quality of the recommendations included here.&lt;br /&gt;
&lt;br /&gt;
== Terminology ==&lt;br /&gt;
We start with a bit of terminology to help make the descriptions which follow more precise. The LTI specification uses the following terms:&lt;br /&gt;
&lt;br /&gt;
* ''tool consumer'' - typically this refers to the VLE; it is the system which users are logged into and from which they will be redirected to the external applications being integrated with it;&lt;br /&gt;
* ''tool provider'' - this is the web-based learning application or content delivery system which is being integrated with the tool consumer;&lt;br /&gt;
* ''consumer key'' - this string value is generated by the tool provider to allow them to uniquely identify the source of requests being received;&lt;br /&gt;
* ''shared secret'' - the communications between the tool provider and the tool consumer are secured using a signature generated using the OAuth 1.0 protocol [[LTI/Best Practice/References#OAuth-A|[OAuth-A]]] with the shared secret (which should be known only to the tool provider and the tool consumer);&lt;br /&gt;
* ''context'' - tool consumers are typically organised into courses, with users being enrolled into each course for which they are permitted to access; thus, in this case, the course is the context from which users launch into tool providers;&lt;br /&gt;
* ''resource link'' - this is the actual link provided within a context which users follow to access the tool provider; there may be multiple resource links to each tool provider within the same context and across the whole tool consumer but each resource link is uniquely identified.&lt;br /&gt;
&lt;br /&gt;
== LTI Releases ==&lt;br /&gt;
This document provides guidance for both the tool consumer and the tool provider components of an LTI 1 connection. At the time of writing, the following versions of LTI 1 have been released:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Version&lt;br /&gt;
!Release date&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|May 2010&lt;br /&gt;
|-&lt;br /&gt;
|1.1&lt;br /&gt;
|March 2012&lt;br /&gt;
|-&lt;br /&gt;
|1.1.1&lt;br /&gt;
|June 2012&lt;br /&gt;
|-&lt;br /&gt;
|1.2&lt;br /&gt;
|Public draft&lt;br /&gt;
|-&lt;br /&gt;
|2.0	&lt;br /&gt;
|January 2014&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
LTI version 2 provides a more extensible framework for implementing learning application/content integrations, but this document will focus essentially on LTI 1 because this is what is currently in use and widely available. At the time of writing LTI 1.2 is in public draft and extends LTI 1 with some of the features of LTI 2.0 (e.g. a tool consumer profile enabling discoverable services) thereby offering a stepping stone for systems looking to move from LTI 1 to LTI 2. [[LTI/Best Practice/References#IMS-A|[IMS-A]]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;comments /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=LTI/Best_Practice/Issues_for_Developers&amp;diff=15</id>
		<title>LTI/Best Practice/Issues for Developers</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=LTI/Best_Practice/Issues_for_Developers&amp;diff=15"/>
		<updated>2014-09-18T03:48:45Z</updated>

		<summary type="html">&lt;p&gt;Admin: Version from the original PDF document&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This section discusses issues relevant to those seeking to write an LTI tool provider application.&lt;br /&gt;
&lt;br /&gt;
== Anatomy of a launch request ==&lt;br /&gt;
The essence of LTI is the launch request. This is the mechanism used by a tool consumer to redirect a user to a tool provider. The fundamentals of this process are:&lt;br /&gt;
&lt;br /&gt;
* redirection is via the user's browser using an HTTP POST request;&lt;br /&gt;
* data is passed using POST data parameters with prescribed names;&lt;br /&gt;
* parameters may include data about the context and resource link from which the launch request originates, the user making the request, and the role of the user within the context;&lt;br /&gt;
* the connection is secured by a timestamp, a nonce value and an OAuth signature.&lt;br /&gt;
&lt;br /&gt;
A tool consumer will typically implement a launch by returning an HTML page to the user's browser consisting of a form containing all the launch parameters as hidden input elements. The form would be submitted automatically by a JavaScript function run when the page is loaded or, if JavaScript is not enabled, by the user clicking a submit button. In most cases, however, JavaScript is a requirement for the tool consumer and so the launch process should be invisible and seamless to the user.&lt;br /&gt;
&lt;br /&gt;
== Launch parameters ==&lt;br /&gt;
The names of supported parameters can be found in the LTI specification. [[LTI/Best Practice/References#IMS-B|[IMS-B]], Sections 3, 4.2 and 6] The only required parameters are:&lt;br /&gt;
&lt;br /&gt;
* lti_message_type&lt;br /&gt;
* lti_version&lt;br /&gt;
* resource_link_id&lt;br /&gt;
&lt;br /&gt;
plus the following OAuth parameters:&lt;br /&gt;
&lt;br /&gt;
* oauth_consumer_key&lt;br /&gt;
* oauth_signature_method&lt;br /&gt;
* oauth_timestamp&lt;br /&gt;
* oauth_nonce&lt;br /&gt;
* oauth_version&lt;br /&gt;
* oauth_signature&lt;br /&gt;
* oauth_callback&lt;br /&gt;
&lt;br /&gt;
So, as you can see, a launch request can be extremely minimal and need not include any data about the context, user or role. When a tool consumer or tool provider has been certified by IMS, some of the parameters recommended by the specification will also be present. These additional demands for certification are designed to enhance interoperability, whilst still allowing flexibility in the specification.&lt;br /&gt;
&lt;br /&gt;
== Security ==&lt;br /&gt;
Launch requests are secured by the tool consumer to allow the tool provider to verify their authenticity. The launch parameters include:&lt;br /&gt;
&lt;br /&gt;
* ''oauth_consumer_key'' – the unique identifier for the tool consumer;&lt;br /&gt;
* ''oauth_timestamp'' – the current Unix epoch time from the tool consumer server;&lt;br /&gt;
* ''oauth_nonce'' – a unique value for the request;&lt;br /&gt;
* ''oauth_signature'' – a hash of the data included in the message generated using a shared secret.&lt;br /&gt;
&lt;br /&gt;
The consumer key is generated by the tool provider who should ensure that all the keys issued are unique and are used only for a single tool consumer system. For example, separate keys should be issued for development, test and production environments. The unique keys may be generated in any manner; for example, based on the client's domain name, or a random GUID.&lt;br /&gt;
&lt;br /&gt;
The timestamp should be checked to ensure it is current (within a small margin of error from the system time on the tool provider server). Any request received which re-uses a nonce value (from the same tool consumer) within the permitted timestamp range should be rejected. The signature should be re-generated by the tool provider using the shared secret and compared with the value received. The shared secret should be a random string of a reasonable length to prevent it from being easily guessed or recreated. It should be shared with the tool consumer in a secure manner so as to maintain its privacy between the two parties.&lt;br /&gt;
&lt;br /&gt;
These mechanisms ensure that the data in requests has not been changed in transit from the tool consumer to the tool provider (which would otherwise be easy to do since the data is passed via the user's browser) and that the request is current and has not been received before. Refer to the OAuth documentation for more details. [[LTI/Best Practice/References#OAuth-A|[OAuth-A]]] In addition it is recommended that tool providers deliver their services through connections using https to provide additional security of the data being transmitted (which is not encrypted in the request).&lt;br /&gt;
&lt;br /&gt;
== Receiving a launch request ==&lt;br /&gt;
The endpoint URL provided to tool consumers for LTI launches will need to be a script which is capable of processing the request. A typical script would perform the following actions:&lt;br /&gt;
&lt;br /&gt;
# Ensure all the required LTI parameters are present and have appropriate values: the lti_message_type and lti_version should have their prescribed values, and the resource_link_id and oauth_consumer_key parameters should not be empty.&lt;br /&gt;
# Check that the request comes from a known tool consumer: look up the consumer key to make sure a shared secret is recorded for it.&lt;br /&gt;
# Verify the authenticity of the request: check the timestamp and nonce values, and generate the OAuth signature from the HTTP request and check that it matches the signature value received.&lt;br /&gt;
# Ensure that any parameters which your system depends upon are present in the request: remember that most of the LTI launch parameters are not required by the specification and so whilst the launch request may be valid it may not provide sufficient data for your needs but, wherever possible, such dependencies should be avoided (see below).&lt;br /&gt;
&lt;br /&gt;
{{anchor|CS1}}&lt;br /&gt;
{{Infobox&lt;br /&gt;
|title = Case Study 1 – WebPA launch&lt;br /&gt;
|titlestyle = background-color: #fff; color: #000;&lt;br /&gt;
|bodystyle = background-color: #008080; color: #fff;&lt;br /&gt;
|datastyle = text-align: left;&lt;br /&gt;
|data1 = ''Required parameters:''&lt;br /&gt;
: resource_link_id, user_id,roles&lt;br /&gt;
&lt;br /&gt;
''Default parameter values generated for:''&lt;br /&gt;
: context title,&amp;lt;br&amp;gt;resource_link_title&amp;lt;br&amp;gt;lis_person_name_given&amp;lt;br&amp;gt;lis_person_name_family&lt;br /&gt;
&lt;br /&gt;
''Launch process:''&lt;br /&gt;
* create new module (or update existing) based on resource_link_id&lt;br /&gt;
* create new user account (or update existing) based on user_id&lt;br /&gt;
* ensure user account has a type of either &amp;quot;Student&amp;quot; or &amp;quot;Tutor&amp;quot; depending upon the role(s) passed&lt;br /&gt;
}}&lt;br /&gt;
If you reach this point it means that you have a valid launch request from a known customer with all the data you require. Hence it is now safe to process the request and provide access to the user. This may involve the following actions:&lt;br /&gt;
&lt;br /&gt;
# Check if this is the first request from the resource link; if so, create any work area, space or other objects required for activity to take place for launches from this link; if not, update the existing objects with any values which have changed (e.g. the name or description).&lt;br /&gt;
# Check if this is the first request from the user; if so, create any user account needed to enable them to access your system; if not, update any existing account with any details which have changed (e.g. name or email address).&lt;br /&gt;
# Ensure the user has the appropriate permissions for accessing the resource link space; for an existing user this may mean changing their privileges if their role has changed.&lt;br /&gt;
# Establish a login session for the user.&lt;br /&gt;
# Redirect the user to an appropriate &amp;quot;home&amp;quot; page; this may depend upon the resource being accessed and the user's role.&lt;br /&gt;
&lt;br /&gt;
The precise nature of these actions will depend upon the type of system which is being accessed. Access to content, for example, may not require the creation of user accounts, but may only involve associating the resource link ID with a content item by a user with an appropriate role (such as an instructor). On the other hand, an application like WebPA&amp;lt;sup&amp;gt;&amp;amp;reg;&amp;lt;/sup&amp;gt; [[LTI/Best Practice/References#WebPA|[WebPA]]]  would provision a new assessment and user as part of the launch request.&lt;br /&gt;
&lt;br /&gt;
== Identity values ==&lt;br /&gt;
One of the most important tasks in developing an LTI integration is that of selecting appropriate values by which each element can be identified within the tool provider application. The elements which may require a unique identity are:&lt;br /&gt;
&lt;br /&gt;
* contexts;&lt;br /&gt;
* resource links; and&lt;br /&gt;
* users.&lt;br /&gt;
&lt;br /&gt;
In all cases, the unique ID for an element should be combined with the consumer key to ensure it is unique across a tool provider application which may be connected to more than one tool consumer.&lt;br /&gt;
&lt;br /&gt;
=== Contexts ===&lt;br /&gt;
In many cases the context from which a launch originated is of no interest to a tool provider – the fact that two resource links are located in the same context does not mean that a user has permissions to access both of these resources, the tool consumer may have additional access rules in place which limit who can see specific links (for example, using the ''conditional access'' functionality in Moodle to control whether an activity or resource can be accessed by individual users). Hence a launch request should not be used to imply anything about a user's access to any other resource links, even within the same context. However, there may be occasions when the context is of interest; for example, when gathering statistics for teachers. The context is uniquely identified by the &amp;lt;code&amp;gt;context_id&amp;lt;/code&amp;gt; parameter which has a status of &amp;quot;recommended&amp;quot; in the LTI specification.&lt;br /&gt;
&lt;br /&gt;
=== Resource links ===&lt;br /&gt;
The &amp;lt;code&amp;gt;resource_link_id&amp;lt;/code&amp;gt; parameter should be present on every launch and provides a unique ID for the specific link within the tool consumer which was followed by the user. This value may be used to associate the launch request with a resource/activity within the tool provider, either by using the same ID or by implementing a one-to-one mapping between the tool consumer and tool provider IDs.&lt;br /&gt;
&lt;br /&gt;
=== Users ===&lt;br /&gt;
The user ID value can be as simple as that for a resource link, but this does depend upon how a tool provider enforces the authorisation of users to access resources. An LTI launch request merely indicates to a tool provider that the specified user has the ability to access the specified resource link (with the specified role(s), if any). It makes no statement about the user's authority to access any other resources which may exist for the same tool consumer or context. Thus, when adding LTI support to an application which allows a user to navigate between different resource instances, there is a danger that this may allow an LTI user to use this navigation to access a resource other than the one associated with the link they launched from. To mitigate against this risk it may be appropriate to create user accounts with a different scope level:&lt;br /&gt;
&lt;br /&gt;
# ''Consumer:'' combine the consumer key with the &amp;lt;code&amp;gt;user_id&amp;lt;/code&amp;gt; parameter;&lt;br /&gt;
# ''Context:'' combine the consumer key with the &amp;lt;code&amp;gt;context_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;user_id&amp;lt;/code&amp;gt; parameters;&lt;br /&gt;
# ''Resource link:'' combine the consumer key with the &amp;lt;code&amp;gt;resource_link_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;user_id&amp;lt;/code&amp;gt; parameters.&lt;br /&gt;
&lt;br /&gt;
The ''Consumer'' choice guarantees to provide you with a unique ID for each user within the tool provider system. However, its use does mean that the tool provider will use the same user ID for launches from all the resource links added in the tool consumers. Thus, there is a possibility that users following one resource link, may be able to access content linked from another resource link, thereby bypassing the authorisation process provided by the tool consumer through an LTI launch request. For example, a student may have been unenrolled from a course in the VLE and, therefore, no longer have access to the resource links in that course. If launching from another course allows them to access the end points of these resource links, then the tool provider has effectively provided a back door for users to access resources which they should have been disconnected from. Some solutions to this problem may be available to you. For example, if you control the code for the tool provider application, you can prevent users from switching to a different resource after a launch (this is how the LTI connector for WebPA works). Alternatively, if the tool consumer supports the unofficial memberships service [[LTI/Best Practice/References#IMS-C|[IMS-C]]], the list of users for each resource link can be updated on a regular basis (e.g. nightly) so any impact will only be short-lived.&lt;br /&gt;
&lt;br /&gt;
The ''Context'' choice is similar to the ''Consumer'' choice (see above) except that it implements an ID value which is unique within a context (e.g. a course). If all resource links within a context are always available to all users enrolled in that context, then there is no issue about providing a back door method for accessing resources. However, if access to some resource links might be restricted to a subset of the enrolled users (e.g. via a conditional release mechanism) then this choice could also provide a way for users to bypass the authorisation implemented by the tool consumer (for which similar solutions as discussed above could be implemented).&lt;br /&gt;
&lt;br /&gt;
{{anchor|CS2}}&lt;br /&gt;
{{Infobox&lt;br /&gt;
|title = Case Study 2 – User scope in WordPress&lt;br /&gt;
|titlestyle = background-color: #fff; color: #000;&lt;br /&gt;
|bodystyle = background-color: #008080; color: #fff;&lt;br /&gt;
|datastyle = text-align: left;&lt;br /&gt;
|data1 = A case could be made for each of the different user scopes in WordPress, so rather than selecting one at random, the &lt;br /&gt;
administrator is given four choices when configuring a new tool consumer. The selected option is used as a prefix to the generated &lt;br /&gt;
consumer key:&lt;br /&gt;
* WP1 – resource&lt;br /&gt;
* WP2 – context&lt;br /&gt;
* WP3 – consumer&lt;br /&gt;
* WP4 – global&lt;br /&gt;
}}&lt;br /&gt;
The'' Resource link'' option for creating user ID values is the closest fit to the expectations of the LTI specification. A downside of implementing this choice is that it means that a separate user account will be created in the tool provider for every combination of &amp;lt;code&amp;gt;user_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;resource_link_id&amp;lt;/code&amp;gt; parameters (and for each consumer key). Thus, if a course has 5 links to the tool provider, a user following each of these links will have 5 separate user accounts created in the tool provider. But if you do not have control over the tool provider code then this is a sure way of preventing a user from bypassing the authorisation implemented by the tool consumer - each user will, by definition, only have access to a single resource; accessing other resources must be achieved via a separate user account (accessed by launching from a different resource link in the tool consumer).&lt;br /&gt;
&lt;br /&gt;
So there are choices for how to implement a unique user ID when developing a tool provider LTI integration and that choice will depend largely on the navigation features of the application and an evaluation of the risks associated with users gaining access to other resources from a launch. [[LTI/Best Practice/References#ceLTIc-A|[ceLTIc-A]]]  But, of course, the choice can be left to the system administrator so that it can be selected to match the needs of a particular tool consumer, as was the case with the LTI connector written for WordPress. [[LTI/Best Practice/References#SPVSP-A|[SPVSP-A]]] &lt;br /&gt;
&lt;br /&gt;
=== Matching IDs with pre-provisioned data ===&lt;br /&gt;
There are times when a tool provider may already be populated with data related to a tool consumer; for example, course and/or user data. In these situations, there may also be a desire to relate this data with the values received on LTI launch requests. The problem here is that the &amp;lt;code&amp;gt;context_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;user&amp;lt;/code&amp;gt;_id parameters are deliberately intended to be opaque by the LTI specification and are often represented by values such as database keys from the VLE. It is, therefore, unlikely that such values would match with any pre-provisioned data which has more likely originated from a different system, such as a student information/record system (SIS). The best suggestions to offer here are:&lt;br /&gt;
&lt;br /&gt;
# check whether the tool consumer has any choices over what values are used to populate the &amp;lt;code&amp;gt;context_id&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;user_id&amp;lt;/code&amp;gt; parameters passed on each launch (in case an alternative choice can be matched with existing data);&lt;br /&gt;
# if supported by the tool consumer, the values of the &amp;lt;code&amp;gt;lis_course_section_sourcedid&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;lis_person_sourcedid&amp;lt;/code&amp;gt; parameters may provide better matches;&lt;br /&gt;
# LTI 1.2+ includes a custom parameter substitution variable for a user's login ID (&amp;lt;code&amp;gt;User.username&amp;lt;/code&amp;gt;) as a way of helping to alleviate this situation; the course ID could be entered as a fixed custom parameter value for each launch link created. [[LTI/Best Practice/References#IMS-D|[IMS-D]], Appendix C.1]&lt;br /&gt;
&lt;br /&gt;
There may be a temptation to try matching users on names or email addresses, but this is fraught with problems. The values are not guaranteed to be unique or fixed within the tool consumer, and they may even be editable by the user themselves and so cannot be trusted to be valid. For a user ID, there is an option of prompting the user when they first connect to enter their pre-provisioned credentials so that they can be associated with their LTI identity in the future. Of course, if the matching of user IDs is designed to permit users to access the tool provider via their tool consumer or by logging in directly, then there is the same authorisation issue as described above when opting to use only the &amp;lt;code&amp;gt;user_id&amp;lt;/code&amp;gt; parameter as the unique ID: users may be given access to resources which they can no longer access via the tool consumer.&lt;br /&gt;
&lt;br /&gt;
=== LTI and SSO ===&lt;br /&gt;
This issue follows on from the wish to match LTI parameter values with pre-provisioned data. In this case the problem is more specific: is there some way in which a user launching via LTI can be associated with an SSO user account? The use case here is to allow a user to log into both the tool consumer and the tool provider using the same identity provider and be able to access the same resources (notwithstanding that the authorisation issue discussed above remains). A solution for this has been proposed by IMS [[LTI/Best Practice/References#IMS-E|[IMS-E]]], though no known implementation currently exists. Its elegance lies in its simplicity. On the assumption that both parties have trust relationships with the same identity provider, the LTI launch is extended to include two additional parameters: the type of SSO used to authenticate the user (e.g. CAS, CoSign, Shibboleth) and the URL of the identity provider. After validating the launch, the tool provider redirects the user to a script protected by the same identity provider. Since the user has already been authenticated, they will fall through this redirection and the tool provider now has access to their SSO identity (e.g. through the &amp;lt;code&amp;gt;REMOTE_USER&amp;lt;/code&amp;gt; environment variable). The SSO identity can be recorded against the user's LTI identity so that when the user next logs in directly their LTI identity can be looked up and access given to any resources associated with this account.&lt;br /&gt;
&lt;br /&gt;
== Roles ==&lt;br /&gt;
When the &amp;lt;code&amp;gt;roles&amp;lt;/code&amp;gt; parameter is included in the launch it specifies one or more roles the user has in respect of the resource link. The roles may be taken from the standard vocabularies listed in the LTI specification [[LTI/Best Practice/References#IMS-B|[IMS-B]], Appendix A]; they may also include vendor-specific roles, though these should always be in the form of a full URI.&lt;br /&gt;
&lt;br /&gt;
The most common roles a tool provider can expect to receive are:&lt;br /&gt;
&lt;br /&gt;
* Instructor;&lt;br /&gt;
* TeachingAssistant;&lt;br /&gt;
* Learner.&lt;br /&gt;
&lt;br /&gt;
Some tool consumers may also support roles of:&lt;br /&gt;
&lt;br /&gt;
* ContentDeveloper;&lt;br /&gt;
* Administrator.&lt;br /&gt;
&lt;br /&gt;
A tool provider has the tricky task of mapping the different roles which may be passed by different tool consumers onto its own set of supported roles. Some tool providers may not distinguish between different roles, in which case this area is a non-issue. Where roles are essentially divided between teachers and students, then the Learner role fits well with the latter, whilst the others could be accepted as the former. When a tool provider supports a wider range of roles there can be issues if a similar range is not mirrored in the tool consumer. For example, whilst a VLE may have separate roles for content developers (course builders) and instructors, they may also allow these roles to be held by the same user and, therefore, a tool provider must be able to deliver the functionality relating to both roles in a unified interface. Wherever, possible it makes sense for roles to be dichotomous, especially as different tool consumers may support different roles, so reliance on a specific role is not advised. Most tool consumer implementations of LTI hard-code the mapping between the internal role and the LTI role so the VLE administrator or teacher has little control over the roles which are passed. Only the open source PowerLink for WebCT [[LTI/Best Practice/References#SPVSP-B|[SPVSP-B]]] and the open source building block for Blackboard Learn 9 [[LTI/Best Practice/References#SPVSP-C|[SPVSP-C]]] are known to offer some flexibility in this respect and allow the mapping to be specified on a tool-by-tool basis, thereby allowing them to match the association deemed appropriate to the institution's needs; for example, giving teaching assistants a role in the tool provider which fits with the way in which this role is being used in the VLE. Without such mapping being generally available within tool consumers, any tool provider offering a rich set of roles is well advised to implement a mapping option which can be configured for each tool consumer, either by the tool provider administrator or perhaps by a user having an LTI role of system administrator.&lt;br /&gt;
&lt;br /&gt;
If a user has multiple roles, it is important to check that none of these conflict; that is, when received individually might lead to a different role being assigned to the user. If they do, then a deliberate choice should be made as to which role is to be assigned (assuming that only one role per user is permitted). For example, if a user has both a role of Learner and Instructor (which has been seen in a real launch request from a tool consumer), then the lowest level of privilege is given (Learner). However, this is an arbitrary choice, and the user could equally be given the highest level of privilege. Since the tool consumer is a trusted source of data, there is no clear basis on which to make either choice where the roles received are inconsistent with those supported within the tool provider.&lt;br /&gt;
&lt;br /&gt;
One final issue to be aware of is that roles may be passed from different vocabularies; for example system, institution and context. Most launch requests are made from within a ''CourseSection'' and hence most roles received are expected to come from the context vocabulary. However, there are instances where launch requests can be made from outside a ''CourseSection'' [[LTI/Best Practice/References#ceLTIc-B|[ceLTIc-B]]] [[LTI/Best Practice/References#ceLTIc-C|[ceLTIc-C]]] and so an appropriate response to these requests should be implemented. Similarly, a user launching from within a ''CourseSection'', may have a relevant role from a different vocabulary; the most relevant example being a system administrator. A tool provider may offer an interface to the system administrator from the tool consumer, but it may not be the case that such a user is able to perform a launch request or, if they can, that their role will be passed. In fact there are several possible administrator roles which could conceivable be relevant here; for example:&lt;br /&gt;
&lt;br /&gt;
* urn:lti:sysrole:ims/lis/SysAdmin&lt;br /&gt;
* urn:lti:sysrole:ims/lis/SysSupport&lt;br /&gt;
* urn:lti:sysrole:ims/lis/Administrator&lt;br /&gt;
* urn:lti:instrole:ims/lis/Administrator&lt;br /&gt;
* urn:lti:role:ims/lis/Administrator&lt;br /&gt;
* urn:lti:role:ims/lis/Administrator/Support&lt;br /&gt;
* urn:lti:role:ims/lis/Administrator/SystemAdministrator&lt;br /&gt;
&lt;br /&gt;
The key here is probably to check for any or all of these so that whichever a tool consumer might send is recognised.&lt;br /&gt;
&lt;br /&gt;
There is scope in this area for tool consumers to be more explicit about the LTI roles they support and the mapping used from their internal roles. This would allow tool providers to make more informed choices as to how to respond to roles received in each tool consumer launch.&lt;br /&gt;
&lt;br /&gt;
== CSS ==&lt;br /&gt;
The release of LTI 1.1 introduced a new launch parameter named &amp;lt;code&amp;gt;launch_presentation_css_url&amp;lt;/code&amp;gt;. This allows a tool consumer to pass the URL of a local CSS file. It does not, as yet, appear to have been widely implemented. There is also potential confusion as to whether it should be a URL to the CSS file for the tool consumer, or a URL to a tool-specific CSS file to apply when the tool provider is launched from that tool consumer. A CSS file is most useful if it overrides style names used by the tool provider to customise the appearance of the application and make it better fit within the local environment. A CSS file consisting of the styles adopted by the tool consumer would be problematic for a tool provider to apply in a simple and meaningful way. However, the LTI connector for WebPA and the open source building block for Blackboard Learn 9 are the only known implementations which support a tool-specific CSS URL. [[LTI/Best Practice/References#SPVSP-D|[SPVSP-D]]] &lt;br /&gt;
&lt;br /&gt;
== Override interface ==&lt;br /&gt;
{{anchor|CS3}}&lt;br /&gt;
{{Infobox&lt;br /&gt;
|title = Case Study 3 – Custom parameters supported by WebPA&lt;br /&gt;
|titlestyle = background-color: #fff; color: #000;&lt;br /&gt;
|bodystyle = background-color: #008080; color: #fff;&lt;br /&gt;
|datastyle = text-align: left;&lt;br /&gt;
|data1 = &lt;br /&gt;
* logo&lt;br /&gt;
* logo_width&lt;br /&gt;
* logo_height&lt;br /&gt;
* name&lt;br /&gt;
* css&lt;br /&gt;
* email_help&lt;br /&gt;
* email_noreply&lt;br /&gt;
* return_menu_text&lt;br /&gt;
}}&lt;br /&gt;
As well as using CSS to change the behaviour of a tool provider, other parameters may also be used to help tailor an interface to fit specific tool consumers. The following parameters about the tool consumer may be provided on a launch:&lt;br /&gt;
&lt;br /&gt;
* tool_consumer_instance_guid&lt;br /&gt;
* tool_consumer_instance_name&lt;br /&gt;
* tool_consumer_instance_description&lt;br /&gt;
* tool_consumer_instance_url&lt;br /&gt;
* tool_consumer_instance_contact_email&lt;br /&gt;
* tool_consumer_info_product_family_code&lt;br /&gt;
* tool_consumer_info_version&lt;br /&gt;
&lt;br /&gt;
The last two were added in LTI 1.1 and provide the most convenient mechanism for identifying the type of tool consumer from which a launch request has originated. For example, if the value of the &amp;lt;code&amp;gt;tool_consumer_info_product_family_code&amp;lt;/code&amp;gt; parameter is &amp;quot;&amp;lt;code&amp;gt;Blackboard Learn&amp;lt;/code&amp;gt;&amp;quot; or &amp;quot;&amp;lt;code&amp;gt;learn&amp;lt;/code&amp;gt;&amp;quot; then the launch has come from Blackboard Learn 9, using either the core functionality or the open source building block, respectively. This would allow a tool provider to offer a different experience for Learn 9 users, which may be especially relevant when being opened within a frame or iframe.&lt;br /&gt;
&lt;br /&gt;
It is also possible, though perhaps less likely, to customise the tool provider experience for a specific tool consumer (rather than a family, or brand, of tool consumers). The &amp;lt;code&amp;gt;tool_consumer_instance_guid&amp;lt;/code&amp;gt; parameter should provide a unique ID for a tool consumer and can be used for this purpose, if required.&lt;br /&gt;
&lt;br /&gt;
== Branding ==&lt;br /&gt;
By using LTI a tool provider can easily offer a multi-tenanted service from a single instance of the application. However, though the use of custom launch parameters, it can be possible to provide some branding of this service for individual tool consumers. For example, these may be to provide an alternative logo, title, contact email address, URL for help, etc. They may also be used as an alternative means of passing values which are not consistently supported by all tool consumers; for example, the LTI connector for WebPA accepts a tool-specific CSS file URL in a custom parameter named css. [[LTI/Best Practice/References#SPVSP-D|[SPVSP-D]]]&lt;br /&gt;
&lt;br /&gt;
== Course archive/restore/copy ==&lt;br /&gt;
LTI 1 does not provide a standard mechanism for a tool provider to distinguish between a launch request coming from a brand new resource link and one coming from a link which has been generated by making a copy of an existing one. In some cases this may not be important, but some tool providers may wish to offer teachers the option to also duplicate the content from the existing link. One workaround to this situation is to include a custom parameter in the launch request with a value which can be matched against the &amp;lt;code&amp;gt;resource_link_id&amp;lt;/code&amp;gt; parameter on launch; if the value matches against a different &amp;lt;code&amp;gt;resource_link_id&amp;lt;/code&amp;gt; then this would suggest that the launch comes from a copy. Such a solution involves some action on the part of the teacher, unless the resource link is created using the Content-item message process [[LTI/Best Practice/References#IMS-F|[IMS-F]]] in which case the tool provider could automatically add the custom parameter required to record its local reference to the resource/content.&lt;br /&gt;
&lt;br /&gt;
An alternative solution being discussed with the IMS community is to recommend an additional parameter to launch requests which provides a history of the resource link as a list of any previous resource link IDs from which it has been copied. This parameter may have a name of &amp;lt;code&amp;gt;ext_copy_of_resource_link_id&amp;lt;/code&amp;gt;; each ID would be separated by a comma with the most recent copy first. But, at the time of writing, this is just a topic for discussion with no known implementations.&lt;br /&gt;
&lt;br /&gt;
== Class libraries ==&lt;br /&gt;
Most of the verification of the authenticity of a launch request can be handled by an OAuth library which is available for most programming languages.[[LTI/Best Practice/References#OAuth-B|[OAuth-B]]]  For example, a method to verify a request in Java can be as simple as the following (using the BLTI Sandwich sample code [[LTI/Best Practice/References#BLTIS|[BLTIS]]]):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;background-color: #ffff99;&amp;quot;&amp;gt;&lt;br /&gt;
public static boolean isValid(String key, String secret) {&lt;br /&gt;
  try { &lt;br /&gt;
    SimpleOAuthValidator simpleoauthvalidator = new SimpleOAuthValidator(); &lt;br /&gt;
    OAuthConsumer oauthconsumer = new OAuthConsumer(&amp;quot;about:blank&amp;quot;, key, secret, null);&lt;br /&gt;
    simpleoauthvalidator.validateMessage(bltimessage.getOAuthMessage(), new OAuthAccessor(oauthconsumer)); &lt;br /&gt;
  } catch (Exception exception) { &lt;br /&gt;
    return false; &lt;br /&gt;
  } &lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
However, this is just part of the processing of a launch request; other standard tasks include:&lt;br /&gt;
&lt;br /&gt;
* verifying that the request complies with the LTI specification;&lt;br /&gt;
* ensure all the parameters required for the tool provider application are included;&lt;br /&gt;
* assemble the user, context and resource link data supplied in useful objects; this might include generating default values for missing parameters and assembling values based on how they were sent (such as the user's name which might be passed as separate given and family names, or as a full name, or as both);&lt;br /&gt;
* redirecting a user when an error arises with the launch.&lt;br /&gt;
&lt;br /&gt;
Rather than writing your own library to handle this process, why not consider using one which is already available? For example, the ceLTIc project has produced LTI Tool Provider class libraries for PHP [[LTI/Best Practice/References#SPVSP-E|[SPVSP-E]]] and Java [[LTI/Best Practice/References#SPVSP-F|[SPVSP-F]]]. Using and contributing to such open source libraries has the following additional benefits:&lt;br /&gt;
&lt;br /&gt;
* keeps application code separate from the details of the LTI specification;&lt;br /&gt;
* simplified validation of launch parameters;&lt;br /&gt;
* simpler to support any changes in the LTI specification;&lt;br /&gt;
* should help to ensure that applications will pass IMS certification tests;&lt;br /&gt;
* support included for LTI services (including unofficial extensions with automatic use of whichever service is supported by the tool consumer where alternatives are available);&lt;br /&gt;
&lt;br /&gt;
In addition, a class library may provide additional functionality to support typical workflows involved in building tool providers. For example, the ceLTIc class libraries include functionality for:&lt;br /&gt;
&lt;br /&gt;
* enabling resource links to be automatically mapped onto a single ID so that users can collaborate in a single space (these resource links may be from the same tool consumer or from different ones);&lt;br /&gt;
* allowing consumer keys to be easily enabled or disabled;&lt;br /&gt;
* setting start and end times for the validity of a consumer key.&lt;br /&gt;
&lt;br /&gt;
The last of these additions has been used by the ceLTIc project to automate the process of generating credentials (consumer key and shared secrets) on demand for trial/demonstration purposes which automatically expire. [[LTI/Best Practice/References#ceLTIc-D|[ceLTIc-D]]]&lt;br /&gt;
&lt;br /&gt;
== Browser issues ==&lt;br /&gt;
LTI is susceptible to all the issues surrounding web-based applications; this section raises some of those most likely to be encountered when using LTI, most relate to using frames or iframes.&lt;br /&gt;
&lt;br /&gt;
=== Third-party cookies ===&lt;br /&gt;
It is highly likely that the tool consumer and tool provider will be served from different domains and this can be problematic when they are mixed on the same page using a frame or an iframe. This is because tool providers will typically use sessions to remember the state of a user's interaction and this session is identified via a cookie in the HTTP request headers. However, different browsers have different rules and default settings for allowing cookies from different domains (third party cookies) within the same page. If a browser has been set to reject third party cookies, then the session cookie for a tool provider opened in a frame or iframe will not be saved and so the login will fail. Internet Explorer (IE) implements a slightly more complicated solution. By default, for domains in the Internet Zone, IE &amp;quot;blocks third-party cookies that save information that can be used to contact you without your explicit consent&amp;quot;. It determines whether a cookie contains personally identifiable information by consulting a policy written using the Platform for Privacy Preferences Project (P3P) protocol. Where appropriate, adding the P3P policy files to the tool provider server and including a P3P header in HTTP response headers can help alleviate this issue. [[LTI/Best Practice/References#ceLTIc-E|[ceLTIc-E]]]&lt;br /&gt;
&lt;br /&gt;
Of course, to completely avoid the problem, ensure that a tool provider is opened in a new window (or tab)! Although it is also quite possible for a tool provider to reside on the same server as the tool consumer, again avoiding any cross-domain issues. [[LTI/Best Practice/References#ceLTIc-F|[ceLTIc-F]]]&lt;br /&gt;
&lt;br /&gt;
=== Internet Explorer zones ===&lt;br /&gt;
Internet Explorer (IE) divides the world into Internet, Local Intranet, Trusted Zones, and Restricted Sites. For the majority of users using their own machines most (or all) of the pages they access via IE will be in the Internet zone. However, issues can arise when the contents of a frame (or iframe) are delivered from a server which is in a different zone from the page itself. When this occurs, for example, with WebPA, attempts to download XML reports fail because IE receives the response from WebPA but re-sends the request but without the session cookie header and so it is declined by the WebPA server. This issue only arises when the two servers are in different IE zones.&lt;br /&gt;
&lt;br /&gt;
=== Support for frames/iframes ===&lt;br /&gt;
There is no requirement in LTI for a tool provider to deliver its content within a frame (or iframe). It may, for example, not make sense given the nature of the application and its UI. The recommended &amp;lt;code&amp;gt;launch_presentation_document_target&amp;lt;/code&amp;gt; launch parameter should identify where the content requested is to be displayed. A launch request could be rejected (with an appropriate message) if an attempt is made to open the tool provider in a frame; this should be simple for the teacher (or system administrator) to resolve by merely altering the launch settings to select the &amp;quot;new window&amp;quot; option. Alternatively, a tool provider might choose to override the choice by using JavaScript to detect that a launch is occurring within a frame and force the page to be displayed within a new window (or tab). In this case an appropriate message should be displayed within the frame or, if a return URL has been supplied, the frame could be redirected to this URL with a message informing the user that the content should be available in a separate window. Which solution to choose is fairly arbitrary, though the former could be preferred on the basis that it does not usurp the request made by the tool consumer.&lt;br /&gt;
&lt;br /&gt;
Of course, if the parameter is not provided on launch then a JavaScript solution is the only option and it could be seen as being more acceptable to force the display into a new window since the tool consumer failed to note a preference!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;comments /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=MediaWiki:Common.css&amp;diff=14</id>
		<title>MediaWiki:Common.css</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=MediaWiki:Common.css&amp;diff=14"/>
		<updated>2014-09-18T03:45:43Z</updated>

		<summary type="html">&lt;p&gt;Admin: Created page with &amp;quot;/* CSS placed here will be applied to all skins */ /* Infobox template style */ .infobox {     border: 1px solid #aaa;     background-color: #f9f9f9;     color: black;     /*...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* CSS placed here will be applied to all skins */&lt;br /&gt;
/* Infobox template style */&lt;br /&gt;
.infobox {&lt;br /&gt;
    border: 1px solid #aaa;&lt;br /&gt;
    background-color: #f9f9f9;&lt;br /&gt;
    color: black;&lt;br /&gt;
    /* @noflip */&lt;br /&gt;
    margin: 0.5em 0 0.5em 1em;&lt;br /&gt;
    padding: 0.2em;&lt;br /&gt;
    /* @noflip */&lt;br /&gt;
    float: right;&lt;br /&gt;
    /* @noflip */&lt;br /&gt;
    clear: right;&lt;br /&gt;
    /* @noflip */&lt;br /&gt;
    text-align: left;&lt;br /&gt;
    font-size: 88%;&lt;br /&gt;
    line-height: 1.5em;&lt;br /&gt;
}&lt;br /&gt;
.infobox caption {&lt;br /&gt;
    font-size: 125%;&lt;br /&gt;
    font-weight: bold;&lt;br /&gt;
}&lt;br /&gt;
.infobox td,&lt;br /&gt;
.infobox th {&lt;br /&gt;
    vertical-align: top;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=Special:Badtitle/NS828:TableTools&amp;diff=13</id>
		<title>Special:Badtitle/NS828:TableTools</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=Special:Badtitle/NS828:TableTools&amp;diff=13"/>
		<updated>2014-09-18T03:39:01Z</updated>

		<summary type="html">&lt;p&gt;Admin: Created page with &amp;quot;--[[ ------------------------------------------------------------------------------------ --                               TableTools                                       --...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;--[[&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
--                               TableTools                                       --&lt;br /&gt;
--                                                                                --&lt;br /&gt;
-- This module includes a number of functions for dealing with Lua tables.        --&lt;br /&gt;
-- It is a meta-module, meant to be called from other Lua modules, and should     --&lt;br /&gt;
-- not be called directly from #invoke.                                           --&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
--]]&lt;br /&gt;
 &lt;br /&gt;
local libraryUtil = require('libraryUtil')&lt;br /&gt;
 &lt;br /&gt;
local p = {}&lt;br /&gt;
 &lt;br /&gt;
-- Define often-used variables and functions.&lt;br /&gt;
local floor = math.floor&lt;br /&gt;
local infinity = math.huge&lt;br /&gt;
local checkType = libraryUtil.checkType&lt;br /&gt;
 &lt;br /&gt;
--[[&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
-- isPositiveInteger&lt;br /&gt;
--&lt;br /&gt;
-- This function returns true if the given value is a positive integer, and false&lt;br /&gt;
-- if not. Although it doesn't operate on tables, it is included here as it is&lt;br /&gt;
-- useful for determining whether a given table key is in the array part or the&lt;br /&gt;
-- hash part of a table.&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
--]]&lt;br /&gt;
function p.isPositiveInteger(v)&lt;br /&gt;
	if type(v) == 'number' and v &amp;gt;= 1 and floor(v) == v and v &amp;lt; infinity then&lt;br /&gt;
		return true&lt;br /&gt;
	else&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
--[[&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
-- isNan&lt;br /&gt;
--&lt;br /&gt;
-- This function returns true if the given number is a NaN value, and false&lt;br /&gt;
-- if not. Although it doesn't operate on tables, it is included here as it is&lt;br /&gt;
-- useful for determining whether a value can be a valid table key. Lua will&lt;br /&gt;
-- generate an error if a NaN is used as a table key.&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
--]]&lt;br /&gt;
function p.isNan(v)&lt;br /&gt;
	if type(v) == 'number' and tostring(v) == '-nan' then&lt;br /&gt;
		return true&lt;br /&gt;
	else&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
--[[&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
-- shallowClone&lt;br /&gt;
--&lt;br /&gt;
-- This returns a clone of a table. The value returned is a new table, but all&lt;br /&gt;
-- subtables and functions are shared. Metamethods are respected, but the returned&lt;br /&gt;
-- table will have no metatable of its own.&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
--]]&lt;br /&gt;
function p.shallowClone(t)&lt;br /&gt;
	local ret = {}&lt;br /&gt;
	for k, v in pairs(t) do&lt;br /&gt;
		ret[k] = v&lt;br /&gt;
	end&lt;br /&gt;
	return ret&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
--[[&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
-- removeDuplicates&lt;br /&gt;
--&lt;br /&gt;
-- This removes duplicate values from an array. Non-positive-integer keys are&lt;br /&gt;
-- ignored. The earliest value is kept, and all subsequent duplicate values are&lt;br /&gt;
-- removed, but otherwise the array order is unchanged.&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
--]]&lt;br /&gt;
function p.removeDuplicates(t)&lt;br /&gt;
	checkType('removeDuplicates', 1, t, 'table')&lt;br /&gt;
	local isNan = p.isNan&lt;br /&gt;
	local ret, exists = {}, {}&lt;br /&gt;
	for i, v in ipairs(t) do&lt;br /&gt;
		if isNan(v) then&lt;br /&gt;
			-- NaNs can't be table keys, and they are also unique, so we don't need to check existence.&lt;br /&gt;
			ret[#ret + 1] = v&lt;br /&gt;
		else&lt;br /&gt;
			if not exists[v] then&lt;br /&gt;
				ret[#ret + 1] = v&lt;br /&gt;
				exists[v] = true&lt;br /&gt;
			end&lt;br /&gt;
		end	&lt;br /&gt;
	end&lt;br /&gt;
	return ret&lt;br /&gt;
end			&lt;br /&gt;
 &lt;br /&gt;
--[[&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
-- numKeys&lt;br /&gt;
--&lt;br /&gt;
-- This takes a table and returns an array containing the numbers of any numerical&lt;br /&gt;
-- keys that have non-nil values, sorted in numerical order.&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
--]]&lt;br /&gt;
function p.numKeys(t)&lt;br /&gt;
	checkType('numKeys', 1, t, 'table')&lt;br /&gt;
	local isPositiveInteger = p.isPositiveInteger&lt;br /&gt;
	local nums = {}&lt;br /&gt;
	for k, v in pairs(t) do&lt;br /&gt;
		if isPositiveInteger(k) then&lt;br /&gt;
			nums[#nums + 1] = k&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	table.sort(nums)&lt;br /&gt;
	return nums&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
--[[&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
-- affixNums&lt;br /&gt;
--&lt;br /&gt;
-- This takes a table and returns an array containing the numbers of keys with the&lt;br /&gt;
-- specified prefix and suffix. For example, for the table&lt;br /&gt;
-- {a1 = 'foo', a3 = 'bar', a6 = 'baz'} and the prefix &amp;quot;a&amp;quot;, affixNums will&lt;br /&gt;
-- return {1, 3, 6}.&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
--]]&lt;br /&gt;
function p.affixNums(t, prefix, suffix)&lt;br /&gt;
	checkType('affixNums', 1, t, 'table')&lt;br /&gt;
	checkType('affixNums', 2, prefix, 'string', true)&lt;br /&gt;
	checkType('affixNums', 3, suffix, 'string', true)&lt;br /&gt;
 &lt;br /&gt;
	local function cleanPattern(s)&lt;br /&gt;
		-- Cleans a pattern so that the magic characters ()%.[]*+-?^$ are interpreted literally.&lt;br /&gt;
		s = s:gsub('([%(%)%%%.%[%]%*%+%-%?%^%$])', '%%%1')&lt;br /&gt;
		return s&lt;br /&gt;
	end&lt;br /&gt;
 &lt;br /&gt;
	prefix = prefix or ''&lt;br /&gt;
	suffix = suffix or ''&lt;br /&gt;
	prefix = cleanPattern(prefix)&lt;br /&gt;
	suffix = cleanPattern(suffix)&lt;br /&gt;
	local pattern = '^' .. prefix .. '([1-9]%d*)' .. suffix .. '$'&lt;br /&gt;
 &lt;br /&gt;
	local nums = {}&lt;br /&gt;
	for k, v in pairs(t) do&lt;br /&gt;
		if type(k) == 'string' then			&lt;br /&gt;
			local num = mw.ustring.match(k, pattern)&lt;br /&gt;
			if num then&lt;br /&gt;
				nums[#nums + 1] = tonumber(num)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	table.sort(nums)&lt;br /&gt;
	return nums&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
--[[&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
-- numData&lt;br /&gt;
--&lt;br /&gt;
-- Given a table with keys like (&amp;quot;foo1&amp;quot;, &amp;quot;bar1&amp;quot;, &amp;quot;foo2&amp;quot;, &amp;quot;baz2&amp;quot;), returns a table&lt;br /&gt;
-- of subtables in the format &lt;br /&gt;
-- { [1] = {foo = 'text', bar = 'text'}, [2] = {foo = 'text', baz = 'text'} }&lt;br /&gt;
-- Keys that don't end with an integer are stored in a subtable named &amp;quot;other&amp;quot;.&lt;br /&gt;
-- The compress option compresses the table so that it can be iterated over with&lt;br /&gt;
-- ipairs.&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
--]]&lt;br /&gt;
function p.numData(t, compress)&lt;br /&gt;
	checkType('numData', 1, t, 'table')&lt;br /&gt;
	checkType('numData', 2, compress, 'boolean', true)&lt;br /&gt;
	local ret = {}&lt;br /&gt;
	for k, v in pairs(t) do&lt;br /&gt;
		local prefix, num = mw.ustring.match(tostring(k), '^([^0-9]*)([1-9][0-9]*)$')&lt;br /&gt;
		if num then&lt;br /&gt;
			num = tonumber(num)&lt;br /&gt;
			local subtable = ret[num] or {}&lt;br /&gt;
			if prefix == '' then&lt;br /&gt;
				-- Positional parameters match the blank string; put them at the start of the subtable instead.&lt;br /&gt;
				prefix = 1&lt;br /&gt;
			end&lt;br /&gt;
			subtable[prefix] = v&lt;br /&gt;
			ret[num] = subtable&lt;br /&gt;
		else&lt;br /&gt;
			local subtable = ret.other or {}&lt;br /&gt;
			subtable[k] = v&lt;br /&gt;
			ret.other = subtable&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if compress then&lt;br /&gt;
		local other = ret.other&lt;br /&gt;
		ret = p.compressSparseArray(ret)&lt;br /&gt;
		ret.other = other&lt;br /&gt;
	end&lt;br /&gt;
	return ret&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
--[[&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
-- compressSparseArray&lt;br /&gt;
--&lt;br /&gt;
-- This takes an array with one or more nil values, and removes the nil values&lt;br /&gt;
-- while preserving the order, so that the array can be safely traversed with&lt;br /&gt;
-- ipairs.&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
--]]&lt;br /&gt;
function p.compressSparseArray(t)&lt;br /&gt;
	checkType('compressSparseArray', 1, t, 'table')&lt;br /&gt;
	local ret = {}&lt;br /&gt;
	local nums = p.numKeys(t)&lt;br /&gt;
	for _, num in ipairs(nums) do&lt;br /&gt;
		ret[#ret + 1] = t[num]&lt;br /&gt;
	end&lt;br /&gt;
	return ret&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
--[[&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
-- sparseIpairs&lt;br /&gt;
--&lt;br /&gt;
-- This is an iterator for sparse arrays. It can be used like ipairs, but can&lt;br /&gt;
-- handle nil values.&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
--]]&lt;br /&gt;
function p.sparseIpairs(t)&lt;br /&gt;
	checkType('sparseIpairs', 1, t, 'table')&lt;br /&gt;
	local nums = p.numKeys(t)&lt;br /&gt;
	local i = 0&lt;br /&gt;
	local lim = #nums&lt;br /&gt;
	return function ()&lt;br /&gt;
		i = i + 1&lt;br /&gt;
		if i &amp;lt;= lim then&lt;br /&gt;
			local key = nums[i]&lt;br /&gt;
			return key, t[key]&lt;br /&gt;
		else&lt;br /&gt;
			return nil, nil&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
--[[&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
-- size&lt;br /&gt;
--&lt;br /&gt;
-- This returns the size of a key/value pair table. It will also work on arrays,&lt;br /&gt;
-- but for arrays it is more efficient to use the # operator.&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
--]]&lt;br /&gt;
function p.size(t)&lt;br /&gt;
	checkType('size', 1, t, 'table')&lt;br /&gt;
	local i = 0&lt;br /&gt;
	for k in pairs(t) do&lt;br /&gt;
		i = i + 1&lt;br /&gt;
	end&lt;br /&gt;
	return i&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=Special:Badtitle/NS828:Arguments&amp;diff=12</id>
		<title>Special:Badtitle/NS828:Arguments</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=Special:Badtitle/NS828:Arguments&amp;diff=12"/>
		<updated>2014-09-18T03:37:22Z</updated>

		<summary type="html">&lt;p&gt;Admin: Created page with &amp;quot;-- This module provides easy processing of arguments passed to Scribunto from -- #invoke. It is intended for use by other Lua modules, and should not be -- called from #invoke...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;-- This module provides easy processing of arguments passed to Scribunto from&lt;br /&gt;
-- #invoke. It is intended for use by other Lua modules, and should not be&lt;br /&gt;
-- called from #invoke directly.&lt;br /&gt;
 &lt;br /&gt;
local libraryUtil = require('libraryUtil')&lt;br /&gt;
local checkType = libraryUtil.checkType&lt;br /&gt;
 &lt;br /&gt;
local arguments = {}&lt;br /&gt;
 &lt;br /&gt;
-- Generate four different tidyVal functions, so that we don't have to check the&lt;br /&gt;
-- options every time we call it.&lt;br /&gt;
 &lt;br /&gt;
local function tidyValDefault(key, val)&lt;br /&gt;
	if type(val) == 'string' then&lt;br /&gt;
		val = val:match('^%s*(.-)%s*$')&lt;br /&gt;
		if val == '' then&lt;br /&gt;
			return nil&lt;br /&gt;
		else&lt;br /&gt;
			return val&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		return val&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
local function tidyValTrimOnly(key, val)&lt;br /&gt;
	if type(val) == 'string' then&lt;br /&gt;
		return val:match('^%s*(.-)%s*$')&lt;br /&gt;
	else&lt;br /&gt;
		return val&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
local function tidyValRemoveBlanksOnly(key, val)&lt;br /&gt;
	if type(val) == 'string' then&lt;br /&gt;
		if val:find('%S') then&lt;br /&gt;
			return val&lt;br /&gt;
		else&lt;br /&gt;
			return nil&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		return val&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
local function tidyValNoChange(key, val)&lt;br /&gt;
	return val&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
function arguments.getArgs(frame, options)&lt;br /&gt;
	checkType('getArgs', 1, frame, 'table', true)&lt;br /&gt;
	checkType('getArgs', 2, options, 'table', true)&lt;br /&gt;
	frame = frame or {}&lt;br /&gt;
	options = options or {}&lt;br /&gt;
 &lt;br /&gt;
	--[[&lt;br /&gt;
	-- Get the argument tables. If we were passed a valid frame object, get the&lt;br /&gt;
	-- frame arguments (fargs) and the parent frame arguments (pargs), depending&lt;br /&gt;
	-- on the options set and on the parent frame's availability. If we weren't&lt;br /&gt;
	-- passed a valid frame object, we are being called from another Lua module&lt;br /&gt;
	-- or from the debug console, so assume that we were passed a table of args&lt;br /&gt;
	-- directly, and assign it to a new variable (luaArgs).&lt;br /&gt;
	--]]&lt;br /&gt;
	local fargs, pargs, luaArgs&lt;br /&gt;
	if type(frame.args) == 'table' and type(frame.getParent) == 'function' then&lt;br /&gt;
		if options.wrappers then&lt;br /&gt;
			--[[&lt;br /&gt;
			-- The wrappers option makes Module:Arguments look up arguments in&lt;br /&gt;
			-- either the frame argument table or the parent argument table, but&lt;br /&gt;
			-- not both. This means that users can use either the #invoke syntax&lt;br /&gt;
			-- or a wrapper template without the loss of performance associated&lt;br /&gt;
			-- with looking arguments up in both the frame and the parent frame.&lt;br /&gt;
			-- Module:Arguments will look up arguments in the parent frame&lt;br /&gt;
			-- if it finds the parent frame's title in options.wrapper;&lt;br /&gt;
			-- otherwise it will look up arguments in the frame object passed&lt;br /&gt;
			-- to getArgs.&lt;br /&gt;
			--]]&lt;br /&gt;
			local parent = frame:getParent()&lt;br /&gt;
			if not parent then&lt;br /&gt;
				fargs = frame.args&lt;br /&gt;
			else&lt;br /&gt;
				local title = parent:getTitle():gsub('/sandbox$', '')&lt;br /&gt;
				local found = false&lt;br /&gt;
				if type(options.wrappers) == 'table' then&lt;br /&gt;
					for _,v in pairs(options.wrappers) do&lt;br /&gt;
						if v == title then&lt;br /&gt;
							found = true&lt;br /&gt;
							break&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
				elseif options.wrappers == title then&lt;br /&gt;
					found = true&lt;br /&gt;
				end&lt;br /&gt;
 &lt;br /&gt;
				-- We test for false specifically here so that nil (the default) acts like true.&lt;br /&gt;
				if found or options.frameOnly == false then&lt;br /&gt;
					pargs = parent.args&lt;br /&gt;
				end&lt;br /&gt;
				if not found or options.parentOnly == false then&lt;br /&gt;
					fargs = frame.args&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			-- options.wrapper isn't set, so check the other options.&lt;br /&gt;
			if not options.parentOnly then&lt;br /&gt;
				fargs = frame.args&lt;br /&gt;
			end&lt;br /&gt;
			if not options.frameOnly then&lt;br /&gt;
				local parent = frame:getParent()&lt;br /&gt;
				pargs = parent and parent.args or nil&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		if options.parentFirst then&lt;br /&gt;
			fargs, pargs = pargs, fargs&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		luaArgs = frame&lt;br /&gt;
	end&lt;br /&gt;
 &lt;br /&gt;
	-- Set the order of precedence of the argument tables. If the variables are&lt;br /&gt;
	-- nil, nothing will be added to the table, which is how we avoid clashes&lt;br /&gt;
	-- between the frame/parent args and the Lua args.	&lt;br /&gt;
	local argTables = {fargs}&lt;br /&gt;
	argTables[#argTables + 1] = pargs&lt;br /&gt;
	argTables[#argTables + 1] = luaArgs&lt;br /&gt;
 &lt;br /&gt;
	--[[&lt;br /&gt;
	-- Generate the tidyVal function. If it has been specified by the user, we&lt;br /&gt;
	-- use that; if not, we choose one of four functions depending on the&lt;br /&gt;
	-- options chosen. This is so that we don't have to call the options table&lt;br /&gt;
	-- every time the function is called.&lt;br /&gt;
	--]]&lt;br /&gt;
	local tidyVal = options.valueFunc&lt;br /&gt;
	if tidyVal then&lt;br /&gt;
		if type(tidyVal) ~= 'function' then&lt;br /&gt;
			error(&lt;br /&gt;
				&amp;quot;bad value assigned to option 'valueFunc'&amp;quot;&lt;br /&gt;
					.. '(function expected, got '&lt;br /&gt;
					.. type(tidyVal)&lt;br /&gt;
					.. ')',&lt;br /&gt;
				2&lt;br /&gt;
			)&lt;br /&gt;
		end&lt;br /&gt;
	elseif options.trim ~= false then&lt;br /&gt;
		if options.removeBlanks ~= false then&lt;br /&gt;
			tidyVal = tidyValDefault&lt;br /&gt;
		else&lt;br /&gt;
			tidyVal = tidyValTrimOnly&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		if options.removeBlanks ~= false then&lt;br /&gt;
			tidyVal = tidyValRemoveBlanksOnly&lt;br /&gt;
		else&lt;br /&gt;
			tidyVal = tidyValNoChange&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
 &lt;br /&gt;
	--[[&lt;br /&gt;
	-- Set up the args, metaArgs and nilArgs tables. args will be the one&lt;br /&gt;
	-- accessed from functions, and metaArgs will hold the actual arguments. Nil&lt;br /&gt;
	-- arguments are memoized in nilArgs, and the metatable connects all of them&lt;br /&gt;
	-- together.&lt;br /&gt;
	--]]&lt;br /&gt;
	local args, metaArgs, nilArgs, metatable = {}, {}, {}, {}&lt;br /&gt;
	setmetatable(args, metatable)&lt;br /&gt;
 &lt;br /&gt;
	local function mergeArgs(iterator, tables)&lt;br /&gt;
		--[[&lt;br /&gt;
		-- Accepts multiple tables as input and merges their keys and values&lt;br /&gt;
		-- into one table using the specified iterator. If a value is already&lt;br /&gt;
		-- present it is not overwritten; tables listed earlier have precedence.&lt;br /&gt;
		-- We are also memoizing nil values, but those values can be&lt;br /&gt;
		-- overwritten.&lt;br /&gt;
		--]]&lt;br /&gt;
		for _, t in ipairs(tables) do&lt;br /&gt;
			for key, val in iterator(t) do&lt;br /&gt;
				if metaArgs[key] == nil then&lt;br /&gt;
					local tidiedVal = tidyVal(key, val)&lt;br /&gt;
					if tidiedVal == nil then&lt;br /&gt;
						nilArgs[key] = true&lt;br /&gt;
					else&lt;br /&gt;
						metaArgs[key] = tidiedVal&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
 &lt;br /&gt;
	--[[&lt;br /&gt;
	-- Define metatable behaviour. Arguments are memoized in the metaArgs table,&lt;br /&gt;
	-- and are only fetched from the argument tables once. Fetching arguments&lt;br /&gt;
	-- from the argument tables is the most resource-intensive step in this&lt;br /&gt;
	-- module, so we try and avoid it where possible. For this reason, nil&lt;br /&gt;
	-- arguments are also memoized, in the nilArgs table. Also, we keep a record&lt;br /&gt;
	-- in the metatable of when pairs and ipairs have been called, so we do not&lt;br /&gt;
	-- run pairs and ipairs on the argument tables more than once. We also do&lt;br /&gt;
	-- not run ipairs on fargs and pargs if pairs has already been run, as all&lt;br /&gt;
	-- the arguments will already have been copied over.&lt;br /&gt;
	--]]&lt;br /&gt;
 &lt;br /&gt;
	metatable.__index = function (t, key)&lt;br /&gt;
		--[[&lt;br /&gt;
		-- Fetches an argument when the args table is indexed. First we check&lt;br /&gt;
		-- to see if the value is memoized, and if not we try and fetch it from&lt;br /&gt;
		-- the argument tables. When we check memoization, we need to check&lt;br /&gt;
		-- metaArgs before nilArgs, as both can be non-nil at the same time.&lt;br /&gt;
		-- If the argument is not present in metaArgs, we also check whether&lt;br /&gt;
		-- pairs has been run yet. If pairs has already been run, we return nil.&lt;br /&gt;
		-- This is because all the arguments will have already been copied into&lt;br /&gt;
		-- metaArgs by the mergeArgs function, meaning that any other arguments&lt;br /&gt;
		-- must be nil.&lt;br /&gt;
		--]]&lt;br /&gt;
		local val = metaArgs[key]&lt;br /&gt;
		if val ~= nil then&lt;br /&gt;
			return val&lt;br /&gt;
		elseif metatable.donePairs or nilArgs[key] then&lt;br /&gt;
			return nil&lt;br /&gt;
		end&lt;br /&gt;
		for _, argTable in ipairs(argTables) do&lt;br /&gt;
			local argTableVal = tidyVal(key, argTable[key])&lt;br /&gt;
			if argTableVal == nil then&lt;br /&gt;
				nilArgs[key] = true&lt;br /&gt;
			else&lt;br /&gt;
				metaArgs[key] = argTableVal&lt;br /&gt;
				return argTableVal&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
 &lt;br /&gt;
	metatable.__newindex = function (t, key, val)&lt;br /&gt;
		-- This function is called when a module tries to add a new value to the&lt;br /&gt;
		-- args table, or tries to change an existing value.&lt;br /&gt;
		if options.readOnly then&lt;br /&gt;
			error(&lt;br /&gt;
				'could not write to argument table key &amp;quot;'&lt;br /&gt;
					.. tostring(key)&lt;br /&gt;
					.. '&amp;quot;; the table is read-only',&lt;br /&gt;
				2&lt;br /&gt;
			)&lt;br /&gt;
		elseif options.noOverwrite and args[key] ~= nil then&lt;br /&gt;
			error(&lt;br /&gt;
				'could not write to argument table key &amp;quot;'&lt;br /&gt;
					.. tostring(key)&lt;br /&gt;
					.. '&amp;quot;; overwriting existing arguments is not permitted',&lt;br /&gt;
				2&lt;br /&gt;
			)&lt;br /&gt;
		elseif val == nil then&lt;br /&gt;
			--[[&lt;br /&gt;
			-- If the argument is to be overwritten with nil, we need to erase&lt;br /&gt;
			-- the value in metaArgs, so that __index, __pairs and __ipairs do&lt;br /&gt;
			-- not use a previous existing value, if present; and we also need&lt;br /&gt;
			-- to memoize the nil in nilArgs, so that the value isn't looked&lt;br /&gt;
			-- up in the argument tables if it is accessed again.&lt;br /&gt;
			--]]&lt;br /&gt;
			metaArgs[key] = nil&lt;br /&gt;
			nilArgs[key] = true&lt;br /&gt;
		else&lt;br /&gt;
			metaArgs[key] = val&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
 &lt;br /&gt;
	metatable.__pairs = function ()&lt;br /&gt;
		-- Called when pairs is run on the args table.&lt;br /&gt;
		if not metatable.donePairs then&lt;br /&gt;
			mergeArgs(pairs, argTables)&lt;br /&gt;
			metatable.donePairs = true&lt;br /&gt;
			metatable.doneIpairs = true&lt;br /&gt;
		end&lt;br /&gt;
		return pairs(metaArgs)&lt;br /&gt;
	end&lt;br /&gt;
 &lt;br /&gt;
	metatable.__ipairs = function ()&lt;br /&gt;
		-- Called when ipairs is run on the args table.&lt;br /&gt;
		if not metatable.doneIpairs then&lt;br /&gt;
			mergeArgs(ipairs, argTables)&lt;br /&gt;
			metatable.doneIpairs = true&lt;br /&gt;
		end&lt;br /&gt;
		return ipairs(metaArgs)&lt;br /&gt;
	end&lt;br /&gt;
 &lt;br /&gt;
	return args&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
return arguments&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=Template:anchor&amp;diff=11</id>
		<title>Template:anchor</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=Template:anchor&amp;diff=11"/>
		<updated>2014-09-18T03:33:28Z</updated>

		<summary type="html">&lt;p&gt;Admin: Created page with &amp;quot;{{#invoke:Anchor|main}}&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{#invoke:Anchor|main}}&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=Template:Infobox&amp;diff=10</id>
		<title>Template:Infobox</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=Template:Infobox&amp;diff=10"/>
		<updated>2014-09-18T03:32:30Z</updated>

		<summary type="html">&lt;p&gt;Admin: Created page with &amp;quot;{{#invoke:Infobox|infobox}}&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{#invoke:Infobox|infobox}}&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=Special:Badtitle/NS828:Infobox&amp;diff=9</id>
		<title>Special:Badtitle/NS828:Infobox</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=Special:Badtitle/NS828:Infobox&amp;diff=9"/>
		<updated>2014-09-18T03:29:25Z</updated>

		<summary type="html">&lt;p&gt;Admin: Created page with &amp;quot;-- -- This module implements {{Infobox}} --   local p = {}   local HtmlBuilder = require('Module:HtmlBuilder')   local args = {} local origArgs local root   local function uni...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;--&lt;br /&gt;
-- This module implements {{Infobox}}&lt;br /&gt;
--&lt;br /&gt;
 &lt;br /&gt;
local p = {}&lt;br /&gt;
 &lt;br /&gt;
local HtmlBuilder = require('Module:HtmlBuilder')&lt;br /&gt;
 &lt;br /&gt;
local args = {}&lt;br /&gt;
local origArgs&lt;br /&gt;
local root&lt;br /&gt;
 &lt;br /&gt;
local function union(t1, t2)&lt;br /&gt;
    -- Returns the union of the values of two tables, as a sequence.&lt;br /&gt;
    local vals = {}&lt;br /&gt;
    for k, v in pairs(t1) do&lt;br /&gt;
        vals[v] = true&lt;br /&gt;
    end&lt;br /&gt;
    for k, v in pairs(t2) do&lt;br /&gt;
        vals[v] = true&lt;br /&gt;
    end&lt;br /&gt;
    local ret = {}&lt;br /&gt;
    for k, v in pairs(vals) do&lt;br /&gt;
        table.insert(ret, k)&lt;br /&gt;
    end&lt;br /&gt;
    return ret&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getArgNums(prefix)&lt;br /&gt;
    -- Returns a table containing the numbers of the arguments that exist&lt;br /&gt;
    -- for the specified prefix. For example, if the prefix was 'data', and&lt;br /&gt;
    -- 'data1', 'data2', and 'data5' exist, it would return {1, 2, 5}.&lt;br /&gt;
    local nums = {}&lt;br /&gt;
    for k, v in pairs(args) do&lt;br /&gt;
        local num = tostring(k):match('^' .. prefix .. '([1-9]%d*)$')&lt;br /&gt;
        if num then table.insert(nums, tonumber(num)) end&lt;br /&gt;
    end&lt;br /&gt;
    table.sort(nums)&lt;br /&gt;
    return nums&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function addRow(rowArgs)&lt;br /&gt;
    -- Adds a row to the infobox, with either a header cell&lt;br /&gt;
    -- or a label/data cell combination.&lt;br /&gt;
    if rowArgs.header then&lt;br /&gt;
        root&lt;br /&gt;
            .tag('tr')&lt;br /&gt;
                .addClass(rowArgs.rowclass)&lt;br /&gt;
                .attr('id', rowArgs.rowid)&lt;br /&gt;
                .tag('th')&lt;br /&gt;
                    .attr('colspan', 2)&lt;br /&gt;
                    .attr('id', rowArgs.headerid)&lt;br /&gt;
                    .addClass(rowArgs.class)&lt;br /&gt;
                    .addClass(args.headerclass)&lt;br /&gt;
                    .css('text-align', 'center')&lt;br /&gt;
                    .cssText(args.headerstyle)&lt;br /&gt;
                    .wikitext(rowArgs.header)&lt;br /&gt;
    elseif rowArgs.data then&lt;br /&gt;
        local row = root.tag('tr')&lt;br /&gt;
        row.addClass(rowArgs.rowclass)&lt;br /&gt;
        row.attr('id', rowArgs.rowid)&lt;br /&gt;
        if rowArgs.label then&lt;br /&gt;
            row&lt;br /&gt;
                .tag('th')&lt;br /&gt;
                    .attr('scope', 'row')&lt;br /&gt;
                    .attr('id', rowArgs.labelid)&lt;br /&gt;
                    .css('text-align', 'left')&lt;br /&gt;
                    .cssText(args.labelstyle)&lt;br /&gt;
                    .wikitext(rowArgs.label)&lt;br /&gt;
                    .done()&lt;br /&gt;
        end&lt;br /&gt;
        &lt;br /&gt;
        local dataCell = row.tag('td')&lt;br /&gt;
        if not rowArgs.label then &lt;br /&gt;
            dataCell&lt;br /&gt;
                .attr('colspan', 2)&lt;br /&gt;
                .css('text-align', 'center') &lt;br /&gt;
        end&lt;br /&gt;
        dataCell&lt;br /&gt;
            .attr('id', rowArgs.dataid)&lt;br /&gt;
            .addClass(rowArgs.class)&lt;br /&gt;
            .cssText(rowArgs.datastyle)&lt;br /&gt;
            .newline()&lt;br /&gt;
            .wikitext(rowArgs.data)&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderTitle()&lt;br /&gt;
    if not args.title then return end&lt;br /&gt;
&lt;br /&gt;
    root&lt;br /&gt;
        .tag('caption')&lt;br /&gt;
            .addClass(args.titleclass)&lt;br /&gt;
            .cssText(args.titlestyle)&lt;br /&gt;
            .wikitext(args.title)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderAboveRow()&lt;br /&gt;
    if not args.above then return end&lt;br /&gt;
    &lt;br /&gt;
    root&lt;br /&gt;
        .tag('tr')&lt;br /&gt;
            .tag('th')&lt;br /&gt;
                .attr('colspan', 2)&lt;br /&gt;
                .addClass(args.aboveclass)&lt;br /&gt;
                .css('text-align', 'center')&lt;br /&gt;
                .css('font-size', '125%')&lt;br /&gt;
                .css('font-weight', 'bold')&lt;br /&gt;
                .cssText(args.abovestyle)&lt;br /&gt;
                .wikitext(args.above)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderBelowRow()&lt;br /&gt;
    if not args.below then return end&lt;br /&gt;
    &lt;br /&gt;
    root&lt;br /&gt;
        .tag('tr')&lt;br /&gt;
            .tag('td')&lt;br /&gt;
                .attr('colspan', '2')&lt;br /&gt;
                .addClass(args.belowclass)&lt;br /&gt;
                .css('text-align', 'center')&lt;br /&gt;
                .cssText(args.belowstyle)&lt;br /&gt;
                .newline()&lt;br /&gt;
                .wikitext(args.below)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderSubheaders()&lt;br /&gt;
    if args.subheader then&lt;br /&gt;
        args.subheader1 = args.subheader&lt;br /&gt;
    end&lt;br /&gt;
    if args.subheaderrowclass then&lt;br /&gt;
        args.subheaderrowclass1 = args.subheaderrowclass&lt;br /&gt;
    end&lt;br /&gt;
    local subheadernums = getArgNums('subheader')&lt;br /&gt;
    for k, num in ipairs(subheadernums) do&lt;br /&gt;
        addRow({&lt;br /&gt;
            data = args['subheader' .. tostring(num)],&lt;br /&gt;
            datastyle = args.subheaderstyle or args['subheaderstyle' .. tostring(num)],&lt;br /&gt;
            class = args.subheaderclass,&lt;br /&gt;
            rowclass = args['subheaderrowclass' .. tostring(num)]&lt;br /&gt;
        })&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderImages()&lt;br /&gt;
    if args.image then&lt;br /&gt;
        args.image1 = args.image&lt;br /&gt;
    end&lt;br /&gt;
    if args.caption then&lt;br /&gt;
        args.caption1 = args.caption&lt;br /&gt;
    end&lt;br /&gt;
    local imagenums = getArgNums('image')&lt;br /&gt;
    for k, num in ipairs(imagenums) do&lt;br /&gt;
        local caption = args['caption' .. tostring(num)]&lt;br /&gt;
        local data = HtmlBuilder.create().wikitext(args['image' .. tostring(num)])&lt;br /&gt;
        if caption then&lt;br /&gt;
            data&lt;br /&gt;
                .tag('div')&lt;br /&gt;
                    .cssText(args.captionstyle)&lt;br /&gt;
                    .wikitext(caption)&lt;br /&gt;
        end&lt;br /&gt;
        addRow({&lt;br /&gt;
            data = tostring(data),&lt;br /&gt;
            datastyle = args.imagestyle,&lt;br /&gt;
            class = args.imageclass,&lt;br /&gt;
            rowclass = args['imagerowclass' .. tostring(num)]&lt;br /&gt;
        })&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderRows()&lt;br /&gt;
    -- Gets the union of the header and data argument numbers,&lt;br /&gt;
    -- and renders them all in order using addRow.&lt;br /&gt;
    local rownums = union(getArgNums('header'), getArgNums('data'))&lt;br /&gt;
    table.sort(rownums)&lt;br /&gt;
    for k, num in ipairs(rownums) do&lt;br /&gt;
        addRow({&lt;br /&gt;
            header = args['header' .. tostring(num)],&lt;br /&gt;
            label = args['label' .. tostring(num)],&lt;br /&gt;
            data = args['data' .. tostring(num)],&lt;br /&gt;
            datastyle = args.datastyle,&lt;br /&gt;
            class = args['class' .. tostring(num)],&lt;br /&gt;
            rowclass = args['rowclass' .. tostring(num)],&lt;br /&gt;
            dataid = args['dataid' .. tostring(num)],&lt;br /&gt;
            labelid = args['labelid' .. tostring(num)],&lt;br /&gt;
            headerid = args['headerid' .. tostring(num)],&lt;br /&gt;
            rowid = args['rowid' .. tostring(num)]&lt;br /&gt;
        })&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderNavBar()&lt;br /&gt;
    if not args.name then return end&lt;br /&gt;
    &lt;br /&gt;
    root&lt;br /&gt;
        .tag('tr')&lt;br /&gt;
            .tag('td')&lt;br /&gt;
                .attr('colspan', '2')&lt;br /&gt;
                .css('text-align', 'right')&lt;br /&gt;
                .wikitext(mw.getCurrentFrame():expandTemplate({ &lt;br /&gt;
                    title = 'navbar', &lt;br /&gt;
                    args = { args.name, mini = 1 }&lt;br /&gt;
                }))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderItalicTitle()&lt;br /&gt;
    local italicTitle = args['italic title'] and mw.ustring.lower(args['italic title'])&lt;br /&gt;
    if italicTitle == '' or italicTitle == 'force' or italicTitle == 'yes' then&lt;br /&gt;
        root.wikitext(mw.getCurrentFrame():expandTemplate({title = 'italic title'}))&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function renderTrackingCategories()&lt;br /&gt;
    if args.decat ~= 'yes' then&lt;br /&gt;
        if #(getArgNums('data')) == 0 and mw.title.getCurrentTitle().namespace == 0 then&lt;br /&gt;
            root.wikitext('[[Category:Articles which use infobox templates with no data rows]]')&lt;br /&gt;
        end&lt;br /&gt;
        if args.child == 'yes' and args.title then&lt;br /&gt;
            root.wikitext('[[Category:Articles which use embedded infobox templates with the title parameter]]')&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function _infobox()&lt;br /&gt;
    -- Specify the overall layout of the infobox, with special settings&lt;br /&gt;
    -- if the infobox is used as a 'child' inside another infobox.&lt;br /&gt;
    if args.child ~= 'yes' then&lt;br /&gt;
        root = HtmlBuilder.create('table')&lt;br /&gt;
        &lt;br /&gt;
        root&lt;br /&gt;
            .addClass('infobox')&lt;br /&gt;
            .addClass(args.bodyclass)&lt;br /&gt;
            .attr('cellspacing', 3)&lt;br /&gt;
            .css('border-spacing', '3px')&lt;br /&gt;
            &lt;br /&gt;
            if args.subbox == 'yes' then&lt;br /&gt;
                root&lt;br /&gt;
                    .css('padding', '0')&lt;br /&gt;
                    .css('border', 'none')&lt;br /&gt;
                    .css('margin', '-3px')&lt;br /&gt;
                    .css('width', 'auto')&lt;br /&gt;
                    .css('min-width', '100%')&lt;br /&gt;
                    .css('font-size', '100%')&lt;br /&gt;
                    .css('clear', 'none')&lt;br /&gt;
                    .css('float', 'none')&lt;br /&gt;
                    .css('background-color', 'transparent')&lt;br /&gt;
            else&lt;br /&gt;
                root&lt;br /&gt;
                    .css('width', '22em')&lt;br /&gt;
            end&lt;br /&gt;
        root&lt;br /&gt;
            .cssText(args.bodystyle)&lt;br /&gt;
    &lt;br /&gt;
        renderTitle()&lt;br /&gt;
        renderAboveRow()&lt;br /&gt;
    else&lt;br /&gt;
        root = HtmlBuilder.create()&lt;br /&gt;
        &lt;br /&gt;
        root&lt;br /&gt;
            .wikitext(args.title)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    renderSubheaders()&lt;br /&gt;
    renderImages() &lt;br /&gt;
    renderRows() &lt;br /&gt;
    renderBelowRow()  &lt;br /&gt;
    renderNavBar()&lt;br /&gt;
    renderItalicTitle()&lt;br /&gt;
    renderTrackingCategories()&lt;br /&gt;
    &lt;br /&gt;
    return tostring(root)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function preprocessSingleArg(argName)&lt;br /&gt;
    -- If the argument exists and isn't blank, add it to the argument table.&lt;br /&gt;
    -- Blank arguments are treated as nil to match the behaviour of ParserFunctions.&lt;br /&gt;
    if origArgs[argName] and origArgs[argName] ~= '' then&lt;br /&gt;
        args[argName] = origArgs[argName]&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function preprocessArgs(prefixTable, step)&lt;br /&gt;
    -- Assign the parameters with the given prefixes to the args table, in order, in batches&lt;br /&gt;
    -- of the step size specified. This is to prevent references etc. from appearing in the&lt;br /&gt;
    -- wrong order. The prefixTable should be an array containing tables, each of which has&lt;br /&gt;
    -- two possible fields, a &amp;quot;prefix&amp;quot; string and a &amp;quot;depend&amp;quot; table. The function always parses&lt;br /&gt;
    -- parameters containing the &amp;quot;prefix&amp;quot; string, but only parses parameters in the &amp;quot;depend&amp;quot;&lt;br /&gt;
    -- table if the prefix parameter is present and non-blank.&lt;br /&gt;
    if type(prefixTable) ~= 'table' then&lt;br /&gt;
        error(&amp;quot;Non-table value detected for the prefix table&amp;quot;, 2)&lt;br /&gt;
    end&lt;br /&gt;
    if type(step) ~= 'number' then&lt;br /&gt;
        error(&amp;quot;Invalid step value detected&amp;quot;, 2)&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    -- Get arguments without a number suffix, and check for bad input.&lt;br /&gt;
    for i,v in ipairs(prefixTable) do&lt;br /&gt;
        if type(v) ~= 'table' or type(v.prefix) ~= &amp;quot;string&amp;quot; or (v.depend and type(v.depend) ~= 'table') then&lt;br /&gt;
            error('Invalid input detected to preprocessArgs prefix table', 2)&lt;br /&gt;
        end&lt;br /&gt;
        preprocessSingleArg(v.prefix)&lt;br /&gt;
        -- Only parse the depend parameter if the prefix parameter is present and not blank.&lt;br /&gt;
        if args[v.prefix] and v.depend then&lt;br /&gt;
            for j, dependValue in ipairs(v.depend) do&lt;br /&gt;
                if type(dependValue) ~= 'string' then&lt;br /&gt;
                    error('Invalid &amp;quot;depend&amp;quot; parameter value detected in preprocessArgs')&lt;br /&gt;
                end&lt;br /&gt;
                preprocessSingleArg(dependValue)&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Get arguments with number suffixes.&lt;br /&gt;
    local a = 1 -- Counter variable.&lt;br /&gt;
    local moreArgumentsExist = true&lt;br /&gt;
    while moreArgumentsExist == true do&lt;br /&gt;
        moreArgumentsExist = false&lt;br /&gt;
        for i = a, a + step - 1 do&lt;br /&gt;
            for j,v in ipairs(prefixTable) do&lt;br /&gt;
                local prefixArgName = v.prefix .. tostring(i)&lt;br /&gt;
                if origArgs[prefixArgName] then&lt;br /&gt;
                    moreArgumentsExist = true -- Do another loop if any arguments are found, even blank ones.&lt;br /&gt;
                    preprocessSingleArg(prefixArgName)&lt;br /&gt;
                end&lt;br /&gt;
                -- Process the depend table if the prefix argument is present and not blank, or&lt;br /&gt;
                -- we are processing &amp;quot;prefix1&amp;quot; and &amp;quot;prefix&amp;quot; is present and not blank, and&lt;br /&gt;
                -- if the depend table is present.&lt;br /&gt;
                if v.depend and (args[prefixArgName] or (i == 1 and args[v.prefix])) then&lt;br /&gt;
                    for j,dependValue in ipairs(v.depend) do&lt;br /&gt;
                        local dependArgName = dependValue .. tostring(i)&lt;br /&gt;
                        preprocessSingleArg(dependArgName)&lt;br /&gt;
                    end&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
        a = a + step&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
function p.infobox(frame)&lt;br /&gt;
    -- If called via #invoke, use the args passed into the invoking template.&lt;br /&gt;
    -- Otherwise, for testing purposes, assume args are being passed directly in.&lt;br /&gt;
    if frame == mw.getCurrentFrame() then&lt;br /&gt;
        origArgs = frame:getParent().args&lt;br /&gt;
    else&lt;br /&gt;
        origArgs = frame&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    -- Parse the data parameters in the same order that the old {{infobox}} did, so that&lt;br /&gt;
    -- references etc. will display in the expected places. Parameters that depend on&lt;br /&gt;
    -- another parameter are only processed if that parameter is present, to avoid&lt;br /&gt;
    -- phantom references appearing in article reference lists.&lt;br /&gt;
    preprocessSingleArg('child')&lt;br /&gt;
    preprocessSingleArg('bodyclass')&lt;br /&gt;
    preprocessSingleArg('subbox')&lt;br /&gt;
    preprocessSingleArg('bodystyle')&lt;br /&gt;
    preprocessSingleArg('title')&lt;br /&gt;
    preprocessSingleArg('titleclass')&lt;br /&gt;
    preprocessSingleArg('titlestyle')&lt;br /&gt;
    preprocessSingleArg('above')&lt;br /&gt;
    preprocessSingleArg('aboveclass')&lt;br /&gt;
    preprocessSingleArg('abovestyle')&lt;br /&gt;
    preprocessArgs({&lt;br /&gt;
        {prefix = 'subheader', depend = {'subheaderstyle', 'subheaderrowclass'}}&lt;br /&gt;
    }, 10)&lt;br /&gt;
    preprocessSingleArg('subheaderstyle')&lt;br /&gt;
    preprocessSingleArg('subheaderclass')&lt;br /&gt;
    preprocessArgs({&lt;br /&gt;
        {prefix = 'image', depend = {'caption', 'imagerowclass'}}&lt;br /&gt;
    }, 10)&lt;br /&gt;
    preprocessSingleArg('captionstyle')&lt;br /&gt;
    preprocessSingleArg('imagestyle')&lt;br /&gt;
    preprocessSingleArg('imageclass')&lt;br /&gt;
    preprocessArgs({&lt;br /&gt;
        {prefix = 'header'},&lt;br /&gt;
        {prefix = 'data', depend = {'label'}},&lt;br /&gt;
        {prefix = 'rowclass'},&lt;br /&gt;
        {prefix = 'class'},&lt;br /&gt;
        {prefix = 'dataid'},&lt;br /&gt;
        {prefix = 'labelid'},&lt;br /&gt;
        {prefix = 'headerid'},&lt;br /&gt;
        {prefix = 'rowid'}&lt;br /&gt;
    }, 50)&lt;br /&gt;
    preprocessSingleArg('headerclass')&lt;br /&gt;
    preprocessSingleArg('headerstyle')&lt;br /&gt;
    preprocessSingleArg('labelstyle')&lt;br /&gt;
    preprocessSingleArg('datastyle')&lt;br /&gt;
    preprocessSingleArg('below')&lt;br /&gt;
    preprocessSingleArg('belowclass')&lt;br /&gt;
    preprocessSingleArg('belowstyle')&lt;br /&gt;
    preprocessSingleArg('name')&lt;br /&gt;
    args['italic title'] = origArgs['italic title'] -- different behaviour if blank or absent&lt;br /&gt;
    preprocessSingleArg('decat')&lt;br /&gt;
 &lt;br /&gt;
    return _infobox()&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=Special:Badtitle/NS828:HtmlBuilder&amp;diff=8</id>
		<title>Special:Badtitle/NS828:HtmlBuilder</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=Special:Badtitle/NS828:HtmlBuilder&amp;diff=8"/>
		<updated>2014-09-18T03:28:17Z</updated>

		<summary type="html">&lt;p&gt;Admin: Created page with &amp;quot;-- Module for building complex HTML (e.g. infoboxes, navboxes) using a fluent interface.  local HtmlBuilder = {}  local metatable = {}  metatable.__index = function(t, key)...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;-- Module for building complex HTML (e.g. infoboxes, navboxes) using a fluent interface.&lt;br /&gt;
&lt;br /&gt;
local HtmlBuilder = {}&lt;br /&gt;
&lt;br /&gt;
local metatable = {}&lt;br /&gt;
&lt;br /&gt;
metatable.__index = function(t, key)&lt;br /&gt;
    local ret = rawget(t, key)&lt;br /&gt;
    if ret then&lt;br /&gt;
        return ret&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    ret = metatable[key]&lt;br /&gt;
    if type(ret) == 'function' then&lt;br /&gt;
        return function(...) &lt;br /&gt;
            return ret(t, ...) &lt;br /&gt;
        end &lt;br /&gt;
    else&lt;br /&gt;
        return ret&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
metatable.__tostring = function(t)&lt;br /&gt;
    local ret = {}&lt;br /&gt;
    t._build(ret)&lt;br /&gt;
    return table.concat(ret)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
metatable._build = function(t, ret)&lt;br /&gt;
    if t.tagName then &lt;br /&gt;
        table.insert(ret, '&amp;lt;' .. t.tagName)&lt;br /&gt;
        for i, attr in ipairs(t.attributes) do&lt;br /&gt;
            table.insert(ret, ' ' .. attr.name .. '=&amp;quot;' .. attr.val .. '&amp;quot;') &lt;br /&gt;
        end&lt;br /&gt;
        if #t.styles &amp;gt; 0 then&lt;br /&gt;
            table.insert(ret, ' style=&amp;quot;')&lt;br /&gt;
            for i, prop in ipairs(t.styles) do&lt;br /&gt;
                if type(prop) == 'string' then -- added with cssText()&lt;br /&gt;
                    table.insert(ret, prop .. ';')&lt;br /&gt;
                else -- added with css()&lt;br /&gt;
                    table.insert(ret, prop.name .. ':' .. prop.val .. ';')&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
            table.insert(ret, '&amp;quot;')&lt;br /&gt;
        end&lt;br /&gt;
        if t.selfClosing then&lt;br /&gt;
            table.insert(ret, ' /')&lt;br /&gt;
        end&lt;br /&gt;
        table.insert(ret, '&amp;gt;') &lt;br /&gt;
    end&lt;br /&gt;
    for i, node in ipairs(t.nodes) do&lt;br /&gt;
        if node then&lt;br /&gt;
            if type(node) == 'table' then&lt;br /&gt;
                node._build(ret)&lt;br /&gt;
            else&lt;br /&gt;
                table.insert(ret, tostring(node))&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    if t.tagName and not t.unclosed and not t.selfClosing then&lt;br /&gt;
        table.insert(ret, '&amp;lt;/' .. t.tagName .. '&amp;gt;')&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
metatable.node = function(t, builder)&lt;br /&gt;
    if builder then&lt;br /&gt;
        table.insert(t.nodes, builder)&lt;br /&gt;
    end&lt;br /&gt;
    return t&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
metatable.wikitext = function(t, ...) &lt;br /&gt;
    local vals = {...}&lt;br /&gt;
    for i = 1, #vals do&lt;br /&gt;
        if vals[i] then&lt;br /&gt;
            table.insert(t.nodes, vals[i])&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    return t&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
metatable.newline = function(t)&lt;br /&gt;
    table.insert(t.nodes, '\n')&lt;br /&gt;
    return t&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
metatable.tag = function(t, tagName, args)&lt;br /&gt;
    args = args or {}&lt;br /&gt;
    args.parent = t&lt;br /&gt;
    local builder = HtmlBuilder.create(tagName, args)&lt;br /&gt;
    table.insert(t.nodes, builder)&lt;br /&gt;
    return builder&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getAttr(t, name)&lt;br /&gt;
    for i, attr in ipairs(t.attributes) do&lt;br /&gt;
        if attr.name == name then&lt;br /&gt;
            return attr&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
metatable.attr = function(t, name, val)&lt;br /&gt;
    if type(val) == 'string' or type(val) == 'number' then&lt;br /&gt;
        -- if caller sets the style attribute explicitly, then replace all styles previously added with css() and cssText()&lt;br /&gt;
        if name == 'style' then&lt;br /&gt;
            t.styles = {val}&lt;br /&gt;
            return t&lt;br /&gt;
        end&lt;br /&gt;
        &lt;br /&gt;
        local attr = getAttr(t, name)&lt;br /&gt;
        if attr then&lt;br /&gt;
            attr.val = val&lt;br /&gt;
        else&lt;br /&gt;
            table.insert(t.attributes, {name = name, val = val})&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    return t&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
metatable.addClass = function(t, class)&lt;br /&gt;
    if class then&lt;br /&gt;
        local attr = getAttr(t, 'class')&lt;br /&gt;
        if attr then&lt;br /&gt;
            attr.val = attr.val .. ' ' .. class&lt;br /&gt;
        else&lt;br /&gt;
            t.attr('class', class)&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    return t&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
metatable.css = function(t, name, val)&lt;br /&gt;
    if type(val) == 'string' or type(val) == 'number' then&lt;br /&gt;
        for i, prop in ipairs(t.styles) do&lt;br /&gt;
            if prop.name == name then&lt;br /&gt;
                prop.val = val&lt;br /&gt;
                return t&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
        &lt;br /&gt;
        table.insert(t.styles, {name = name, val = val})&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    return t&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
metatable.cssText = function(t, css)&lt;br /&gt;
    if css then&lt;br /&gt;
        table.insert(t.styles, css)&lt;br /&gt;
    end&lt;br /&gt;
    return t&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
metatable.done = function(t)&lt;br /&gt;
    return t.parent or t&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
metatable.allDone = function(t)&lt;br /&gt;
    while t.parent do&lt;br /&gt;
        t = t.parent&lt;br /&gt;
    end&lt;br /&gt;
    return t&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function HtmlBuilder.create(tagName, args)&lt;br /&gt;
    args = args or {}&lt;br /&gt;
    local builder = {}&lt;br /&gt;
    setmetatable(builder, metatable)&lt;br /&gt;
    builder.nodes = {}&lt;br /&gt;
    builder.attributes = {}&lt;br /&gt;
    builder.styles = {}&lt;br /&gt;
    builder.tagName = tagName&lt;br /&gt;
    builder.parent = args.parent&lt;br /&gt;
    builder.unclosed = args.unclosed or false&lt;br /&gt;
    builder.selfClosing = args.selfClosing or false&lt;br /&gt;
    return builder&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return HtmlBuilder&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=Special:Badtitle/NS828:Anchor&amp;diff=7</id>
		<title>Special:Badtitle/NS828:Anchor</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=Special:Badtitle/NS828:Anchor&amp;diff=7"/>
		<updated>2014-09-18T03:26:31Z</updated>

		<summary type="html">&lt;p&gt;Admin: Created page with &amp;quot;-- This module implements {{anchor}}.   local getArgs = require('Module:Arguments').getArgs local tableTools = require('Module:TableTools')   local p = {}  function p.main(fra...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;-- This module implements {{anchor}}.&lt;br /&gt;
 &lt;br /&gt;
local getArgs = require('Module:Arguments').getArgs&lt;br /&gt;
local tableTools = require('Module:TableTools')&lt;br /&gt;
 &lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
function p.main(frame)&lt;br /&gt;
	-- Get the positional arguments from #invoke, remove any nil values,&lt;br /&gt;
	-- and pass them to p._main.&lt;br /&gt;
	local args = getArgs(frame)&lt;br /&gt;
	local argArray = tableTools.compressSparseArray(args)&lt;br /&gt;
	return p._main(unpack(argArray))&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
function p._main(...)&lt;br /&gt;
	-- Generate the list of anchors.&lt;br /&gt;
	local anchors = {...}&lt;br /&gt;
	local ret = {}&lt;br /&gt;
	for _, anchor in ipairs(anchors) do&lt;br /&gt;
		ret[#ret + 1] = '&amp;lt;span id=&amp;quot;' .. anchor .. '&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;'&lt;br /&gt;
	end&lt;br /&gt;
	return table.concat(ret)&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=LTI/Best_Practice/Introduction&amp;diff=6</id>
		<title>LTI/Best Practice/Introduction</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=LTI/Best_Practice/Introduction&amp;diff=6"/>
		<updated>2014-09-18T03:14:05Z</updated>

		<summary type="html">&lt;p&gt;Admin: Version from the original PDF document&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Learning Tools Interoperability (LTI) specification was first released by the IMS Global Learning Consortium as Basic LTI in May 2010 [[LTI/Best Practice/References#IMS-A|[IMS-A]]] (and is now referred to as LTI 1.0). Since that time it has become well adopted as a simple but effective mechanism for integrating third party content and products with virtual learning environments (VLEs). For example, it is now part of the core product for all major VLEs, including Moodle, Blackboard Learn 9, Desire2Learn and Canvas from Instructure.&lt;br /&gt;
&lt;br /&gt;
The purpose of this document is to provide you with a detailed exploration of how LTI works and the issues which arise so as to give you guidance on good practice, if not, best practice. The document contains sections relating to all the main parties involved in delivering learning experiences to students:&lt;br /&gt;
&lt;br /&gt;
* developers;&lt;br /&gt;
* VLE administrators;&lt;br /&gt;
* teachers;&lt;br /&gt;
* service providers.&lt;br /&gt;
&lt;br /&gt;
Please provide feedback based on your own experiences to help improve the quality of the recommendations included here.&lt;br /&gt;
&lt;br /&gt;
== Terminology ==&lt;br /&gt;
We start with a bit of terminology to help make the descriptions which follow more precise. The LTI specification uses the following terms:&lt;br /&gt;
&lt;br /&gt;
* ''tool consumer'' - typically this refers to the VLE; it is the system which users are logged into and from which they will be redirected to the external applications being integrated with it;&lt;br /&gt;
* ''tool provider'' - this is the web-based learning application or content delivery system which is being integrated with the tool consumer;&lt;br /&gt;
* ''consumer key'' - this string value is generated by the tool provider to allow them to uniquely identify the source of requests being received;&lt;br /&gt;
* ''shared secret'' - the communications between the tool provider and the tool consumer are secured using a signature generated using the OAuth 1.0 protocol [[LTI/Best Practice/References#OAuth-A|[OAuth-A]]] with the shared secret (which should be known only to the tool provider and the tool consumer);&lt;br /&gt;
* ''context'' - tool consumers are typically organised into courses, with users being enrolled into each course for which they are permitted to access; thus, in this case, the course is the context from which users launch into tool providers;&lt;br /&gt;
* ''resource link'' - this is the actual link provided within a context which users follow to access the tool provider; there may be multiple resource links to each tool provider within the same context and across the whole tool consumer but each resource link is uniquely identified.&lt;br /&gt;
&lt;br /&gt;
== LTI Releases ==&lt;br /&gt;
This document provides guidance for both the tool consumer and the tool provider components of an LTI 1 connection. At the time of writing, the following versions of LTI 1 have been released:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Version&lt;br /&gt;
!Release date&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|May 2010&lt;br /&gt;
|-&lt;br /&gt;
|1.1&lt;br /&gt;
|March 2012&lt;br /&gt;
|-&lt;br /&gt;
|1.1.1&lt;br /&gt;
|June 2012&lt;br /&gt;
|-&lt;br /&gt;
|1.2&lt;br /&gt;
|Public draft&lt;br /&gt;
|-&lt;br /&gt;
|2.0	&lt;br /&gt;
|January 2014&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
LTI version 2 provides a more extensible framework for implementing learning application/content integrations, but this document will focus essentially on LTI 1 because this is what is currently in use and widely available. At the time of writing LTI 1.2 is in public draft and extends LTI 1 with some of the features of LTI 2.0 (e.g. a tool consumer profile enabling discoverable services) thereby offering a stepping stone for systems looking to move from LTI 1 to LTI 2. [[LTI/Best Practice/References#IMS-A|[IMS-A]]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=LTI/Best_Practice&amp;diff=5</id>
		<title>LTI/Best Practice</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=LTI/Best_Practice&amp;diff=5"/>
		<updated>2014-09-18T03:12:42Z</updated>

		<summary type="html">&lt;p&gt;Admin: Version from the original PDF document&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;'''''Learning Tools Interoperability&amp;lt;sup&amp;gt;&amp;amp;reg;&amp;lt;/sup&amp;gt; (LTI&amp;lt;sup&amp;gt;&amp;amp;reg;&amp;lt;/sup&amp;gt;): A Best Practice Guide'''''&lt;br /&gt;
&lt;br /&gt;
based on the [http://ltiapps.net/guide/best_practice original report] written by&lt;br /&gt;
&lt;br /&gt;
''Stephen P Vickers''&amp;lt;br /&amp;gt;''Simon Booth''&lt;br /&gt;
&lt;br /&gt;
for&lt;br /&gt;
&lt;br /&gt;
[http://celtic-project.org ceLTIc:developers Project]&lt;br /&gt;
&lt;br /&gt;
August 2014&lt;br /&gt;
&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Contents ==&lt;br /&gt;
&lt;br /&gt;
# [[LTI/Best Practice/Introduction|Introduction]]&lt;br /&gt;
## Terminology&lt;br /&gt;
## LTI Releases&lt;br /&gt;
# [[LTI/Best Practice/Issues for Developers|Issues for Developers]]&lt;br /&gt;
## Anatomy of a launch request&lt;br /&gt;
## Launch parameters&lt;br /&gt;
## Security&lt;br /&gt;
## Receiving a launch request&lt;br /&gt;
## Identity values&lt;br /&gt;
## Roles&lt;br /&gt;
## CSS&lt;br /&gt;
## Override interface&lt;br /&gt;
## Branding&lt;br /&gt;
## Course archive/restore/copy&lt;br /&gt;
## Class libraries&lt;br /&gt;
## Browser issues&lt;br /&gt;
# [[LTI/Best Practice/Issues for System Administrators|Issues for System Administrators]]&lt;br /&gt;
## Tool requirements&lt;br /&gt;
## Configuring tools (XML)&lt;br /&gt;
## Verifying connections&lt;br /&gt;
## Course archive/restore/copy&lt;br /&gt;
## Mapping VLE/LTI roles&lt;br /&gt;
# [[LTI/Best Practice/Issues for Teachers and Students|Issues for Teachers and Students]]&lt;br /&gt;
## Number of links per course&lt;br /&gt;
## Pre-populating enrolments and groups&lt;br /&gt;
## Managing outcomes&lt;br /&gt;
## Re-using content&lt;br /&gt;
## Sharing content&lt;br /&gt;
## Mapping VLE/LTI roles&lt;br /&gt;
## &amp;quot;Dummy&amp;quot; users&lt;br /&gt;
# [[LTI/Best Practice/Issues for Service Providers|Issues for Service Providers]]&lt;br /&gt;
## Service level agreements&lt;br /&gt;
## Upgrades&lt;br /&gt;
## Backups&lt;br /&gt;
* [[LTI/Best Practice/References|References]]&lt;br /&gt;
&lt;br /&gt;
== Case studies ==&lt;br /&gt;
# [[LTI/Best Practice/Issues for Developers#CS1|WebPA launch requests]]&lt;br /&gt;
# [[LTI/Best Practice/Issues for Developers#CS2|User scope in WordPress]]&lt;br /&gt;
# [[LTI/Best Practice/Issues for Developers#CS3|Custom parameters supported by WebPA]]&lt;br /&gt;
# [[LTI/Best Practice/Issues for System Administrators#CS4|Testing mode]]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
You are welcome, even encouraged, to contribute your own experiences and best practices to this document.  Just sign up for an account and use the discussion option on each page, or edit the page directly with your content.&lt;br /&gt;
&lt;br /&gt;
''Learning Tools Interoperability and LTI are registered trademarks of IMS Global Learning Consortium, Inc. in the United States and/or other countries.''&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=ceLTIc_wiki&amp;diff=4</id>
		<title>ceLTIc wiki</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=ceLTIc_wiki&amp;diff=4"/>
		<updated>2014-09-18T03:09:52Z</updated>

		<summary type="html">&lt;p&gt;Admin: Created page with &amp;quot;The [http://celtic-project.org/ Creating Environments for Learning using Tightly Integrated Components (ceLTIc) project] came out of a [http://www.jisc.ac.uk/ JISC]-funded pro...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The [http://celtic-project.org/ Creating Environments for Learning using Tightly Integrated Components (ceLTIc) project] came out of a [http://www.jisc.ac.uk/ JISC]-funded project in 2010.  Its broad aim is to raise awareness of the IMS Learning Tools Interoperability&amp;amp;reg; (LTI&amp;amp;reg;) within the education community by demonstrating its benefits for integrating learning applications within on-line course environments.  Further JISC funding in 2012/13 was used to demonstrate the use of LTI for providing shared services across multiple institutions and foster a network and toolsets for developers.  For further information see the project website.&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=MediaWiki:Monobook.css&amp;diff=3</id>
		<title>MediaWiki:Monobook.css</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=MediaWiki:Monobook.css&amp;diff=3"/>
		<updated>2014-09-18T02:56:51Z</updated>

		<summary type="html">&lt;p&gt;Admin: Created page with &amp;quot;/* CSS placed here will affect users of the MonoBook skin */ #p-tb{   display : none; }&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* CSS placed here will affect users of the MonoBook skin */&lt;br /&gt;
#p-tb{&lt;br /&gt;
  display : none;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>http://celtic.lti.tools/w/index.php?title=MediaWiki:Sidebar&amp;diff=2</id>
		<title>MediaWiki:Sidebar</title>
		<link rel="alternate" type="text/html" href="http://celtic.lti.tools/w/index.php?title=MediaWiki:Sidebar&amp;diff=2"/>
		<updated>2014-09-18T02:41:41Z</updated>

		<summary type="html">&lt;p&gt;Admin: Created page with &amp;quot; * navigation ** ceLTIc wiki|Wiki home ** http://celtic-project.org/|ceLTIc project ** recentchanges-url|recentchanges ** randompage-url|randompage ** helppage|help * SEARCH *...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
* navigation&lt;br /&gt;
** ceLTIc wiki|Wiki home&lt;br /&gt;
** http://celtic-project.org/|ceLTIc project&lt;br /&gt;
** recentchanges-url|recentchanges&lt;br /&gt;
** randompage-url|randompage&lt;br /&gt;
** helppage|help&lt;br /&gt;
* SEARCH&lt;br /&gt;
* LANGUAGES&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
</feed>