<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://docs.moodle.org/dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ankitfrenz</id>
	<title>MoodleDocs - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://docs.moodle.org/dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ankitfrenz"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Ankitfrenz"/>
	<updated>2026-10-06T04:56:56Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Task_API&amp;diff=53212</id>
		<title>Task API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Task_API&amp;diff=53212"/>
		<updated>2017-11-13T03:25:07Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* Adhoc tasks */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Project&lt;br /&gt;
|name = Task&lt;br /&gt;
|state = Integrated&lt;br /&gt;
|tracker = MDL-25505&lt;br /&gt;
|discussion = https://moodle.org/mod/forum/discuss.php?d=229139&lt;br /&gt;
|assignee = Damyon&lt;br /&gt;
}}&lt;br /&gt;
{{Moodle 2.7}}&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
A task is a unit of work that needs to be done later. Good uses for tasks:&lt;br /&gt;
&lt;br /&gt;
* Run a slow operation in the background&lt;br /&gt;
* Run a maintenance task on a regular schedule&lt;br /&gt;
&lt;br /&gt;
In general any operation that takes more than a few seconds should be a candidate for a task.&lt;br /&gt;
&lt;br /&gt;
== Benefits ==&lt;br /&gt;
&lt;br /&gt;
* Better user experience (give them feedback immediately, that their task has been queued)&lt;br /&gt;
* Prevent browser timeouts&lt;br /&gt;
* Better performance for clusters (tasks can be run on separate, non-webserving cluster node, tasks can run in parallel)&lt;br /&gt;
* Failed tasks will be retried&lt;br /&gt;
* A better user interface will prevent users queuing multiple tasks, because they thought it had &amp;quot;got stuck&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Types of task ==&lt;br /&gt;
&lt;br /&gt;
=== Scheduled tasks ===&lt;br /&gt;
Scheduled tasks are tasks that will run on a regular schedule. A default schedule can be set, but admins have the ability to change the default schedule if required. Note: Tasks will only run as often as cron is run in Moodle. In 2.7 it is recommended to run cron once per minute to get the benefit from the new task scheduling (don&#039;t worry - it will do much less work each time it runs).&lt;br /&gt;
&lt;br /&gt;
=== Adhoc tasks ===&lt;br /&gt;
Adhoc tasks are for when you need to queue something to run in the background immediately, they would be executed as soon as possible. Adhoc tasks can contain custom data, specific to this specific instance of the task.&lt;br /&gt;
&lt;br /&gt;
== Usage ==&lt;br /&gt;
&lt;br /&gt;
=== Scheduled task usage ===&lt;br /&gt;
&lt;br /&gt;
Scheduled tasks are created by subclassing \core\task\scheduled_task. They also require an entry in &amp;quot;db/tasks.php&amp;quot; for your plugin.&lt;br /&gt;
&lt;br /&gt;
1. Create a subclass of \core\task\scheduled_task that contains your code to run in a schedule (within &amp;quot;&amp;lt;pluginroot&amp;gt;/classes/task/cut_my_toe_nails.php&amp;quot; for the autoloading mechanism to pick up).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
namespace mod_hygene\task;&lt;br /&gt;
&lt;br /&gt;
class cut_my_toe_nails extends \core\task\scheduled_task {      &lt;br /&gt;
    public function get_name() {&lt;br /&gt;
        // Shown in admin screens&lt;br /&gt;
        return get_string(&#039;cutmytoenails&#039;, &#039;mod_hygene&#039;);&lt;br /&gt;
    }&lt;br /&gt;
                                                                     &lt;br /&gt;
    public function execute() {       &lt;br /&gt;
        // apply fungus cream&lt;br /&gt;
        // apply chainsaw&lt;br /&gt;
        // apply olive oil&lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
} &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. Create entry in db/tasks.php for your plugin (then a version bump to your plugin will install the task):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$tasks = array(                                                                                                                     &lt;br /&gt;
    array(                                                                                                                          &lt;br /&gt;
        &#039;classname&#039; =&amp;gt; &#039;mod_hygene\task\cut_my_toe_nails&#039;,                                                                            &lt;br /&gt;
        &#039;blocking&#039; =&amp;gt; 0,                                                                                                            &lt;br /&gt;
        &#039;minute&#039; =&amp;gt; &#039;30&#039;,                                                                                                            &lt;br /&gt;
        &#039;hour&#039; =&amp;gt; &#039;17&#039;,                                                                                                              &lt;br /&gt;
        &#039;day&#039; =&amp;gt; &#039;*&#039;,                                                                                                               &lt;br /&gt;
        &#039;dayofweek&#039; =&amp;gt; &#039;0&#039;,                                                                                                         &lt;br /&gt;
        &#039;month&#039; =&amp;gt; &#039;1,7&#039;                                                                                                              &lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The fields required in the db/tasks.php file are:&lt;br /&gt;
* classname - the fully namespaced classname of your task. This needs to comply with the autoloading rules. &lt;br /&gt;
* blocking - if this is set to 1, no other scheduled task will run at the same time as this task. Do not set this to 1 unless you really need it as it will impact the performance of the task queue.&lt;br /&gt;
* minute, hour, day, dayofweek, month - This is the default schedule for running the task. The syntax matches the syntax of unix cron. Starting with Moodle 2.8, the minute and hour values accept a special &#039;R&#039; syntax which causes a random value to be set in the database at install time (useful to avoid overloading web services).&lt;br /&gt;
&lt;br /&gt;
3. Increase the version number in version.php for your plugin and visit the Site &amp;quot;Administration -&amp;gt; Notifications&amp;quot; page to install the new task. &lt;br /&gt;
&lt;br /&gt;
4. (Optional - since 2.8) Run this task even when the plugin is disabled. In rare cases, you may want the scheduled tasks for a plugin to run, even when the plugin is disabled. Some of the enrolment plugins do this to clean up data. If this is the case, the scheduled task must override the  &amp;quot;get_run_if_component_disabled()&amp;quot; method and return true instead of false. If they do not do this, the scheduled task will not be run while the plugin is disabled.&lt;br /&gt;
&lt;br /&gt;
When called from the command line for testing purposes errors can be hidden and a misleading error about locks can be displayed. To get at the details of an error Moodle 3.2 supports a shodebugging option that will show the actual errors. Read about it here&lt;br /&gt;
https://docs.moodle.org/32/en/Administration_via_command_line#Scheduled_tasks&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Cron syntax examples ====&lt;br /&gt;
* day - Day of month field for task schedule. &lt;br /&gt;
** &amp;quot;*&amp;quot; - Every day&lt;br /&gt;
** &amp;quot;*/2&amp;quot; - Every 2nd day&lt;br /&gt;
** &amp;quot;1&amp;quot; - The first of every month&lt;br /&gt;
** &amp;quot;1,15&amp;quot; - The first and fifteenth of every month&lt;br /&gt;
* dayofweek - Day of week field for task schedule.&lt;br /&gt;
** &amp;quot;*&amp;quot; - Every day&lt;br /&gt;
** &amp;quot;0&amp;quot; - Every Sunday&lt;br /&gt;
** &amp;quot;6&amp;quot; - Every Saturday&lt;br /&gt;
** &amp;quot;1,5&amp;quot; - Every Monday and Friday&lt;br /&gt;
* hour - Hour field for task schedule.&lt;br /&gt;
** &amp;quot;*&amp;quot; - Every hour&lt;br /&gt;
** &amp;quot;*/2&amp;quot; - Every 2 hours&lt;br /&gt;
** &amp;quot;2-10&amp;quot; - Every hour from 2am until 10am (inclusive)&lt;br /&gt;
** &amp;quot;2,6,9&amp;quot; - 2am, 6am and 9am&lt;br /&gt;
** &amp;quot;R&amp;quot; - A random value between 0 and 23 is chosen at task install time (or when reset to default) [Supported since Moodle 2.8]&lt;br /&gt;
* minute - Minute field for task schedule.&lt;br /&gt;
** &amp;quot;*&amp;quot; - Every minute&lt;br /&gt;
** &amp;quot;*/5&amp;quot; - Every 5 minutes&lt;br /&gt;
** &amp;quot;2-10&amp;quot; - Every minute between 2 and 10 minutes past the hour (inclusive)&lt;br /&gt;
** &amp;quot;2,6,9&amp;quot; - 2, 6 and 9 minutes past the hour&lt;br /&gt;
** &amp;quot;R&amp;quot; - A random value between 0 and 59 is chosen at task install time (or when reset to default) [Supported since Moodle 2.8]&lt;br /&gt;
* month - Month field for task schedule.&lt;br /&gt;
** &amp;quot;*&amp;quot; - Every month&lt;br /&gt;
** &amp;quot;*/2&amp;quot; - Every second month&lt;br /&gt;
** &amp;quot;1&amp;quot; - Every January&lt;br /&gt;
** &amp;quot;1,5&amp;quot; - Every January and May&lt;br /&gt;
&lt;br /&gt;
=== Adhoc task usage ===&lt;br /&gt;
&lt;br /&gt;
This is even easier than scheduled tasks. &lt;br /&gt;
&lt;br /&gt;
1. Create a subclass of \core\task\adhoc_task that contains your code to run in the background.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
class take_over_the_world extends \core\task\adhoc_task {                                                                           &lt;br /&gt;
    public function execute() {       &lt;br /&gt;
        // gain 100,000,000 friends on facebook.&lt;br /&gt;
        // crash the stock market.&lt;br /&gt;
        // run for president.&lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
} &lt;br /&gt;
                                      &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Create an instance of the task and queue it (adding custom data if required).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   // create the instance&lt;br /&gt;
   $domination = new take_over_the_world();&lt;br /&gt;
   // set blocking if required (it probably isn&#039;t)&lt;br /&gt;
   // $domination-&amp;gt;set_blocking(true);&lt;br /&gt;
   // add custom data&lt;br /&gt;
   $domination-&amp;gt;set_custom_data(array(&lt;br /&gt;
       &#039;plansfortomorrownight&#039; =&amp;gt; &#039;The same thing we do every night, Pinky!&#039;&lt;br /&gt;
   ));&lt;br /&gt;
&lt;br /&gt;
   // queue it&lt;br /&gt;
   \core\task\manager::queue_adhoc_task($domination);&lt;br /&gt;
&lt;br /&gt;
   // profit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. There is no 3.&lt;br /&gt;
&lt;br /&gt;
=== Failures ===&lt;br /&gt;
A task, either scheduled or adhoc can sometimes fail. An example would be updating an RSS field when the network is temporarily down. This is handled by the task system automatically - all the failing task needs to do is throw an exception. The task will be retried after 1 minute. If the task keeps failing, the retry algorithm will add more time between each successive attempts up to a max of 24 hours.&lt;br /&gt;
&lt;br /&gt;
=== Caches ===&lt;br /&gt;
There is one special case that needs to be considered with this new system. If a particular scheduled or adhoc task runs for a long time and updates many DB records - particularly something related to enrolment - the next task in the queue may suffer because various API&#039;s in moodle use static caching to speed up requests, but assume that the data will not change much between the start and end of the request. In this case, you can force the cron to exit after running a task that has done many DB updates. The next cron will be run in the next minute, and will have all static caches cleared because it&#039;s a new process. To do this call \core\task\manager::clear_static_caches();&lt;br /&gt;
&lt;br /&gt;
=== Security ===&lt;br /&gt;
When scheduling a task to run in the background - or creating a scheduled task, the task will run in the context of the cron user (see &amp;quot;cron_setup_user()&amp;quot;). If you need to perform access checks in your background task, you should pass the userid/context in custom_data and then pass that userid to the access check functions (&amp;quot;require_capability(&#039;moodle/course:update&#039;,  $context, $userid)&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
=== Legacy cron ===&lt;br /&gt;
The older syntax of cron.php or modname_cron() is still supported - but is not as good as this new API. This is because:&lt;br /&gt;
* the legacy cron functions run serially - a long running cron in one plugin will hold up the other plugins crons&lt;br /&gt;
* the legacy cron functions are fragile - a failure in one cron in one plugin will prevent the cron in other functions from running at all&lt;br /&gt;
* the scheduling cannot be changed by admins&lt;br /&gt;
&lt;br /&gt;
== For Admins ==&lt;br /&gt;
Admins have a new screen where they can adjust the schedules for any scheduled task. They can also reset any scheduled task to its default schedule.&lt;br /&gt;
[[File:task_admin_screenshot.png|Screenshot of admin page]]&lt;br /&gt;
&lt;br /&gt;
 NOTE: You can also run [https://docs.moodle.org/32/en/Administration_via_command_line#Scheduled_tasks Scheduled tasks] via command line, individually.&lt;br /&gt;
&lt;br /&gt;
== Specification ==&lt;br /&gt;
The specification for this feature is here: https://docs.moodle.org/dev/Scheduled_Tasks_Proposal&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_libraries_credits&amp;diff=53046</id>
		<title>Moodle libraries credits</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_libraries_credits&amp;diff=53046"/>
		<updated>2017-10-16T10:56:46Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* SimplePie */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Some of Moodle&#039;s libraries were written by other people, and are being redistributed as part of Moodle under their respective open source licenses that thankfully allow us to do so. Thanks to the authors of all these excellent products - without them Moodle would be missing important functionality. Copyright information for each package is included below:&lt;br /&gt;
&lt;br /&gt;
==ADOdb==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/adodb&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Database abstraction library for MySQL, PostgreSQL, MSSQL, Oracle, Interbase, Foxpro, Access, ADO, Sybase, DB2 and ODBC.&lt;br /&gt;
&lt;br /&gt;
Version: 5.20.9&lt;br /&gt;
&lt;br /&gt;
@copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.&lt;br /&gt;
&lt;br /&gt;
@copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community&lt;br /&gt;
&lt;br /&gt;
License: Dual LGPL and BSD-style&lt;br /&gt;
&lt;br /&gt;
http://adodb.sourceforge.net&lt;br /&gt;
&lt;br /&gt;
==Amazon S3==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;repository/s3/S3.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A standalone Amazon S3 (REST) client for PHP 5.2.x using CURL that does not require PEAR. &lt;br /&gt;
&lt;br /&gt;
Version: 0.5.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2013, Donovan Schönknecht&lt;br /&gt;
&lt;br /&gt;
License: BSD 2-Clause&lt;br /&gt;
&lt;br /&gt;
https://github.com/tpyo/amazon-s3-php-class/releases&lt;br /&gt;
&lt;br /&gt;
==CAS==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;auth/cas/CAS&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
phpCAS library to support CAS authentication plugin&lt;br /&gt;
&lt;br /&gt;
Copyright Jasig&lt;br /&gt;
&lt;br /&gt;
License: Apache License 2.0&lt;br /&gt;
&lt;br /&gt;
https://wiki.jasig.org/display/CASC/phpCAS&lt;br /&gt;
&lt;br /&gt;
==Chart.js==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/amd/src/chartjs-lazy.js&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Simple yet flexible JavaScript charting for designers &amp;amp; developers&lt;br /&gt;
&lt;br /&gt;
Version: 2.2.2&lt;br /&gt;
&lt;br /&gt;
Copyright 2016 Nick Downie&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
http://www.chartjs.org&lt;br /&gt;
&lt;br /&gt;
==EvalMath==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/evalmath&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to safely evaluate math expressions&lt;br /&gt;
&lt;br /&gt;
Copyright Miles Kaufmann&lt;br /&gt;
&lt;br /&gt;
License: BSD&lt;br /&gt;
&lt;br /&gt;
http://www.twmagic.com/&lt;br /&gt;
&lt;br /&gt;
==FLV player==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;filter/mediaplugin/flvplayer.swf&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Flash movie to play FLV files&lt;br /&gt;
&lt;br /&gt;
Copyright Jeroen Wijering &lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.jeroenwijering.com&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==FPDF Class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/fpdf&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to generate PDF files&lt;br /&gt;
&lt;br /&gt;
Version: 1.54&lt;br /&gt;
&lt;br /&gt;
Copyright Olivier PLATHEY&lt;br /&gt;
&lt;br /&gt;
License: Freeware&lt;br /&gt;
&lt;br /&gt;
http://www.setasign.com/products/fpdi/downloads&lt;br /&gt;
&lt;br /&gt;
== GeoIp2 ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/maxmind/GeoIp2&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library for precessing of GeoIP data files&lt;br /&gt;
&lt;br /&gt;
Version: 2.6.0&lt;br /&gt;
&lt;br /&gt;
Copyright MaxMind&lt;br /&gt;
&lt;br /&gt;
License: Apache 2.0&lt;br /&gt;
&lt;br /&gt;
https://github.com/maxmind/GeoIP2-php&lt;br /&gt;
&lt;br /&gt;
==Google APIs==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/google&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Library Google APIs Client Library for PHP&lt;br /&gt;
&lt;br /&gt;
Version: 1.1.7&lt;br /&gt;
&lt;br /&gt;
License: Apache License Version 2.0&lt;br /&gt;
&lt;br /&gt;
https://github.com/google/google-api-php-client&lt;br /&gt;
&lt;br /&gt;
==Graph Class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/graphlib.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to draw line, point, bar, and area graphs, including numeric x-axis and double y-axis.&lt;br /&gt;
&lt;br /&gt;
Version: 1.6.3 (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2000  Herman Veluwenkamp (&#039;&#039;hermanV AT mindless DOT com&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
==Horde==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/horde&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library used by the inbound e-mail handling system.&lt;br /&gt;
&lt;br /&gt;
Version: 5.2.7&lt;br /&gt;
&lt;br /&gt;
Copyright © Horde LLC&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://www.horde.org/&lt;br /&gt;
&lt;br /&gt;
==html2text==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/html2text&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP script to convert HTML into an approximate text equivalent&lt;br /&gt;
&lt;br /&gt;
Version: 4.1.0&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2005-2007 Jon Abernathy &amp;lt;jon@chuggnutt.com&amp;gt;&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
https://github.com/mtibben/html2text.git&lt;br /&gt;
&lt;br /&gt;
==htmlArea==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/editor&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Javascript/HTML script to put a GUI editor in textareas on Internet Explorer and Mozilla&lt;br /&gt;
&lt;br /&gt;
Version: 3.0 beta (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002  interactivetools.com, inc.&lt;br /&gt;
&lt;br /&gt;
License: htmlArea License (based on BSD license)&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==HTML Purifier==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/htmlpurifier&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Filters HTML.&lt;br /&gt;
&lt;br /&gt;
Version: 4.8.0&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
==IP-Atlas==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/ipatlas&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP scripts to show the location of an IP address on a map.&lt;br /&gt;
&lt;br /&gt;
Version: 1.0 (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002   Ivan Kozik&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.xpenguin.com/ip-atlas.php&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==jQuery==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/jquery&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
jQuery is a fast, small, and feature-rich JavaScript library widely used on moodle.&lt;br /&gt;
&lt;br /&gt;
Version: 1.12.3&lt;br /&gt;
&lt;br /&gt;
Copyright: 2016 The jQuery Foundation&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://jquery.com&lt;br /&gt;
&lt;br /&gt;
==jQuery migrate==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/jquery/jquery-migrate-1.4.0.js&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library used migrate older jQuery code to jQuery 3.0.&lt;br /&gt;
&lt;br /&gt;
Version: 1.4.0&lt;br /&gt;
&lt;br /&gt;
Copyright: 2016 The jQuery Foundation and other contributors&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/jquery/jquery-migrate&lt;br /&gt;
&lt;br /&gt;
==jQuery UI==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/jquery/ui-1.12.1/&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
jQuery UI is a set of user interface interactions, effects, widgets, and themes built on top of the jQuery library.&lt;br /&gt;
&lt;br /&gt;
Version: 1.12.1&lt;br /&gt;
&lt;br /&gt;
Copyright: 2016 The jQuery Foundation and other contributors&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/jquery/jquery-migrate&lt;br /&gt;
&lt;br /&gt;
==Services_JSON==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/json&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Allows PHP-&amp;gt;JS communication via JSON&lt;br /&gt;
&lt;br /&gt;
Version: 1.3.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005 Michal Migurski&lt;br /&gt;
&lt;br /&gt;
License: Modified BSD (GPL-compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/pepr/pepr-proposal-show.php?id=198&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==kses==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/kses.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
HTML/XHTML filter that only allows some elements and attributes&lt;br /&gt;
&lt;br /&gt;
Version: 0.2.2&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002, 2003, 2005   Ulf Harnhammar&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://sourceforge.net/projects/kses&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==less.php==&lt;br /&gt;
&lt;br /&gt;
The less.php is a PHP port of the official LESS processor used by moodle themes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/lessphp&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Version: 1.7.0.10&lt;br /&gt;
&lt;br /&gt;
License: Apache 2.0&lt;br /&gt;
&lt;br /&gt;
http://lessphp.typesettercms.com/&lt;br /&gt;
&lt;br /&gt;
Copyright:  Matt Agar and Martin Jantošovič&lt;br /&gt;
==loglevel.js==&lt;br /&gt;
&lt;br /&gt;
Minimal lightweight simple logging for JavaScript.&lt;br /&gt;
&lt;br /&gt;
Version 1.4.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2013 Tim Perry&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/pimterry/loglevel/&lt;br /&gt;
==MathJax==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Not actually included in Moodle. Moodle instead has a setting where the mathjax library is located. It is currently pointing to CDN by default.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
JavaScript filter library for displaying LaTeX, AsciiMath notation, and MathML.&lt;br /&gt;
&lt;br /&gt;
Version 2.7&lt;br /&gt;
&lt;br /&gt;
© Copyright 2015 The MathJax Consortium.&lt;br /&gt;
&lt;br /&gt;
License: Apache V2.0&lt;br /&gt;
&lt;br /&gt;
https://github.com/mathjax/MathJax&lt;br /&gt;
&lt;br /&gt;
==MatthiasMullie\Minify==&lt;br /&gt;
CSS &amp;amp; JavaScript minifier, in PHP&lt;br /&gt;
&lt;br /&gt;
Version 1.3.37&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/matthiasmullie/minify&lt;br /&gt;
&lt;br /&gt;
==mimeTeX==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;filter/tex&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Compiled C program to convert TeX into GIFs&lt;br /&gt;
&lt;br /&gt;
Version: 1.4&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002-2004   John Forkosh Associates, Inc&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.forkosh.com/mimetex.html&lt;br /&gt;
&lt;br /&gt;
==Mustache.js==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/amd/src/mustache.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
JS library for displaying mustache templates.&lt;br /&gt;
&lt;br /&gt;
Version: 2.2.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2009 Chris Wanstrath (Ruby)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2014 Jan Lehnardt (JavaScript)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2015 The mustache.js community&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/janl/mustache.js/releases&lt;br /&gt;
&lt;br /&gt;
==Mustache==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/mustache&amp;quot;&lt;br /&gt;
&lt;br /&gt;
PHP library for displaying mustache templates.&lt;br /&gt;
&lt;br /&gt;
Version: 2.11.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2016 Justin Hileman&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/bobthecow/mustache.php/releases&lt;br /&gt;
&lt;br /&gt;
==mp3player==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/mp3player&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Flash movie to play streaming MP3s&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005   Andrew Walker&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==overlibmws==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/overlib.js&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Javascript library to enable DHTML popups, floating windows, events etc&lt;br /&gt;
&lt;br /&gt;
Version: July 2004&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002-2004   Foteos Macrides&lt;br /&gt;
&lt;br /&gt;
Copyright © 1998-2004   Erik Bosrup&lt;br /&gt;
&lt;br /&gt;
License: Artistic Open Source License&lt;br /&gt;
&lt;br /&gt;
http://www.macridesweb.com/oltest/&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PclZip==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pclzip&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to create, manage and unpack zip files.&lt;br /&gt;
&lt;br /&gt;
Version: 2.4 RC1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Vincent Blavet (&#039;&#039;vincent AT phpconcept DOT net&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.phpconcept.net&lt;br /&gt;
&lt;br /&gt;
==PEAR OLE Classes==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to write Excel files&lt;br /&gt;
&lt;br /&gt;
Version: 0.5&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Xavier Noguer&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/OLE&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PEAR Spreadsheet_Excel_Writer==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to write Excel files&lt;br /&gt;
&lt;br /&gt;
Version: 0.9.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Xavier Noguer and Mika Tuupola&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/Spreadsheet_Excel_Writer&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_Quickform==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to write forms&lt;br /&gt;
&lt;br /&gt;
Version: 3.2.6&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Bertrand Mansion, Adam Daniel, Alexey Borzov&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_Quickform&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_Quickform_Renderer_Tableless==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to render forms without tables&lt;br /&gt;
&lt;br /&gt;
Version: 0.3.4&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005 Mark Wiesemann&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_Quickform_Renderer_Tableless&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_QuickForm_DHTMLRulesTableless==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to render validation notices with dhtml&lt;br /&gt;
&lt;br /&gt;
Version: 0.1.2&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005 Alexey Borzov, Adam Daniel, Bertrand Mansion, Justin Patrin, Mark Wiesemann&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_QuickForm_DHTMLRulesTableless&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_Common==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class with many common HTML functions (used by HTML Quickform)&lt;br /&gt;
&lt;br /&gt;
Version: 0.3.4&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Adam Daniel, Bertrand Mansion, Klaus Guenther, Alexey Borzov&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_Common&lt;br /&gt;
&lt;br /&gt;
==PEAR XML_Parser==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class implementing one handy (sax-expat) XML parser&lt;br /&gt;
&lt;br /&gt;
Version: 1.3.2&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004-2008 The PHP Group &amp;amp; Stephan Schmidt&lt;br /&gt;
&lt;br /&gt;
License: New BSD License&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/XML_Parser&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PHP-CSS-Parser==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/php-css-parser&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A Parser for CSS Files written in PHP.&lt;br /&gt;
&lt;br /&gt;
Version: 8.1.0&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2011 Raphael Schweikert, http://sabberworm.com/&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/sabberworm/PHP-CSS-Parser&lt;br /&gt;
&lt;br /&gt;
==PHPExcel==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/phpexcel/PHPExcel.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library to read, write and create spreadsheet documents in PHP.&lt;br /&gt;
&lt;br /&gt;
Version 1.8.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2006 - 2015 PHPExcel&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
https://github.com/PHPOffice/PHPExcel&lt;br /&gt;
&lt;br /&gt;
==PHP mailer==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/class.phpmailer.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class for sending email using either sendmail, PHP mail(), or SMTP.  Methods are based upon the standard AspEmail(tm) classes.&lt;br /&gt;
&lt;br /&gt;
Version 5.2.16&lt;br /&gt;
&lt;br /&gt;
Copyright © 2003 Brent R. Matzelle (&#039;&#039;bmatzelle AT yahoo DOT com&#039;&#039;)&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://phpmailer.sourceforge.net&lt;br /&gt;
https://github.com/PHPMailer/PHPMailer/releases&lt;br /&gt;
&lt;br /&gt;
==PHP Markdown==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/markdown.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Functions to convert from the Markdown text format into clean XHTML.&lt;br /&gt;
&lt;br /&gt;
Version: 1.7.0 (with modifications)&lt;br /&gt;
&lt;br /&gt;
 * @copyright 2004-2016 Michel Fortin &amp;lt;https://michelf.com/projects/php-markdown/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 * @copyright (Original Markdown) 2004-2006 John Gruber &amp;lt;https://daringfireball.net/projects/markdown/&amp;gt;&lt;br /&gt;
All rights reserved.&lt;br /&gt;
&lt;br /&gt;
License: BSD&lt;br /&gt;
&lt;br /&gt;
http://www.michelf.com/projects/php-markdown/&lt;br /&gt;
&lt;br /&gt;
==RequireJS==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;/lib/requirejs/&#039;&#039;	&lt;br /&gt;
&lt;br /&gt;
RequireJS is a JavaScript file and module loader.&lt;br /&gt;
&lt;br /&gt;
Version 2.3.2&lt;br /&gt;
&lt;br /&gt;
License: new BSD or MIT&lt;br /&gt;
&lt;br /&gt;
http://requirejs.org/&lt;br /&gt;
&lt;br /&gt;
==scssphp==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;/lib/scssphp/&#039;&#039;	&lt;br /&gt;
&lt;br /&gt;
scssphp is a compiler for SCSS written in PHP.&lt;br /&gt;
&lt;br /&gt;
Version: 0.6.5&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2015 Leaf Corcoran&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
http://leafo.github.io/scssphp&lt;br /&gt;
&lt;br /&gt;
==SimplePie==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/lib/simplepie&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Simple Pie helps with blogs.&lt;br /&gt;
&lt;br /&gt;
Version 1.5&lt;br /&gt;
&lt;br /&gt;
License: BSD&lt;br /&gt;
&lt;br /&gt;
https://github.com/simplepie/simplepie&lt;br /&gt;
&lt;br /&gt;
==Snoopy==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/snoopy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A PHP net client&lt;br /&gt;
&lt;br /&gt;
Version: 1.0&lt;br /&gt;
&lt;br /&gt;
Copyright © 1999-2000 Monte Ohrt (&#039;&#039;monte AT ispi DOT net&#039;&#039;)&lt;br /&gt;
License: GNU LGPL&lt;br /&gt;
&lt;br /&gt;
http://snoopy.sourceforge.com&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==SMTP class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/class.smtp.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class that can be used to connect and communicate with any SMTP server. It implements all the SMTP functions defined in RFC821 except TURN.&lt;br /&gt;
&lt;br /&gt;
Version: 03/26/2001&lt;br /&gt;
&lt;br /&gt;
Copyright © 2001  Chris Ryan (&#039;&#039;chris AT greatbridge DOT com&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==Spike PHPCoverage==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/spikephpcoverage&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP code coverage reporting tool&lt;br /&gt;
&lt;br /&gt;
Version: 0.8.2 (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004 SpikeSource Inc&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://developer.spikesource.com/projects/phpcoverage&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==Spout==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/spout&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Library for importing and exporting csv / excel / ODS files.&lt;br /&gt;
&lt;br /&gt;
Version 2.7.3&lt;br /&gt;
&lt;br /&gt;
License: Apache&lt;br /&gt;
&lt;br /&gt;
https://github.com/box/spout/&lt;br /&gt;
&lt;br /&gt;
==Typo3 Character Set Class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/typo3&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class for conversion between charsets and multibyte-savy operations with strings.&lt;br /&gt;
&lt;br /&gt;
Version: 4.7.19&lt;br /&gt;
&lt;br /&gt;
Copyright © 2003-2005 Kasper Skaarhoj&lt;br /&gt;
&lt;br /&gt;
Licence: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://typo3.org/&lt;br /&gt;
&lt;br /&gt;
==Yahoo User Interface==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/yui&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The Yahoo! User Interface Library is a set of utilities and controls, in JavaScript, for building richly interactive web applications using techniques such as DOM scripting, DHTML and AJAX. The YUI Library also includes several core CSS resources.Set of user-interface components using AJAX, DHTML etc.  We use it for all our AJAX-related stuff.&lt;br /&gt;
&lt;br /&gt;
CVS version: 2.3.0&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2006, Yahoo! Inc.&lt;br /&gt;
&lt;br /&gt;
Licence: BSD&lt;br /&gt;
&lt;br /&gt;
http://developer.yahoo.com/yui/&lt;br /&gt;
&lt;br /&gt;
==Mustache.js==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/amd/src/mustache.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
JS library for displaying mustache templates.&lt;br /&gt;
&lt;br /&gt;
Version: 2.2.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2009 Chris Wanstrath (Ruby)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2014 Jan Lehnardt (JavaScript)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2015 The mustache.js community&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/janl/mustache.js/releases&lt;br /&gt;
&lt;br /&gt;
==LTI Tool Provider Library for PHP==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/ltiprovider/&amp;quot;&lt;br /&gt;
&lt;br /&gt;
PHP library for communicating with learning tools as per the LTI specification.&lt;br /&gt;
&lt;br /&gt;
Version: 3.0.2&lt;br /&gt;
&lt;br /&gt;
© 2016 IMS Global Learning Consortium Inc. All Rights Reserved. Trademark Policy - (www.imsglobal.org/trademarks)&lt;br /&gt;
&lt;br /&gt;
License: Apache 2&lt;br /&gt;
&lt;br /&gt;
https://github.com/IMSGlobal/LTI-Tool-Provider-Library-PHP&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Popper.js==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;admin/tool/usertours/amd/src/popper.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
A kickass library used to created Poppers in web applications&lt;br /&gt;
&lt;br /&gt;
© 2016 Federico Zivolo and contributors&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/FezVrasta/popper.js&lt;br /&gt;
&lt;br /&gt;
==Flexitour==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;admin/tool/usertours/amd/src/tour.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
A JS library for tours&lt;br /&gt;
&lt;br /&gt;
© 2016 Andrew Nicols and contributors&lt;br /&gt;
&lt;br /&gt;
License: GPLv3&lt;br /&gt;
&lt;br /&gt;
https://github.com/andrewnicols/flexitour&lt;br /&gt;
&lt;br /&gt;
[[Category:Credits]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_libraries_credits&amp;diff=53045</id>
		<title>Moodle libraries credits</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_libraries_credits&amp;diff=53045"/>
		<updated>2017-10-16T10:55:33Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* html2text */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Some of Moodle&#039;s libraries were written by other people, and are being redistributed as part of Moodle under their respective open source licenses that thankfully allow us to do so. Thanks to the authors of all these excellent products - without them Moodle would be missing important functionality. Copyright information for each package is included below:&lt;br /&gt;
&lt;br /&gt;
==ADOdb==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/adodb&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Database abstraction library for MySQL, PostgreSQL, MSSQL, Oracle, Interbase, Foxpro, Access, ADO, Sybase, DB2 and ODBC.&lt;br /&gt;
&lt;br /&gt;
Version: 5.20.9&lt;br /&gt;
&lt;br /&gt;
@copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.&lt;br /&gt;
&lt;br /&gt;
@copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community&lt;br /&gt;
&lt;br /&gt;
License: Dual LGPL and BSD-style&lt;br /&gt;
&lt;br /&gt;
http://adodb.sourceforge.net&lt;br /&gt;
&lt;br /&gt;
==Amazon S3==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;repository/s3/S3.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A standalone Amazon S3 (REST) client for PHP 5.2.x using CURL that does not require PEAR. &lt;br /&gt;
&lt;br /&gt;
Version: 0.5.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2013, Donovan Schönknecht&lt;br /&gt;
&lt;br /&gt;
License: BSD 2-Clause&lt;br /&gt;
&lt;br /&gt;
https://github.com/tpyo/amazon-s3-php-class/releases&lt;br /&gt;
&lt;br /&gt;
==CAS==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;auth/cas/CAS&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
phpCAS library to support CAS authentication plugin&lt;br /&gt;
&lt;br /&gt;
Copyright Jasig&lt;br /&gt;
&lt;br /&gt;
License: Apache License 2.0&lt;br /&gt;
&lt;br /&gt;
https://wiki.jasig.org/display/CASC/phpCAS&lt;br /&gt;
&lt;br /&gt;
==Chart.js==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/amd/src/chartjs-lazy.js&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Simple yet flexible JavaScript charting for designers &amp;amp; developers&lt;br /&gt;
&lt;br /&gt;
Version: 2.2.2&lt;br /&gt;
&lt;br /&gt;
Copyright 2016 Nick Downie&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
http://www.chartjs.org&lt;br /&gt;
&lt;br /&gt;
==EvalMath==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/evalmath&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to safely evaluate math expressions&lt;br /&gt;
&lt;br /&gt;
Copyright Miles Kaufmann&lt;br /&gt;
&lt;br /&gt;
License: BSD&lt;br /&gt;
&lt;br /&gt;
http://www.twmagic.com/&lt;br /&gt;
&lt;br /&gt;
==FLV player==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;filter/mediaplugin/flvplayer.swf&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Flash movie to play FLV files&lt;br /&gt;
&lt;br /&gt;
Copyright Jeroen Wijering &lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.jeroenwijering.com&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==FPDF Class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/fpdf&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to generate PDF files&lt;br /&gt;
&lt;br /&gt;
Version: 1.54&lt;br /&gt;
&lt;br /&gt;
Copyright Olivier PLATHEY&lt;br /&gt;
&lt;br /&gt;
License: Freeware&lt;br /&gt;
&lt;br /&gt;
http://www.setasign.com/products/fpdi/downloads&lt;br /&gt;
&lt;br /&gt;
== GeoIp2 ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/maxmind/GeoIp2&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library for precessing of GeoIP data files&lt;br /&gt;
&lt;br /&gt;
Version: 2.6.0&lt;br /&gt;
&lt;br /&gt;
Copyright MaxMind&lt;br /&gt;
&lt;br /&gt;
License: Apache 2.0&lt;br /&gt;
&lt;br /&gt;
https://github.com/maxmind/GeoIP2-php&lt;br /&gt;
&lt;br /&gt;
==Google APIs==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/google&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Library Google APIs Client Library for PHP&lt;br /&gt;
&lt;br /&gt;
Version: 1.1.7&lt;br /&gt;
&lt;br /&gt;
License: Apache License Version 2.0&lt;br /&gt;
&lt;br /&gt;
https://github.com/google/google-api-php-client&lt;br /&gt;
&lt;br /&gt;
==Graph Class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/graphlib.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to draw line, point, bar, and area graphs, including numeric x-axis and double y-axis.&lt;br /&gt;
&lt;br /&gt;
Version: 1.6.3 (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2000  Herman Veluwenkamp (&#039;&#039;hermanV AT mindless DOT com&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
==Horde==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/horde&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library used by the inbound e-mail handling system.&lt;br /&gt;
&lt;br /&gt;
Version: 5.2.7&lt;br /&gt;
&lt;br /&gt;
Copyright © Horde LLC&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://www.horde.org/&lt;br /&gt;
&lt;br /&gt;
==html2text==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/html2text&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP script to convert HTML into an approximate text equivalent&lt;br /&gt;
&lt;br /&gt;
Version: 4.1.0&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2005-2007 Jon Abernathy &amp;lt;jon@chuggnutt.com&amp;gt;&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
https://github.com/mtibben/html2text.git&lt;br /&gt;
&lt;br /&gt;
==htmlArea==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/editor&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Javascript/HTML script to put a GUI editor in textareas on Internet Explorer and Mozilla&lt;br /&gt;
&lt;br /&gt;
Version: 3.0 beta (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002  interactivetools.com, inc.&lt;br /&gt;
&lt;br /&gt;
License: htmlArea License (based on BSD license)&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==HTML Purifier==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/htmlpurifier&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Filters HTML.&lt;br /&gt;
&lt;br /&gt;
Version: 4.8.0&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
==IP-Atlas==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/ipatlas&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP scripts to show the location of an IP address on a map.&lt;br /&gt;
&lt;br /&gt;
Version: 1.0 (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002   Ivan Kozik&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.xpenguin.com/ip-atlas.php&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==jQuery==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/jquery&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
jQuery is a fast, small, and feature-rich JavaScript library widely used on moodle.&lt;br /&gt;
&lt;br /&gt;
Version: 1.12.3&lt;br /&gt;
&lt;br /&gt;
Copyright: 2016 The jQuery Foundation&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://jquery.com&lt;br /&gt;
&lt;br /&gt;
==jQuery migrate==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/jquery/jquery-migrate-1.4.0.js&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library used migrate older jQuery code to jQuery 3.0.&lt;br /&gt;
&lt;br /&gt;
Version: 1.4.0&lt;br /&gt;
&lt;br /&gt;
Copyright: 2016 The jQuery Foundation and other contributors&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/jquery/jquery-migrate&lt;br /&gt;
&lt;br /&gt;
==jQuery UI==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/jquery/ui-1.12.1/&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
jQuery UI is a set of user interface interactions, effects, widgets, and themes built on top of the jQuery library.&lt;br /&gt;
&lt;br /&gt;
Version: 1.12.1&lt;br /&gt;
&lt;br /&gt;
Copyright: 2016 The jQuery Foundation and other contributors&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/jquery/jquery-migrate&lt;br /&gt;
&lt;br /&gt;
==Services_JSON==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/json&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Allows PHP-&amp;gt;JS communication via JSON&lt;br /&gt;
&lt;br /&gt;
Version: 1.3.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005 Michal Migurski&lt;br /&gt;
&lt;br /&gt;
License: Modified BSD (GPL-compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/pepr/pepr-proposal-show.php?id=198&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==kses==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/kses.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
HTML/XHTML filter that only allows some elements and attributes&lt;br /&gt;
&lt;br /&gt;
Version: 0.2.2&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002, 2003, 2005   Ulf Harnhammar&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://sourceforge.net/projects/kses&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==less.php==&lt;br /&gt;
&lt;br /&gt;
The less.php is a PHP port of the official LESS processor used by moodle themes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/lessphp&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Version: 1.7.0.10&lt;br /&gt;
&lt;br /&gt;
License: Apache 2.0&lt;br /&gt;
&lt;br /&gt;
http://lessphp.typesettercms.com/&lt;br /&gt;
&lt;br /&gt;
Copyright:  Matt Agar and Martin Jantošovič&lt;br /&gt;
==loglevel.js==&lt;br /&gt;
&lt;br /&gt;
Minimal lightweight simple logging for JavaScript.&lt;br /&gt;
&lt;br /&gt;
Version 1.4.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2013 Tim Perry&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/pimterry/loglevel/&lt;br /&gt;
==MathJax==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Not actually included in Moodle. Moodle instead has a setting where the mathjax library is located. It is currently pointing to CDN by default.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
JavaScript filter library for displaying LaTeX, AsciiMath notation, and MathML.&lt;br /&gt;
&lt;br /&gt;
Version 2.7&lt;br /&gt;
&lt;br /&gt;
© Copyright 2015 The MathJax Consortium.&lt;br /&gt;
&lt;br /&gt;
License: Apache V2.0&lt;br /&gt;
&lt;br /&gt;
https://github.com/mathjax/MathJax&lt;br /&gt;
&lt;br /&gt;
==MatthiasMullie\Minify==&lt;br /&gt;
CSS &amp;amp; JavaScript minifier, in PHP&lt;br /&gt;
&lt;br /&gt;
Version 1.3.37&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/matthiasmullie/minify&lt;br /&gt;
&lt;br /&gt;
==mimeTeX==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;filter/tex&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Compiled C program to convert TeX into GIFs&lt;br /&gt;
&lt;br /&gt;
Version: 1.4&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002-2004   John Forkosh Associates, Inc&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.forkosh.com/mimetex.html&lt;br /&gt;
&lt;br /&gt;
==Mustache.js==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/amd/src/mustache.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
JS library for displaying mustache templates.&lt;br /&gt;
&lt;br /&gt;
Version: 2.2.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2009 Chris Wanstrath (Ruby)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2014 Jan Lehnardt (JavaScript)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2015 The mustache.js community&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/janl/mustache.js/releases&lt;br /&gt;
&lt;br /&gt;
==Mustache==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/mustache&amp;quot;&lt;br /&gt;
&lt;br /&gt;
PHP library for displaying mustache templates.&lt;br /&gt;
&lt;br /&gt;
Version: 2.11.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2016 Justin Hileman&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/bobthecow/mustache.php/releases&lt;br /&gt;
&lt;br /&gt;
==mp3player==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/mp3player&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Flash movie to play streaming MP3s&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005   Andrew Walker&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==overlibmws==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/overlib.js&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Javascript library to enable DHTML popups, floating windows, events etc&lt;br /&gt;
&lt;br /&gt;
Version: July 2004&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002-2004   Foteos Macrides&lt;br /&gt;
&lt;br /&gt;
Copyright © 1998-2004   Erik Bosrup&lt;br /&gt;
&lt;br /&gt;
License: Artistic Open Source License&lt;br /&gt;
&lt;br /&gt;
http://www.macridesweb.com/oltest/&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PclZip==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pclzip&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to create, manage and unpack zip files.&lt;br /&gt;
&lt;br /&gt;
Version: 2.4 RC1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Vincent Blavet (&#039;&#039;vincent AT phpconcept DOT net&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.phpconcept.net&lt;br /&gt;
&lt;br /&gt;
==PEAR OLE Classes==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to write Excel files&lt;br /&gt;
&lt;br /&gt;
Version: 0.5&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Xavier Noguer&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/OLE&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PEAR Spreadsheet_Excel_Writer==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to write Excel files&lt;br /&gt;
&lt;br /&gt;
Version: 0.9.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Xavier Noguer and Mika Tuupola&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/Spreadsheet_Excel_Writer&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_Quickform==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to write forms&lt;br /&gt;
&lt;br /&gt;
Version: 3.2.6&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Bertrand Mansion, Adam Daniel, Alexey Borzov&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_Quickform&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_Quickform_Renderer_Tableless==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to render forms without tables&lt;br /&gt;
&lt;br /&gt;
Version: 0.3.4&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005 Mark Wiesemann&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_Quickform_Renderer_Tableless&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_QuickForm_DHTMLRulesTableless==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to render validation notices with dhtml&lt;br /&gt;
&lt;br /&gt;
Version: 0.1.2&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005 Alexey Borzov, Adam Daniel, Bertrand Mansion, Justin Patrin, Mark Wiesemann&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_QuickForm_DHTMLRulesTableless&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_Common==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class with many common HTML functions (used by HTML Quickform)&lt;br /&gt;
&lt;br /&gt;
Version: 0.3.4&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Adam Daniel, Bertrand Mansion, Klaus Guenther, Alexey Borzov&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_Common&lt;br /&gt;
&lt;br /&gt;
==PEAR XML_Parser==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class implementing one handy (sax-expat) XML parser&lt;br /&gt;
&lt;br /&gt;
Version: 1.3.2&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004-2008 The PHP Group &amp;amp; Stephan Schmidt&lt;br /&gt;
&lt;br /&gt;
License: New BSD License&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/XML_Parser&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PHP-CSS-Parser==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/php-css-parser&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A Parser for CSS Files written in PHP.&lt;br /&gt;
&lt;br /&gt;
Version: 8.1.0&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2011 Raphael Schweikert, http://sabberworm.com/&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/sabberworm/PHP-CSS-Parser&lt;br /&gt;
&lt;br /&gt;
==PHPExcel==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/phpexcel/PHPExcel.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library to read, write and create spreadsheet documents in PHP.&lt;br /&gt;
&lt;br /&gt;
Version 1.8.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2006 - 2015 PHPExcel&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
https://github.com/PHPOffice/PHPExcel&lt;br /&gt;
&lt;br /&gt;
==PHP mailer==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/class.phpmailer.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class for sending email using either sendmail, PHP mail(), or SMTP.  Methods are based upon the standard AspEmail(tm) classes.&lt;br /&gt;
&lt;br /&gt;
Version 5.2.16&lt;br /&gt;
&lt;br /&gt;
Copyright © 2003 Brent R. Matzelle (&#039;&#039;bmatzelle AT yahoo DOT com&#039;&#039;)&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://phpmailer.sourceforge.net&lt;br /&gt;
https://github.com/PHPMailer/PHPMailer/releases&lt;br /&gt;
&lt;br /&gt;
==PHP Markdown==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/markdown.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Functions to convert from the Markdown text format into clean XHTML.&lt;br /&gt;
&lt;br /&gt;
Version: 1.7.0 (with modifications)&lt;br /&gt;
&lt;br /&gt;
 * @copyright 2004-2016 Michel Fortin &amp;lt;https://michelf.com/projects/php-markdown/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 * @copyright (Original Markdown) 2004-2006 John Gruber &amp;lt;https://daringfireball.net/projects/markdown/&amp;gt;&lt;br /&gt;
All rights reserved.&lt;br /&gt;
&lt;br /&gt;
License: BSD&lt;br /&gt;
&lt;br /&gt;
http://www.michelf.com/projects/php-markdown/&lt;br /&gt;
&lt;br /&gt;
==RequireJS==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;/lib/requirejs/&#039;&#039;	&lt;br /&gt;
&lt;br /&gt;
RequireJS is a JavaScript file and module loader.&lt;br /&gt;
&lt;br /&gt;
Version 2.3.2&lt;br /&gt;
&lt;br /&gt;
License: new BSD or MIT&lt;br /&gt;
&lt;br /&gt;
http://requirejs.org/&lt;br /&gt;
&lt;br /&gt;
==scssphp==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;/lib/scssphp/&#039;&#039;	&lt;br /&gt;
&lt;br /&gt;
scssphp is a compiler for SCSS written in PHP.&lt;br /&gt;
&lt;br /&gt;
Version: 0.6.5&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2015 Leaf Corcoran&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
http://leafo.github.io/scssphp&lt;br /&gt;
&lt;br /&gt;
==SimplePie==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/lib/simplepie&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Simple Pie helps with blogs.&lt;br /&gt;
&lt;br /&gt;
Version 1.4.2&lt;br /&gt;
&lt;br /&gt;
License: BSD&lt;br /&gt;
&lt;br /&gt;
https://github.com/simplepie/simplepie&lt;br /&gt;
&lt;br /&gt;
==Snoopy==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/snoopy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A PHP net client&lt;br /&gt;
&lt;br /&gt;
Version: 1.0&lt;br /&gt;
&lt;br /&gt;
Copyright © 1999-2000 Monte Ohrt (&#039;&#039;monte AT ispi DOT net&#039;&#039;)&lt;br /&gt;
License: GNU LGPL&lt;br /&gt;
&lt;br /&gt;
http://snoopy.sourceforge.com&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==SMTP class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/class.smtp.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class that can be used to connect and communicate with any SMTP server. It implements all the SMTP functions defined in RFC821 except TURN.&lt;br /&gt;
&lt;br /&gt;
Version: 03/26/2001&lt;br /&gt;
&lt;br /&gt;
Copyright © 2001  Chris Ryan (&#039;&#039;chris AT greatbridge DOT com&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==Spike PHPCoverage==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/spikephpcoverage&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP code coverage reporting tool&lt;br /&gt;
&lt;br /&gt;
Version: 0.8.2 (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004 SpikeSource Inc&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://developer.spikesource.com/projects/phpcoverage&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==Spout==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/spout&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Library for importing and exporting csv / excel / ODS files.&lt;br /&gt;
&lt;br /&gt;
Version 2.7.3&lt;br /&gt;
&lt;br /&gt;
License: Apache&lt;br /&gt;
&lt;br /&gt;
https://github.com/box/spout/&lt;br /&gt;
&lt;br /&gt;
==Typo3 Character Set Class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/typo3&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class for conversion between charsets and multibyte-savy operations with strings.&lt;br /&gt;
&lt;br /&gt;
Version: 4.7.19&lt;br /&gt;
&lt;br /&gt;
Copyright © 2003-2005 Kasper Skaarhoj&lt;br /&gt;
&lt;br /&gt;
Licence: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://typo3.org/&lt;br /&gt;
&lt;br /&gt;
==Yahoo User Interface==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/yui&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The Yahoo! User Interface Library is a set of utilities and controls, in JavaScript, for building richly interactive web applications using techniques such as DOM scripting, DHTML and AJAX. The YUI Library also includes several core CSS resources.Set of user-interface components using AJAX, DHTML etc.  We use it for all our AJAX-related stuff.&lt;br /&gt;
&lt;br /&gt;
CVS version: 2.3.0&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2006, Yahoo! Inc.&lt;br /&gt;
&lt;br /&gt;
Licence: BSD&lt;br /&gt;
&lt;br /&gt;
http://developer.yahoo.com/yui/&lt;br /&gt;
&lt;br /&gt;
==Mustache.js==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/amd/src/mustache.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
JS library for displaying mustache templates.&lt;br /&gt;
&lt;br /&gt;
Version: 2.2.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2009 Chris Wanstrath (Ruby)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2014 Jan Lehnardt (JavaScript)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2015 The mustache.js community&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/janl/mustache.js/releases&lt;br /&gt;
&lt;br /&gt;
==LTI Tool Provider Library for PHP==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/ltiprovider/&amp;quot;&lt;br /&gt;
&lt;br /&gt;
PHP library for communicating with learning tools as per the LTI specification.&lt;br /&gt;
&lt;br /&gt;
Version: 3.0.2&lt;br /&gt;
&lt;br /&gt;
© 2016 IMS Global Learning Consortium Inc. All Rights Reserved. Trademark Policy - (www.imsglobal.org/trademarks)&lt;br /&gt;
&lt;br /&gt;
License: Apache 2&lt;br /&gt;
&lt;br /&gt;
https://github.com/IMSGlobal/LTI-Tool-Provider-Library-PHP&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Popper.js==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;admin/tool/usertours/amd/src/popper.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
A kickass library used to created Poppers in web applications&lt;br /&gt;
&lt;br /&gt;
© 2016 Federico Zivolo and contributors&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/FezVrasta/popper.js&lt;br /&gt;
&lt;br /&gt;
==Flexitour==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;admin/tool/usertours/amd/src/tour.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
A JS library for tours&lt;br /&gt;
&lt;br /&gt;
© 2016 Andrew Nicols and contributors&lt;br /&gt;
&lt;br /&gt;
License: GPLv3&lt;br /&gt;
&lt;br /&gt;
https://github.com/andrewnicols/flexitour&lt;br /&gt;
&lt;br /&gt;
[[Category:Credits]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Restore_2.0_for_developers&amp;diff=53039</id>
		<title>Restore 2.0 for developers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Restore_2.0_for_developers&amp;diff=53039"/>
		<updated>2017-10-16T05:52:11Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* restore_choice_stepslib.php */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:Backup 2.0}}{{Moodle_2.0}}{{Work in progress}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This page tries to explain, from a development perspective, &#039;&#039;&#039;how to implement&#039;&#039;&#039; the restore feature for various Moodle 2.x plugins, mainly, modules and blocks. &lt;br /&gt;
&lt;br /&gt;
In order to work with Restore 2.0 you must read [[Backup 2.0 for developers]]. Everything will be crystal clear once you have read it. &lt;br /&gt;
&lt;br /&gt;
In this documentation you will learn about some points that you can not easily deduce from [[Backup 2.0 for developers]] concerning the Choice module.&lt;br /&gt;
&lt;br /&gt;
== Coding ==&lt;br /&gt;
the restore is composed by two main php files: restore_choice_stepslib.php and restore_choice_activity_task.class.php&lt;br /&gt;
=== restore_choice_stepslib.php ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Structure step to restore one choice activity&lt;br /&gt;
 */&lt;br /&gt;
class restore_choice_activity_structure_step extends restore_activity_structure_step {&lt;br /&gt;
&lt;br /&gt;
    protected function define_structure() {&lt;br /&gt;
&lt;br /&gt;
        $paths = array();&lt;br /&gt;
        $userinfo = $this-&amp;gt;get_setting_value(&#039;userinfo&#039;);&lt;br /&gt;
&lt;br /&gt;
        $paths[] = new restore_path_element(&#039;choice&#039;, &#039;/activity/choice&#039;);&lt;br /&gt;
        $paths[] = new restore_path_element(&#039;choice_option&#039;, &#039;/activity/choice/options/option&#039;);&lt;br /&gt;
        if ($userinfo) {&lt;br /&gt;
            $paths[] = new restore_path_element(&#039;choice_answer&#039;, &#039;/activity/choice/answers/answer&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Return the paths wrapped into standard activity structure&lt;br /&gt;
        return $this-&amp;gt;prepare_activity_structure($paths);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function process_choice($data) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
&lt;br /&gt;
        $data = (object)$data;&lt;br /&gt;
        $oldid = $data-&amp;gt;id;&lt;br /&gt;
        $data-&amp;gt;course = $this-&amp;gt;get_courseid();&lt;br /&gt;
&lt;br /&gt;
        $data-&amp;gt;timeopen = $this-&amp;gt;apply_date_offset($data-&amp;gt;timeopen);&lt;br /&gt;
        $data-&amp;gt;timeclose = $this-&amp;gt;apply_date_offset($data-&amp;gt;timeclose);&lt;br /&gt;
&lt;br /&gt;
        // insert the choice record&lt;br /&gt;
        $newitemid = $DB-&amp;gt;insert_record(&#039;choice&#039;, $data);&lt;br /&gt;
        // immediately after inserting &amp;quot;activity&amp;quot; record, call this&lt;br /&gt;
        $this-&amp;gt;apply_activity_instance($newitemid);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function process_choice_option($data) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
&lt;br /&gt;
        $data = (object)$data;&lt;br /&gt;
        $oldid = $data-&amp;gt;id;&lt;br /&gt;
&lt;br /&gt;
        $data-&amp;gt;choiceid = $this-&amp;gt;get_new_parentid(&#039;choice&#039;);&lt;br /&gt;
&lt;br /&gt;
        $newitemid = $DB-&amp;gt;insert_record(&#039;choice_options&#039;, $data);&lt;br /&gt;
        $this-&amp;gt;set_mapping(&#039;choice_option&#039;, $oldid, $newitemid);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function process_choice_answer($data) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
&lt;br /&gt;
        $data = (object)$data;&lt;br /&gt;
&lt;br /&gt;
        $data-&amp;gt;choiceid = $this-&amp;gt;get_new_parentid(&#039;choice&#039;);&lt;br /&gt;
        $data-&amp;gt;optionid = $this-&amp;gt;get_mappingid(&#039;choice_option&#039;, $data-&amp;gt;optionid);&lt;br /&gt;
        $data-&amp;gt;userid = $this-&amp;gt;get_mappingid(&#039;user&#039;, $data-&amp;gt;userid);&lt;br /&gt;
&lt;br /&gt;
        $newitemid = $DB-&amp;gt;insert_record(&#039;choice_answers&#039;, $data);&lt;br /&gt;
        // No need to save this mapping as far as nothing depend on it&lt;br /&gt;
        // (child paths, file areas nor links decoder)&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function after_execute() {&lt;br /&gt;
        // Add choice related files, no need to match by itemname (just internally handled context)&lt;br /&gt;
        $this-&amp;gt;add_related_files(&#039;mod_choice&#039;, &#039;intro&#039;, null);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== restore_choice_activity_task.class.php ===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * choice restore task that provides all the settings and steps to perform one&lt;br /&gt;
 * complete restore of the activity&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot . &#039;/mod/choice/backup/moodle2/restore_choice_stepslib.php&#039;); // Because it exists (must)&lt;br /&gt;
&lt;br /&gt;
class restore_choice_activity_task extends restore_activity_task {&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Define (add) particular settings this activity can have&lt;br /&gt;
     */&lt;br /&gt;
    protected function define_my_settings() {&lt;br /&gt;
        // No particular settings for this activity&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Define (add) particular steps this activity can have&lt;br /&gt;
     */&lt;br /&gt;
    protected function define_my_steps() {&lt;br /&gt;
        // Choice only has one structure step&lt;br /&gt;
        $this-&amp;gt;add_step(new restore_choice_activity_structure_step(&#039;choice_structure&#039;, &#039;choice.xml&#039;));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Define the contents in the activity that must be&lt;br /&gt;
     * processed by the link decoder&lt;br /&gt;
     */&lt;br /&gt;
    static public function define_decode_contents() {&lt;br /&gt;
        $contents = array();&lt;br /&gt;
&lt;br /&gt;
        $contents[] = new restore_decode_content(&#039;choice&#039;, array(&#039;intro&#039;), &#039;choice&#039;);&lt;br /&gt;
&lt;br /&gt;
        return $contents;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Define the decoding rules for links belonging&lt;br /&gt;
     * to the activity to be executed by the link decoder&lt;br /&gt;
     */&lt;br /&gt;
    static public function define_decode_rules() {&lt;br /&gt;
        $rules = array();&lt;br /&gt;
&lt;br /&gt;
        $rules[] = new restore_decode_rule(&#039;CHOICEVIEWBYID&#039;, &#039;/mod/choice/view.php?id=$1&#039;, &#039;course_module&#039;);&lt;br /&gt;
        $rules[] = new restore_decode_rule(&#039;CHOICEINDEX&#039;, &#039;/mod/choice/index.php?id=$1&#039;, &#039;course&#039;);&lt;br /&gt;
&lt;br /&gt;
        return $rules;&lt;br /&gt;
&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Define the restore log rules that will be applied&lt;br /&gt;
     * by the {@link restore_logs_processor} when restoring&lt;br /&gt;
     * choice logs. It must return one array&lt;br /&gt;
     * of {@link restore_log_rule} objects&lt;br /&gt;
     */&lt;br /&gt;
    static public function define_restore_log_rules() {&lt;br /&gt;
        $rules = array();&lt;br /&gt;
&lt;br /&gt;
        $rules[] = new restore_log_rule(&#039;choice&#039;, &#039;add&#039;, &#039;view.php?id={course_module}&#039;, &#039;{choice}&#039;);&lt;br /&gt;
        $rules[] = new restore_log_rule(&#039;choice&#039;, &#039;update&#039;, &#039;view.php?id={course_module}&#039;, &#039;{choice}&#039;);&lt;br /&gt;
        $rules[] = new restore_log_rule(&#039;choice&#039;, &#039;view&#039;, &#039;view.php?id={course_module}&#039;, &#039;{choice}&#039;);&lt;br /&gt;
        $rules[] = new restore_log_rule(&#039;choice&#039;, &#039;choose&#039;, &#039;view.php?id={course_module}&#039;, &#039;{choice}&#039;);&lt;br /&gt;
        $rules[] = new restore_log_rule(&#039;choice&#039;, &#039;choose again&#039;, &#039;view.php?id={course_module}&#039;, &#039;{choice}&#039;);&lt;br /&gt;
        $rules[] = new restore_log_rule(&#039;choice&#039;, &#039;report&#039;, &#039;report.php?id={course_module}&#039;, &#039;{choice}&#039;);&lt;br /&gt;
&lt;br /&gt;
        return $rules;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Define the restore log rules that will be applied&lt;br /&gt;
     * by the {@link restore_logs_processor} when restoring&lt;br /&gt;
     * course logs. It must return one array&lt;br /&gt;
     * of {@link restore_log_rule} objects&lt;br /&gt;
     *&lt;br /&gt;
     * Note this rules are applied when restoring course logs&lt;br /&gt;
     * by the restore final task, but are defined here at&lt;br /&gt;
     * activity level. All them are rules not linked to any module instance (cmid = 0)&lt;br /&gt;
     */&lt;br /&gt;
    static public function define_restore_log_rules_for_course() {&lt;br /&gt;
        $rules = array();&lt;br /&gt;
&lt;br /&gt;
        // Fix old wrong uses (missing extension)&lt;br /&gt;
        $rules[] = new restore_log_rule(&#039;choice&#039;, &#039;view all&#039;, &#039;index?id={course}&#039;, null,&lt;br /&gt;
                                        null, null, &#039;index.php?id={course}&#039;);&lt;br /&gt;
        $rules[] = new restore_log_rule(&#039;choice&#039;, &#039;view all&#039;, &#039;index.php?id={course}&#039;, null);&lt;br /&gt;
&lt;br /&gt;
        return $rules;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;define_restore_log_rules&#039;&#039;&#039;: it covers all the &amp;quot;mandatory&amp;quot; log actions, performing {course_module} and {choice} mappings properly. Note that names between curly brackets instruct the log processor to look in the mapping tables for item = name between brackets. Of course, other modules like forum, has a lot of rules, with more complex mappings and so on. Choice is pretty basic.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;define_restore_log_rules_for_course&#039;&#039;&#039;: choice module has the 1st rule because, while implementing restore, we discovered one bug causing URLs to be written in the logs table WITHOUT the .php in the URL, hence choice has that extra rule (that uses the 5-8 params, to REWRITE the URL to be inserted on restore). But that was one problem with choices only, afaik, so you probably would not need it in your own module.&lt;br /&gt;
&lt;br /&gt;
== Automatically triggering restore in code ==&lt;br /&gt;
&lt;br /&gt;
As with backup it is possible to automatically trigger a restore for a course (or activity or anything else you can back up). Here is how to restore a course backup into a new course:&lt;br /&gt;
&lt;br /&gt;
# Put the backup files in a specific folder: $CFG-&amp;gt;dataroot/temp/backup/$folder, where $folder is a random or unused unique id.&lt;br /&gt;
# Decide on the course shortname, fullname, and category id for restore (course must not already exist).&lt;br /&gt;
# Run the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
define(&#039;CLI_SCRIPT&#039;, true);&lt;br /&gt;
&lt;br /&gt;
require_once(&#039;config.php&#039;);&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot . &#039;/backup/util/includes/restore_includes.php&#039;);&lt;br /&gt;
&lt;br /&gt;
// Transaction.&lt;br /&gt;
$transaction = $DB-&amp;gt;start_delegated_transaction();&lt;br /&gt;
&lt;br /&gt;
// Create new course.&lt;br /&gt;
$folder             = XX; // as found in: $CFG-&amp;gt;dataroot . &#039;/temp/backup/&#039; &lt;br /&gt;
$categoryid         = YY; // e.g. 1 == Miscellaneous&lt;br /&gt;
$userdoingrestore   = ZZ; // e.g. 2 == admin&lt;br /&gt;
$courseid           = restore_dbops::create_new_course(&#039;&#039;, &#039;&#039;, $categoryid);&lt;br /&gt;
&lt;br /&gt;
// Restore backup into course.&lt;br /&gt;
$controller = new restore_controller($folder, $courseid, &lt;br /&gt;
        backup::INTERACTIVE_NO, backup::MODE_SAMESITE, $userdoingrestore,&lt;br /&gt;
        backup::TARGET_NEW_COURSE);&lt;br /&gt;
$controller-&amp;gt;execute_precheck();&lt;br /&gt;
$controller-&amp;gt;execute_plan();&lt;br /&gt;
&lt;br /&gt;
// Commit.&lt;br /&gt;
$transaction-&amp;gt;allow_commit();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
&lt;br /&gt;
* The transaction is used so that if backup fails, the course isn&#039;t created.&lt;br /&gt;
* The MODE_SAMESITE option is used if restoring a backup which comes from the same site, otherwise MODE_GENERAL might be used.&lt;br /&gt;
&lt;br /&gt;
== Code that runs after restore ==&lt;br /&gt;
&lt;br /&gt;
If you are writing a restore task for an activity module, your code is all executed while the system is restoring that module. The &amp;lt;tt&amp;gt;after_execute&amp;lt;/tt&amp;gt; method in your &amp;lt;tt&amp;gt;restore_mymodule_activity_structure_step&amp;lt;/tt&amp;gt; class is called immediately after all the other restore functions in that step are finished for that instance of the module.&lt;br /&gt;
&lt;br /&gt;
=== The problem ===&lt;br /&gt;
&lt;br /&gt;
Usually this is correct, but in some situations you may need to have an activity module restore that depends in some way on another activity module or on a course section other than the one the module belongs to. Depending on the order within the course, in some cases the other module or section has not yet been restored, so this is a problem.&lt;br /&gt;
&lt;br /&gt;
The code that may not work as a result is code that tries to convert from an &#039;old&#039; course-module ID or section ID into a &#039;new&#039; one:&lt;br /&gt;
&lt;br /&gt;
 $newcmid = $this-&amp;gt;get_mappingid(&#039;course_module&#039;, $oldcmid);&lt;br /&gt;
 $newsectionid = $this-&amp;gt;get_mappingid(&#039;course_section&#039;, $oldsectionid);&lt;br /&gt;
&lt;br /&gt;
These functions will return false if the relevant course-module or section has not yet been restored.&lt;br /&gt;
&lt;br /&gt;
=== The solution ===&lt;br /&gt;
&lt;br /&gt;
You can have a method called &amp;lt;tt&amp;gt;after_restore&amp;lt;/tt&amp;gt; inside your TASK (not step) class, &amp;lt;tt&amp;gt;restore_mymodule_activity_task&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 public function after_restore() {&lt;br /&gt;
     // Do something at end of restore&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
In this method you can carry out necessary finishing tasks such as updating course-module and section IDs (using code like the above).&lt;br /&gt;
&lt;br /&gt;
The function will be called once per activity that was restored (for example, if you put this code into forum restore, and there are four forums on the website being restored, then it will be called four times). You can use the &amp;lt;tt&amp;gt;get_activityid&amp;lt;/tt&amp;gt; method to return the current activity ID (other functions such as &amp;lt;tt&amp;gt;get_courseid&amp;lt;/tt&amp;gt; are also available).&lt;br /&gt;
&lt;br /&gt;
=== Warning ===&lt;br /&gt;
&lt;br /&gt;
You should do as little as possible in this method, and be aware that using it may mean your activity module does not function correctly in some cases.&lt;br /&gt;
&lt;br /&gt;
* It is possible to backup and restore a single module, or a section, rather than a whole course. &lt;br /&gt;
* This function (backing up a single module) may also be used to support other upcoming features such as the &#039;copy activity&#039; feature.&lt;br /&gt;
&lt;br /&gt;
If somebody backs up your activity as a single activity, then obviously any such dependencies will not be included. There is currently no way to indicate that your module has any dependencies. So the backup and restore will go ahead but, once again, the &amp;lt;tt&amp;gt;get_mappingid&amp;lt;/tt&amp;gt; function will return false.&lt;br /&gt;
&lt;br /&gt;
At present the best way to handle this is to add a message to the restore log (which will not currently be displayed anywhere, but this might change):&lt;br /&gt;
&lt;br /&gt;
 $this-&amp;gt;get_logger()-&amp;gt;process(&amp;quot;Failed to restore dependency in mymodule &#039;$name&#039;. &amp;quot; .&lt;br /&gt;
         &amp;quot;Backup and restore will not work correctly unless you include the dependent module.&amp;quot;,&lt;br /&gt;
         backup::LOG_ERROR);&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=ctags&amp;diff=53038</id>
		<title>ctags</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=ctags&amp;diff=53038"/>
		<updated>2017-10-16T05:42:06Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Moodle 3.4 and newer ==&lt;br /&gt;
As of Moodle 3.4 tags.txt file is completely removed from core, use features of your respective editors.&lt;br /&gt;
&lt;br /&gt;
== Moodle 1.9.6 and newer ==&lt;br /&gt;
As of Moodle 1.9.6 the tags file is no longer included in the Moodle distribution. Instead a file tags.txt is included providing instructions on creating the tag file yourself. The text of this file is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Generating a tags file&lt;br /&gt;
======================&lt;br /&gt;
&lt;br /&gt;
If you need a tags file so that you can jump around Moodle code&lt;br /&gt;
easily in your editor (eg vim or emacs), you can generate one:&lt;br /&gt;
&lt;br /&gt;
Exuberant ctags (default on Linux, can be compiled on other platforms):&lt;br /&gt;
----------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
ctags -R --languages=php --php-kinds=f \&lt;br /&gt;
--regex-PHP=&#039;/abstract +class +([^ ]*)/\1/c/&#039; \&lt;br /&gt;
--regex-PHP=&#039;/interface +([^ ]*)/\1/c/&#039; \&lt;br /&gt;
--regex-PHP=&#039;/(public |static |abstract |protected |private )+ *function +([^ (]*)/\2/f/&#039;&lt;br /&gt;
&lt;br /&gt;
BSD ctags (Default on Mac OS X):&lt;br /&gt;
-------------------------------&lt;br /&gt;
&lt;br /&gt;
 (TODO)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Using tags with Vim ==&lt;br /&gt;
&lt;br /&gt;
In order to use the tags file with the Vim editor (on a Unix style system), you should first add the following line to the file &#039;&#039;&#039;.vimrc&#039;&#039;&#039; in your home directory:&lt;br /&gt;
&lt;br /&gt;
    set tags=tags;/&lt;br /&gt;
&lt;br /&gt;
If .vimrc does not exist you should create it. This directive will force Vim to search for the tags file in the directory tree in which you are working (it searches up from where you are) so it will work for multiple versions of the code automatically.&lt;br /&gt;
&lt;br /&gt;
=== How to jump to a tag with Vim ===&lt;br /&gt;
&lt;br /&gt;
There are a number of things you can do:&lt;br /&gt;
&lt;br /&gt;
* Place the cursor over the tag (e.g., function name) and press &#039;&#039;&#039;CTRL+]&#039;&#039;&#039;.&lt;br /&gt;
* Type the command &#039;&#039;&#039;:tag &amp;lt;tagname&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
* To open in a new editor window type the command &#039;&#039;&#039;:stag &amp;lt;tagname&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
* To return to your previous location type &#039;&#039;&#039;CTRL+t&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Using tags with Emacs ==&lt;br /&gt;
To create the TAGS file add a -e to the command of tags.txt, like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ctags -e -R --languages=php --exclude=&amp;quot;CVS&amp;quot; --php-kinds=f \&lt;br /&gt;
--regex-PHP=&#039;/abstract class ([^ ]*)/\1/c/&#039; \&lt;br /&gt;
--regex-PHP=&#039;/interface ([^ ]*)/\1/c/&#039; \&lt;br /&gt;
--regex-PHP=&#039;/(public |static |abstract |protected |private )+function ([^ (]*)/\2/f/&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For instructions about how to use it look to the emacs wiki page [http://www.emacswiki.org/emacs/EmacsTags EmacsTags]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [http://www.vim.org/tips/tip.php?tip_id=94 Vim tags usage tip]&lt;br /&gt;
* [http://vimdoc.sourceforge.net/htmldoc/usr_29.html#29.1 Vim documentation: Using tags]&lt;br /&gt;
* [http://vimdoc.sourceforge.net/htmldoc/tagsrch.html Vim documentation: Tags and special searches]&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer tools]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_libraries_credits&amp;diff=53037</id>
		<title>Moodle libraries credits</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_libraries_credits&amp;diff=53037"/>
		<updated>2017-10-16T05:36:55Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* PHP Markdown */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Some of Moodle&#039;s libraries were written by other people, and are being redistributed as part of Moodle under their respective open source licenses that thankfully allow us to do so. Thanks to the authors of all these excellent products - without them Moodle would be missing important functionality. Copyright information for each package is included below:&lt;br /&gt;
&lt;br /&gt;
==ADOdb==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/adodb&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Database abstraction library for MySQL, PostgreSQL, MSSQL, Oracle, Interbase, Foxpro, Access, ADO, Sybase, DB2 and ODBC.&lt;br /&gt;
&lt;br /&gt;
Version: 5.20.9&lt;br /&gt;
&lt;br /&gt;
@copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.&lt;br /&gt;
&lt;br /&gt;
@copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community&lt;br /&gt;
&lt;br /&gt;
License: Dual LGPL and BSD-style&lt;br /&gt;
&lt;br /&gt;
http://adodb.sourceforge.net&lt;br /&gt;
&lt;br /&gt;
==Amazon S3==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;repository/s3/S3.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A standalone Amazon S3 (REST) client for PHP 5.2.x using CURL that does not require PEAR. &lt;br /&gt;
&lt;br /&gt;
Version: 0.5.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2013, Donovan Schönknecht&lt;br /&gt;
&lt;br /&gt;
License: BSD 2-Clause&lt;br /&gt;
&lt;br /&gt;
https://github.com/tpyo/amazon-s3-php-class/releases&lt;br /&gt;
&lt;br /&gt;
==CAS==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;auth/cas/CAS&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
phpCAS library to support CAS authentication plugin&lt;br /&gt;
&lt;br /&gt;
Copyright Jasig&lt;br /&gt;
&lt;br /&gt;
License: Apache License 2.0&lt;br /&gt;
&lt;br /&gt;
https://wiki.jasig.org/display/CASC/phpCAS&lt;br /&gt;
&lt;br /&gt;
==Chart.js==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/amd/src/chartjs-lazy.js&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Simple yet flexible JavaScript charting for designers &amp;amp; developers&lt;br /&gt;
&lt;br /&gt;
Version: 2.2.2&lt;br /&gt;
&lt;br /&gt;
Copyright 2016 Nick Downie&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
http://www.chartjs.org&lt;br /&gt;
&lt;br /&gt;
==EvalMath==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/evalmath&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to safely evaluate math expressions&lt;br /&gt;
&lt;br /&gt;
Copyright Miles Kaufmann&lt;br /&gt;
&lt;br /&gt;
License: BSD&lt;br /&gt;
&lt;br /&gt;
http://www.twmagic.com/&lt;br /&gt;
&lt;br /&gt;
==FLV player==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;filter/mediaplugin/flvplayer.swf&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Flash movie to play FLV files&lt;br /&gt;
&lt;br /&gt;
Copyright Jeroen Wijering &lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.jeroenwijering.com&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==FPDF Class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/fpdf&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to generate PDF files&lt;br /&gt;
&lt;br /&gt;
Version: 1.54&lt;br /&gt;
&lt;br /&gt;
Copyright Olivier PLATHEY&lt;br /&gt;
&lt;br /&gt;
License: Freeware&lt;br /&gt;
&lt;br /&gt;
http://www.setasign.com/products/fpdi/downloads&lt;br /&gt;
&lt;br /&gt;
== GeoIp2 ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/maxmind/GeoIp2&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library for precessing of GeoIP data files&lt;br /&gt;
&lt;br /&gt;
Version: 2.6.0&lt;br /&gt;
&lt;br /&gt;
Copyright MaxMind&lt;br /&gt;
&lt;br /&gt;
License: Apache 2.0&lt;br /&gt;
&lt;br /&gt;
https://github.com/maxmind/GeoIP2-php&lt;br /&gt;
&lt;br /&gt;
==Google APIs==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/google&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Library Google APIs Client Library for PHP&lt;br /&gt;
&lt;br /&gt;
Version: 1.1.7&lt;br /&gt;
&lt;br /&gt;
License: Apache License Version 2.0&lt;br /&gt;
&lt;br /&gt;
https://github.com/google/google-api-php-client&lt;br /&gt;
&lt;br /&gt;
==Graph Class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/graphlib.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to draw line, point, bar, and area graphs, including numeric x-axis and double y-axis.&lt;br /&gt;
&lt;br /&gt;
Version: 1.6.3 (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2000  Herman Veluwenkamp (&#039;&#039;hermanV AT mindless DOT com&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
==Horde==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/horde&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library used by the inbound e-mail handling system.&lt;br /&gt;
&lt;br /&gt;
Version: 5.2.7&lt;br /&gt;
&lt;br /&gt;
Copyright © Horde LLC&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://www.horde.org/&lt;br /&gt;
&lt;br /&gt;
==html2text==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/html2text&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP script to convert HTML into an approximate text equivalent&lt;br /&gt;
&lt;br /&gt;
Version: 4.0.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005-7 Jon Abernathy&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
https://github.com/mtibben/html2text.git&lt;br /&gt;
&lt;br /&gt;
==htmlArea==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/editor&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Javascript/HTML script to put a GUI editor in textareas on Internet Explorer and Mozilla&lt;br /&gt;
&lt;br /&gt;
Version: 3.0 beta (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002  interactivetools.com, inc.&lt;br /&gt;
&lt;br /&gt;
License: htmlArea License (based on BSD license)&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==HTML Purifier==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/htmlpurifier&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Filters HTML.&lt;br /&gt;
&lt;br /&gt;
Version: 4.8.0&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
==IP-Atlas==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/ipatlas&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP scripts to show the location of an IP address on a map.&lt;br /&gt;
&lt;br /&gt;
Version: 1.0 (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002   Ivan Kozik&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.xpenguin.com/ip-atlas.php&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==jQuery==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/jquery&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
jQuery is a fast, small, and feature-rich JavaScript library widely used on moodle.&lt;br /&gt;
&lt;br /&gt;
Version: 1.12.3&lt;br /&gt;
&lt;br /&gt;
Copyright: 2016 The jQuery Foundation&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://jquery.com&lt;br /&gt;
&lt;br /&gt;
==jQuery migrate==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/jquery/jquery-migrate-1.4.0.js&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library used migrate older jQuery code to jQuery 3.0.&lt;br /&gt;
&lt;br /&gt;
Version: 1.4.0&lt;br /&gt;
&lt;br /&gt;
Copyright: 2016 The jQuery Foundation and other contributors&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/jquery/jquery-migrate&lt;br /&gt;
&lt;br /&gt;
==jQuery UI==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/jquery/ui-1.12.1/&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
jQuery UI is a set of user interface interactions, effects, widgets, and themes built on top of the jQuery library.&lt;br /&gt;
&lt;br /&gt;
Version: 1.12.1&lt;br /&gt;
&lt;br /&gt;
Copyright: 2016 The jQuery Foundation and other contributors&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/jquery/jquery-migrate&lt;br /&gt;
&lt;br /&gt;
==Services_JSON==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/json&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Allows PHP-&amp;gt;JS communication via JSON&lt;br /&gt;
&lt;br /&gt;
Version: 1.3.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005 Michal Migurski&lt;br /&gt;
&lt;br /&gt;
License: Modified BSD (GPL-compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/pepr/pepr-proposal-show.php?id=198&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==kses==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/kses.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
HTML/XHTML filter that only allows some elements and attributes&lt;br /&gt;
&lt;br /&gt;
Version: 0.2.2&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002, 2003, 2005   Ulf Harnhammar&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://sourceforge.net/projects/kses&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==less.php==&lt;br /&gt;
&lt;br /&gt;
The less.php is a PHP port of the official LESS processor used by moodle themes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/lessphp&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Version: 1.7.0.10&lt;br /&gt;
&lt;br /&gt;
License: Apache 2.0&lt;br /&gt;
&lt;br /&gt;
http://lessphp.typesettercms.com/&lt;br /&gt;
&lt;br /&gt;
Copyright:  Matt Agar and Martin Jantošovič&lt;br /&gt;
==loglevel.js==&lt;br /&gt;
&lt;br /&gt;
Minimal lightweight simple logging for JavaScript.&lt;br /&gt;
&lt;br /&gt;
Version 1.4.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2013 Tim Perry&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/pimterry/loglevel/&lt;br /&gt;
==MathJax==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Not actually included in Moodle. Moodle instead has a setting where the mathjax library is located. It is currently pointing to CDN by default.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
JavaScript filter library for displaying LaTeX, AsciiMath notation, and MathML.&lt;br /&gt;
&lt;br /&gt;
Version 2.7&lt;br /&gt;
&lt;br /&gt;
© Copyright 2015 The MathJax Consortium.&lt;br /&gt;
&lt;br /&gt;
License: Apache V2.0&lt;br /&gt;
&lt;br /&gt;
https://github.com/mathjax/MathJax&lt;br /&gt;
&lt;br /&gt;
==MatthiasMullie\Minify==&lt;br /&gt;
CSS &amp;amp; JavaScript minifier, in PHP&lt;br /&gt;
&lt;br /&gt;
Version 1.3.37&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/matthiasmullie/minify&lt;br /&gt;
&lt;br /&gt;
==mimeTeX==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;filter/tex&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Compiled C program to convert TeX into GIFs&lt;br /&gt;
&lt;br /&gt;
Version: 1.4&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002-2004   John Forkosh Associates, Inc&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.forkosh.com/mimetex.html&lt;br /&gt;
&lt;br /&gt;
==Mustache.js==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/amd/src/mustache.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
JS library for displaying mustache templates.&lt;br /&gt;
&lt;br /&gt;
Version: 2.2.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2009 Chris Wanstrath (Ruby)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2014 Jan Lehnardt (JavaScript)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2015 The mustache.js community&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/janl/mustache.js/releases&lt;br /&gt;
&lt;br /&gt;
==Mustache==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/mustache&amp;quot;&lt;br /&gt;
&lt;br /&gt;
PHP library for displaying mustache templates.&lt;br /&gt;
&lt;br /&gt;
Version: 2.11.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2016 Justin Hileman&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/bobthecow/mustache.php/releases&lt;br /&gt;
&lt;br /&gt;
==mp3player==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/mp3player&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Flash movie to play streaming MP3s&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005   Andrew Walker&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==overlibmws==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/overlib.js&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Javascript library to enable DHTML popups, floating windows, events etc&lt;br /&gt;
&lt;br /&gt;
Version: July 2004&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002-2004   Foteos Macrides&lt;br /&gt;
&lt;br /&gt;
Copyright © 1998-2004   Erik Bosrup&lt;br /&gt;
&lt;br /&gt;
License: Artistic Open Source License&lt;br /&gt;
&lt;br /&gt;
http://www.macridesweb.com/oltest/&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PclZip==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pclzip&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to create, manage and unpack zip files.&lt;br /&gt;
&lt;br /&gt;
Version: 2.4 RC1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Vincent Blavet (&#039;&#039;vincent AT phpconcept DOT net&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.phpconcept.net&lt;br /&gt;
&lt;br /&gt;
==PEAR OLE Classes==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to write Excel files&lt;br /&gt;
&lt;br /&gt;
Version: 0.5&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Xavier Noguer&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/OLE&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PEAR Spreadsheet_Excel_Writer==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to write Excel files&lt;br /&gt;
&lt;br /&gt;
Version: 0.9.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Xavier Noguer and Mika Tuupola&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/Spreadsheet_Excel_Writer&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_Quickform==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to write forms&lt;br /&gt;
&lt;br /&gt;
Version: 3.2.6&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Bertrand Mansion, Adam Daniel, Alexey Borzov&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_Quickform&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_Quickform_Renderer_Tableless==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to render forms without tables&lt;br /&gt;
&lt;br /&gt;
Version: 0.3.4&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005 Mark Wiesemann&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_Quickform_Renderer_Tableless&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_QuickForm_DHTMLRulesTableless==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to render validation notices with dhtml&lt;br /&gt;
&lt;br /&gt;
Version: 0.1.2&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005 Alexey Borzov, Adam Daniel, Bertrand Mansion, Justin Patrin, Mark Wiesemann&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_QuickForm_DHTMLRulesTableless&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_Common==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class with many common HTML functions (used by HTML Quickform)&lt;br /&gt;
&lt;br /&gt;
Version: 0.3.4&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Adam Daniel, Bertrand Mansion, Klaus Guenther, Alexey Borzov&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_Common&lt;br /&gt;
&lt;br /&gt;
==PEAR XML_Parser==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class implementing one handy (sax-expat) XML parser&lt;br /&gt;
&lt;br /&gt;
Version: 1.3.2&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004-2008 The PHP Group &amp;amp; Stephan Schmidt&lt;br /&gt;
&lt;br /&gt;
License: New BSD License&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/XML_Parser&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PHP-CSS-Parser==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/php-css-parser&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A Parser for CSS Files written in PHP.&lt;br /&gt;
&lt;br /&gt;
Version: 8.1.0&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2011 Raphael Schweikert, http://sabberworm.com/&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/sabberworm/PHP-CSS-Parser&lt;br /&gt;
&lt;br /&gt;
==PHPExcel==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/phpexcel/PHPExcel.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library to read, write and create spreadsheet documents in PHP.&lt;br /&gt;
&lt;br /&gt;
Version 1.8.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2006 - 2015 PHPExcel&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
https://github.com/PHPOffice/PHPExcel&lt;br /&gt;
&lt;br /&gt;
==PHP mailer==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/class.phpmailer.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class for sending email using either sendmail, PHP mail(), or SMTP.  Methods are based upon the standard AspEmail(tm) classes.&lt;br /&gt;
&lt;br /&gt;
Version 5.2.16&lt;br /&gt;
&lt;br /&gt;
Copyright © 2003 Brent R. Matzelle (&#039;&#039;bmatzelle AT yahoo DOT com&#039;&#039;)&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://phpmailer.sourceforge.net&lt;br /&gt;
https://github.com/PHPMailer/PHPMailer/releases&lt;br /&gt;
&lt;br /&gt;
==PHP Markdown==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/markdown.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Functions to convert from the Markdown text format into clean XHTML.&lt;br /&gt;
&lt;br /&gt;
Version: 1.7.0 (with modifications)&lt;br /&gt;
&lt;br /&gt;
 * @copyright 2004-2016 Michel Fortin &amp;lt;https://michelf.com/projects/php-markdown/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 * @copyright (Original Markdown) 2004-2006 John Gruber &amp;lt;https://daringfireball.net/projects/markdown/&amp;gt;&lt;br /&gt;
All rights reserved.&lt;br /&gt;
&lt;br /&gt;
License: BSD&lt;br /&gt;
&lt;br /&gt;
http://www.michelf.com/projects/php-markdown/&lt;br /&gt;
&lt;br /&gt;
==RequireJS==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;/lib/requirejs/&#039;&#039;	&lt;br /&gt;
&lt;br /&gt;
RequireJS is a JavaScript file and module loader.&lt;br /&gt;
&lt;br /&gt;
Version 2.3.2&lt;br /&gt;
&lt;br /&gt;
License: new BSD or MIT&lt;br /&gt;
&lt;br /&gt;
http://requirejs.org/&lt;br /&gt;
&lt;br /&gt;
==scssphp==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;/lib/scssphp/&#039;&#039;	&lt;br /&gt;
&lt;br /&gt;
scssphp is a compiler for SCSS written in PHP.&lt;br /&gt;
&lt;br /&gt;
Version: 0.6.5&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2015 Leaf Corcoran&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
http://leafo.github.io/scssphp&lt;br /&gt;
&lt;br /&gt;
==SimplePie==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/lib/simplepie&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Simple Pie helps with blogs.&lt;br /&gt;
&lt;br /&gt;
Version 1.4.2&lt;br /&gt;
&lt;br /&gt;
License: BSD&lt;br /&gt;
&lt;br /&gt;
https://github.com/simplepie/simplepie&lt;br /&gt;
&lt;br /&gt;
==Snoopy==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/snoopy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A PHP net client&lt;br /&gt;
&lt;br /&gt;
Version: 1.0&lt;br /&gt;
&lt;br /&gt;
Copyright © 1999-2000 Monte Ohrt (&#039;&#039;monte AT ispi DOT net&#039;&#039;)&lt;br /&gt;
License: GNU LGPL&lt;br /&gt;
&lt;br /&gt;
http://snoopy.sourceforge.com&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==SMTP class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/class.smtp.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class that can be used to connect and communicate with any SMTP server. It implements all the SMTP functions defined in RFC821 except TURN.&lt;br /&gt;
&lt;br /&gt;
Version: 03/26/2001&lt;br /&gt;
&lt;br /&gt;
Copyright © 2001  Chris Ryan (&#039;&#039;chris AT greatbridge DOT com&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==Spike PHPCoverage==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/spikephpcoverage&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP code coverage reporting tool&lt;br /&gt;
&lt;br /&gt;
Version: 0.8.2 (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004 SpikeSource Inc&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://developer.spikesource.com/projects/phpcoverage&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==Spout==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/spout&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Library for importing and exporting csv / excel / ODS files.&lt;br /&gt;
&lt;br /&gt;
Version 2.7.3&lt;br /&gt;
&lt;br /&gt;
License: Apache&lt;br /&gt;
&lt;br /&gt;
https://github.com/box/spout/&lt;br /&gt;
&lt;br /&gt;
==Typo3 Character Set Class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/typo3&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class for conversion between charsets and multibyte-savy operations with strings.&lt;br /&gt;
&lt;br /&gt;
Version: 4.7.19&lt;br /&gt;
&lt;br /&gt;
Copyright © 2003-2005 Kasper Skaarhoj&lt;br /&gt;
&lt;br /&gt;
Licence: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://typo3.org/&lt;br /&gt;
&lt;br /&gt;
==Yahoo User Interface==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/yui&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The Yahoo! User Interface Library is a set of utilities and controls, in JavaScript, for building richly interactive web applications using techniques such as DOM scripting, DHTML and AJAX. The YUI Library also includes several core CSS resources.Set of user-interface components using AJAX, DHTML etc.  We use it for all our AJAX-related stuff.&lt;br /&gt;
&lt;br /&gt;
CVS version: 2.3.0&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2006, Yahoo! Inc.&lt;br /&gt;
&lt;br /&gt;
Licence: BSD&lt;br /&gt;
&lt;br /&gt;
http://developer.yahoo.com/yui/&lt;br /&gt;
&lt;br /&gt;
==Mustache.js==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/amd/src/mustache.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
JS library for displaying mustache templates.&lt;br /&gt;
&lt;br /&gt;
Version: 2.2.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2009 Chris Wanstrath (Ruby)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2014 Jan Lehnardt (JavaScript)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2015 The mustache.js community&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/janl/mustache.js/releases&lt;br /&gt;
&lt;br /&gt;
==LTI Tool Provider Library for PHP==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/ltiprovider/&amp;quot;&lt;br /&gt;
&lt;br /&gt;
PHP library for communicating with learning tools as per the LTI specification.&lt;br /&gt;
&lt;br /&gt;
Version: 3.0.2&lt;br /&gt;
&lt;br /&gt;
© 2016 IMS Global Learning Consortium Inc. All Rights Reserved. Trademark Policy - (www.imsglobal.org/trademarks)&lt;br /&gt;
&lt;br /&gt;
License: Apache 2&lt;br /&gt;
&lt;br /&gt;
https://github.com/IMSGlobal/LTI-Tool-Provider-Library-PHP&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Popper.js==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;admin/tool/usertours/amd/src/popper.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
A kickass library used to created Poppers in web applications&lt;br /&gt;
&lt;br /&gt;
© 2016 Federico Zivolo and contributors&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/FezVrasta/popper.js&lt;br /&gt;
&lt;br /&gt;
==Flexitour==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;admin/tool/usertours/amd/src/tour.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
A JS library for tours&lt;br /&gt;
&lt;br /&gt;
© 2016 Andrew Nicols and contributors&lt;br /&gt;
&lt;br /&gt;
License: GPLv3&lt;br /&gt;
&lt;br /&gt;
https://github.com/andrewnicols/flexitour&lt;br /&gt;
&lt;br /&gt;
[[Category:Credits]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_libraries_credits&amp;diff=53036</id>
		<title>Moodle libraries credits</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_libraries_credits&amp;diff=53036"/>
		<updated>2017-10-16T05:32:58Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* Spout */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Some of Moodle&#039;s libraries were written by other people, and are being redistributed as part of Moodle under their respective open source licenses that thankfully allow us to do so. Thanks to the authors of all these excellent products - without them Moodle would be missing important functionality. Copyright information for each package is included below:&lt;br /&gt;
&lt;br /&gt;
==ADOdb==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/adodb&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Database abstraction library for MySQL, PostgreSQL, MSSQL, Oracle, Interbase, Foxpro, Access, ADO, Sybase, DB2 and ODBC.&lt;br /&gt;
&lt;br /&gt;
Version: 5.20.9&lt;br /&gt;
&lt;br /&gt;
@copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.&lt;br /&gt;
&lt;br /&gt;
@copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community&lt;br /&gt;
&lt;br /&gt;
License: Dual LGPL and BSD-style&lt;br /&gt;
&lt;br /&gt;
http://adodb.sourceforge.net&lt;br /&gt;
&lt;br /&gt;
==Amazon S3==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;repository/s3/S3.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A standalone Amazon S3 (REST) client for PHP 5.2.x using CURL that does not require PEAR. &lt;br /&gt;
&lt;br /&gt;
Version: 0.5.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2013, Donovan Schönknecht&lt;br /&gt;
&lt;br /&gt;
License: BSD 2-Clause&lt;br /&gt;
&lt;br /&gt;
https://github.com/tpyo/amazon-s3-php-class/releases&lt;br /&gt;
&lt;br /&gt;
==CAS==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;auth/cas/CAS&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
phpCAS library to support CAS authentication plugin&lt;br /&gt;
&lt;br /&gt;
Copyright Jasig&lt;br /&gt;
&lt;br /&gt;
License: Apache License 2.0&lt;br /&gt;
&lt;br /&gt;
https://wiki.jasig.org/display/CASC/phpCAS&lt;br /&gt;
&lt;br /&gt;
==Chart.js==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/amd/src/chartjs-lazy.js&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Simple yet flexible JavaScript charting for designers &amp;amp; developers&lt;br /&gt;
&lt;br /&gt;
Version: 2.2.2&lt;br /&gt;
&lt;br /&gt;
Copyright 2016 Nick Downie&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
http://www.chartjs.org&lt;br /&gt;
&lt;br /&gt;
==EvalMath==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/evalmath&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to safely evaluate math expressions&lt;br /&gt;
&lt;br /&gt;
Copyright Miles Kaufmann&lt;br /&gt;
&lt;br /&gt;
License: BSD&lt;br /&gt;
&lt;br /&gt;
http://www.twmagic.com/&lt;br /&gt;
&lt;br /&gt;
==FLV player==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;filter/mediaplugin/flvplayer.swf&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Flash movie to play FLV files&lt;br /&gt;
&lt;br /&gt;
Copyright Jeroen Wijering &lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.jeroenwijering.com&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==FPDF Class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/fpdf&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to generate PDF files&lt;br /&gt;
&lt;br /&gt;
Version: 1.54&lt;br /&gt;
&lt;br /&gt;
Copyright Olivier PLATHEY&lt;br /&gt;
&lt;br /&gt;
License: Freeware&lt;br /&gt;
&lt;br /&gt;
http://www.setasign.com/products/fpdi/downloads&lt;br /&gt;
&lt;br /&gt;
== GeoIp2 ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/maxmind/GeoIp2&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library for precessing of GeoIP data files&lt;br /&gt;
&lt;br /&gt;
Version: 2.6.0&lt;br /&gt;
&lt;br /&gt;
Copyright MaxMind&lt;br /&gt;
&lt;br /&gt;
License: Apache 2.0&lt;br /&gt;
&lt;br /&gt;
https://github.com/maxmind/GeoIP2-php&lt;br /&gt;
&lt;br /&gt;
==Google APIs==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/google&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Library Google APIs Client Library for PHP&lt;br /&gt;
&lt;br /&gt;
Version: 1.1.7&lt;br /&gt;
&lt;br /&gt;
License: Apache License Version 2.0&lt;br /&gt;
&lt;br /&gt;
https://github.com/google/google-api-php-client&lt;br /&gt;
&lt;br /&gt;
==Graph Class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/graphlib.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to draw line, point, bar, and area graphs, including numeric x-axis and double y-axis.&lt;br /&gt;
&lt;br /&gt;
Version: 1.6.3 (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2000  Herman Veluwenkamp (&#039;&#039;hermanV AT mindless DOT com&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
==Horde==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/horde&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library used by the inbound e-mail handling system.&lt;br /&gt;
&lt;br /&gt;
Version: 5.2.7&lt;br /&gt;
&lt;br /&gt;
Copyright © Horde LLC&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://www.horde.org/&lt;br /&gt;
&lt;br /&gt;
==html2text==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/html2text&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP script to convert HTML into an approximate text equivalent&lt;br /&gt;
&lt;br /&gt;
Version: 4.0.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005-7 Jon Abernathy&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
https://github.com/mtibben/html2text.git&lt;br /&gt;
&lt;br /&gt;
==htmlArea==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/editor&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Javascript/HTML script to put a GUI editor in textareas on Internet Explorer and Mozilla&lt;br /&gt;
&lt;br /&gt;
Version: 3.0 beta (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002  interactivetools.com, inc.&lt;br /&gt;
&lt;br /&gt;
License: htmlArea License (based on BSD license)&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==HTML Purifier==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/htmlpurifier&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Filters HTML.&lt;br /&gt;
&lt;br /&gt;
Version: 4.8.0&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
==IP-Atlas==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/ipatlas&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP scripts to show the location of an IP address on a map.&lt;br /&gt;
&lt;br /&gt;
Version: 1.0 (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002   Ivan Kozik&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.xpenguin.com/ip-atlas.php&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==jQuery==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/jquery&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
jQuery is a fast, small, and feature-rich JavaScript library widely used on moodle.&lt;br /&gt;
&lt;br /&gt;
Version: 1.12.3&lt;br /&gt;
&lt;br /&gt;
Copyright: 2016 The jQuery Foundation&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://jquery.com&lt;br /&gt;
&lt;br /&gt;
==jQuery migrate==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/jquery/jquery-migrate-1.4.0.js&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library used migrate older jQuery code to jQuery 3.0.&lt;br /&gt;
&lt;br /&gt;
Version: 1.4.0&lt;br /&gt;
&lt;br /&gt;
Copyright: 2016 The jQuery Foundation and other contributors&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/jquery/jquery-migrate&lt;br /&gt;
&lt;br /&gt;
==jQuery UI==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/jquery/ui-1.12.1/&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
jQuery UI is a set of user interface interactions, effects, widgets, and themes built on top of the jQuery library.&lt;br /&gt;
&lt;br /&gt;
Version: 1.12.1&lt;br /&gt;
&lt;br /&gt;
Copyright: 2016 The jQuery Foundation and other contributors&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/jquery/jquery-migrate&lt;br /&gt;
&lt;br /&gt;
==Services_JSON==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/json&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Allows PHP-&amp;gt;JS communication via JSON&lt;br /&gt;
&lt;br /&gt;
Version: 1.3.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005 Michal Migurski&lt;br /&gt;
&lt;br /&gt;
License: Modified BSD (GPL-compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/pepr/pepr-proposal-show.php?id=198&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==kses==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/kses.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
HTML/XHTML filter that only allows some elements and attributes&lt;br /&gt;
&lt;br /&gt;
Version: 0.2.2&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002, 2003, 2005   Ulf Harnhammar&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://sourceforge.net/projects/kses&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==less.php==&lt;br /&gt;
&lt;br /&gt;
The less.php is a PHP port of the official LESS processor used by moodle themes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/lessphp&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Version: 1.7.0.10&lt;br /&gt;
&lt;br /&gt;
License: Apache 2.0&lt;br /&gt;
&lt;br /&gt;
http://lessphp.typesettercms.com/&lt;br /&gt;
&lt;br /&gt;
Copyright:  Matt Agar and Martin Jantošovič&lt;br /&gt;
==loglevel.js==&lt;br /&gt;
&lt;br /&gt;
Minimal lightweight simple logging for JavaScript.&lt;br /&gt;
&lt;br /&gt;
Version 1.4.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2013 Tim Perry&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/pimterry/loglevel/&lt;br /&gt;
==MathJax==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Not actually included in Moodle. Moodle instead has a setting where the mathjax library is located. It is currently pointing to CDN by default.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
JavaScript filter library for displaying LaTeX, AsciiMath notation, and MathML.&lt;br /&gt;
&lt;br /&gt;
Version 2.7&lt;br /&gt;
&lt;br /&gt;
© Copyright 2015 The MathJax Consortium.&lt;br /&gt;
&lt;br /&gt;
License: Apache V2.0&lt;br /&gt;
&lt;br /&gt;
https://github.com/mathjax/MathJax&lt;br /&gt;
&lt;br /&gt;
==MatthiasMullie\Minify==&lt;br /&gt;
CSS &amp;amp; JavaScript minifier, in PHP&lt;br /&gt;
&lt;br /&gt;
Version 1.3.37&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/matthiasmullie/minify&lt;br /&gt;
&lt;br /&gt;
==mimeTeX==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;filter/tex&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Compiled C program to convert TeX into GIFs&lt;br /&gt;
&lt;br /&gt;
Version: 1.4&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002-2004   John Forkosh Associates, Inc&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.forkosh.com/mimetex.html&lt;br /&gt;
&lt;br /&gt;
==Mustache.js==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/amd/src/mustache.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
JS library for displaying mustache templates.&lt;br /&gt;
&lt;br /&gt;
Version: 2.2.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2009 Chris Wanstrath (Ruby)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2014 Jan Lehnardt (JavaScript)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2015 The mustache.js community&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/janl/mustache.js/releases&lt;br /&gt;
&lt;br /&gt;
==Mustache==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/mustache&amp;quot;&lt;br /&gt;
&lt;br /&gt;
PHP library for displaying mustache templates.&lt;br /&gt;
&lt;br /&gt;
Version: 2.11.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2016 Justin Hileman&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/bobthecow/mustache.php/releases&lt;br /&gt;
&lt;br /&gt;
==mp3player==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/mp3player&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Flash movie to play streaming MP3s&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005   Andrew Walker&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==overlibmws==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/overlib.js&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Javascript library to enable DHTML popups, floating windows, events etc&lt;br /&gt;
&lt;br /&gt;
Version: July 2004&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002-2004   Foteos Macrides&lt;br /&gt;
&lt;br /&gt;
Copyright © 1998-2004   Erik Bosrup&lt;br /&gt;
&lt;br /&gt;
License: Artistic Open Source License&lt;br /&gt;
&lt;br /&gt;
http://www.macridesweb.com/oltest/&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PclZip==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pclzip&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to create, manage and unpack zip files.&lt;br /&gt;
&lt;br /&gt;
Version: 2.4 RC1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Vincent Blavet (&#039;&#039;vincent AT phpconcept DOT net&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.phpconcept.net&lt;br /&gt;
&lt;br /&gt;
==PEAR OLE Classes==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to write Excel files&lt;br /&gt;
&lt;br /&gt;
Version: 0.5&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Xavier Noguer&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/OLE&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PEAR Spreadsheet_Excel_Writer==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to write Excel files&lt;br /&gt;
&lt;br /&gt;
Version: 0.9.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Xavier Noguer and Mika Tuupola&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/Spreadsheet_Excel_Writer&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_Quickform==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to write forms&lt;br /&gt;
&lt;br /&gt;
Version: 3.2.6&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Bertrand Mansion, Adam Daniel, Alexey Borzov&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_Quickform&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_Quickform_Renderer_Tableless==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to render forms without tables&lt;br /&gt;
&lt;br /&gt;
Version: 0.3.4&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005 Mark Wiesemann&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_Quickform_Renderer_Tableless&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_QuickForm_DHTMLRulesTableless==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to render validation notices with dhtml&lt;br /&gt;
&lt;br /&gt;
Version: 0.1.2&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005 Alexey Borzov, Adam Daniel, Bertrand Mansion, Justin Patrin, Mark Wiesemann&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_QuickForm_DHTMLRulesTableless&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_Common==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class with many common HTML functions (used by HTML Quickform)&lt;br /&gt;
&lt;br /&gt;
Version: 0.3.4&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Adam Daniel, Bertrand Mansion, Klaus Guenther, Alexey Borzov&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_Common&lt;br /&gt;
&lt;br /&gt;
==PEAR XML_Parser==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class implementing one handy (sax-expat) XML parser&lt;br /&gt;
&lt;br /&gt;
Version: 1.3.2&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004-2008 The PHP Group &amp;amp; Stephan Schmidt&lt;br /&gt;
&lt;br /&gt;
License: New BSD License&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/XML_Parser&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PHP-CSS-Parser==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/php-css-parser&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A Parser for CSS Files written in PHP.&lt;br /&gt;
&lt;br /&gt;
Version: 8.1.0&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2011 Raphael Schweikert, http://sabberworm.com/&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/sabberworm/PHP-CSS-Parser&lt;br /&gt;
&lt;br /&gt;
==PHPExcel==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/phpexcel/PHPExcel.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library to read, write and create spreadsheet documents in PHP.&lt;br /&gt;
&lt;br /&gt;
Version 1.8.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2006 - 2015 PHPExcel&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
https://github.com/PHPOffice/PHPExcel&lt;br /&gt;
&lt;br /&gt;
==PHP mailer==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/class.phpmailer.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class for sending email using either sendmail, PHP mail(), or SMTP.  Methods are based upon the standard AspEmail(tm) classes.&lt;br /&gt;
&lt;br /&gt;
Version 5.2.16&lt;br /&gt;
&lt;br /&gt;
Copyright © 2003 Brent R. Matzelle (&#039;&#039;bmatzelle AT yahoo DOT com&#039;&#039;)&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://phpmailer.sourceforge.net&lt;br /&gt;
https://github.com/PHPMailer/PHPMailer/releases&lt;br /&gt;
&lt;br /&gt;
==PHP Markdown==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/markdown.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Functions to convert from the Markdown text format into clean XHTML.&lt;br /&gt;
&lt;br /&gt;
Version: 1.6.0 (with modifications)&lt;br /&gt;
&lt;br /&gt;
PHP Markdown Lib Copyright © 2004-2015 Michel Fortin https://michelf.ca/&lt;br /&gt;
All rights reserved.&lt;br /&gt;
&lt;br /&gt;
Based on Markdown&lt;br /&gt;
Copyright © 2003-2005 John Gruber https://daringfireball.net/&lt;br /&gt;
All rights reserved.&lt;br /&gt;
&lt;br /&gt;
License: BSD&lt;br /&gt;
&lt;br /&gt;
http://www.michelf.com/projects/php-markdown/&lt;br /&gt;
&lt;br /&gt;
==RequireJS==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;/lib/requirejs/&#039;&#039;	&lt;br /&gt;
&lt;br /&gt;
RequireJS is a JavaScript file and module loader.&lt;br /&gt;
&lt;br /&gt;
Version 2.3.2&lt;br /&gt;
&lt;br /&gt;
License: new BSD or MIT&lt;br /&gt;
&lt;br /&gt;
http://requirejs.org/&lt;br /&gt;
&lt;br /&gt;
==scssphp==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;/lib/scssphp/&#039;&#039;	&lt;br /&gt;
&lt;br /&gt;
scssphp is a compiler for SCSS written in PHP.&lt;br /&gt;
&lt;br /&gt;
Version: 0.6.5&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2015 Leaf Corcoran&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
http://leafo.github.io/scssphp&lt;br /&gt;
&lt;br /&gt;
==SimplePie==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/lib/simplepie&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Simple Pie helps with blogs.&lt;br /&gt;
&lt;br /&gt;
Version 1.4.2&lt;br /&gt;
&lt;br /&gt;
License: BSD&lt;br /&gt;
&lt;br /&gt;
https://github.com/simplepie/simplepie&lt;br /&gt;
&lt;br /&gt;
==Snoopy==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/snoopy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A PHP net client&lt;br /&gt;
&lt;br /&gt;
Version: 1.0&lt;br /&gt;
&lt;br /&gt;
Copyright © 1999-2000 Monte Ohrt (&#039;&#039;monte AT ispi DOT net&#039;&#039;)&lt;br /&gt;
License: GNU LGPL&lt;br /&gt;
&lt;br /&gt;
http://snoopy.sourceforge.com&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==SMTP class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/class.smtp.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class that can be used to connect and communicate with any SMTP server. It implements all the SMTP functions defined in RFC821 except TURN.&lt;br /&gt;
&lt;br /&gt;
Version: 03/26/2001&lt;br /&gt;
&lt;br /&gt;
Copyright © 2001  Chris Ryan (&#039;&#039;chris AT greatbridge DOT com&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==Spike PHPCoverage==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/spikephpcoverage&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP code coverage reporting tool&lt;br /&gt;
&lt;br /&gt;
Version: 0.8.2 (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004 SpikeSource Inc&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://developer.spikesource.com/projects/phpcoverage&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==Spout==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/spout&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Library for importing and exporting csv / excel / ODS files.&lt;br /&gt;
&lt;br /&gt;
Version 2.7.3&lt;br /&gt;
&lt;br /&gt;
License: Apache&lt;br /&gt;
&lt;br /&gt;
https://github.com/box/spout/&lt;br /&gt;
&lt;br /&gt;
==Typo3 Character Set Class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/typo3&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class for conversion between charsets and multibyte-savy operations with strings.&lt;br /&gt;
&lt;br /&gt;
Version: 4.7.19&lt;br /&gt;
&lt;br /&gt;
Copyright © 2003-2005 Kasper Skaarhoj&lt;br /&gt;
&lt;br /&gt;
Licence: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://typo3.org/&lt;br /&gt;
&lt;br /&gt;
==Yahoo User Interface==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/yui&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The Yahoo! User Interface Library is a set of utilities and controls, in JavaScript, for building richly interactive web applications using techniques such as DOM scripting, DHTML and AJAX. The YUI Library also includes several core CSS resources.Set of user-interface components using AJAX, DHTML etc.  We use it for all our AJAX-related stuff.&lt;br /&gt;
&lt;br /&gt;
CVS version: 2.3.0&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2006, Yahoo! Inc.&lt;br /&gt;
&lt;br /&gt;
Licence: BSD&lt;br /&gt;
&lt;br /&gt;
http://developer.yahoo.com/yui/&lt;br /&gt;
&lt;br /&gt;
==Mustache.js==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/amd/src/mustache.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
JS library for displaying mustache templates.&lt;br /&gt;
&lt;br /&gt;
Version: 2.2.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2009 Chris Wanstrath (Ruby)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2014 Jan Lehnardt (JavaScript)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2015 The mustache.js community&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/janl/mustache.js/releases&lt;br /&gt;
&lt;br /&gt;
==LTI Tool Provider Library for PHP==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/ltiprovider/&amp;quot;&lt;br /&gt;
&lt;br /&gt;
PHP library for communicating with learning tools as per the LTI specification.&lt;br /&gt;
&lt;br /&gt;
Version: 3.0.2&lt;br /&gt;
&lt;br /&gt;
© 2016 IMS Global Learning Consortium Inc. All Rights Reserved. Trademark Policy - (www.imsglobal.org/trademarks)&lt;br /&gt;
&lt;br /&gt;
License: Apache 2&lt;br /&gt;
&lt;br /&gt;
https://github.com/IMSGlobal/LTI-Tool-Provider-Library-PHP&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Popper.js==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;admin/tool/usertours/amd/src/popper.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
A kickass library used to created Poppers in web applications&lt;br /&gt;
&lt;br /&gt;
© 2016 Federico Zivolo and contributors&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/FezVrasta/popper.js&lt;br /&gt;
&lt;br /&gt;
==Flexitour==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;admin/tool/usertours/amd/src/tour.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
A JS library for tours&lt;br /&gt;
&lt;br /&gt;
© 2016 Andrew Nicols and contributors&lt;br /&gt;
&lt;br /&gt;
License: GPLv3&lt;br /&gt;
&lt;br /&gt;
https://github.com/andrewnicols/flexitour&lt;br /&gt;
&lt;br /&gt;
[[Category:Credits]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_libraries_credits&amp;diff=53035</id>
		<title>Moodle libraries credits</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_libraries_credits&amp;diff=53035"/>
		<updated>2017-10-16T05:31:30Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* GeoIp2 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Some of Moodle&#039;s libraries were written by other people, and are being redistributed as part of Moodle under their respective open source licenses that thankfully allow us to do so. Thanks to the authors of all these excellent products - without them Moodle would be missing important functionality. Copyright information for each package is included below:&lt;br /&gt;
&lt;br /&gt;
==ADOdb==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/adodb&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Database abstraction library for MySQL, PostgreSQL, MSSQL, Oracle, Interbase, Foxpro, Access, ADO, Sybase, DB2 and ODBC.&lt;br /&gt;
&lt;br /&gt;
Version: 5.20.9&lt;br /&gt;
&lt;br /&gt;
@copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.&lt;br /&gt;
&lt;br /&gt;
@copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community&lt;br /&gt;
&lt;br /&gt;
License: Dual LGPL and BSD-style&lt;br /&gt;
&lt;br /&gt;
http://adodb.sourceforge.net&lt;br /&gt;
&lt;br /&gt;
==Amazon S3==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;repository/s3/S3.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A standalone Amazon S3 (REST) client for PHP 5.2.x using CURL that does not require PEAR. &lt;br /&gt;
&lt;br /&gt;
Version: 0.5.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2013, Donovan Schönknecht&lt;br /&gt;
&lt;br /&gt;
License: BSD 2-Clause&lt;br /&gt;
&lt;br /&gt;
https://github.com/tpyo/amazon-s3-php-class/releases&lt;br /&gt;
&lt;br /&gt;
==CAS==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;auth/cas/CAS&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
phpCAS library to support CAS authentication plugin&lt;br /&gt;
&lt;br /&gt;
Copyright Jasig&lt;br /&gt;
&lt;br /&gt;
License: Apache License 2.0&lt;br /&gt;
&lt;br /&gt;
https://wiki.jasig.org/display/CASC/phpCAS&lt;br /&gt;
&lt;br /&gt;
==Chart.js==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/amd/src/chartjs-lazy.js&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Simple yet flexible JavaScript charting for designers &amp;amp; developers&lt;br /&gt;
&lt;br /&gt;
Version: 2.2.2&lt;br /&gt;
&lt;br /&gt;
Copyright 2016 Nick Downie&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
http://www.chartjs.org&lt;br /&gt;
&lt;br /&gt;
==EvalMath==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/evalmath&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to safely evaluate math expressions&lt;br /&gt;
&lt;br /&gt;
Copyright Miles Kaufmann&lt;br /&gt;
&lt;br /&gt;
License: BSD&lt;br /&gt;
&lt;br /&gt;
http://www.twmagic.com/&lt;br /&gt;
&lt;br /&gt;
==FLV player==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;filter/mediaplugin/flvplayer.swf&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Flash movie to play FLV files&lt;br /&gt;
&lt;br /&gt;
Copyright Jeroen Wijering &lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.jeroenwijering.com&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==FPDF Class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/fpdf&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to generate PDF files&lt;br /&gt;
&lt;br /&gt;
Version: 1.54&lt;br /&gt;
&lt;br /&gt;
Copyright Olivier PLATHEY&lt;br /&gt;
&lt;br /&gt;
License: Freeware&lt;br /&gt;
&lt;br /&gt;
http://www.setasign.com/products/fpdi/downloads&lt;br /&gt;
&lt;br /&gt;
== GeoIp2 ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/maxmind/GeoIp2&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library for precessing of GeoIP data files&lt;br /&gt;
&lt;br /&gt;
Version: 2.6.0&lt;br /&gt;
&lt;br /&gt;
Copyright MaxMind&lt;br /&gt;
&lt;br /&gt;
License: Apache 2.0&lt;br /&gt;
&lt;br /&gt;
https://github.com/maxmind/GeoIP2-php&lt;br /&gt;
&lt;br /&gt;
==Google APIs==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/google&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Library Google APIs Client Library for PHP&lt;br /&gt;
&lt;br /&gt;
Version: 1.1.7&lt;br /&gt;
&lt;br /&gt;
License: Apache License Version 2.0&lt;br /&gt;
&lt;br /&gt;
https://github.com/google/google-api-php-client&lt;br /&gt;
&lt;br /&gt;
==Graph Class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/graphlib.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to draw line, point, bar, and area graphs, including numeric x-axis and double y-axis.&lt;br /&gt;
&lt;br /&gt;
Version: 1.6.3 (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2000  Herman Veluwenkamp (&#039;&#039;hermanV AT mindless DOT com&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
==Horde==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/horde&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library used by the inbound e-mail handling system.&lt;br /&gt;
&lt;br /&gt;
Version: 5.2.7&lt;br /&gt;
&lt;br /&gt;
Copyright © Horde LLC&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://www.horde.org/&lt;br /&gt;
&lt;br /&gt;
==html2text==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/html2text&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP script to convert HTML into an approximate text equivalent&lt;br /&gt;
&lt;br /&gt;
Version: 4.0.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005-7 Jon Abernathy&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
https://github.com/mtibben/html2text.git&lt;br /&gt;
&lt;br /&gt;
==htmlArea==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/editor&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Javascript/HTML script to put a GUI editor in textareas on Internet Explorer and Mozilla&lt;br /&gt;
&lt;br /&gt;
Version: 3.0 beta (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002  interactivetools.com, inc.&lt;br /&gt;
&lt;br /&gt;
License: htmlArea License (based on BSD license)&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==HTML Purifier==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/htmlpurifier&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Filters HTML.&lt;br /&gt;
&lt;br /&gt;
Version: 4.8.0&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
==IP-Atlas==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/ipatlas&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP scripts to show the location of an IP address on a map.&lt;br /&gt;
&lt;br /&gt;
Version: 1.0 (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002   Ivan Kozik&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.xpenguin.com/ip-atlas.php&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==jQuery==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/jquery&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
jQuery is a fast, small, and feature-rich JavaScript library widely used on moodle.&lt;br /&gt;
&lt;br /&gt;
Version: 1.12.3&lt;br /&gt;
&lt;br /&gt;
Copyright: 2016 The jQuery Foundation&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://jquery.com&lt;br /&gt;
&lt;br /&gt;
==jQuery migrate==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/jquery/jquery-migrate-1.4.0.js&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library used migrate older jQuery code to jQuery 3.0.&lt;br /&gt;
&lt;br /&gt;
Version: 1.4.0&lt;br /&gt;
&lt;br /&gt;
Copyright: 2016 The jQuery Foundation and other contributors&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/jquery/jquery-migrate&lt;br /&gt;
&lt;br /&gt;
==jQuery UI==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/jquery/ui-1.12.1/&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
jQuery UI is a set of user interface interactions, effects, widgets, and themes built on top of the jQuery library.&lt;br /&gt;
&lt;br /&gt;
Version: 1.12.1&lt;br /&gt;
&lt;br /&gt;
Copyright: 2016 The jQuery Foundation and other contributors&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/jquery/jquery-migrate&lt;br /&gt;
&lt;br /&gt;
==Services_JSON==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/json&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Allows PHP-&amp;gt;JS communication via JSON&lt;br /&gt;
&lt;br /&gt;
Version: 1.3.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005 Michal Migurski&lt;br /&gt;
&lt;br /&gt;
License: Modified BSD (GPL-compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/pepr/pepr-proposal-show.php?id=198&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==kses==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/kses.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
HTML/XHTML filter that only allows some elements and attributes&lt;br /&gt;
&lt;br /&gt;
Version: 0.2.2&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002, 2003, 2005   Ulf Harnhammar&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://sourceforge.net/projects/kses&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==less.php==&lt;br /&gt;
&lt;br /&gt;
The less.php is a PHP port of the official LESS processor used by moodle themes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/lessphp&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Version: 1.7.0.10&lt;br /&gt;
&lt;br /&gt;
License: Apache 2.0&lt;br /&gt;
&lt;br /&gt;
http://lessphp.typesettercms.com/&lt;br /&gt;
&lt;br /&gt;
Copyright:  Matt Agar and Martin Jantošovič&lt;br /&gt;
==loglevel.js==&lt;br /&gt;
&lt;br /&gt;
Minimal lightweight simple logging for JavaScript.&lt;br /&gt;
&lt;br /&gt;
Version 1.4.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2013 Tim Perry&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/pimterry/loglevel/&lt;br /&gt;
==MathJax==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Not actually included in Moodle. Moodle instead has a setting where the mathjax library is located. It is currently pointing to CDN by default.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
JavaScript filter library for displaying LaTeX, AsciiMath notation, and MathML.&lt;br /&gt;
&lt;br /&gt;
Version 2.7&lt;br /&gt;
&lt;br /&gt;
© Copyright 2015 The MathJax Consortium.&lt;br /&gt;
&lt;br /&gt;
License: Apache V2.0&lt;br /&gt;
&lt;br /&gt;
https://github.com/mathjax/MathJax&lt;br /&gt;
&lt;br /&gt;
==MatthiasMullie\Minify==&lt;br /&gt;
CSS &amp;amp; JavaScript minifier, in PHP&lt;br /&gt;
&lt;br /&gt;
Version 1.3.37&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/matthiasmullie/minify&lt;br /&gt;
&lt;br /&gt;
==mimeTeX==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;filter/tex&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Compiled C program to convert TeX into GIFs&lt;br /&gt;
&lt;br /&gt;
Version: 1.4&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002-2004   John Forkosh Associates, Inc&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.forkosh.com/mimetex.html&lt;br /&gt;
&lt;br /&gt;
==Mustache.js==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/amd/src/mustache.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
JS library for displaying mustache templates.&lt;br /&gt;
&lt;br /&gt;
Version: 2.2.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2009 Chris Wanstrath (Ruby)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2014 Jan Lehnardt (JavaScript)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2015 The mustache.js community&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/janl/mustache.js/releases&lt;br /&gt;
&lt;br /&gt;
==Mustache==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/mustache&amp;quot;&lt;br /&gt;
&lt;br /&gt;
PHP library for displaying mustache templates.&lt;br /&gt;
&lt;br /&gt;
Version: 2.11.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2016 Justin Hileman&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/bobthecow/mustache.php/releases&lt;br /&gt;
&lt;br /&gt;
==mp3player==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/mp3player&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Flash movie to play streaming MP3s&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005   Andrew Walker&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==overlibmws==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/overlib.js&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Javascript library to enable DHTML popups, floating windows, events etc&lt;br /&gt;
&lt;br /&gt;
Version: July 2004&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002-2004   Foteos Macrides&lt;br /&gt;
&lt;br /&gt;
Copyright © 1998-2004   Erik Bosrup&lt;br /&gt;
&lt;br /&gt;
License: Artistic Open Source License&lt;br /&gt;
&lt;br /&gt;
http://www.macridesweb.com/oltest/&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PclZip==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pclzip&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to create, manage and unpack zip files.&lt;br /&gt;
&lt;br /&gt;
Version: 2.4 RC1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Vincent Blavet (&#039;&#039;vincent AT phpconcept DOT net&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.phpconcept.net&lt;br /&gt;
&lt;br /&gt;
==PEAR OLE Classes==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to write Excel files&lt;br /&gt;
&lt;br /&gt;
Version: 0.5&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Xavier Noguer&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/OLE&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PEAR Spreadsheet_Excel_Writer==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to write Excel files&lt;br /&gt;
&lt;br /&gt;
Version: 0.9.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Xavier Noguer and Mika Tuupola&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/Spreadsheet_Excel_Writer&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_Quickform==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to write forms&lt;br /&gt;
&lt;br /&gt;
Version: 3.2.6&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Bertrand Mansion, Adam Daniel, Alexey Borzov&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_Quickform&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_Quickform_Renderer_Tableless==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to render forms without tables&lt;br /&gt;
&lt;br /&gt;
Version: 0.3.4&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005 Mark Wiesemann&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_Quickform_Renderer_Tableless&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_QuickForm_DHTMLRulesTableless==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to render validation notices with dhtml&lt;br /&gt;
&lt;br /&gt;
Version: 0.1.2&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005 Alexey Borzov, Adam Daniel, Bertrand Mansion, Justin Patrin, Mark Wiesemann&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_QuickForm_DHTMLRulesTableless&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_Common==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class with many common HTML functions (used by HTML Quickform)&lt;br /&gt;
&lt;br /&gt;
Version: 0.3.4&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Adam Daniel, Bertrand Mansion, Klaus Guenther, Alexey Borzov&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_Common&lt;br /&gt;
&lt;br /&gt;
==PEAR XML_Parser==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class implementing one handy (sax-expat) XML parser&lt;br /&gt;
&lt;br /&gt;
Version: 1.3.2&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004-2008 The PHP Group &amp;amp; Stephan Schmidt&lt;br /&gt;
&lt;br /&gt;
License: New BSD License&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/XML_Parser&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PHP-CSS-Parser==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/php-css-parser&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A Parser for CSS Files written in PHP.&lt;br /&gt;
&lt;br /&gt;
Version: 8.1.0&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2011 Raphael Schweikert, http://sabberworm.com/&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/sabberworm/PHP-CSS-Parser&lt;br /&gt;
&lt;br /&gt;
==PHPExcel==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/phpexcel/PHPExcel.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library to read, write and create spreadsheet documents in PHP.&lt;br /&gt;
&lt;br /&gt;
Version 1.8.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2006 - 2015 PHPExcel&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
https://github.com/PHPOffice/PHPExcel&lt;br /&gt;
&lt;br /&gt;
==PHP mailer==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/class.phpmailer.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class for sending email using either sendmail, PHP mail(), or SMTP.  Methods are based upon the standard AspEmail(tm) classes.&lt;br /&gt;
&lt;br /&gt;
Version 5.2.16&lt;br /&gt;
&lt;br /&gt;
Copyright © 2003 Brent R. Matzelle (&#039;&#039;bmatzelle AT yahoo DOT com&#039;&#039;)&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://phpmailer.sourceforge.net&lt;br /&gt;
https://github.com/PHPMailer/PHPMailer/releases&lt;br /&gt;
&lt;br /&gt;
==PHP Markdown==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/markdown.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Functions to convert from the Markdown text format into clean XHTML.&lt;br /&gt;
&lt;br /&gt;
Version: 1.6.0 (with modifications)&lt;br /&gt;
&lt;br /&gt;
PHP Markdown Lib Copyright © 2004-2015 Michel Fortin https://michelf.ca/&lt;br /&gt;
All rights reserved.&lt;br /&gt;
&lt;br /&gt;
Based on Markdown&lt;br /&gt;
Copyright © 2003-2005 John Gruber https://daringfireball.net/&lt;br /&gt;
All rights reserved.&lt;br /&gt;
&lt;br /&gt;
License: BSD&lt;br /&gt;
&lt;br /&gt;
http://www.michelf.com/projects/php-markdown/&lt;br /&gt;
&lt;br /&gt;
==RequireJS==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;/lib/requirejs/&#039;&#039;	&lt;br /&gt;
&lt;br /&gt;
RequireJS is a JavaScript file and module loader.&lt;br /&gt;
&lt;br /&gt;
Version 2.3.2&lt;br /&gt;
&lt;br /&gt;
License: new BSD or MIT&lt;br /&gt;
&lt;br /&gt;
http://requirejs.org/&lt;br /&gt;
&lt;br /&gt;
==scssphp==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;/lib/scssphp/&#039;&#039;	&lt;br /&gt;
&lt;br /&gt;
scssphp is a compiler for SCSS written in PHP.&lt;br /&gt;
&lt;br /&gt;
Version: 0.6.5&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2015 Leaf Corcoran&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
http://leafo.github.io/scssphp&lt;br /&gt;
&lt;br /&gt;
==SimplePie==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/lib/simplepie&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Simple Pie helps with blogs.&lt;br /&gt;
&lt;br /&gt;
Version 1.4.2&lt;br /&gt;
&lt;br /&gt;
License: BSD&lt;br /&gt;
&lt;br /&gt;
https://github.com/simplepie/simplepie&lt;br /&gt;
&lt;br /&gt;
==Snoopy==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/snoopy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A PHP net client&lt;br /&gt;
&lt;br /&gt;
Version: 1.0&lt;br /&gt;
&lt;br /&gt;
Copyright © 1999-2000 Monte Ohrt (&#039;&#039;monte AT ispi DOT net&#039;&#039;)&lt;br /&gt;
License: GNU LGPL&lt;br /&gt;
&lt;br /&gt;
http://snoopy.sourceforge.com&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==SMTP class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/class.smtp.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class that can be used to connect and communicate with any SMTP server. It implements all the SMTP functions defined in RFC821 except TURN.&lt;br /&gt;
&lt;br /&gt;
Version: 03/26/2001&lt;br /&gt;
&lt;br /&gt;
Copyright © 2001  Chris Ryan (&#039;&#039;chris AT greatbridge DOT com&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==Spike PHPCoverage==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/spikephpcoverage&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP code coverage reporting tool&lt;br /&gt;
&lt;br /&gt;
Version: 0.8.2 (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004 SpikeSource Inc&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://developer.spikesource.com/projects/phpcoverage&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==Spout==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/spout&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Library for importing and exporting csv / excel / ODS files.&lt;br /&gt;
&lt;br /&gt;
Version 2.6.0&lt;br /&gt;
&lt;br /&gt;
License: Apache&lt;br /&gt;
&lt;br /&gt;
https://github.com/box/spout/&lt;br /&gt;
&lt;br /&gt;
==Typo3 Character Set Class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/typo3&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class for conversion between charsets and multibyte-savy operations with strings.&lt;br /&gt;
&lt;br /&gt;
Version: 4.7.19&lt;br /&gt;
&lt;br /&gt;
Copyright © 2003-2005 Kasper Skaarhoj&lt;br /&gt;
&lt;br /&gt;
Licence: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://typo3.org/&lt;br /&gt;
&lt;br /&gt;
==Yahoo User Interface==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/yui&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The Yahoo! User Interface Library is a set of utilities and controls, in JavaScript, for building richly interactive web applications using techniques such as DOM scripting, DHTML and AJAX. The YUI Library also includes several core CSS resources.Set of user-interface components using AJAX, DHTML etc.  We use it for all our AJAX-related stuff.&lt;br /&gt;
&lt;br /&gt;
CVS version: 2.3.0&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2006, Yahoo! Inc.&lt;br /&gt;
&lt;br /&gt;
Licence: BSD&lt;br /&gt;
&lt;br /&gt;
http://developer.yahoo.com/yui/&lt;br /&gt;
&lt;br /&gt;
==Mustache.js==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/amd/src/mustache.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
JS library for displaying mustache templates.&lt;br /&gt;
&lt;br /&gt;
Version: 2.2.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2009 Chris Wanstrath (Ruby)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2014 Jan Lehnardt (JavaScript)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2015 The mustache.js community&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/janl/mustache.js/releases&lt;br /&gt;
&lt;br /&gt;
==LTI Tool Provider Library for PHP==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/ltiprovider/&amp;quot;&lt;br /&gt;
&lt;br /&gt;
PHP library for communicating with learning tools as per the LTI specification.&lt;br /&gt;
&lt;br /&gt;
Version: 3.0.2&lt;br /&gt;
&lt;br /&gt;
© 2016 IMS Global Learning Consortium Inc. All Rights Reserved. Trademark Policy - (www.imsglobal.org/trademarks)&lt;br /&gt;
&lt;br /&gt;
License: Apache 2&lt;br /&gt;
&lt;br /&gt;
https://github.com/IMSGlobal/LTI-Tool-Provider-Library-PHP&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Popper.js==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;admin/tool/usertours/amd/src/popper.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
A kickass library used to created Poppers in web applications&lt;br /&gt;
&lt;br /&gt;
© 2016 Federico Zivolo and contributors&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/FezVrasta/popper.js&lt;br /&gt;
&lt;br /&gt;
==Flexitour==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;admin/tool/usertours/amd/src/tour.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
A JS library for tours&lt;br /&gt;
&lt;br /&gt;
© 2016 Andrew Nicols and contributors&lt;br /&gt;
&lt;br /&gt;
License: GPLv3&lt;br /&gt;
&lt;br /&gt;
https://github.com/andrewnicols/flexitour&lt;br /&gt;
&lt;br /&gt;
[[Category:Credits]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_libraries_credits&amp;diff=53034</id>
		<title>Moodle libraries credits</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_libraries_credits&amp;diff=53034"/>
		<updated>2017-10-16T05:28:42Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* ADOdb */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Some of Moodle&#039;s libraries were written by other people, and are being redistributed as part of Moodle under their respective open source licenses that thankfully allow us to do so. Thanks to the authors of all these excellent products - without them Moodle would be missing important functionality. Copyright information for each package is included below:&lt;br /&gt;
&lt;br /&gt;
==ADOdb==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/adodb&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Database abstraction library for MySQL, PostgreSQL, MSSQL, Oracle, Interbase, Foxpro, Access, ADO, Sybase, DB2 and ODBC.&lt;br /&gt;
&lt;br /&gt;
Version: 5.20.9&lt;br /&gt;
&lt;br /&gt;
@copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.&lt;br /&gt;
&lt;br /&gt;
@copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community&lt;br /&gt;
&lt;br /&gt;
License: Dual LGPL and BSD-style&lt;br /&gt;
&lt;br /&gt;
http://adodb.sourceforge.net&lt;br /&gt;
&lt;br /&gt;
==Amazon S3==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;repository/s3/S3.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A standalone Amazon S3 (REST) client for PHP 5.2.x using CURL that does not require PEAR. &lt;br /&gt;
&lt;br /&gt;
Version: 0.5.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2013, Donovan Schönknecht&lt;br /&gt;
&lt;br /&gt;
License: BSD 2-Clause&lt;br /&gt;
&lt;br /&gt;
https://github.com/tpyo/amazon-s3-php-class/releases&lt;br /&gt;
&lt;br /&gt;
==CAS==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;auth/cas/CAS&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
phpCAS library to support CAS authentication plugin&lt;br /&gt;
&lt;br /&gt;
Copyright Jasig&lt;br /&gt;
&lt;br /&gt;
License: Apache License 2.0&lt;br /&gt;
&lt;br /&gt;
https://wiki.jasig.org/display/CASC/phpCAS&lt;br /&gt;
&lt;br /&gt;
==Chart.js==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/amd/src/chartjs-lazy.js&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Simple yet flexible JavaScript charting for designers &amp;amp; developers&lt;br /&gt;
&lt;br /&gt;
Version: 2.2.2&lt;br /&gt;
&lt;br /&gt;
Copyright 2016 Nick Downie&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
http://www.chartjs.org&lt;br /&gt;
&lt;br /&gt;
==EvalMath==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/evalmath&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to safely evaluate math expressions&lt;br /&gt;
&lt;br /&gt;
Copyright Miles Kaufmann&lt;br /&gt;
&lt;br /&gt;
License: BSD&lt;br /&gt;
&lt;br /&gt;
http://www.twmagic.com/&lt;br /&gt;
&lt;br /&gt;
==FLV player==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;filter/mediaplugin/flvplayer.swf&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Flash movie to play FLV files&lt;br /&gt;
&lt;br /&gt;
Copyright Jeroen Wijering &lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.jeroenwijering.com&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==FPDF Class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/fpdf&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to generate PDF files&lt;br /&gt;
&lt;br /&gt;
Version: 1.54&lt;br /&gt;
&lt;br /&gt;
Copyright Olivier PLATHEY&lt;br /&gt;
&lt;br /&gt;
License: Freeware&lt;br /&gt;
&lt;br /&gt;
http://www.setasign.com/products/fpdi/downloads&lt;br /&gt;
&lt;br /&gt;
== GeoIp2 ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/maxmind/GeoIp2&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library for precessing of GeoIP data files&lt;br /&gt;
&lt;br /&gt;
Version: 2.4.2&lt;br /&gt;
&lt;br /&gt;
Copyright MaxMind&lt;br /&gt;
&lt;br /&gt;
License: Apache 2.0&lt;br /&gt;
&lt;br /&gt;
https://github.com/maxmind/GeoIP2-php&lt;br /&gt;
&lt;br /&gt;
==Google APIs==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/google&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Library Google APIs Client Library for PHP&lt;br /&gt;
&lt;br /&gt;
Version: 1.1.7&lt;br /&gt;
&lt;br /&gt;
License: Apache License Version 2.0&lt;br /&gt;
&lt;br /&gt;
https://github.com/google/google-api-php-client&lt;br /&gt;
&lt;br /&gt;
==Graph Class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/graphlib.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to draw line, point, bar, and area graphs, including numeric x-axis and double y-axis.&lt;br /&gt;
&lt;br /&gt;
Version: 1.6.3 (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2000  Herman Veluwenkamp (&#039;&#039;hermanV AT mindless DOT com&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
==Horde==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/horde&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library used by the inbound e-mail handling system.&lt;br /&gt;
&lt;br /&gt;
Version: 5.2.7&lt;br /&gt;
&lt;br /&gt;
Copyright © Horde LLC&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://www.horde.org/&lt;br /&gt;
&lt;br /&gt;
==html2text==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/html2text&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP script to convert HTML into an approximate text equivalent&lt;br /&gt;
&lt;br /&gt;
Version: 4.0.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005-7 Jon Abernathy&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
https://github.com/mtibben/html2text.git&lt;br /&gt;
&lt;br /&gt;
==htmlArea==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/editor&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Javascript/HTML script to put a GUI editor in textareas on Internet Explorer and Mozilla&lt;br /&gt;
&lt;br /&gt;
Version: 3.0 beta (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002  interactivetools.com, inc.&lt;br /&gt;
&lt;br /&gt;
License: htmlArea License (based on BSD license)&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==HTML Purifier==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/htmlpurifier&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Filters HTML.&lt;br /&gt;
&lt;br /&gt;
Version: 4.8.0&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
==IP-Atlas==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/ipatlas&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP scripts to show the location of an IP address on a map.&lt;br /&gt;
&lt;br /&gt;
Version: 1.0 (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002   Ivan Kozik&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.xpenguin.com/ip-atlas.php&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==jQuery==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/jquery&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
jQuery is a fast, small, and feature-rich JavaScript library widely used on moodle.&lt;br /&gt;
&lt;br /&gt;
Version: 1.12.3&lt;br /&gt;
&lt;br /&gt;
Copyright: 2016 The jQuery Foundation&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://jquery.com&lt;br /&gt;
&lt;br /&gt;
==jQuery migrate==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/jquery/jquery-migrate-1.4.0.js&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library used migrate older jQuery code to jQuery 3.0.&lt;br /&gt;
&lt;br /&gt;
Version: 1.4.0&lt;br /&gt;
&lt;br /&gt;
Copyright: 2016 The jQuery Foundation and other contributors&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/jquery/jquery-migrate&lt;br /&gt;
&lt;br /&gt;
==jQuery UI==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/jquery/ui-1.12.1/&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
jQuery UI is a set of user interface interactions, effects, widgets, and themes built on top of the jQuery library.&lt;br /&gt;
&lt;br /&gt;
Version: 1.12.1&lt;br /&gt;
&lt;br /&gt;
Copyright: 2016 The jQuery Foundation and other contributors&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/jquery/jquery-migrate&lt;br /&gt;
&lt;br /&gt;
==Services_JSON==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/json&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Allows PHP-&amp;gt;JS communication via JSON&lt;br /&gt;
&lt;br /&gt;
Version: 1.3.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005 Michal Migurski&lt;br /&gt;
&lt;br /&gt;
License: Modified BSD (GPL-compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/pepr/pepr-proposal-show.php?id=198&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==kses==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/kses.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
HTML/XHTML filter that only allows some elements and attributes&lt;br /&gt;
&lt;br /&gt;
Version: 0.2.2&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002, 2003, 2005   Ulf Harnhammar&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://sourceforge.net/projects/kses&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==less.php==&lt;br /&gt;
&lt;br /&gt;
The less.php is a PHP port of the official LESS processor used by moodle themes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/lessphp&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Version: 1.7.0.10&lt;br /&gt;
&lt;br /&gt;
License: Apache 2.0&lt;br /&gt;
&lt;br /&gt;
http://lessphp.typesettercms.com/&lt;br /&gt;
&lt;br /&gt;
Copyright:  Matt Agar and Martin Jantošovič&lt;br /&gt;
==loglevel.js==&lt;br /&gt;
&lt;br /&gt;
Minimal lightweight simple logging for JavaScript.&lt;br /&gt;
&lt;br /&gt;
Version 1.4.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2013 Tim Perry&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/pimterry/loglevel/&lt;br /&gt;
==MathJax==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Not actually included in Moodle. Moodle instead has a setting where the mathjax library is located. It is currently pointing to CDN by default.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
JavaScript filter library for displaying LaTeX, AsciiMath notation, and MathML.&lt;br /&gt;
&lt;br /&gt;
Version 2.7&lt;br /&gt;
&lt;br /&gt;
© Copyright 2015 The MathJax Consortium.&lt;br /&gt;
&lt;br /&gt;
License: Apache V2.0&lt;br /&gt;
&lt;br /&gt;
https://github.com/mathjax/MathJax&lt;br /&gt;
&lt;br /&gt;
==MatthiasMullie\Minify==&lt;br /&gt;
CSS &amp;amp; JavaScript minifier, in PHP&lt;br /&gt;
&lt;br /&gt;
Version 1.3.37&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/matthiasmullie/minify&lt;br /&gt;
&lt;br /&gt;
==mimeTeX==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;filter/tex&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Compiled C program to convert TeX into GIFs&lt;br /&gt;
&lt;br /&gt;
Version: 1.4&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002-2004   John Forkosh Associates, Inc&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.forkosh.com/mimetex.html&lt;br /&gt;
&lt;br /&gt;
==Mustache.js==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/amd/src/mustache.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
JS library for displaying mustache templates.&lt;br /&gt;
&lt;br /&gt;
Version: 2.2.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2009 Chris Wanstrath (Ruby)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2014 Jan Lehnardt (JavaScript)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2015 The mustache.js community&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/janl/mustache.js/releases&lt;br /&gt;
&lt;br /&gt;
==Mustache==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/mustache&amp;quot;&lt;br /&gt;
&lt;br /&gt;
PHP library for displaying mustache templates.&lt;br /&gt;
&lt;br /&gt;
Version: 2.11.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2016 Justin Hileman&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/bobthecow/mustache.php/releases&lt;br /&gt;
&lt;br /&gt;
==mp3player==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/mp3player&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Flash movie to play streaming MP3s&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005   Andrew Walker&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==overlibmws==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/overlib.js&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Javascript library to enable DHTML popups, floating windows, events etc&lt;br /&gt;
&lt;br /&gt;
Version: July 2004&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002-2004   Foteos Macrides&lt;br /&gt;
&lt;br /&gt;
Copyright © 1998-2004   Erik Bosrup&lt;br /&gt;
&lt;br /&gt;
License: Artistic Open Source License&lt;br /&gt;
&lt;br /&gt;
http://www.macridesweb.com/oltest/&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PclZip==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pclzip&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to create, manage and unpack zip files.&lt;br /&gt;
&lt;br /&gt;
Version: 2.4 RC1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Vincent Blavet (&#039;&#039;vincent AT phpconcept DOT net&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.phpconcept.net&lt;br /&gt;
&lt;br /&gt;
==PEAR OLE Classes==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to write Excel files&lt;br /&gt;
&lt;br /&gt;
Version: 0.5&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Xavier Noguer&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/OLE&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PEAR Spreadsheet_Excel_Writer==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to write Excel files&lt;br /&gt;
&lt;br /&gt;
Version: 0.9.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Xavier Noguer and Mika Tuupola&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/Spreadsheet_Excel_Writer&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_Quickform==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to write forms&lt;br /&gt;
&lt;br /&gt;
Version: 3.2.6&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Bertrand Mansion, Adam Daniel, Alexey Borzov&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_Quickform&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_Quickform_Renderer_Tableless==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to render forms without tables&lt;br /&gt;
&lt;br /&gt;
Version: 0.3.4&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005 Mark Wiesemann&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_Quickform_Renderer_Tableless&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_QuickForm_DHTMLRulesTableless==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to render validation notices with dhtml&lt;br /&gt;
&lt;br /&gt;
Version: 0.1.2&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005 Alexey Borzov, Adam Daniel, Bertrand Mansion, Justin Patrin, Mark Wiesemann&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_QuickForm_DHTMLRulesTableless&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_Common==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class with many common HTML functions (used by HTML Quickform)&lt;br /&gt;
&lt;br /&gt;
Version: 0.3.4&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Adam Daniel, Bertrand Mansion, Klaus Guenther, Alexey Borzov&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_Common&lt;br /&gt;
&lt;br /&gt;
==PEAR XML_Parser==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class implementing one handy (sax-expat) XML parser&lt;br /&gt;
&lt;br /&gt;
Version: 1.3.2&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004-2008 The PHP Group &amp;amp; Stephan Schmidt&lt;br /&gt;
&lt;br /&gt;
License: New BSD License&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/XML_Parser&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PHP-CSS-Parser==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/php-css-parser&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A Parser for CSS Files written in PHP.&lt;br /&gt;
&lt;br /&gt;
Version: 8.1.0&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2011 Raphael Schweikert, http://sabberworm.com/&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/sabberworm/PHP-CSS-Parser&lt;br /&gt;
&lt;br /&gt;
==PHPExcel==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/phpexcel/PHPExcel.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library to read, write and create spreadsheet documents in PHP.&lt;br /&gt;
&lt;br /&gt;
Version 1.8.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2006 - 2015 PHPExcel&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
https://github.com/PHPOffice/PHPExcel&lt;br /&gt;
&lt;br /&gt;
==PHP mailer==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/class.phpmailer.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class for sending email using either sendmail, PHP mail(), or SMTP.  Methods are based upon the standard AspEmail(tm) classes.&lt;br /&gt;
&lt;br /&gt;
Version 5.2.16&lt;br /&gt;
&lt;br /&gt;
Copyright © 2003 Brent R. Matzelle (&#039;&#039;bmatzelle AT yahoo DOT com&#039;&#039;)&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://phpmailer.sourceforge.net&lt;br /&gt;
https://github.com/PHPMailer/PHPMailer/releases&lt;br /&gt;
&lt;br /&gt;
==PHP Markdown==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/markdown.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Functions to convert from the Markdown text format into clean XHTML.&lt;br /&gt;
&lt;br /&gt;
Version: 1.6.0 (with modifications)&lt;br /&gt;
&lt;br /&gt;
PHP Markdown Lib Copyright © 2004-2015 Michel Fortin https://michelf.ca/&lt;br /&gt;
All rights reserved.&lt;br /&gt;
&lt;br /&gt;
Based on Markdown&lt;br /&gt;
Copyright © 2003-2005 John Gruber https://daringfireball.net/&lt;br /&gt;
All rights reserved.&lt;br /&gt;
&lt;br /&gt;
License: BSD&lt;br /&gt;
&lt;br /&gt;
http://www.michelf.com/projects/php-markdown/&lt;br /&gt;
&lt;br /&gt;
==RequireJS==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;/lib/requirejs/&#039;&#039;	&lt;br /&gt;
&lt;br /&gt;
RequireJS is a JavaScript file and module loader.&lt;br /&gt;
&lt;br /&gt;
Version 2.3.2&lt;br /&gt;
&lt;br /&gt;
License: new BSD or MIT&lt;br /&gt;
&lt;br /&gt;
http://requirejs.org/&lt;br /&gt;
&lt;br /&gt;
==scssphp==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;/lib/scssphp/&#039;&#039;	&lt;br /&gt;
&lt;br /&gt;
scssphp is a compiler for SCSS written in PHP.&lt;br /&gt;
&lt;br /&gt;
Version: 0.6.5&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2015 Leaf Corcoran&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
http://leafo.github.io/scssphp&lt;br /&gt;
&lt;br /&gt;
==SimplePie==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/lib/simplepie&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Simple Pie helps with blogs.&lt;br /&gt;
&lt;br /&gt;
Version 1.4.2&lt;br /&gt;
&lt;br /&gt;
License: BSD&lt;br /&gt;
&lt;br /&gt;
https://github.com/simplepie/simplepie&lt;br /&gt;
&lt;br /&gt;
==Snoopy==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/snoopy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A PHP net client&lt;br /&gt;
&lt;br /&gt;
Version: 1.0&lt;br /&gt;
&lt;br /&gt;
Copyright © 1999-2000 Monte Ohrt (&#039;&#039;monte AT ispi DOT net&#039;&#039;)&lt;br /&gt;
License: GNU LGPL&lt;br /&gt;
&lt;br /&gt;
http://snoopy.sourceforge.com&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==SMTP class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/class.smtp.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class that can be used to connect and communicate with any SMTP server. It implements all the SMTP functions defined in RFC821 except TURN.&lt;br /&gt;
&lt;br /&gt;
Version: 03/26/2001&lt;br /&gt;
&lt;br /&gt;
Copyright © 2001  Chris Ryan (&#039;&#039;chris AT greatbridge DOT com&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==Spike PHPCoverage==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/spikephpcoverage&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP code coverage reporting tool&lt;br /&gt;
&lt;br /&gt;
Version: 0.8.2 (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004 SpikeSource Inc&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://developer.spikesource.com/projects/phpcoverage&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==Spout==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/spout&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Library for importing and exporting csv / excel / ODS files.&lt;br /&gt;
&lt;br /&gt;
Version 2.6.0&lt;br /&gt;
&lt;br /&gt;
License: Apache&lt;br /&gt;
&lt;br /&gt;
https://github.com/box/spout/&lt;br /&gt;
&lt;br /&gt;
==Typo3 Character Set Class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/typo3&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class for conversion between charsets and multibyte-savy operations with strings.&lt;br /&gt;
&lt;br /&gt;
Version: 4.7.19&lt;br /&gt;
&lt;br /&gt;
Copyright © 2003-2005 Kasper Skaarhoj&lt;br /&gt;
&lt;br /&gt;
Licence: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://typo3.org/&lt;br /&gt;
&lt;br /&gt;
==Yahoo User Interface==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/yui&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The Yahoo! User Interface Library is a set of utilities and controls, in JavaScript, for building richly interactive web applications using techniques such as DOM scripting, DHTML and AJAX. The YUI Library also includes several core CSS resources.Set of user-interface components using AJAX, DHTML etc.  We use it for all our AJAX-related stuff.&lt;br /&gt;
&lt;br /&gt;
CVS version: 2.3.0&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2006, Yahoo! Inc.&lt;br /&gt;
&lt;br /&gt;
Licence: BSD&lt;br /&gt;
&lt;br /&gt;
http://developer.yahoo.com/yui/&lt;br /&gt;
&lt;br /&gt;
==Mustache.js==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/amd/src/mustache.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
JS library for displaying mustache templates.&lt;br /&gt;
&lt;br /&gt;
Version: 2.2.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2009 Chris Wanstrath (Ruby)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2014 Jan Lehnardt (JavaScript)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2015 The mustache.js community&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/janl/mustache.js/releases&lt;br /&gt;
&lt;br /&gt;
==LTI Tool Provider Library for PHP==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/ltiprovider/&amp;quot;&lt;br /&gt;
&lt;br /&gt;
PHP library for communicating with learning tools as per the LTI specification.&lt;br /&gt;
&lt;br /&gt;
Version: 3.0.2&lt;br /&gt;
&lt;br /&gt;
© 2016 IMS Global Learning Consortium Inc. All Rights Reserved. Trademark Policy - (www.imsglobal.org/trademarks)&lt;br /&gt;
&lt;br /&gt;
License: Apache 2&lt;br /&gt;
&lt;br /&gt;
https://github.com/IMSGlobal/LTI-Tool-Provider-Library-PHP&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Popper.js==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;admin/tool/usertours/amd/src/popper.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
A kickass library used to created Poppers in web applications&lt;br /&gt;
&lt;br /&gt;
© 2016 Federico Zivolo and contributors&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/FezVrasta/popper.js&lt;br /&gt;
&lt;br /&gt;
==Flexitour==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;admin/tool/usertours/amd/src/tour.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
A JS library for tours&lt;br /&gt;
&lt;br /&gt;
© 2016 Andrew Nicols and contributors&lt;br /&gt;
&lt;br /&gt;
License: GPLv3&lt;br /&gt;
&lt;br /&gt;
https://github.com/andrewnicols/flexitour&lt;br /&gt;
&lt;br /&gt;
[[Category:Credits]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_libraries_credits&amp;diff=53033</id>
		<title>Moodle libraries credits</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_libraries_credits&amp;diff=53033"/>
		<updated>2017-10-16T05:28:21Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* ADOdb */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Some of Moodle&#039;s libraries were written by other people, and are being redistributed as part of Moodle under their respective open source licenses that thankfully allow us to do so. Thanks to the authors of all these excellent products - without them Moodle would be missing important functionality. Copyright information for each package is included below:&lt;br /&gt;
&lt;br /&gt;
==ADOdb==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/adodb&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Database abstraction library for MySQL, PostgreSQL, MSSQL, Oracle, Interbase, Foxpro, Access, ADO, Sybase, DB2 and ODBC.&lt;br /&gt;
&lt;br /&gt;
Version: 5.20.9&lt;br /&gt;
&lt;br /&gt;
@copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.&lt;br /&gt;
@copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community&lt;br /&gt;
&lt;br /&gt;
License: Dual LGPL and BSD-style&lt;br /&gt;
&lt;br /&gt;
http://adodb.sourceforge.net&lt;br /&gt;
&lt;br /&gt;
==Amazon S3==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;repository/s3/S3.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A standalone Amazon S3 (REST) client for PHP 5.2.x using CURL that does not require PEAR. &lt;br /&gt;
&lt;br /&gt;
Version: 0.5.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2013, Donovan Schönknecht&lt;br /&gt;
&lt;br /&gt;
License: BSD 2-Clause&lt;br /&gt;
&lt;br /&gt;
https://github.com/tpyo/amazon-s3-php-class/releases&lt;br /&gt;
&lt;br /&gt;
==CAS==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;auth/cas/CAS&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
phpCAS library to support CAS authentication plugin&lt;br /&gt;
&lt;br /&gt;
Copyright Jasig&lt;br /&gt;
&lt;br /&gt;
License: Apache License 2.0&lt;br /&gt;
&lt;br /&gt;
https://wiki.jasig.org/display/CASC/phpCAS&lt;br /&gt;
&lt;br /&gt;
==Chart.js==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/amd/src/chartjs-lazy.js&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Simple yet flexible JavaScript charting for designers &amp;amp; developers&lt;br /&gt;
&lt;br /&gt;
Version: 2.2.2&lt;br /&gt;
&lt;br /&gt;
Copyright 2016 Nick Downie&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
http://www.chartjs.org&lt;br /&gt;
&lt;br /&gt;
==EvalMath==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/evalmath&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to safely evaluate math expressions&lt;br /&gt;
&lt;br /&gt;
Copyright Miles Kaufmann&lt;br /&gt;
&lt;br /&gt;
License: BSD&lt;br /&gt;
&lt;br /&gt;
http://www.twmagic.com/&lt;br /&gt;
&lt;br /&gt;
==FLV player==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;filter/mediaplugin/flvplayer.swf&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Flash movie to play FLV files&lt;br /&gt;
&lt;br /&gt;
Copyright Jeroen Wijering &lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.jeroenwijering.com&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==FPDF Class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/fpdf&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to generate PDF files&lt;br /&gt;
&lt;br /&gt;
Version: 1.54&lt;br /&gt;
&lt;br /&gt;
Copyright Olivier PLATHEY&lt;br /&gt;
&lt;br /&gt;
License: Freeware&lt;br /&gt;
&lt;br /&gt;
http://www.setasign.com/products/fpdi/downloads&lt;br /&gt;
&lt;br /&gt;
== GeoIp2 ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/maxmind/GeoIp2&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library for precessing of GeoIP data files&lt;br /&gt;
&lt;br /&gt;
Version: 2.4.2&lt;br /&gt;
&lt;br /&gt;
Copyright MaxMind&lt;br /&gt;
&lt;br /&gt;
License: Apache 2.0&lt;br /&gt;
&lt;br /&gt;
https://github.com/maxmind/GeoIP2-php&lt;br /&gt;
&lt;br /&gt;
==Google APIs==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/google&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Library Google APIs Client Library for PHP&lt;br /&gt;
&lt;br /&gt;
Version: 1.1.7&lt;br /&gt;
&lt;br /&gt;
License: Apache License Version 2.0&lt;br /&gt;
&lt;br /&gt;
https://github.com/google/google-api-php-client&lt;br /&gt;
&lt;br /&gt;
==Graph Class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/graphlib.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to draw line, point, bar, and area graphs, including numeric x-axis and double y-axis.&lt;br /&gt;
&lt;br /&gt;
Version: 1.6.3 (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2000  Herman Veluwenkamp (&#039;&#039;hermanV AT mindless DOT com&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
==Horde==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/horde&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library used by the inbound e-mail handling system.&lt;br /&gt;
&lt;br /&gt;
Version: 5.2.7&lt;br /&gt;
&lt;br /&gt;
Copyright © Horde LLC&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://www.horde.org/&lt;br /&gt;
&lt;br /&gt;
==html2text==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/html2text&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP script to convert HTML into an approximate text equivalent&lt;br /&gt;
&lt;br /&gt;
Version: 4.0.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005-7 Jon Abernathy&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
https://github.com/mtibben/html2text.git&lt;br /&gt;
&lt;br /&gt;
==htmlArea==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/editor&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Javascript/HTML script to put a GUI editor in textareas on Internet Explorer and Mozilla&lt;br /&gt;
&lt;br /&gt;
Version: 3.0 beta (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002  interactivetools.com, inc.&lt;br /&gt;
&lt;br /&gt;
License: htmlArea License (based on BSD license)&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==HTML Purifier==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/htmlpurifier&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Filters HTML.&lt;br /&gt;
&lt;br /&gt;
Version: 4.8.0&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
==IP-Atlas==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/ipatlas&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP scripts to show the location of an IP address on a map.&lt;br /&gt;
&lt;br /&gt;
Version: 1.0 (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002   Ivan Kozik&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.xpenguin.com/ip-atlas.php&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==jQuery==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/jquery&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
jQuery is a fast, small, and feature-rich JavaScript library widely used on moodle.&lt;br /&gt;
&lt;br /&gt;
Version: 1.12.3&lt;br /&gt;
&lt;br /&gt;
Copyright: 2016 The jQuery Foundation&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://jquery.com&lt;br /&gt;
&lt;br /&gt;
==jQuery migrate==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/jquery/jquery-migrate-1.4.0.js&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library used migrate older jQuery code to jQuery 3.0.&lt;br /&gt;
&lt;br /&gt;
Version: 1.4.0&lt;br /&gt;
&lt;br /&gt;
Copyright: 2016 The jQuery Foundation and other contributors&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/jquery/jquery-migrate&lt;br /&gt;
&lt;br /&gt;
==jQuery UI==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/jquery/ui-1.12.1/&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
jQuery UI is a set of user interface interactions, effects, widgets, and themes built on top of the jQuery library.&lt;br /&gt;
&lt;br /&gt;
Version: 1.12.1&lt;br /&gt;
&lt;br /&gt;
Copyright: 2016 The jQuery Foundation and other contributors&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/jquery/jquery-migrate&lt;br /&gt;
&lt;br /&gt;
==Services_JSON==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/json&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Allows PHP-&amp;gt;JS communication via JSON&lt;br /&gt;
&lt;br /&gt;
Version: 1.3.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005 Michal Migurski&lt;br /&gt;
&lt;br /&gt;
License: Modified BSD (GPL-compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/pepr/pepr-proposal-show.php?id=198&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==kses==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/kses.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
HTML/XHTML filter that only allows some elements and attributes&lt;br /&gt;
&lt;br /&gt;
Version: 0.2.2&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002, 2003, 2005   Ulf Harnhammar&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://sourceforge.net/projects/kses&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==less.php==&lt;br /&gt;
&lt;br /&gt;
The less.php is a PHP port of the official LESS processor used by moodle themes.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/lessphp&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Version: 1.7.0.10&lt;br /&gt;
&lt;br /&gt;
License: Apache 2.0&lt;br /&gt;
&lt;br /&gt;
http://lessphp.typesettercms.com/&lt;br /&gt;
&lt;br /&gt;
Copyright:  Matt Agar and Martin Jantošovič&lt;br /&gt;
==loglevel.js==&lt;br /&gt;
&lt;br /&gt;
Minimal lightweight simple logging for JavaScript.&lt;br /&gt;
&lt;br /&gt;
Version 1.4.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2013 Tim Perry&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/pimterry/loglevel/&lt;br /&gt;
==MathJax==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Not actually included in Moodle. Moodle instead has a setting where the mathjax library is located. It is currently pointing to CDN by default.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
JavaScript filter library for displaying LaTeX, AsciiMath notation, and MathML.&lt;br /&gt;
&lt;br /&gt;
Version 2.7&lt;br /&gt;
&lt;br /&gt;
© Copyright 2015 The MathJax Consortium.&lt;br /&gt;
&lt;br /&gt;
License: Apache V2.0&lt;br /&gt;
&lt;br /&gt;
https://github.com/mathjax/MathJax&lt;br /&gt;
&lt;br /&gt;
==MatthiasMullie\Minify==&lt;br /&gt;
CSS &amp;amp; JavaScript minifier, in PHP&lt;br /&gt;
&lt;br /&gt;
Version 1.3.37&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/matthiasmullie/minify&lt;br /&gt;
&lt;br /&gt;
==mimeTeX==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;filter/tex&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Compiled C program to convert TeX into GIFs&lt;br /&gt;
&lt;br /&gt;
Version: 1.4&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002-2004   John Forkosh Associates, Inc&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.forkosh.com/mimetex.html&lt;br /&gt;
&lt;br /&gt;
==Mustache.js==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/amd/src/mustache.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
JS library for displaying mustache templates.&lt;br /&gt;
&lt;br /&gt;
Version: 2.2.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2009 Chris Wanstrath (Ruby)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2014 Jan Lehnardt (JavaScript)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2015 The mustache.js community&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/janl/mustache.js/releases&lt;br /&gt;
&lt;br /&gt;
==Mustache==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/mustache&amp;quot;&lt;br /&gt;
&lt;br /&gt;
PHP library for displaying mustache templates.&lt;br /&gt;
&lt;br /&gt;
Version: 2.11.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2016 Justin Hileman&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/bobthecow/mustache.php/releases&lt;br /&gt;
&lt;br /&gt;
==mp3player==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/mp3player&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Flash movie to play streaming MP3s&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005   Andrew Walker&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==overlibmws==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/overlib.js&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Javascript library to enable DHTML popups, floating windows, events etc&lt;br /&gt;
&lt;br /&gt;
Version: July 2004&lt;br /&gt;
&lt;br /&gt;
Copyright © 2002-2004   Foteos Macrides&lt;br /&gt;
&lt;br /&gt;
Copyright © 1998-2004   Erik Bosrup&lt;br /&gt;
&lt;br /&gt;
License: Artistic Open Source License&lt;br /&gt;
&lt;br /&gt;
http://www.macridesweb.com/oltest/&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PclZip==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pclzip&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to create, manage and unpack zip files.&lt;br /&gt;
&lt;br /&gt;
Version: 2.4 RC1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Vincent Blavet (&#039;&#039;vincent AT phpconcept DOT net&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
License: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://www.phpconcept.net&lt;br /&gt;
&lt;br /&gt;
==PEAR OLE Classes==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to write Excel files&lt;br /&gt;
&lt;br /&gt;
Version: 0.5&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Xavier Noguer&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/OLE&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PEAR Spreadsheet_Excel_Writer==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to write Excel files&lt;br /&gt;
&lt;br /&gt;
Version: 0.9.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Xavier Noguer and Mika Tuupola&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/Spreadsheet_Excel_Writer&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_Quickform==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to write forms&lt;br /&gt;
&lt;br /&gt;
Version: 3.2.6&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Bertrand Mansion, Adam Daniel, Alexey Borzov&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_Quickform&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_Quickform_Renderer_Tableless==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to render forms without tables&lt;br /&gt;
&lt;br /&gt;
Version: 0.3.4&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005 Mark Wiesemann&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_Quickform_Renderer_Tableless&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_QuickForm_DHTMLRulesTableless==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class to render validation notices with dhtml&lt;br /&gt;
&lt;br /&gt;
Version: 0.1.2&lt;br /&gt;
&lt;br /&gt;
Copyright © 2005 Alexey Borzov, Adam Daniel, Bertrand Mansion, Justin Patrin, Mark Wiesemann&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_QuickForm_DHTMLRulesTableless&lt;br /&gt;
&lt;br /&gt;
==PEAR HTML_Common==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class with many common HTML functions (used by HTML Quickform)&lt;br /&gt;
&lt;br /&gt;
Version: 0.3.4&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004  Adam Daniel, Bertrand Mansion, Klaus Guenther, Alexey Borzov&lt;br /&gt;
&lt;br /&gt;
License: PHP (plus special exemption for Moodle to make it compatible)&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/HTML_Common&lt;br /&gt;
&lt;br /&gt;
==PEAR XML_Parser==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/pear&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class implementing one handy (sax-expat) XML parser&lt;br /&gt;
&lt;br /&gt;
Version: 1.3.2&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004-2008 The PHP Group &amp;amp; Stephan Schmidt&lt;br /&gt;
&lt;br /&gt;
License: New BSD License&lt;br /&gt;
&lt;br /&gt;
http://pear.php.net/package/XML_Parser&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==PHP-CSS-Parser==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/php-css-parser&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A Parser for CSS Files written in PHP.&lt;br /&gt;
&lt;br /&gt;
Version: 8.1.0&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2011 Raphael Schweikert, http://sabberworm.com/&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/sabberworm/PHP-CSS-Parser&lt;br /&gt;
&lt;br /&gt;
==PHPExcel==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/phpexcel/PHPExcel.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Library to read, write and create spreadsheet documents in PHP.&lt;br /&gt;
&lt;br /&gt;
Version 1.8.1&lt;br /&gt;
&lt;br /&gt;
Copyright © 2006 - 2015 PHPExcel&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
https://github.com/PHPOffice/PHPExcel&lt;br /&gt;
&lt;br /&gt;
==PHP mailer==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/class.phpmailer.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class for sending email using either sendmail, PHP mail(), or SMTP.  Methods are based upon the standard AspEmail(tm) classes.&lt;br /&gt;
&lt;br /&gt;
Version 5.2.16&lt;br /&gt;
&lt;br /&gt;
Copyright © 2003 Brent R. Matzelle (&#039;&#039;bmatzelle AT yahoo DOT com&#039;&#039;)&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://phpmailer.sourceforge.net&lt;br /&gt;
https://github.com/PHPMailer/PHPMailer/releases&lt;br /&gt;
&lt;br /&gt;
==PHP Markdown==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/markdown.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Functions to convert from the Markdown text format into clean XHTML.&lt;br /&gt;
&lt;br /&gt;
Version: 1.6.0 (with modifications)&lt;br /&gt;
&lt;br /&gt;
PHP Markdown Lib Copyright © 2004-2015 Michel Fortin https://michelf.ca/&lt;br /&gt;
All rights reserved.&lt;br /&gt;
&lt;br /&gt;
Based on Markdown&lt;br /&gt;
Copyright © 2003-2005 John Gruber https://daringfireball.net/&lt;br /&gt;
All rights reserved.&lt;br /&gt;
&lt;br /&gt;
License: BSD&lt;br /&gt;
&lt;br /&gt;
http://www.michelf.com/projects/php-markdown/&lt;br /&gt;
&lt;br /&gt;
==RequireJS==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;/lib/requirejs/&#039;&#039;	&lt;br /&gt;
&lt;br /&gt;
RequireJS is a JavaScript file and module loader.&lt;br /&gt;
&lt;br /&gt;
Version 2.3.2&lt;br /&gt;
&lt;br /&gt;
License: new BSD or MIT&lt;br /&gt;
&lt;br /&gt;
http://requirejs.org/&lt;br /&gt;
&lt;br /&gt;
==scssphp==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;/lib/scssphp/&#039;&#039;	&lt;br /&gt;
&lt;br /&gt;
scssphp is a compiler for SCSS written in PHP.&lt;br /&gt;
&lt;br /&gt;
Version: 0.6.5&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2015 Leaf Corcoran&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
http://leafo.github.io/scssphp&lt;br /&gt;
&lt;br /&gt;
==SimplePie==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;/lib/simplepie&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Simple Pie helps with blogs.&lt;br /&gt;
&lt;br /&gt;
Version 1.4.2&lt;br /&gt;
&lt;br /&gt;
License: BSD&lt;br /&gt;
&lt;br /&gt;
https://github.com/simplepie/simplepie&lt;br /&gt;
&lt;br /&gt;
==Snoopy==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/snoopy&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A PHP net client&lt;br /&gt;
&lt;br /&gt;
Version: 1.0&lt;br /&gt;
&lt;br /&gt;
Copyright © 1999-2000 Monte Ohrt (&#039;&#039;monte AT ispi DOT net&#039;&#039;)&lt;br /&gt;
License: GNU LGPL&lt;br /&gt;
&lt;br /&gt;
http://snoopy.sourceforge.com&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==SMTP class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/class.smtp.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class that can be used to connect and communicate with any SMTP server. It implements all the SMTP functions defined in RFC821 except TURN.&lt;br /&gt;
&lt;br /&gt;
Version: 03/26/2001&lt;br /&gt;
&lt;br /&gt;
Copyright © 2001  Chris Ryan (&#039;&#039;chris AT greatbridge DOT com&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==Spike PHPCoverage==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/spikephpcoverage&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
PHP code coverage reporting tool&lt;br /&gt;
&lt;br /&gt;
Version: 0.8.2 (with modifications)&lt;br /&gt;
&lt;br /&gt;
Copyright © 2004 SpikeSource Inc&lt;br /&gt;
&lt;br /&gt;
License: LGPL&lt;br /&gt;
&lt;br /&gt;
http://developer.spikesource.com/projects/phpcoverage&lt;br /&gt;
&lt;br /&gt;
(This library is not currently used in Moodle)&lt;br /&gt;
&lt;br /&gt;
==Spout==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/spout&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Library for importing and exporting csv / excel / ODS files.&lt;br /&gt;
&lt;br /&gt;
Version 2.6.0&lt;br /&gt;
&lt;br /&gt;
License: Apache&lt;br /&gt;
&lt;br /&gt;
https://github.com/box/spout/&lt;br /&gt;
&lt;br /&gt;
==Typo3 Character Set Class==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/typo3&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Class for conversion between charsets and multibyte-savy operations with strings.&lt;br /&gt;
&lt;br /&gt;
Version: 4.7.19&lt;br /&gt;
&lt;br /&gt;
Copyright © 2003-2005 Kasper Skaarhoj&lt;br /&gt;
&lt;br /&gt;
Licence: GNU GPL&lt;br /&gt;
&lt;br /&gt;
http://typo3.org/&lt;br /&gt;
&lt;br /&gt;
==Yahoo User Interface==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib/yui&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The Yahoo! User Interface Library is a set of utilities and controls, in JavaScript, for building richly interactive web applications using techniques such as DOM scripting, DHTML and AJAX. The YUI Library also includes several core CSS resources.Set of user-interface components using AJAX, DHTML etc.  We use it for all our AJAX-related stuff.&lt;br /&gt;
&lt;br /&gt;
CVS version: 2.3.0&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2006, Yahoo! Inc.&lt;br /&gt;
&lt;br /&gt;
Licence: BSD&lt;br /&gt;
&lt;br /&gt;
http://developer.yahoo.com/yui/&lt;br /&gt;
&lt;br /&gt;
==Mustache.js==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/amd/src/mustache.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
JS library for displaying mustache templates.&lt;br /&gt;
&lt;br /&gt;
Version: 2.2.1&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2009 Chris Wanstrath (Ruby)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2014 Jan Lehnardt (JavaScript)&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2010-2015 The mustache.js community&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/janl/mustache.js/releases&lt;br /&gt;
&lt;br /&gt;
==LTI Tool Provider Library for PHP==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lib/ltiprovider/&amp;quot;&lt;br /&gt;
&lt;br /&gt;
PHP library for communicating with learning tools as per the LTI specification.&lt;br /&gt;
&lt;br /&gt;
Version: 3.0.2&lt;br /&gt;
&lt;br /&gt;
© 2016 IMS Global Learning Consortium Inc. All Rights Reserved. Trademark Policy - (www.imsglobal.org/trademarks)&lt;br /&gt;
&lt;br /&gt;
License: Apache 2&lt;br /&gt;
&lt;br /&gt;
https://github.com/IMSGlobal/LTI-Tool-Provider-Library-PHP&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Popper.js==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;admin/tool/usertours/amd/src/popper.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
A kickass library used to created Poppers in web applications&lt;br /&gt;
&lt;br /&gt;
© 2016 Federico Zivolo and contributors&lt;br /&gt;
&lt;br /&gt;
License: MIT&lt;br /&gt;
&lt;br /&gt;
https://github.com/FezVrasta/popper.js&lt;br /&gt;
&lt;br /&gt;
==Flexitour==&lt;br /&gt;
&lt;br /&gt;
&amp;quot;admin/tool/usertours/amd/src/tour.js&amp;quot;&lt;br /&gt;
&lt;br /&gt;
A JS library for tours&lt;br /&gt;
&lt;br /&gt;
© 2016 Andrew Nicols and contributors&lt;br /&gt;
&lt;br /&gt;
License: GPLv3&lt;br /&gt;
&lt;br /&gt;
https://github.com/andrewnicols/flexitour&lt;br /&gt;
&lt;br /&gt;
[[Category:Credits]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=52844</id>
		<title>Tutorial</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=52844"/>
		<updated>2017-08-23T06:34:31Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* Plugin types */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Welcome to Moodle development!&lt;br /&gt;
&lt;br /&gt;
This is a tutorial to help you learn how to write plugins for Moodle from start to finish, while showing you how to navigate the most important developer documentation along the way.&lt;br /&gt;
&lt;br /&gt;
PRE-REQUISITES:  We assume you are fairly comfortable with [[PHP FAQ|PHP]] in general and that you are able to [[:en:Installing AMP|install a database and web server]] on your local machine. &lt;br /&gt;
&lt;br /&gt;
If you need to learn PHP, you can see one PHP tutorial at http://www.w3schools.com/php/default.asp, another at http://php.net/manual/en/tutorial.php and several videos in YouTube at https://www.youtube.com/results?search_query=learn+php. There is a very old unmaintained Introduction to Moodle 1.8 Programming course at http://dev.moodle.org/course/view.php?id=2.&lt;br /&gt;
&lt;br /&gt;
Code examples can be found on GitHub at https://github.com/abgreeve/devcourse where a working plugin is located.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
===What&#039;s in the box===&lt;br /&gt;
If you [http://download.moodle.org/ download] Moodle source code or clone it from [https://github.com/moodle/moodle git], you will see a bunch of files and folders. This code consists of [[Core_APIs|Moodle core]] (that consists of the Very core and Core components), [[Moodle_libraries_credits|third party libraries]] and [[Plugin_types|plugins]]. Their mixed locations can be quite confusing at first but as you start working with it it will become more clear. Moodle developers should avoid modifications of the third party libraries (unless required) and core can never call methods defined in plugins. See also [[Communication Between Components]]&lt;br /&gt;
&lt;br /&gt;
===Setting up your development environment===&lt;br /&gt;
* Moodle uses Git for developement. View the link below for basic information about Git and Moodle.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Git for developers]]&lt;br /&gt;
&lt;br /&gt;
===The Moodle development framework===&lt;br /&gt;
===What type of plugin are you developing?===&lt;br /&gt;
* Moodle has lots of different types of plugins.&lt;br /&gt;
* There are 24 different categories of plugin listed on the moodle plugin database. Before starting check here to see if someone else has not already created what you are looking for. Perhaps you could contribute to their plugin instead of creating a new one.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* https://moodle.org/plugins/&lt;br /&gt;
* [[Plugin types]]&lt;br /&gt;
&lt;br /&gt;
==Let&#039;s make a plugin==&lt;br /&gt;
===The skeleton of your plugin===&lt;br /&gt;
&lt;br /&gt;
You plugin code will be organised into multiple files within a single root directory (and the subdirectories).&lt;br /&gt;
&lt;br /&gt;
The page [[Plugin files]] provides a list of common plugins files and their purpose.&lt;br /&gt;
&lt;br /&gt;
See also:&lt;br /&gt;
&lt;br /&gt;
* [[Moodle architecture]] - general overview of Moodle code architecture&lt;br /&gt;
* [[Plugin types]] - list of all supported plugin types&lt;br /&gt;
* [https://moodle.org/plugins/ Moodle plugins directory] - repository of contributed plugins for Moodle&lt;br /&gt;
* [https://moodle.org/plugins/tool_pluginskel Moodle plugin skeleton generator] - allows to quickly generate code skeleton for a new plugin&lt;br /&gt;
&lt;br /&gt;
===Basic page structure===&lt;br /&gt;
&lt;br /&gt;
The link below explains how to create and display a simple page in Moodle.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Page API]]&lt;br /&gt;
&lt;br /&gt;
===How to support over 100 languages===&lt;br /&gt;
* Language files are stored in the &amp;quot;lang&amp;quot; directory. English strings would be found in &amp;quot;lang/en&amp;quot;. Each language contains a file named after the plugin which contains all of the strings. For example the language strings for the assignment activity are found in &amp;quot;mod/assign/lang/en/assign.php&amp;quot;.&lt;br /&gt;
* [[:en:Language FAQ#Which_is_the_official_language_for_Moodle.3F| Moodle&#039;s default is Australian English]]. &lt;br /&gt;
** American English is a separate language pack (en_us). Please use only Australian (UK) English grammar and spelling when writing Moodle plugins.&lt;br /&gt;
** There is no need to include languages other than the default English, as almost all approved [https://lang.moodle.org/mod/forum/discuss.php?d=2485 plugin strings will be automatically imported into AMOS] for translation by the language packs translators.  &lt;br /&gt;
* get_string() is used in most cases for displaying text.&lt;br /&gt;
* lang_string() is used in situations where the text may not necessarily be displayed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Declaration in language file (lang/en/{pluginname}.php)&lt;br /&gt;
$string[&#039;nameofstring&#039;] = &#039;Actual string&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The get_string() function takes four parameters, but in this example we are only filling in the first two. The last two parameters are optional. The first parameter is the identifier for the string. The second is the component.&lt;br /&gt;
The component will be the name of the language file.&lt;br /&gt;
The following example shows a string in the badges block.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Use of string in code.&lt;br /&gt;
echo html_writer::tag(&#039;p&#039;, get_string(&#039;numbadgestodisplay&#039;, &#039;block_badges&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[String API]]&lt;br /&gt;
* [[Places to search for lang strings]]&lt;br /&gt;
* [[:en:Language customisation]]&lt;br /&gt;
* [[Plugin contribution checklist#Strings]]&lt;br /&gt;
&lt;br /&gt;
===Moodle file structure===&lt;br /&gt;
==== Automatic Class Loading ====&lt;br /&gt;
Automatic class loading helps us to automatically include class files as and when they are required instead of manually including them everytime. Moodle supports automatic class loading. See the link below for the explanation of rules associated with it - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Automatic class loading]]&lt;br /&gt;
&lt;br /&gt;
==== Callbacks ====&lt;br /&gt;
You can add a lot of features to your plugin by providing certain callbacks that Moodle expects to be present in your plugin&#039;s lib.php file. A detailed list can be found at - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Callbacks ]]&lt;br /&gt;
&lt;br /&gt;
==== Plugin types ====&lt;br /&gt;
Moodle supports a wide range of plugin types. The complete list and location to place these plugins can be found at - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Plugin types ]]&lt;br /&gt;
&lt;br /&gt;
==== Core APIs ====&lt;br /&gt;
Moodle provides apis for a plugin to interact with core and other external systems. For example you don&#039;t have to manually do any SQL queries, Moodle provides it&#039;s own DDL and DML layers. The link below lists all major core apis in Moodle - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Core APIs ]]&lt;br /&gt;
&lt;br /&gt;
==== Browser accessible pages ====&lt;br /&gt;
Any php file in your plugin will either be browser accessible or be an internal file. &lt;br /&gt;
&lt;br /&gt;
For browser accessible pages you must include config.php with code something similar to this - &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once(&#039;../../config.php&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For internal files the code should use the following - &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Add content to your page===&lt;br /&gt;
* Content for a page is added through renderers.&lt;br /&gt;
* Renderers are typically stored in the &amp;quot;classes/output&amp;quot; directory.&lt;br /&gt;
* Putting content in renderers allows themers to override the visual display of the content.&lt;br /&gt;
* Very basic information is presented using the html_writer class.&lt;br /&gt;
* In most cases templates should be used.&lt;br /&gt;
* templates are stored in the &amp;quot;templates&amp;quot; directory. The templates use mustache files.&lt;br /&gt;
* Mustache files allow for more generic html with placeholders inserted, that inserts the data (context) at run time.&lt;br /&gt;
&lt;br /&gt;
The example used below is an admin tool and would be located under admin/tool.&lt;br /&gt;
&lt;br /&gt;
Step One: Create a class for rendering. This class collects information to display and has a method for formatting that information into a format that the template will understand.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/classes/output/developer_course_main_page.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace tool_devcourse\output;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
use renderable;&lt;br /&gt;
use renderer_base;&lt;br /&gt;
use templatable;&lt;br /&gt;
use stdClass;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class developer_course_main_page implements renderable, templatable {&lt;br /&gt;
&lt;br /&gt;
   protected $comment;&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Construct this renderable.&lt;br /&gt;
     * @param int $courseid The course record for this page.&lt;br /&gt;
     */&lt;br /&gt;
    public function __construct($comment) {&lt;br /&gt;
        $this-&amp;gt;comment = $comment;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Export this data so it can be used as the context for a mustache template.&lt;br /&gt;
     *&lt;br /&gt;
     * @param renderer_base $output Renderer base.&lt;br /&gt;
     * @return stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function export_for_template(renderer_base $output) {&lt;br /&gt;
        $data = new stdClass();&lt;br /&gt;
        $data-&amp;gt;comment = $this-&amp;gt;comment;&lt;br /&gt;
        return $data;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Step Two: To render this information a custom renderer is created for the plugin. This renderer class must extend plugin_renderer_base.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/classes/output/renderer.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace tool_devcourse\output;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
use plugin_renderer_base;&lt;br /&gt;
use renderable;&lt;br /&gt;
&lt;br /&gt;
class renderer extends plugin_renderer_base {&lt;br /&gt;
&lt;br /&gt;
     /**&lt;br /&gt;
     * Defer to template.&lt;br /&gt;
     *&lt;br /&gt;
     * @param developer_course_main_page $page&lt;br /&gt;
     *&lt;br /&gt;
     * @return string html for the page&lt;br /&gt;
     */&lt;br /&gt;
    public function render_developer_course_main_page(developer_course_main_page $page) {&lt;br /&gt;
        $data = $page-&amp;gt;export_for_template($this);&lt;br /&gt;
        return parent::render_from_template(&#039;tool_devcourse/developer_course_main_page&#039;, $data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Step three: A mustache template is to then be created. The information is sent to the template and at this point the information is known as the context (not to be confused with the normal definition of context throughout Moodle).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/templates/developer_course_main_page.mustache&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code html&amp;gt;&lt;br /&gt;
{{!&lt;br /&gt;
    @template tool_devcourse/developer_course_main_page&lt;br /&gt;
&lt;br /&gt;
    Example context (json):&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;comment&amp;quot;: &amp;quot;Example comment for the context&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;h2&amp;gt;{{#str}}maintitle, tool_devdoc{{/str}}&amp;lt;/h2&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;{{comment}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This shows an extremely simple mustache template with one item in the context (comment). It also shows how strings are defined in the template.&lt;br /&gt;
&lt;br /&gt;
Step four: To actually have this template be displayed we get the custom renderer. This chunk of code would be located in a place such as devcourse/index.php after the appropriate setup outlined in the [[Tutorial#Basic_page_structure|basic page structure]].&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$output = $PAGE-&amp;gt;get_renderer(&#039;tool_devcourse&#039;);&lt;br /&gt;
//Then we get the class for rendering and provide it with information (if needed).&lt;br /&gt;
$randomcomment = &#039;This comment is random&#039;;&lt;br /&gt;
$page = new \tool_devdoc\output\developer_course_main_page($randomcomment);&lt;br /&gt;
//Finally we echo out the template&lt;br /&gt;
echo $output-&amp;gt;render($page);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Output API]]&lt;br /&gt;
* [[Output functions]]&lt;br /&gt;
* [[Templates]]&lt;br /&gt;
* [[Output renderers]]&lt;br /&gt;
* [[Renderer]]&lt;br /&gt;
* [[Overriding a renderer]]&lt;br /&gt;
&lt;br /&gt;
===Adding your plugin into Moodle&#039;s navigation===&lt;br /&gt;
* The moodle navigation system has hooks which allows plugins to add links to the navigation menu.&lt;br /&gt;
* Hooks are located in lib.php. Try to keep lib.php as small as possible as this file is included on every page. Put classes and functions elsewhere.&lt;br /&gt;
* Course navigation extension example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function tool_devcourse_extend_navigation_course($navigation, $course, $coursecontext) {&lt;br /&gt;
    $url = new moodle_url(&#039;/admin/tool/devcourse/index.php&#039;);&lt;br /&gt;
    $devcoursenode = navigation_node::create(&#039;Development course&#039;, $url, navigation_node::TYPE_CUSTOM, &#039;Dev course&#039;, &#039;devcourse&#039;);&lt;br /&gt;
    $navigation-&amp;gt;add_node($devcoursenode);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Navigation API]]&lt;br /&gt;
* [[:en:Navigation]]&lt;br /&gt;
&lt;br /&gt;
===Database queries===&lt;br /&gt;
* Moodle has a generic database query library. Behind this library are additional libraries which allow Moodle to work with MySQL, PostgreSQL, Oracle, SQL Server, and Maria DB.&lt;br /&gt;
* Where possible it is advisable to use the predefined functions rather than write out SQL. Writing SQL has a greater chance of not working with one of the supported databases.&lt;br /&gt;
* The return of the select functions tends to be an object or an array of objects.&lt;br /&gt;
&lt;br /&gt;
Example call to retrieve data from the course table.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
global $DB;&lt;br /&gt;
$courses = $DB-&amp;gt;get_records(&#039;course&#039;, null, &#039;&#039;, &#039;id, category, fullname, shortname&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Example of data returned from the above code.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Array&lt;br /&gt;
(&lt;br /&gt;
    [43] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 43&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; XX -Test 5&lt;br /&gt;
            [shortname] =&amp;gt; xxt5&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    [5] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 5&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; With the glossary&lt;br /&gt;
            [shortname] =&amp;gt; wtg&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    [39] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 39&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; XX - Test 1&lt;br /&gt;
            [shortname] =&amp;gt; xxt1&lt;br /&gt;
        )&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Database]]&lt;br /&gt;
* [[Data manipulation API]]&lt;br /&gt;
&lt;br /&gt;
===Creating your own database tables===&lt;br /&gt;
* We create our database tables in Moodle using the  XMLDB editor. This is located in the administration block &amp;quot;Site administration | Development | XMLDB editor&amp;quot;.&lt;br /&gt;
* The {plugin}\db directory needs to have write access for the XMLDB editor to be most effective.&lt;br /&gt;
* XMLDB editor creates an install.xml file in the db directory. This file will be loaded during the install to create your tables.&lt;br /&gt;
* XMLDB editor will produce php update code for adding and updating moodle database tables.&lt;br /&gt;
&lt;br /&gt;
The XMLDB main page.&lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:xmldb-main.png]]&lt;br /&gt;
&lt;br /&gt;
Upgrade code generated by the XMLDB&lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:xmldb-upgrade-code.png]]&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[XMLDB editor]]&lt;br /&gt;
* [[Using XMLDB]]&lt;br /&gt;
* [[XMLDB Documentation]]&lt;br /&gt;
* [[Upgrade API]]&lt;br /&gt;
* [[XMLDB introduction]]&lt;br /&gt;
&lt;br /&gt;
===Supporting access permissions: roles, capabilities and contexts===&lt;br /&gt;
* Capabilities are controlled in &amp;quot;access.php&amp;quot; under the &amp;quot;db&amp;quot; directory.&lt;br /&gt;
* This file has an array of capabilities with the following:&lt;br /&gt;
** name&lt;br /&gt;
** possible security risks behind giving this capability.&lt;br /&gt;
** The context that this capability works in.&lt;br /&gt;
** The default roles (teacher, manager, student, etc) that have this capability.&lt;br /&gt;
** Various other information.&lt;br /&gt;
* These capabilities are checked in code to allow access to pages, sections, and abilities (saving, deleting, etc).&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[Access API]]&lt;br /&gt;
* [[Roles#Context]]&lt;br /&gt;
* [[:en:Category:Capabilities]]&lt;br /&gt;
* [[:en:Roles and permissions]]&lt;br /&gt;
&lt;br /&gt;
===Adding web forms===&lt;br /&gt;
* Moodle has it&#039;s own forms library.&lt;br /&gt;
* The forms lib includes a lot of accessibility code, and error checking, by default.&lt;br /&gt;
* Moodle forms can be displayed in JavaScript using &#039;fragments&#039;.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Form API]]&lt;br /&gt;
* [[lib/formslib.php Form Definition]]&lt;br /&gt;
* [[Fragment]]&lt;br /&gt;
&lt;br /&gt;
===Maintaining good security===&lt;br /&gt;
* Use the sesskey when directing to pages to do actions.&lt;br /&gt;
* Use the appropriate filters when retrieving parameters&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[lib/formslib.php Form Definition#Most Commonly Used PARAM .2A Types]]&lt;br /&gt;
* [[Output functions#p.28.29 and s.28.29]]&lt;br /&gt;
&lt;br /&gt;
===Handling files===&lt;br /&gt;
* Files are conceptually stored in file areas.&lt;br /&gt;
* Plugins can only access files from it&#039;s own component.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[File API]]&lt;br /&gt;
* [[File API internals]]&lt;br /&gt;
* [[Using the File API in Moodle forms]]&lt;br /&gt;
&lt;br /&gt;
===Adding Javascript===&lt;br /&gt;
* Moodle is currently using jquery and AMD (Asynchronous Module Definition).&lt;br /&gt;
* JavaScript files are located in the &amp;quot;amd/src&amp;quot; directory.&lt;br /&gt;
* Use grunt to build your JavaScript.&lt;br /&gt;
* Include your JavaScript in php files as follows:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;requires-&amp;gt;js_call_amd(&#039;{JScriptfilename}&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* Can also be included in mustache templates.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Javascript Modules]]&lt;br /&gt;
* [[jQuery]]&lt;br /&gt;
* [[Javascript FAQ]]&lt;br /&gt;
* [[JavaScript guidelines]]&lt;br /&gt;
* [[Grunt]]&lt;br /&gt;
&lt;br /&gt;
===Adding events and logging===&lt;br /&gt;
* All logging in moodle is done through the events system.&lt;br /&gt;
* New events should be located in the &amp;quot;classes/event&amp;quot; directory.&lt;br /&gt;
* It is possible to create observers and subscribe to events.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Event 2]]&lt;br /&gt;
* [[Logging 2]]&lt;br /&gt;
&lt;br /&gt;
===Accessibility===&lt;br /&gt;
&lt;br /&gt;
Accessibility is an important consideration while developing a plugin to make sure your plugin is accessible to all users and doesn&#039;t discriminate against users with disablities. This often is a mandated requirement in many countries. The links below explain common practices that we follow at Moodle to make the interface more accessible.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[Accessibility]]&lt;br /&gt;
* [[Usability]]&lt;br /&gt;
===Web Services and AJAX===&lt;br /&gt;
* Moodle web services uses the external functions API.&lt;br /&gt;
* The recommended way to make AJAX requests is to use the ajax AMD file which uses the external functions API.&lt;br /&gt;
* External functions should be located in the &amp;quot;classes/external.php&amp;quot; file.&lt;br /&gt;
* A list of services should be included in &amp;quot;db/services.php&amp;quot;. This file is required to register the web services with Moodle.&lt;br /&gt;
* The services list is an array which contains:&lt;br /&gt;
** &#039;&#039;&#039;classname&#039;&#039;&#039; Name of the external class.&lt;br /&gt;
** &#039;&#039;&#039;methodname&#039;&#039;&#039; The name of the external function.&lt;br /&gt;
** &#039;&#039;&#039;classpath&#039;&#039;&#039; system path to the external function file.&lt;br /&gt;
** &#039;&#039;&#039;description&#039;&#039;&#039; Description of the function&lt;br /&gt;
** &#039;&#039;&#039;type&#039;&#039;&#039; Create, read, update, delete&lt;br /&gt;
** &#039;&#039;&#039;ajax&#039;&#039;&#039; Can this function be used with ajax?&lt;br /&gt;
** &#039;&#039;&#039;capabilities&#039;&#039;&#039; Capabilities required to use this function.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[External functions API]]&lt;br /&gt;
* [[Adding a web service to a plugin]]&lt;br /&gt;
* [[Web services API]]&lt;br /&gt;
&lt;br /&gt;
===Using caching to improve performance===&lt;br /&gt;
* The main cache used by moodle is the Moodle Universal Cache (MUC).&lt;br /&gt;
* The MUC has several cache definitions - &lt;br /&gt;
** Request cache&lt;br /&gt;
** Session cache&lt;br /&gt;
** Application&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[The Moodle Universal Cache (MUC)]]&lt;br /&gt;
* [[:en:MUC FAQ]]&lt;br /&gt;
* [[:en:Caching]]&lt;br /&gt;
&lt;br /&gt;
===Supporting backup and restore===&lt;br /&gt;
* Supporting backup and restore requires creating several files in the &#039;backup/moodle2&#039; directory.&lt;br /&gt;
* Back requires a class to extend the backup_task of some sort. There may be a specific plugin task to extend.&lt;br /&gt;
* Restore requires a class to extend the restore_task of some sort. There may be a specific plugin task to extend.&lt;br /&gt;
* The restore steps lib defines the structure of the plugin to be restored.&lt;br /&gt;
* The backup steps lib defines steps, settings, attributes, etc.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Backup 2.0 for developers]] - provides an example of step-by-step implementation of backup support to your plugin&lt;br /&gt;
* [[:en:Backup and restore FAQ]]&lt;br /&gt;
&lt;br /&gt;
===Supporting automated testing===&lt;br /&gt;
* Moodle has two types of automated testing: php unit tests, and behat tests.&lt;br /&gt;
* Unit tests are for testing functions.&lt;br /&gt;
* Behat tests runs through scenarios.&lt;br /&gt;
** Behat tests follows a script and navigates through moodle pages.&lt;br /&gt;
* unit tests should be located in the &amp;quot;tests&amp;quot; directory.&lt;br /&gt;
* behat tests should be located in the &amp;quot;tests/behat&amp;quot; directory.&lt;br /&gt;
* Tests located in these directories will be run through when a full test run is initiated.&lt;br /&gt;
* behat tests are actually feature files and end with the extension &amp;quot;.feature&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Writing PHPUnit tests]]&lt;br /&gt;
* [[PHPUnit]]&lt;br /&gt;
* [[Acceptance testing]]&lt;br /&gt;
* [[Behat integration]]&lt;br /&gt;
&lt;br /&gt;
==Publishing your plugin==&lt;br /&gt;
===Adding your plugin to moodle.org===&lt;br /&gt;
* publish your plugins at https://moodle.org/plugins/&lt;br /&gt;
* Publishing plugins on the moodle site leads you through a bunch of steps that need to be completed in order for the plugin to be approved and published.&lt;br /&gt;
* Plugins will be run through a pre-checker to give suggestions about possible issues with the code.&lt;br /&gt;
&lt;br /&gt;
===Supporting your plugin===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=TODO=&lt;br /&gt;
&lt;br /&gt;
Finishing this tutorial:&lt;br /&gt;
# About one or two screens for each section with a very generic overview for beginners, containing links to relevant docs WITH COMMENTS ABOUT QUALITY, USEFULNESS, CAVEATS etc.&lt;br /&gt;
# Go through all the linked pages and make sure they are current and accurate.&lt;br /&gt;
# Add a worked example to this page, so that each section has suggestions about things to add to the admin tool being built as an exercise.  If the code is long, it could be placed on separate pages.  A good reference for style is [[Moodle_Mobile_Developing_a_plugin_tutorial]] and [[Blocks]].&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* See [https://moodle.org/mod/forum/discuss.php?d=352360 this forum thread] about Getting Started with Moodle Development.&lt;br /&gt;
&lt;br /&gt;
=See also these older tutorials =&lt;br /&gt;
* [[Blocks|A Step-by-step Guide To Creating Blocks]] &lt;br /&gt;
* [[NEWMODULE Tutorial]]&lt;br /&gt;
* [http://dev.moodle.org Introduction to Moodle programming (based on Moodle 1.8)]&lt;br /&gt;
* [[Moodle_Mobile_Developing_a_plugin_tutorial|Moodle Mobile plugin tutorial]]&lt;br /&gt;
* [[Category:Tutorial|Other tutorials in these docs]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Tutorial]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=52843</id>
		<title>Tutorial</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=52843"/>
		<updated>2017-08-23T06:21:30Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* Core APIs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Welcome to Moodle development!&lt;br /&gt;
&lt;br /&gt;
This is a tutorial to help you learn how to write plugins for Moodle from start to finish, while showing you how to navigate the most important developer documentation along the way.&lt;br /&gt;
&lt;br /&gt;
PRE-REQUISITES:  We assume you are fairly comfortable with [[PHP FAQ|PHP]] in general and that you are able to [[:en:Installing AMP|install a database and web server]] on your local machine. &lt;br /&gt;
&lt;br /&gt;
If you need to learn PHP, you can see one PHP tutorial at http://www.w3schools.com/php/default.asp, another at http://php.net/manual/en/tutorial.php and several videos in YouTube at https://www.youtube.com/results?search_query=learn+php. There is a very old unmaintained Introduction to Moodle 1.8 Programming course at http://dev.moodle.org/course/view.php?id=2.&lt;br /&gt;
&lt;br /&gt;
Code examples can be found on GitHub at https://github.com/abgreeve/devcourse where a working plugin is located.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
===What&#039;s in the box===&lt;br /&gt;
If you [http://download.moodle.org/ download] Moodle source code or clone it from [https://github.com/moodle/moodle git], you will see a bunch of files and folders. This code consists of [[Core_APIs|Moodle core]] (that consists of the Very core and Core components), [[Moodle_libraries_credits|third party libraries]] and [[Plugin_types|plugins]]. Their mixed locations can be quite confusing at first but as you start working with it it will become more clear. Moodle developers should avoid modifications of the third party libraries (unless required) and core can never call methods defined in plugins. See also [[Communication Between Components]]&lt;br /&gt;
&lt;br /&gt;
===Setting up your development environment===&lt;br /&gt;
* Moodle uses Git for developement. View the link below for basic information about Git and Moodle.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Git for developers]]&lt;br /&gt;
&lt;br /&gt;
===The Moodle development framework===&lt;br /&gt;
===What type of plugin are you developing?===&lt;br /&gt;
* Moodle has lots of different types of plugins.&lt;br /&gt;
* There are 24 different categories of plugin listed on the moodle plugin database. Before starting check here to see if someone else has not already created what you are looking for. Perhaps you could contribute to their plugin instead of creating a new one.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* https://moodle.org/plugins/&lt;br /&gt;
* [[Plugin types]]&lt;br /&gt;
&lt;br /&gt;
==Let&#039;s make a plugin==&lt;br /&gt;
===The skeleton of your plugin===&lt;br /&gt;
&lt;br /&gt;
You plugin code will be organised into multiple files within a single root directory (and the subdirectories).&lt;br /&gt;
&lt;br /&gt;
The page [[Plugin files]] provides a list of common plugins files and their purpose.&lt;br /&gt;
&lt;br /&gt;
See also:&lt;br /&gt;
&lt;br /&gt;
* [[Moodle architecture]] - general overview of Moodle code architecture&lt;br /&gt;
* [[Plugin types]] - list of all supported plugin types&lt;br /&gt;
* [https://moodle.org/plugins/ Moodle plugins directory] - repository of contributed plugins for Moodle&lt;br /&gt;
* [https://moodle.org/plugins/tool_pluginskel Moodle plugin skeleton generator] - allows to quickly generate code skeleton for a new plugin&lt;br /&gt;
&lt;br /&gt;
===Basic page structure===&lt;br /&gt;
&lt;br /&gt;
The link below explains how to create and display a simple page in Moodle.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Page API]]&lt;br /&gt;
&lt;br /&gt;
===How to support over 100 languages===&lt;br /&gt;
* Language files are stored in the &amp;quot;lang&amp;quot; directory. English strings would be found in &amp;quot;lang/en&amp;quot;. Each language contains a file named after the plugin which contains all of the strings. For example the language strings for the assignment activity are found in &amp;quot;mod/assign/lang/en/assign.php&amp;quot;.&lt;br /&gt;
* [[:en:Language FAQ#Which_is_the_official_language_for_Moodle.3F| Moodle&#039;s default is Australian English]]. &lt;br /&gt;
** American English is a separate language pack (en_us). Please use only Australian (UK) English grammar and spelling when writing Moodle plugins.&lt;br /&gt;
** There is no need to include languages other than the default English, as almost all approved [https://lang.moodle.org/mod/forum/discuss.php?d=2485 plugin strings will be automatically imported into AMOS] for translation by the language packs translators.  &lt;br /&gt;
* get_string() is used in most cases for displaying text.&lt;br /&gt;
* lang_string() is used in situations where the text may not necessarily be displayed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Declaration in language file (lang/en/{pluginname}.php)&lt;br /&gt;
$string[&#039;nameofstring&#039;] = &#039;Actual string&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The get_string() function takes four parameters, but in this example we are only filling in the first two. The last two parameters are optional. The first parameter is the identifier for the string. The second is the component.&lt;br /&gt;
The component will be the name of the language file.&lt;br /&gt;
The following example shows a string in the badges block.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Use of string in code.&lt;br /&gt;
echo html_writer::tag(&#039;p&#039;, get_string(&#039;numbadgestodisplay&#039;, &#039;block_badges&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[String API]]&lt;br /&gt;
* [[Places to search for lang strings]]&lt;br /&gt;
* [[:en:Language customisation]]&lt;br /&gt;
* [[Plugin contribution checklist#Strings]]&lt;br /&gt;
&lt;br /&gt;
===Moodle file structure===&lt;br /&gt;
==== Automatic Class Loading ====&lt;br /&gt;
Automatic class loading helps us to automatically include class files as and when they are required instead of manually including them everytime. Moodle supports automatic class loading. See the link below for the explanation of rules associated with it - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Automatic class loading]]&lt;br /&gt;
&lt;br /&gt;
==== Callbacks ====&lt;br /&gt;
You can add a lot of features to your plugin by providing certain callbacks that Moodle expects to be present in your plugin&#039;s lib.php file. A detailed list can be found at - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Callbacks ]]&lt;br /&gt;
&lt;br /&gt;
==== Plugin types ====&lt;br /&gt;
Moodle supports a wide range of plugin types. The complete list can be found at - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Plugin types ]]&lt;br /&gt;
&lt;br /&gt;
==== Core APIs ====&lt;br /&gt;
Moodle provides apis for a plugin to interact with core and other external systems. For example you don&#039;t have to manually do any SQL queries, Moodle provides it&#039;s own DDL and DML layers. The link below lists all major core apis in Moodle - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Core APIs ]]&lt;br /&gt;
&lt;br /&gt;
==== Browser accessible pages ====&lt;br /&gt;
Any php file in your plugin will either be browser accessible or be an internal file. &lt;br /&gt;
&lt;br /&gt;
For browser accessible pages you must include config.php with code something similar to this - &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once(&#039;../../config.php&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For internal files the code should use the following - &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Add content to your page===&lt;br /&gt;
* Content for a page is added through renderers.&lt;br /&gt;
* Renderers are typically stored in the &amp;quot;classes/output&amp;quot; directory.&lt;br /&gt;
* Putting content in renderers allows themers to override the visual display of the content.&lt;br /&gt;
* Very basic information is presented using the html_writer class.&lt;br /&gt;
* In most cases templates should be used.&lt;br /&gt;
* templates are stored in the &amp;quot;templates&amp;quot; directory. The templates use mustache files.&lt;br /&gt;
* Mustache files allow for more generic html with placeholders inserted, that inserts the data (context) at run time.&lt;br /&gt;
&lt;br /&gt;
The example used below is an admin tool and would be located under admin/tool.&lt;br /&gt;
&lt;br /&gt;
Step One: Create a class for rendering. This class collects information to display and has a method for formatting that information into a format that the template will understand.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/classes/output/developer_course_main_page.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace tool_devcourse\output;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
use renderable;&lt;br /&gt;
use renderer_base;&lt;br /&gt;
use templatable;&lt;br /&gt;
use stdClass;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class developer_course_main_page implements renderable, templatable {&lt;br /&gt;
&lt;br /&gt;
   protected $comment;&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Construct this renderable.&lt;br /&gt;
     * @param int $courseid The course record for this page.&lt;br /&gt;
     */&lt;br /&gt;
    public function __construct($comment) {&lt;br /&gt;
        $this-&amp;gt;comment = $comment;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Export this data so it can be used as the context for a mustache template.&lt;br /&gt;
     *&lt;br /&gt;
     * @param renderer_base $output Renderer base.&lt;br /&gt;
     * @return stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function export_for_template(renderer_base $output) {&lt;br /&gt;
        $data = new stdClass();&lt;br /&gt;
        $data-&amp;gt;comment = $this-&amp;gt;comment;&lt;br /&gt;
        return $data;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Step Two: To render this information a custom renderer is created for the plugin. This renderer class must extend plugin_renderer_base.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/classes/output/renderer.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace tool_devcourse\output;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
use plugin_renderer_base;&lt;br /&gt;
use renderable;&lt;br /&gt;
&lt;br /&gt;
class renderer extends plugin_renderer_base {&lt;br /&gt;
&lt;br /&gt;
     /**&lt;br /&gt;
     * Defer to template.&lt;br /&gt;
     *&lt;br /&gt;
     * @param developer_course_main_page $page&lt;br /&gt;
     *&lt;br /&gt;
     * @return string html for the page&lt;br /&gt;
     */&lt;br /&gt;
    public function render_developer_course_main_page(developer_course_main_page $page) {&lt;br /&gt;
        $data = $page-&amp;gt;export_for_template($this);&lt;br /&gt;
        return parent::render_from_template(&#039;tool_devcourse/developer_course_main_page&#039;, $data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Step three: A mustache template is to then be created. The information is sent to the template and at this point the information is known as the context (not to be confused with the normal definition of context throughout Moodle).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/templates/developer_course_main_page.mustache&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code html&amp;gt;&lt;br /&gt;
{{!&lt;br /&gt;
    @template tool_devcourse/developer_course_main_page&lt;br /&gt;
&lt;br /&gt;
    Example context (json):&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;comment&amp;quot;: &amp;quot;Example comment for the context&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;h2&amp;gt;{{#str}}maintitle, tool_devdoc{{/str}}&amp;lt;/h2&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;{{comment}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This shows an extremely simple mustache template with one item in the context (comment). It also shows how strings are defined in the template.&lt;br /&gt;
&lt;br /&gt;
Step four: To actually have this template be displayed we get the custom renderer. This chunk of code would be located in a place such as devcourse/index.php after the appropriate setup outlined in the [[Tutorial#Basic_page_structure|basic page structure]].&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$output = $PAGE-&amp;gt;get_renderer(&#039;tool_devcourse&#039;);&lt;br /&gt;
//Then we get the class for rendering and provide it with information (if needed).&lt;br /&gt;
$randomcomment = &#039;This comment is random&#039;;&lt;br /&gt;
$page = new \tool_devdoc\output\developer_course_main_page($randomcomment);&lt;br /&gt;
//Finally we echo out the template&lt;br /&gt;
echo $output-&amp;gt;render($page);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Output API]]&lt;br /&gt;
* [[Output functions]]&lt;br /&gt;
* [[Templates]]&lt;br /&gt;
* [[Output renderers]]&lt;br /&gt;
* [[Renderer]]&lt;br /&gt;
* [[Overriding a renderer]]&lt;br /&gt;
&lt;br /&gt;
===Adding your plugin into Moodle&#039;s navigation===&lt;br /&gt;
* The moodle navigation system has hooks which allows plugins to add links to the navigation menu.&lt;br /&gt;
* Hooks are located in lib.php. Try to keep lib.php as small as possible as this file is included on every page. Put classes and functions elsewhere.&lt;br /&gt;
* Course navigation extension example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function tool_devcourse_extend_navigation_course($navigation, $course, $coursecontext) {&lt;br /&gt;
    $url = new moodle_url(&#039;/admin/tool/devcourse/index.php&#039;);&lt;br /&gt;
    $devcoursenode = navigation_node::create(&#039;Development course&#039;, $url, navigation_node::TYPE_CUSTOM, &#039;Dev course&#039;, &#039;devcourse&#039;);&lt;br /&gt;
    $navigation-&amp;gt;add_node($devcoursenode);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Navigation API]]&lt;br /&gt;
* [[:en:Navigation]]&lt;br /&gt;
&lt;br /&gt;
===Database queries===&lt;br /&gt;
* Moodle has a generic database query library. Behind this library are additional libraries which allow Moodle to work with MySQL, PostgreSQL, Oracle, SQL Server, and Maria DB.&lt;br /&gt;
* Where possible it is advisable to use the predefined functions rather than write out SQL. Writing SQL has a greater chance of not working with one of the supported databases.&lt;br /&gt;
* The return of the select functions tends to be an object or an array of objects.&lt;br /&gt;
&lt;br /&gt;
Example call to retrieve data from the course table.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
global $DB;&lt;br /&gt;
$courses = $DB-&amp;gt;get_records(&#039;course&#039;, null, &#039;&#039;, &#039;id, category, fullname, shortname&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Example of data returned from the above code.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Array&lt;br /&gt;
(&lt;br /&gt;
    [43] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 43&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; XX -Test 5&lt;br /&gt;
            [shortname] =&amp;gt; xxt5&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    [5] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 5&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; With the glossary&lt;br /&gt;
            [shortname] =&amp;gt; wtg&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    [39] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 39&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; XX - Test 1&lt;br /&gt;
            [shortname] =&amp;gt; xxt1&lt;br /&gt;
        )&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Database]]&lt;br /&gt;
* [[Data manipulation API]]&lt;br /&gt;
&lt;br /&gt;
===Creating your own database tables===&lt;br /&gt;
* We create our database tables in Moodle using the  XMLDB editor. This is located in the administration block &amp;quot;Site administration | Development | XMLDB editor&amp;quot;.&lt;br /&gt;
* The {plugin}\db directory needs to have write access for the XMLDB editor to be most effective.&lt;br /&gt;
* XMLDB editor creates an install.xml file in the db directory. This file will be loaded during the install to create your tables.&lt;br /&gt;
* XMLDB editor will produce php update code for adding and updating moodle database tables.&lt;br /&gt;
&lt;br /&gt;
The XMLDB main page.&lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:xmldb-main.png]]&lt;br /&gt;
&lt;br /&gt;
Upgrade code generated by the XMLDB&lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:xmldb-upgrade-code.png]]&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[XMLDB editor]]&lt;br /&gt;
* [[Using XMLDB]]&lt;br /&gt;
* [[XMLDB Documentation]]&lt;br /&gt;
* [[Upgrade API]]&lt;br /&gt;
* [[XMLDB introduction]]&lt;br /&gt;
&lt;br /&gt;
===Supporting access permissions: roles, capabilities and contexts===&lt;br /&gt;
* Capabilities are controlled in &amp;quot;access.php&amp;quot; under the &amp;quot;db&amp;quot; directory.&lt;br /&gt;
* This file has an array of capabilities with the following:&lt;br /&gt;
** name&lt;br /&gt;
** possible security risks behind giving this capability.&lt;br /&gt;
** The context that this capability works in.&lt;br /&gt;
** The default roles (teacher, manager, student, etc) that have this capability.&lt;br /&gt;
** Various other information.&lt;br /&gt;
* These capabilities are checked in code to allow access to pages, sections, and abilities (saving, deleting, etc).&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[Access API]]&lt;br /&gt;
* [[Roles#Context]]&lt;br /&gt;
* [[:en:Category:Capabilities]]&lt;br /&gt;
* [[:en:Roles and permissions]]&lt;br /&gt;
&lt;br /&gt;
===Adding web forms===&lt;br /&gt;
* Moodle has it&#039;s own forms library.&lt;br /&gt;
* The forms lib includes a lot of accessibility code, and error checking, by default.&lt;br /&gt;
* Moodle forms can be displayed in JavaScript using &#039;fragments&#039;.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Form API]]&lt;br /&gt;
* [[lib/formslib.php Form Definition]]&lt;br /&gt;
* [[Fragment]]&lt;br /&gt;
&lt;br /&gt;
===Maintaining good security===&lt;br /&gt;
* Use the sesskey when directing to pages to do actions.&lt;br /&gt;
* Use the appropriate filters when retrieving parameters&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[lib/formslib.php Form Definition#Most Commonly Used PARAM .2A Types]]&lt;br /&gt;
* [[Output functions#p.28.29 and s.28.29]]&lt;br /&gt;
&lt;br /&gt;
===Handling files===&lt;br /&gt;
* Files are conceptually stored in file areas.&lt;br /&gt;
* Plugins can only access files from it&#039;s own component.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[File API]]&lt;br /&gt;
* [[File API internals]]&lt;br /&gt;
* [[Using the File API in Moodle forms]]&lt;br /&gt;
&lt;br /&gt;
===Adding Javascript===&lt;br /&gt;
* Moodle is currently using jquery and AMD (Asynchronous Module Definition).&lt;br /&gt;
* JavaScript files are located in the &amp;quot;amd/src&amp;quot; directory.&lt;br /&gt;
* Use grunt to build your JavaScript.&lt;br /&gt;
* Include your JavaScript in php files as follows:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;requires-&amp;gt;js_call_amd(&#039;{JScriptfilename}&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* Can also be included in mustache templates.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Javascript Modules]]&lt;br /&gt;
* [[jQuery]]&lt;br /&gt;
* [[Javascript FAQ]]&lt;br /&gt;
* [[JavaScript guidelines]]&lt;br /&gt;
* [[Grunt]]&lt;br /&gt;
&lt;br /&gt;
===Adding events and logging===&lt;br /&gt;
* All logging in moodle is done through the events system.&lt;br /&gt;
* New events should be located in the &amp;quot;classes/event&amp;quot; directory.&lt;br /&gt;
* It is possible to create observers and subscribe to events.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Event 2]]&lt;br /&gt;
* [[Logging 2]]&lt;br /&gt;
&lt;br /&gt;
===Accessibility===&lt;br /&gt;
&lt;br /&gt;
Accessibility is an important consideration while developing a plugin to make sure your plugin is accessible to all users and doesn&#039;t discriminate against users with disablities. This often is a mandated requirement in many countries. The links below explain common practices that we follow at Moodle to make the interface more accessible.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[Accessibility]]&lt;br /&gt;
* [[Usability]]&lt;br /&gt;
===Web Services and AJAX===&lt;br /&gt;
* Moodle web services uses the external functions API.&lt;br /&gt;
* The recommended way to make AJAX requests is to use the ajax AMD file which uses the external functions API.&lt;br /&gt;
* External functions should be located in the &amp;quot;classes/external.php&amp;quot; file.&lt;br /&gt;
* A list of services should be included in &amp;quot;db/services.php&amp;quot;. This file is required to register the web services with Moodle.&lt;br /&gt;
* The services list is an array which contains:&lt;br /&gt;
** &#039;&#039;&#039;classname&#039;&#039;&#039; Name of the external class.&lt;br /&gt;
** &#039;&#039;&#039;methodname&#039;&#039;&#039; The name of the external function.&lt;br /&gt;
** &#039;&#039;&#039;classpath&#039;&#039;&#039; system path to the external function file.&lt;br /&gt;
** &#039;&#039;&#039;description&#039;&#039;&#039; Description of the function&lt;br /&gt;
** &#039;&#039;&#039;type&#039;&#039;&#039; Create, read, update, delete&lt;br /&gt;
** &#039;&#039;&#039;ajax&#039;&#039;&#039; Can this function be used with ajax?&lt;br /&gt;
** &#039;&#039;&#039;capabilities&#039;&#039;&#039; Capabilities required to use this function.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[External functions API]]&lt;br /&gt;
* [[Adding a web service to a plugin]]&lt;br /&gt;
* [[Web services API]]&lt;br /&gt;
&lt;br /&gt;
===Using caching to improve performance===&lt;br /&gt;
* The main cache used by moodle is the Moodle Universal Cache (MUC).&lt;br /&gt;
* The MUC has several cache definitions - &lt;br /&gt;
** Request cache&lt;br /&gt;
** Session cache&lt;br /&gt;
** Application&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[The Moodle Universal Cache (MUC)]]&lt;br /&gt;
* [[:en:MUC FAQ]]&lt;br /&gt;
* [[:en:Caching]]&lt;br /&gt;
&lt;br /&gt;
===Supporting backup and restore===&lt;br /&gt;
* Supporting backup and restore requires creating several files in the &#039;backup/moodle2&#039; directory.&lt;br /&gt;
* Back requires a class to extend the backup_task of some sort. There may be a specific plugin task to extend.&lt;br /&gt;
* Restore requires a class to extend the restore_task of some sort. There may be a specific plugin task to extend.&lt;br /&gt;
* The restore steps lib defines the structure of the plugin to be restored.&lt;br /&gt;
* The backup steps lib defines steps, settings, attributes, etc.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Backup 2.0 for developers]] - provides an example of step-by-step implementation of backup support to your plugin&lt;br /&gt;
* [[:en:Backup and restore FAQ]]&lt;br /&gt;
&lt;br /&gt;
===Supporting automated testing===&lt;br /&gt;
* Moodle has two types of automated testing: php unit tests, and behat tests.&lt;br /&gt;
* Unit tests are for testing functions.&lt;br /&gt;
* Behat tests runs through scenarios.&lt;br /&gt;
** Behat tests follows a script and navigates through moodle pages.&lt;br /&gt;
* unit tests should be located in the &amp;quot;tests&amp;quot; directory.&lt;br /&gt;
* behat tests should be located in the &amp;quot;tests/behat&amp;quot; directory.&lt;br /&gt;
* Tests located in these directories will be run through when a full test run is initiated.&lt;br /&gt;
* behat tests are actually feature files and end with the extension &amp;quot;.feature&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Writing PHPUnit tests]]&lt;br /&gt;
* [[PHPUnit]]&lt;br /&gt;
* [[Acceptance testing]]&lt;br /&gt;
* [[Behat integration]]&lt;br /&gt;
&lt;br /&gt;
==Publishing your plugin==&lt;br /&gt;
===Adding your plugin to moodle.org===&lt;br /&gt;
* publish your plugins at https://moodle.org/plugins/&lt;br /&gt;
* Publishing plugins on the moodle site leads you through a bunch of steps that need to be completed in order for the plugin to be approved and published.&lt;br /&gt;
* Plugins will be run through a pre-checker to give suggestions about possible issues with the code.&lt;br /&gt;
&lt;br /&gt;
===Supporting your plugin===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=TODO=&lt;br /&gt;
&lt;br /&gt;
Finishing this tutorial:&lt;br /&gt;
# About one or two screens for each section with a very generic overview for beginners, containing links to relevant docs WITH COMMENTS ABOUT QUALITY, USEFULNESS, CAVEATS etc.&lt;br /&gt;
# Go through all the linked pages and make sure they are current and accurate.&lt;br /&gt;
# Add a worked example to this page, so that each section has suggestions about things to add to the admin tool being built as an exercise.  If the code is long, it could be placed on separate pages.  A good reference for style is [[Moodle_Mobile_Developing_a_plugin_tutorial]] and [[Blocks]].&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* See [https://moodle.org/mod/forum/discuss.php?d=352360 this forum thread] about Getting Started with Moodle Development.&lt;br /&gt;
&lt;br /&gt;
=See also these older tutorials =&lt;br /&gt;
* [[Blocks|A Step-by-step Guide To Creating Blocks]] &lt;br /&gt;
* [[NEWMODULE Tutorial]]&lt;br /&gt;
* [http://dev.moodle.org Introduction to Moodle programming (based on Moodle 1.8)]&lt;br /&gt;
* [[Moodle_Mobile_Developing_a_plugin_tutorial|Moodle Mobile plugin tutorial]]&lt;br /&gt;
* [[Category:Tutorial|Other tutorials in these docs]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Tutorial]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=52842</id>
		<title>Tutorial</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=52842"/>
		<updated>2017-08-23T06:20:11Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* Automatic Class Loading */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Welcome to Moodle development!&lt;br /&gt;
&lt;br /&gt;
This is a tutorial to help you learn how to write plugins for Moodle from start to finish, while showing you how to navigate the most important developer documentation along the way.&lt;br /&gt;
&lt;br /&gt;
PRE-REQUISITES:  We assume you are fairly comfortable with [[PHP FAQ|PHP]] in general and that you are able to [[:en:Installing AMP|install a database and web server]] on your local machine. &lt;br /&gt;
&lt;br /&gt;
If you need to learn PHP, you can see one PHP tutorial at http://www.w3schools.com/php/default.asp, another at http://php.net/manual/en/tutorial.php and several videos in YouTube at https://www.youtube.com/results?search_query=learn+php. There is a very old unmaintained Introduction to Moodle 1.8 Programming course at http://dev.moodle.org/course/view.php?id=2.&lt;br /&gt;
&lt;br /&gt;
Code examples can be found on GitHub at https://github.com/abgreeve/devcourse where a working plugin is located.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
===What&#039;s in the box===&lt;br /&gt;
If you [http://download.moodle.org/ download] Moodle source code or clone it from [https://github.com/moodle/moodle git], you will see a bunch of files and folders. This code consists of [[Core_APIs|Moodle core]] (that consists of the Very core and Core components), [[Moodle_libraries_credits|third party libraries]] and [[Plugin_types|plugins]]. Their mixed locations can be quite confusing at first but as you start working with it it will become more clear. Moodle developers should avoid modifications of the third party libraries (unless required) and core can never call methods defined in plugins. See also [[Communication Between Components]]&lt;br /&gt;
&lt;br /&gt;
===Setting up your development environment===&lt;br /&gt;
* Moodle uses Git for developement. View the link below for basic information about Git and Moodle.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Git for developers]]&lt;br /&gt;
&lt;br /&gt;
===The Moodle development framework===&lt;br /&gt;
===What type of plugin are you developing?===&lt;br /&gt;
* Moodle has lots of different types of plugins.&lt;br /&gt;
* There are 24 different categories of plugin listed on the moodle plugin database. Before starting check here to see if someone else has not already created what you are looking for. Perhaps you could contribute to their plugin instead of creating a new one.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* https://moodle.org/plugins/&lt;br /&gt;
* [[Plugin types]]&lt;br /&gt;
&lt;br /&gt;
==Let&#039;s make a plugin==&lt;br /&gt;
===The skeleton of your plugin===&lt;br /&gt;
&lt;br /&gt;
You plugin code will be organised into multiple files within a single root directory (and the subdirectories).&lt;br /&gt;
&lt;br /&gt;
The page [[Plugin files]] provides a list of common plugins files and their purpose.&lt;br /&gt;
&lt;br /&gt;
See also:&lt;br /&gt;
&lt;br /&gt;
* [[Moodle architecture]] - general overview of Moodle code architecture&lt;br /&gt;
* [[Plugin types]] - list of all supported plugin types&lt;br /&gt;
* [https://moodle.org/plugins/ Moodle plugins directory] - repository of contributed plugins for Moodle&lt;br /&gt;
* [https://moodle.org/plugins/tool_pluginskel Moodle plugin skeleton generator] - allows to quickly generate code skeleton for a new plugin&lt;br /&gt;
&lt;br /&gt;
===Basic page structure===&lt;br /&gt;
&lt;br /&gt;
The link below explains how to create and display a simple page in Moodle.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Page API]]&lt;br /&gt;
&lt;br /&gt;
===How to support over 100 languages===&lt;br /&gt;
* Language files are stored in the &amp;quot;lang&amp;quot; directory. English strings would be found in &amp;quot;lang/en&amp;quot;. Each language contains a file named after the plugin which contains all of the strings. For example the language strings for the assignment activity are found in &amp;quot;mod/assign/lang/en/assign.php&amp;quot;.&lt;br /&gt;
* [[:en:Language FAQ#Which_is_the_official_language_for_Moodle.3F| Moodle&#039;s default is Australian English]]. &lt;br /&gt;
** American English is a separate language pack (en_us). Please use only Australian (UK) English grammar and spelling when writing Moodle plugins.&lt;br /&gt;
** There is no need to include languages other than the default English, as almost all approved [https://lang.moodle.org/mod/forum/discuss.php?d=2485 plugin strings will be automatically imported into AMOS] for translation by the language packs translators.  &lt;br /&gt;
* get_string() is used in most cases for displaying text.&lt;br /&gt;
* lang_string() is used in situations where the text may not necessarily be displayed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Declaration in language file (lang/en/{pluginname}.php)&lt;br /&gt;
$string[&#039;nameofstring&#039;] = &#039;Actual string&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The get_string() function takes four parameters, but in this example we are only filling in the first two. The last two parameters are optional. The first parameter is the identifier for the string. The second is the component.&lt;br /&gt;
The component will be the name of the language file.&lt;br /&gt;
The following example shows a string in the badges block.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Use of string in code.&lt;br /&gt;
echo html_writer::tag(&#039;p&#039;, get_string(&#039;numbadgestodisplay&#039;, &#039;block_badges&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[String API]]&lt;br /&gt;
* [[Places to search for lang strings]]&lt;br /&gt;
* [[:en:Language customisation]]&lt;br /&gt;
* [[Plugin contribution checklist#Strings]]&lt;br /&gt;
&lt;br /&gt;
===Moodle file structure===&lt;br /&gt;
==== Automatic Class Loading ====&lt;br /&gt;
Automatic class loading helps us to automatically include class files as and when they are required instead of manually including them everytime. Moodle supports automatic class loading. See the link below for the explanation of rules associated with it - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Automatic class loading]]&lt;br /&gt;
&lt;br /&gt;
==== Callbacks ====&lt;br /&gt;
You can add a lot of features to your plugin by providing certain callbacks that Moodle expects to be present in your plugin&#039;s lib.php file. A detailed list can be found at - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Callbacks ]]&lt;br /&gt;
&lt;br /&gt;
==== Plugin types ====&lt;br /&gt;
Moodle supports a wide range of plugin types. The complete list can be found at - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Plugin types ]]&lt;br /&gt;
&lt;br /&gt;
==== Core APIs ====&lt;br /&gt;
The link below lists all major core apis in Moodle - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Core APIs ]]&lt;br /&gt;
&lt;br /&gt;
==== Browser accessible pages ====&lt;br /&gt;
Any php file in your plugin will either be browser accessible or be an internal file. &lt;br /&gt;
&lt;br /&gt;
For browser accessible pages you must include config.php with code something similar to this - &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once(&#039;../../config.php&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For internal files the code should use the following - &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Add content to your page===&lt;br /&gt;
* Content for a page is added through renderers.&lt;br /&gt;
* Renderers are typically stored in the &amp;quot;classes/output&amp;quot; directory.&lt;br /&gt;
* Putting content in renderers allows themers to override the visual display of the content.&lt;br /&gt;
* Very basic information is presented using the html_writer class.&lt;br /&gt;
* In most cases templates should be used.&lt;br /&gt;
* templates are stored in the &amp;quot;templates&amp;quot; directory. The templates use mustache files.&lt;br /&gt;
* Mustache files allow for more generic html with placeholders inserted, that inserts the data (context) at run time.&lt;br /&gt;
&lt;br /&gt;
The example used below is an admin tool and would be located under admin/tool.&lt;br /&gt;
&lt;br /&gt;
Step One: Create a class for rendering. This class collects information to display and has a method for formatting that information into a format that the template will understand.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/classes/output/developer_course_main_page.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace tool_devcourse\output;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
use renderable;&lt;br /&gt;
use renderer_base;&lt;br /&gt;
use templatable;&lt;br /&gt;
use stdClass;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class developer_course_main_page implements renderable, templatable {&lt;br /&gt;
&lt;br /&gt;
   protected $comment;&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Construct this renderable.&lt;br /&gt;
     * @param int $courseid The course record for this page.&lt;br /&gt;
     */&lt;br /&gt;
    public function __construct($comment) {&lt;br /&gt;
        $this-&amp;gt;comment = $comment;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Export this data so it can be used as the context for a mustache template.&lt;br /&gt;
     *&lt;br /&gt;
     * @param renderer_base $output Renderer base.&lt;br /&gt;
     * @return stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function export_for_template(renderer_base $output) {&lt;br /&gt;
        $data = new stdClass();&lt;br /&gt;
        $data-&amp;gt;comment = $this-&amp;gt;comment;&lt;br /&gt;
        return $data;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Step Two: To render this information a custom renderer is created for the plugin. This renderer class must extend plugin_renderer_base.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/classes/output/renderer.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace tool_devcourse\output;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
use plugin_renderer_base;&lt;br /&gt;
use renderable;&lt;br /&gt;
&lt;br /&gt;
class renderer extends plugin_renderer_base {&lt;br /&gt;
&lt;br /&gt;
     /**&lt;br /&gt;
     * Defer to template.&lt;br /&gt;
     *&lt;br /&gt;
     * @param developer_course_main_page $page&lt;br /&gt;
     *&lt;br /&gt;
     * @return string html for the page&lt;br /&gt;
     */&lt;br /&gt;
    public function render_developer_course_main_page(developer_course_main_page $page) {&lt;br /&gt;
        $data = $page-&amp;gt;export_for_template($this);&lt;br /&gt;
        return parent::render_from_template(&#039;tool_devcourse/developer_course_main_page&#039;, $data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Step three: A mustache template is to then be created. The information is sent to the template and at this point the information is known as the context (not to be confused with the normal definition of context throughout Moodle).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/templates/developer_course_main_page.mustache&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code html&amp;gt;&lt;br /&gt;
{{!&lt;br /&gt;
    @template tool_devcourse/developer_course_main_page&lt;br /&gt;
&lt;br /&gt;
    Example context (json):&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;comment&amp;quot;: &amp;quot;Example comment for the context&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;h2&amp;gt;{{#str}}maintitle, tool_devdoc{{/str}}&amp;lt;/h2&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;{{comment}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This shows an extremely simple mustache template with one item in the context (comment). It also shows how strings are defined in the template.&lt;br /&gt;
&lt;br /&gt;
Step four: To actually have this template be displayed we get the custom renderer. This chunk of code would be located in a place such as devcourse/index.php after the appropriate setup outlined in the [[Tutorial#Basic_page_structure|basic page structure]].&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$output = $PAGE-&amp;gt;get_renderer(&#039;tool_devcourse&#039;);&lt;br /&gt;
//Then we get the class for rendering and provide it with information (if needed).&lt;br /&gt;
$randomcomment = &#039;This comment is random&#039;;&lt;br /&gt;
$page = new \tool_devdoc\output\developer_course_main_page($randomcomment);&lt;br /&gt;
//Finally we echo out the template&lt;br /&gt;
echo $output-&amp;gt;render($page);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Output API]]&lt;br /&gt;
* [[Output functions]]&lt;br /&gt;
* [[Templates]]&lt;br /&gt;
* [[Output renderers]]&lt;br /&gt;
* [[Renderer]]&lt;br /&gt;
* [[Overriding a renderer]]&lt;br /&gt;
&lt;br /&gt;
===Adding your plugin into Moodle&#039;s navigation===&lt;br /&gt;
* The moodle navigation system has hooks which allows plugins to add links to the navigation menu.&lt;br /&gt;
* Hooks are located in lib.php. Try to keep lib.php as small as possible as this file is included on every page. Put classes and functions elsewhere.&lt;br /&gt;
* Course navigation extension example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function tool_devcourse_extend_navigation_course($navigation, $course, $coursecontext) {&lt;br /&gt;
    $url = new moodle_url(&#039;/admin/tool/devcourse/index.php&#039;);&lt;br /&gt;
    $devcoursenode = navigation_node::create(&#039;Development course&#039;, $url, navigation_node::TYPE_CUSTOM, &#039;Dev course&#039;, &#039;devcourse&#039;);&lt;br /&gt;
    $navigation-&amp;gt;add_node($devcoursenode);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Navigation API]]&lt;br /&gt;
* [[:en:Navigation]]&lt;br /&gt;
&lt;br /&gt;
===Database queries===&lt;br /&gt;
* Moodle has a generic database query library. Behind this library are additional libraries which allow Moodle to work with MySQL, PostgreSQL, Oracle, SQL Server, and Maria DB.&lt;br /&gt;
* Where possible it is advisable to use the predefined functions rather than write out SQL. Writing SQL has a greater chance of not working with one of the supported databases.&lt;br /&gt;
* The return of the select functions tends to be an object or an array of objects.&lt;br /&gt;
&lt;br /&gt;
Example call to retrieve data from the course table.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
global $DB;&lt;br /&gt;
$courses = $DB-&amp;gt;get_records(&#039;course&#039;, null, &#039;&#039;, &#039;id, category, fullname, shortname&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Example of data returned from the above code.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Array&lt;br /&gt;
(&lt;br /&gt;
    [43] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 43&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; XX -Test 5&lt;br /&gt;
            [shortname] =&amp;gt; xxt5&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    [5] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 5&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; With the glossary&lt;br /&gt;
            [shortname] =&amp;gt; wtg&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    [39] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 39&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; XX - Test 1&lt;br /&gt;
            [shortname] =&amp;gt; xxt1&lt;br /&gt;
        )&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Database]]&lt;br /&gt;
* [[Data manipulation API]]&lt;br /&gt;
&lt;br /&gt;
===Creating your own database tables===&lt;br /&gt;
* We create our database tables in Moodle using the  XMLDB editor. This is located in the administration block &amp;quot;Site administration | Development | XMLDB editor&amp;quot;.&lt;br /&gt;
* The {plugin}\db directory needs to have write access for the XMLDB editor to be most effective.&lt;br /&gt;
* XMLDB editor creates an install.xml file in the db directory. This file will be loaded during the install to create your tables.&lt;br /&gt;
* XMLDB editor will produce php update code for adding and updating moodle database tables.&lt;br /&gt;
&lt;br /&gt;
The XMLDB main page.&lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:xmldb-main.png]]&lt;br /&gt;
&lt;br /&gt;
Upgrade code generated by the XMLDB&lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:xmldb-upgrade-code.png]]&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[XMLDB editor]]&lt;br /&gt;
* [[Using XMLDB]]&lt;br /&gt;
* [[XMLDB Documentation]]&lt;br /&gt;
* [[Upgrade API]]&lt;br /&gt;
* [[XMLDB introduction]]&lt;br /&gt;
&lt;br /&gt;
===Supporting access permissions: roles, capabilities and contexts===&lt;br /&gt;
* Capabilities are controlled in &amp;quot;access.php&amp;quot; under the &amp;quot;db&amp;quot; directory.&lt;br /&gt;
* This file has an array of capabilities with the following:&lt;br /&gt;
** name&lt;br /&gt;
** possible security risks behind giving this capability.&lt;br /&gt;
** The context that this capability works in.&lt;br /&gt;
** The default roles (teacher, manager, student, etc) that have this capability.&lt;br /&gt;
** Various other information.&lt;br /&gt;
* These capabilities are checked in code to allow access to pages, sections, and abilities (saving, deleting, etc).&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[Access API]]&lt;br /&gt;
* [[Roles#Context]]&lt;br /&gt;
* [[:en:Category:Capabilities]]&lt;br /&gt;
* [[:en:Roles and permissions]]&lt;br /&gt;
&lt;br /&gt;
===Adding web forms===&lt;br /&gt;
* Moodle has it&#039;s own forms library.&lt;br /&gt;
* The forms lib includes a lot of accessibility code, and error checking, by default.&lt;br /&gt;
* Moodle forms can be displayed in JavaScript using &#039;fragments&#039;.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Form API]]&lt;br /&gt;
* [[lib/formslib.php Form Definition]]&lt;br /&gt;
* [[Fragment]]&lt;br /&gt;
&lt;br /&gt;
===Maintaining good security===&lt;br /&gt;
* Use the sesskey when directing to pages to do actions.&lt;br /&gt;
* Use the appropriate filters when retrieving parameters&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[lib/formslib.php Form Definition#Most Commonly Used PARAM .2A Types]]&lt;br /&gt;
* [[Output functions#p.28.29 and s.28.29]]&lt;br /&gt;
&lt;br /&gt;
===Handling files===&lt;br /&gt;
* Files are conceptually stored in file areas.&lt;br /&gt;
* Plugins can only access files from it&#039;s own component.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[File API]]&lt;br /&gt;
* [[File API internals]]&lt;br /&gt;
* [[Using the File API in Moodle forms]]&lt;br /&gt;
&lt;br /&gt;
===Adding Javascript===&lt;br /&gt;
* Moodle is currently using jquery and AMD (Asynchronous Module Definition).&lt;br /&gt;
* JavaScript files are located in the &amp;quot;amd/src&amp;quot; directory.&lt;br /&gt;
* Use grunt to build your JavaScript.&lt;br /&gt;
* Include your JavaScript in php files as follows:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;requires-&amp;gt;js_call_amd(&#039;{JScriptfilename}&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* Can also be included in mustache templates.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Javascript Modules]]&lt;br /&gt;
* [[jQuery]]&lt;br /&gt;
* [[Javascript FAQ]]&lt;br /&gt;
* [[JavaScript guidelines]]&lt;br /&gt;
* [[Grunt]]&lt;br /&gt;
&lt;br /&gt;
===Adding events and logging===&lt;br /&gt;
* All logging in moodle is done through the events system.&lt;br /&gt;
* New events should be located in the &amp;quot;classes/event&amp;quot; directory.&lt;br /&gt;
* It is possible to create observers and subscribe to events.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Event 2]]&lt;br /&gt;
* [[Logging 2]]&lt;br /&gt;
&lt;br /&gt;
===Accessibility===&lt;br /&gt;
&lt;br /&gt;
Accessibility is an important consideration while developing a plugin to make sure your plugin is accessible to all users and doesn&#039;t discriminate against users with disablities. This often is a mandated requirement in many countries. The links below explain common practices that we follow at Moodle to make the interface more accessible.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[Accessibility]]&lt;br /&gt;
* [[Usability]]&lt;br /&gt;
===Web Services and AJAX===&lt;br /&gt;
* Moodle web services uses the external functions API.&lt;br /&gt;
* The recommended way to make AJAX requests is to use the ajax AMD file which uses the external functions API.&lt;br /&gt;
* External functions should be located in the &amp;quot;classes/external.php&amp;quot; file.&lt;br /&gt;
* A list of services should be included in &amp;quot;db/services.php&amp;quot;. This file is required to register the web services with Moodle.&lt;br /&gt;
* The services list is an array which contains:&lt;br /&gt;
** &#039;&#039;&#039;classname&#039;&#039;&#039; Name of the external class.&lt;br /&gt;
** &#039;&#039;&#039;methodname&#039;&#039;&#039; The name of the external function.&lt;br /&gt;
** &#039;&#039;&#039;classpath&#039;&#039;&#039; system path to the external function file.&lt;br /&gt;
** &#039;&#039;&#039;description&#039;&#039;&#039; Description of the function&lt;br /&gt;
** &#039;&#039;&#039;type&#039;&#039;&#039; Create, read, update, delete&lt;br /&gt;
** &#039;&#039;&#039;ajax&#039;&#039;&#039; Can this function be used with ajax?&lt;br /&gt;
** &#039;&#039;&#039;capabilities&#039;&#039;&#039; Capabilities required to use this function.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[External functions API]]&lt;br /&gt;
* [[Adding a web service to a plugin]]&lt;br /&gt;
* [[Web services API]]&lt;br /&gt;
&lt;br /&gt;
===Using caching to improve performance===&lt;br /&gt;
* The main cache used by moodle is the Moodle Universal Cache (MUC).&lt;br /&gt;
* The MUC has several cache definitions - &lt;br /&gt;
** Request cache&lt;br /&gt;
** Session cache&lt;br /&gt;
** Application&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[The Moodle Universal Cache (MUC)]]&lt;br /&gt;
* [[:en:MUC FAQ]]&lt;br /&gt;
* [[:en:Caching]]&lt;br /&gt;
&lt;br /&gt;
===Supporting backup and restore===&lt;br /&gt;
* Supporting backup and restore requires creating several files in the &#039;backup/moodle2&#039; directory.&lt;br /&gt;
* Back requires a class to extend the backup_task of some sort. There may be a specific plugin task to extend.&lt;br /&gt;
* Restore requires a class to extend the restore_task of some sort. There may be a specific plugin task to extend.&lt;br /&gt;
* The restore steps lib defines the structure of the plugin to be restored.&lt;br /&gt;
* The backup steps lib defines steps, settings, attributes, etc.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Backup 2.0 for developers]] - provides an example of step-by-step implementation of backup support to your plugin&lt;br /&gt;
* [[:en:Backup and restore FAQ]]&lt;br /&gt;
&lt;br /&gt;
===Supporting automated testing===&lt;br /&gt;
* Moodle has two types of automated testing: php unit tests, and behat tests.&lt;br /&gt;
* Unit tests are for testing functions.&lt;br /&gt;
* Behat tests runs through scenarios.&lt;br /&gt;
** Behat tests follows a script and navigates through moodle pages.&lt;br /&gt;
* unit tests should be located in the &amp;quot;tests&amp;quot; directory.&lt;br /&gt;
* behat tests should be located in the &amp;quot;tests/behat&amp;quot; directory.&lt;br /&gt;
* Tests located in these directories will be run through when a full test run is initiated.&lt;br /&gt;
* behat tests are actually feature files and end with the extension &amp;quot;.feature&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Writing PHPUnit tests]]&lt;br /&gt;
* [[PHPUnit]]&lt;br /&gt;
* [[Acceptance testing]]&lt;br /&gt;
* [[Behat integration]]&lt;br /&gt;
&lt;br /&gt;
==Publishing your plugin==&lt;br /&gt;
===Adding your plugin to moodle.org===&lt;br /&gt;
* publish your plugins at https://moodle.org/plugins/&lt;br /&gt;
* Publishing plugins on the moodle site leads you through a bunch of steps that need to be completed in order for the plugin to be approved and published.&lt;br /&gt;
* Plugins will be run through a pre-checker to give suggestions about possible issues with the code.&lt;br /&gt;
&lt;br /&gt;
===Supporting your plugin===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=TODO=&lt;br /&gt;
&lt;br /&gt;
Finishing this tutorial:&lt;br /&gt;
# About one or two screens for each section with a very generic overview for beginners, containing links to relevant docs WITH COMMENTS ABOUT QUALITY, USEFULNESS, CAVEATS etc.&lt;br /&gt;
# Go through all the linked pages and make sure they are current and accurate.&lt;br /&gt;
# Add a worked example to this page, so that each section has suggestions about things to add to the admin tool being built as an exercise.  If the code is long, it could be placed on separate pages.  A good reference for style is [[Moodle_Mobile_Developing_a_plugin_tutorial]] and [[Blocks]].&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* See [https://moodle.org/mod/forum/discuss.php?d=352360 this forum thread] about Getting Started with Moodle Development.&lt;br /&gt;
&lt;br /&gt;
=See also these older tutorials =&lt;br /&gt;
* [[Blocks|A Step-by-step Guide To Creating Blocks]] &lt;br /&gt;
* [[NEWMODULE Tutorial]]&lt;br /&gt;
* [http://dev.moodle.org Introduction to Moodle programming (based on Moodle 1.8)]&lt;br /&gt;
* [[Moodle_Mobile_Developing_a_plugin_tutorial|Moodle Mobile plugin tutorial]]&lt;br /&gt;
* [[Category:Tutorial|Other tutorials in these docs]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Tutorial]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=52841</id>
		<title>Tutorial</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=52841"/>
		<updated>2017-08-23T06:07:47Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* Browser end points */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Welcome to Moodle development!&lt;br /&gt;
&lt;br /&gt;
This is a tutorial to help you learn how to write plugins for Moodle from start to finish, while showing you how to navigate the most important developer documentation along the way.&lt;br /&gt;
&lt;br /&gt;
PRE-REQUISITES:  We assume you are fairly comfortable with [[PHP FAQ|PHP]] in general and that you are able to [[:en:Installing AMP|install a database and web server]] on your local machine. &lt;br /&gt;
&lt;br /&gt;
If you need to learn PHP, you can see one PHP tutorial at http://www.w3schools.com/php/default.asp, another at http://php.net/manual/en/tutorial.php and several videos in YouTube at https://www.youtube.com/results?search_query=learn+php. There is a very old unmaintained Introduction to Moodle 1.8 Programming course at http://dev.moodle.org/course/view.php?id=2.&lt;br /&gt;
&lt;br /&gt;
Code examples can be found on GitHub at https://github.com/abgreeve/devcourse where a working plugin is located.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
===What&#039;s in the box===&lt;br /&gt;
If you [http://download.moodle.org/ download] Moodle source code or clone it from [https://github.com/moodle/moodle git], you will see a bunch of files and folders. This code consists of [[Core_APIs|Moodle core]] (that consists of the Very core and Core components), [[Moodle_libraries_credits|third party libraries]] and [[Plugin_types|plugins]]. Their mixed locations can be quite confusing at first but as you start working with it it will become more clear. Moodle developers should avoid modifications of the third party libraries (unless required) and core can never call methods defined in plugins. See also [[Communication Between Components]]&lt;br /&gt;
&lt;br /&gt;
===Setting up your development environment===&lt;br /&gt;
* Moodle uses Git for developement. View the link below for basic information about Git and Moodle.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Git for developers]]&lt;br /&gt;
&lt;br /&gt;
===The Moodle development framework===&lt;br /&gt;
===What type of plugin are you developing?===&lt;br /&gt;
* Moodle has lots of different types of plugins.&lt;br /&gt;
* There are 24 different categories of plugin listed on the moodle plugin database. Before starting check here to see if someone else has not already created what you are looking for. Perhaps you could contribute to their plugin instead of creating a new one.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* https://moodle.org/plugins/&lt;br /&gt;
* [[Plugin types]]&lt;br /&gt;
&lt;br /&gt;
==Let&#039;s make a plugin==&lt;br /&gt;
===The skeleton of your plugin===&lt;br /&gt;
&lt;br /&gt;
You plugin code will be organised into multiple files within a single root directory (and the subdirectories).&lt;br /&gt;
&lt;br /&gt;
The page [[Plugin files]] provides a list of common plugins files and their purpose.&lt;br /&gt;
&lt;br /&gt;
See also:&lt;br /&gt;
&lt;br /&gt;
* [[Moodle architecture]] - general overview of Moodle code architecture&lt;br /&gt;
* [[Plugin types]] - list of all supported plugin types&lt;br /&gt;
* [https://moodle.org/plugins/ Moodle plugins directory] - repository of contributed plugins for Moodle&lt;br /&gt;
* [https://moodle.org/plugins/tool_pluginskel Moodle plugin skeleton generator] - allows to quickly generate code skeleton for a new plugin&lt;br /&gt;
&lt;br /&gt;
===Basic page structure===&lt;br /&gt;
&lt;br /&gt;
The link below explains how to create and display a simple page in Moodle.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Page API]]&lt;br /&gt;
&lt;br /&gt;
===How to support over 100 languages===&lt;br /&gt;
* Language files are stored in the &amp;quot;lang&amp;quot; directory. English strings would be found in &amp;quot;lang/en&amp;quot;. Each language contains a file named after the plugin which contains all of the strings. For example the language strings for the assignment activity are found in &amp;quot;mod/assign/lang/en/assign.php&amp;quot;.&lt;br /&gt;
* [[:en:Language FAQ#Which_is_the_official_language_for_Moodle.3F| Moodle&#039;s default is Australian English]]. &lt;br /&gt;
** American English is a separate language pack (en_us). Please use only Australian (UK) English grammar and spelling when writing Moodle plugins.&lt;br /&gt;
** There is no need to include languages other than the default English, as almost all approved [https://lang.moodle.org/mod/forum/discuss.php?d=2485 plugin strings will be automatically imported into AMOS] for translation by the language packs translators.  &lt;br /&gt;
* get_string() is used in most cases for displaying text.&lt;br /&gt;
* lang_string() is used in situations where the text may not necessarily be displayed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Declaration in language file (lang/en/{pluginname}.php)&lt;br /&gt;
$string[&#039;nameofstring&#039;] = &#039;Actual string&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The get_string() function takes four parameters, but in this example we are only filling in the first two. The last two parameters are optional. The first parameter is the identifier for the string. The second is the component.&lt;br /&gt;
The component will be the name of the language file.&lt;br /&gt;
The following example shows a string in the badges block.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Use of string in code.&lt;br /&gt;
echo html_writer::tag(&#039;p&#039;, get_string(&#039;numbadgestodisplay&#039;, &#039;block_badges&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[String API]]&lt;br /&gt;
* [[Places to search for lang strings]]&lt;br /&gt;
* [[:en:Language customisation]]&lt;br /&gt;
* [[Plugin contribution checklist#Strings]]&lt;br /&gt;
&lt;br /&gt;
===Moodle file structure===&lt;br /&gt;
==== Automatic Class Loading ====&lt;br /&gt;
Moodle supports automatic class loading. See the link below for the explanation of rules associated with it - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Automatic class loading]]&lt;br /&gt;
&lt;br /&gt;
==== Callbacks ====&lt;br /&gt;
You can add a lot of features to your plugin by providing certain callbacks that Moodle expects to be present in your plugin&#039;s lib.php file. A detailed list can be found at - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Callbacks ]]&lt;br /&gt;
&lt;br /&gt;
==== Plugin types ====&lt;br /&gt;
Moodle supports a wide range of plugin types. The complete list can be found at - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Plugin types ]]&lt;br /&gt;
&lt;br /&gt;
==== Core APIs ====&lt;br /&gt;
The link below lists all major core apis in Moodle - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Core APIs ]]&lt;br /&gt;
&lt;br /&gt;
==== Browser accessible pages ====&lt;br /&gt;
Any php file in your plugin will either be browser accessible or be an internal file. &lt;br /&gt;
&lt;br /&gt;
For browser accessible pages you must include config.php with code something similar to this - &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once(&#039;../../config.php&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For internal files the code should use the following - &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Add content to your page===&lt;br /&gt;
* Content for a page is added through renderers.&lt;br /&gt;
* Renderers are typically stored in the &amp;quot;classes/output&amp;quot; directory.&lt;br /&gt;
* Putting content in renderers allows themers to override the visual display of the content.&lt;br /&gt;
* Very basic information is presented using the html_writer class.&lt;br /&gt;
* In most cases templates should be used.&lt;br /&gt;
* templates are stored in the &amp;quot;templates&amp;quot; directory. The templates use mustache files.&lt;br /&gt;
* Mustache files allow for more generic html with placeholders inserted, that inserts the data (context) at run time.&lt;br /&gt;
&lt;br /&gt;
The example used below is an admin tool and would be located under admin/tool.&lt;br /&gt;
&lt;br /&gt;
Step One: Create a class for rendering. This class collects information to display and has a method for formatting that information into a format that the template will understand.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/classes/output/developer_course_main_page.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace tool_devcourse\output;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
use renderable;&lt;br /&gt;
use renderer_base;&lt;br /&gt;
use templatable;&lt;br /&gt;
use stdClass;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class developer_course_main_page implements renderable, templatable {&lt;br /&gt;
&lt;br /&gt;
   protected $comment;&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Construct this renderable.&lt;br /&gt;
     * @param int $courseid The course record for this page.&lt;br /&gt;
     */&lt;br /&gt;
    public function __construct($comment) {&lt;br /&gt;
        $this-&amp;gt;comment = $comment;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Export this data so it can be used as the context for a mustache template.&lt;br /&gt;
     *&lt;br /&gt;
     * @param renderer_base $output Renderer base.&lt;br /&gt;
     * @return stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function export_for_template(renderer_base $output) {&lt;br /&gt;
        $data = new stdClass();&lt;br /&gt;
        $data-&amp;gt;comment = $this-&amp;gt;comment;&lt;br /&gt;
        return $data;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Step Two: To render this information a custom renderer is created for the plugin. This renderer class must extend plugin_renderer_base.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/classes/output/renderer.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace tool_devcourse\output;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
use plugin_renderer_base;&lt;br /&gt;
use renderable;&lt;br /&gt;
&lt;br /&gt;
class renderer extends plugin_renderer_base {&lt;br /&gt;
&lt;br /&gt;
     /**&lt;br /&gt;
     * Defer to template.&lt;br /&gt;
     *&lt;br /&gt;
     * @param developer_course_main_page $page&lt;br /&gt;
     *&lt;br /&gt;
     * @return string html for the page&lt;br /&gt;
     */&lt;br /&gt;
    public function render_developer_course_main_page(developer_course_main_page $page) {&lt;br /&gt;
        $data = $page-&amp;gt;export_for_template($this);&lt;br /&gt;
        return parent::render_from_template(&#039;tool_devcourse/developer_course_main_page&#039;, $data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Step three: A mustache template is to then be created. The information is sent to the template and at this point the information is known as the context (not to be confused with the normal definition of context throughout Moodle).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/templates/developer_course_main_page.mustache&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code html&amp;gt;&lt;br /&gt;
{{!&lt;br /&gt;
    @template tool_devcourse/developer_course_main_page&lt;br /&gt;
&lt;br /&gt;
    Example context (json):&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;comment&amp;quot;: &amp;quot;Example comment for the context&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;h2&amp;gt;{{#str}}maintitle, tool_devdoc{{/str}}&amp;lt;/h2&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;{{comment}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This shows an extremely simple mustache template with one item in the context (comment). It also shows how strings are defined in the template.&lt;br /&gt;
&lt;br /&gt;
Step four: To actually have this template be displayed we get the custom renderer. This chunk of code would be located in a place such as devcourse/index.php after the appropriate setup outlined in the [[Tutorial#Basic_page_structure|basic page structure]].&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$output = $PAGE-&amp;gt;get_renderer(&#039;tool_devcourse&#039;);&lt;br /&gt;
//Then we get the class for rendering and provide it with information (if needed).&lt;br /&gt;
$randomcomment = &#039;This comment is random&#039;;&lt;br /&gt;
$page = new \tool_devdoc\output\developer_course_main_page($randomcomment);&lt;br /&gt;
//Finally we echo out the template&lt;br /&gt;
echo $output-&amp;gt;render($page);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Output API]]&lt;br /&gt;
* [[Output functions]]&lt;br /&gt;
* [[Templates]]&lt;br /&gt;
* [[Output renderers]]&lt;br /&gt;
* [[Renderer]]&lt;br /&gt;
* [[Overriding a renderer]]&lt;br /&gt;
&lt;br /&gt;
===Adding your plugin into Moodle&#039;s navigation===&lt;br /&gt;
* The moodle navigation system has hooks which allows plugins to add links to the navigation menu.&lt;br /&gt;
* Hooks are located in lib.php. Try to keep lib.php as small as possible as this file is included on every page. Put classes and functions elsewhere.&lt;br /&gt;
* Course navigation extension example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function tool_devcourse_extend_navigation_course($navigation, $course, $coursecontext) {&lt;br /&gt;
    $url = new moodle_url(&#039;/admin/tool/devcourse/index.php&#039;);&lt;br /&gt;
    $devcoursenode = navigation_node::create(&#039;Development course&#039;, $url, navigation_node::TYPE_CUSTOM, &#039;Dev course&#039;, &#039;devcourse&#039;);&lt;br /&gt;
    $navigation-&amp;gt;add_node($devcoursenode);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Navigation API]]&lt;br /&gt;
* [[:en:Navigation]]&lt;br /&gt;
&lt;br /&gt;
===Database queries===&lt;br /&gt;
* Moodle has a generic database query library. Behind this library are additional libraries which allow Moodle to work with MySQL, PostgreSQL, Oracle, SQL Server, and Maria DB.&lt;br /&gt;
* Where possible it is advisable to use the predefined functions rather than write out SQL. Writing SQL has a greater chance of not working with one of the supported databases.&lt;br /&gt;
* The return of the select functions tends to be an object or an array of objects.&lt;br /&gt;
&lt;br /&gt;
Example call to retrieve data from the course table.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
global $DB;&lt;br /&gt;
$courses = $DB-&amp;gt;get_records(&#039;course&#039;, null, &#039;&#039;, &#039;id, category, fullname, shortname&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Example of data returned from the above code.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Array&lt;br /&gt;
(&lt;br /&gt;
    [43] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 43&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; XX -Test 5&lt;br /&gt;
            [shortname] =&amp;gt; xxt5&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    [5] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 5&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; With the glossary&lt;br /&gt;
            [shortname] =&amp;gt; wtg&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    [39] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 39&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; XX - Test 1&lt;br /&gt;
            [shortname] =&amp;gt; xxt1&lt;br /&gt;
        )&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Database]]&lt;br /&gt;
* [[Data manipulation API]]&lt;br /&gt;
&lt;br /&gt;
===Creating your own database tables===&lt;br /&gt;
* We create our database tables in Moodle using the  XMLDB editor. This is located in the administration block &amp;quot;Site administration | Development | XMLDB editor&amp;quot;.&lt;br /&gt;
* The {plugin}\db directory needs to have write access for the XMLDB editor to be most effective.&lt;br /&gt;
* XMLDB editor creates an install.xml file in the db directory. This file will be loaded during the install to create your tables.&lt;br /&gt;
* XMLDB editor will produce php update code for adding and updating moodle database tables.&lt;br /&gt;
&lt;br /&gt;
The XMLDB main page.&lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:xmldb-main.png]]&lt;br /&gt;
&lt;br /&gt;
Upgrade code generated by the XMLDB&lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:xmldb-upgrade-code.png]]&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[XMLDB editor]]&lt;br /&gt;
* [[Using XMLDB]]&lt;br /&gt;
* [[XMLDB Documentation]]&lt;br /&gt;
* [[Upgrade API]]&lt;br /&gt;
* [[XMLDB introduction]]&lt;br /&gt;
&lt;br /&gt;
===Supporting access permissions: roles, capabilities and contexts===&lt;br /&gt;
* Capabilities are controlled in &amp;quot;access.php&amp;quot; under the &amp;quot;db&amp;quot; directory.&lt;br /&gt;
* This file has an array of capabilities with the following:&lt;br /&gt;
** name&lt;br /&gt;
** possible security risks behind giving this capability.&lt;br /&gt;
** The context that this capability works in.&lt;br /&gt;
** The default roles (teacher, manager, student, etc) that have this capability.&lt;br /&gt;
** Various other information.&lt;br /&gt;
* These capabilities are checked in code to allow access to pages, sections, and abilities (saving, deleting, etc).&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[Access API]]&lt;br /&gt;
* [[Roles#Context]]&lt;br /&gt;
* [[:en:Category:Capabilities]]&lt;br /&gt;
* [[:en:Roles and permissions]]&lt;br /&gt;
&lt;br /&gt;
===Adding web forms===&lt;br /&gt;
* Moodle has it&#039;s own forms library.&lt;br /&gt;
* The forms lib includes a lot of accessibility code, and error checking, by default.&lt;br /&gt;
* Moodle forms can be displayed in JavaScript using &#039;fragments&#039;.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Form API]]&lt;br /&gt;
* [[lib/formslib.php Form Definition]]&lt;br /&gt;
* [[Fragment]]&lt;br /&gt;
&lt;br /&gt;
===Maintaining good security===&lt;br /&gt;
* Use the sesskey when directing to pages to do actions.&lt;br /&gt;
* Use the appropriate filters when retrieving parameters&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[lib/formslib.php Form Definition#Most Commonly Used PARAM .2A Types]]&lt;br /&gt;
* [[Output functions#p.28.29 and s.28.29]]&lt;br /&gt;
&lt;br /&gt;
===Handling files===&lt;br /&gt;
* Files are conceptually stored in file areas.&lt;br /&gt;
* Plugins can only access files from it&#039;s own component.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[File API]]&lt;br /&gt;
* [[File API internals]]&lt;br /&gt;
* [[Using the File API in Moodle forms]]&lt;br /&gt;
&lt;br /&gt;
===Adding Javascript===&lt;br /&gt;
* Moodle is currently using jquery and AMD (Asynchronous Module Definition).&lt;br /&gt;
* JavaScript files are located in the &amp;quot;amd/src&amp;quot; directory.&lt;br /&gt;
* Use grunt to build your JavaScript.&lt;br /&gt;
* Include your JavaScript in php files as follows:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;requires-&amp;gt;js_call_amd(&#039;{JScriptfilename}&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* Can also be included in mustache templates.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Javascript Modules]]&lt;br /&gt;
* [[jQuery]]&lt;br /&gt;
* [[Javascript FAQ]]&lt;br /&gt;
* [[JavaScript guidelines]]&lt;br /&gt;
* [[Grunt]]&lt;br /&gt;
&lt;br /&gt;
===Adding events and logging===&lt;br /&gt;
* All logging in moodle is done through the events system.&lt;br /&gt;
* New events should be located in the &amp;quot;classes/event&amp;quot; directory.&lt;br /&gt;
* It is possible to create observers and subscribe to events.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Event 2]]&lt;br /&gt;
* [[Logging 2]]&lt;br /&gt;
&lt;br /&gt;
===Accessibility===&lt;br /&gt;
&lt;br /&gt;
Accessibility is an important consideration while developing a plugin to make sure your plugin is accessible to all users and doesn&#039;t discriminate against users with disablities. This often is a mandated requirement in many countries. The links below explain common practices that we follow at Moodle to make the interface more accessible.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[Accessibility]]&lt;br /&gt;
* [[Usability]]&lt;br /&gt;
===Web Services and AJAX===&lt;br /&gt;
* Moodle web services uses the external functions API.&lt;br /&gt;
* The recommended way to make AJAX requests is to use the ajax AMD file which uses the external functions API.&lt;br /&gt;
* External functions should be located in the &amp;quot;classes/external.php&amp;quot; file.&lt;br /&gt;
* A list of services should be included in &amp;quot;db/services.php&amp;quot;. This file is required to register the web services with Moodle.&lt;br /&gt;
* The services list is an array which contains:&lt;br /&gt;
** &#039;&#039;&#039;classname&#039;&#039;&#039; Name of the external class.&lt;br /&gt;
** &#039;&#039;&#039;methodname&#039;&#039;&#039; The name of the external function.&lt;br /&gt;
** &#039;&#039;&#039;classpath&#039;&#039;&#039; system path to the external function file.&lt;br /&gt;
** &#039;&#039;&#039;description&#039;&#039;&#039; Description of the function&lt;br /&gt;
** &#039;&#039;&#039;type&#039;&#039;&#039; Create, read, update, delete&lt;br /&gt;
** &#039;&#039;&#039;ajax&#039;&#039;&#039; Can this function be used with ajax?&lt;br /&gt;
** &#039;&#039;&#039;capabilities&#039;&#039;&#039; Capabilities required to use this function.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[External functions API]]&lt;br /&gt;
* [[Adding a web service to a plugin]]&lt;br /&gt;
* [[Web services API]]&lt;br /&gt;
&lt;br /&gt;
===Using caching to improve performance===&lt;br /&gt;
* The main cache used by moodle is the Moodle Universal Cache (MUC).&lt;br /&gt;
* The MUC has several cache definitions - &lt;br /&gt;
** Request cache&lt;br /&gt;
** Session cache&lt;br /&gt;
** Application&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[The Moodle Universal Cache (MUC)]]&lt;br /&gt;
* [[:en:MUC FAQ]]&lt;br /&gt;
* [[:en:Caching]]&lt;br /&gt;
&lt;br /&gt;
===Supporting backup and restore===&lt;br /&gt;
* Supporting backup and restore requires creating several files in the &#039;backup/moodle2&#039; directory.&lt;br /&gt;
* Back requires a class to extend the backup_task of some sort. There may be a specific plugin task to extend.&lt;br /&gt;
* Restore requires a class to extend the restore_task of some sort. There may be a specific plugin task to extend.&lt;br /&gt;
* The restore steps lib defines the structure of the plugin to be restored.&lt;br /&gt;
* The backup steps lib defines steps, settings, attributes, etc.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Backup 2.0 for developers]] - provides an example of step-by-step implementation of backup support to your plugin&lt;br /&gt;
* [[:en:Backup and restore FAQ]]&lt;br /&gt;
&lt;br /&gt;
===Supporting automated testing===&lt;br /&gt;
* Moodle has two types of automated testing: php unit tests, and behat tests.&lt;br /&gt;
* Unit tests are for testing functions.&lt;br /&gt;
* Behat tests runs through scenarios.&lt;br /&gt;
** Behat tests follows a script and navigates through moodle pages.&lt;br /&gt;
* unit tests should be located in the &amp;quot;tests&amp;quot; directory.&lt;br /&gt;
* behat tests should be located in the &amp;quot;tests/behat&amp;quot; directory.&lt;br /&gt;
* Tests located in these directories will be run through when a full test run is initiated.&lt;br /&gt;
* behat tests are actually feature files and end with the extension &amp;quot;.feature&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Writing PHPUnit tests]]&lt;br /&gt;
* [[PHPUnit]]&lt;br /&gt;
* [[Acceptance testing]]&lt;br /&gt;
* [[Behat integration]]&lt;br /&gt;
&lt;br /&gt;
==Publishing your plugin==&lt;br /&gt;
===Adding your plugin to moodle.org===&lt;br /&gt;
* publish your plugins at https://moodle.org/plugins/&lt;br /&gt;
* Publishing plugins on the moodle site leads you through a bunch of steps that need to be completed in order for the plugin to be approved and published.&lt;br /&gt;
* Plugins will be run through a pre-checker to give suggestions about possible issues with the code.&lt;br /&gt;
&lt;br /&gt;
===Supporting your plugin===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=TODO=&lt;br /&gt;
&lt;br /&gt;
Finishing this tutorial:&lt;br /&gt;
# About one or two screens for each section with a very generic overview for beginners, containing links to relevant docs WITH COMMENTS ABOUT QUALITY, USEFULNESS, CAVEATS etc.&lt;br /&gt;
# Go through all the linked pages and make sure they are current and accurate.&lt;br /&gt;
# Add a worked example to this page, so that each section has suggestions about things to add to the admin tool being built as an exercise.  If the code is long, it could be placed on separate pages.  A good reference for style is [[Moodle_Mobile_Developing_a_plugin_tutorial]] and [[Blocks]].&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* See [https://moodle.org/mod/forum/discuss.php?d=352360 this forum thread] about Getting Started with Moodle Development.&lt;br /&gt;
&lt;br /&gt;
=See also these older tutorials =&lt;br /&gt;
* [[Blocks|A Step-by-step Guide To Creating Blocks]] &lt;br /&gt;
* [[NEWMODULE Tutorial]]&lt;br /&gt;
* [http://dev.moodle.org Introduction to Moodle programming (based on Moodle 1.8)]&lt;br /&gt;
* [[Moodle_Mobile_Developing_a_plugin_tutorial|Moodle Mobile plugin tutorial]]&lt;br /&gt;
* [[Category:Tutorial|Other tutorials in these docs]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Tutorial]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=52840</id>
		<title>Tutorial</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=52840"/>
		<updated>2017-08-22T17:31:27Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* Moodle file structure */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Welcome to Moodle development!&lt;br /&gt;
&lt;br /&gt;
This is a tutorial to help you learn how to write plugins for Moodle from start to finish, while showing you how to navigate the most important developer documentation along the way.&lt;br /&gt;
&lt;br /&gt;
PRE-REQUISITES:  We assume you are fairly comfortable with [[PHP FAQ|PHP]] in general and that you are able to [[:en:Installing AMP|install a database and web server]] on your local machine. &lt;br /&gt;
&lt;br /&gt;
If you need to learn PHP, you can see one PHP tutorial at http://www.w3schools.com/php/default.asp, another at http://php.net/manual/en/tutorial.php and several videos in YouTube at https://www.youtube.com/results?search_query=learn+php. There is a very old unmaintained Introduction to Moodle 1.8 Programming course at http://dev.moodle.org/course/view.php?id=2.&lt;br /&gt;
&lt;br /&gt;
Code examples can be found on GitHub at https://github.com/abgreeve/devcourse where a working plugin is located.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
===What&#039;s in the box===&lt;br /&gt;
If you [http://download.moodle.org/ download] Moodle source code or clone it from [https://github.com/moodle/moodle git], you will see a bunch of files and folders. This code consists of [[Core_APIs|Moodle core]] (that consists of the Very core and Core components), [[Moodle_libraries_credits|third party libraries]] and [[Plugin_types|plugins]]. Their mixed locations can be quite confusing at first but as you start working with it it will become more clear. Moodle developers should avoid modifications of the third party libraries (unless required) and core can never call methods defined in plugins. See also [[Communication Between Components]]&lt;br /&gt;
&lt;br /&gt;
===Setting up your development environment===&lt;br /&gt;
* Moodle uses Git for developement. View the link below for basic information about Git and Moodle.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Git for developers]]&lt;br /&gt;
&lt;br /&gt;
===The Moodle development framework===&lt;br /&gt;
===What type of plugin are you developing?===&lt;br /&gt;
* Moodle has lots of different types of plugins.&lt;br /&gt;
* There are 24 different categories of plugin listed on the moodle plugin database. Before starting check here to see if someone else has not already created what you are looking for. Perhaps you could contribute to their plugin instead of creating a new one.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* https://moodle.org/plugins/&lt;br /&gt;
* [[Plugin types]]&lt;br /&gt;
&lt;br /&gt;
==Let&#039;s make a plugin==&lt;br /&gt;
===The skeleton of your plugin===&lt;br /&gt;
&lt;br /&gt;
You plugin code will be organised into multiple files within a single root directory (and the subdirectories).&lt;br /&gt;
&lt;br /&gt;
The page [[Plugin files]] provides a list of common plugins files and their purpose.&lt;br /&gt;
&lt;br /&gt;
See also:&lt;br /&gt;
&lt;br /&gt;
* [[Moodle architecture]] - general overview of Moodle code architecture&lt;br /&gt;
* [[Plugin types]] - list of all supported plugin types&lt;br /&gt;
* [https://moodle.org/plugins/ Moodle plugins directory] - repository of contributed plugins for Moodle&lt;br /&gt;
* [https://moodle.org/plugins/tool_pluginskel Moodle plugin skeleton generator] - allows to quickly generate code skeleton for a new plugin&lt;br /&gt;
&lt;br /&gt;
===Basic page structure===&lt;br /&gt;
&lt;br /&gt;
The link below explains how to create and display a simple page in Moodle.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Page API]]&lt;br /&gt;
&lt;br /&gt;
===How to support over 100 languages===&lt;br /&gt;
* Language files are stored in the &amp;quot;lang&amp;quot; directory. English strings would be found in &amp;quot;lang/en&amp;quot;. Each language contains a file named after the plugin which contains all of the strings. For example the language strings for the assignment activity are found in &amp;quot;mod/assign/lang/en/assign.php&amp;quot;.&lt;br /&gt;
* [[:en:Language FAQ#Which_is_the_official_language_for_Moodle.3F| Moodle&#039;s default is Australian English]]. &lt;br /&gt;
** American English is a separate language pack (en_us). Please use only Australian (UK) English grammar and spelling when writing Moodle plugins.&lt;br /&gt;
** There is no need to include languages other than the default English, as almost all approved [https://lang.moodle.org/mod/forum/discuss.php?d=2485 plugin strings will be automatically imported into AMOS] for translation by the language packs translators.  &lt;br /&gt;
* get_string() is used in most cases for displaying text.&lt;br /&gt;
* lang_string() is used in situations where the text may not necessarily be displayed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Declaration in language file (lang/en/{pluginname}.php)&lt;br /&gt;
$string[&#039;nameofstring&#039;] = &#039;Actual string&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The get_string() function takes four parameters, but in this example we are only filling in the first two. The last two parameters are optional. The first parameter is the identifier for the string. The second is the component.&lt;br /&gt;
The component will be the name of the language file.&lt;br /&gt;
The following example shows a string in the badges block.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Use of string in code.&lt;br /&gt;
echo html_writer::tag(&#039;p&#039;, get_string(&#039;numbadgestodisplay&#039;, &#039;block_badges&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[String API]]&lt;br /&gt;
* [[Places to search for lang strings]]&lt;br /&gt;
* [[:en:Language customisation]]&lt;br /&gt;
* [[Plugin contribution checklist#Strings]]&lt;br /&gt;
&lt;br /&gt;
===Moodle file structure===&lt;br /&gt;
==== Automatic Class Loading ====&lt;br /&gt;
Moodle supports automatic class loading. See the link below for the explanation of rules associated with it - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Automatic class loading]]&lt;br /&gt;
&lt;br /&gt;
==== Callbacks ====&lt;br /&gt;
You can add a lot of features to your plugin by providing certain callbacks that Moodle expects to be present in your plugin&#039;s lib.php file. A detailed list can be found at - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Callbacks ]]&lt;br /&gt;
&lt;br /&gt;
==== Plugin types ====&lt;br /&gt;
Moodle supports a wide range of plugin types. The complete list can be found at - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Plugin types ]]&lt;br /&gt;
&lt;br /&gt;
==== Core APIs ====&lt;br /&gt;
The link below lists all major core apis in Moodle - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Core APIs ]]&lt;br /&gt;
&lt;br /&gt;
==== Browser end points ====&lt;br /&gt;
Any php file in your plugin will either be an end point for browser entry or be an internal file. &lt;br /&gt;
&lt;br /&gt;
For end points you must include config.php with code something similar to this - &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once(&#039;../../config.php&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For internal files the code should use the following - &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Add content to your page===&lt;br /&gt;
* Content for a page is added through renderers.&lt;br /&gt;
* Renderers are typically stored in the &amp;quot;classes/output&amp;quot; directory.&lt;br /&gt;
* Putting content in renderers allows themers to override the visual display of the content.&lt;br /&gt;
* Very basic information is presented using the html_writer class.&lt;br /&gt;
* In most cases templates should be used.&lt;br /&gt;
* templates are stored in the &amp;quot;templates&amp;quot; directory. The templates use mustache files.&lt;br /&gt;
* Mustache files allow for more generic html with placeholders inserted, that inserts the data (context) at run time.&lt;br /&gt;
&lt;br /&gt;
The example used below is an admin tool and would be located under admin/tool.&lt;br /&gt;
&lt;br /&gt;
Step One: Create a class for rendering. This class collects information to display and has a method for formatting that information into a format that the template will understand.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/classes/output/developer_course_main_page.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace tool_devcourse\output;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
use renderable;&lt;br /&gt;
use renderer_base;&lt;br /&gt;
use templatable;&lt;br /&gt;
use stdClass;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class developer_course_main_page implements renderable, templatable {&lt;br /&gt;
&lt;br /&gt;
   protected $comment;&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Construct this renderable.&lt;br /&gt;
     * @param int $courseid The course record for this page.&lt;br /&gt;
     */&lt;br /&gt;
    public function __construct($comment) {&lt;br /&gt;
        $this-&amp;gt;comment = $comment;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Export this data so it can be used as the context for a mustache template.&lt;br /&gt;
     *&lt;br /&gt;
     * @param renderer_base $output Renderer base.&lt;br /&gt;
     * @return stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function export_for_template(renderer_base $output) {&lt;br /&gt;
        $data = new stdClass();&lt;br /&gt;
        $data-&amp;gt;comment = $this-&amp;gt;comment;&lt;br /&gt;
        return $data;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Step Two: To render this information a custom renderer is created for the plugin. This renderer class must extend plugin_renderer_base.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/classes/output/renderer.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace tool_devcourse\output;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
use plugin_renderer_base;&lt;br /&gt;
use renderable;&lt;br /&gt;
&lt;br /&gt;
class renderer extends plugin_renderer_base {&lt;br /&gt;
&lt;br /&gt;
     /**&lt;br /&gt;
     * Defer to template.&lt;br /&gt;
     *&lt;br /&gt;
     * @param developer_course_main_page $page&lt;br /&gt;
     *&lt;br /&gt;
     * @return string html for the page&lt;br /&gt;
     */&lt;br /&gt;
    public function render_developer_course_main_page(developer_course_main_page $page) {&lt;br /&gt;
        $data = $page-&amp;gt;export_for_template($this);&lt;br /&gt;
        return parent::render_from_template(&#039;tool_devcourse/developer_course_main_page&#039;, $data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Step three: A mustache template is to then be created. The information is sent to the template and at this point the information is known as the context (not to be confused with the normal definition of context throughout Moodle).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/templates/developer_course_main_page.mustache&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code html&amp;gt;&lt;br /&gt;
{{!&lt;br /&gt;
    @template tool_devcourse/developer_course_main_page&lt;br /&gt;
&lt;br /&gt;
    Example context (json):&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;comment&amp;quot;: &amp;quot;Example comment for the context&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;h2&amp;gt;{{#str}}maintitle, tool_devdoc{{/str}}&amp;lt;/h2&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;{{comment}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This shows an extremely simple mustache template with one item in the context (comment). It also shows how strings are defined in the template.&lt;br /&gt;
&lt;br /&gt;
Step four: To actually have this template be displayed we get the custom renderer. This chunk of code would be located in a place such as devcourse/index.php after the appropriate setup outlined in the [[Tutorial#Basic_page_structure|basic page structure]].&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$output = $PAGE-&amp;gt;get_renderer(&#039;tool_devcourse&#039;);&lt;br /&gt;
//Then we get the class for rendering and provide it with information (if needed).&lt;br /&gt;
$randomcomment = &#039;This comment is random&#039;;&lt;br /&gt;
$page = new \tool_devdoc\output\developer_course_main_page($randomcomment);&lt;br /&gt;
//Finally we echo out the template&lt;br /&gt;
echo $output-&amp;gt;render($page);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Output API]]&lt;br /&gt;
* [[Output functions]]&lt;br /&gt;
* [[Templates]]&lt;br /&gt;
* [[Output renderers]]&lt;br /&gt;
* [[Renderer]]&lt;br /&gt;
* [[Overriding a renderer]]&lt;br /&gt;
&lt;br /&gt;
===Adding your plugin into Moodle&#039;s navigation===&lt;br /&gt;
* The moodle navigation system has hooks which allows plugins to add links to the navigation menu.&lt;br /&gt;
* Hooks are located in lib.php. Try to keep lib.php as small as possible as this file is included on every page. Put classes and functions elsewhere.&lt;br /&gt;
* Course navigation extension example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function tool_devcourse_extend_navigation_course($navigation, $course, $coursecontext) {&lt;br /&gt;
    $url = new moodle_url(&#039;/admin/tool/devcourse/index.php&#039;);&lt;br /&gt;
    $devcoursenode = navigation_node::create(&#039;Development course&#039;, $url, navigation_node::TYPE_CUSTOM, &#039;Dev course&#039;, &#039;devcourse&#039;);&lt;br /&gt;
    $navigation-&amp;gt;add_node($devcoursenode);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Navigation API]]&lt;br /&gt;
* [[:en:Navigation]]&lt;br /&gt;
&lt;br /&gt;
===Database queries===&lt;br /&gt;
* Moodle has a generic database query library. Behind this library are additional libraries which allow Moodle to work with MySQL, PostgreSQL, Oracle, SQL Server, and Maria DB.&lt;br /&gt;
* Where possible it is advisable to use the predefined functions rather than write out SQL. Writing SQL has a greater chance of not working with one of the supported databases.&lt;br /&gt;
* The return of the select functions tends to be an object or an array of objects.&lt;br /&gt;
&lt;br /&gt;
Example call to retrieve data from the course table.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
global $DB;&lt;br /&gt;
$courses = $DB-&amp;gt;get_records(&#039;course&#039;, null, &#039;&#039;, &#039;id, category, fullname, shortname&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Example of data returned from the above code.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Array&lt;br /&gt;
(&lt;br /&gt;
    [43] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 43&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; XX -Test 5&lt;br /&gt;
            [shortname] =&amp;gt; xxt5&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    [5] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 5&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; With the glossary&lt;br /&gt;
            [shortname] =&amp;gt; wtg&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    [39] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 39&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; XX - Test 1&lt;br /&gt;
            [shortname] =&amp;gt; xxt1&lt;br /&gt;
        )&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Database]]&lt;br /&gt;
* [[Data manipulation API]]&lt;br /&gt;
&lt;br /&gt;
===Creating your own database tables===&lt;br /&gt;
* We create our database tables in Moodle using the  XMLDB editor. This is located in the administration block &amp;quot;Site administration | Development | XMLDB editor&amp;quot;.&lt;br /&gt;
* The {plugin}\db directory needs to have write access for the XMLDB editor to be most effective.&lt;br /&gt;
* XMLDB editor creates an install.xml file in the db directory. This file will be loaded during the install to create your tables.&lt;br /&gt;
* XMLDB editor will produce php update code for adding and updating moodle database tables.&lt;br /&gt;
&lt;br /&gt;
The XMLDB main page.&lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:xmldb-main.png]]&lt;br /&gt;
&lt;br /&gt;
Upgrade code generated by the XMLDB&lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:xmldb-upgrade-code.png]]&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[XMLDB editor]]&lt;br /&gt;
* [[Using XMLDB]]&lt;br /&gt;
* [[XMLDB Documentation]]&lt;br /&gt;
* [[Upgrade API]]&lt;br /&gt;
* [[XMLDB introduction]]&lt;br /&gt;
&lt;br /&gt;
===Supporting access permissions: roles, capabilities and contexts===&lt;br /&gt;
* Capabilities are controlled in &amp;quot;access.php&amp;quot; under the &amp;quot;db&amp;quot; directory.&lt;br /&gt;
* This file has an array of capabilities with the following:&lt;br /&gt;
** name&lt;br /&gt;
** possible security risks behind giving this capability.&lt;br /&gt;
** The context that this capability works in.&lt;br /&gt;
** The default roles (teacher, manager, student, etc) that have this capability.&lt;br /&gt;
** Various other information.&lt;br /&gt;
* These capabilities are checked in code to allow access to pages, sections, and abilities (saving, deleting, etc).&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[Access API]]&lt;br /&gt;
* [[Roles#Context]]&lt;br /&gt;
* [[:en:Category:Capabilities]]&lt;br /&gt;
* [[:en:Roles and permissions]]&lt;br /&gt;
&lt;br /&gt;
===Adding web forms===&lt;br /&gt;
* Moodle has it&#039;s own forms library.&lt;br /&gt;
* The forms lib includes a lot of accessibility code, and error checking, by default.&lt;br /&gt;
* Moodle forms can be displayed in JavaScript using &#039;fragments&#039;.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Form API]]&lt;br /&gt;
* [[lib/formslib.php Form Definition]]&lt;br /&gt;
* [[Fragment]]&lt;br /&gt;
&lt;br /&gt;
===Maintaining good security===&lt;br /&gt;
* Use the sesskey when directing to pages to do actions.&lt;br /&gt;
* Use the appropriate filters when retrieving parameters&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[lib/formslib.php Form Definition#Most Commonly Used PARAM .2A Types]]&lt;br /&gt;
* [[Output functions#p.28.29 and s.28.29]]&lt;br /&gt;
&lt;br /&gt;
===Handling files===&lt;br /&gt;
* Files are conceptually stored in file areas.&lt;br /&gt;
* Plugins can only access files from it&#039;s own component.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[File API]]&lt;br /&gt;
* [[File API internals]]&lt;br /&gt;
* [[Using the File API in Moodle forms]]&lt;br /&gt;
&lt;br /&gt;
===Adding Javascript===&lt;br /&gt;
* Moodle is currently using jquery and AMD (Asynchronous Module Definition).&lt;br /&gt;
* JavaScript files are located in the &amp;quot;amd/src&amp;quot; directory.&lt;br /&gt;
* Use grunt to build your JavaScript.&lt;br /&gt;
* Include your JavaScript in php files as follows:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;requires-&amp;gt;js_call_amd(&#039;{JScriptfilename}&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* Can also be included in mustache templates.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Javascript Modules]]&lt;br /&gt;
* [[jQuery]]&lt;br /&gt;
* [[Javascript FAQ]]&lt;br /&gt;
* [[JavaScript guidelines]]&lt;br /&gt;
* [[Grunt]]&lt;br /&gt;
&lt;br /&gt;
===Adding events and logging===&lt;br /&gt;
* All logging in moodle is done through the events system.&lt;br /&gt;
* New events should be located in the &amp;quot;classes/event&amp;quot; directory.&lt;br /&gt;
* It is possible to create observers and subscribe to events.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Event 2]]&lt;br /&gt;
* [[Logging 2]]&lt;br /&gt;
&lt;br /&gt;
===Accessibility===&lt;br /&gt;
&lt;br /&gt;
Accessibility is an important consideration while developing a plugin to make sure your plugin is accessible to all users and doesn&#039;t discriminate against users with disablities. This often is a mandated requirement in many countries. The links below explain common practices that we follow at Moodle to make the interface more accessible.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[Accessibility]]&lt;br /&gt;
* [[Usability]]&lt;br /&gt;
===Web Services and AJAX===&lt;br /&gt;
* Moodle web services uses the external functions API.&lt;br /&gt;
* The recommended way to make AJAX requests is to use the ajax AMD file which uses the external functions API.&lt;br /&gt;
* External functions should be located in the &amp;quot;classes/external.php&amp;quot; file.&lt;br /&gt;
* A list of services should be included in &amp;quot;db/services.php&amp;quot;. This file is required to register the web services with Moodle.&lt;br /&gt;
* The services list is an array which contains:&lt;br /&gt;
** &#039;&#039;&#039;classname&#039;&#039;&#039; Name of the external class.&lt;br /&gt;
** &#039;&#039;&#039;methodname&#039;&#039;&#039; The name of the external function.&lt;br /&gt;
** &#039;&#039;&#039;classpath&#039;&#039;&#039; system path to the external function file.&lt;br /&gt;
** &#039;&#039;&#039;description&#039;&#039;&#039; Description of the function&lt;br /&gt;
** &#039;&#039;&#039;type&#039;&#039;&#039; Create, read, update, delete&lt;br /&gt;
** &#039;&#039;&#039;ajax&#039;&#039;&#039; Can this function be used with ajax?&lt;br /&gt;
** &#039;&#039;&#039;capabilities&#039;&#039;&#039; Capabilities required to use this function.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[External functions API]]&lt;br /&gt;
* [[Adding a web service to a plugin]]&lt;br /&gt;
* [[Web services API]]&lt;br /&gt;
&lt;br /&gt;
===Using caching to improve performance===&lt;br /&gt;
* The main cache used by moodle is the Moodle Universal Cache (MUC).&lt;br /&gt;
* The MUC has several cache definitions - &lt;br /&gt;
** Request cache&lt;br /&gt;
** Session cache&lt;br /&gt;
** Application&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[The Moodle Universal Cache (MUC)]]&lt;br /&gt;
* [[:en:MUC FAQ]]&lt;br /&gt;
* [[:en:Caching]]&lt;br /&gt;
&lt;br /&gt;
===Supporting backup and restore===&lt;br /&gt;
* Supporting backup and restore requires creating several files in the &#039;backup/moodle2&#039; directory.&lt;br /&gt;
* Back requires a class to extend the backup_task of some sort. There may be a specific plugin task to extend.&lt;br /&gt;
* Restore requires a class to extend the restore_task of some sort. There may be a specific plugin task to extend.&lt;br /&gt;
* The restore steps lib defines the structure of the plugin to be restored.&lt;br /&gt;
* The backup steps lib defines steps, settings, attributes, etc.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Backup 2.0 for developers]] - provides an example of step-by-step implementation of backup support to your plugin&lt;br /&gt;
* [[:en:Backup and restore FAQ]]&lt;br /&gt;
&lt;br /&gt;
===Supporting automated testing===&lt;br /&gt;
* Moodle has two types of automated testing: php unit tests, and behat tests.&lt;br /&gt;
* Unit tests are for testing functions.&lt;br /&gt;
* Behat tests runs through scenarios.&lt;br /&gt;
** Behat tests follows a script and navigates through moodle pages.&lt;br /&gt;
* unit tests should be located in the &amp;quot;tests&amp;quot; directory.&lt;br /&gt;
* behat tests should be located in the &amp;quot;tests/behat&amp;quot; directory.&lt;br /&gt;
* Tests located in these directories will be run through when a full test run is initiated.&lt;br /&gt;
* behat tests are actually feature files and end with the extension &amp;quot;.feature&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Writing PHPUnit tests]]&lt;br /&gt;
* [[PHPUnit]]&lt;br /&gt;
* [[Acceptance testing]]&lt;br /&gt;
* [[Behat integration]]&lt;br /&gt;
&lt;br /&gt;
==Publishing your plugin==&lt;br /&gt;
===Adding your plugin to moodle.org===&lt;br /&gt;
* publish your plugins at https://moodle.org/plugins/&lt;br /&gt;
* Publishing plugins on the moodle site leads you through a bunch of steps that need to be completed in order for the plugin to be approved and published.&lt;br /&gt;
* Plugins will be run through a pre-checker to give suggestions about possible issues with the code.&lt;br /&gt;
&lt;br /&gt;
===Supporting your plugin===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=TODO=&lt;br /&gt;
&lt;br /&gt;
Finishing this tutorial:&lt;br /&gt;
# About one or two screens for each section with a very generic overview for beginners, containing links to relevant docs WITH COMMENTS ABOUT QUALITY, USEFULNESS, CAVEATS etc.&lt;br /&gt;
# Go through all the linked pages and make sure they are current and accurate.&lt;br /&gt;
# Add a worked example to this page, so that each section has suggestions about things to add to the admin tool being built as an exercise.  If the code is long, it could be placed on separate pages.  A good reference for style is [[Moodle_Mobile_Developing_a_plugin_tutorial]] and [[Blocks]].&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* See [https://moodle.org/mod/forum/discuss.php?d=352360 this forum thread] about Getting Started with Moodle Development.&lt;br /&gt;
&lt;br /&gt;
=See also these older tutorials =&lt;br /&gt;
* [[Blocks|A Step-by-step Guide To Creating Blocks]] &lt;br /&gt;
* [[NEWMODULE Tutorial]]&lt;br /&gt;
* [http://dev.moodle.org Introduction to Moodle programming (based on Moodle 1.8)]&lt;br /&gt;
* [[Moodle_Mobile_Developing_a_plugin_tutorial|Moodle Mobile plugin tutorial]]&lt;br /&gt;
* [[Category:Tutorial|Other tutorials in these docs]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Tutorial]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=52839</id>
		<title>Tutorial</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=52839"/>
		<updated>2017-08-22T05:46:32Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Welcome to Moodle development!&lt;br /&gt;
&lt;br /&gt;
This is a tutorial to help you learn how to write plugins for Moodle from start to finish, while showing you how to navigate the most important developer documentation along the way.&lt;br /&gt;
&lt;br /&gt;
PRE-REQUISITES:  We assume you are fairly comfortable with [[PHP FAQ|PHP]] in general and that you are able to [[:en:Installing AMP|install a database and web server]] on your local machine. &lt;br /&gt;
&lt;br /&gt;
If you need to learn PHP, you can see one PHP tutorial at http://www.w3schools.com/php/default.asp, another at http://php.net/manual/en/tutorial.php and several videos in YouTube at https://www.youtube.com/results?search_query=learn+php. There is a very old unmaintained Introduction to Moodle 1.8 Programming course at http://dev.moodle.org/course/view.php?id=2.&lt;br /&gt;
&lt;br /&gt;
Code examples can be found on GitHub at https://github.com/abgreeve/devcourse where a working plugin is located.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
===What&#039;s in the box===&lt;br /&gt;
If you [http://download.moodle.org/ download] Moodle source code or clone it from [https://github.com/moodle/moodle git], you will see a bunch of files and folders. This code consists of [[Core_APIs|Moodle core]] (that consists of the Very core and Core components), [[Moodle_libraries_credits|third party libraries]] and [[Plugin_types|plugins]]. Their mixed locations can be quite confusing at first but as you start working with it it will become more clear. Moodle developers should avoid modifications of the third party libraries (unless required) and core can never call methods defined in plugins. See also [[Communication Between Components]]&lt;br /&gt;
&lt;br /&gt;
===Setting up your development environment===&lt;br /&gt;
* Moodle uses Git for developement. View the link below for basic information about Git and Moodle.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Git for developers]]&lt;br /&gt;
&lt;br /&gt;
===The Moodle development framework===&lt;br /&gt;
===What type of plugin are you developing?===&lt;br /&gt;
* Moodle has lots of different types of plugins.&lt;br /&gt;
* There are 24 different categories of plugin listed on the moodle plugin database. Before starting check here to see if someone else has not already created what you are looking for. Perhaps you could contribute to their plugin instead of creating a new one.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* https://moodle.org/plugins/&lt;br /&gt;
* [[Plugin types]]&lt;br /&gt;
&lt;br /&gt;
==Let&#039;s make a plugin==&lt;br /&gt;
===The skeleton of your plugin===&lt;br /&gt;
&lt;br /&gt;
You plugin code will be organised into multiple files within a single root directory (and the subdirectories).&lt;br /&gt;
&lt;br /&gt;
The page [[Plugin files]] provides a list of common plugins files and their purpose.&lt;br /&gt;
&lt;br /&gt;
See also:&lt;br /&gt;
&lt;br /&gt;
* [[Moodle architecture]] - general overview of Moodle code architecture&lt;br /&gt;
* [[Plugin types]] - list of all supported plugin types&lt;br /&gt;
* [https://moodle.org/plugins/ Moodle plugins directory] - repository of contributed plugins for Moodle&lt;br /&gt;
* [https://moodle.org/plugins/tool_pluginskel Moodle plugin skeleton generator] - allows to quickly generate code skeleton for a new plugin&lt;br /&gt;
&lt;br /&gt;
===Basic page structure===&lt;br /&gt;
&lt;br /&gt;
The link below explains how to create and display a simple page in Moodle.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Page API]]&lt;br /&gt;
&lt;br /&gt;
===How to support over 100 languages===&lt;br /&gt;
* Language files are stored in the &amp;quot;lang&amp;quot; directory. English strings would be found in &amp;quot;lang/en&amp;quot;. Each language contains a file named after the plugin which contains all of the strings. For example the language strings for the assignment activity are found in &amp;quot;mod/assign/lang/en/assign.php&amp;quot;.&lt;br /&gt;
* [[:en:Language FAQ#Which_is_the_official_language_for_Moodle.3F| Moodle&#039;s default is Australian English]]. &lt;br /&gt;
** American English is a separate language pack (en_us). Please use only Australian (UK) English grammar and spelling when writing Moodle plugins.&lt;br /&gt;
** There is no need to include languages other than the default English, as almost all approved [https://lang.moodle.org/mod/forum/discuss.php?d=2485 plugin strings will be automatically imported into AMOS] for translation by the language packs translators.  &lt;br /&gt;
* get_string() is used in most cases for displaying text.&lt;br /&gt;
* lang_string() is used in situations where the text may not necessarily be displayed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Declaration in language file (lang/en/{pluginname}.php)&lt;br /&gt;
$string[&#039;nameofstring&#039;] = &#039;Actual string&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The get_string() function takes four parameters, but in this example we are only filling in the first two. The last two parameters are optional. The first parameter is the identifier for the string. The second is the component.&lt;br /&gt;
The component will be the name of the language file.&lt;br /&gt;
The following example shows a string in the badges block.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Use of string in code.&lt;br /&gt;
echo html_writer::tag(&#039;p&#039;, get_string(&#039;numbadgestodisplay&#039;, &#039;block_badges&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[String API]]&lt;br /&gt;
* [[Places to search for lang strings]]&lt;br /&gt;
* [[:en:Language customisation]]&lt;br /&gt;
* [[Plugin contribution checklist#Strings]]&lt;br /&gt;
&lt;br /&gt;
===Moodle file structure===&lt;br /&gt;
==== Automatic Class Loading ====&lt;br /&gt;
Moodle supports automatic class loading. See the link below for the explanation of rules associated with it - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Automatic class loading]]&lt;br /&gt;
&lt;br /&gt;
==== Callbacks ====&lt;br /&gt;
You can add a lot of features to your plugin by providing certain callbacks that Moodle expects to be present in your plugin&#039;s lib.php file. A detailed list can be found at - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Callbacks ]]&lt;br /&gt;
&lt;br /&gt;
==== Plugin types ====&lt;br /&gt;
Moodle supports a wide range of plugin types. The complete list can be found at - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Plugin types ]]&lt;br /&gt;
&lt;br /&gt;
==== Core APIS ====&lt;br /&gt;
The link below lists all major core apis in Moodle - &lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
[[ Core APIs ]]&lt;br /&gt;
&lt;br /&gt;
===Add content to your page===&lt;br /&gt;
* Content for a page is added through renderers.&lt;br /&gt;
* Renderers are typically stored in the &amp;quot;classes/output&amp;quot; directory.&lt;br /&gt;
* Putting content in renderers allows themers to override the visual display of the content.&lt;br /&gt;
* Very basic information is presented using the html_writer class.&lt;br /&gt;
* In most cases templates should be used.&lt;br /&gt;
* templates are stored in the &amp;quot;templates&amp;quot; directory. The templates use mustache files.&lt;br /&gt;
* Mustache files allow for more generic html with placeholders inserted, that inserts the data (context) at run time.&lt;br /&gt;
&lt;br /&gt;
The example used below is an admin tool and would be located under admin/tool.&lt;br /&gt;
&lt;br /&gt;
Step One: Create a class for rendering. This class collects information to display and has a method for formatting that information into a format that the template will understand.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/classes/output/developer_course_main_page.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace tool_devcourse\output;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
use renderable;&lt;br /&gt;
use renderer_base;&lt;br /&gt;
use templatable;&lt;br /&gt;
use stdClass;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class developer_course_main_page implements renderable, templatable {&lt;br /&gt;
&lt;br /&gt;
   protected $comment;&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Construct this renderable.&lt;br /&gt;
     * @param int $courseid The course record for this page.&lt;br /&gt;
     */&lt;br /&gt;
    public function __construct($comment) {&lt;br /&gt;
        $this-&amp;gt;comment = $comment;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Export this data so it can be used as the context for a mustache template.&lt;br /&gt;
     *&lt;br /&gt;
     * @param renderer_base $output Renderer base.&lt;br /&gt;
     * @return stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function export_for_template(renderer_base $output) {&lt;br /&gt;
        $data = new stdClass();&lt;br /&gt;
        $data-&amp;gt;comment = $this-&amp;gt;comment;&lt;br /&gt;
        return $data;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Step Two: To render this information a custom renderer is created for the plugin. This renderer class must extend plugin_renderer_base.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/classes/output/renderer.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace tool_devcourse\output;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
use plugin_renderer_base;&lt;br /&gt;
use renderable;&lt;br /&gt;
&lt;br /&gt;
class renderer extends plugin_renderer_base {&lt;br /&gt;
&lt;br /&gt;
     /**&lt;br /&gt;
     * Defer to template.&lt;br /&gt;
     *&lt;br /&gt;
     * @param developer_course_main_page $page&lt;br /&gt;
     *&lt;br /&gt;
     * @return string html for the page&lt;br /&gt;
     */&lt;br /&gt;
    public function render_developer_course_main_page(developer_course_main_page $page) {&lt;br /&gt;
        $data = $page-&amp;gt;export_for_template($this);&lt;br /&gt;
        return parent::render_from_template(&#039;tool_devcourse/developer_course_main_page&#039;, $data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Step three: A mustache template is to then be created. The information is sent to the template and at this point the information is known as the context (not to be confused with the normal definition of context throughout Moodle).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/templates/developer_course_main_page.mustache&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code html&amp;gt;&lt;br /&gt;
{{!&lt;br /&gt;
    @template tool_devcourse/developer_course_main_page&lt;br /&gt;
&lt;br /&gt;
    Example context (json):&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;comment&amp;quot;: &amp;quot;Example comment for the context&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;h2&amp;gt;{{#str}}maintitle, tool_devdoc{{/str}}&amp;lt;/h2&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;{{comment}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This shows an extremely simple mustache template with one item in the context (comment). It also shows how strings are defined in the template.&lt;br /&gt;
&lt;br /&gt;
Step four: To actually have this template be displayed we get the custom renderer. This chunk of code would be located in a place such as devcourse/index.php after the appropriate setup outlined in the [[Tutorial#Basic_page_structure|basic page structure]].&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$output = $PAGE-&amp;gt;get_renderer(&#039;tool_devcourse&#039;);&lt;br /&gt;
//Then we get the class for rendering and provide it with information (if needed).&lt;br /&gt;
$randomcomment = &#039;This comment is random&#039;;&lt;br /&gt;
$page = new \tool_devdoc\output\developer_course_main_page($randomcomment);&lt;br /&gt;
//Finally we echo out the template&lt;br /&gt;
echo $output-&amp;gt;render($page);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Output API]]&lt;br /&gt;
* [[Output functions]]&lt;br /&gt;
* [[Templates]]&lt;br /&gt;
* [[Output renderers]]&lt;br /&gt;
* [[Renderer]]&lt;br /&gt;
* [[Overriding a renderer]]&lt;br /&gt;
&lt;br /&gt;
===Adding your plugin into Moodle&#039;s navigation===&lt;br /&gt;
* The moodle navigation system has hooks which allows plugins to add links to the navigation menu.&lt;br /&gt;
* Hooks are located in lib.php. Try to keep lib.php as small as possible as this file is included on every page. Put classes and functions elsewhere.&lt;br /&gt;
* Course navigation extension example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function tool_devcourse_extend_navigation_course($navigation, $course, $coursecontext) {&lt;br /&gt;
    $url = new moodle_url(&#039;/admin/tool/devcourse/index.php&#039;);&lt;br /&gt;
    $devcoursenode = navigation_node::create(&#039;Development course&#039;, $url, navigation_node::TYPE_CUSTOM, &#039;Dev course&#039;, &#039;devcourse&#039;);&lt;br /&gt;
    $navigation-&amp;gt;add_node($devcoursenode);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Navigation API]]&lt;br /&gt;
* [[:en:Navigation]]&lt;br /&gt;
&lt;br /&gt;
===Database queries===&lt;br /&gt;
* Moodle has a generic database query library. Behind this library are additional libraries which allow Moodle to work with MySQL, PostgreSQL, Oracle, SQL Server, and Maria DB.&lt;br /&gt;
* Where possible it is advisable to use the predefined functions rather than write out SQL. Writing SQL has a greater chance of not working with one of the supported databases.&lt;br /&gt;
* The return of the select functions tends to be an object or an array of objects.&lt;br /&gt;
&lt;br /&gt;
Example call to retrieve data from the course table.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
global $DB;&lt;br /&gt;
$courses = $DB-&amp;gt;get_records(&#039;course&#039;, null, &#039;&#039;, &#039;id, category, fullname, shortname&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Example of data returned from the above code.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Array&lt;br /&gt;
(&lt;br /&gt;
    [43] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 43&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; XX -Test 5&lt;br /&gt;
            [shortname] =&amp;gt; xxt5&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    [5] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 5&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; With the glossary&lt;br /&gt;
            [shortname] =&amp;gt; wtg&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    [39] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 39&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; XX - Test 1&lt;br /&gt;
            [shortname] =&amp;gt; xxt1&lt;br /&gt;
        )&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Database]]&lt;br /&gt;
* [[Data manipulation API]]&lt;br /&gt;
&lt;br /&gt;
===Creating your own database tables===&lt;br /&gt;
* We create our database tables in Moodle using the  XMLDB editor. This is located in the administration block &amp;quot;Site administration | Development | XMLDB editor&amp;quot;.&lt;br /&gt;
* The {plugin}\db directory needs to have write access for the XMLDB editor to be most effective.&lt;br /&gt;
* XMLDB editor creates an install.xml file in the db directory. This file will be loaded during the install to create your tables.&lt;br /&gt;
* XMLDB editor will produce php update code for adding and updating moodle database tables.&lt;br /&gt;
&lt;br /&gt;
The XMLDB main page.&lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:xmldb-main.png]]&lt;br /&gt;
&lt;br /&gt;
Upgrade code generated by the XMLDB&lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:xmldb-upgrade-code.png]]&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[XMLDB editor]]&lt;br /&gt;
* [[Using XMLDB]]&lt;br /&gt;
* [[XMLDB Documentation]]&lt;br /&gt;
* [[Upgrade API]]&lt;br /&gt;
* [[XMLDB introduction]]&lt;br /&gt;
&lt;br /&gt;
===Supporting access permissions: roles, capabilities and contexts===&lt;br /&gt;
* Capabilities are controlled in &amp;quot;access.php&amp;quot; under the &amp;quot;db&amp;quot; directory.&lt;br /&gt;
* This file has an array of capabilities with the following:&lt;br /&gt;
** name&lt;br /&gt;
** possible security risks behind giving this capability.&lt;br /&gt;
** The context that this capability works in.&lt;br /&gt;
** The default roles (teacher, manager, student, etc) that have this capability.&lt;br /&gt;
** Various other information.&lt;br /&gt;
* These capabilities are checked in code to allow access to pages, sections, and abilities (saving, deleting, etc).&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[Access API]]&lt;br /&gt;
* [[Roles#Context]]&lt;br /&gt;
* [[:en:Category:Capabilities]]&lt;br /&gt;
* [[:en:Roles and permissions]]&lt;br /&gt;
&lt;br /&gt;
===Adding web forms===&lt;br /&gt;
* Moodle has it&#039;s own forms library.&lt;br /&gt;
* The forms lib includes a lot of accessibility code, and error checking, by default.&lt;br /&gt;
* Moodle forms can be displayed in JavaScript using &#039;fragments&#039;.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Form API]]&lt;br /&gt;
* [[lib/formslib.php Form Definition]]&lt;br /&gt;
* [[Fragment]]&lt;br /&gt;
&lt;br /&gt;
===Maintaining good security===&lt;br /&gt;
* Use the sesskey when directing to pages to do actions.&lt;br /&gt;
* Use the appropriate filters when retrieving parameters&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[lib/formslib.php Form Definition#Most Commonly Used PARAM .2A Types]]&lt;br /&gt;
* [[Output functions#p.28.29 and s.28.29]]&lt;br /&gt;
&lt;br /&gt;
===Handling files===&lt;br /&gt;
* Files are conceptually stored in file areas.&lt;br /&gt;
* Plugins can only access files from it&#039;s own component.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[File API]]&lt;br /&gt;
* [[File API internals]]&lt;br /&gt;
* [[Using the File API in Moodle forms]]&lt;br /&gt;
&lt;br /&gt;
===Adding Javascript===&lt;br /&gt;
* Moodle is currently using jquery and AMD (Asynchronous Module Definition).&lt;br /&gt;
* JavaScript files are located in the &amp;quot;amd/src&amp;quot; directory.&lt;br /&gt;
* Use grunt to build your JavaScript.&lt;br /&gt;
* Include your JavaScript in php files as follows:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;requires-&amp;gt;js_call_amd(&#039;{JScriptfilename}&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* Can also be included in mustache templates.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Javascript Modules]]&lt;br /&gt;
* [[jQuery]]&lt;br /&gt;
* [[Javascript FAQ]]&lt;br /&gt;
* [[JavaScript guidelines]]&lt;br /&gt;
* [[Grunt]]&lt;br /&gt;
&lt;br /&gt;
===Adding events and logging===&lt;br /&gt;
* All logging in moodle is done through the events system.&lt;br /&gt;
* New events should be located in the &amp;quot;classes/event&amp;quot; directory.&lt;br /&gt;
* It is possible to create observers and subscribe to events.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Event 2]]&lt;br /&gt;
* [[Logging 2]]&lt;br /&gt;
&lt;br /&gt;
===Accessibility===&lt;br /&gt;
&lt;br /&gt;
Accessibility is an important consideration while developing a plugin to make sure your plugin is accessible to all users and doesn&#039;t discriminate against users with disablities. This often is a mandated requirement in many countries. The links below explain common practices that we follow at Moodle to make the interface more accessible.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[Accessibility]]&lt;br /&gt;
* [[Usability]]&lt;br /&gt;
===Web Services and AJAX===&lt;br /&gt;
* Moodle web services uses the external functions API.&lt;br /&gt;
* The recommended way to make AJAX requests is to use the ajax AMD file which uses the external functions API.&lt;br /&gt;
* External functions should be located in the &amp;quot;classes/external.php&amp;quot; file.&lt;br /&gt;
* A list of services should be included in &amp;quot;db/services.php&amp;quot;. This file is required to register the web services with Moodle.&lt;br /&gt;
* The services list is an array which contains:&lt;br /&gt;
** &#039;&#039;&#039;classname&#039;&#039;&#039; Name of the external class.&lt;br /&gt;
** &#039;&#039;&#039;methodname&#039;&#039;&#039; The name of the external function.&lt;br /&gt;
** &#039;&#039;&#039;classpath&#039;&#039;&#039; system path to the external function file.&lt;br /&gt;
** &#039;&#039;&#039;description&#039;&#039;&#039; Description of the function&lt;br /&gt;
** &#039;&#039;&#039;type&#039;&#039;&#039; Create, read, update, delete&lt;br /&gt;
** &#039;&#039;&#039;ajax&#039;&#039;&#039; Can this function be used with ajax?&lt;br /&gt;
** &#039;&#039;&#039;capabilities&#039;&#039;&#039; Capabilities required to use this function.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[External functions API]]&lt;br /&gt;
* [[Adding a web service to a plugin]]&lt;br /&gt;
* [[Web services API]]&lt;br /&gt;
&lt;br /&gt;
===Using caching to improve performance===&lt;br /&gt;
* The main cache used by moodle is the Moodle Universal Cache (MUC).&lt;br /&gt;
* The MUC has several cache definitions - &lt;br /&gt;
** Request cache&lt;br /&gt;
** Session cache&lt;br /&gt;
** Application&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[The Moodle Universal Cache (MUC)]]&lt;br /&gt;
* [[:en:MUC FAQ]]&lt;br /&gt;
* [[:en:Caching]]&lt;br /&gt;
&lt;br /&gt;
===Supporting backup and restore===&lt;br /&gt;
* Supporting backup and restore requires creating several files in the &#039;backup/moodle2&#039; directory.&lt;br /&gt;
* Back requires a class to extend the backup_task of some sort. There may be a specific plugin task to extend.&lt;br /&gt;
* Restore requires a class to extend the restore_task of some sort. There may be a specific plugin task to extend.&lt;br /&gt;
* The restore steps lib defines the structure of the plugin to be restored.&lt;br /&gt;
* The backup steps lib defines steps, settings, attributes, etc.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Backup 2.0 for developers]] - provides an example of step-by-step implementation of backup support to your plugin&lt;br /&gt;
* [[:en:Backup and restore FAQ]]&lt;br /&gt;
&lt;br /&gt;
===Supporting automated testing===&lt;br /&gt;
* Moodle has two types of automated testing: php unit tests, and behat tests.&lt;br /&gt;
* Unit tests are for testing functions.&lt;br /&gt;
* Behat tests runs through scenarios.&lt;br /&gt;
** Behat tests follows a script and navigates through moodle pages.&lt;br /&gt;
* unit tests should be located in the &amp;quot;tests&amp;quot; directory.&lt;br /&gt;
* behat tests should be located in the &amp;quot;tests/behat&amp;quot; directory.&lt;br /&gt;
* Tests located in these directories will be run through when a full test run is initiated.&lt;br /&gt;
* behat tests are actually feature files and end with the extension &amp;quot;.feature&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Writing PHPUnit tests]]&lt;br /&gt;
* [[PHPUnit]]&lt;br /&gt;
* [[Acceptance testing]]&lt;br /&gt;
* [[Behat integration]]&lt;br /&gt;
&lt;br /&gt;
==Publishing your plugin==&lt;br /&gt;
===Adding your plugin to moodle.org===&lt;br /&gt;
* publish your plugins at https://moodle.org/plugins/&lt;br /&gt;
* Publishing plugins on the moodle site leads you through a bunch of steps that need to be completed in order for the plugin to be approved and published.&lt;br /&gt;
* Plugins will be run through a pre-checker to give suggestions about possible issues with the code.&lt;br /&gt;
&lt;br /&gt;
===Supporting your plugin===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=TODO=&lt;br /&gt;
&lt;br /&gt;
Finishing this tutorial:&lt;br /&gt;
# About one or two screens for each section with a very generic overview for beginners, containing links to relevant docs WITH COMMENTS ABOUT QUALITY, USEFULNESS, CAVEATS etc.&lt;br /&gt;
# Go through all the linked pages and make sure they are current and accurate.&lt;br /&gt;
# Add a worked example to this page, so that each section has suggestions about things to add to the admin tool being built as an exercise.  If the code is long, it could be placed on separate pages.  A good reference for style is [[Moodle_Mobile_Developing_a_plugin_tutorial]] and [[Blocks]].&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* See [https://moodle.org/mod/forum/discuss.php?d=352360 this forum thread] about Getting Started with Moodle Development.&lt;br /&gt;
&lt;br /&gt;
=See also these older tutorials =&lt;br /&gt;
* [[Blocks|A Step-by-step Guide To Creating Blocks]] &lt;br /&gt;
* [[NEWMODULE Tutorial]]&lt;br /&gt;
* [http://dev.moodle.org Introduction to Moodle programming (based on Moodle 1.8)]&lt;br /&gt;
* [[Moodle_Mobile_Developing_a_plugin_tutorial|Moodle Mobile plugin tutorial]]&lt;br /&gt;
* [[Category:Tutorial|Other tutorials in these docs]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Tutorial]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=52838</id>
		<title>Tutorial</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=52838"/>
		<updated>2017-08-21T07:28:04Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Welcome to Moodle development!&lt;br /&gt;
&lt;br /&gt;
This is a tutorial to help you learn how to write plugins for Moodle from start to finish, while showing you how to navigate the most important developer documentation along the way.&lt;br /&gt;
&lt;br /&gt;
PRE-REQUISITES:  We assume you are fairly comfortable with [[PHP FAQ|PHP]] in general and that you are able to [[:en:Installing AMP|install a database and web server]] on your local machine. &lt;br /&gt;
&lt;br /&gt;
If you need to learn PHP, you can see one PHP tutorial at http://www.w3schools.com/php/default.asp, another at http://php.net/manual/en/tutorial.php and several videos in YouTube at https://www.youtube.com/results?search_query=learn+php. There is a very old unmaintained Introduction to Moodle 1.8 Programming course at http://dev.moodle.org/course/view.php?id=2.&lt;br /&gt;
&lt;br /&gt;
Code examples can be found on GitHub at https://github.com/abgreeve/devcourse where a working plugin is located.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
===What&#039;s in the box===&lt;br /&gt;
If you [http://download.moodle.org/ download] Moodle source code or clone it from [https://github.com/moodle/moodle git], you will see a bunch of files and folders. This code consists of [[Core_APIs|Moodle core]] (that consists of the Very core and Core components), [[Moodle_libraries_credits|third party libraries]] and [[Plugin_types|plugins]]. Their mixed locations can be quite confusing at first but as you start working with it it will become more clear. Moodle developers should avoid modifications of the third party libraries (unless required) and core can never call methods defined in plugins. See also [[Communication Between Components]]&lt;br /&gt;
&lt;br /&gt;
===Setting up your development environment===&lt;br /&gt;
* Moodle uses Git for developement. View the link below for basic information about Git and Moodle.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Git for developers]]&lt;br /&gt;
&lt;br /&gt;
===The Moodle development framework===&lt;br /&gt;
===What type of plugin are you developing?===&lt;br /&gt;
* Moodle has lots of different types of plugins.&lt;br /&gt;
* There are 24 different categories of plugin listed on the moodle plugin database. Before starting check here to see if someone else has not already created what you are looking for. Perhaps you could contribute to their plugin instead of creating a new one.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* https://moodle.org/plugins/&lt;br /&gt;
* [[Plugin types]]&lt;br /&gt;
&lt;br /&gt;
==Let&#039;s make a plugin==&lt;br /&gt;
===The skeleton of your plugin===&lt;br /&gt;
&lt;br /&gt;
You plugin code will be organised into multiple files within a single root directory (and the subdirectories).&lt;br /&gt;
&lt;br /&gt;
The page [[Plugin files]] provides a list of common plugins files and their purpose.&lt;br /&gt;
&lt;br /&gt;
See also:&lt;br /&gt;
&lt;br /&gt;
* [[Moodle architecture]] - general overview of Moodle code architecture&lt;br /&gt;
* [[Plugin types]] - list of all supported plugin types&lt;br /&gt;
* [https://moodle.org/plugins/ Moodle plugins directory] - repository of contributed plugins for Moodle&lt;br /&gt;
* [https://moodle.org/plugins/tool_pluginskel Moodle plugin skeleton generator] - allows to quickly generate code skeleton for a new plugin&lt;br /&gt;
&lt;br /&gt;
===Basic page structure===&lt;br /&gt;
&lt;br /&gt;
The link below explains how to create and display a simple page in Moodle.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Page API]]&lt;br /&gt;
&lt;br /&gt;
===How to support over 100 languages===&lt;br /&gt;
* Language files are stored in the &amp;quot;lang&amp;quot; directory. English strings would be found in &amp;quot;lang/en&amp;quot;. Each language contains a file named after the plugin which contains all of the strings. For example the language strings for the assignment activity are found in &amp;quot;mod/assign/lang/en/assign.php&amp;quot;.&lt;br /&gt;
* [[:en:Language FAQ#Which_is_the_official_language_for_Moodle.3F| Moodle&#039;s default is Australian English]]. &lt;br /&gt;
** American English is a separate language pack (en_us). Please use only Australian (UK) English grammar and spelling when writing Moodle plugins.&lt;br /&gt;
** There is no need to include languages other than the default English, as almost all approved [https://lang.moodle.org/mod/forum/discuss.php?d=2485 plugin strings will be automatically imported into AMOS] for translation by the language packs translators.  &lt;br /&gt;
* get_string() is used in most cases for displaying text.&lt;br /&gt;
* lang_string() is used in situations where the text may not necessarily be displayed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Declaration in language file (lang/en/{pluginname}.php)&lt;br /&gt;
$string[&#039;nameofstring&#039;] = &#039;Actual string&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The get_string() function takes four parameters, but in this example we are only filling in the first two. The last two parameters are optional. The first parameter is the identifier for the string. The second is the component.&lt;br /&gt;
The component will be the name of the language file.&lt;br /&gt;
The following example shows a string in the badges block.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Use of string in code.&lt;br /&gt;
echo html_writer::tag(&#039;p&#039;, get_string(&#039;numbadgestodisplay&#039;, &#039;block_badges&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[String API]]&lt;br /&gt;
* [[Places to search for lang strings]]&lt;br /&gt;
* [[:en:Language customisation]]&lt;br /&gt;
* [[Plugin contribution checklist#Strings]]&lt;br /&gt;
&lt;br /&gt;
===Add content to your page===&lt;br /&gt;
* Content for a page is added through renderers.&lt;br /&gt;
* Renderers are typically stored in the &amp;quot;classes/output&amp;quot; directory.&lt;br /&gt;
* Putting content in renderers allows themers to override the visual display of the content.&lt;br /&gt;
* Very basic information is presented using the html_writer class.&lt;br /&gt;
* In most cases templates should be used.&lt;br /&gt;
* templates are stored in the &amp;quot;templates&amp;quot; directory. The templates use mustache files.&lt;br /&gt;
* Mustache files allow for more generic html with placeholders inserted, that inserts the data (context) at run time.&lt;br /&gt;
&lt;br /&gt;
The example used below is an admin tool and would be located under admin/tool.&lt;br /&gt;
&lt;br /&gt;
Step One: Create a class for rendering. This class collects information to display and has a method for formatting that information into a format that the template will understand.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/classes/output/developer_course_main_page.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace tool_devcourse\output;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
use renderable;&lt;br /&gt;
use renderer_base;&lt;br /&gt;
use templatable;&lt;br /&gt;
use stdClass;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class developer_course_main_page implements renderable, templatable {&lt;br /&gt;
&lt;br /&gt;
   protected $comment;&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Construct this renderable.&lt;br /&gt;
     * @param int $courseid The course record for this page.&lt;br /&gt;
     */&lt;br /&gt;
    public function __construct($comment) {&lt;br /&gt;
        $this-&amp;gt;comment = $comment;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Export this data so it can be used as the context for a mustache template.&lt;br /&gt;
     *&lt;br /&gt;
     * @param renderer_base $output Renderer base.&lt;br /&gt;
     * @return stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function export_for_template(renderer_base $output) {&lt;br /&gt;
        $data = new stdClass();&lt;br /&gt;
        $data-&amp;gt;comment = $this-&amp;gt;comment;&lt;br /&gt;
        return $data;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Step Two: To render this information a custom renderer is created for the plugin. This renderer class must extend plugin_renderer_base.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/classes/output/renderer.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace tool_devcourse\output;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
use plugin_renderer_base;&lt;br /&gt;
use renderable;&lt;br /&gt;
&lt;br /&gt;
class renderer extends plugin_renderer_base {&lt;br /&gt;
&lt;br /&gt;
     /**&lt;br /&gt;
     * Defer to template.&lt;br /&gt;
     *&lt;br /&gt;
     * @param developer_course_main_page $page&lt;br /&gt;
     *&lt;br /&gt;
     * @return string html for the page&lt;br /&gt;
     */&lt;br /&gt;
    public function render_developer_course_main_page(developer_course_main_page $page) {&lt;br /&gt;
        $data = $page-&amp;gt;export_for_template($this);&lt;br /&gt;
        return parent::render_from_template(&#039;tool_devcourse/developer_course_main_page&#039;, $data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Step three: A mustache template is to then be created. The information is sent to the template and at this point the information is known as the context (not to be confused with the normal definition of context throughout Moodle).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/templates/developer_course_main_page.mustache&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code html&amp;gt;&lt;br /&gt;
{{!&lt;br /&gt;
    @template tool_devcourse/developer_course_main_page&lt;br /&gt;
&lt;br /&gt;
    Example context (json):&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;comment&amp;quot;: &amp;quot;Example comment for the context&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;h2&amp;gt;{{#str}}maintitle, tool_devdoc{{/str}}&amp;lt;/h2&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;{{comment}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This shows an extremely simple mustache template with one item in the context (comment). It also shows how strings are defined in the template.&lt;br /&gt;
&lt;br /&gt;
Step four: To actually have this template be displayed we get the custom renderer. This chunk of code would be located in a place such as devcourse/index.php after the appropriate setup outlined in the [[Tutorial#Basic_page_structure|basic page structure]].&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$output = $PAGE-&amp;gt;get_renderer(&#039;tool_devcourse&#039;);&lt;br /&gt;
//Then we get the class for rendering and provide it with information (if needed).&lt;br /&gt;
$randomcomment = &#039;This comment is random&#039;;&lt;br /&gt;
$page = new \tool_devdoc\output\developer_course_main_page($randomcomment);&lt;br /&gt;
//Finally we echo out the template&lt;br /&gt;
echo $output-&amp;gt;render($page);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Output API]]&lt;br /&gt;
* [[Output functions]]&lt;br /&gt;
* [[Templates]]&lt;br /&gt;
* [[Output renderers]]&lt;br /&gt;
* [[Renderer]]&lt;br /&gt;
* [[Overriding a renderer]]&lt;br /&gt;
&lt;br /&gt;
===Adding your plugin into Moodle&#039;s navigation===&lt;br /&gt;
* The moodle navigation system has hooks which allows plugins to add links to the navigation menu.&lt;br /&gt;
* Hooks are located in lib.php. Try to keep lib.php as small as possible as this file is included on every page. Put classes and functions elsewhere.&lt;br /&gt;
* Course navigation extension example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function tool_devcourse_extend_navigation_course($navigation, $course, $coursecontext) {&lt;br /&gt;
    $url = new moodle_url(&#039;/admin/tool/devcourse/index.php&#039;);&lt;br /&gt;
    $devcoursenode = navigation_node::create(&#039;Development course&#039;, $url, navigation_node::TYPE_CUSTOM, &#039;Dev course&#039;, &#039;devcourse&#039;);&lt;br /&gt;
    $navigation-&amp;gt;add_node($devcoursenode);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Navigation API]]&lt;br /&gt;
* [[:en:Navigation]]&lt;br /&gt;
&lt;br /&gt;
===Database queries===&lt;br /&gt;
* Moodle has a generic database query library. Behind this library are additional libraries which allow Moodle to work with MySQL, PostgreSQL, Oracle, SQL Server, and Maria DB.&lt;br /&gt;
* Where possible it is advisable to use the predefined functions rather than write out SQL. Writing SQL has a greater chance of not working with one of the supported databases.&lt;br /&gt;
* The return of the select functions tends to be an object or an array of objects.&lt;br /&gt;
&lt;br /&gt;
Example call to retrieve data from the course table.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
global $DB;&lt;br /&gt;
$courses = $DB-&amp;gt;get_records(&#039;course&#039;, null, &#039;&#039;, &#039;id, category, fullname, shortname&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Example of data returned from the above code.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Array&lt;br /&gt;
(&lt;br /&gt;
    [43] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 43&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; XX -Test 5&lt;br /&gt;
            [shortname] =&amp;gt; xxt5&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    [5] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 5&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; With the glossary&lt;br /&gt;
            [shortname] =&amp;gt; wtg&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    [39] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 39&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; XX - Test 1&lt;br /&gt;
            [shortname] =&amp;gt; xxt1&lt;br /&gt;
        )&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Database]]&lt;br /&gt;
* [[Data manipulation API]]&lt;br /&gt;
&lt;br /&gt;
===Creating your own database tables===&lt;br /&gt;
* We create our database tables in Moodle using the  XMLDB editor. This is located in the administration block &amp;quot;Site administration | Development | XMLDB editor&amp;quot;.&lt;br /&gt;
* The {plugin}\db directory needs to have write access for the XMLDB editor to be most effective.&lt;br /&gt;
* XMLDB editor creates an install.xml file in the db directory. This file will be loaded during the install to create your tables.&lt;br /&gt;
* XMLDB editor will produce php update code for adding and updating moodle database tables.&lt;br /&gt;
&lt;br /&gt;
The XMLDB main page.&lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:xmldb-main.png]]&lt;br /&gt;
&lt;br /&gt;
Upgrade code generated by the XMLDB&lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:xmldb-upgrade-code.png]]&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[XMLDB editor]]&lt;br /&gt;
* [[Using XMLDB]]&lt;br /&gt;
* [[XMLDB Documentation]]&lt;br /&gt;
* [[Upgrade API]]&lt;br /&gt;
* [[XMLDB introduction]]&lt;br /&gt;
&lt;br /&gt;
===Supporting access permissions: roles, capabilities and contexts===&lt;br /&gt;
* Capabilities are controlled in &amp;quot;access.php&amp;quot; under the &amp;quot;db&amp;quot; directory.&lt;br /&gt;
* This file has an array of capabilities with the following:&lt;br /&gt;
** name&lt;br /&gt;
** possible security risks behind giving this capability.&lt;br /&gt;
** The context that this capability works in.&lt;br /&gt;
** The default roles (teacher, manager, student, etc) that have this capability.&lt;br /&gt;
** Various other information.&lt;br /&gt;
* These capabilities are checked in code to allow access to pages, sections, and abilities (saving, deleting, etc).&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[Access API]]&lt;br /&gt;
* [[Roles#Context]]&lt;br /&gt;
* [[:en:Category:Capabilities]]&lt;br /&gt;
* [[:en:Roles and permissions]]&lt;br /&gt;
&lt;br /&gt;
===Adding web forms===&lt;br /&gt;
* Moodle has it&#039;s own forms library.&lt;br /&gt;
* The forms lib includes a lot of accessibility code, and error checking, by default.&lt;br /&gt;
* Moodle forms can be displayed in JavaScript using &#039;fragments&#039;.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Form API]]&lt;br /&gt;
* [[lib/formslib.php Form Definition]]&lt;br /&gt;
* [[Fragment]]&lt;br /&gt;
&lt;br /&gt;
===Maintaining good security===&lt;br /&gt;
* Use the sesskey when directing to pages to do actions.&lt;br /&gt;
* Use the appropriate filters when retrieving parameters&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[lib/formslib.php Form Definition#Most Commonly Used PARAM .2A Types]]&lt;br /&gt;
* [[Output functions#p.28.29 and s.28.29]]&lt;br /&gt;
&lt;br /&gt;
===Handling files===&lt;br /&gt;
* Files are conceptually stored in file areas.&lt;br /&gt;
* Plugins can only access files from it&#039;s own component.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[File API]]&lt;br /&gt;
* [[File API internals]]&lt;br /&gt;
* [[Using the File API in Moodle forms]]&lt;br /&gt;
&lt;br /&gt;
===Adding Javascript===&lt;br /&gt;
* Moodle is currently using jquery and AMD (Asynchronous Module Definition).&lt;br /&gt;
* JavaScript files are located in the &amp;quot;amd/src&amp;quot; directory.&lt;br /&gt;
* Use grunt to build your JavaScript.&lt;br /&gt;
* Include your JavaScript in php files as follows:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;requires-&amp;gt;js_call_amd(&#039;{JScriptfilename}&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* Can also be included in mustache templates.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Javascript Modules]]&lt;br /&gt;
* [[jQuery]]&lt;br /&gt;
* [[Javascript FAQ]]&lt;br /&gt;
* [[JavaScript guidelines]]&lt;br /&gt;
* [[Grunt]]&lt;br /&gt;
&lt;br /&gt;
===Adding events and logging===&lt;br /&gt;
* All logging in moodle is done through the events system.&lt;br /&gt;
* New events should be located in the &amp;quot;classes/event&amp;quot; directory.&lt;br /&gt;
* It is possible to create observers and subscribe to events.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Event 2]]&lt;br /&gt;
* [[Logging 2]]&lt;br /&gt;
&lt;br /&gt;
===Accessibility===&lt;br /&gt;
&lt;br /&gt;
Accessibility is an important consideration while developing a plugin to make sure your plugin is accessible to all users and doesn&#039;t discriminate against users with disablities. This often is a mandated requirement in many countries. The links below explain common practices that we follow at Moodle to make the interface more accessible.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[Accessibility]]&lt;br /&gt;
* [[Usability]]&lt;br /&gt;
===Web Services and AJAX===&lt;br /&gt;
* Moodle web services uses the external functions API.&lt;br /&gt;
* The recommended way to make AJAX requests is to use the ajax AMD file which uses the external functions API.&lt;br /&gt;
* External functions should be located in the &amp;quot;classes/external.php&amp;quot; file.&lt;br /&gt;
* A list of services should be included in &amp;quot;db/services.php&amp;quot;. This file is required to register the web services with Moodle.&lt;br /&gt;
* The services list is an array which contains:&lt;br /&gt;
** &#039;&#039;&#039;classname&#039;&#039;&#039; Name of the external class.&lt;br /&gt;
** &#039;&#039;&#039;methodname&#039;&#039;&#039; The name of the external function.&lt;br /&gt;
** &#039;&#039;&#039;classpath&#039;&#039;&#039; system path to the external function file.&lt;br /&gt;
** &#039;&#039;&#039;description&#039;&#039;&#039; Description of the function&lt;br /&gt;
** &#039;&#039;&#039;type&#039;&#039;&#039; Create, read, update, delete&lt;br /&gt;
** &#039;&#039;&#039;ajax&#039;&#039;&#039; Can this function be used with ajax?&lt;br /&gt;
** &#039;&#039;&#039;capabilities&#039;&#039;&#039; Capabilities required to use this function.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[External functions API]]&lt;br /&gt;
* [[Adding a web service to a plugin]]&lt;br /&gt;
* [[Web services API]]&lt;br /&gt;
&lt;br /&gt;
===Using caching to improve performance===&lt;br /&gt;
* The main cache used by moodle is the Moodle Universal Cache (MUC).&lt;br /&gt;
* The MUC has several cache definitions - &lt;br /&gt;
** Request cache&lt;br /&gt;
** Session cache&lt;br /&gt;
** Application&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[The Moodle Universal Cache (MUC)]]&lt;br /&gt;
* [[:en:MUC FAQ]]&lt;br /&gt;
* [[:en:Caching]]&lt;br /&gt;
&lt;br /&gt;
===Supporting backup and restore===&lt;br /&gt;
* Supporting backup and restore requires creating several files in the &#039;backup/moodle2&#039; directory.&lt;br /&gt;
* Back requires a class to extend the backup_task of some sort. There may be a specific plugin task to extend.&lt;br /&gt;
* Restore requires a class to extend the restore_task of some sort. There may be a specific plugin task to extend.&lt;br /&gt;
* The restore steps lib defines the structure of the plugin to be restored.&lt;br /&gt;
* The backup steps lib defines steps, settings, attributes, etc.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Backup 2.0 for developers]] - provides an example of step-by-step implementation of backup support to your plugin&lt;br /&gt;
* [[:en:Backup and restore FAQ]]&lt;br /&gt;
&lt;br /&gt;
===Supporting automated testing===&lt;br /&gt;
* Moodle has two types of automated testing: php unit tests, and behat tests.&lt;br /&gt;
* Unit tests are for testing functions.&lt;br /&gt;
* Behat tests runs through scenarios.&lt;br /&gt;
** Behat tests follows a script and navigates through moodle pages.&lt;br /&gt;
* unit tests should be located in the &amp;quot;tests&amp;quot; directory.&lt;br /&gt;
* behat tests should be located in the &amp;quot;tests/behat&amp;quot; directory.&lt;br /&gt;
* Tests located in these directories will be run through when a full test run is initiated.&lt;br /&gt;
* behat tests are actually feature files and end with the extension &amp;quot;.feature&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Writing PHPUnit tests]]&lt;br /&gt;
* [[PHPUnit]]&lt;br /&gt;
* [[Acceptance testing]]&lt;br /&gt;
* [[Behat integration]]&lt;br /&gt;
&lt;br /&gt;
==Publishing your plugin==&lt;br /&gt;
===Adding your plugin to moodle.org===&lt;br /&gt;
* publish your plugins at https://moodle.org/plugins/&lt;br /&gt;
* Publishing plugins on the moodle site leads you through a bunch of steps that need to be completed in order for the plugin to be approved and published.&lt;br /&gt;
* Plugins will be run through a pre-checker to give suggestions about possible issues with the code.&lt;br /&gt;
&lt;br /&gt;
===Supporting your plugin===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=TODO=&lt;br /&gt;
&lt;br /&gt;
Finishing this tutorial:&lt;br /&gt;
# About one or two screens for each section with a very generic overview for beginners, containing links to relevant docs WITH COMMENTS ABOUT QUALITY, USEFULNESS, CAVEATS etc.&lt;br /&gt;
# Go through all the linked pages and make sure they are current and accurate.&lt;br /&gt;
# Add a worked example to this page, so that each section has suggestions about things to add to the admin tool being built as an exercise.  If the code is long, it could be placed on separate pages.  A good reference for style is [[Moodle_Mobile_Developing_a_plugin_tutorial]] and [[Blocks]].&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* See [https://moodle.org/mod/forum/discuss.php?d=352360 this forum thread] about Getting Started with Moodle Development.&lt;br /&gt;
&lt;br /&gt;
=See also these older tutorials =&lt;br /&gt;
* [[Blocks|A Step-by-step Guide To Creating Blocks]] &lt;br /&gt;
* [[NEWMODULE Tutorial]]&lt;br /&gt;
* [http://dev.moodle.org Introduction to Moodle programming (based on Moodle 1.8)]&lt;br /&gt;
* [[Moodle_Mobile_Developing_a_plugin_tutorial|Moodle Mobile plugin tutorial]]&lt;br /&gt;
* [[Category:Tutorial|Other tutorials in these docs]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Tutorial]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=52837</id>
		<title>Tutorial</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=52837"/>
		<updated>2017-08-21T06:05:41Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* Basic page structure */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Welcome to Moodle development!&lt;br /&gt;
&lt;br /&gt;
This is a tutorial to help you learn how to write plugins for Moodle from start to finish, while showing you how to navigate the most important developer documentation along the way.&lt;br /&gt;
&lt;br /&gt;
PRE-REQUISITES:  We assume you are fairly comfortable with [[PHP FAQ|PHP]] in general and that you are able to [[:en:Installing AMP|install a database and web server]] on your local machine. &lt;br /&gt;
&lt;br /&gt;
If you need to learn PHP, you can see one PHP tutorial at http://www.w3schools.com/php/default.asp, another at http://php.net/manual/en/tutorial.php and several videos in YouTube at https://www.youtube.com/results?search_query=learn+php. There is a very old unmaintained Introduction to Moodle 1.8 Programming course at http://dev.moodle.org/course/view.php?id=2.&lt;br /&gt;
&lt;br /&gt;
Code examples can be found on GitHub at https://github.com/abgreeve/devcourse where a working plugin is located.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
===What&#039;s in the box===&lt;br /&gt;
If you [http://download.moodle.org/ download] Moodle source code or clone it from [https://github.com/moodle/moodle git], you will see a bunch of files and folders. This code consists of [[Core_APIs|Moodle core]] (that consists of the Very core and Core components), [[Moodle_libraries_credits|third party libraries]] and [[Plugin_types|plugins]]. Their mixed locations can be quite confusing at first but as you start working with it it will become more clear. Moodle developers should avoid modifications of the third party libraries (unless required) and core can never call methods defined in plugins. See also [[Communication Between Components]]&lt;br /&gt;
&lt;br /&gt;
===Setting up your development environment===&lt;br /&gt;
* Moodle uses Git for developement. View the link below for basic information about Git and Moodle.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Git for developers]]&lt;br /&gt;
&lt;br /&gt;
===The Moodle development framework===&lt;br /&gt;
===What type of plugin are you developing?===&lt;br /&gt;
* Moodle has lots of different types of plugins.&lt;br /&gt;
* There are 24 different categories of plugin listed on the moodle plugin database. Before starting check here to see if someone else has not already created what you are looking for. Perhaps you could contribute to their plugin instead of creating a new one.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* https://moodle.org/plugins/&lt;br /&gt;
* [[Plugin types]]&lt;br /&gt;
&lt;br /&gt;
==Let&#039;s make a plugin==&lt;br /&gt;
===The skeleton of your plugin===&lt;br /&gt;
&lt;br /&gt;
You plugin code will be organised into multiple files within a single root directory (and the subdirectories).&lt;br /&gt;
&lt;br /&gt;
The page [[Plugin files]] provides a list of common plugins files and their purpose.&lt;br /&gt;
&lt;br /&gt;
See also:&lt;br /&gt;
&lt;br /&gt;
* [[Moodle architecture]] - general overview of Moodle code architecture&lt;br /&gt;
* [[Plugin types]] - list of all supported plugin types&lt;br /&gt;
* [https://moodle.org/plugins/ Moodle plugins directory] - repository of contributed plugins for Moodle&lt;br /&gt;
* [https://moodle.org/plugins/tool_pluginskel Moodle plugin skeleton generator] - allows to quickly generate code skeleton for a new plugin&lt;br /&gt;
&lt;br /&gt;
===Basic page structure===&lt;br /&gt;
&lt;br /&gt;
The link below explains how to create and display a simple page in Moodle.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Page API]]&lt;br /&gt;
&lt;br /&gt;
===How to support over 100 languages===&lt;br /&gt;
* Language files are stored in the &amp;quot;lang&amp;quot; directory. English strings would be found in &amp;quot;lang/en&amp;quot;. Each language contains a file named after the plugin which contains all of the strings. For example the language strings for the assignment activity are found in &amp;quot;mod/assign/lang/en/assign.php&amp;quot;.&lt;br /&gt;
* [[:en:Language FAQ#Which_is_the_official_language_for_Moodle.3F| Moodle&#039;s default is Australian English]]. &lt;br /&gt;
** American English is a separate language pack (en_us). Please use only Australian (UK) English grammar and spelling when writing Moodle plugins.&lt;br /&gt;
** There is no need to include languages other than the default English, as almost all approved [https://lang.moodle.org/mod/forum/discuss.php?d=2485 plugin strings will be automatically imported into AMOS] for translation by the language packs translators.  &lt;br /&gt;
* get_string() is used in most cases for displaying text.&lt;br /&gt;
* lang_string() is used in situations where the text may not necessarily be displayed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Declaration in language file (lang/en/{pluginname}.php)&lt;br /&gt;
$string[&#039;nameofstring&#039;] = &#039;Actual string&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The get_string() function takes four parameters, but in this example we are only filling in the first two. The last two parameters are optional. The first parameter is the identifier for the string. The second is the component.&lt;br /&gt;
The component will be the name of the language file.&lt;br /&gt;
The following example shows a string in the badges block.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Use of string in code.&lt;br /&gt;
echo html_writer::tag(&#039;p&#039;, get_string(&#039;numbadgestodisplay&#039;, &#039;block_badges&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[String API]]&lt;br /&gt;
* [[Places to search for lang strings]]&lt;br /&gt;
* [[:en:Language customisation]]&lt;br /&gt;
* [[Plugin contribution checklist#Strings]]&lt;br /&gt;
&lt;br /&gt;
===Add content to your page===&lt;br /&gt;
* Content for a page is added through renderers.&lt;br /&gt;
* Renderers are typically stored in the &amp;quot;classes/output&amp;quot; directory.&lt;br /&gt;
* Putting content in renderers allows themers to override the visual display of the content.&lt;br /&gt;
* Very basic information is presented using the html_writer class.&lt;br /&gt;
* In most cases templates should be used.&lt;br /&gt;
* templates are stored in the &amp;quot;templates&amp;quot; directory. The templates use mustache files.&lt;br /&gt;
* Mustache files allow for more generic html with placeholders inserted, that inserts the data (context) at run time.&lt;br /&gt;
&lt;br /&gt;
The example used below is an admin tool and would be located under admin/tool.&lt;br /&gt;
&lt;br /&gt;
Step One: Create a class for rendering. This class collects information to display and has a method for formatting that information into a format that the template will understand.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/classes/output/developer_course_main_page.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace tool_devcourse\output;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
use renderable;&lt;br /&gt;
use renderer_base;&lt;br /&gt;
use templatable;&lt;br /&gt;
use stdClass;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class developer_course_main_page implements renderable, templatable {&lt;br /&gt;
&lt;br /&gt;
   protected $comment;&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Construct this renderable.&lt;br /&gt;
     * @param int $courseid The course record for this page.&lt;br /&gt;
     */&lt;br /&gt;
    public function __construct($comment) {&lt;br /&gt;
        $this-&amp;gt;comment = $comment;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Export this data so it can be used as the context for a mustache template.&lt;br /&gt;
     *&lt;br /&gt;
     * @param renderer_base $output Renderer base.&lt;br /&gt;
     * @return stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function export_for_template(renderer_base $output) {&lt;br /&gt;
        $data = new stdClass();&lt;br /&gt;
        $data-&amp;gt;comment = $this-&amp;gt;comment;&lt;br /&gt;
        return $data;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Step Two: To render this information a custom renderer is created for the plugin. This renderer class must extend plugin_renderer_base.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/classes/output/renderer.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace tool_devcourse\output;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
use plugin_renderer_base;&lt;br /&gt;
use renderable;&lt;br /&gt;
&lt;br /&gt;
class renderer extends plugin_renderer_base {&lt;br /&gt;
&lt;br /&gt;
     /**&lt;br /&gt;
     * Defer to template.&lt;br /&gt;
     *&lt;br /&gt;
     * @param developer_course_main_page $page&lt;br /&gt;
     *&lt;br /&gt;
     * @return string html for the page&lt;br /&gt;
     */&lt;br /&gt;
    public function render_developer_course_main_page(developer_course_main_page $page) {&lt;br /&gt;
        $data = $page-&amp;gt;export_for_template($this);&lt;br /&gt;
        return parent::render_from_template(&#039;tool_devcourse/developer_course_main_page&#039;, $data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Step three: A mustache template is to then be created. The information is sent to the template and at this point the information is known as the context (not to be confused with the normal definition of context throughout Moodle).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/templates/developer_course_main_page.mustache&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code html&amp;gt;&lt;br /&gt;
{{!&lt;br /&gt;
    @template tool_devcourse/developer_course_main_page&lt;br /&gt;
&lt;br /&gt;
    Example context (json):&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;comment&amp;quot;: &amp;quot;Example comment for the context&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;h2&amp;gt;{{#str}}maintitle, tool_devdoc{{/str}}&amp;lt;/h2&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;{{comment}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This shows an extremely simple mustache template with one item in the context (comment). It also shows how strings are defined in the template.&lt;br /&gt;
&lt;br /&gt;
Step four: To actually have this template be displayed we get the custom renderer. This chunk of code would be located in a place such as devcourse/index.php after the appropriate setup outlined in the [[Tutorial#Basic_page_structure|basic page structure]].&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$output = $PAGE-&amp;gt;get_renderer(&#039;tool_devcourse&#039;);&lt;br /&gt;
//Then we get the class for rendering and provide it with information (if needed).&lt;br /&gt;
$randomcomment = &#039;This comment is random&#039;;&lt;br /&gt;
$page = new \tool_devdoc\output\developer_course_main_page($randomcomment);&lt;br /&gt;
//Finally we echo out the template&lt;br /&gt;
echo $output-&amp;gt;render($page);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Output API]]&lt;br /&gt;
* [[Output functions]]&lt;br /&gt;
* [[Templates]]&lt;br /&gt;
* [[Output renderers]]&lt;br /&gt;
* [[Renderer]]&lt;br /&gt;
* [[Overriding a renderer]]&lt;br /&gt;
&lt;br /&gt;
===Adding your plugin into Moodle&#039;s navigation===&lt;br /&gt;
* The moodle navigation system has hooks which allows plugins to add links to the navigation menu.&lt;br /&gt;
* Hooks are located in lib.php. Try to keep lib.php as small as possible as this file is included on every page. Put classes and functions elsewhere.&lt;br /&gt;
* Course navigation extension example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function tool_devcourse_extend_navigation_course($navigation, $course, $coursecontext) {&lt;br /&gt;
    $url = new moodle_url(&#039;/admin/tool/devcourse/index.php&#039;);&lt;br /&gt;
    $devcoursenode = navigation_node::create(&#039;Development course&#039;, $url, navigation_node::TYPE_CUSTOM, &#039;Dev course&#039;, &#039;devcourse&#039;);&lt;br /&gt;
    $navigation-&amp;gt;add_node($devcoursenode);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Navigation API]]&lt;br /&gt;
* [[:en:Navigation]]&lt;br /&gt;
&lt;br /&gt;
===Database queries===&lt;br /&gt;
* Moodle has a generic database query library. Behind this library are additional libraries which allow Moodle to work with MySQL, PostgreSQL, Oracle, SQL Server, and Maria DB.&lt;br /&gt;
* Where possible it is advisable to use the predefined functions rather than write out SQL. Writing SQL has a greater chance of not working with one of the supported databases.&lt;br /&gt;
* The return of the select functions tends to be an object or an array of objects.&lt;br /&gt;
&lt;br /&gt;
Example call to retrieve data from the course table.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
global $DB;&lt;br /&gt;
$courses = $DB-&amp;gt;get_records(&#039;course&#039;, null, &#039;&#039;, &#039;id, category, fullname, shortname&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Example of data returned from the above code.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Array&lt;br /&gt;
(&lt;br /&gt;
    [43] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 43&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; XX -Test 5&lt;br /&gt;
            [shortname] =&amp;gt; xxt5&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    [5] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 5&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; With the glossary&lt;br /&gt;
            [shortname] =&amp;gt; wtg&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    [39] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 39&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; XX - Test 1&lt;br /&gt;
            [shortname] =&amp;gt; xxt1&lt;br /&gt;
        )&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Database]]&lt;br /&gt;
* [[Data manipulation API]]&lt;br /&gt;
&lt;br /&gt;
===Creating your own database tables===&lt;br /&gt;
* We create our database tables in Moodle using the  XMLDB editor. This is located in the administration block &amp;quot;Site administration | Development | XMLDB editor&amp;quot;.&lt;br /&gt;
* The {plugin}\db directory needs to have write access for the XMLDB editor to be most effective.&lt;br /&gt;
* XMLDB editor creates an install.xml file in the db directory. This file will be loaded during the install to create your tables.&lt;br /&gt;
* XMLDB editor will produce php update code for adding and updating moodle database tables.&lt;br /&gt;
&lt;br /&gt;
The XMLDB main page.&lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:xmldb-main.png]]&lt;br /&gt;
&lt;br /&gt;
Upgrade code generated by the XMLDB&lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:xmldb-upgrade-code.png]]&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[XMLDB editor]]&lt;br /&gt;
* [[Using XMLDB]]&lt;br /&gt;
* [[XMLDB Documentation]]&lt;br /&gt;
* [[Upgrade API]]&lt;br /&gt;
* [[XMLDB introduction]]&lt;br /&gt;
&lt;br /&gt;
===Supporting access permissions: roles, capabilities and contexts===&lt;br /&gt;
* Capabilities are controlled in &amp;quot;access.php&amp;quot; under the &amp;quot;db&amp;quot; directory.&lt;br /&gt;
* This file has an array of capabilities with the following:&lt;br /&gt;
** name&lt;br /&gt;
** possible security risks behind giving this capability.&lt;br /&gt;
** The context that this capability works in.&lt;br /&gt;
** The default roles (teacher, manager, student, etc) that have this capability.&lt;br /&gt;
** Various other information.&lt;br /&gt;
* These capabilities are checked in code to allow access to pages, sections, and abilities (saving, deleting, etc).&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[Access API]]&lt;br /&gt;
* [[Roles#Context]]&lt;br /&gt;
* [[:en:Category:Capabilities]]&lt;br /&gt;
* [[:en:Roles and permissions]]&lt;br /&gt;
&lt;br /&gt;
===Adding web forms===&lt;br /&gt;
* Moodle has it&#039;s own forms library.&lt;br /&gt;
* The forms lib includes a lot of accessibility code, and error checking, by default.&lt;br /&gt;
* Moodle forms can be displayed in JavaScript using &#039;fragments&#039;.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Form API]]&lt;br /&gt;
* [[lib/formslib.php Form Definition]]&lt;br /&gt;
* [[Fragment]]&lt;br /&gt;
&lt;br /&gt;
===Maintaining good security===&lt;br /&gt;
* Use the sesskey when directing to pages to do actions.&lt;br /&gt;
* Use the appropriate filters when retrieving parameters&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[lib/formslib.php Form Definition#Most Commonly Used PARAM .2A Types]]&lt;br /&gt;
* [[Output functions#p.28.29 and s.28.29]]&lt;br /&gt;
&lt;br /&gt;
===Handling files===&lt;br /&gt;
* Files are conceptually stored in file areas.&lt;br /&gt;
* Plugins can only access files from it&#039;s own component.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[File API]]&lt;br /&gt;
* [[File API internals]]&lt;br /&gt;
* [[Using the File API in Moodle forms]]&lt;br /&gt;
&lt;br /&gt;
===Adding Javascript===&lt;br /&gt;
* Moodle is currently using jquery and AMD (Asynchronous Module Definition).&lt;br /&gt;
* JavaScript files are located in the &amp;quot;amd/src&amp;quot; directory.&lt;br /&gt;
* Use grunt to build your JavaScript.&lt;br /&gt;
* Include your JavaScript in php files as follows:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;requires-&amp;gt;js_call_amd(&#039;{JScriptfilename}&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* Can also be included in mustache templates.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Javascript Modules]]&lt;br /&gt;
* [[jQuery]]&lt;br /&gt;
* [[Javascript FAQ]]&lt;br /&gt;
* [[JavaScript guidelines]]&lt;br /&gt;
* [[Grunt]]&lt;br /&gt;
&lt;br /&gt;
===Adding events and logging===&lt;br /&gt;
* All logging in moodle is done through the events system.&lt;br /&gt;
* New events should be located in the &amp;quot;classes/event&amp;quot; directory.&lt;br /&gt;
* It is possible to create observers and subscribe to events.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Event 2]]&lt;br /&gt;
* [[Logging 2]]&lt;br /&gt;
&lt;br /&gt;
===Web Services and AJAX===&lt;br /&gt;
* Moodle web services uses the external functions API.&lt;br /&gt;
* The recommended way to make AJAX requests is to use the ajax AMD file which uses the external functions API.&lt;br /&gt;
* External functions should be located in the &amp;quot;classes/external.php&amp;quot; file.&lt;br /&gt;
* A list of services should be included in &amp;quot;db/services.php&amp;quot;. This file is required to register the web services with Moodle.&lt;br /&gt;
* The services list is an array which contains:&lt;br /&gt;
** &#039;&#039;&#039;classname&#039;&#039;&#039; Name of the external class.&lt;br /&gt;
** &#039;&#039;&#039;methodname&#039;&#039;&#039; The name of the external function.&lt;br /&gt;
** &#039;&#039;&#039;classpath&#039;&#039;&#039; system path to the external function file.&lt;br /&gt;
** &#039;&#039;&#039;description&#039;&#039;&#039; Description of the function&lt;br /&gt;
** &#039;&#039;&#039;type&#039;&#039;&#039; Create, read, update, delete&lt;br /&gt;
** &#039;&#039;&#039;ajax&#039;&#039;&#039; Can this function be used with ajax?&lt;br /&gt;
** &#039;&#039;&#039;capabilities&#039;&#039;&#039; Capabilities required to use this function.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[External functions API]]&lt;br /&gt;
* [[Adding a web service to a plugin]]&lt;br /&gt;
* [[Web services API]]&lt;br /&gt;
&lt;br /&gt;
===Using caching to improve performance===&lt;br /&gt;
* The main cache used by moodle is the Moodle Universal Cache (MUC).&lt;br /&gt;
* The MUC has several cache definitions - &lt;br /&gt;
** Request cache&lt;br /&gt;
** Session cache&lt;br /&gt;
** Application&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[The Moodle Universal Cache (MUC)]]&lt;br /&gt;
* [[:en:MUC FAQ]]&lt;br /&gt;
* [[:en:Caching]]&lt;br /&gt;
&lt;br /&gt;
===Supporting backup and restore===&lt;br /&gt;
* Supporting backup and restore requires creating several files in the &#039;backup/moodle2&#039; directory.&lt;br /&gt;
* Back requires a class to extend the backup_task of some sort. There may be a specific plugin task to extend.&lt;br /&gt;
* Restore requires a class to extend the restore_task of some sort. There may be a specific plugin task to extend.&lt;br /&gt;
* The restore steps lib defines the structure of the plugin to be restored.&lt;br /&gt;
* The backup steps lib defines steps, settings, attributes, etc.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Backup 2.0 for developers]] - provides an example of step-by-step implementation of backup support to your plugin&lt;br /&gt;
* [[:en:Backup and restore FAQ]]&lt;br /&gt;
&lt;br /&gt;
===Supporting automated testing===&lt;br /&gt;
* Moodle has two types of automated testing: php unit tests, and behat tests.&lt;br /&gt;
* Unit tests are for testing functions.&lt;br /&gt;
* Behat tests runs through scenarios.&lt;br /&gt;
** Behat tests follows a script and navigates through moodle pages.&lt;br /&gt;
* unit tests should be located in the &amp;quot;tests&amp;quot; directory.&lt;br /&gt;
* behat tests should be located in the &amp;quot;tests/behat&amp;quot; directory.&lt;br /&gt;
* Tests located in these directories will be run through when a full test run is initiated.&lt;br /&gt;
* behat tests are actually feature files and end with the extension &amp;quot;.feature&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Writing PHPUnit tests]]&lt;br /&gt;
* [[PHPUnit]]&lt;br /&gt;
* [[Acceptance testing]]&lt;br /&gt;
* [[Behat integration]]&lt;br /&gt;
&lt;br /&gt;
==Publishing your plugin==&lt;br /&gt;
===Adding your plugin to moodle.org===&lt;br /&gt;
* publish your plugins at https://moodle.org/plugins/&lt;br /&gt;
* Publishing plugins on the moodle site leads you through a bunch of steps that need to be completed in order for the plugin to be approved and published.&lt;br /&gt;
* Plugins will be run through a pre-checker to give suggestions about possible issues with the code.&lt;br /&gt;
&lt;br /&gt;
===Supporting your plugin===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=TODO=&lt;br /&gt;
&lt;br /&gt;
Finishing this tutorial:&lt;br /&gt;
# About one or two screens for each section with a very generic overview for beginners, containing links to relevant docs WITH COMMENTS ABOUT QUALITY, USEFULNESS, CAVEATS etc.&lt;br /&gt;
# Go through all the linked pages and make sure they are current and accurate.&lt;br /&gt;
# Add a worked example to this page, so that each section has suggestions about things to add to the admin tool being built as an exercise.  If the code is long, it could be placed on separate pages.  A good reference for style is [[Moodle_Mobile_Developing_a_plugin_tutorial]] and [[Blocks]].&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* See [https://moodle.org/mod/forum/discuss.php?d=352360 this forum thread] about Getting Started with Moodle Development.&lt;br /&gt;
&lt;br /&gt;
=See also these older tutorials =&lt;br /&gt;
* [[Blocks|A Step-by-step Guide To Creating Blocks]] &lt;br /&gt;
* [[NEWMODULE Tutorial]]&lt;br /&gt;
* [http://dev.moodle.org Introduction to Moodle programming (based on Moodle 1.8)]&lt;br /&gt;
* [[Moodle_Mobile_Developing_a_plugin_tutorial|Moodle Mobile plugin tutorial]]&lt;br /&gt;
* [[Category:Tutorial|Other tutorials in these docs]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Tutorial]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Page_API&amp;diff=52836</id>
		<title>Page API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Page_API&amp;diff=52836"/>
		<updated>2017-08-21T06:04:30Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Page API is used to set up the current page, add JavaScript, and configure how things will be displayed to the user.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
The Page API is an integral part of any Moodle page. It allows the developer to set things up the way they envisage it. Through the Page API you can set things like the title, initial heading, where the user is for the navigation, and which layout you think the page should use.&lt;br /&gt;
&lt;br /&gt;
This document starts off with a simple example, and then proceeds to provide a more complete description of how to set up a page for display.&lt;br /&gt;
&lt;br /&gt;
==A simple example==&lt;br /&gt;
This example covers how to set up a basic page for use within an activity plugin and is undoubtedly the simplest example as much of the work is done behind the scenes for you.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// File: /mod/mymodulename/view.php&lt;br /&gt;
require_once(&#039;../../config.php&#039;);&lt;br /&gt;
$cmid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$cm = get_coursemodule_from_id(&#039;mymodulename&#039;, $cmid, 0, false, MUST_EXIST);&lt;br /&gt;
$course = $DB-&amp;gt;get_record(&#039;course&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;course), &#039;*&#039;, MUST_EXIST);&lt;br /&gt;
&lt;br /&gt;
require_login($course, true, $cm);&lt;br /&gt;
$PAGE-&amp;gt;set_url(&#039;/mod/mymodulename/view.php&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;id));&lt;br /&gt;
$PAGE-&amp;gt;set_title(&#039;My modules page title&#039;);&lt;br /&gt;
$PAGE-&amp;gt;set_heading(&#039;My modules page heading&#039;);&lt;br /&gt;
&lt;br /&gt;
// The rest of your code goes below this.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If you are not familiar with what the first four lines are doing try going through these docs before proceeding - &lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/en/Context Context explained]&lt;br /&gt;
* [https://docs.moodle.org/dev/Course_module Course module explained]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So lets start at require_login and assume you already have the course and course module objects ready to use. When you call require_login part of the magic it does for you is set up the basic for the current page.&amp;lt;br /&amp;gt;&lt;br /&gt;
In the case of the example above because require_login is given a course and course module it is already setting up much of the page for you. It is giving the course and course module objects to the page, setting the context for the page to the course modules context, and setting the page layout to &#039;&#039;incourse&#039;&#039; so that you get the standard look of a course module.&lt;br /&gt;
&lt;br /&gt;
The set up that we are having to do is as follows:&lt;br /&gt;
# Set the URL for the page. This MUST be done.&lt;br /&gt;
# Set a title for the page. Most likely will be shown in the &amp;lt;title&amp;gt; tag.&lt;br /&gt;
# Set the heading for the page. Most likely used in the pages header.&lt;br /&gt;
&lt;br /&gt;
It&#039;s important to mention that this has to be done before output starts. That means you must set up the page before the header is printed and before you instantiate any moodleform instances.&lt;br /&gt;
&lt;br /&gt;
And that is it, if you were to add a bit of simple output there you would get a page that already looks like other module pages you would have seen. Simple as.&lt;br /&gt;
&lt;br /&gt;
==$PAGE The Moodle page global==&lt;br /&gt;
For every page request Moodle sets up a couple of global structures that you will likely need. $DB the database object, and $CFG which stores configuration are two that you are likely already aware of. $PAGE is the focus of this article, it is a moodle_page instance that stores all of the information and is used by the output library $OUTPUT when displaying the page.&amp;lt;br /&amp;gt;&lt;br /&gt;
It&#039;s important to note the difference between $PAGE and $OUTPUT, $PAGE is for setting up the page and $OUTPUT is for displaying the page. $PAGE contains lots of logic and magic, $OUTPUT is purely about display and does little more than produce HTML.&lt;br /&gt;
&lt;br /&gt;
==Setting up the page==&lt;br /&gt;
When creating a page in Moodle there are a couple of things that you must set, and a couple of things that get set for you in many cases but not all of the time.&lt;br /&gt;
&lt;br /&gt;
===URL===&lt;br /&gt;
This is an absolute must, failing to set this will lead Moodle to display an error that it has not been set.&amp;lt;br /&amp;gt;&lt;br /&gt;
It can be set in the following manner:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;set_url(new moodle_url(&#039;/path/to/your/file.php&#039;, array(&#039;key&#039; =&amp;gt; &#039;value&#039;, &#039;id&#039; =&amp;gt; 3)));&lt;br /&gt;
$PAGE-&amp;gt;set_url(&#039;/path/to/your/file.php&#039;, array(&#039;key&#039; =&amp;gt; &#039;value&#039;, &#039;id&#039; =&amp;gt; 3));&lt;br /&gt;
$PAGE-&amp;gt;set_url(&#039;/path/to/your/file.php?key=value&amp;amp;id=3&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The above code sets the page URL 3 times, and highlights the 3 different ways you can set the URL. Either of the first two methods are the preferred way as it provides 100% accuracy when processing the URL. Internally set_url() converts what ever you give it to a moodle_url object.&lt;br /&gt;
&lt;br /&gt;
The URL that you give to the page is going to be used by many Moodle core API&#039;s. Most importantly it is going to be used to create the navigation for your page so it&#039;s very important you set it accurately.&lt;br /&gt;
&lt;br /&gt;
===Context===&lt;br /&gt;
This is an absolute must as well, however in many cases it will be set for you magically by Moodle.&lt;br /&gt;
&lt;br /&gt;
In order to set the context for the page you must provide a context object, in Moodle 2.2 and greater this will look as follows:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Moodle 2.2 and greater&lt;br /&gt;
$PAGE-&amp;gt;set_context(context_system::instance());&lt;br /&gt;
$PAGE-&amp;gt;set_context(context_coursecat::instance($categoryid));&lt;br /&gt;
$PAGE-&amp;gt;set_context(context_course::instance($courseid));&lt;br /&gt;
$PAGE-&amp;gt;set_context(context_module::instance($moduleid));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In Moodle 2.0+, and Moodle 2.1+ the following is the equivalent code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Moodle 2.0 and 2.1&lt;br /&gt;
$PAGE-&amp;gt;set_context(get_system_context());&lt;br /&gt;
$PAGE-&amp;gt;set_context(get_context_instance(CONTEXT_COURSECAT, $categoryid));&lt;br /&gt;
$PAGE-&amp;gt;set_context(get_context_instance(CONTEXT_COURSE, $courseid));&lt;br /&gt;
$PAGE-&amp;gt;set_context(get_context_instance(CONTEXT_MODULE, $moduleid));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In both examples above setting different types of contexts has been illustrated however you should only ever call set_context() once with the context that is most appropriate to the page you are creating.&amp;lt;br /&amp;gt;&lt;br /&gt;
If it is a plugin then the context to use would be the context you are using for your capability checks.&lt;br /&gt;
&lt;br /&gt;
As mentioned above the other thing to be aware of is that in some circumstances this gets automatically set for you.&amp;lt;br /&amp;gt;&lt;br /&gt;
If your script calls require_login (and most scripts have to) and you are providing a course, or a module to your require login call then you will not need to call set_context().&amp;lt;br /&amp;gt;&lt;br /&gt;
This is because require_login handles it for you.&lt;br /&gt;
&lt;br /&gt;
If your script doesn&#039;t call require_login, or you don&#039;t call it with a course and/or module then you will need to manually set the context as shown.&lt;br /&gt;
&lt;br /&gt;
===Optional set up===&lt;br /&gt;
The following are optional extras you can set up against the PAGE object that you are likely to encounter throughout Moodle core, and are likely to want to use yourself.&lt;br /&gt;
====Page layout====&lt;br /&gt;
The following code sets the pages layout to the standard layout, the most generic layout in the arsenal.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;set_pagelayout(&#039;standard&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
When setting the page layout you should use the layout that is the closest match to the page you are creating. Layouts are used by themes to determine what is  shown on the page. The most prominent difference between layouts is the block regions they support. The default layout `&#039;&#039;base&#039;&#039;` for example doesn&#039;t normally have any block regions at all, where as normally `&#039;&#039;standard&#039;&#039;` has the most generic layout and several block regions.&lt;br /&gt;
&lt;br /&gt;
There are dozens of different layouts that can be, and are used throughout Moodle core that you can use within your code. For a full list of common layouts you are best too look at theme/base/config.php or refer to the list below.&lt;br /&gt;
&lt;br /&gt;
Note: It&#039;s important to know that the theme determines what layouts are available and how each looks. If you select a layout that the theme doesn&#039;t support then it will revert to the default layout while using that theme.&amp;lt;br /&amp;gt;Themes are also able to specify additional layouts, however its important to spot them and know that while they may work with one theme they are unlikely to work as you expect with other themes.&lt;br /&gt;
&lt;br /&gt;
====Base theme page layouts====&lt;br /&gt;
The following is a list of the layouts defined by the base theme. Theme designers are encouraged to make the base theme a parent of their custom theme so you can be sure that in 99% of cases these layouts will be available.&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Layout&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| base&lt;br /&gt;
| Most backwards compatible layout without the blocks. This is the layout used by default.&lt;br /&gt;
|-&lt;br /&gt;
| standard&lt;br /&gt;
| Standard layout with blocks, this is recommended for most pages with general information&lt;br /&gt;
|-&lt;br /&gt;
| course&lt;br /&gt;
| The course main page uses this layout.&lt;br /&gt;
|-&lt;br /&gt;
| coursecategory&lt;br /&gt;
| Category course listings.&lt;br /&gt;
|-&lt;br /&gt;
| incourse&lt;br /&gt;
| Used for areas within a course, typical for modules. Default page layout if $cm specified in require_login().&lt;br /&gt;
|-&lt;br /&gt;
| frontpage&lt;br /&gt;
| The site home page uses this.&lt;br /&gt;
|-&lt;br /&gt;
| admin&lt;br /&gt;
| Admin and settings pages as well as server administration scripts.&lt;br /&gt;
|-&lt;br /&gt;
| mydashboard&lt;br /&gt;
| The users dashboard.&lt;br /&gt;
|-&lt;br /&gt;
| mypublic&lt;br /&gt;
| A users public profile uses this layout.&lt;br /&gt;
|-&lt;br /&gt;
| login&lt;br /&gt;
| The login screen.&lt;br /&gt;
|-&lt;br /&gt;
| popup&lt;br /&gt;
| Pages that appear in popup windows, usually no navigation, blocks, or header.&lt;br /&gt;
|-&lt;br /&gt;
| frametop&lt;br /&gt;
| Used for the outermost content of a page constructed with frames. Usually no blocks and minimal footer.&lt;br /&gt;
|-&lt;br /&gt;
| embedded&lt;br /&gt;
| Embedded pages such as content for iframes/objects. Needs as much space as possible usually no blocks, header, or footer.&lt;br /&gt;
|-&lt;br /&gt;
| maintenance&lt;br /&gt;
| Used during upgrade, installation, and when maintenance mode is enabled.&lt;br /&gt;
|-&lt;br /&gt;
| print&lt;br /&gt;
| Gets used when printing a page. Normally just a simple header and no blocks.&lt;br /&gt;
|-&lt;br /&gt;
| redirect&lt;br /&gt;
| A special layout used during a redirect. Normally with content only.&lt;br /&gt;
|-&lt;br /&gt;
| report&lt;br /&gt;
| Used for reports within Moodle. Special layout designed to handle horizontal scrolling in a nice way.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Title====&lt;br /&gt;
Setting an appropriate title is certainly a must for any properly designed page. While it is optional it is highly recommended that you set the title.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;set_title(&#039;This is my title&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
When setting the title for the page you need to provide just the string you want to use for the title. It should be a basic string and contain no HTML. Any HTML will be stripped out as the title is used within the &amp;lt;title&amp;gt; tag in the HTML head.&lt;br /&gt;
&lt;br /&gt;
====Heading====&lt;br /&gt;
Like title it is highly recommended that you set a meaningful heading for the page, although it is optional.&amp;lt;br /&amp;gt;The heading is normally displayed at the top of the page before the rest of the content starts. However it is up to the layout defined by the theme as to where it is displayed. Not all layouts will display a heading but I encourage you to always set one even if you are using a layout that doesn&#039;t support headings. This way if you are using a theme that uses a heading on every page regardless of layout things still look consistent.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;set_heading(get_string(&#039;pluginname&#039;, &#039;local_myplugin&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When setting a heading there is just one argument, the string to use for the heading. It should be a basic string and contain no HTML.&lt;br /&gt;
&lt;br /&gt;
=== Advanced set up ===&lt;br /&gt;
The following are advanced optional methods you can call to further set up your page. In most cases you will never need to use these.&lt;br /&gt;
&lt;br /&gt;
; set_activity_record : If you have called require_login with a course module, or you have manually set a course module on $PAGE then one other thing you may want to do is set the activity module record on $PAGE as well.&amp;lt;br /&amp;gt;This is best done when you have already fetched the activity record yourself in which case manually setting the activity record may reduce the number of queries for the page by 1.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_activity_record($activityrecord);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_blocks_editing_capability : Using this method you can set an additional capability that users must posses before being able to edit blocks on this page.&amp;lt;br /&amp;gt;By default &#039;moodle/site:manageblocks&#039; is used however there are sometimes reasons to use a different capability.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_blocks_editing_capability($strcapability);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_button : This allows you to set some HTML that will be shown in the navigation bar where the `Turn on editing` button normally lives.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_button($htmlstring);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_cacheable : By setting this to false the page will be sent with headers to prevent the client from caching the page. Defaults to true.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_cacheable(true/false);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_category_by_id : Allows you to set a category that this page is displaying. Calling this will force the $PAGE-&amp;gt;course to be set to the front page course.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_category_by_id($categoryid);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_cm : Like set page above, sometimes you need to manually set the course module for $PAGE. Again you must set the context to the context of the course module if you call this.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_cm($coursemodulerecord);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_course : This allows you to set the course the page belongs to. Normally when you call require_login the course you give it automatically gets sent to $PAGE for you.&amp;lt;br /&amp;gt;However if you don&#039;t want to require login for the course, but you need it in $PAGE then you can call set_course and provide it.&amp;lt;br /&amp;gt;Note that if you do this then you MUST use the context of the course when calling set_context().&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_course($courserecord);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_docs_path : Normally this gets automatically constructed for you, however in some circumstances you may want to manually set it.&amp;lt;br /&amp;gt;This allows you to have several pages that all point to the same docs page rather than requiring a docs page for each.&amp;lt;br /&amp;gt;The docs page link is normally shown by a theme in the footer.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_docs_path($strpath);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_focuscontrol : If you pass this method an element id when the page loads on the client focus will be shifted to the element with the corresponding id.&amp;lt;br /&amp;gt;Using this function is a REALLY bad idea in most situations because changing focus automatically in a browser is a nightmare for the vision impaired and those using screen readers.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_focuscontrol($controlid);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_headingmenu : This allows you to set some HTML that will be shown next to the pages main heading where the language select box normally lives.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_headingmenu($htmlstring);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_other_editing_capability : Can be used to set an additional capability that the user must posses before they can turn editing on for this page.&amp;lt;br /&amp;gt;This is useful if you can an editing more for your page that is more than just editing blocks.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_other_editing_capability($strcapability);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_pagetype : This gets automatically set up for by default to the path of your file e.g. mod/mymod/index.php will set up as mod-mymod-index.&amp;lt;br /&amp;gt;This is absolutely fine in 99% of cases however every now and again there is a reason to override it.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_pagetype($strpagetype);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_periodic_refresh_delay : If set a meta tag gets added to the page header causing it to refresh intermittently.&amp;lt;br /&amp;gt;This is rarely needed but can be useful if you need to automatically refresh the likes of a chat page, or news feed.&amp;lt;br /&amp;gt;Today it is not recommended to use this, but instead to create a means of getting additional content via AJAX.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_periodic_refresh_delay($intdelay);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_popup_notification_allowed : Allow or disallow popup notifications on this page. Things like messaging can cause messages to popup at the bottom of the screen sometimes.&amp;lt;br /&amp;gt;On some pages this functionality is not desired and can be stopped by calling this method and using false as the first argument.&amp;lt;br /&amp;gt;Popups are allowed by default.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_popup_notification_allowed(true/false);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; set_subpage : If context-&amp;gt;id and pagetype are not enough to uniquely identify this page and you need to include another string to make it more unique you can do it by calling this method setting a custom sub page type.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;set_subpage($strsubpage);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; add_body_class : Adds a CSS class to the body tag that will be printed by the Output API as part of the header.&amp;lt;br /&amp;gt;This is useful for adding classes to the body tag that describe the content of the page and may be required for styling the whole page, or for including indicator classes that may be useful to look for in JavaScript.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;add_body_class($strcssclass);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; add_body_classes : Adds an array of CSS classes to the body tag. Have a look at the above comment for &#039;&#039;&#039;add_body_class&#039;&#039;&#039; for more details.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;add_body_classes($arrayofclasses);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; force_settings_menu : Theme boost does it&#039;s best to find a place to put a settings cog for your activity / resource, but if for some reason it isn&#039;t displayed, you can manually set the settings cog to be displayed on the page. This should be called before main content is displayed. This setting only currently shows the setting cog on theme_boost.&lt;br /&gt;
&amp;lt;code php&amp;gt;$PAGE-&amp;gt;force_settings_menu();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Getting information about the page==&lt;br /&gt;
As well of setting up the page you can of course get information back from it about the page it has been set up to display.&amp;lt;br /&amp;gt;&lt;br /&gt;
Anything you set against the page can be retrieved as can any information that was set magically for you by other methods.&lt;br /&gt;
&lt;br /&gt;
The following are the most interesting and likely useful things you can get back from the page.&lt;br /&gt;
&lt;br /&gt;
; activityrecord : The activityrecord will be the record from the database that relates to the cm that was set by require_login, or manually by your code.&amp;lt;br /&amp;gt;For example if you provided a $cm instance that related to a forum this will be a row from the forum table.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;activityrecord;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; blockmanager : This is the block manager responsible for loading the all of the blocks that will be shown on the page.&amp;lt;br /&amp;gt;For more information see the [[Blocks API]].&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;blockmanager;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; bodyid : The id that will be given to the body tag when the page is displayed.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;bodyid;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; categories : An array of all the categories the page course belongs to, starting with the immediately containing category.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;categories;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; category : The category that the page course belongs to.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;category;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; cm : The course module that has been set for the page.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;cm;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; course : The course that has been set for the page.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;course;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; devicetypeinuse : The device the user is using browse the page.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;devicetypeinuse;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; headerprinted : Is true if the page header has already been printed. &lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;headerprinted;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; heading : The page heading.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;heading;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; navbar : Gets a reference to the pages navigation bar so that you can interact with that. See the [[Navigation API]] for more information.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;navbar;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; navigation : Gets a reference to the navigation for the page. See the [[Navigation API]] for more information.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;navigation;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; requires : Gets the page requirements manager that handles any JavaScript and special CSS requirements for the page.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;requires;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; settingsnav : Gets the settings navigation for the page. See the [[Navigation API]] for more information.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;settingsnav;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; theme : Gets the theme that is being used for the page. Is a theme_config object.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;theme;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; title : Gets the title for the page.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;title;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; url : Gets the URL that was set for the page. Is a moodle_url object.&lt;br /&gt;
&amp;lt;code php&amp;gt;$var = $PAGE-&amp;gt;url;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==FAQs==&lt;br /&gt;
&lt;br /&gt;
; I don&#039;t have any blocks on my page? : This has happened because you have not set a page layout that uses blocks OR you have set it after output has started. Once output has started you cannot change integral aspects of that page that are used for the initial output. Included is the page title, heading, url and layout.&lt;br /&gt;
&lt;br /&gt;
; I am getting a notice about not having set the page URL but I have set it? : As above you must set up the page before output starts, trying to do so will lead to notices and developer warnings about having things in the wrong order.&lt;br /&gt;
&lt;br /&gt;
; What starts output? : Output starts when either the script calls echo $OUTPUT-&amp;gt;header OR a moodleform is instantiated.&lt;br /&gt;
&lt;br /&gt;
==Related API&#039;s==&lt;br /&gt;
There are a couple of API&#039;s that are closely related to the Page API that you should be aware of as well.&lt;br /&gt;
&lt;br /&gt;
===Output API===&lt;br /&gt;
The output API is an immediate relation of the page API. The page API is about setting things up, whereas the output API is all about displaying things.&lt;br /&gt;
It&#039;s through the output API that content is actually produced, and much of the information you set up through the page is used to customise what is produced, and fill in the general blanks of any page (such as title and heading.&lt;br /&gt;
&lt;br /&gt;
See the [[Output API]] documentation for more information.&lt;br /&gt;
&lt;br /&gt;
===Page requirements API===&lt;br /&gt;
The page requirements API allows you the developer to include additional CSS, and JavaScript resources that should be included with the page, and to include JavaScript calls within the page through a variety of means.&lt;br /&gt;
Technically this API is part of the Output API mentioned above, however it deserves special mention. If you are going to be using any JavaScript or CSS within your page you will need to know about this.&lt;br /&gt;
&lt;br /&gt;
See the [[Output API]] documentation for more information on the page requirements API.&lt;br /&gt;
&lt;br /&gt;
===Navigation API===&lt;br /&gt;
The final API to mention is the navigation API. This again is integral to both the page and output API and is used to recognise the context of the content being displayed and ensure that the correct blocks and navigaiton structure are loaded for the context.&lt;br /&gt;
There is a good chance that you will encounter a need to customise the navigation early on in plugin page development and it&#039;s important to be aware of this important API.&lt;br /&gt;
&lt;br /&gt;
See the [[Navigation API]] documentation for more information on the page requirements API.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Core APIs]] : A list of all the core API&#039;s in Moodle.&lt;br /&gt;
* [[Output API]] : The Output API.&lt;br /&gt;
* [[Navigation API]] : The Navigation API.&lt;br /&gt;
* [http://moodle.org/mod/forum/view.php?id=55 General developer forum] : The place to ask question you may have about the Page API.&lt;br /&gt;
* MDL-30977 : The issue to see the Page API properly documented.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=52835</id>
		<title>Tutorial</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=52835"/>
		<updated>2017-08-21T03:55:09Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Welcome to Moodle development!&lt;br /&gt;
&lt;br /&gt;
This is a tutorial to help you learn how to write plugins for Moodle from start to finish, while showing you how to navigate the most important developer documentation along the way.&lt;br /&gt;
&lt;br /&gt;
PRE-REQUISITES:  We assume you are fairly comfortable with [[PHP FAQ|PHP]] in general and that you are able to [[:en:Installing AMP|install a database and web server]] on your local machine. &lt;br /&gt;
&lt;br /&gt;
If you need to learn PHP, you can see one PHP tutorial at http://www.w3schools.com/php/default.asp, another at http://php.net/manual/en/tutorial.php and several videos in YouTube at https://www.youtube.com/results?search_query=learn+php. There is a very old unmaintained Introduction to Moodle 1.8 Programming course at http://dev.moodle.org/course/view.php?id=2.&lt;br /&gt;
&lt;br /&gt;
Code examples can be found on GitHub at https://github.com/abgreeve/devcourse where a working plugin is located.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
===What&#039;s in the box===&lt;br /&gt;
If you [http://download.moodle.org/ download] Moodle source code or clone it from [https://github.com/moodle/moodle git], you will see a bunch of files and folders. This code consists of [[Core_APIs|Moodle core]] (that consists of the Very core and Core components), [[Moodle_libraries_credits|third party libraries]] and [[Plugin_types|plugins]]. Their mixed locations can be quite confusing at first but as you start working with it it will become more clear. Moodle developers should avoid modifications of the third party libraries (unless required) and core can never call methods defined in plugins. See also [[Communication Between Components]]&lt;br /&gt;
&lt;br /&gt;
===Setting up your development environment===&lt;br /&gt;
* Moodle uses Git for developement. View the link below for basic information about Git and Moodle.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Git for developers]]&lt;br /&gt;
&lt;br /&gt;
===The Moodle development framework===&lt;br /&gt;
===What type of plugin are you developing?===&lt;br /&gt;
* Moodle has lots of different types of plugins.&lt;br /&gt;
* There are 24 different categories of plugin listed on the moodle plugin database. Before starting check here to see if someone else has not already created what you are looking for. Perhaps you could contribute to their plugin instead of creating a new one.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* https://moodle.org/plugins/&lt;br /&gt;
* [[Plugin types]]&lt;br /&gt;
&lt;br /&gt;
==Let&#039;s make a plugin==&lt;br /&gt;
===The skeleton of your plugin===&lt;br /&gt;
&lt;br /&gt;
You plugin code will be organised into multiple files within a single root directory (and the subdirectories).&lt;br /&gt;
&lt;br /&gt;
The page [[Plugin files]] provides a list of common plugins files and their purpose.&lt;br /&gt;
&lt;br /&gt;
See also:&lt;br /&gt;
&lt;br /&gt;
* [[Moodle architecture]] - general overview of Moodle code architecture&lt;br /&gt;
* [[Plugin types]] - list of all supported plugin types&lt;br /&gt;
* [https://moodle.org/plugins/ Moodle plugins directory] - repository of contributed plugins for Moodle&lt;br /&gt;
* [https://moodle.org/plugins/tool_pluginskel Moodle plugin skeleton generator] - allows to quickly generate code skeleton for a new plugin&lt;br /&gt;
&lt;br /&gt;
===Basic page structure===&lt;br /&gt;
&lt;br /&gt;
* For a page that is displaying content to a user we have the following sections:&lt;br /&gt;
** Required files.&lt;br /&gt;
** POST and GET variables retrieved using required_param and optional_param.&lt;br /&gt;
** context.&lt;br /&gt;
** navigation setup.&lt;br /&gt;
** title, headings, headers.&lt;br /&gt;
** content.&lt;br /&gt;
** footers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Required files.&lt;br /&gt;
require_once(__DIR__ . &#039;/config.php&#039;);&lt;br /&gt;
// Required and optional parameters.&lt;br /&gt;
$id = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$text = optional_param(&#039;text&#039;, &#039;&#039;, PARAM_ALPHA);&lt;br /&gt;
&lt;br /&gt;
// Setting context for the page.&lt;br /&gt;
$PAGE-&amp;gt;set_context(context_system::instance());&lt;br /&gt;
// URL is created and then set for the page navigation.&lt;br /&gt;
$url = new moodle_url(&#039;/test.php&#039;);&lt;br /&gt;
$PAGE-&amp;gt;set_url($url);&lt;br /&gt;
// Heading, headers, page layout.&lt;br /&gt;
$PAGE-&amp;gt;set_heading(get_string(&#039;hello&#039;));&lt;br /&gt;
$PAGE-&amp;gt;set_pagelayout(&#039;standard&#039;);&lt;br /&gt;
echo $OUTPUT-&amp;gt;header();&lt;br /&gt;
// Displaying basic content.&lt;br /&gt;
echo html_writer::tag(&#039;p&#039;, $text);&lt;br /&gt;
// Display the footer.&lt;br /&gt;
echo $OUTPUT-&amp;gt;footer();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Page API]]&lt;br /&gt;
&lt;br /&gt;
===How to support over 100 languages===&lt;br /&gt;
* Language files are stored in the &amp;quot;lang&amp;quot; directory. English strings would be found in &amp;quot;lang/en&amp;quot;. Each language contains a file named after the plugin which contains all of the strings. For example the language strings for the assignment activity are found in &amp;quot;mod/assign/lang/en/assign.php&amp;quot;.&lt;br /&gt;
* [[:en:Language FAQ#Which_is_the_official_language_for_Moodle.3F| Moodle&#039;s default is Australian English]]. &lt;br /&gt;
** American English is a separate language pack (en_us). Please use only Australian (UK) English grammar and spelling when writing Moodle plugins.&lt;br /&gt;
** There is no need to include languages other than the default English, as almost all approved [https://lang.moodle.org/mod/forum/discuss.php?d=2485 plugin strings will be automatically imported into AMOS] for translation by the language packs translators.  &lt;br /&gt;
* get_string() is used in most cases for displaying text.&lt;br /&gt;
* lang_string() is used in situations where the text may not necessarily be displayed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Declaration in language file (lang/en/{pluginname}.php)&lt;br /&gt;
$string[&#039;nameofstring&#039;] = &#039;Actual string&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The get_string() function takes four parameters, but in this example we are only filling in the first two. The last two parameters are optional. The first parameter is the identifier for the string. The second is the component.&lt;br /&gt;
The component will be the name of the language file.&lt;br /&gt;
The following example shows a string in the badges block.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Use of string in code.&lt;br /&gt;
echo html_writer::tag(&#039;p&#039;, get_string(&#039;numbadgestodisplay&#039;, &#039;block_badges&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[String API]]&lt;br /&gt;
* [[Places to search for lang strings]]&lt;br /&gt;
* [[:en:Language customisation]]&lt;br /&gt;
* [[Plugin contribution checklist#Strings]]&lt;br /&gt;
&lt;br /&gt;
===Add content to your page===&lt;br /&gt;
* Content for a page is added through renderers.&lt;br /&gt;
* Renderers are typically stored in the &amp;quot;classes/output&amp;quot; directory.&lt;br /&gt;
* Putting content in renderers allows themers to override the visual display of the content.&lt;br /&gt;
* Very basic information is presented using the html_writer class.&lt;br /&gt;
* In most cases templates should be used.&lt;br /&gt;
* templates are stored in the &amp;quot;templates&amp;quot; directory. The templates use mustache files.&lt;br /&gt;
* Mustache files allow for more generic html with placeholders inserted, that inserts the data (context) at run time.&lt;br /&gt;
&lt;br /&gt;
The example used below is an admin tool and would be located under admin/tool.&lt;br /&gt;
&lt;br /&gt;
Step One: Create a class for rendering. This class collects information to display and has a method for formatting that information into a format that the template will understand.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/classes/output/developer_course_main_page.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace tool_devcourse\output;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
use renderable;&lt;br /&gt;
use renderer_base;&lt;br /&gt;
use templatable;&lt;br /&gt;
use stdClass;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class developer_course_main_page implements renderable, templatable {&lt;br /&gt;
&lt;br /&gt;
   protected $comment;&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Construct this renderable.&lt;br /&gt;
     * @param int $courseid The course record for this page.&lt;br /&gt;
     */&lt;br /&gt;
    public function __construct($comment) {&lt;br /&gt;
        $this-&amp;gt;comment = $comment;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Export this data so it can be used as the context for a mustache template.&lt;br /&gt;
     *&lt;br /&gt;
     * @param renderer_base $output Renderer base.&lt;br /&gt;
     * @return stdClass&lt;br /&gt;
     */&lt;br /&gt;
    public function export_for_template(renderer_base $output) {&lt;br /&gt;
        $data = new stdClass();&lt;br /&gt;
        $data-&amp;gt;comment = $this-&amp;gt;comment;&lt;br /&gt;
        return $data;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Step Two: To render this information a custom renderer is created for the plugin. This renderer class must extend plugin_renderer_base.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/classes/output/renderer.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace tool_devcourse\output;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
use plugin_renderer_base;&lt;br /&gt;
use renderable;&lt;br /&gt;
&lt;br /&gt;
class renderer extends plugin_renderer_base {&lt;br /&gt;
&lt;br /&gt;
     /**&lt;br /&gt;
     * Defer to template.&lt;br /&gt;
     *&lt;br /&gt;
     * @param developer_course_main_page $page&lt;br /&gt;
     *&lt;br /&gt;
     * @return string html for the page&lt;br /&gt;
     */&lt;br /&gt;
    public function render_developer_course_main_page(developer_course_main_page $page) {&lt;br /&gt;
        $data = $page-&amp;gt;export_for_template($this);&lt;br /&gt;
        return parent::render_from_template(&#039;tool_devcourse/developer_course_main_page&#039;, $data);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Step three: A mustache template is to then be created. The information is sent to the template and at this point the information is known as the context (not to be confused with the normal definition of context throughout Moodle).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;devcourse/templates/developer_course_main_page.mustache&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code html&amp;gt;&lt;br /&gt;
{{!&lt;br /&gt;
    @template tool_devcourse/developer_course_main_page&lt;br /&gt;
&lt;br /&gt;
    Example context (json):&lt;br /&gt;
    {&lt;br /&gt;
        &amp;quot;comment&amp;quot;: &amp;quot;Example comment for the context&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;h2&amp;gt;{{#str}}maintitle, tool_devdoc{{/str}}&amp;lt;/h2&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;{{comment}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This shows an extremely simple mustache template with one item in the context (comment). It also shows how strings are defined in the template.&lt;br /&gt;
&lt;br /&gt;
Step four: To actually have this template be displayed we get the custom renderer. This chunk of code would be located in a place such as devcourse/index.php after the appropriate setup outlined in the [[Tutorial#Basic_page_structure|basic page structure]].&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$output = $PAGE-&amp;gt;get_renderer(&#039;tool_devcourse&#039;);&lt;br /&gt;
//Then we get the class for rendering and provide it with information (if needed).&lt;br /&gt;
$randomcomment = &#039;This comment is random&#039;;&lt;br /&gt;
$page = new \tool_devdoc\output\developer_course_main_page($randomcomment);&lt;br /&gt;
//Finally we echo out the template&lt;br /&gt;
echo $output-&amp;gt;render($page);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Output API]]&lt;br /&gt;
* [[Output functions]]&lt;br /&gt;
* [[Templates]]&lt;br /&gt;
* [[Output renderers]]&lt;br /&gt;
* [[Renderer]]&lt;br /&gt;
* [[Overriding a renderer]]&lt;br /&gt;
&lt;br /&gt;
===Adding your plugin into Moodle&#039;s navigation===&lt;br /&gt;
* The moodle navigation system has hooks which allows plugins to add links to the navigation menu.&lt;br /&gt;
* Hooks are located in lib.php. Try to keep lib.php as small as possible as this file is included on every page. Put classes and functions elsewhere.&lt;br /&gt;
* Course navigation extension example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function tool_devcourse_extend_navigation_course($navigation, $course, $coursecontext) {&lt;br /&gt;
    $url = new moodle_url(&#039;/admin/tool/devcourse/index.php&#039;);&lt;br /&gt;
    $devcoursenode = navigation_node::create(&#039;Development course&#039;, $url, navigation_node::TYPE_CUSTOM, &#039;Dev course&#039;, &#039;devcourse&#039;);&lt;br /&gt;
    $navigation-&amp;gt;add_node($devcoursenode);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Navigation API]]&lt;br /&gt;
* [[:en:Navigation]]&lt;br /&gt;
&lt;br /&gt;
===Database queries===&lt;br /&gt;
* Moodle has a generic database query library. Behind this library are additional libraries which allow Moodle to work with MySQL, PostgreSQL, Oracle, SQL Server, and Maria DB.&lt;br /&gt;
* Where possible it is advisable to use the predefined functions rather than write out SQL. Writing SQL has a greater chance of not working with one of the supported databases.&lt;br /&gt;
* The return of the select functions tends to be an object or an array of objects.&lt;br /&gt;
&lt;br /&gt;
Example call to retrieve data from the course table.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
global $DB;&lt;br /&gt;
$courses = $DB-&amp;gt;get_records(&#039;course&#039;, null, &#039;&#039;, &#039;id, category, fullname, shortname&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Example of data returned from the above code.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Array&lt;br /&gt;
(&lt;br /&gt;
    [43] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 43&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; XX -Test 5&lt;br /&gt;
            [shortname] =&amp;gt; xxt5&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    [5] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 5&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; With the glossary&lt;br /&gt;
            [shortname] =&amp;gt; wtg&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    [39] =&amp;gt; stdClass Object&lt;br /&gt;
        (&lt;br /&gt;
            [id] =&amp;gt; 39&lt;br /&gt;
            [category] =&amp;gt; 1&lt;br /&gt;
            [fullname] =&amp;gt; XX - Test 1&lt;br /&gt;
            [shortname] =&amp;gt; xxt1&lt;br /&gt;
        )&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Database]]&lt;br /&gt;
* [[Data manipulation API]]&lt;br /&gt;
&lt;br /&gt;
===Creating your own database tables===&lt;br /&gt;
* We create our database tables in Moodle using the  XMLDB editor. This is located in the administration block &amp;quot;Site administration | Development | XMLDB editor&amp;quot;.&lt;br /&gt;
* The {plugin}\db directory needs to have write access for the XMLDB editor to be most effective.&lt;br /&gt;
* XMLDB editor creates an install.xml file in the db directory. This file will be loaded during the install to create your tables.&lt;br /&gt;
* XMLDB editor will produce php update code for adding and updating moodle database tables.&lt;br /&gt;
&lt;br /&gt;
The XMLDB main page.&lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:xmldb-main.png]]&lt;br /&gt;
&lt;br /&gt;
Upgrade code generated by the XMLDB&lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:xmldb-upgrade-code.png]]&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[XMLDB editor]]&lt;br /&gt;
* [[Using XMLDB]]&lt;br /&gt;
* [[XMLDB Documentation]]&lt;br /&gt;
* [[Upgrade API]]&lt;br /&gt;
* [[XMLDB introduction]]&lt;br /&gt;
&lt;br /&gt;
===Supporting access permissions: roles, capabilities and contexts===&lt;br /&gt;
* Capabilities are controlled in &amp;quot;access.php&amp;quot; under the &amp;quot;db&amp;quot; directory.&lt;br /&gt;
* This file has an array of capabilities with the following:&lt;br /&gt;
** name&lt;br /&gt;
** possible security risks behind giving this capability.&lt;br /&gt;
** The context that this capability works in.&lt;br /&gt;
** The default roles (teacher, manager, student, etc) that have this capability.&lt;br /&gt;
** Various other information.&lt;br /&gt;
* These capabilities are checked in code to allow access to pages, sections, and abilities (saving, deleting, etc).&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
* [[Access API]]&lt;br /&gt;
* [[Roles#Context]]&lt;br /&gt;
* [[:en:Category:Capabilities]]&lt;br /&gt;
* [[:en:Roles and permissions]]&lt;br /&gt;
&lt;br /&gt;
===Adding web forms===&lt;br /&gt;
* Moodle has it&#039;s own forms library.&lt;br /&gt;
* The forms lib includes a lot of accessibility code, and error checking, by default.&lt;br /&gt;
* Moodle forms can be displayed in JavaScript using &#039;fragments&#039;.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Form API]]&lt;br /&gt;
* [[lib/formslib.php Form Definition]]&lt;br /&gt;
* [[Fragment]]&lt;br /&gt;
&lt;br /&gt;
===Maintaining good security===&lt;br /&gt;
* Use the sesskey when directing to pages to do actions.&lt;br /&gt;
* Use the appropriate filters when retrieving parameters&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[lib/formslib.php Form Definition#Most Commonly Used PARAM .2A Types]]&lt;br /&gt;
* [[Output functions#p.28.29 and s.28.29]]&lt;br /&gt;
&lt;br /&gt;
===Handling files===&lt;br /&gt;
* Files are conceptually stored in file areas.&lt;br /&gt;
* Plugins can only access files from it&#039;s own component.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[File API]]&lt;br /&gt;
* [[File API internals]]&lt;br /&gt;
* [[Using the File API in Moodle forms]]&lt;br /&gt;
&lt;br /&gt;
===Adding Javascript===&lt;br /&gt;
* Moodle is currently using jquery and AMD (Asynchronous Module Definition).&lt;br /&gt;
* JavaScript files are located in the &amp;quot;amd/src&amp;quot; directory.&lt;br /&gt;
* Use grunt to build your JavaScript.&lt;br /&gt;
* Include your JavaScript in php files as follows:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;requires-&amp;gt;js_call_amd(&#039;{JScriptfilename}&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* Can also be included in mustache templates.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Javascript Modules]]&lt;br /&gt;
* [[jQuery]]&lt;br /&gt;
* [[Javascript FAQ]]&lt;br /&gt;
* [[JavaScript guidelines]]&lt;br /&gt;
* [[Grunt]]&lt;br /&gt;
&lt;br /&gt;
===Adding events and logging===&lt;br /&gt;
* All logging in moodle is done through the events system.&lt;br /&gt;
* New events should be located in the &amp;quot;classes/event&amp;quot; directory.&lt;br /&gt;
* It is possible to create observers and subscribe to events.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Event 2]]&lt;br /&gt;
* [[Logging 2]]&lt;br /&gt;
&lt;br /&gt;
===Web Services and AJAX===&lt;br /&gt;
* Moodle web services uses the external functions API.&lt;br /&gt;
* The recommended way to make AJAX requests is to use the ajax AMD file which uses the external functions API.&lt;br /&gt;
* External functions should be located in the &amp;quot;classes/external.php&amp;quot; file.&lt;br /&gt;
* A list of services should be included in &amp;quot;db/services.php&amp;quot;. This file is required to register the web services with Moodle.&lt;br /&gt;
* The services list is an array which contains:&lt;br /&gt;
** &#039;&#039;&#039;classname&#039;&#039;&#039; Name of the external class.&lt;br /&gt;
** &#039;&#039;&#039;methodname&#039;&#039;&#039; The name of the external function.&lt;br /&gt;
** &#039;&#039;&#039;classpath&#039;&#039;&#039; system path to the external function file.&lt;br /&gt;
** &#039;&#039;&#039;description&#039;&#039;&#039; Description of the function&lt;br /&gt;
** &#039;&#039;&#039;type&#039;&#039;&#039; Create, read, update, delete&lt;br /&gt;
** &#039;&#039;&#039;ajax&#039;&#039;&#039; Can this function be used with ajax?&lt;br /&gt;
** &#039;&#039;&#039;capabilities&#039;&#039;&#039; Capabilities required to use this function.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[External functions API]]&lt;br /&gt;
* [[Adding a web service to a plugin]]&lt;br /&gt;
* [[Web services API]]&lt;br /&gt;
&lt;br /&gt;
===Using caching to improve performance===&lt;br /&gt;
* The main cache used by moodle is the Moodle Universal Cache (MUC).&lt;br /&gt;
* The MUC has several cache definitions - &lt;br /&gt;
** Request cache&lt;br /&gt;
** Session cache&lt;br /&gt;
** Application&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[The Moodle Universal Cache (MUC)]]&lt;br /&gt;
* [[:en:MUC FAQ]]&lt;br /&gt;
* [[:en:Caching]]&lt;br /&gt;
&lt;br /&gt;
===Supporting backup and restore===&lt;br /&gt;
* Supporting backup and restore requires creating several files in the &#039;backup/moodle2&#039; directory.&lt;br /&gt;
* Back requires a class to extend the backup_task of some sort. There may be a specific plugin task to extend.&lt;br /&gt;
* Restore requires a class to extend the restore_task of some sort. There may be a specific plugin task to extend.&lt;br /&gt;
* The restore steps lib defines the structure of the plugin to be restored.&lt;br /&gt;
* The backup steps lib defines steps, settings, attributes, etc.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Backup 2.0 for developers]] - provides an example of step-by-step implementation of backup support to your plugin&lt;br /&gt;
* [[:en:Backup and restore FAQ]]&lt;br /&gt;
&lt;br /&gt;
===Supporting automated testing===&lt;br /&gt;
* Moodle has two types of automated testing: php unit tests, and behat tests.&lt;br /&gt;
* Unit tests are for testing functions.&lt;br /&gt;
* Behat tests runs through scenarios.&lt;br /&gt;
** Behat tests follows a script and navigates through moodle pages.&lt;br /&gt;
* unit tests should be located in the &amp;quot;tests&amp;quot; directory.&lt;br /&gt;
* behat tests should be located in the &amp;quot;tests/behat&amp;quot; directory.&lt;br /&gt;
* Tests located in these directories will be run through when a full test run is initiated.&lt;br /&gt;
* behat tests are actually feature files and end with the extension &amp;quot;.feature&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
links&lt;br /&gt;
&lt;br /&gt;
* [[Writing PHPUnit tests]]&lt;br /&gt;
* [[PHPUnit]]&lt;br /&gt;
* [[Acceptance testing]]&lt;br /&gt;
* [[Behat integration]]&lt;br /&gt;
&lt;br /&gt;
==Publishing your plugin==&lt;br /&gt;
===Adding your plugin to moodle.org===&lt;br /&gt;
* publish your plugins at https://moodle.org/plugins/&lt;br /&gt;
* Publishing plugins on the moodle site leads you through a bunch of steps that need to be completed in order for the plugin to be approved and published.&lt;br /&gt;
* Plugins will be run through a pre-checker to give suggestions about possible issues with the code.&lt;br /&gt;
&lt;br /&gt;
===Supporting your plugin===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=TODO=&lt;br /&gt;
&lt;br /&gt;
Finishing this tutorial:&lt;br /&gt;
# About one or two screens for each section with a very generic overview for beginners, containing links to relevant docs WITH COMMENTS ABOUT QUALITY, USEFULNESS, CAVEATS etc.&lt;br /&gt;
# Go through all the linked pages and make sure they are current and accurate.&lt;br /&gt;
# Add a worked example to this page, so that each section has suggestions about things to add to the admin tool being built as an exercise.  If the code is long, it could be placed on separate pages.  A good reference for style is [[Moodle_Mobile_Developing_a_plugin_tutorial]] and [[Blocks]].&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* See [https://moodle.org/mod/forum/discuss.php?d=352360 this forum thread] about Getting Started with Moodle Development.&lt;br /&gt;
&lt;br /&gt;
=See also these older tutorials =&lt;br /&gt;
* [[Blocks|A Step-by-step Guide To Creating Blocks]] &lt;br /&gt;
* [[NEWMODULE Tutorial]]&lt;br /&gt;
* [http://dev.moodle.org Introduction to Moodle programming (based on Moodle 1.8)]&lt;br /&gt;
* [[Moodle_Mobile_Developing_a_plugin_tutorial|Moodle Mobile plugin tutorial]]&lt;br /&gt;
* [[Category:Tutorial|Other tutorials in these docs]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Tutorial]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Developer_meeting_July_2015&amp;diff=48304</id>
		<title>Developer meeting July 2015</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Developer_meeting_July_2015&amp;diff=48304"/>
		<updated>2015-07-20T09:23:06Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* Agenda */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Developer meetings]] &amp;gt; July 2015 meeting notes&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Time&lt;br /&gt;
| [http://www.timeanddate.com/worldclock/fixedtime.html?year=2015&amp;amp;month=7&amp;amp;day=21&amp;amp;hour=07&amp;amp;min=0&amp;amp;sec=0 07:00 UTC on Tuesday, 21 July 2015] [http://www.google.com/calendar/event?action=TEMPLATE&amp;amp;text=Moodle+General+developer+meeting&amp;amp;dates=20150721T070000Z/20150721T090000Z&amp;amp;details=&amp;amp;location= &amp;lt;span class=&amp;quot;btn btn-info&amp;quot;&amp;gt;Add to my calendar&amp;lt;/span&amp;gt;]&lt;br /&gt;
|-&lt;br /&gt;
| Meeting room&lt;br /&gt;
| [https://www.youtube.com/watch?v=pgPBohzErr4 Live stream at YouTube]&lt;br /&gt;
|-&lt;br /&gt;
| Forum discussion&lt;br /&gt;
| [https://moodle.org/mod/forum/discuss.php?d=316807 Thread in GDF at moodle.org]&lt;br /&gt;
|-&lt;br /&gt;
| Chat&lt;br /&gt;
| [https://moodle.org/local/chatlogs/info.php Regular dev chat]&lt;br /&gt;
|-&lt;br /&gt;
| Twitter&lt;br /&gt;
| [https://twitter.com/search?q=%23moodledev #moodledev]&lt;br /&gt;
|-&lt;br /&gt;
| Social event page&lt;br /&gt;
| [https://plus.google.com/events/c63rl8n5jdjldr9slcd1tdcqmg0 Google+ page]&lt;br /&gt;
|-&lt;br /&gt;
| Meeting notes&lt;br /&gt;
| [https://devpad.moodle.org/p/gdm150721 devpad]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Agenda ==&lt;br /&gt;
&lt;br /&gt;
* Moodle Mobile 2 - Juan Leyva&lt;br /&gt;
* Summary report of the recent MoodleMoot Working groups and hackfests (Dublin, Melbourne) - David Mudrák, Andrew Nicols, Michael de Raadt&lt;br /&gt;
* Moodle Association and how it is supposed to affect the Moodle development in the future - Martin Dougiamas&lt;br /&gt;
* Moodle HQ&#039;s personal projects week products - HQ devs&lt;br /&gt;
** Improved East Asian support (ruby tags in Atto and in fullname()) - Jetha Chan&lt;br /&gt;
** mod_lesson improved lesson creation tool - Adrian Greeve&lt;br /&gt;
** Events Graphic Reports plugin - Simey Lameze&lt;br /&gt;
** Moodle - Ifttt integration - Ankit Agarwal&lt;br /&gt;
* Work in progress on Learning plans and outcomes project for Moodle 3.0 - Damyon (to be confirmed)&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Please feel encouraged to raise topics you would like to present / discuss during the meeting. Contact [https://moodle.org/user/profile.php?id=1601 David Mudrák] for details.&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Release_process&amp;diff=48000</id>
		<title>Release process</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Release_process&amp;diff=48000"/>
		<updated>2015-06-09T02:24:22Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* 1 week after */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== 8 weeks prior ==&lt;br /&gt;
{| class=&amp;quot;table table-striped table-bordered&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | #&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Major&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Minor&lt;br /&gt;
! Task&lt;br /&gt;
! style=&amp;quot;width:12%&amp;quot; | Responsibility&lt;br /&gt;
|-&lt;br /&gt;
| 1.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Create an issue to review latest stable version of all third party libraries and add to sprint. The issue should refer to the list at [[Moodle libraries credits]]. The issue can be a clone of MDL-47147.&lt;br /&gt;
| Development Manager&lt;br /&gt;
|-&lt;br /&gt;
| 2.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Ensure we are running latest/good behat version.&lt;br /&gt;
| Testing Maintainer&lt;br /&gt;
|-&lt;br /&gt;
| 3.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
|  &lt;br /&gt;
| Move [http://tiny.cc/gl8swx QA tests] for new features in old release with automated tests from MDLQA-1 to MDLQA-5249. &lt;br /&gt;
| Testing Maintainer&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==7 weeks prior==&lt;br /&gt;
{| class=&amp;quot;table table-striped table-bordered&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | #&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Major&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Minor&lt;br /&gt;
! Task&lt;br /&gt;
! style=&amp;quot;width:12%&amp;quot; | Responsibility&lt;br /&gt;
|-&lt;br /&gt;
| 1.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Full demo of new code and sign-off for internal HQ projects. Decide which projects will be completed by the code freeze.&lt;br /&gt;
| Lead Developer&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==6 weeks prior==&lt;br /&gt;
{| class=&amp;quot;table table-striped table-bordered&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | #&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Major&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Minor&lt;br /&gt;
! Task&lt;br /&gt;
! style=&amp;quot;width:12%&amp;quot; | Responsibility&lt;br /&gt;
|-&lt;br /&gt;
| 1.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Create the next &amp;quot;X.Y+1&amp;quot; (next dev) version in the Tracker (MDL and CONTRIB), so people can move delayed stuff to next major release if needed.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 2.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Create a &amp;quot;Must fix for X.Y&amp;quot; version in the tracker.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 3.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Warn external developers about the impending code freeze in a post to the [http://moodle.org/mod/forum/view.php?id=55 General developer forum]. ([https://moodle.org/mod/forum/discuss.php?d=225854 example])&lt;br /&gt;
| Development Manager&lt;br /&gt;
|-&lt;br /&gt;
| 4.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Check [https://tracker.moodle.org/issues/?jql=labels%20%3D%20qa_test_required%20AND%20status%20%3D%20Closed closed qa_test_required-labelled issues] and create new QA tests as required. If features has automated tests then set priority to blocker and link the issue as &amp;quot;is a QA written for&amp;quot;&lt;br /&gt;
| Community Manager&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==5 weeks prior==&lt;br /&gt;
{| class=&amp;quot;table table-striped table-bordered&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | #&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Major&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Minor&lt;br /&gt;
! Task&lt;br /&gt;
! style=&amp;quot;width:12%&amp;quot; | Responsibility&lt;br /&gt;
|-&lt;br /&gt;
| 1.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Confirm the code freeze by replying to the previous warning in the [http://moodle.org/mod/forum/view.php?id=55 General developer forum].&lt;br /&gt;
| Development manager&lt;br /&gt;
|-&lt;br /&gt;
| 2.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Once the integration server has ended with Monday&#039;s job [http://integration.moodle.org/view/tracker/job/Tracker%20-%20CI%20-%20Move%20awaiting%20issues%20to%20current%20integration Move awaiting issues to current integration] it will be disabled and, issues will be manually picked for integration until the post-release &amp;quot;On Sync&amp;quot; period ends (usually 3 weeks after release).&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 3.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Prepare a fresh installation of the [http://qa.moodle.net QA site] based on the beta code to make sure the site is not affected by incremental upgrade steps during the development cycle.&lt;br /&gt;
| QA Master Site Maintainer&lt;br /&gt;
|-&lt;br /&gt;
| 4.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Write documentation on new features in the dev docs, adding a link to it from the tracker issue, together with the label &#039;&#039;docs_required&#039;&#039;. The documentation will then be transferred to the new en version wiki when it is set up (3 weeks prior) and polished, with screenshots added.&lt;br /&gt;
| &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==4 weeks prior==&lt;br /&gt;
{| class=&amp;quot;table table-striped table-bordered&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | #&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Major&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Minor&lt;br /&gt;
! Task&lt;br /&gt;
! style=&amp;quot;width:12%&amp;quot; | Responsibility&lt;br /&gt;
|-&lt;br /&gt;
| 1.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Start working on the [[Releases|release notes]] ([[Release notes template|template]]) of the upcoming version.&lt;br /&gt;
| Development Manager&lt;br /&gt;
|-&lt;br /&gt;
| 2.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Release normal weeklies but with these changes in the master branch:&lt;br /&gt;
* version.php: Move to $maturity = MATURITY_BETA and $release  = &#039;X.Ybeta (Build:xxxxxxxx)&#039;&lt;br /&gt;
* tag git repo with: &amp;quot;vX.Y.0-beta&amp;quot; (and MOODLE_XY_BETA as description and CVS tag)&lt;br /&gt;
And make packages available under download.moodle.org (and windows). Promote master up in the download page and adjust info for it.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 3.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| (Optionally) Announce Beta release in forums (ideally once packages are available).&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 4.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| During the QA weeks integration [[Integration Review#During continuous integration/Freeze/QA period|becomes continuous]]; roll (on demand, beta, rc...) happens often (Tuesday &amp;amp; Friday are the usual days).&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 5.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| At some points produce release candidates (Z = 1, 2, 3..), which are normal builds with:&lt;br /&gt;
* version.php: Move to $maturity = MATURITY_RC and $release  = &#039;X.YrcZ (Build:xxxxxxxx)&#039;&lt;br /&gt;
* tag git repo with: &amp;quot;vX.Y.0-rcZ&amp;quot;  (and MOODLE_XY_RCZ as description and CVS tag)&lt;br /&gt;
* Make packages available under download.moodle.org (and Windows).&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 6.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Add a new version in the Plugins Directory with the version&#039;s name and the beta release version build number (https://moodle.org/plugins/admin/softwareversions.php).&lt;br /&gt;
* Any standard plugins being retired from the release can transition to Add-on (that supports this release and/or any previous ones) now.&lt;br /&gt;
* These plugins currently collect at https://moodle.org/plugins/browse.php?list=contributor&amp;amp;id=1532512&lt;br /&gt;
| Plugins Liaison&lt;br /&gt;
|-&lt;br /&gt;
| 7.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Tidy up current latest en version of Moodle Docs prior to copying it to create new version wiki as described in [[New docs version process]].&lt;br /&gt;
| Community Manager&lt;br /&gt;
|-&lt;br /&gt;
| 8.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Create new QA test cycle and invite community volunteers to start [[QA testing]].&lt;br /&gt;
| Community Manager&lt;br /&gt;
|-&lt;br /&gt;
| 9.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Monitor QA fails. Check each fail is real and if so ensure an MDL issue has been created and correctly linked and labelled.&lt;br /&gt;
| Testing Maintainer&lt;br /&gt;
|-&lt;br /&gt;
| 10.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Monitor MDL issues created for QA fails. Add them to the &amp;quot;Must fix for X.Y&amp;quot; list and get a developer to work on the issue immediately.&lt;br /&gt;
| Development Manager&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==3 weeks prior==&lt;br /&gt;
{| class=&amp;quot;table table-striped table-bordered&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | #&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Major&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Minor&lt;br /&gt;
! Task&lt;br /&gt;
! style=&amp;quot;width:12%&amp;quot; | Responsibility&lt;br /&gt;
|-&lt;br /&gt;
| 1.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Prompt developers to begin QA tests marked &#039;&#039;test_server_required&#039;&#039;.&lt;br /&gt;
| Development Manager&lt;br /&gt;
|-&lt;br /&gt;
| 2.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Create new en and de Moodle Docs version wikis.&lt;br /&gt;
| Moodle Docs Maintainer&lt;br /&gt;
|-&lt;br /&gt;
| 3.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Check [https://tracker.moodle.org/issues/?jql=labels%20%3D%20docs_required%20AND%20status%20%3D%20Closed docs_required-labelled issues] and write new documentation, removing the label and commenting in the issue when the work is done.&lt;br /&gt;
| Community Manager&lt;br /&gt;
|-&lt;br /&gt;
| 4.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
|&lt;br /&gt;
| Go through all points listed under 3 weeks prior in [[New docs version process]].&lt;br /&gt;
| Community Manager&lt;br /&gt;
|-&lt;br /&gt;
| 5.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Review issues with labelled with [https://tracker.moodle.org/issues/?filter=11824&amp;amp;jql=labels%20in%20%28dev_docs_required%29%20AND%20resolution%20%3D%20fixed%20ORDER%20BY%20assignee%20ASC%2C%20created%20ASC dev_docs_required], prompting assigned developers to create/update this documentation and remove this label when relevant docs are updated.&lt;br /&gt;
| Development Manager&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==2 weeks prior==&lt;br /&gt;
{| class=&amp;quot;table table-striped table-bordered&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | #&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Major&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Minor&lt;br /&gt;
! Task&lt;br /&gt;
! style=&amp;quot;width:12%&amp;quot; | Responsibility&lt;br /&gt;
|-&lt;br /&gt;
| 1.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
|&lt;br /&gt;
* Prompt developers to complete remaining QA tests.&lt;br /&gt;
* Ensure all QA tests are completed and passed by the end of the week.&lt;br /&gt;
| Development Manager&lt;br /&gt;
|-&lt;br /&gt;
| 2.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
|&lt;br /&gt;
Create MDLSITE issue to ensure all prototype.moodle.net sites which are no longer relevant (part of release) are removed from prototype.moodle.net&lt;br /&gt;
| Development Manager&lt;br /&gt;
|-&lt;br /&gt;
| 3.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Merge fixes from en_fix pack and then integrate them.&lt;br /&gt;
| AMOS Maintainer&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==1 week prior==&lt;br /&gt;
{| class=&amp;quot;table table-striped table-bordered&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | #&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Major&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Minor&lt;br /&gt;
! Task&lt;br /&gt;
! style=&amp;quot;width:12%&amp;quot; | Responsibility&lt;br /&gt;
|-&lt;br /&gt;
| 1.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Clone as many filters as needed in the Tracker, modifying them to point to the new, upcoming, branch (keeping same perms, title...). &lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 2.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Create new minor version X.Y.Z+1 in the Tracker (MDL and CONTRIB). Archive any version &amp;gt; 6 months old.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 3.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Clone MDL-50102 and bump all versions, requires and dependencies along all plugins in codebase to planned release dates.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 4.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Post a &amp;quot;Heads-up&amp;quot; message on the [http://partners.moodle.com/mod/forum/view.php?id=2 Partners forum] and [http://moodle.org/mod/forum/view.php?id=55 General Developer forum].&lt;br /&gt;
| Development Manager&lt;br /&gt;
|-&lt;br /&gt;
| 5.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Post a &amp;quot;Heads-up&amp;quot; message on Twitter and other outlets.&lt;br /&gt;
| Marketing Officer&lt;br /&gt;
|-&lt;br /&gt;
| 6.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Identify security issues that need to be integrated using the [http://tracker.moodle.org/secure/IssueNavigator.jspa?reset=true&amp;amp;jqlQuery=labels+%3D+security_held security_held label].&lt;br /&gt;
* Integrate from provided patches into supported branches (including branches supported only for security issues).&lt;br /&gt;
* Ensure security issues are given priority in weekly integration and testing. &lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 7.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Collect security issues into a clone of the [https://tracker.moodle.org/issues/?jql=component%20%3D%20%22Security%20Alert%22%20AND%20project%20%3D%20MDL%20AND%20level%20is%20not%20EMPTY%20AND%20summary%20~%20%22security%20advisories%22%20ORDER%20BY%20updated%20DESC last advisory in the list] to prepare for release of Security Advisories.&lt;br /&gt;
* Determine which security issues will be integrated.&lt;br /&gt;
* Request CVE Identifiers by emailing issue descriptions to [mailto:distros@vs.openwall.org distros@vs.openwall.org] with a message like... &amp;lt;tt&amp;gt; The following security issues have been discovered in Moodle. We request CVE Identifiers for these issues. We will be releasing the security announcements for these on moodle.org on XXX at 12noon AWST which is 04:00 UTC.&amp;lt;/tt&amp;gt; The email subject should include the characters &amp;lt;tt&amp;gt;[vs]&amp;lt;/tt&amp;gt;. The format needs to be plain text or encrypted. When granted CVE Identifiers, our issues should appear in the [http://cve.mitre.org/cve/cve.html CVE list]. More [http://oss-security.openwall.org/wiki/mailing-lists/distros instructions] are available.&lt;br /&gt;
* Post security issues as a reply to the &amp;quot;Heads-up&amp;quot; message on the [http://partners.moodle.com/mod/forum/view.php?id=2 Partners forum].&lt;br /&gt;
| Development Manager&lt;br /&gt;
|-&lt;br /&gt;
| 8.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Review and complete the [[Releases|release notes]] for the upcoming minor versions.&lt;br /&gt;
* Ensure all issues labelled with &amp;quot;ui_change&amp;quot;, &amp;quot;api_change&amp;quot; and &amp;quot;release_notes&amp;quot; are listed as UI changes, functional changed and fixes/improvements respectively in the release notes.&lt;br /&gt;
| Development Manager&lt;br /&gt;
|-&lt;br /&gt;
| 9.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Check on the &amp;quot;Must fix for X.Y version&amp;quot;. Filter out unrealistic issues.&lt;br /&gt;
| Development Manager&lt;br /&gt;
|-&lt;br /&gt;
| 10.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
|  &lt;br /&gt;
| Upgrade moodle.org to beta release&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 11.&lt;br /&gt;
| &lt;br /&gt;
|  style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Upgrade moodle.org and all other Moodle community sites (next sites first, then production) - Friday before release if not before&lt;br /&gt;
| &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Releasing==&lt;br /&gt;
===Packaging===&lt;br /&gt;
This should happen immediately before the next integration cycle begins on Monday (i.e., some days after last weekly, 2 days prior to official release).&lt;br /&gt;
{| class=&amp;quot;table table-striped table-bordered&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | #&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Major&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Minor&lt;br /&gt;
! Task&lt;br /&gt;
! style=&amp;quot;width:12%&amp;quot; | Responsibility&lt;br /&gt;
|-&lt;br /&gt;
| 1.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Make sure there are no real blockers introduced in the last weekly (install / upgrade ...). Confirm that the latest [https://tracker.moodle.org/issues/?jql=summary%20~%20%22en_fix%22%20order%20by%20createdDate%20desc en_fix changes]have been generated and integrated.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 2.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Verify all unit tests and integration tests have passed.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 3.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Verify QA tests have passed.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 4.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Follow the &amp;quot;mdlrelease&amp;quot; steps:&lt;br /&gt;
* Run the &#039;&#039;&#039;prerelease.sh&#039;&#039;&#039; script to generate the target minor (--type minor) and major (--type major) releases and their corresponding tags. Follow the on-screen instructions. Triple verify all changes are correct!&lt;br /&gt;
* Push changes to integration.git (but tags).&lt;br /&gt;
For major releases only:&lt;br /&gt;
* Configure &amp;quot;mdlrelease&amp;quot; (config.sh) to know about the new MOODLE_XY+1 stable branch.&lt;br /&gt;
* Update the CI server(s) by cloning all the &amp;quot;master&amp;quot; jobs to a new &amp;quot;MXY&amp;quot; view. Adjust &amp;quot;master&amp;quot; compare DB jobs to check for upgrade from MOODLE_XY_STABLE. Don&#039;t forget to re-chain the jobs properly. Run them.&lt;br /&gt;
    &#039;&#039;&#039;Important note&#039;&#039;&#039;: don&#039;t forget to disable memcached application store for unit tests in stable branches. ([https://tracker.moodle.org/browse/MDL-48192?focusedCommentId=322040&amp;amp;page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-322040 more info]).&lt;br /&gt;
Continue with the &amp;quot;mdlrelease&amp;quot; steps:&lt;br /&gt;
* Once CI servers have ended and all jobs have passed, push tags and run the &#039;&#039;&#039;release.sh&#039;&#039;&#039; script to apply the changes to moodle.git.&lt;br /&gt;
* If needed configure &amp;quot;mdlrelease&amp;quot; (config.sh) to get rid of any unsupported version and adjust stable and security branches. Make a pull request with the changes.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 5.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Post a &amp;quot;git repos updated &amp;amp; tagged&amp;quot; message on the [http://partners.moodle.com/mod/forum/view.php?id=2 Partner forum]&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 6.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
|&lt;br /&gt;
| Create a new MOODLE_XY+1_STABLE branch in https://github.com/moodlehq/moodle-performance-comparison and set the new release commit hash as $basecommit&lt;br /&gt;
| Testing Maintainer&lt;br /&gt;
|-&lt;br /&gt;
| 7.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Wait for the automated moodle-package to finish building for all versions. Verify the process has ended successfully (email).&lt;br /&gt;
For major releases only:&lt;br /&gt;
* Use the &#039;&#039;&#039;prerelease.sh&#039;&#039;&#039; script (--type back-to-dev) to move master to next X.Y+1 development version/branch. And push changes to integration.git - note this will lead to the &amp;quot;versions checker&amp;quot; failing for master, no problem, it will be fixed by the 1st cloned issue at #12 below).&lt;br /&gt;
* Once CIs have ended, use the &amp;quot;release.sh&amp;quot; script to send those master changes to moodle.git.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 8.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
* Create new windows packager script (cloning the current master one and configuring it).&lt;br /&gt;
* Create new windows_wpiXY dir by cloning the previous one (HEAD based), configuring build-latest-XY.sh.&lt;br /&gt;
* Edit the stats.php script (in the moodle-local_downloadmoodleorg repository), adding the new branch to the versions. Deploy it.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 9.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| In the Tracker...&lt;br /&gt;
* Visit the versions page and make the release, bumping all remaining open bugs to the next point release. If there is not next (end of support), clean that version from all the issues having it as &amp;quot;Fix for&amp;quot;. This must be done both for the [http://tracker.moodle.org/secure/project/ViewProject.jspa?pid=10011 Moodle Project] and the [http://tracker.moodle.org/secure/project/ViewProject.jspa?pid=10033 Plugins project]. Archive any version &amp;gt; 6 months old.&lt;br /&gt;
* Remove from all screens the custom fields belonging to 100% unsupported branches.&lt;br /&gt;
For major releases only:&lt;br /&gt;
* Release and package the &amp;quot;Must fix for X.Y&amp;quot; versions, it must be empty to do so.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 10.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Create the new &amp;quot;Pull X.Y Branch&amp;quot; and &amp;quot;Pull X.Y Diff URL&amp;quot; custom fields and spread them to all the screens needing them (copy from previous ones). Order them properly on each screen. Re-index Tracker.&lt;br /&gt;
Also, in the CI servers ([http://integration.moodle.org/view/tracker/job/Tracker%20-%20CI%20-%20Bulk%20precheck%20issues/ 1], [http://ci.stronk7.com/view/tracker/job/Tracker%20-%20CI%20-%20Bulk%20precheck%20issues/ 2]), edit the &amp;quot;Bulk precheck issues&amp;quot; job to make it meet the new &amp;quot;Pull X.Y Branch&amp;quot; field created.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 11.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| In the Tracker...&lt;br /&gt;
* Verify how the &amp;quot;X.Y regressions&amp;quot; versions [https://tracker.moodle.org/issues/?jql=resolution%20%3D%20Unresolved%20AND%20affectedVersion%20in%20(%222.6%20regressions%22%2C%20%222.7%20regressions%22%2C%20%222.8%20regressions%22%2C%20%222.9%20regressions%22)%20AND%20project%20%3D%20MDL are going] and ping Development Managers about. Package and archive them once empty.&lt;br /&gt;
For major releases only:&lt;br /&gt;
* Create the new &amp;quot;X.Y regressions&amp;quot; version to be applied to every issue found to be a recent problem introduced by the major release. These issues should get priority after release. &lt;br /&gt;
Adjust the filter [https://tracker.moodle.org/issues/?filter=17528 Latest regressions]&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 12.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Clone MDL-50184, MDL-50183 and MDL-50182, to be resolved ASAP.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 13.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Add/update the release date, build number and link on the [[Releases|Releases page]] and date in new version pages.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 14.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Create the new security-MOODLE_XY_STABLE and lastbased-MOODLE_XY_STABLE branches in the security report (branching from the just created MOODLE_XY_STABLE branch).&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Release day===&lt;br /&gt;
Usually on Monday&lt;br /&gt;
{| class=&amp;quot;table table-striped table-bordered&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | #&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Major&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Minor&lt;br /&gt;
! Task&lt;br /&gt;
! style=&amp;quot;width:12%&amp;quot; | Responsibility&lt;br /&gt;
|-&lt;br /&gt;
| 1.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| The execution of &amp;quot;moodle-package-extract-and-postprocess X&amp;quot; script may be needed if the releases *are not going to be published on Monday* but another weekday (X is the weekday, (1-7) starting in Monday). By default it happens automatically around 09:00 AM Perth/Australia time. &lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 2.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Verify release status, download pages and windows packages.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 3.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| If needed, modify the downloads cfg script (serverscripts) to decide about branches status, master visibility and windows availability. Push changes, will be autodeployed in a few minutes.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 4.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Notify all registered sys admins, including security notes with CVE identifiers, using the [http://lists.moodle.org/ mailing list server].&lt;br /&gt;
| Development Manager&lt;br /&gt;
|-&lt;br /&gt;
| 5.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Post about the Major release on the [http://moodle.org/news/ moodle.org News forum]&lt;br /&gt;
| Lead Developer&lt;br /&gt;
|-&lt;br /&gt;
| 6.&lt;br /&gt;
| &lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Post about minor releases on the [http://moodle.org/news/ moodle.org News forum]&lt;br /&gt;
| Development Manager&lt;br /&gt;
|-&lt;br /&gt;
| 7.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Post about the release on Twitter and other outlets. Update no. of releases on moodle.com &#039;Fact Sheet&#039; page: http://moodle.com/news/moodle-fact-sheet/&lt;br /&gt;
| Digital Marketing Specialist&lt;br /&gt;
|-&lt;br /&gt;
| 8.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| New &amp;quot;X.Y+1dev&amp;quot; branch to be created in AMOS, to have master changes performed there. New install_XY_STABLE processing set up. These needs to be done anytime during the on-sync period.&lt;br /&gt;
| AMOS Maintainer&lt;br /&gt;
|-&lt;br /&gt;
| 9.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Verify, 24h after tagging, that https://moodle.org/dev/ has been updated with new versions. If not, file an urgent mdlsite issue, crons must be running!&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 10.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| For en and de Moodle Docs, update default redirects and enable email notifications.&lt;br /&gt;
| Moodle Docs Maintainer&lt;br /&gt;
|-&lt;br /&gt;
| 11.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Go through all points listed under Day of release in [[New docs version process]].&lt;br /&gt;
| Community Manager&lt;br /&gt;
|-&lt;br /&gt;
| 12.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
|&lt;br /&gt;
* Decide the &amp;quot;Full demo&amp;quot;, &amp;quot;Code freeze&amp;quot; and &amp;quot;QA begins&amp;quot; dates for the next X.(Y+1) major release and put them in the [https://www.google.com/calendar/ical/moodle.com_p4c2oe7hsb77ltaro5qtihb5d4%40group.calendar.google.com/public/basic.ics Moodle development calendar]. They will be -7w, -5w and -4w before release date respectively.&lt;br /&gt;
* Update the &amp;quot;Full demo&amp;quot;, &amp;quot;Code freeze&amp;quot;, &amp;quot;QA begins&amp;quot; and Release dates on the [[Roadmap]] page.&lt;br /&gt;
* Add events to the HQ calendar for next Major release 6-months cycle according to [[Process#Sprints|the cycle plan]]: ~4 weeks planning and regression fixing, 2 sprints, 1 personal project week, 2 sprints, 1 personal project week, 1 sprint (which should lead up to code freeze).&lt;br /&gt;
* Notify the Community Manager of new dates to be added to the moodle.org calendar.&lt;br /&gt;
| Development Manager&lt;br /&gt;
|-&lt;br /&gt;
| 13.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &lt;br /&gt;
| Add calendar events in the [https://moodle.org/calendar moodle.org calendar] for coming Major and Minor releases up to the next Major release.&lt;br /&gt;
| Community Manager&lt;br /&gt;
|-&lt;br /&gt;
| 14.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &lt;br /&gt;
| Add $CFG-&amp;gt;skiplangupgrade = 1; to master acceptance test on nightly (apache01 &amp;amp; phantom01), as language pack is not available during on-sync for master.&lt;br /&gt;
| Testing Maintainer&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==1 week after==&lt;br /&gt;
{| class=&amp;quot;table table-striped table-bordered&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | #&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Major&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Minor&lt;br /&gt;
! Task&lt;br /&gt;
! style=&amp;quot;width:12%&amp;quot; | Responsibility&lt;br /&gt;
|-&lt;br /&gt;
| 1.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Publish the X.Y+ packages for download.moodle.org (should be automatic once weeklies are packaged).&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 2.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Update the version.php in git to be X.Y.Z+ during the next weekly integration process&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 3.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Create a new release notes page for the next minor versions (using the [[Release notes template|release notes template]].) Add note to top of relevant version page about security support.&lt;br /&gt;
| Development Manager&lt;br /&gt;
|-&lt;br /&gt;
| 4.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Add all security advisories to [http://moodle.org/security Security news] and [[:Category:Release notes|release notes]] with links to security advisories&lt;br /&gt;
|| Development Manager&lt;br /&gt;
|-&lt;br /&gt;
| 5.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| Send a plain text email to the OSS mailing list: [mailto:oss-security@lists.openwall.com oss-security@lists.openwall.com]. An appropriate message when sending the issues is... &lt;br /&gt;
:&amp;lt;tt&amp;gt;The following security notifications have now been made public. Thanks to OSS members for their cooperation.&amp;lt;/tt&amp;gt; &lt;br /&gt;
...followed by the security notes.&lt;br /&gt;
| Development Manager&lt;br /&gt;
|-&lt;br /&gt;
| 6.&lt;br /&gt;
|  style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Upgrade moodle.org and all other Moodle community sites (next sites first, then production)&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 7.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Create nightly jobs for the XY branch (Refer doc [http://wiki.moodle.com/display/integration/How+to+create+VM+after+release+on+nightly?flashId=-515750122]) and disable it after running jobs for day or two, so as to conserve resources on nightly&lt;br /&gt;
| Testing Maintainer&lt;br /&gt;
|-&lt;br /&gt;
| 7.&lt;br /&gt;
|  style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Clone this issue for next major release - MDL-48470&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==3 weeks after==&lt;br /&gt;
{| class=&amp;quot;table table-striped table-bordered&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | #&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Major&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Minor&lt;br /&gt;
! Task&lt;br /&gt;
! style=&amp;quot;width:12%&amp;quot; | Responsibility&lt;br /&gt;
|-&lt;br /&gt;
| 1.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Once the &amp;quot;On Sync&amp;quot; period ends:&lt;br /&gt;
* The &amp;quot;[https://tracker.moodle.org/issues/?filter=13669 integration_held]&amp;quot; label will be removed from issues awaiting integration, so they will be, automatically (see next point), be moved to current integration. Send a &amp;quot;rebase&amp;quot; message to all those issues.&lt;br /&gt;
* The &amp;quot;[http://integration.moodle.org/view/tracker/job/Tracker%20-%20CI%20-%20Move%20awaiting%20issues%20to%20current%20integration/ Move awaiting issues to current integration]&amp;quot; job will be re-enabled in the public CI server.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 2.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| In https://github.com/moodlehq/moodle-behat-extension project:&lt;br /&gt;
* For the new stable version:&lt;br /&gt;
*# Create a MOODLE_XY_STABLE branch from master&lt;br /&gt;
* For master:&lt;br /&gt;
*# Add a 1.X(Y+1).0 tag for the new release in the master branch&lt;br /&gt;
*# Clone MDL-39489, implement, and send it to integration.&lt;br /&gt;
| Testing Maintainer&lt;br /&gt;
|-&lt;br /&gt;
| 3.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Ensure Language pack for master is available and remove $CFG-&amp;gt;skiplangupgrade = 1; for master on nightly (apache01 and phantom01)&lt;br /&gt;
| Testing Maintainer&lt;br /&gt;
|-&lt;br /&gt;
| 4.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Enable nightly jobs for the XY.&lt;br /&gt;
| Testing Maintainer&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==1 month after==&lt;br /&gt;
{| class=&amp;quot;table table-striped table-bordered&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | #&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Major&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | Minor&lt;br /&gt;
! Task&lt;br /&gt;
! style=&amp;quot;width:12%&amp;quot; | Responsibility&lt;br /&gt;
|-&lt;br /&gt;
| 1.&lt;br /&gt;
| style=&amp;quot;text-align:center&amp;quot; | &amp;amp;#10003;&lt;br /&gt;
| &lt;br /&gt;
| Publish the X.(Y+1)dev packages for download.moodle.org&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Deprecation|Deprecation process]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Processes|Release process]]&lt;br /&gt;
[[Category:Release notes|Release process]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=String_deprecation&amp;diff=47917</id>
		<title>String deprecation</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=String_deprecation&amp;diff=47917"/>
		<updated>2015-05-18T07:47:04Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Project&lt;br /&gt;
|name = String deprecation&lt;br /&gt;
|state = Implemented&lt;br /&gt;
|tracker = MDL-46585&lt;br /&gt;
|discussion =&lt;br /&gt;
|assignee = Marina Glancy&lt;br /&gt;
}}&lt;br /&gt;
{{Moodle 2.8}}&lt;br /&gt;
==Removing strings which are no longer used==&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.8 onwards, strings can be deprecated in a way very similar to how functions are  deprecated. This feature allows us to safely remove strings once we are reasonably sure they are no longer used. The process should help to remove unnecessary strings from the language packs, so translators do not waste valuable time  translating them, while protecting us from accidentally removing a string that is still being used somewhere.&lt;br /&gt;
&lt;br /&gt;
== How it works ==&lt;br /&gt;
&lt;br /&gt;
There is a file with the list of deprecated strings. When a deprecated string is used (typically via the &amp;lt;code&amp;gt;get_string()&amp;lt;/code&amp;gt; call), a warning message is displayed, such as:&lt;br /&gt;
&lt;br /&gt;
    String [identifier,component] is deprecated. Either you should no longer be using that string, &lt;br /&gt;
    or the string has been incorrectly deprecated, in which case you should report this as a bug. &lt;br /&gt;
    Please refer to https://docs.moodle.org/dev/String_deprecation&lt;br /&gt;
&lt;br /&gt;
Note that this warning is displayed at the DEBUG_DEVELOPER level only (which is what Moodle developers should have selected). See below for info on what to do if you see this message.&lt;br /&gt;
&lt;br /&gt;
=== Why and when should a string be deprecated? ===&lt;br /&gt;
&lt;br /&gt;
The most common case is that you realize that a string is not used any more in standard Moodle code. You will probably search the whole moodle.git for the string identifier and the only relevant place found is the string definition itself. Even if it seems that the given string is not used any more in the standard Moodle code, it&#039;s possible that some additional (contributed) plugins still rely on it. This is typical for semantically general strings provided by the moodle.php (core) component such as &amp;quot;Yes&amp;quot;, &amp;quot;Continue&amp;quot;, &amp;quot;Hidden&amp;quot; etc.&lt;br /&gt;
&lt;br /&gt;
Beware that searching for the string identifier only may sometimes lead to false negatives. Imagine you have a suspicion that a hypothetical string &amp;quot;actionloginremote&amp;quot; is no longer used any more as there is no code that would actually use this stringid. However, there can be places like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$action = optional_param(&#039;action&#039;, &#039;loginremote&#039;, PARAM_ALPHA);&lt;br /&gt;
print_string(&#039;action&#039;.$action);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
that are harder to detect. So, instead of simply removing the string &amp;quot;actionloginremote&amp;quot; you would put it to the list of deprecated strings.&lt;br /&gt;
&lt;br /&gt;
Another scenario may be that a semantically identical string was defined twice or it was put into the wrong component. If you think there may be places that rely on the wrong location (component), you should deprecate it. Copy the string to a new location (do not forget to use CPY instruction for AMOS to replay the change in all existing translations) and deprecate the old one.&lt;br /&gt;
&lt;br /&gt;
Also, it may turn out that some strings are only vaguely defined and do not have a clear and unique context / semantics. Ideally, Moodle code should use context-sensitive strings rather than rely on one general string covering all cases. Things like [http://en.wikipedia.org/wiki/Grammatical_gender grammatical gender] play an important role in many languages. For example, in Czech, &amp;quot;a role&amp;quot; or &amp;quot;a question&amp;quot; are of feminine gender and the correct translation of &amp;quot;hidden&amp;quot; in this case is &amp;quot;skrytá&amp;quot;, while &amp;quot;a badge&amp;quot; is of masculine gender and the correct translation is &amp;quot;skrytý&amp;quot;. So it would be better to have separate strings like &amp;quot;hiddenrole&amp;quot;, &amp;quot;hiddenquestion&amp;quot; and &amp;quot;hiddenbadge&amp;quot; even if they all read just &amp;quot;Hidden&amp;quot; in the English language pack. When you are about to split existing string into a couple of specific ones, you may wish to deprecate the general one at the end too (also, do not forget to use the CPY again).&lt;br /&gt;
&lt;br /&gt;
=== When should a string be removed? ===&lt;br /&gt;
&lt;br /&gt;
There are situations where deprecation does not make sense. For example when a whole functionality is being removed, or a very specific string (such as error message) is no longer used by the code. If it is very unlikely that the string is not used by any other code, it can simply be removed without the full deprecation process.&lt;br /&gt;
&lt;br /&gt;
The same logic applies to cases when a very specific string is to be moved or renamed. In this situation, it is valid to just move it (together with the matching MOV instruction in the AMOScript).&lt;br /&gt;
&lt;br /&gt;
== How to deprecate a string ==&lt;br /&gt;
&lt;br /&gt;
* Strings can be deprecated and removed on master branch only.&lt;br /&gt;
* Locate or create a file deprecated.txt either in &#039;&#039;lang/en/&#039;&#039; or &#039;&#039;componentfullpath/lang/en/&#039;&#039;&lt;br /&gt;
* Add a line &amp;quot;identifier,fullcomponentname&amp;quot; to the end of this file&lt;br /&gt;
* Move the string inside the existing language file to the end of the file under the comment &amp;quot;// Deprecated since Moodle X.Y&amp;quot; (this comment will help removing deprecated strings later).&lt;br /&gt;
* For final deprecation (2 major versions later), delete the string from both deprecated.txt and respective lang file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: when deprecating core string from lang/en/xxxx.php the fullcomponentname should be &amp;quot;core_xxxx&amp;quot;, except for lang/en/moodle.php that has fullcomponentname &amp;quot;core&amp;quot;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== What to do if you get a debugging message ==&lt;br /&gt;
&lt;br /&gt;
There are two possibilities. Either the code that uses the deprecated string must be fixed, or the string should not have been deprecated and must be removed from the list.&lt;br /&gt;
&lt;br /&gt;
Use the git-blame tool on the corresponding lang/en/deprecated.txt and find the commit/issue that deprecated the string. It should give you enough information to decide on the most appropriate action.&lt;br /&gt;
&lt;br /&gt;
* If you think the string was deprecated by mistake, create a new issue in the tracker to remove it from the list (on all supported branches, not only on master).&lt;br /&gt;
* If the string was renamed or moved, you will probably want to fix the caller to use the new name/location of the string.&lt;br /&gt;
* You may as well copy the string to your own plugin scope and make it context-specific.&lt;br /&gt;
&lt;br /&gt;
  [https://github.com/moodle/moodle/blame/master/lang/en/deprecated.txt &amp;lt;nowiki&amp;gt;git blame lang/en/deprecated.txt&amp;lt;/nowiki&amp;gt;]&lt;br /&gt;
  [https://github.com/moodle/moodle/blame/master/mod/quiz/lang/en/deprecated.txt &amp;lt;nowiki&amp;gt;git blame mod/quiz/lang/en/deprecated.txt&amp;lt;/nowiki&amp;gt;]&lt;br /&gt;
&lt;br /&gt;
[[Category:Language]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Inbound_message_API&amp;diff=47797</id>
		<title>Inbound message API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Inbound_message_API&amp;diff=47797"/>
		<updated>2015-05-06T05:55:36Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* Handlers */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Project&lt;br /&gt;
|name = Inbound Message API&lt;br /&gt;
|state = Complete&lt;br /&gt;
|tracker = MDL-46282&lt;br /&gt;
|discussion = https://moodle.org/mod/forum/discuss.php?d=269424&lt;br /&gt;
|assignee = Andrew Nicols&lt;br /&gt;
}}&lt;br /&gt;
{{Moodle 2.8}}&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
By encoding pieces of data within an e-mail address, it is possible to route a message within Moodle and to&lt;br /&gt;
handle it accordingly. With the encoding of appropriate data within the e-mail address, it is also possible to perform&lt;br /&gt;
some level of sender verification, and to store additional data to enable further routing.&lt;br /&gt;
&lt;br /&gt;
To ensure that the solution remains practical, a single incoming e-mail account is used, making use of the e-mail&lt;br /&gt;
Subaddress extension defined in RFC 5233 (Sieve Email Filtering: Subaddress Extension). This RFC specifies that a the &#039;+&#039;&lt;br /&gt;
symbol can be used to separate the mailbox from any additional subaddress data.  For example, in the e-mail address&lt;br /&gt;
`bob+moodle@example.com, the e-mail would be delivered to `bob@example.com` but the recipient would be able to filter&lt;br /&gt;
mail based on the +moodle extension. This extension is referred to as the subaddress.&lt;br /&gt;
&lt;br /&gt;
The maximum length of the localpart of an e-mail address (including subadress) as defined in RFC 5232, is 64&lt;br /&gt;
characters. The current maximum length of the subaddress component is 48 characters, with a further character used for&lt;br /&gt;
the subaddress separator. This leaves space for 15 characters in the address component.&lt;br /&gt;
&lt;br /&gt;
== Benefits ==&lt;br /&gt;
&lt;br /&gt;
The main benefits of this kind of handling are the addition of new ways of interacting with Moodle for certain content:&lt;br /&gt;
&lt;br /&gt;
* the ability for users to reply to content received from Moodle; and&lt;br /&gt;
* the ability to e-mail new content in to Moodle.&lt;br /&gt;
&lt;br /&gt;
This has other potential knock-on benefits for users who cannot use the Moodle mobile application, or to unusual&lt;br /&gt;
scenarios where Internet access may be unusually limited. It also allows users to respond in a natural, and familiar environment which mirrors that of other systems.&lt;br /&gt;
&lt;br /&gt;
== Components ==&lt;br /&gt;
&lt;br /&gt;
The Inbound Message Handling system is broken down into several main components:&lt;br /&gt;
&lt;br /&gt;
# Address Management&lt;br /&gt;
# Message Handling&lt;br /&gt;
# Handler Management&lt;br /&gt;
# Message retrieval system&lt;br /&gt;
&lt;br /&gt;
In order to preserve user-verification, each address used in the process must be unique to that user. Additionally,&lt;br /&gt;
the message must identify how the message should be handled within Moodle.&lt;br /&gt;
&lt;br /&gt;
A handler is only passed a message following successful verification of that message and may decide how it will handle&lt;br /&gt;
the message from that point on.&lt;br /&gt;
&lt;br /&gt;
Handlers may define certain characteristics of the message handling system including:&lt;br /&gt;
# the extent of the verification which takes place; and&lt;br /&gt;
# the default validity period.&lt;br /&gt;
&lt;br /&gt;
=== Address Manager ===&lt;br /&gt;
&lt;br /&gt;
An address and routing manager exists to:&lt;br /&gt;
# generate unique addresses;&lt;br /&gt;
# process received messages, and extract the data stored within them;&lt;br /&gt;
# validate addresses; and&lt;br /&gt;
# verify sender authenticity.&lt;br /&gt;
&lt;br /&gt;
Both an encode, and a decode stage exist.&lt;br /&gt;
&lt;br /&gt;
Note: It is up to the developer to use the generated address in the correct fashion. Typically this will be as a &#039;reply-to&#039; address when sending new messages.&lt;br /&gt;
&lt;br /&gt;
==== Creating an e-mail address (Encode stage) ====&lt;br /&gt;
&lt;br /&gt;
When creating a new e-mail address, the following information is required:&lt;br /&gt;
# the &#039;&#039;&#039;handler&#039;&#039;&#039; - the system which will handle any e-mail received to the generated address;&lt;br /&gt;
# the &#039;&#039;&#039;data value&#039;&#039;&#039; - a single integer data which the received message relates to; and&lt;br /&gt;
# the &#039;&#039;&#039;user id&#039;&#039;&#039; - the id of the user that a message relates to.&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;data key&#039;&#039;&#039; is generated for the supplied data value.&lt;br /&gt;
&lt;br /&gt;
In the following example, an e-mail address is generated when sending a new forum post notification to a user. This&lt;br /&gt;
address is used in the reply-to field when sending the message, thereby allowing a user to reply to a post by e-mail.&lt;br /&gt;
&lt;br /&gt;
A new handler has been written for the forum &amp;lt;code php&amp;gt;\mod\forum\message\inbound\reply_handler&amp;lt;/code&amp;gt; which is aware of how it should handle any&lt;br /&gt;
received information.&lt;br /&gt;
The forum post notification will be sent to the user described by $recipient with a unique user id of &amp;lt;code php&amp;gt;$recipient-&amp;gt;id&amp;lt;/code&amp;gt;.&lt;br /&gt;
The forum post notification describes a new post described by $post and with a unique post id of &amp;lt;code php&amp;gt;$post-&amp;gt;id&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Create a new instance of the address manager.&lt;br /&gt;
$generator = new \core\message\inbound\address_manager();&lt;br /&gt;
&lt;br /&gt;
// Specify the handler which will process any incoming messages for the generated address.&lt;br /&gt;
$generator-&amp;gt;set_handler(&#039;\mod\forum\message\inbound\reply_hander&#039;);&lt;br /&gt;
&lt;br /&gt;
// Specify the post that is being replied to.&lt;br /&gt;
$generator-&amp;gt;set_data($post-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
// Generate an e-mail address to use for the reply-to, unique to this recipient.&lt;br /&gt;
$replyaddress = $generator-&amp;gt;generate($recipient-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
$eventdata = new stdClass();&lt;br /&gt;
$eventdata-&amp;gt;component           = &#039;mod_forum&#039;;&lt;br /&gt;
$eventdata-&amp;gt;name                = &#039;posts&#039;;&lt;br /&gt;
$eventdata-&amp;gt;userfrom            = $userfrom;&lt;br /&gt;
$eventdata-&amp;gt;userto              = $userto;&lt;br /&gt;
$eventdata-&amp;gt;subject             = $postsubject;&lt;br /&gt;
$eventdata-&amp;gt;fullmessage         = $posttext;&lt;br /&gt;
$eventdata-&amp;gt;fullmessageformat   = FORMAT_PLAIN;&lt;br /&gt;
$eventdata-&amp;gt;fullmessagehtml     = $posthtml;&lt;br /&gt;
$eventdata-&amp;gt;notification        = 1;&lt;br /&gt;
$eventdata-&amp;gt;replyto             = $replyaddress;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The e-mail address generated will be of the nature:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
incoming+AAAAFXrQKf8AA3QP92///wABUl2Ukn//uCbIXwoNLnXy94kV@example.com&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Parsing an e-mail address (Decode and validation stage) ====&lt;br /&gt;
&lt;br /&gt;
When an e-mail is received, the &#039;To&#039; address field is parsed to determine the way in which the e-mail should be&lt;br /&gt;
processed.&lt;br /&gt;
&lt;br /&gt;
The following example address can be parsed to determine the sender, the handler, and the item of data to which the&lt;br /&gt;
message refers. Note that this has been implemented as core functionality and developers are not expected to need to implement this section themselves.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
incoming+AAAAFXrQKf8AA3QP92///wABUl2Ukn//uCbIXwoNLnXy94kV@example.com&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// The message was sent by bob to the incoming mailbox:&lt;br /&gt;
$recipient = &#039;incoming+AAAAFXrQKf8AA3QP92///wABUl2Ukn//uCbIXwoNLnXy94kV@example.com&#039;;&lt;br /&gt;
$sender = &#039;bob@example.com&#039;;&lt;br /&gt;
&lt;br /&gt;
// Create a new instance of the address manager.&lt;br /&gt;
$parser = new \core\message\inbound\address_manager();&lt;br /&gt;
&lt;br /&gt;
// First parse the envelope data.&lt;br /&gt;
$result = $parser-&amp;gt;process_envelope($recipient, $sender);&lt;br /&gt;
&lt;br /&gt;
// We can check that the data validation passed.&lt;br /&gt;
if ($result !== \core\message\inbound\address::VALIDATION_SUCCESS) {&lt;br /&gt;
  echo &amp;quot;Some part of the data could not be verified\n&amp;quot;;&lt;br /&gt;
} else {&lt;br /&gt;
  // We can retrieve the data stored in the message.&lt;br /&gt;
  $data = $result-&amp;gt;get_data();&lt;br /&gt;
&lt;br /&gt;
  // Get the instance of the handler - this will be the \mod_forum\message\inbound\reply_hander used to define the message originally.&lt;br /&gt;
  $data-&amp;gt;get_handler();&lt;br /&gt;
&lt;br /&gt;
  // The user key is the user record of the user who the original message was sent to.&lt;br /&gt;
  $data-&amp;gt;user;&lt;br /&gt;
&lt;br /&gt;
  // The datavalue is the integer value that was specified when the message was originally sent.&lt;br /&gt;
  $data-&amp;gt;datavalue;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Handlers ===&lt;br /&gt;
&lt;br /&gt;
Once a message has been processed by the address manager, it is passed to the handler specified in the address data.&lt;br /&gt;
&lt;br /&gt;
Each Handler belongs to a specific component, and comprises of a class extending \core\message\inbound\handler, which specifies a&lt;br /&gt;
function to handle any received e-mail messages.&lt;br /&gt;
&lt;br /&gt;
==== Creating a new Handler ====&lt;br /&gt;
&lt;br /&gt;
To create a new handler, you must:&lt;br /&gt;
# create a class extending the handler class; and&lt;br /&gt;
# specify it&#039;s default values in that component&#039;s db/messageinbound_handlers.php file.&lt;br /&gt;
&lt;br /&gt;
Each new handler must have a unique class name within Moodle and must be loadable using the Moodle class autoloader.&lt;br /&gt;
&lt;br /&gt;
As an example, to create a forum post reply handler called reply_handler:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! scope=&amp;quot;row&amp;quot; | Component Name&lt;br /&gt;
| mod_forum&lt;br /&gt;
|-&lt;br /&gt;
! scope=&amp;quot;row&amp;quot; | Handler Name&lt;br /&gt;
| reply_handler&lt;br /&gt;
|-&lt;br /&gt;
! scope=&amp;quot;row&amp;quot; | Namespace&lt;br /&gt;
| mod_forum\message\inbound&lt;br /&gt;
|-&lt;br /&gt;
! scope=&amp;quot;row&amp;quot; | Class Name&lt;br /&gt;
| mod_forum\message\inbound\reply_handler&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In mod/forum/db/messageinbound_handlers.php, define the available handlers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
$handlers = array(&lt;br /&gt;
    array(&lt;br /&gt;
      &#039;classname&#039; =&amp;gt; &#039;\mod_forum\message\inbound\reply_handler&#039;,&lt;br /&gt;
      &#039;enabled&#039; =&amp;gt; false,&lt;br /&gt;
      &#039;validateaddress&#039; =&amp;gt; true,&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
And define the handler itself in /mod/forum/classes/message/inbound/reply_handler.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace mod_forum\message\inbound;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
class reply_handler extends \core\message\inbound\handler {&lt;br /&gt;
  // Place the content of the handler here.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A handler class must define three abstract functions:&lt;br /&gt;
# get_name() - Typically a string returned by get_string() to display as a name in the admin interface;&lt;br /&gt;
# get_description() - Typically a string returned by get_string() to display in the admin interface; and&lt;br /&gt;
# process_message() - The function called after successful validation of a message, which takes information including the recipient, sender, headers, body, and a list of attachments.&lt;br /&gt;
&lt;br /&gt;
It may optionally define some additional functions:&lt;br /&gt;
# allow_validateaddress_change() - To prevent an Moodle administrator from changing whether E-mail address validation is required. Typically this is used to &#039;&#039;&#039;force&#039;&#039;&#039; sender validation.&lt;br /&gt;
# allow_enabled_change() - To prevent a Moodle administrator from enabling, or disabling the handler&lt;br /&gt;
&lt;br /&gt;
A new handler must also be defined within the component in lib/db/messageinbound_handlers.php. This array of handlers&lt;br /&gt;
includes the default settings for the handler used at creation time.&lt;br /&gt;
&lt;br /&gt;
==== Removing quoted text from email messages ====&lt;br /&gt;
If you want the quoted text to be removed from email messages you can call the method remove_quoted_text from inside your handler as below:-&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 list ($message, $format) = self::remove_quoted_text($messagedata);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The method will make an educated guess and remove quoted text from the message and return the format and message contents. This method doesn&#039;t work perfectly at the moment and MDL-50058 is supposed to improve this.&lt;br /&gt;
&lt;br /&gt;
== Validation and Verification ==&lt;br /&gt;
&lt;br /&gt;
The Inbound Message system performs a step of both validation, and verification.&lt;br /&gt;
&lt;br /&gt;
Note: E-mail is never a secure method of communication, and it is easy to `spoof` the `sender` field when sending an&lt;br /&gt;
e-mail very easily. As a result, administrators should be fully aware of the consequences when enabling any Inbound Message&lt;br /&gt;
handler.&lt;br /&gt;
&lt;br /&gt;
When an address is generated, it will be composed of a base64-encoded binary set containing:&lt;br /&gt;
[handlerid][userid][datavalue][verifiationstring]&lt;br /&gt;
&lt;br /&gt;
# the handlerid is the database ID of the handler used to process the message;&lt;br /&gt;
# the userid is the database ID of the user associated with the message;&lt;br /&gt;
# the datavalue is an integer value associated with the message; and&lt;br /&gt;
# the verifiationstring is part of an md5 hash of a user key, and data key.&lt;br /&gt;
&lt;br /&gt;
A new key will be generated for each individual user. This is unique to the user.&lt;br /&gt;
A new key will be generated for each piece of data for a handler. This is unique to the handler and datavalue combination.&lt;br /&gt;
&lt;br /&gt;
The keys generated for both the user, and for the handler-data pair are never exposed in the string and are always&lt;br /&gt;
verified. The userid specified in the address must match the key stored for that user in Moodle; and similarly the&lt;br /&gt;
datavalue specified in the address must match the key stored for the handler-pair in moodle.&lt;br /&gt;
&lt;br /&gt;
This combination of three pieces of plain-text information, with two pieces of hidden additional information should&lt;br /&gt;
make it harder for any potential attacks.&lt;br /&gt;
&lt;br /&gt;
Additionally, an administrator can choose whether to compare the e-mail address of the sender against the e-mail address&lt;br /&gt;
held against a user record. This is enabled by default, but can be disabled by an administrator.&lt;br /&gt;
&lt;br /&gt;
As a further protection, it is possible to specify an expiry timestamp for each handler-datavalue keypair.&lt;br /&gt;
&lt;br /&gt;
=== Potential attack vectors ===&lt;br /&gt;
&lt;br /&gt;
Several potential attack vectors exist, and handler authors should determine the optimum solution required. At the very&lt;br /&gt;
least, it is advisable to recommend sender address comparison, but this is not foolproof on it&#039;s own.&lt;br /&gt;
&lt;br /&gt;
As an additional prevention method, the handler could define a further e-mail based verification check whereby on&lt;br /&gt;
reception of an inboune e-mail, the handler system would:&lt;br /&gt;
# store the retrieved message (park it);&lt;br /&gt;
# send a new e-mail to the user described in $user containing a link or a further reply message; and&lt;br /&gt;
# await for approval from the e-mail.&lt;br /&gt;
&lt;br /&gt;
==== Spoofed e-mail address ====&lt;br /&gt;
&lt;br /&gt;
As mentioned above, it is incredibly easy to spoof the Sender field in an e-mail. If the full address is captured&lt;br /&gt;
by an attacker, then it would be possible to send e-mail as that user and the Inbound Message system would be unable to distinguish&lt;br /&gt;
the message from a valid address.&lt;br /&gt;
&lt;br /&gt;
==== Mitigations =====&lt;br /&gt;
&lt;br /&gt;
===== Prevention =====&lt;br /&gt;
&lt;br /&gt;
# When creating keys, specify an appropriate expiry time for that key pair&lt;br /&gt;
# When sending e-mail within Moodle, only use the Reply-To field as this is not typically exposed when a message is forwarded to a third-party&lt;br /&gt;
# Provide information to users advising against forwarding of e-mail&lt;br /&gt;
&lt;br /&gt;
===== Damage Control =====&lt;br /&gt;
&lt;br /&gt;
# Expire any affected keys&lt;br /&gt;
&lt;br /&gt;
==== Brute force attack of e-mail accounts ====&lt;br /&gt;
&lt;br /&gt;
As with any system of this nature (including passwords), it is possible to apply a brute force attack. It would be&lt;br /&gt;
possible to reverse engineer the e-mail address for a known user, and then recompile it with a range of combinations.&lt;br /&gt;
&lt;br /&gt;
With the proposed length of the verification has (24 characters), this provides for&lt;br /&gt;
79,228,162,514,264,337,593,543,950,336 combinations of hash.&lt;br /&gt;
&lt;br /&gt;
===== Prevention =====&lt;br /&gt;
&lt;br /&gt;
# When creating data keys, specify an appropriate expiry time for that key pair&lt;br /&gt;
&lt;br /&gt;
===== Damage Control =====&lt;br /&gt;
&lt;br /&gt;
# Expire any affected keys&lt;br /&gt;
&lt;br /&gt;
===== Other notes =====&lt;br /&gt;
&lt;br /&gt;
It is difficult to increase the length of the verification hash. At present the hash is 24 characters which makes the&lt;br /&gt;
maximum length of the subaddress 48 characters, leaving space for 15 characters in the mailbox part of the address.&lt;br /&gt;
Although it would be possible to increase the length of an address, doing so would invalidate all previously used&lt;br /&gt;
addresses.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:verp-prototype-screen-examples.png]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Message_API&amp;diff=47789</id>
		<title>Message API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Message_API&amp;diff=47789"/>
		<updated>2015-05-06T04:59:40Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* How to send a message */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==What is this document?==&lt;br /&gt;
&lt;br /&gt;
This document describes how to make use of the Moodle Messaging API to send messages to Moodle users.&lt;br /&gt;
&lt;br /&gt;
If you are after a general introduction on using the Moodle Messaging system go to [[:en:Messaging|messaging user documentation]].&lt;br /&gt;
&lt;br /&gt;
If you are looking for details of how the Messaging system&#039;s internal structure was implemented, go to [[Messaging 2.0]].&lt;br /&gt;
&lt;br /&gt;
If you are looking for instructions on the implementation of a custom message processor (a component that receives messages sent to a user), go to [[Messaging custom components]].&lt;br /&gt;
&lt;br /&gt;
If you are looking for instructions on sending messages programatically within Moodle then read on...&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
Moodle components have the ability to send messages to users via the Moodle messaging system. Any type of component, for example a plugin or block, can register as a message producer then send messages to users.&lt;br /&gt;
&lt;br /&gt;
==File locations==&lt;br /&gt;
&lt;br /&gt;
The Message API code is contained within lib/messagelib.php and is automatically included for you during page setup.&lt;br /&gt;
&lt;br /&gt;
==Functions==&lt;br /&gt;
&lt;br /&gt;
message_send() is the primary point of contact for the message API. Call it to send a message to a user. You can find a full description of the arguments that must be supplied at (link to phpdocs). There is also an example below.&lt;br /&gt;
&lt;br /&gt;
==Message popup==&lt;br /&gt;
{{Moodle_2.9}}&lt;br /&gt;
A Javascript popup can be displayed through a link to invite a user to message another. In order to use this feature, you need to require the Javascript libraries using &#039;&#039;message_messenger_requirejs()&#039;&#039; and create a link with the attributes returned by &#039;&#039;message_messenger_sendmessage_link_params()&#039;&#039;. More in the examples.&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
===How to register as a message producer===&lt;br /&gt;
&lt;br /&gt;
The messages produced by a message provider is defined in the /db/messages.php file of a component. Below is code from the quiz module&#039;s messages.php file, shown as an example.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
$messageproviders = array (&lt;br /&gt;
    // Notify teacher that a student has submitted a quiz attempt&lt;br /&gt;
    &#039;submission&#039; =&amp;gt; array (&lt;br /&gt;
        &#039;capability&#039;  =&amp;gt; &#039;mod/quiz:emailnotifysubmission&#039;&lt;br /&gt;
    ),&lt;br /&gt;
    // Confirm a student&#039;s quiz attempt&lt;br /&gt;
    &#039;confirmation&#039; =&amp;gt; array (&lt;br /&gt;
        &#039;capability&#039;  =&amp;gt; &#039;mod/quiz:emailconfirmsubmission&#039;&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The quiz can send two kinds of messages, quiz &amp;quot;submission&amp;quot; and &amp;quot;confirmation&amp;quot; notifications. Each message type is only available to users with the appropriate capability. Please note that the capability is checked at the system level context. Users who have this capability will have this message listed in their messaging preferences. You can omit the capability section if your message should be visible for all users. For example forum post notifications are available to all users.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$messageproviders = array (&lt;br /&gt;
    // Ordinary single forum posts&lt;br /&gt;
    &#039;posts&#039; =&amp;gt; array (&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When displaying your message types in a user&#039;s messaging preferences it will use a string from your component&#039;s language file called &amp;quot;messageprovider:messagename&amp;quot;. For example here are the relevant strings from the quiz&#039;s language file.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;messageprovider:confirmation&#039;] = &#039;Confirmation of your own quiz submissions&#039;;&lt;br /&gt;
$string[&#039;messageprovider:submission&#039;] = &#039;Notification of quiz submissions&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your messages.php is complete you need to increase the version number of your component in its version.php. That will cause Moodle to check messages.php looking for new or changed message definitions. Log in as an admin and go to /admin/index.php (the Notifications page) to start the upgrade process.&lt;br /&gt;
&lt;br /&gt;
===How to send a message===&lt;br /&gt;
{{Moodle_2.9}}&lt;br /&gt;
Here is example code showing you how to actually send a message. The example shows the construction of a object with specific properties, which is then passed to the message_send() function that uses the information to send a message.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$message = new \core\message\message();&lt;br /&gt;
$message-&amp;gt;component = &#039;moodle&#039;;&lt;br /&gt;
$message-&amp;gt;name = &#039;instantmessage&#039;;&lt;br /&gt;
$message-&amp;gt;userfrom = $USER;&lt;br /&gt;
$message-&amp;gt;userto = $user;&lt;br /&gt;
$message-&amp;gt;subject = &#039;message subject 1&#039;;&lt;br /&gt;
$message-&amp;gt;fullmessage = &#039;message body&#039;;&lt;br /&gt;
$message-&amp;gt;fullmessageformat = FORMAT_MARKDOWN;&lt;br /&gt;
$message-&amp;gt;fullmessagehtml = &#039;&amp;lt;p&amp;gt;message body&amp;lt;/p&amp;gt;&#039;;&lt;br /&gt;
$message-&amp;gt;smallmessage = &#039;small message&#039;;&lt;br /&gt;
$message-&amp;gt;notification = &#039;0&#039;;&lt;br /&gt;
$message-&amp;gt;contexturl = &#039;http://GalaxyFarFarAway.com&#039;;&lt;br /&gt;
$message-&amp;gt;contexturlname = &#039;Context name&#039;;&lt;br /&gt;
$message-&amp;gt;replyto = &amp;quot;random@example.com&amp;quot;;&lt;br /&gt;
$content = array(&#039;*&#039; =&amp;gt; array(&#039;header&#039; =&amp;gt; &#039; test &#039;, &#039;footer&#039; =&amp;gt; &#039; test &#039;)); // Extra content for specific processor&lt;br /&gt;
$message-&amp;gt;set_additional_content(&#039;email&#039;, $content);&lt;br /&gt;
&lt;br /&gt;
// Create a file instance.&lt;br /&gt;
$usercontext = context_user::instance($user-&amp;gt;id);&lt;br /&gt;
$file = new stdClass;&lt;br /&gt;
$file-&amp;gt;contextid = $usercontext-&amp;gt;id;&lt;br /&gt;
$file-&amp;gt;component = &#039;user&#039;;&lt;br /&gt;
$file-&amp;gt;filearea  = &#039;private&#039;;&lt;br /&gt;
$file-&amp;gt;itemid    = 0;&lt;br /&gt;
$file-&amp;gt;filepath  = &#039;/&#039;;&lt;br /&gt;
$file-&amp;gt;filename  = &#039;1.txt&#039;;&lt;br /&gt;
$file-&amp;gt;source    = &#039;test&#039;;&lt;br /&gt;
&lt;br /&gt;
$fs = get_file_storage();&lt;br /&gt;
$file = $fs-&amp;gt;create_file_from_string($file, &#039;file1 content&#039;);&lt;br /&gt;
$message-&amp;gt;attachment = $file;&lt;br /&gt;
&lt;br /&gt;
$messageid = message_send($message);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Before 2.9 message data used to be a stdClass object as shown below:-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$message = new stdClass();&lt;br /&gt;
$message-&amp;gt;component         = &#039;mod_quiz&#039;; //your component name&lt;br /&gt;
$message-&amp;gt;name              = &#039;submission&#039;; //this is the message name from messages.php&lt;br /&gt;
$message-&amp;gt;userfrom          = $USER;&lt;br /&gt;
$message-&amp;gt;userto            = $touser;&lt;br /&gt;
$message-&amp;gt;subject           = $subject;&lt;br /&gt;
$message-&amp;gt;fullmessage       = $message;&lt;br /&gt;
$message-&amp;gt;fullmessageformat = FORMAT_PLAIN;&lt;br /&gt;
$message-&amp;gt;fullmessagehtml   = &#039;&#039;;&lt;br /&gt;
$message-&amp;gt;smallmessage      = &#039;&#039;;&lt;br /&gt;
$message-&amp;gt;notification      = 1; //this is only set to 0 for personal messages between users&lt;br /&gt;
message_send($message);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===How to set-up the message popup===&lt;br /&gt;
&lt;br /&gt;
Here is example code showing you how to set-up the Javascript popup link.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once(&#039;message/lib.php&#039;);&lt;br /&gt;
$userid = 2;&lt;br /&gt;
$userto = $DB-&amp;gt;get_record(&#039;user&#039;, array(&#039;id&#039; =&amp;gt; $userid));&lt;br /&gt;
&lt;br /&gt;
message_messenger_requirejs();&lt;br /&gt;
$url = new moodle_url(&#039;message/index.php&#039;, array(&#039;id&#039; =&amp;gt; $userto-&amp;gt;id));&lt;br /&gt;
$attributes = message_messenger_sendmessage_link_params($userto);&lt;br /&gt;
echo html_writer::link($url, &#039;Send a message&#039;, $attributes);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* [[Core APIs]]&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
[[Category:Tutorial]]&lt;br /&gt;
[[Category:Plugins]]&lt;br /&gt;
[[Category:Messaging]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_2.9_release_notes&amp;diff=47576</id>
		<title>Moodle 2.9 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_2.9_release_notes&amp;diff=47576"/>
		<updated>2015-04-13T05:37:42Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* For developers */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&#039;&#039;&#039;Note:&#039;&#039;&#039; This page is a work-in-progress. Please use the [[{{TALKPAGENAME}}|page comments]] for suggested improvements.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
&lt;br /&gt;
Release date: Not yet released, expected on Monday, 11th May 2015&lt;br /&gt;
 &lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%222.9%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 2.9].&lt;br /&gt;
&lt;br /&gt;
==Server requirements==&lt;br /&gt;
&lt;br /&gt;
These are just the minimum supported versions. We recommend keeping all of your software up-to-date.&lt;br /&gt;
&lt;br /&gt;
* Moodle upgrade:  Moodle 2.2 or later (if upgrading from earlier versions, you must upgrade to 2.2.11 as a first step)&lt;br /&gt;
* Minimum PHP version: PHP 5.4.4 (always use latest PHP 5.4.x or 5.5.x on Windows - http://windows.php.net/download/)&lt;br /&gt;
* Ghostscript should be installed for pdf annotation.&lt;br /&gt;
&lt;br /&gt;
=== Database requirements ===&lt;br /&gt;
&lt;br /&gt;
Moodle supports the following database servers. Again, version numbers are just the minimum supported version. We recommend running the latest stable version of any software.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Database&lt;br /&gt;
! Minimum version&lt;br /&gt;
! Recommended&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.postgresql.org/ PostgreSQL]&lt;br /&gt;
| 9.1&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mysql.com/ MySQL]&lt;br /&gt;
| 5.5.31&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [https://mariadb.org/ MariaDB]&lt;br /&gt;
| 5.5.31&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.microsoft.com/en-us/server-cloud/products/sql-server/ Microsoft SQL Server]&lt;br /&gt;
| 2008&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.oracle.com/us/products/database/overview/index.html Oracle Database]&lt;br /&gt;
| 10.2&lt;br /&gt;
| Latest&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Client requirements==&lt;br /&gt;
&lt;br /&gt;
=== Browser support ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Browser&lt;br /&gt;
! Minimum version&lt;br /&gt;
! Recommended version&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| [https://www.google.com/intl/en_au/chrome/browser/ Google Chrome]&lt;br /&gt;
| 30.0&lt;br /&gt;
| Latest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mozilla.org/en-US/ Mozilla Firefox]&lt;br /&gt;
| 25.0&lt;br /&gt;
| Latest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.apple.com/safari/ Apple Safari]&lt;br /&gt;
| 6&lt;br /&gt;
| Latest&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| [http://windows.microsoft.com/en-AU/internet-explorer/download-ie Microsoft Internet Explorer]&lt;br /&gt;
| 9&lt;br /&gt;
| Latest&lt;br /&gt;
| Version 10 is required for drag-and-drop upload of content from outside the browser into Moodle&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Major features==&lt;br /&gt;
&lt;br /&gt;
===Navigation improvements===&lt;br /&gt;
&lt;br /&gt;
One of the biggest project was improvements in Navigation and Users pages, see also MDL-45774. It includes:&lt;br /&gt;
&lt;br /&gt;
* My grades page listing all my courses, and all courses I am teaching in one place (linked from User Menu) MDL-45894, MDL-49634&lt;br /&gt;
* My Home is now My Dashboard MDL-48936&lt;br /&gt;
* Redesign “My profile”, make it pluggable MDL-48932, MDL-45898&lt;br /&gt;
* New “My preferences” page (linked from User Menu) MDL-45895&lt;br /&gt;
* Consistent header for user pages MDL-45896&lt;br /&gt;
* Consistent header for user sub pages MDL-48931&lt;br /&gt;
* Consistent bread crumbs for user pages MDL-48935&lt;br /&gt;
* Remove redundant nodes from nav tree MDL-49635&lt;br /&gt;
&lt;br /&gt;
===User interface improvements===&lt;br /&gt;
&lt;br /&gt;
* MDL-43996 - Drag and drop image into Atto editor inserts it as a file &lt;br /&gt;
* MDL-19670 - Teacher can post the same forum question to all groups at once &lt;br /&gt;
* MDL-47172 - “You have assignments that need attention” displays relevant information for teachers &lt;br /&gt;
* MDL-48933 - Ajax interface for messaging a user &lt;br /&gt;
* MDL-25721 - Sort by age when viewing question banks &lt;br /&gt;
* MDL-23296 - Provide search function for Server Files area in File Picker&lt;br /&gt;
* MDL-48937 - Don&#039;t show the category in the breadcrumb if there is only one category&lt;br /&gt;
* MDL-49694 - Overview report shows the full course name&lt;br /&gt;
* MDL-47527 - Allow access to overview report for users who can view all grades&lt;br /&gt;
&lt;br /&gt;
===Course creation improvements===&lt;br /&gt;
&lt;br /&gt;
* MDL-10405 - Added button to quickly delete the whole course section &lt;br /&gt;
* MDL-31500 - Allow backup and restore on the front page&lt;br /&gt;
* MDL-5583 - Fields in database module can be set as required &lt;br /&gt;
* MDL-28526 - Glossary can export/import embedded images and attached files &lt;br /&gt;
* MDL-49006, MDL-49101 - Removed default requirement of activity description and substituted with a single setting&lt;br /&gt;
* MDL-13831 - Grade to pass can be set by editing activity without going to gradebook &lt;br /&gt;
* MDL-27074 - Display group name for group events in the calendar&lt;br /&gt;
* MDL-48969 - New generic block: activity results&lt;br /&gt;
* MDL-18177 - Add option to choose whether groups and/or groupings are includedin a back up&lt;br /&gt;
* MDL-20053 - Database: create ##userpicture## tag to allow the user&#039;s profile picture to be displayed&lt;br /&gt;
* MDL-49543 - Add a WYSIWYG field to Badges which is displayed on the Criteria page&lt;br /&gt;
* MDL-46416 - Possible to change / remove picture from group&lt;br /&gt;
* MDL-49687 - Adding a single person to multiple groups at the same time&lt;br /&gt;
* MDL-21724 - The course edit page needs a way to redirect to some page other than the main course page after saving&lt;br /&gt;
&lt;br /&gt;
===Administrator features===&lt;br /&gt;
&lt;br /&gt;
* MDL-15187 - Assign global roles using CSV upload&lt;br /&gt;
* MDL-30937 - Backup report again links to the individual course backup summaries&lt;br /&gt;
* MDL-32547 - Configure temporary file deletion, to avoid moodledata/temp/backup filling up the filesystem&lt;br /&gt;
* MDL-49684 - Replace custom Moodle timezone stuff with standard PHP date/time code&lt;br /&gt;
* MDL-25763 - CLI version of admin/replace.php&lt;br /&gt;
* MDL-44874 - Per-request temp directories&lt;br /&gt;
* MDL-46064 - Drop support for MyISAM&lt;br /&gt;
* MDL-49298 - Make tgz backups standard&lt;br /&gt;
* MDL-47834 - New option for restriction of concurrent logins&lt;br /&gt;
* MDL-47800 - Logout user when somebody changes their password&lt;br /&gt;
* MDL-47830 - Add password rotation restrictions&lt;br /&gt;
* MDL-48559 - Web CRON should be disabled by default&lt;br /&gt;
* MDL-48080 - Never send mail to domains ending in .invalid&lt;br /&gt;
* MDL-48595 - Log exports no longer fails because of memory limit&lt;br /&gt;
* MDL-28513 - Allow specification of admin user email in CLI installer&lt;br /&gt;
* MDL-47803 - New page that shows all browser sessions of current user&lt;br /&gt;
* MDL-34684 - New health check to detect incorrect category path order and/or missing parent categories&lt;br /&gt;
* MDL-48493 - Automatically detect the plugin type when installing from ZIP&lt;br /&gt;
* MDL-48894 - Registration page should state if site is registered&lt;br /&gt;
&lt;br /&gt;
===Files and repositories===&lt;br /&gt;
&lt;br /&gt;
* MDL-42616 - Files: Support custom file types&lt;br /&gt;
* MDL-43752 - S3 repository works for non-US repositories&lt;br /&gt;
&lt;br /&gt;
===Authentication, enrolments and access===&lt;br /&gt;
&lt;br /&gt;
* Several improvements to meta enrolments, such as: populate groups from courses MDL-17929, sorting courses alphabetically MDL-35696, button to quickly add a new method MDL-49439&lt;br /&gt;
* MDL-26017 - Keyholder capability in self-enrolment plugin&lt;br /&gt;
* MDL-20365 - Salted Crypt passwords option for external database authentication&lt;br /&gt;
* MDL-49380 - Chose &amp;quot;Create new group&amp;quot; when synchronising cohort enrolment with a group&lt;br /&gt;
* MDL-49677 - Improvement of Custom welcome message in self-enrolment plugin&lt;br /&gt;
* MDL-43415 - Custom profile fields should be syncable with external DB auth&lt;br /&gt;
&lt;br /&gt;
===Quiz===&lt;br /&gt;
&lt;br /&gt;
* MDL-348 - Printer-friendly option for quizzes &lt;br /&gt;
* MDL-40988 - Add section headings to quiz&lt;br /&gt;
* MDL-40992 - Option for teachers to allow students to redo a finished question within a quiz attempt&lt;br /&gt;
* MDL-35280 - quiz_reset_userdata does not have an option to remove user/group overrides&lt;br /&gt;
* MDL-48898 - Quiz time period setting should use admin_setting_configduration&lt;br /&gt;
* MDL-6340 - force unique/unseen questions in  retakes&lt;br /&gt;
* MDL-40990 - Teachers can require students to complete Question 1 before they can see Question 2&lt;br /&gt;
&lt;br /&gt;
===Lesson===&lt;br /&gt;
&lt;br /&gt;
* MDL-48803 - support for groups  &lt;br /&gt;
* MDL-48715 - moving “time spent” from prerequisite to the proper completion rule  &lt;br /&gt;
* MDL-43387 - UI for grading essays &lt;br /&gt;
* MDL-48244 - Lessons with no questions show completed after the first page is viewed&lt;br /&gt;
* MDL-47587 - Make progress bar available on the very last page of a lesson.&lt;br /&gt;
* MDL-49642 - Give time/date extensions to users and groups in lesson&lt;br /&gt;
* MDL-40286 - non-editing teacher should see Grade analysis in Lesson&lt;br /&gt;
* MDL-48473 - Lesson shortanswer question: add fill in the blank option&lt;br /&gt;
* MDL-48984 - Lesson content page jump descriptions, numerical and shortanswer questions answers allow rich html but should be plain text&lt;br /&gt;
* MDL-18553 - Removing grade info from lesson pages if lesson grade is 0&lt;br /&gt;
* MDL-26689 - in order to prevent interactivity references from being broken move the &amp;quot;Dependent on&amp;quot; feature to the completion/availability subsystem&lt;br /&gt;
&lt;br /&gt;
===Other things===&lt;br /&gt;
&lt;br /&gt;
* MDL-46728 - WOFF2 fonts are supported in themes.&lt;br /&gt;
* MDL-48221 - Make forum subscription combinations less confusing with different combinations&lt;br /&gt;
* MDL-47777 - Convert assignment maximum files per submission maximum to global setting&lt;br /&gt;
* MDL-26226 - Moodle2 nav menu Topic Items should be links to Topic menu&lt;br /&gt;
* MDL-47159 - atto_link should add &#039;http://&#039; prefix when necessary&lt;br /&gt;
* MDL-46763 - Save user images as JPEG if uploaded in that format.&lt;br /&gt;
* MDL-47104 - Make &#039;calendar_lookahead&#039; setting more flexible&lt;br /&gt;
* MDL-48760 - Update mathjax to 2.5 when it&#039;s released&lt;br /&gt;
* MDL-36009 - Gradebook table uses complex tables that are not accessible&lt;br /&gt;
* MDL-48266 - Automated backup setting page needs additional validation&lt;br /&gt;
* MDL-47562 - UI Fixes and improvements for Singleview&lt;br /&gt;
* MDL-47232 - Course completion: &amp;quot;activities to be completed&amp;quot; improperly requires passing grade&lt;br /&gt;
* MDL-48437 - Make Visible/All groups selector show own groups first&lt;br /&gt;
* MDL-47501 - Add an indication that the grade letters was overridden&lt;br /&gt;
* MDL-9443 - Run *.xhtml file through the text filters.&lt;br /&gt;
* MDL-46662 - Accessibility improvements for gradereport course header and aggregation controls.&lt;br /&gt;
* MDL-45848 - Cannot assign Marker on a marking guide or rubric assignment without giving a grade&lt;br /&gt;
* MDL-48822 - Find last visual post in a discussion&lt;br /&gt;
* MDL-48482 - Duration admin setting doesn&#039;t have a label associated to it&lt;br /&gt;
* MDL-47915 - Two inconsistent layout files should be consistent, use id=page-content rather than content&lt;br /&gt;
* MDL-47628 - Availability: Grouping confusing for sites which used groupmembersonly [2.8]&lt;br /&gt;
* MDL-48212 - Forum reply by email puts reply instructions in messages for all handlers&lt;br /&gt;
* MDL-48616 - Macrons for Atto character map&lt;br /&gt;
* MDL-46755 - Allow teachers to configure the number of discussions displayed using the social course format&lt;br /&gt;
* MDL-46665 - Add &#039;idnumber&#039; field to user filter&lt;br /&gt;
* MDL-49220 - Allow preview of Choice options before activity is opened for submission&lt;br /&gt;
* MDL-40864 - Tidy up Bootstrapbase / Clean / More home links&lt;br /&gt;
* MDL-38663 - Remove navbar and login info from forgot_password.php&lt;br /&gt;
* MDL-34375 - Choice module lacks print_overview callback and does not appear on the MyMoodle Page&lt;br /&gt;
* MDL-18183 - XMLRPC in MNET does not verify SSL peers by default&lt;br /&gt;
* MDL-43770 - Exclude inactive users&#039; responses from Choice report (with an option to include)&lt;br /&gt;
* MDL-48499 - Show which users have not received messages in bulk messaging&lt;br /&gt;
* MDL-32285 - Added &amp;quot;Continue&amp;quot; button under Error notification message (IMS CP)&lt;br /&gt;
* MDL-46960 - Results returned from external tool activities don&#039;t update completion status&lt;br /&gt;
* MDL-49333 - Return additional information in core_get_site_info&lt;br /&gt;
* MDL-49262 - Delete the yui versions of the bootstrap plugins&lt;br /&gt;
* MDL-49052 - Incorrect headings for upcoming events pages&lt;br /&gt;
* MDL-49638 - reCAPTCHA should be moved below custom profile fields during self registration&lt;br /&gt;
* MDL-49730 - Workshop: use full page width when displaying contents&lt;br /&gt;
* MDL-48159 - Prevent submissions instead of using &amp;quot;Default team&amp;quot; in group assignments.&lt;br /&gt;
* MDL-49563 - Allow glossary entry to be updated from glossary navigation&lt;br /&gt;
* MDL-46238 - Add a simple way to go back from enrol/users.php page to the course&lt;br /&gt;
* MDL-47434 - Section &#039;General&#039; in navigation block&lt;br /&gt;
* MDL-36874 - Text navigation for Books&lt;br /&gt;
* MDL-49650 - Add a tool to browse templates in the current theme.&lt;br /&gt;
* MDL-23178 - Allow indenting again for activities in the Main Menu block&lt;br /&gt;
* MDL-49069 - Ability to specify default values for Forum RSS&lt;br /&gt;
* MDL-48160 - Improve all block region layouts when coded for RTL&lt;br /&gt;
&lt;br /&gt;
==Security issues==&lt;br /&gt;
 &lt;br /&gt;
A number of security related issues were resolved. Details of these issues will be released after a period of approximately one week to allow system administrators to safely update to the latest version.&lt;br /&gt;
 &lt;br /&gt;
==For developers==&lt;br /&gt;
 &lt;br /&gt;
* Support for Asynchronous Module Definition formatted javascript modules MDL-49046&lt;br /&gt;
* Support for calling webservice functions directly from javascript MDL-49163&lt;br /&gt;
* Support for implementing renderers as mustache templates (php and javascript) MDL-49152&lt;br /&gt;
* Behat tests can run in parallel - MDL-39752 (backported)&lt;br /&gt;
* A new per-request directory API has been added MDL-44874, and should be used instead of make_temp_directory wherever possible.&lt;br /&gt;
* Support for in browser caching (localstorage) of strings and templates MDL-49604&lt;br /&gt;
* Template Library - tool for displaying templates in the current theme MDL-49650&lt;br /&gt;
* Use PHP native timezones support MDL-49684&lt;br /&gt;
* New auth hook to intercept code before login page is shown. MDL-48887&lt;br /&gt;
* MDL-49101 - Single setting for the activity description requirement&lt;br /&gt;
* MDL-48177 - Allow plugin environment checks to work without defining explicit versions of Moodle&lt;br /&gt;
* MDL-48887 - Add new auth pre_loginpage_hook() (save redirects, implement autologins...)&lt;br /&gt;
* MDL-39752 - Behat tests runs in parallel&lt;br /&gt;
* MDL-49163 - Unified Ajax script handler&lt;br /&gt;
* MDL-49152 - Templates for renderers&lt;br /&gt;
* MDL-27548 - The comments table contains the component&lt;br /&gt;
* MDL-49269 - Add an AMD log module&lt;br /&gt;
* MDL-49534 - Delete pear/HTTP/WebDav&lt;br /&gt;
* MDL-48212 - Introduces a new class \core\message\message that should be used instead of \stdClass for creating messages.&lt;br /&gt;
* MDL-37477 - html_table API supports caption tag&lt;br /&gt;
* MDL-49643 - Deprecate inconsistent API to extend the navigation by local plugins&lt;br /&gt;
* MDL-49361 - Ability to provide alternate strings manager&lt;br /&gt;
* MDL-44642 - Implemented backend to keep session alive &lt;br /&gt;
* MDL-45725 - User preferences for flexible tables can be set persistent across sessions&lt;br /&gt;
&lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 2.9]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 2.9]]&lt;br /&gt;
[[es:Notas de Moodle 2.9]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=SCORM_reports&amp;diff=46601</id>
		<title>SCORM reports</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=SCORM_reports&amp;diff=46601"/>
		<updated>2014-10-28T01:38:19Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* Naming Conventions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.2}}&lt;br /&gt;
== Introduction ==&lt;br /&gt;
SCORM reports were converted to a pluggable architecture as of MOODLE 2.2. The original documentation of the project can be found at [https://docs.moodle.org/dev/SCORM_reporting_improvements SCORM Reporting Improvements]. Scorm Reports define a way for developer to develop reports of their own for the scorm module. The rest of this page deals with the details of how to develop such a report.&lt;br /&gt;
== Template ==&lt;br /&gt;
Here is a basic template for scorm report plugin on [https://github.com/ankitagarwal/scorm_report_template Github]&lt;br /&gt;
== File structure ==&lt;br /&gt;
Each plugin is allowed to have following files and folders:&lt;br /&gt;
&lt;br /&gt;
=== Mandatory Files ===&lt;br /&gt;
* classes/report.php&lt;br /&gt;
* lang/xx/scormreport_pluginname.php&lt;br /&gt;
&lt;br /&gt;
=== Other Optional Files ===&lt;br /&gt;
* Version.php&lt;br /&gt;
* db/install.php&lt;br /&gt;
* db/install.xml&lt;br /&gt;
* db/upgrade.php&lt;br /&gt;
* db/access.php&lt;br /&gt;
Please refer [[Upgrade API]] and [[Access API]] to understand the working of above files.&lt;br /&gt;
&lt;br /&gt;
As you might have noticed the file structure for scorm report plugin is similar to any other standard plugin in Moodle. The only differences are:-&lt;br /&gt;
* There must be a file classes/report.php implementing class \scormreport_yourreport\report that must extend the default reporting class &amp;quot;\mod_scorm\report&amp;quot; and the extended class must implement the method &amp;quot;display($scorm, $cm, $course, $download)&amp;quot;, which should handle the core reporting feature.&lt;br /&gt;
* The lang file is not optional. That is, each plugin must define the string &amp;quot;pluginname&amp;quot; in the lang files.&lt;br /&gt;
&lt;br /&gt;
== Naming Conventions ==&lt;br /&gt;
Following Naming conventions should be kept in mind while writing a scorm report plugin:-&lt;br /&gt;
* Folder name should be same as pluginname&lt;br /&gt;
* Name of the extended class should be in format \scormreport_myreport\report&lt;br /&gt;
* \scormreport_myreport\report must implement the function&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
   function display($scorm, $cm, $course, $download) {}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* Each plugin must define the string &amp;quot;pluginname&amp;quot; in the language files.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
[https://docs.moodle.org/dev/SCORM_reporting_improvements SCORM Reporting Improvements] Original GSOC 2011 Project Documentation&lt;br /&gt;
=== User Docs ===&lt;br /&gt;
[https://docs.moodle.org/en/Using_SCORM Using SCORM]&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/en/SCORM_FAQ SCORM FAQ]&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/en/SCORM_module SCORM Module]&lt;br /&gt;
&lt;br /&gt;
[[Category:Tutorial]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=SCORM_reports&amp;diff=46600</id>
		<title>SCORM reports</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=SCORM_reports&amp;diff=46600"/>
		<updated>2014-10-28T01:37:08Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* Other Optional Files */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.2}}&lt;br /&gt;
== Introduction ==&lt;br /&gt;
SCORM reports were converted to a pluggable architecture as of MOODLE 2.2. The original documentation of the project can be found at [https://docs.moodle.org/dev/SCORM_reporting_improvements SCORM Reporting Improvements]. Scorm Reports define a way for developer to develop reports of their own for the scorm module. The rest of this page deals with the details of how to develop such a report.&lt;br /&gt;
== Template ==&lt;br /&gt;
Here is a basic template for scorm report plugin on [https://github.com/ankitagarwal/scorm_report_template Github]&lt;br /&gt;
== File structure ==&lt;br /&gt;
Each plugin is allowed to have following files and folders:&lt;br /&gt;
&lt;br /&gt;
=== Mandatory Files ===&lt;br /&gt;
* classes/report.php&lt;br /&gt;
* lang/xx/scormreport_pluginname.php&lt;br /&gt;
&lt;br /&gt;
=== Other Optional Files ===&lt;br /&gt;
* Version.php&lt;br /&gt;
* db/install.php&lt;br /&gt;
* db/install.xml&lt;br /&gt;
* db/upgrade.php&lt;br /&gt;
* db/access.php&lt;br /&gt;
Please refer [[Upgrade API]] and [[Access API]] to understand the working of above files.&lt;br /&gt;
&lt;br /&gt;
As you might have noticed the file structure for scorm report plugin is similar to any other standard plugin in Moodle. The only differences are:-&lt;br /&gt;
* There must be a file classes/report.php implementing class \scormreport_yourreport\report that must extend the default reporting class &amp;quot;\mod_scorm\report&amp;quot; and the extended class must implement the method &amp;quot;display($scorm, $cm, $course, $download)&amp;quot;, which should handle the core reporting feature.&lt;br /&gt;
* The lang file is not optional. That is, each plugin must define the string &amp;quot;pluginname&amp;quot; in the lang files.&lt;br /&gt;
&lt;br /&gt;
== Naming Conventions ==&lt;br /&gt;
Following Naming conventions should be kept in mind while writing a scorm report plugin:-&lt;br /&gt;
* Folder name should be same as pluginname&lt;br /&gt;
* Name of the extended class should be scorm_pluginname_report&lt;br /&gt;
* scorm_pluginname_report must implement the function&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
   function display($scorm, $cm, $course, $download) {}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* Each plugin must define the string &amp;quot;pluginname&amp;quot; in the language files.&lt;br /&gt;
== See Also ==&lt;br /&gt;
[https://docs.moodle.org/dev/SCORM_reporting_improvements SCORM Reporting Improvements] Original GSOC 2011 Project Documentation&lt;br /&gt;
=== User Docs ===&lt;br /&gt;
[https://docs.moodle.org/en/Using_SCORM Using SCORM]&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/en/SCORM_FAQ SCORM FAQ]&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/en/SCORM_module SCORM Module]&lt;br /&gt;
&lt;br /&gt;
[[Category:Tutorial]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=SCORM_reports&amp;diff=46599</id>
		<title>SCORM reports</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=SCORM_reports&amp;diff=46599"/>
		<updated>2014-10-28T01:36:36Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* Other Optional Files */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.2}}&lt;br /&gt;
== Introduction ==&lt;br /&gt;
SCORM reports were converted to a pluggable architecture as of MOODLE 2.2. The original documentation of the project can be found at [https://docs.moodle.org/dev/SCORM_reporting_improvements SCORM Reporting Improvements]. Scorm Reports define a way for developer to develop reports of their own for the scorm module. The rest of this page deals with the details of how to develop such a report.&lt;br /&gt;
== Template ==&lt;br /&gt;
Here is a basic template for scorm report plugin on [https://github.com/ankitagarwal/scorm_report_template Github]&lt;br /&gt;
== File structure ==&lt;br /&gt;
Each plugin is allowed to have following files and folders:&lt;br /&gt;
&lt;br /&gt;
=== Mandatory Files ===&lt;br /&gt;
* classes/report.php&lt;br /&gt;
* lang/xx/scormreport_pluginname.php&lt;br /&gt;
&lt;br /&gt;
=== Other Optional Files ===&lt;br /&gt;
* Version.php&lt;br /&gt;
* db/install.php&lt;br /&gt;
* db/install.xml&lt;br /&gt;
* db/upgrade.php&lt;br /&gt;
* db/access.php&lt;br /&gt;
Please refer [[Upgrade API]] and [[Access API]] to understand the working of above files.&lt;br /&gt;
&lt;br /&gt;
As you might have noticed the file structure for scorm report plugin is similar to any other standard plugin in Moodle. The only differences are:-&lt;br /&gt;
* There must a file classes/report.php implementing class \scormreport_yourreport\report that must extend the default reporting class &amp;quot;\mod_scorm\report&amp;quot; and the extended class must implement the method &amp;quot;display($scorm, $cm, $course, $download)&amp;quot;, which should handle the core reporting feature.&lt;br /&gt;
* The lang file is not optional. That is, each plugin must define the string &amp;quot;pluginname&amp;quot; in the lang files.&lt;br /&gt;
&lt;br /&gt;
== Naming Conventions ==&lt;br /&gt;
Following Naming conventions should be kept in mind while writing a scorm report plugin:-&lt;br /&gt;
* Folder name should be same as pluginname&lt;br /&gt;
* Name of the extended class should be scorm_pluginname_report&lt;br /&gt;
* scorm_pluginname_report must implement the function&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
   function display($scorm, $cm, $course, $download) {}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* Each plugin must define the string &amp;quot;pluginname&amp;quot; in the language files.&lt;br /&gt;
== See Also ==&lt;br /&gt;
[https://docs.moodle.org/dev/SCORM_reporting_improvements SCORM Reporting Improvements] Original GSOC 2011 Project Documentation&lt;br /&gt;
=== User Docs ===&lt;br /&gt;
[https://docs.moodle.org/en/Using_SCORM Using SCORM]&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/en/SCORM_FAQ SCORM FAQ]&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/en/SCORM_module SCORM Module]&lt;br /&gt;
&lt;br /&gt;
[[Category:Tutorial]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=SCORM_reports&amp;diff=46598</id>
		<title>SCORM reports</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=SCORM_reports&amp;diff=46598"/>
		<updated>2014-10-28T01:34:31Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* Mandatory Files */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.2}}&lt;br /&gt;
== Introduction ==&lt;br /&gt;
SCORM reports were converted to a pluggable architecture as of MOODLE 2.2. The original documentation of the project can be found at [https://docs.moodle.org/dev/SCORM_reporting_improvements SCORM Reporting Improvements]. Scorm Reports define a way for developer to develop reports of their own for the scorm module. The rest of this page deals with the details of how to develop such a report.&lt;br /&gt;
== Template ==&lt;br /&gt;
Here is a basic template for scorm report plugin on [https://github.com/ankitagarwal/scorm_report_template Github]&lt;br /&gt;
== File structure ==&lt;br /&gt;
Each plugin is allowed to have following files and folders:&lt;br /&gt;
&lt;br /&gt;
=== Mandatory Files ===&lt;br /&gt;
* classes/report.php&lt;br /&gt;
* lang/xx/scormreport_pluginname.php&lt;br /&gt;
&lt;br /&gt;
=== Other Optional Files ===&lt;br /&gt;
* Version.php&lt;br /&gt;
* db/install.php&lt;br /&gt;
* db/install.xml&lt;br /&gt;
* db/upgrade.php&lt;br /&gt;
* db/access.php&lt;br /&gt;
Please refer [[Upgrade API]] and [[Access API]] to understand the working of above files.&lt;br /&gt;
&lt;br /&gt;
As you might have noticed the file structure for scorm report plugin is similar to any other standard plugin in Moodle. The only differences are:-&lt;br /&gt;
* There must a file report.php must extend the default reporting class &amp;quot;scorm_default_report&amp;quot; and the extended class must implement the method &amp;quot;display($scorm, $cm, $course, $download)&amp;quot;, which should handle the core reporting feature.&lt;br /&gt;
* The lang file is not optional. That is each plugin must define the string &amp;quot;pluginname&amp;quot; in the lang files.&lt;br /&gt;
== Naming Conventions ==&lt;br /&gt;
Following Naming conventions should be kept in mind while writing a scorm report plugin:-&lt;br /&gt;
* Folder name should be same as pluginname&lt;br /&gt;
* Name of the extended class should be scorm_pluginname_report&lt;br /&gt;
* scorm_pluginname_report must implement the function&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
   function display($scorm, $cm, $course, $download) {}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* Each plugin must define the string &amp;quot;pluginname&amp;quot; in the language files.&lt;br /&gt;
== See Also ==&lt;br /&gt;
[https://docs.moodle.org/dev/SCORM_reporting_improvements SCORM Reporting Improvements] Original GSOC 2011 Project Documentation&lt;br /&gt;
=== User Docs ===&lt;br /&gt;
[https://docs.moodle.org/en/Using_SCORM Using SCORM]&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/en/SCORM_FAQ SCORM FAQ]&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/en/SCORM_module SCORM Module]&lt;br /&gt;
&lt;br /&gt;
[[Category:Tutorial]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Events_API&amp;diff=46006</id>
		<title>Events API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Events_API&amp;diff=46006"/>
		<updated>2014-07-29T02:57:28Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* Rules */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Project&lt;br /&gt;
|name = Events 2&lt;br /&gt;
|state = Completed&lt;br /&gt;
|tracker = MDL-39797 , MDL-39952, MDL-39846&lt;br /&gt;
|discussion = https://moodle.org/mod/forum/discuss.php?d=229425&lt;br /&gt;
|assignee = Backend Team&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
= What are events? =&lt;br /&gt;
&lt;br /&gt;
Events are atomic pieces of information describing something that happened in Moodle. Events are primarily the result of user actions, but could also be the result of the [[:en:Cron|cron]] process or administration actions [[:en:Administration via command line|undertaken via the command line]].&lt;br /&gt;
&lt;br /&gt;
When an action takes place, an event is created by a [[Core APIs|core API]] or [[Plugins|plugin]]. The Events system then disseminates this event information to observers registered for this event. In this way, the events system acts as a communication backbone throughout the Moodle system. Event observers can not modify event data or interrupt the dispatching of events, it is a one way communication channel.&lt;br /&gt;
&lt;br /&gt;
= Why was a new events system needed? =&lt;br /&gt;
&lt;br /&gt;
The need to improve the Events system was prompted by a need for a richer and more efficient logging system, however the benefits of this improvement are useful to other parts of Moodle that observe event information.&lt;br /&gt;
&lt;br /&gt;
* The events need to be more strictly defined for logging and other advanced use cases. They need to contain more information, organised in a standardised way (in addition to the fields from the legacy log table and log_actions table).&lt;br /&gt;
* Complex data types were allowed in old events, which was causing major problems when serialising/storing/unserialising the data.&lt;br /&gt;
* The logging tables and events contain similar information and were triggered at the same places; utilising events for logging would remove this code duplication. All events should be loggable and all current log entries should be triggered as events.&lt;br /&gt;
* The logging system is an event observer, listening to all events and directing them to logging storage plugins in a controllable way.&lt;br /&gt;
* It is possible to subscribe to &#039;*&#039; event, which would allow a system to potentially observe, and selectively deal with, all events. Previously, handlers did not receive event names which made this problematic.&lt;br /&gt;
* Previously, event handlers could trigger exceptions during site upgrades, which would lead to fatal upgrade problems. The new design eliminates this.&lt;br /&gt;
* Failure in previous handlers blocked dispatching of subsequent events. Problems in new observers would only be logged and execution would continue normally.&lt;br /&gt;
* Previously, execution of external handlers during DB transactions blocked other handlers. This would be eliminated by in-memory buffer for external events.&lt;br /&gt;
* Previously there was no observer priority.&lt;br /&gt;
* Previously, nested events were not dispatched sequentially, which would change the order of events were received by lower priority handlers.&lt;br /&gt;
&lt;br /&gt;
= Performance =&lt;br /&gt;
Some basic profiling was conducted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;This next two paragraphs need to be replaced with results.&amp;lt;/p&amp;gt;&lt;br /&gt;
There is a general plan to complete pre- and post-implementation testing as development happens. The new system will be implemented in parallel with the old one, which should help with comparison of new and old logging and event triggering performance on each page.&lt;br /&gt;
&lt;br /&gt;
Our aim is to capture more information about actions in Moodle by triggering more events and logging more information about each event. This is going to impact negatively on performance. We hope to offset that impact by improving log storage, simplifying event dispatching and adding other core performance improvements. The proposed class structure of the base event should allow some new advanced techniques, which may also improve performance in some scenarios.&lt;br /&gt;
&lt;br /&gt;
More details will be added to this section soon.&lt;br /&gt;
&lt;br /&gt;
= Events API =&lt;br /&gt;
&lt;br /&gt;
Each plugin defines the events that it can report (trigger) by extending an abstract base class, once for each possible event. This approach has several benefits.&lt;br /&gt;
; Events are active objects&lt;br /&gt;
: When they are triggered and possibly after they are reinstantiated (say, when they are retrieved from a log), an event object is able to provide callback functions for various purposes (such as capability checks).&lt;br /&gt;
; Automatic inclusion&lt;br /&gt;
: Event class definitions is automatically included when needed, without having to maintain lists of known event types. New event definitions can be added without the need to upgrade, only purging of the MUC cache is required after adding a new observer.&lt;br /&gt;
; Maintainability&lt;br /&gt;
: It is relatively simple to add new events and migrate existing events. Code review is simplified because there is less duplication of code when triggering same events and all event related information/code is concentrated in one file in fixed locations.&lt;br /&gt;
; Self documenting&lt;br /&gt;
: The behaviour of events is combined with the definition of events in one place (file). It is easy for event observer writers to know what events a plugin can trigger. This includes support for autocompletion and code inspection in modern IDEs. A list of all events is now available as a report to administrators and researchers.&lt;br /&gt;
; Quick, self-validating data structure&lt;br /&gt;
: As events are instantiated objects, the PHP processor will validate the structure and type of event classes. This does not ensure data value validity, but does give some assurance of consistency and it also detects unintentional typos.&lt;br /&gt;
&lt;br /&gt;
== Backwards compatibility and migration ==&lt;br /&gt;
&lt;br /&gt;
Events:&lt;br /&gt;
* All legacy events in the standard distribution have been replaced with the new events API and events_trigger() has been deprecated.&lt;br /&gt;
* For events that already exist in Moodle 2.5, the additional legacy information has been added to the event data (in properties &#039;legacyeventname&#039; and &#039;legacyeventdata&#039;)&lt;br /&gt;
* The legacy events handling code is maintained  separately and will continue being supported in Moodle 2.7.&lt;br /&gt;
* All legacy events-handlers have been migrated to new observers in standard distribution.&lt;br /&gt;
* In future, more subsystems may be migrated to events-observers, ex.: gradebook history, completion.&lt;br /&gt;
&lt;br /&gt;
Logging:&lt;br /&gt;
* The function add_to_log() has been deprecated with a notice as of Moodle 2.7.&lt;br /&gt;
* Existing add_to_log() parameters has been migrated inside new events method, in get_legacy_log_data(). Calls to core_event_base::trigger() will lead to entries being added to the legacy log table if the legacy log plugin is enabled.&lt;br /&gt;
&lt;br /&gt;
See https://docs.moodle.org/dev/Migrating_logging_calls_in_plugins&lt;br /&gt;
&lt;br /&gt;
== Event dispatching and observers ==&lt;br /&gt;
&lt;br /&gt;
The new event dispatching system is completely separate from the old events code. Original event handlers are now called observers with the description stored in the same db/events.php file, but as a new array with a different format.&lt;br /&gt;
&lt;br /&gt;
=== Event observers ===&lt;br /&gt;
&lt;br /&gt;
Observers are described in db/events.php in the array $observers, the array is not indexed and contains a list of observers defined as an array with the following properties;&lt;br /&gt;
* eventname – fully qualified event class name or &amp;quot;*&amp;quot; indicating all events, ex.: &#039;&#039;\plugintype_pluginname\event\something_happened&#039;&#039;.&lt;br /&gt;
* callback - PHP callable type.&lt;br /&gt;
* includefile - optional. File to be included before calling the observer. Path relative to dirroot.&lt;br /&gt;
* priority - optional. Defaults to 0. Observers with higher priority are notified first.&lt;br /&gt;
* internal - optional. Defaults to true. Non-internal observers are not called during database transactions, but instead after a successful commit of the transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$observers = array(&lt;br /&gt;
&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;eventname&#039;   =&amp;gt; &#039;\core\event\sample_executed&#039;,&lt;br /&gt;
        &#039;callback&#039;    =&amp;gt; &#039;core_event_sample_observer::observe_one&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;eventname&#039;   =&amp;gt; &#039;\core\event\sample_executed&#039;,&lt;br /&gt;
        &#039;callback&#039;    =&amp;gt; &#039;core_event_sample_observer::external_observer&#039;,&lt;br /&gt;
        &#039;priority&#039;    =&amp;gt; 200,&lt;br /&gt;
        &#039;internal&#039;    =&amp;gt; false,&lt;br /&gt;
    ),&lt;br /&gt;
&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;eventname&#039;   =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;callback&#039;    =&amp;gt; &#039;core_event_sample_observer::observe_all&#039;,&lt;br /&gt;
        &#039;includefile&#039; =&amp;gt; null,&lt;br /&gt;
        &#039;internal&#039;    =&amp;gt; true,&lt;br /&gt;
        &#039;priority&#039;    =&amp;gt; 9999,&lt;br /&gt;
    ),&lt;br /&gt;
&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Event dispatching ===&lt;br /&gt;
&lt;br /&gt;
A list of available observers is constructed on the fly directly from all available in &#039;events.php&#039; files. Previously handlers were installed only during installation and upgrade. This has little risk of performance regression because the list is already cached in MUC. Observers get events before installation or any upgrade, however observers are not notified during the initial installation of Moodle core tables.&lt;br /&gt;
&lt;br /&gt;
Developers of observers must make sure that execution does not end with a fatal error under any condition (before install, before upgrade or normal operation). Exceptions are automatically captured, logged in the PHP error log, and notification of other observers continues. Current handlers must not throw any exceptions at any time.&lt;br /&gt;
&lt;br /&gt;
Observers are notified sequentially in the same order in which events were triggered. This means that events triggered in observers are queued in FIFO buffer and are processed after all observers are notified.&lt;br /&gt;
&lt;br /&gt;
=== Differences from old event handling ===&lt;br /&gt;
&lt;br /&gt;
# New events contain a lot more structured information.&lt;br /&gt;
# There is separate context cache that may be used when deleting data or for observer performance improvements.&lt;br /&gt;
# No database access is allowed in new event dispatching code.&lt;br /&gt;
# There is no support for cron execution. This eliminates performance problems, simplifies events dispatching and prevents abuse of cron events.&lt;br /&gt;
# Events triggered in observers are processed in a different order.&lt;br /&gt;
# External events are buffered when a transaction is in progress, instead of being sent to the cron queue.&lt;br /&gt;
# It is possible to define multiple observers for one event in one events.php file.&lt;br /&gt;
# It is possible to subscribe an observer to all events.&lt;br /&gt;
# The new event manager is using frankenstyle autoloading, which leads to a smaller memory footprint when events are not used on the current page.&lt;br /&gt;
&lt;br /&gt;
== Triggering events ==&lt;br /&gt;
&lt;br /&gt;
* All event definitions are classes extending the \core\event\base class.&lt;br /&gt;
* Events are triggered by creating a new instance of the class event and executing $event-&amp;gt;trigger().&lt;br /&gt;
* Each event class names are a unique identifier of the event.&lt;br /&gt;
* Class names and namespace follow the identifier scheme \&#039;&#039;&#039;frankenstyle_component&#039;&#039;&#039;\event\&#039;&#039;&#039;some_object_action&#039;&#039;&#039;. Core events have prefix &#039;core_&#039;.&lt;br /&gt;
* Each event class is defined in a separate file. File name and location must match the class name for the use of auto loading, for example: &#039;&#039;&#039;plugindir&#039;&#039;&#039;/classes/event/&#039;&#039;&#039;something_happened&#039;&#039;&#039;.php&lt;br /&gt;
* The event identifier suffix has the form &#039;&#039;some_object_action&#039;&#039;  (&#039;&#039;&#039;something_happened&#039;&#039;&#039; in the example above) and should follow the standard naming convention. The last word after the underscore is automatically parsed as its action, the rest of word is its object.&lt;br /&gt;
&lt;br /&gt;
Decision:[[#Verb_list| Recommended verb list]]&lt;br /&gt;
&lt;br /&gt;
Examples: \core\event\course_completed, \mod_assign\event\submission_commented, \mod_forum\event\post_shared, \mod_forum\event\post_responded, etc.&lt;br /&gt;
&lt;br /&gt;
* Ideally, it should be possible to trigger an event without gathering additional information for the event. To reduce the cost of data gathering, specifically the cost of database reads, at least the minimal values needed to trigger an event should be already available in variables.&lt;br /&gt;
&lt;br /&gt;
An example of triggering an event:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event = \mod_myplugin\event\something_happened::create(array(&#039;context&#039; =&amp;gt; $context, &#039;objectid&#039; =&amp;gt; YYY, &#039;other&#039; =&amp;gt; ZZZ));&lt;br /&gt;
// ... code that may add some record snapshots&lt;br /&gt;
$event-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Use of PHP autoloading ===&lt;br /&gt;
&lt;br /&gt;
All new OOP APIs in Moodle 2.6 onwards are going to use class auto loading - see [[Automatic class loading]]. New events use PHP within strictly defined namespaces, which concentrate all event classes in the classes/event/ subdirectory.&lt;br /&gt;
&lt;br /&gt;
=== Why separate classes? ===&lt;br /&gt;
Pros&lt;br /&gt;
* Maintainability - It is much easier to review, debug and integrate.&lt;br /&gt;
* Self documenting, behaviour is combined with definition.&lt;br /&gt;
* It is extremely flexible for plugin developers and core devs too.&lt;br /&gt;
* Automatic lists events can be generated without being installed - PHPDocs as events documentation.&lt;br /&gt;
* It is included only when needed using autoloading.&lt;br /&gt;
* Self-validating data structure (by PHP).&lt;br /&gt;
* Some developers will find it easier to copy whole class files as templates.&lt;br /&gt;
Cons&lt;br /&gt;
* Big learning curve for developers without OOP skills (all other new subsystems in Moodle already use OOP, you can not code without these skills any more).&lt;br /&gt;
* Some developers may find it harder to copy-and-paste examples because they will need to create new class first and use it afterwards (this can be viewed as a benefit because it forces developers to think more about events).&lt;br /&gt;
* This has increased the number lines of code in Moodle for events and logging.&lt;br /&gt;
&lt;br /&gt;
== Information contained in events ==&lt;br /&gt;
&lt;br /&gt;
Events have to contain as much information as they can, but this should not affect the performance. That&#039;s why part of the information is available in properties, and the rest via methods. This allows for delayed computation of data until the time it is really needed, if it ever is.&lt;br /&gt;
&lt;br /&gt;
=== Properties ===&lt;br /&gt;
&lt;br /&gt;
The following is a list of properties that the developer has to pass to the event upon creation, or ones that can be automatically generated where possible and cost free. Some of these properties are not mandatory.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Property name&lt;br /&gt;
! Title&lt;br /&gt;
! Type&lt;br /&gt;
! Required&lt;br /&gt;
! Comment&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;eventname&#039;&#039;&lt;br /&gt;
| Event name&lt;br /&gt;
| &#039;&#039;static, automatic from class name&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| Automatically computed by copying class name&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;component&#039;&#039;&lt;br /&gt;
| Component&lt;br /&gt;
| &#039;&#039;static, automatic from top namespace&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| Component declaring the event, automatically computed from class name.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;action&#039;&#039;&lt;br /&gt;
| Action&lt;br /&gt;
| &#039;&#039;static, automatic from last word in class name&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| Can be automatically computed from class name.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;target&#039;&#039;&lt;br /&gt;
| target of action&lt;br /&gt;
| &#039;&#039;static, automatic from class name&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| Target on which the action is taken, can be automatically computed from class name.&lt;br /&gt;
|-&lt;br /&gt;
| objecttable&lt;br /&gt;
| Database table name&lt;br /&gt;
| static&lt;br /&gt;
| optional (Must be set if objetid present)&lt;br /&gt;
| Database table name which represents the event object to the best. Never use a relationship table here.&lt;br /&gt;
|-&lt;br /&gt;
| objectid&lt;br /&gt;
| Object ID&lt;br /&gt;
| variable&lt;br /&gt;
| Optional (Must be set if objettable present)&lt;br /&gt;
| Id of the object record from objecttable.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;&#039;&#039;crud&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
| Transaction type&lt;br /&gt;
| &#039;&#039;static&#039;&#039;&lt;br /&gt;
| optional&lt;br /&gt;
| One of [crud] letters. Statically declared in the event class method init().&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;&#039;&#039;level&#039;&#039;&#039;&#039;&#039; / &#039;&#039;&#039;&#039;&#039;edulevel&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
| Level&lt;br /&gt;
| &#039;&#039;static&#039;&#039;&lt;br /&gt;
| optional&lt;br /&gt;
| Level of educational value of the event. Statically declared in the event class method init(). Changed from &#039;&#039;&#039;&#039;&#039;level&#039;&#039;&#039;&#039;&#039; to &#039;&#039;&#039;&#039;&#039;edulevel&#039;&#039;&#039;&#039;&#039; in Moodle 2.7 (See below for more details)&lt;br /&gt;
|-&lt;br /&gt;
| contextid&lt;br /&gt;
| Context ID&lt;br /&gt;
| mandatory&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
| contextlevel&lt;br /&gt;
| Context level&lt;br /&gt;
| automatic from context&lt;br /&gt;
| -&lt;br /&gt;
| This tells you if it was a course, activity, course category, etc.&lt;br /&gt;
|-&lt;br /&gt;
| contextinstanceid&lt;br /&gt;
| Context instanceid&lt;br /&gt;
| automatic from context&lt;br /&gt;
| -&lt;br /&gt;
| Based on context level this may be course id , course module id, course category, etc.&lt;br /&gt;
|-&lt;br /&gt;
| userid&lt;br /&gt;
| User ID&lt;br /&gt;
| defaults to current user&lt;br /&gt;
| -&lt;br /&gt;
| User ID, or 0 when not logged in, or -1 when other (System, CLI, Cron, ...)&lt;br /&gt;
|-&lt;br /&gt;
| courseid&lt;br /&gt;
| Affected course&lt;br /&gt;
| defaults to course context from context&lt;br /&gt;
| -&lt;br /&gt;
| This is used only for contexts at and bellow course level - this can be used to filter events by course (includes all course activities)&lt;br /&gt;
|-&lt;br /&gt;
| relateduserid&lt;br /&gt;
| Affected user&lt;br /&gt;
| variable&lt;br /&gt;
| optional&lt;br /&gt;
| Is this action related to some user? This could be used for some personal timeline view.&lt;br /&gt;
|-&lt;br /&gt;
| anonymous&lt;br /&gt;
| Anonymous action&lt;br /&gt;
| variable&lt;br /&gt;
| optional (Defaults to 0)&lt;br /&gt;
| Is this action anonymous? Reports should ignore events with anonymous set to 1.&lt;br /&gt;
|-&lt;br /&gt;
| other&lt;br /&gt;
| All other data&lt;br /&gt;
| variable array&lt;br /&gt;
| optional&lt;br /&gt;
| Any other fields needed for event description - scalars or arrays, must be serialisable using json_encode()&lt;br /&gt;
|-&lt;br /&gt;
| timecreated&lt;br /&gt;
| Time of the event&lt;br /&gt;
| automatic&lt;br /&gt;
| -&lt;br /&gt;
| Time when the event was triggered.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* static: same for all event instances of this class&lt;br /&gt;
* variable: might not be same for all instances of this event class&lt;br /&gt;
* mandatory: required in order to trigger the event&lt;br /&gt;
* optional: not necessarily required to trigger the event&lt;br /&gt;
&lt;br /&gt;
==== Level property ====&lt;br /&gt;
&lt;br /&gt;
The edulevel property helps define the educational value of the event. It is intentional that the list is limited to only 3 different constants as having too many options would make it harder for developers to pick the right one(s). We also have to keep in mind that this is not supposed to answer all the questions about a particular event, other event properties like the courseid, the context, the component name can be used with the level to get more granular reports.&lt;br /&gt;
&lt;br /&gt;
Remember that this is event based. If the user that has triggered the event is not really &amp;quot;participating&amp;quot; because he is an admin, or a manager, then it is the job of the report to filter those. The event itself has a static educational level.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Teaching&#039;&#039;&#039; (LEVEL_TEACHING: 1)&lt;br /&gt;
&lt;br /&gt;
Any event/action that is performed by someone (typically a teacher) and has a teaching value (anything that is effecting the learning experience/environment of the students). This should not be combined with &amp;quot;Participating&amp;quot; events.&lt;br /&gt;
&lt;br /&gt;
Valid events:&lt;br /&gt;
&lt;br /&gt;
* A teacher grading a student&lt;br /&gt;
* A teacher modifying the course settings&lt;br /&gt;
* A teacher adding a new section to the course page&lt;br /&gt;
* A teacher modifying a module settings&lt;br /&gt;
* A teacher adding a page to course&lt;br /&gt;
* A teacher leaving a feedback&lt;br /&gt;
&lt;br /&gt;
INVALID events:&lt;br /&gt;
&lt;br /&gt;
* A teacher posting in a forum (it might affect the learning experience, but not necessarily, so the teacher is just participating)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Participating&#039;&#039;&#039; (LEVEL_PARTICIPATING: 2)&lt;br /&gt;
&lt;br /&gt;
Any event/action that is performed by a user, that is related (or could be related) to his learning experience.&lt;br /&gt;
&lt;br /&gt;
Valid events:&lt;br /&gt;
&lt;br /&gt;
* A user posting to a forum&lt;br /&gt;
* A user submitting an assignment&lt;br /&gt;
* A user blogging&lt;br /&gt;
* A user reading someone&#039;s blog&lt;br /&gt;
* A user posting a comment&lt;br /&gt;
* A user chatting on a chat activity&lt;br /&gt;
* A user viewing the course page&lt;br /&gt;
* A user deletes a blog post&lt;br /&gt;
&lt;br /&gt;
INVALID events:&lt;br /&gt;
&lt;br /&gt;
* A user updating his profile&lt;br /&gt;
* A user visiting someone&#039;s profile&lt;br /&gt;
* A user viewing his /my/ page&lt;br /&gt;
* A user sending a message to another one&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Other&#039;&#039;&#039; (LEVEL_OTHER: 0)&lt;br /&gt;
&lt;br /&gt;
Any other action, whether they are related to the site administration, or are specific to user. They do not have any educational value.&lt;br /&gt;
&lt;br /&gt;
=== Methods ===&lt;br /&gt;
&lt;br /&gt;
The computation of this data is not required by default, but can be accessed by any event observer if need be.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Comment&lt;br /&gt;
|-&lt;br /&gt;
| get_name()&lt;br /&gt;
| Returns localised name of the event, it is the same for all instances.&lt;br /&gt;
|-&lt;br /&gt;
| get_description()&lt;br /&gt;
| Returns non-localised description of one particular event. There are plans to make this localised in future.&lt;br /&gt;
&lt;br /&gt;
It is recommended that the string begins with identifying the user who triggered the event by providing the user id in quotations. This applies to other variables used in the description as well. If an activity is also mentioned then the course module id should be used, not the id from the activity table. For example &amp;quot;The user with the id &#039;$this-&amp;gt;userid&#039; updated the activity &#039;youractivity&#039; with the course module id &#039;$this-&amp;gt;contextinstanceid&#039;.&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| can_view($user)&lt;br /&gt;
| This method is deprecated, please do not use this.&lt;br /&gt;
|-&lt;br /&gt;
| get_url()&lt;br /&gt;
| Returns Moodle URL where the event can be observed afterwards. Can be null, if no valid location is present.&lt;br /&gt;
|-&lt;br /&gt;
| get_legacy_eventname()&lt;br /&gt;
| Information necessary for event backward compatibility.&lt;br /&gt;
|-&lt;br /&gt;
| get_legacy_eventdata()&lt;br /&gt;
| Information necessary for event backward compatibility.&lt;br /&gt;
|-&lt;br /&gt;
| get_legacy_logdata()&lt;br /&gt;
| Information necessary for logging backward compatibility.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Record caching===&lt;br /&gt;
&lt;br /&gt;
The standard event data may not contain all the information observers need. The built-in record snapshot support in events allows developers to attach more auxiliary information when triggering events, it may be for example course record, some record that was just deleted, etc. &lt;br /&gt;
* Snapshots are expected to be an exact snapshot of the database table at the instance when the event was triggered.&lt;br /&gt;
* Snapshot can be set and requested for any table. If not cached, it defaults to direct $DB-&amp;gt;get_record calls.&lt;br /&gt;
* Please be aware that the snapshots are not stored in the event, and cannot be restored.&lt;br /&gt;
* Snapshot are supposed to be used only by observers. They should never be used by reports or by the event itself.&lt;br /&gt;
* When using a snapshot in an observer, please make sure you are taking proper care of handling exceptions as the record you are requesting could have been deleted in the time, in between your observer is notified about the event and the trigger.&lt;br /&gt;
* We recommend all delete event must add snapshot of the deleted record.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    $event = \core\event\role_assigned::create(&lt;br /&gt;
        array(&#039;context&#039;=&amp;gt;$context, &#039;objectid&#039;=&amp;gt;$ra-&amp;gt;roleid, &#039;relateduserid&#039;=&amp;gt;$ra-&amp;gt;userid,&lt;br /&gt;
            &#039;other&#039;=&amp;gt;array(&#039;id&#039;=&amp;gt;$ra-&amp;gt;id, &#039;component&#039;=&amp;gt;$ra-&amp;gt;component, &#039;itemid&#039;=&amp;gt;$ra-&amp;gt;itemid)));&lt;br /&gt;
    $event-&amp;gt;add_record_snapshot(&#039;role_assignments&#039;, $ra);&lt;br /&gt;
    $event-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    $event = \core\event\role_unassigned::create(&lt;br /&gt;
        array(&#039;context&#039;=&amp;gt;$context, &#039;objectid&#039;=&amp;gt;$ra-&amp;gt;roleid, &#039;relateduserid&#039;=&amp;gt;$ra-&amp;gt;userid,&lt;br /&gt;
            &#039;other&#039;=&amp;gt;array(&#039;id&#039;=&amp;gt;$ra-&amp;gt;id, &#039;component&#039;=&amp;gt;$ra-&amp;gt;component, &#039;itemid&#039;=&amp;gt;$ra-&amp;gt;itemid)));&lt;br /&gt;
    $event-&amp;gt;add_record_snapshot(&#039;role_assignments&#039;, $ra);&lt;br /&gt;
    $event-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The related methods are:&lt;br /&gt;
* public function add_record_snapshot($tablename, $record)&lt;br /&gt;
* public function get_record_snapshot($tablename, $id)&lt;br /&gt;
&lt;br /&gt;
== Events naming convention ==&lt;br /&gt;
&lt;br /&gt;
Clear event names help developers when reading what events are triggered, and defining the events properties when defining the event class.&lt;br /&gt;
&lt;br /&gt;
 Decision: \&amp;lt;component&amp;gt;\event\&amp;lt;some_object&amp;gt;_&amp;lt;verb&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Existing events ===&lt;br /&gt;
&lt;br /&gt;
List of existing events in Moodle code base, along with their 2.5 couterparts.&lt;br /&gt;
&lt;br /&gt;
This list is out of date. For a full list of events check out the [https://docs.moodle.org/en/Event_list_report Event list report] which is located in &amp;quot;Site administration &amp;gt; Reports &amp;gt; Event list&amp;quot; of your Moodle installation (2.7+).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fully qualified event name&lt;br /&gt;
! 2.5 name&lt;br /&gt;
! Component&lt;br /&gt;
! Object&lt;br /&gt;
! Action (Verb)&lt;br /&gt;
! Comment&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_comments\event\comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| assignsubmission_comments&lt;br /&gt;
| comment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_comments\event\comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| assignsubmission_comments&lt;br /&gt;
| comment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_file\event\assessable_uploaded&#039;&#039;&#039;&lt;br /&gt;
| assessable_file_uploaded&lt;br /&gt;
| assignsubmission_file&lt;br /&gt;
| assessable&lt;br /&gt;
| uploaded&lt;br /&gt;
| To be deprecated MDL-35197&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_file\event\submission_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| assignsubmission_file&lt;br /&gt;
| submission&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_file\event\submission_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| assignsubmission_file&lt;br /&gt;
| submission&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_onlinetext\event\assessable_uploaded&#039;&#039;&#039;&lt;br /&gt;
| assessable_content_uploaded&lt;br /&gt;
| assignsubmission_onlinetext&lt;br /&gt;
| assessable&lt;br /&gt;
| uploaded&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_onlinetext\event\submission_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| assignsubmission_onlinetext&lt;br /&gt;
| submission&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_onlinetext\event\submission_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| assignsubmission_onlinetext&lt;br /&gt;
| submission&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;block_comments\event\comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| block_comments&lt;br /&gt;
| comment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;block_comments\event\comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| block_comments&lt;br /&gt;
| comment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;booktool_exportimscp\event\book_exported&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| booktool_exportimscp&lt;br /&gt;
| book&lt;br /&gt;
| exported&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;booktool_print\event\book_printed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| booktool_print&lt;br /&gt;
| book&lt;br /&gt;
| printed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;booktool_print\event\chapter_printed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| booktool_print&lt;br /&gt;
| chapter&lt;br /&gt;
| printed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\assessable_submitted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| assessable&lt;br /&gt;
| submitted&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\assessable_uploaded&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| assessable&lt;br /&gt;
| uploaded&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\base&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| base&lt;br /&gt;
| -&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_association_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| blog_association&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| blog_comment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| blog_comment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_entries_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| blog_entries&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_entry_created&#039;&#039;&#039;&lt;br /&gt;
| blog_entry_added&lt;br /&gt;
| core&lt;br /&gt;
| blog_entry&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_entry_deleted&#039;&#039;&#039;&lt;br /&gt;
| blog_entry_deleted&lt;br /&gt;
| core&lt;br /&gt;
| blog_entry&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_entry_updated&#039;&#039;&#039;&lt;br /&gt;
| blog_entry_edited&lt;br /&gt;
| core&lt;br /&gt;
| blog_entry&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\cohort_created&#039;&#039;&#039;&lt;br /&gt;
| cohort_added&lt;br /&gt;
| core&lt;br /&gt;
| cohort&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\cohort_deleted&#039;&#039;&#039;&lt;br /&gt;
| cohort_deleted&lt;br /&gt;
| core&lt;br /&gt;
| cohort&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\cohort_member_added&#039;&#039;&#039;&lt;br /&gt;
| cohort_member_added&lt;br /&gt;
| core&lt;br /&gt;
| cohort_member&lt;br /&gt;
| added&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\cohort_member_removed&#039;&#039;&#039;&lt;br /&gt;
| cohort_member_removed&lt;br /&gt;
| core&lt;br /&gt;
| cohort_member&lt;br /&gt;
| removed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\cohort_updated&#039;&#039;&#039;&lt;br /&gt;
| cohort_updated&lt;br /&gt;
| core&lt;br /&gt;
| cohort&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| comment&lt;br /&gt;
| created&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| comment&lt;br /&gt;
| deleted&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\comments_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| comments&lt;br /&gt;
| viewed&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\content_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| content&lt;br /&gt;
| viewed&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_category_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_category&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_category_deleted&#039;&#039;&#039;&lt;br /&gt;
| course_category_deleted&lt;br /&gt;
| core&lt;br /&gt;
| course_category&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_category_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_category&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_completed&#039;&#039;&#039;&lt;br /&gt;
| course_completed&lt;br /&gt;
| core&lt;br /&gt;
| course&lt;br /&gt;
| completed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_completion_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_completion&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_content_deleted&#039;&#039;&#039;&lt;br /&gt;
| course_content_removed&lt;br /&gt;
| core&lt;br /&gt;
| course_content&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_created&#039;&#039;&#039;&lt;br /&gt;
| course_created&lt;br /&gt;
| core&lt;br /&gt;
| course&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_deleted&#039;&#039;&#039;&lt;br /&gt;
| course_deleted&lt;br /&gt;
| core&lt;br /&gt;
| course&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_completion_updated&#039;&#039;&#039;&lt;br /&gt;
| activity_completion_changed&lt;br /&gt;
| core&lt;br /&gt;
| course_module_completion&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_created&#039;&#039;&#039;&lt;br /&gt;
| mod_created&lt;br /&gt;
| core&lt;br /&gt;
| course_module&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_deleted&#039;&#039;&#039;&lt;br /&gt;
| mod_deleted&lt;br /&gt;
| core&lt;br /&gt;
| course_module&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_instances_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_module_instances_list&lt;br /&gt;
| viewed&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_updated&#039;&#039;&#039;&lt;br /&gt;
| mod_updated&lt;br /&gt;
| core&lt;br /&gt;
| course_module&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_reset_ended&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_reset&lt;br /&gt;
| ended&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_reset_started&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_reset&lt;br /&gt;
| started&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_restored&#039;&#039;&#039;&lt;br /&gt;
| course_restored&lt;br /&gt;
| core&lt;br /&gt;
| course&lt;br /&gt;
| restored&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_section_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_section&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_updated&#039;&#039;&#039;&lt;br /&gt;
| course_updated&lt;br /&gt;
| core&lt;br /&gt;
| course&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\email_failed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| email&lt;br /&gt;
| failed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\group_created&#039;&#039;&#039;&lt;br /&gt;
| groups_group_created&lt;br /&gt;
| core&lt;br /&gt;
| group&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\group_deleted&#039;&#039;&#039;&lt;br /&gt;
| groups_group_deleted&lt;br /&gt;
| core&lt;br /&gt;
| group&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\group_member_added&#039;&#039;&#039;&lt;br /&gt;
| groups_member_added&lt;br /&gt;
| core&lt;br /&gt;
| group_member&lt;br /&gt;
| added&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\group_member_removed&#039;&#039;&#039;&lt;br /&gt;
| groups_member_removed&lt;br /&gt;
| core&lt;br /&gt;
| group_member&lt;br /&gt;
| removed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\group_updated&#039;&#039;&#039;&lt;br /&gt;
| groups_group_updated&lt;br /&gt;
| core&lt;br /&gt;
| group&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\grouping_created&#039;&#039;&#039;&lt;br /&gt;
| groups_grouping_created&lt;br /&gt;
| core&lt;br /&gt;
| grouping&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\grouping_deleted&#039;&#039;&#039;&lt;br /&gt;
| groups_grouping_deleted&lt;br /&gt;
| core&lt;br /&gt;
| grouping&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\grouping_updated&#039;&#039;&#039;&lt;br /&gt;
| groups_grouping_updated&lt;br /&gt;
| core&lt;br /&gt;
| grouping&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\manager&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| manager&lt;br /&gt;
| anager&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\mnet_access_control_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| mnet_access_control&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\mnet_access_control_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| mnet_access_control&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\note_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| note&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\note_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| note&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\note_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| note&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\notes_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| notes&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_allow_assign_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| role_allow_assign&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_allow_override_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| role_allow_override&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_allow_switch_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| role_allow_switch&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_assigned&#039;&#039;&#039;&lt;br /&gt;
| role_assigned&lt;br /&gt;
| core&lt;br /&gt;
| role&lt;br /&gt;
| assigned&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_capabilities_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| role_capabilities&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| role&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_unassigned&#039;&#039;&#039;&lt;br /&gt;
| role_unassigned&lt;br /&gt;
| core&lt;br /&gt;
| role&lt;br /&gt;
| unassigned&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_created&#039;&#039;&#039;&lt;br /&gt;
| user_created&lt;br /&gt;
| core&lt;br /&gt;
| user&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_deleted&#039;&#039;&#039;&lt;br /&gt;
| user_deleted&lt;br /&gt;
| core&lt;br /&gt;
| user&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_enrolment_created&#039;&#039;&#039;&lt;br /&gt;
| user_enrolled&lt;br /&gt;
| core&lt;br /&gt;
| user_enrolment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_enrolment_deleted&#039;&#039;&#039;&lt;br /&gt;
| user_unenrolled&lt;br /&gt;
| core&lt;br /&gt;
| user_enrolment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_enrolment_updated&#039;&#039;&#039;&lt;br /&gt;
| user_enrol_modified&lt;br /&gt;
| core&lt;br /&gt;
| user_enrolment&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| user_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_loggedin&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| user&lt;br /&gt;
| loggedin&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_loggedinas&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| user&lt;br /&gt;
| loggedinas&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_loggedout&#039;&#039;&#039;&lt;br /&gt;
| user_logout&lt;br /&gt;
| core&lt;br /&gt;
| user&lt;br /&gt;
| loggedout&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_login_failed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| user_login&lt;br /&gt;
| failed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_profile_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| user_profile&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_updated&#039;&#039;&#039;&lt;br /&gt;
| user_updated&lt;br /&gt;
| core&lt;br /&gt;
| user&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_function_called&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_function&lt;br /&gt;
| called&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_login_failed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_login&lt;br /&gt;
| failed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_service_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_service&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_service_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_service&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_service_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_service&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_service_user_added&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_service_user&lt;br /&gt;
| added&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_service_user_removed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_service_user&lt;br /&gt;
| removed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_token_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_token&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_token_sent&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_token&lt;br /&gt;
| sent&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;logstore_legacy\event\legacy_logged&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| logstore_legacy&lt;br /&gt;
| legacy&lt;br /&gt;
| logged&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\all_submissions_downloaded&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| all_submissions&lt;br /&gt;
| downloaded&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\assessable_submitted&#039;&#039;&#039;&lt;br /&gt;
| assessable_submitted&lt;br /&gt;
| mod_assign&lt;br /&gt;
| assessable&lt;br /&gt;
| submitted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\extension_granted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| extension&lt;br /&gt;
| granted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\identities_revealed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| identities&lt;br /&gt;
| revealed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\marker_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| marker&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\statement_accepted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| statement&lt;br /&gt;
| accepted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission&lt;br /&gt;
| created&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_duplicated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission&lt;br /&gt;
| duplicated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_graded&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission&lt;br /&gt;
| graded&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_locked&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission&lt;br /&gt;
| locked&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_status_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission_status&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_unlocked&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission&lt;br /&gt;
| unlocked&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission&lt;br /&gt;
| updated&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\workflow_state_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| workflow_state&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_book\event\chapter_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_book&lt;br /&gt;
| chapter&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_book\event\chapter_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_book&lt;br /&gt;
| chapter&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_book\event\chapter_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_book&lt;br /&gt;
| chapter&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_book\event\chapter_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_book&lt;br /&gt;
| chapter&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_book\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_book&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_book\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_book&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_chat\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_chat&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_chat\event\message_sent&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_chat&lt;br /&gt;
| message&lt;br /&gt;
| sent&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_chat\event\sessions_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_chat&lt;br /&gt;
| sessions&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_choice\event\answer_submitted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_choice&lt;br /&gt;
| answer&lt;br /&gt;
| submitted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_choice\event\answer_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_choice&lt;br /&gt;
| answer&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_choice\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_choice&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_choice\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_choice&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_choice\event\report_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_choice&lt;br /&gt;
| report&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| comment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| comment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\field_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| field&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\field_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| field&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\field_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| field&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\record_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| record&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\record_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| record&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\record_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| record&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\template_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| template&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\template_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| template&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_feedback\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_feedback&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_feedback\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_feedback&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_feedback\event\response_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_feedback&lt;br /&gt;
| response&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_feedback\event\response_submitted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_feedback&lt;br /&gt;
| response&lt;br /&gt;
| submitted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_folder\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_folder&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_folder\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_folder&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_folder\event\folder_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_folder&lt;br /&gt;
| folder&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\assessable_uploaded&#039;&#039;&#039;&lt;br /&gt;
| assessable_content_uploaded&lt;br /&gt;
| mod_forum&lt;br /&gt;
| assessable&lt;br /&gt;
| uploaded&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\course_searched&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| course&lt;br /&gt;
| searched&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\discussion_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| discussion&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\discussion_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| discussion&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\discussion_moved&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| discussion&lt;br /&gt;
| moved&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\discussion_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| discussion&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\discussion_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| discussion&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\forum_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| forum&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\post_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| post&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\post_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| post&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\post_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| post&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\readtracking_disabled&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| readtracking&lt;br /&gt;
| disabled&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\readtracking_enabled&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| readtracking&lt;br /&gt;
| enabled&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\subscribers_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| subscribers&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\subscription_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| subscription&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\subscription_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| subscription&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\userreport_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| userreport&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_glossary\event\comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_glossary&lt;br /&gt;
| comment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_glossary\event\comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_glossary&lt;br /&gt;
| comment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\essay_assessed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| essay&lt;br /&gt;
| assessed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\essay_attempt_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| essay_attempt&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\highscore_added&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| highscore&lt;br /&gt;
| added&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\highscores_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| highscores&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\lesson_ended&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| lesson&lt;br /&gt;
| ended&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\lesson_started&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| lesson&lt;br /&gt;
| started&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lti\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lti&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lti\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lti&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lti\event\unknown_service_api_called&#039;&#039;&#039;&lt;br /&gt;
| lti_unknown_service_api_call&lt;br /&gt;
| mod_lti&lt;br /&gt;
| unknown_service_api&lt;br /&gt;
| called&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_page\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_page&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_page\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_page&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_quiz\event\attempt_abandoned&#039;&#039;&#039;&lt;br /&gt;
| quiz_attempt_abandoned&lt;br /&gt;
| mod_quiz&lt;br /&gt;
| attempt&lt;br /&gt;
| abandoned&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_quiz\event\attempt_becameoverdue&#039;&#039;&#039;&lt;br /&gt;
| quiz_attempt_overdue&lt;br /&gt;
| mod_quiz&lt;br /&gt;
| attempt&lt;br /&gt;
| becameoverdue&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_quiz\event\attempt_started&#039;&#039;&#039;&lt;br /&gt;
| quiz_attempt_started&lt;br /&gt;
| mod_quiz&lt;br /&gt;
| attempt&lt;br /&gt;
| started&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_quiz\event\attempt_submitted&#039;&#039;&#039;&lt;br /&gt;
| quiz_attempt_submitted&lt;br /&gt;
| mod_quiz&lt;br /&gt;
| attempt&lt;br /&gt;
| submitted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_resource\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_resource&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_resource\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_resource&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\attempt_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| attempt&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\interactions_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| interactions&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\report_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| report&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\sco_launched&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| sco&lt;br /&gt;
| launched&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\tracks_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| tracks&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\user_report_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| user_report&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_url\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_url&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_url\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_url&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| comment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| comment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\comments_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| comments&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_diff_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_diff&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_history_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_history&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_locks_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_locks&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_map_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_map&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_version_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_version&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_version_restored&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_version&lt;br /&gt;
| restored&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_version_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_version&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\assessable_uploaded&#039;&#039;&#039;&lt;br /&gt;
| assessable_content_uploaded&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| assessable&lt;br /&gt;
| uploaded&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\assessment_evaluated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| assessment&lt;br /&gt;
| evaluated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\assessment_evaluations_reset&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| assessment_evaluations&lt;br /&gt;
| reset&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\assessment_reevaluated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| assessment&lt;br /&gt;
| reevaluated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| workshop_viewed&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\instances_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| instances_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\phase_switched&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| phase&lt;br /&gt;
| switched&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\submission_assessed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| submission&lt;br /&gt;
| assessed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\submission_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| submission&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\submission_reassessed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| submission&lt;br /&gt;
| reassessed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\submission_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| submission&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\submission_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| submission&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;report_log\event\content_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| report_log&lt;br /&gt;
| content&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;report_loglive\event\content_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| report_loglive&lt;br /&gt;
| content&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;report_outline\event\content_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| report_outline&lt;br /&gt;
| content&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;report_participation\event\content_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| report_participation&lt;br /&gt;
| content&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;report_stats\event\content_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| report_stats&lt;br /&gt;
| content&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Verb list ===&lt;br /&gt;
All events must use a verb from this list. New verbs can be added to this list if required, but additions should only be made if there is no valid alternative (we want to keep this list as small as possible).&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!verb&lt;br /&gt;
!Explanation&lt;br /&gt;
!Source&lt;br /&gt;
|-&lt;br /&gt;
|abandoned&lt;br /&gt;
|When a attempt is abandoned by user (Quiz attempt)&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|accepted&lt;br /&gt;
|Example: Accepting a statement when submitting an assignment.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|added&lt;br /&gt;
|	Used to represent &amp;quot;something that already exists is now part of/bound to another entity&amp;quot;. Examples: &amp;quot;Admin added role to user X&amp;quot;, &amp;quot;Admin added user X to group A&amp;quot;. Wrong example: &amp;quot;User added course in category&amp;quot; because it is a &#039;move&#039; action, except if a course can be part of multiple categories. The good examples work because: A user can have multiple roles, a user can be in multiple groups.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|answered&lt;br /&gt;
| Indicates the actor responded to a Question&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|assessed&lt;br /&gt;
| Some submitted material has been assessed&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|assigned&lt;br /&gt;
| Assign some privilege or role to user.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|attempted&lt;br /&gt;
| Trying to do an activity. Example: attempting a Math class.&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|awarded&lt;br /&gt;
| ex:-teacher awarded student a badge.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|backedup&lt;br /&gt;
| When a backup has been performed.&lt;br /&gt;
|Moodle	&lt;br /&gt;
|-&lt;br /&gt;
|becomeoverdue&lt;br /&gt;
| When an activity is overdue Example: Quiz attempt is overdue&lt;br /&gt;
|Moodle	&lt;br /&gt;
|-&lt;br /&gt;
|called&lt;br /&gt;
| When a call to something is made like an API @see unknown_service_api_called.php&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|commented&lt;br /&gt;
|Offered an opinion or written experience of the activity. Can be used with the learner as the actor or a system as an actor. Comments can be sent from either party with the idea that the other will read and react to the content.&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|completed&lt;br /&gt;
|To experience the activity in its entirety. Used to affirm the completion of content. This can be simply experiencing all the content, be tied to objectives or interactions, or determined in any other way. Any content that has been initialized, but not yet completed, should be considered incomplete. There is no verb to &#039;incomplete&#039; an activity, one would void the statement which completes the activity.&amp;quot;&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|created&lt;br /&gt;
|Used to represent &amp;quot;something new has been created&amp;quot;.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|deleted&lt;br /&gt;
|Used to indicate the object in context was deleted.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|disabled&lt;br /&gt;
|When an activity is disabled. Example: forum read tracking disabled.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|downloaded&lt;br /&gt;
|When a user download file from user. Example submission/report downloaded.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|duplicated&lt;br /&gt;
|For something that has been copied.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|enabled&lt;br /&gt;
|When some setting is enabled. Example: forum read tracking enabled.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|ended&lt;br /&gt;
|When a process ends. Example: Lesson ended or course reset ended.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|evaluated&lt;br /&gt;
|Material has been evaluated.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|exported&lt;br /&gt;
|When a report is exported in certain format.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|failed&lt;br /&gt;
|Learner did not perform the activity to a level of pre-determined satisfaction. Used to affirm the lack of success a learner experienced within the learning content in relation to a threshold. If the user performed below the minimum to the level of this threshold, the content is &#039;failed&#039;. The opposite of &#039;passed&#039;. This is also used in case when message sending is failed.&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|graded&lt;br /&gt;
|Used to represent an activity was graded.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|granted&lt;br /&gt;
|User is granted some extension or capability. Example: extension granted for submission.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|imported&lt;br /&gt;
|The act of moving an object into another location or system.&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|launched&lt;br /&gt;
|When an external object is launched. Try consider started if there is related stopped event.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|locked&lt;br /&gt;
|When an activity is locked. Should have a related unlocked event.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|loggedin/loggedout&lt;br /&gt;
|	For login and logout.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|loggedinas&lt;br /&gt;
|	 If user is logged in as different user. This is used by only one event (user_loggedinas). Adding this verb makes event name more clear, then using loggedin verb.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|locked&lt;br /&gt;
|&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|moved&lt;br /&gt;
|	Used to indicate the object in context was moved.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|passed&lt;br /&gt;
|Used to affirm the success a learner experienced within the learning content in relation to a threshold. If the user performed at a minimum to the level of this threshold, the content is &#039;passed&#039;. The opposite of &#039;failed&#039;.&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|printed&lt;br /&gt;
|Something is printed.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|reassessed&lt;br /&gt;
|Submitted material has been assessed again.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|reevaluated&lt;br /&gt;
|Material has been evaluated again.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|removed&lt;br /&gt;
|By opposition to &amp;quot;Added&amp;quot;. This does not mean that the object has been deleted, but removed from the entity, or not bound to it any more.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|reset&lt;br /&gt;
|Sets one or more properties back to the default value.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|restored&lt;br /&gt;
|When restoring a backup. Rolling back to a previous state.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|revealed&lt;br /&gt;
|Some identity is revealed. Example: Identities revealed after blind marking.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|searched&lt;br /&gt;
|Something is searched. Example: searched in course.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|sent&lt;br /&gt;
|Message sent.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|started&lt;br /&gt;
|Some activity started&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|submitted&lt;br /&gt;
|This is very close to &amp;quot;Attempted&amp;quot;. Depends on context which one should be used. For example:- &amp;quot;Admin submitted a form. Student attempted a quiz.&amp;quot;  is correct, however some cases might not be as clear as the previous example. We can say both &amp;quot;Student submitted an assignment&amp;quot; or &amp;quot;student attempted an assignment&amp;quot;. We need to make the difference clear.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|suspended&lt;br /&gt;
| Suspend something. (example a user)&lt;br /&gt;
| Tincan (However the context is different)&lt;br /&gt;
|-&lt;br /&gt;
|switched&lt;br /&gt;
|Something has been switched. For example:- The workshop phase has been switched to assessment&amp;quot;&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|unassigned&lt;br /&gt;
|As opposed to assigned. When some role is unassigned.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|unlocked&lt;br /&gt;
|&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|upgraded&lt;br /&gt;
|Something was upgraded, some module probably&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|updated&lt;br /&gt;
|Used to indicate the object in context was updated. Simple example is &amp;quot;Admin updated course xyz&amp;quot;.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|uploaded&lt;br /&gt;
|When an assignment is uploaded.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|viewed&lt;br /&gt;
|Something has been viewed. For example:- &amp;quot;Student viewed chapter 1 of book 1.&amp;quot;&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Rules ===&lt;br /&gt;
&lt;br /&gt;
==== Use singular ====&lt;br /&gt;
&lt;br /&gt;
Plurals must be used on objects when it&#039;s a &#039;&#039;One to Many&#039;&#039; relationship. Ex: bulk import, mass deletion, ... In any other case, use the singular.&lt;br /&gt;
&lt;br /&gt;
==== Ends with a verb ====&lt;br /&gt;
&lt;br /&gt;
The last word (after the last underscore) must be a verb.&lt;br /&gt;
&lt;br /&gt;
==== Consistency among child events ====&lt;br /&gt;
&lt;br /&gt;
If an event is extending a parent class, it should have the same exact name as the parent event.&lt;br /&gt;
&lt;br /&gt;
=== Deprecated events ===&lt;br /&gt;
Following are the events that were supported in 2.5, but deprecated in 2.6 or later&lt;br /&gt;
&lt;br /&gt;
groups_groupings_deleted (see MDL-41312)&lt;br /&gt;
&lt;br /&gt;
groups_groupings_groups_removed (see MDL-41312)&lt;br /&gt;
&lt;br /&gt;
groups_groups_deleted (see MDL-41312)&lt;br /&gt;
&lt;br /&gt;
groups_members_removed (see MDL-41312)&lt;br /&gt;
&lt;br /&gt;
== Shared events ==&lt;br /&gt;
&lt;br /&gt;
 Decision: Not supported at this stage.&lt;br /&gt;
&lt;br /&gt;
In Moodle 2.5 we have a good example of a shared event: &#039;assessable_content_uploaded&#039; which is triggered in &#039;&#039;forum&#039;&#039;, &#039;assignment&#039;&#039; and &#039;&#039;workshop&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The problem with shared events is that we cannot easily track what component triggered them. Of course we could add a new property to the event to keep track of that, but we would soon need more information and more properties. Also, in the case of a logger, the event received would be unique, where in fact it should be considered different depending on the component firing it.&lt;br /&gt;
&lt;br /&gt;
In our first implementation, we will create one specific event per module. This flexibility does not prevent any observer from capturing them, but still makes sure that the consistency and specificity of each event is maintained.&lt;br /&gt;
&lt;br /&gt;
It could happen that some events are defined in core and shared, but this should not really happen as low-level APIs should trigger the event, and a module should call that low API instead of doing the job itself.&lt;br /&gt;
&lt;br /&gt;
== One to many ==&lt;br /&gt;
&lt;br /&gt;
 Decision: Each event should have a one to one relationship. We can reconsider this at a later stage, if the performance hit is extremely high.&lt;br /&gt;
&lt;br /&gt;
In 2.5, some events are triggered when an action happens on multiple objects. We have to decide whether we want to keep supporting &#039;&#039;One to Many&#039;&#039; events or not.&lt;br /&gt;
&lt;br /&gt;
Keeping a list of all changes for multiple actions may be problematic because you would have to keep them all in memory until all things are processed. This might also result in the order of events being incorrect. The only correct solution seems to be to trigger each item individually and then many things at the end. Performance needs to be improved elsewhere...&lt;br /&gt;
&lt;br /&gt;
=== Accuracy ===&lt;br /&gt;
&lt;br /&gt;
When uploading a bunch of users using the CSV upload feature, if only one event is triggered, it means that the observers of &#039;&#039;user_created&#039;&#039; won&#039;t be triggered. And so some functionality can be lost as, as a plugin developer, I expect this &#039;&#039;user_created&#039;&#039; to be triggered regardless of the way they have been uploaded. Of course, the developer could observe the event &#039;&#039;bulk_user_imported&#039;&#039;, but that means that he could miss some relevant observers.&lt;br /&gt;
&lt;br /&gt;
This applies to existing events.&lt;br /&gt;
&lt;br /&gt;
=== Performance ===&lt;br /&gt;
&lt;br /&gt;
Triggering one event is cheaper then repeating the same events x number of times...&lt;br /&gt;
&lt;br /&gt;
=== Information tracking ===&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;bulk&#039;&#039; event, might not be verbose enough to allow for proper logging afterwards. Though this is the responsibility of the logger, we probably want to make it easy to store relevant information.&lt;br /&gt;
&lt;br /&gt;
=== Double event ===&lt;br /&gt;
&lt;br /&gt;
In the case of a bulk user import, if we were to trigger an event per user created, we probably want to trigger one event &#039;user_bulk_upload_started&#039; when the action starts.&lt;br /&gt;
&lt;br /&gt;
== Unit Testing ==&lt;br /&gt;
&lt;br /&gt;
With unit testing for this system we want to assert the following:&lt;br /&gt;
&lt;br /&gt;
* That event strict validation and custom validation works.&lt;br /&gt;
* Missing event data is auto filled with accurate data.&lt;br /&gt;
* Typos in properties passed to ::create() are captured (if we decide to validate).&lt;br /&gt;
* The legacy methods return the expected values (use assertEventLegacyData() and assertEventLegacyData())&lt;br /&gt;
* The class properties are correctly overridden (crud, level, action, object, ...).&lt;br /&gt;
* The properties automatically generated (component, name, ...) are correct.&lt;br /&gt;
* Events are dispatched to the corresponding observers.&lt;br /&gt;
* Events are dispatched to the corresponding legacy handlers.&lt;br /&gt;
* Events are dispatched to the * observers.&lt;br /&gt;
* Events perform an add_to_log() if it has legacy log data.&lt;br /&gt;
* &#039;Events restore&#039; restored the whole event data, and does not miss any information.&lt;br /&gt;
* &#039;Events restore&#039; does not generate any extra information.&lt;br /&gt;
* Event methods should check context object or avoid using it, as context might not be valid at time of event restore (use assertEventContextNotUsed())&lt;br /&gt;
&lt;br /&gt;
= PHP docs =&lt;br /&gt;
* All events php docs must include @since parameter, indicating when the event was first included in standard Moodle distribution.&lt;br /&gt;
* All events must declare the $other properties using mark down in the php docs. This later might be converted to a self documenting structure. (See MDL-45108)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * blog_association_created&lt;br /&gt;
 *&lt;br /&gt;
 * Class for event to be triggered when a new blog entry is associated with a context.&lt;br /&gt;
 *&lt;br /&gt;
 * @property-read array $other {&lt;br /&gt;
 *      Extra information about event.&lt;br /&gt;
 *&lt;br /&gt;
 *      - string associatetype: type of blog association, course/coursemodule.&lt;br /&gt;
 *      - int blogid: id of blog.&lt;br /&gt;
 *      - int associateid: id of associate.&lt;br /&gt;
 *      - string subject: blog subject.&lt;br /&gt;
 * }&lt;br /&gt;
 *&lt;br /&gt;
 * @package    core&lt;br /&gt;
 * @since      Moodle 2.7&lt;br /&gt;
 * @copyright  2013 onwards Ankit Agarwal&lt;br /&gt;
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Example events =&lt;br /&gt;
&lt;br /&gt;
== Assignment ==&lt;br /&gt;
&lt;br /&gt;
Assumption: Course contains groups with students in each group.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.&#039;&#039;&#039; Teacher creates an assignment with group mode set to &#039;Separate groups&#039; and Feedback type set to comments and files.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has created assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;2.&#039;&#039;&#039; A student views the assignment.&lt;br /&gt;
*Event: User &#039;Student&#039; has viewed assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;3.&#039;&#039;&#039; A member from one of the groups submits an assignment&lt;br /&gt;
*Event: User &#039;Student&#039; has added a submission for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to the teacher and all students in that group.&lt;br /&gt;
&#039;&#039;&#039;4.&#039;&#039;&#039; User &#039;Adrian&#039; adds some changes to the assignment and updates it.&lt;br /&gt;
*Event: User &#039;Adrian&#039; has updated the submission for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to the teacher and all students in that group.&lt;br /&gt;
&#039;&#039;&#039;5.&#039;&#039;&#039; Teacher views the assignment.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has viewed assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;6.&#039;&#039;&#039; Teacher clicks on &#039;View/grade all submissions&#039;&lt;br /&gt;
*Event: User &#039;Teacher&#039; has viewed the assignment &#039;B&#039; grade area in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;7.&#039;&#039;&#039; Teacher clicks to grade the student&#039;s submission.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has viewed the submission for user &#039;student&#039; for assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;8.&#039;&#039;&#039; Teacher marks the assignment with the setting &#039;Apply grades and feedback to entire group&#039; set to &#039;Yes&#039; leaving a comment and a file.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has marked assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has left a comment for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has uploaded a feedback file for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has uploaded a file to the course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to user &#039;Student&#039; notifying them their submission for assignment &#039;B&#039; has been marked. - This is done for all users in the group.&lt;br /&gt;
&#039;&#039;&#039;9.&#039;&#039;&#039; User &#039;Adrian&#039; views the feedback.&lt;br /&gt;
*Event: User &#039;Adrian&#039; has viewed assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;10.&#039;&#039;&#039; User &#039;Adrian&#039; opens the feedback file.&lt;br /&gt;
*Event: User &#039;Adrian&#039; has viewed the file &#039;A&#039; for assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;11.&#039;&#039;&#039; User &#039;Adrian&#039; adds some changes to the assignment insulting the teachers marking and updates it.&lt;br /&gt;
*Event: User &#039;Adrian&#039; has updated the submission for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to user &#039;Teacher&#039; notifying them that user &#039;Adrian&#039; has updated the submission for assignment &#039;B&#039;.&lt;br /&gt;
*Event: Email sent to user &#039;Student&#039; notifying them their submission for assignment &#039;B&#039; has been updated. - This is done for all users in the group.&lt;br /&gt;
&#039;&#039;&#039;12.&#039;&#039;&#039; The teacher clicks directly on the link in the email to be taken to the grading page.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has viewed the submission for user &#039;student&#039; for assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;13.&#039;&#039;&#039; The teacher is upset due to the harsh comments and decides to mark Adrian down, but not the rest of the group by setting &#039;Apply grades and feedback to entire group&#039; set to &#039;No&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has marked assignment &#039;B&#039; for user &#039;Adrian&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has left a comment for assignment &#039;B&#039; for user &#039;Adrian&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has uploaded a feedback file for assignment &#039;B&#039; for user &#039;Adrian&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to user &#039;Adrian&#039; notifying them their submission for assignment &#039;B&#039; has been marked.&lt;br /&gt;
&lt;br /&gt;
= FAQs =&lt;br /&gt;
&lt;br /&gt;
; Why not create events in core subsystems? : Because we could not see all core events in one place, it would create problems when naming event classes and finally subsystems are incomplete, we would have to add more now because we could not move the events in the future.&lt;br /&gt;
&lt;br /&gt;
= Possible future work = &lt;br /&gt;
* MDL-45108 &amp;quot;Other&amp;quot; parameters should be defined in a method similar to webservices&lt;br /&gt;
* MDL-45217 Create traits for refactoring event triggers&lt;br /&gt;
* MDL-42897 Converting completion to use events&lt;br /&gt;
* MDL-42898 Develop a timeline page/block&lt;br /&gt;
&lt;br /&gt;
= See Also =&lt;br /&gt;
[[Logging 2]]  &lt;br /&gt;
&lt;br /&gt;
[[Tin Can]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Event_Monitor_specification&amp;diff=45612</id>
		<title>Event Monitor specification</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Event_Monitor_specification&amp;diff=45612"/>
		<updated>2014-07-01T05:45:58Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* Future work */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Project&lt;br /&gt;
|name = Event Monitor&lt;br /&gt;
|state = Implementation&lt;br /&gt;
|tracker = MDL-45758&lt;br /&gt;
|discussion = https://moodle.org/mod/forum/discuss.php?d=261660&lt;br /&gt;
|assignee = Ankit, Simey&lt;br /&gt;
}}&lt;br /&gt;
{{Work in progress|forumurl=https://moodle.org/mod/forum/discuss.php?d=261660}}&lt;br /&gt;
The Event Monitor report will allow users to select events and receive notifications in real time* when the chosen event happens.&lt;br /&gt;
&lt;br /&gt;
This report will be built on top of the new [[Event 2]] infrastructure. &lt;br /&gt;
&lt;br /&gt;
== How it works ==&lt;br /&gt;
&lt;br /&gt;
* The user or site admin creates a specific set of “rules” that can be subscribed to.&lt;br /&gt;
* Each rule defines an event and frequency parameters.&lt;br /&gt;
* The users select the rules they are interested in and then subscribe to it at course level for a specific module or all modules.&lt;br /&gt;
* Whenever the event occurs in the system , in the frequency specified in the rule, a message is sent out to all the subscribers.&lt;br /&gt;
* Since we are using Moodle messaging system to send out these notifications, it can be delivered in any format supported by Moodle (Mobile notification, popup, email etc)&lt;br /&gt;
* There would be some default rules that would be shipped with the report, that users can subscribe to straight away.&lt;br /&gt;
&lt;br /&gt;
=== User interface mock-ups ===&lt;br /&gt;
&lt;br /&gt;
==== Subscribe to a rule ====&lt;br /&gt;
&lt;br /&gt;
This is the main page of the Event Monitor report where users can see a list of rules and their current subscriptions. This also lets users to subscribe to new rules or delete their current subscriptions.&lt;br /&gt;
&lt;br /&gt;
[[File:subscriptions.png]]&lt;br /&gt;
&lt;br /&gt;
==== Manage rules ====&lt;br /&gt;
&lt;br /&gt;
This page lets you manage the rules if you have appropriate permissions (create/edit/delete/copy)&lt;br /&gt;
&lt;br /&gt;
This is roughly how the page will look like:-&lt;br /&gt;
&lt;br /&gt;
[[File:listrules.png]]&lt;br /&gt;
&lt;br /&gt;
==== Add/Edit a rule ====&lt;br /&gt;
&lt;br /&gt;
This is the form where users can create a new rule, customise the filters (frequency and time) and personalise the notification message.&lt;br /&gt;
&lt;br /&gt;
[[File:addrule.png]]&lt;br /&gt;
&lt;br /&gt;
=== A specific example ===&lt;br /&gt;
&lt;br /&gt;
One scenario may be that you wish to be notified when discussions are becoming active in the forums.&lt;br /&gt;
&lt;br /&gt;
The figure above shows the creation of a new rule called &#039;My Student Discussions&#039;, which is set to monitor &#039;Post Created event&#039; on &#039;Forum Module&#039;. &lt;br /&gt;
&lt;br /&gt;
In this case, any user subscribed to this rule will receive notifications whenever &#039;30 posts are created in 60 minutes&#039; on the forum they are subscribed to. &lt;br /&gt;
&lt;br /&gt;
The notification will contain the customised message as configured in the rule.&lt;br /&gt;
&lt;br /&gt;
== Benefits ==&lt;br /&gt;
&lt;br /&gt;
* Real time monitoring of events happening in Moodle. &lt;br /&gt;
* Admin can be notified when there is heavy activity on the site or they can monitor specific actions that interests them (ex:- course delete).&lt;br /&gt;
* A notification can be sent straight to a user&#039;s mobile if there is a situation that needs immediate attention.&lt;br /&gt;
* The report will be designed to trigger an event when a given subscription criteria are met. This will allow developers to build really powerful scripts on top of the report. For example, a block displaying “Hot forums”, or something more complex like load balancing when there is lot of activity in the forums or quiz.&lt;br /&gt;
&lt;br /&gt;
== Usage scenarios ==&lt;br /&gt;
&lt;br /&gt;
* Send notification when more than X posts in any forum are made in a given course in Y minutes.&lt;br /&gt;
* Send notification when new chapters are created in a book.&lt;br /&gt;
* Send notification (to admin) when a course is deleted.&lt;br /&gt;
* Send notification  (to students) that a particular activity has been updated.&lt;br /&gt;
* Send notification (to admin) when potential security risk might happen due to change in system setting.&lt;br /&gt;
&lt;br /&gt;
== Future work ==&lt;br /&gt;
&lt;br /&gt;
* Allow events to be subscribed by only certain roles&lt;br /&gt;
* Forced subscriptions for students for certain rules&lt;br /&gt;
* An activity stream for messages&lt;br /&gt;
* An facebook style notification system for notifying logged in users&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Event 2]]&lt;br /&gt;
* Moodlerooms developed a &amp;quot;[http://kb.moodlerooms.com/article/81/administrator Personalized Learning Designer]&amp;quot; that has some of these features (mostly for individual students only).&lt;br /&gt;
* Real time means “as soon as possible” - this depends on the cron configuration of the site. (For further information refer to [[https://docs.moodle.org/dev/Task_API#Adhoc_task_usage Adhoc tasks]])&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Event_Monitor_specification&amp;diff=45509</id>
		<title>Event Monitor specification</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Event_Monitor_specification&amp;diff=45509"/>
		<updated>2014-06-26T03:40:45Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Project&lt;br /&gt;
|name = Event Monitor&lt;br /&gt;
|state = Implementation&lt;br /&gt;
|tracker = MDL-45758&lt;br /&gt;
|discussion = https://moodle.org/mod/forum/discuss.php?d=261660&lt;br /&gt;
|assignee = Ankit, Simey&lt;br /&gt;
}}&lt;br /&gt;
{{Work in progress|forumurl=https://moodle.org/mod/forum/discuss.php?d=261660}}&lt;br /&gt;
The Event Monitor report will allow users to select events and receive notifications in real time* when the chosen event happens.&lt;br /&gt;
&lt;br /&gt;
This report will be built on top of the new [[Event 2]] infrastructure. &lt;br /&gt;
&lt;br /&gt;
== How it works ==&lt;br /&gt;
&lt;br /&gt;
* The user or site admin creates a specific set of “rules” that can be subscribed to.&lt;br /&gt;
* Each rule defines an event and frequency parameters.&lt;br /&gt;
* The users select the rules they are interested in and then subscribe to it at course level for a specific module or all modules.&lt;br /&gt;
* Whenever the event occurs in the system , in the frequency specified in the rule, a message is sent out to all the subscribers.&lt;br /&gt;
* Since we are using Moodle messaging system to send out these notifications, it can be delivered in any format supported by Moodle (Mobile notification, popup, email etc)&lt;br /&gt;
* There would be some default rules that would be shipped with the report, that users can subscribe to straight away.&lt;br /&gt;
&lt;br /&gt;
=== User interface mock-ups ===&lt;br /&gt;
&lt;br /&gt;
==== Subscribe to a rule ====&lt;br /&gt;
&lt;br /&gt;
This is the main page of the Event Monitor report where users can see a list of rules and their current subscriptions. This also lets users to subscribe to new rules or delete their current subscriptions.&lt;br /&gt;
&lt;br /&gt;
[[File:subscriptions.png]]&lt;br /&gt;
&lt;br /&gt;
==== Manage rules ====&lt;br /&gt;
&lt;br /&gt;
This page lets you manage the rules if you have appropriate permissions (create/edit/delete/copy)&lt;br /&gt;
&lt;br /&gt;
This is roughly how the page will look like:-&lt;br /&gt;
&lt;br /&gt;
[[File:listrules.png]]&lt;br /&gt;
&lt;br /&gt;
==== Add/Edit a rule ====&lt;br /&gt;
&lt;br /&gt;
This is the form where users can create a new rule, customise the filters (frequency and time) and personalise the notification message.&lt;br /&gt;
&lt;br /&gt;
[[File:addrule.png]]&lt;br /&gt;
&lt;br /&gt;
=== A specific example ===&lt;br /&gt;
&lt;br /&gt;
One scenario may be that you wish to be notified when discussions are becoming active in the forums.&lt;br /&gt;
&lt;br /&gt;
The figure above shows the creation of a new rule called &#039;My Student Discussions&#039;, which is set to monitor &#039;Post Created event&#039; on &#039;Forum Module&#039;. &lt;br /&gt;
&lt;br /&gt;
In this case, any user subscribed to this rule will receive notifications whenever &#039;30 posts are created in 60 minutes&#039; on the forum they are subscribed to. &lt;br /&gt;
&lt;br /&gt;
The notification will contain the customised message as configured in the rule.&lt;br /&gt;
&lt;br /&gt;
== Benefits ==&lt;br /&gt;
&lt;br /&gt;
* Real time monitoring of events happening in Moodle. &lt;br /&gt;
* Admin can be notified when there is heavy activity on the site or they can monitor specific actions that interests them (ex:- course delete).&lt;br /&gt;
* A notification can be sent straight to a user&#039;s mobile if there is a situation that needs immediate attention.&lt;br /&gt;
* The report will be designed to trigger an event when a given subscription criteria are met. This will allow developers to build really powerful scripts on top of the report. For example, a block displaying “Hot forums”, or something more complex like load balancing when there is lot of activity in the forums or quiz.&lt;br /&gt;
&lt;br /&gt;
== Usage scenarios ==&lt;br /&gt;
&lt;br /&gt;
* Send notification when more than X posts in any forum are made in a given course in Y minutes.&lt;br /&gt;
* Send notification when new chapters are created in a book.&lt;br /&gt;
* Send notification (to admin) when a course is deleted.&lt;br /&gt;
* Send notification  (to students) that a particular activity has been updated.&lt;br /&gt;
* Send notification (to admin) when potential security risk might happen due to change in system setting.&lt;br /&gt;
&lt;br /&gt;
== Future work ==&lt;br /&gt;
&lt;br /&gt;
* Allow events to be subscribed by only certain roles&lt;br /&gt;
* Forced subscriptions for students for certain rules&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Event 2]]&lt;br /&gt;
* Moodlerooms developed a &amp;quot;[http://kb.moodlerooms.com/article/81/administrator Personalized Learning Designer]&amp;quot; that has some of these features (mostly for individual students only).&lt;br /&gt;
* Real time means “as soon as possible” - this depends on the cron configuration of the site. (For further information refer to [[https://docs.moodle.org/dev/Task_API#Adhoc_task_usage Adhoc tasks]])&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Event_Monitor_specification&amp;diff=45189</id>
		<title>Event Monitor specification</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Event_Monitor_specification&amp;diff=45189"/>
		<updated>2014-06-06T10:23:05Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Work in progress}}&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Event Monitor&lt;br /&gt;
|state = Specification/Prototyping&lt;br /&gt;
|tracker = MDL-45758&lt;br /&gt;
|discussion = https://moodle.org/mod/forum/discuss.php?d=261660&lt;br /&gt;
|assignee = Ankit, Simey&lt;br /&gt;
}}&lt;br /&gt;
The Event Monitor report will allow users to select events and receive notifications in real time* when the chosen event happens.&lt;br /&gt;
&lt;br /&gt;
This report will be built on top of the new [[Event 2]] infrastructure. &lt;br /&gt;
&lt;br /&gt;
== How it works ==&lt;br /&gt;
&lt;br /&gt;
* The user or site admin creates a specific set of “rules” that can be subscribed to.&lt;br /&gt;
* Each rule defines an event and frequency parameters.&lt;br /&gt;
* The users select the rules they are interested in and then subscribe to it at course level for a specific module or all modules.&lt;br /&gt;
* Whenever the event occurs in the system , in the frequency specified in the rule, a message is sent out to all the subscribers.&lt;br /&gt;
* Since we are using Moodle messaging system to send out these notifications, it can be delivered in any format supported by Moodle (Mobile notification, popup, email etc)&lt;br /&gt;
* There would be some default rules that would be shipped with the report, that users can subscribe to straight away.&lt;br /&gt;
&lt;br /&gt;
=== User interface mock-ups ===&lt;br /&gt;
&lt;br /&gt;
==== Subscribe to a rule ====&lt;br /&gt;
&lt;br /&gt;
This is the main page of the Event Monitor report where users can see a list of rules and their current subscriptions. This also lets users to subscribe to new rules or delete their current subscriptions.&lt;br /&gt;
&lt;br /&gt;
[[File:subscriptions.png]]&lt;br /&gt;
&lt;br /&gt;
==== Manage rules ====&lt;br /&gt;
&lt;br /&gt;
This page lets you manage the rules if you have appropriate permissions (create/edit/delete/copy)&lt;br /&gt;
&lt;br /&gt;
This is roughly how the page will look like:-&lt;br /&gt;
&lt;br /&gt;
[[File:listrules.png]]&lt;br /&gt;
&lt;br /&gt;
==== Add/Edit a rule ====&lt;br /&gt;
&lt;br /&gt;
This is the form where users can create a new rule, customise the filters (frequency and time) and personalise the notification message.&lt;br /&gt;
&lt;br /&gt;
[[File:addrule.png]]&lt;br /&gt;
&lt;br /&gt;
=== A specific example ===&lt;br /&gt;
&lt;br /&gt;
One scenario may be that you wish to be notified when discussions are becoming active in the forums.&lt;br /&gt;
&lt;br /&gt;
The figure above shows the creation of a new rule called &#039;My Student Discussions&#039;, which is set to monitor &#039;Post Created event&#039; on &#039;Forum Module&#039;. &lt;br /&gt;
&lt;br /&gt;
In this case, any user subscribed to this rule will receive notifications whenever &#039;30 posts are created in 60 minutes&#039; on the forum they are subscribed to. &lt;br /&gt;
&lt;br /&gt;
The notification will contain the customised message as configured in the rule.&lt;br /&gt;
&lt;br /&gt;
== Benefits ==&lt;br /&gt;
&lt;br /&gt;
* Real time monitoring of events happening in Moodle. &lt;br /&gt;
* Admin can be notified when there is heavy activity on the site or they can monitor specific actions that interests them (ex:- course delete).&lt;br /&gt;
* A notification can be sent straight to a user&#039;s mobile if there is a situation that needs immediate attention.&lt;br /&gt;
* The report will be designed to trigger an event when a given subscription criteria are met. This will allow developers to build really powerful scripts on top of the report. For example, a block displaying “Hot forums”, or something more complex like load balancing when there is lot of activity in the forums or quiz.&lt;br /&gt;
&lt;br /&gt;
== Usage scenarios ==&lt;br /&gt;
&lt;br /&gt;
* Send notification when more than X posts in any forum are made in a given course in Y minutes.&lt;br /&gt;
* Send notification when new chapters are created in a book.&lt;br /&gt;
* Send notification (to admin) when a course is deleted.&lt;br /&gt;
* Send notification  (to students) that a particular activity has been updated.&lt;br /&gt;
* Send notification (to admin) when potential security risk might happen due to change in system setting.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Event 2]]&lt;br /&gt;
* Moodlerooms developed a &amp;quot;[http://kb.moodlerooms.com/article/81/administrator Personalized Learning Designer]&amp;quot; that has some of these features (mostly for individual students only).&lt;br /&gt;
* Real time means “as soon as possible” - this depends on the cron configuration of the site. (For further information refer to [[https://docs.moodle.org/dev/Task_API#Adhoc_task_usage Adhoc tasks]])&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Event_Monitor_specification&amp;diff=45175</id>
		<title>Event Monitor specification</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Event_Monitor_specification&amp;diff=45175"/>
		<updated>2014-06-06T07:35:44Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* Usage scenarios */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Work in progress}}&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Event Monitor&lt;br /&gt;
|state = Specification/Prototyping&lt;br /&gt;
|tracker = MDL-45758&lt;br /&gt;
|discussion = To be created&lt;br /&gt;
|assignee = Ankit, Simey&lt;br /&gt;
}}&lt;br /&gt;
The Event Monitor report will allow users to select events and receive notifications in real time* when the chosen event happens.&lt;br /&gt;
&lt;br /&gt;
This report will be built on top of the new [[Event 2]] infrastructure. &lt;br /&gt;
&lt;br /&gt;
== How it works ==&lt;br /&gt;
&lt;br /&gt;
* The user or site admin creates a specific set of “rules” that can be subscribed to.&lt;br /&gt;
* Each rule defines an event and frequency parameters.&lt;br /&gt;
* The users select the rules they are interested in and then subscribe to it at course level for a specific module or all modules.&lt;br /&gt;
* Whenever the event occurs in the system , in the frequency specified in the rule, a message is sent out to all the subscribers.&lt;br /&gt;
* Since we are using Moodle messaging system to send out these notifications, it can be delivered in any format supported by Moodle (Mobile notification, popup, email etc)&lt;br /&gt;
* There would be some default rules that would be shipped with the report, that users can subscribe to straight away.&lt;br /&gt;
&lt;br /&gt;
=== User interface mock-ups ===&lt;br /&gt;
&lt;br /&gt;
==== List rules ====&lt;br /&gt;
&lt;br /&gt;
This is the main page of the Event Monitor report where users can see a list of rules. This page lets you subscribe/un-subscribe to the rules, and also lets you manage the rules if you have appropriate permissions (create/edit/delete/copy)&lt;br /&gt;
&lt;br /&gt;
This is roughly how the page will look like:-&lt;br /&gt;
&lt;br /&gt;
[[File:listrules.png]]&lt;br /&gt;
&lt;br /&gt;
==== Add/Edit a rule ====&lt;br /&gt;
&lt;br /&gt;
This is the form where users can create a new rule, customise the filters (frequency and time) and personalise the notification message.&lt;br /&gt;
&lt;br /&gt;
[[File:addrule.png]]&lt;br /&gt;
&lt;br /&gt;
=== A specific example ===&lt;br /&gt;
&lt;br /&gt;
One scenario may be that you wish to be notified when discussions are becoming active in the forums.&lt;br /&gt;
&lt;br /&gt;
The figure above shows the creation of a new rule called &#039;My Student Discussions&#039;, which is set to monitor &#039;Post Created event&#039; on &#039;Forum Module&#039;. &lt;br /&gt;
&lt;br /&gt;
In this case, any user subscribed to this rule will receive notifications whenever &#039;30 posts are created in 60 minutes&#039; on the forum they are subscribed to. &lt;br /&gt;
&lt;br /&gt;
The notification will contain the customised message as configured in the rule.&lt;br /&gt;
&lt;br /&gt;
== Benefits ==&lt;br /&gt;
&lt;br /&gt;
* Real time monitoring of events happening in Moodle. &lt;br /&gt;
* Admin can be notified when there is heavy activity on the site or they can monitor specific actions that interests them (ex:- course delete).&lt;br /&gt;
* A notification can be sent straight to a user&#039;s mobile if there is a situation that needs immediate attention.&lt;br /&gt;
* The report will be designed to trigger an event when a given subscription criteria are met. This will allow developers to build really powerful scripts on top of the report. For example, a block displaying “Hot forums”, or something more complex like load balancing when there is lot of activity in the forums or quiz.&lt;br /&gt;
&lt;br /&gt;
== Usage scenarios ==&lt;br /&gt;
&lt;br /&gt;
* Send notification when more than X posts in any forum are made in a given course in Y minutes.&lt;br /&gt;
* Send notification when new chapters are created in a book.&lt;br /&gt;
* Send notification (to admin) when a course is deleted.&lt;br /&gt;
* Send notification  (to students) that a particular activity has been updated.&lt;br /&gt;
* Send notification (to admin) when potential security risk might happen due to change in system setting.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Event 2]]&lt;br /&gt;
* Moodlerooms developed a &amp;quot;[http://kb.moodlerooms.com/article/81/administrator Personalized Learning Designer]&amp;quot; that has some of these features (mostly for individual students only).&lt;br /&gt;
* Real time means “as soon as possible” - this depends on the cron configuration of the site. (For further information refer to [[https://docs.moodle.org/dev/Task_API#Adhoc_task_usage Adhoc tasks]])&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Event_Monitor_specification&amp;diff=45101</id>
		<title>Event Monitor specification</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Event_Monitor_specification&amp;diff=45101"/>
		<updated>2014-06-03T09:36:42Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Project&lt;br /&gt;
|name = Event Monitor&lt;br /&gt;
|state = Specification/Prototyping&lt;br /&gt;
|tracker = MDL-45758&lt;br /&gt;
|discussion = To be created&lt;br /&gt;
|assignee = Ankit, Simey&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Work in progress}}&lt;br /&gt;
&lt;br /&gt;
The Event Monitor report will allow users to select events and receive notifications in real time* when the chosen event happens.&lt;br /&gt;
&lt;br /&gt;
This report will be built on top of the new [[Event 2]] infrastructure. &lt;br /&gt;
&lt;br /&gt;
== How it works ==&lt;br /&gt;
&lt;br /&gt;
* The user or site admin creates a specific set of “rules” that can be subscribed to.&lt;br /&gt;
* Each rule defines an event and frequency parameters.&lt;br /&gt;
* The users select the rules they are interested in and then subscribe to it at course level for a specific module or all modules.&lt;br /&gt;
* Whenever the event occurs in the system , in the frequency specified in the rule, a message is sent out to all the subscribers.&lt;br /&gt;
* Since we are using Moodle messaging system to send out these notifications, it can be delivered in any format supported by Moodle (Mobile notification, popup, email etc)&lt;br /&gt;
* There would be some default rules that would be shipped with the report, that users can subscribe to straight away.&lt;br /&gt;
&lt;br /&gt;
=== User interface mock-ups ===&lt;br /&gt;
&lt;br /&gt;
==== List rules ====&lt;br /&gt;
&lt;br /&gt;
This is the main page of the Event Monitor report where users can see a list of rules. This page lets you subscribe/un-subscribe to the rules, and also lets you manage the rules if you have appropriate permissions (create/edit/delete/copy)&lt;br /&gt;
&lt;br /&gt;
This is roughly how the page will look like:-&lt;br /&gt;
&lt;br /&gt;
[[File:listrules.png]]&lt;br /&gt;
&lt;br /&gt;
==== Add/Edit a rule ====&lt;br /&gt;
&lt;br /&gt;
This is the form where users can create a new rule, customise the filters (frequency and time) and personalise the notification message.&lt;br /&gt;
&lt;br /&gt;
[[File:addrule.png]]&lt;br /&gt;
&lt;br /&gt;
=== A specific example ===&lt;br /&gt;
&lt;br /&gt;
One scenario may be that you wish to be notified when discussions are becoming active in the forums.&lt;br /&gt;
&lt;br /&gt;
The figure above shows the creation of a new rule called &#039;My Student Discussions&#039;, which is set to monitor &#039;Post Created event&#039; on &#039;Forum Module&#039;. &lt;br /&gt;
&lt;br /&gt;
In this case, any user subscribed to this rule will receive notifications whenever &#039;30 posts are created in 60 minutes&#039; on the forum they are subscribed to. &lt;br /&gt;
&lt;br /&gt;
The notification will contain the customised message as configured in the rule.&lt;br /&gt;
&lt;br /&gt;
== Benefits ==&lt;br /&gt;
&lt;br /&gt;
* Real time monitoring of events happening in Moodle. &lt;br /&gt;
* Admin can be notified when there is heavy activity on the site or they can monitor specific actions that interests them (ex:- course delete).&lt;br /&gt;
* A notification can be sent straight to a user&#039;s mobile if there is a situation that needs immediate attention.&lt;br /&gt;
* The report will be designed to trigger an event when a given subscription criteria are met. This will allow developers to build really powerful scripts on top of the report. For example, a block displaying “Hot forums”, or something more complex like load balancing when there is lot of activity in the forums or quiz.&lt;br /&gt;
&lt;br /&gt;
== Usage scenarios ==&lt;br /&gt;
&lt;br /&gt;
* Send notification when more than X posts in any forum are made in a given course in Y minutes.&lt;br /&gt;
* Send notification when assignment is submitted in their course.&lt;br /&gt;
* Send notification (to admin) when a course is deleted.&lt;br /&gt;
* Send notification  (to students) that a particular activity has been updated.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Event 2]]&lt;br /&gt;
* Moodlerooms developed a &amp;quot;[http://kb.moodlerooms.com/article/81/administrator Personalized Learning Designer]&amp;quot; that has some of these features (mostly for individual students only).&lt;br /&gt;
* Real time means “as soon as possible” - this depends on the cron configuration of the site. (For further information refer to [[https://docs.moodle.org/dev/Task_API#Adhoc_task_usage Adhoc tasks]])&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Event_Monitor_specification&amp;diff=45098</id>
		<title>Event Monitor specification</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Event_Monitor_specification&amp;diff=45098"/>
		<updated>2014-06-03T09:15:25Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: Add more info and some cleanup&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Project&lt;br /&gt;
|name = Event Monitor&lt;br /&gt;
|state = Specification/Prototyping&lt;br /&gt;
|tracker = MDL-45758&lt;br /&gt;
|discussion = https://moodle.org/mod/forum/discuss.php&lt;br /&gt;
|assignee = Ankit, Simey&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Work in progress}}&lt;br /&gt;
&lt;br /&gt;
The Event Monitor report will allow users to select events and receive notifications in real time* when the chosen event happens. &lt;br /&gt;
This report will be built on top of the new [[Events_2]] infrastructure. &lt;br /&gt;
&lt;br /&gt;
== How it works ==&lt;br /&gt;
* The user or site admin creates a specific set of “rules” that can be subscribed to.&lt;br /&gt;
* Each rule defines a event and frequency parameters.&lt;br /&gt;
* The users select the rules they are interested in and then subscribe to it at course level for a specific module or all modules.&lt;br /&gt;
* Whenever the event occurs in the system , in the frequency specified in the rule, a message is sent out to all the subscribers.&lt;br /&gt;
* Since we would be using Moodle messaging system to send out these notifications, it can be delivered in any format supported by Moodle (Mobile notification, popup, email etc)&lt;br /&gt;
* There would be some default rules that would be shipped with the report, that users can subscribe to straight away.&lt;br /&gt;
&lt;br /&gt;
=== User interface mock-ups ===&lt;br /&gt;
&lt;br /&gt;
==== List rules ====&lt;br /&gt;
&lt;br /&gt;
This is the main page of Event Monitor where users can see list of rules. This page lets you subscribe/un-subscribe to the rules. And this also lets you manage the rules if you have appropriate permissions (create/edit/delete/copy)&lt;br /&gt;
&lt;br /&gt;
This is roughly how the page would look like:-&lt;br /&gt;
[[File:listrules.png]]&lt;br /&gt;
&lt;br /&gt;
==== Add/Edit a rule ====&lt;br /&gt;
&lt;br /&gt;
This is the form where users can create a new rule, customise the filters (frequency and time) and personalise the notification message.&lt;br /&gt;
&lt;br /&gt;
[[File:addrule.png]]&lt;br /&gt;
&lt;br /&gt;
=== A specific example ===&lt;br /&gt;
Consider the case when you want to be notified when active discussions are going on in the forums.&lt;br /&gt;
&lt;br /&gt;
The figure above show the creation of a new rule called &#039;My Student Discussions&#039;, which is set to monitor &#039;Post Created event&#039; on &#039;Forum Module&#039;. &lt;br /&gt;
&lt;br /&gt;
In this case, any user subscribed to this rule will receive notifications whenever &#039;30 posts are created in 60 minutes&#039; on the forum they are subscribed to. &lt;br /&gt;
&lt;br /&gt;
The notification will contain the customised message as configured in the rule.&lt;br /&gt;
&lt;br /&gt;
== Benefits ==&lt;br /&gt;
&lt;br /&gt;
* Real time monitoring of events happening in Moodle. &lt;br /&gt;
* Admin can be notified when there is heavy activity on the site or they can monitor specific actions that interests them (ex:- course delete).&lt;br /&gt;
* Notification can be sent straight to users&#039; mobile if needed to inform them of situation that needs their immediate attention.&lt;br /&gt;
* The report would be designed to trigger an event when a given subscription criteria are met. This will allow developers to build really powerful scripts on top of the report. For example, say a block displaying “Hot forums”, or something more complex like load balancing when there is lot of activity in the forum or quiz.&lt;br /&gt;
&lt;br /&gt;
== Usage scenarios ==&lt;br /&gt;
&lt;br /&gt;
* Send notification when more than X posts in any forum are made in a given course in Y minutes.&lt;br /&gt;
* Send notification when assignment is submitted in their course.&lt;br /&gt;
* Send notification (to admin) when a course is deleted.&lt;br /&gt;
* Send notification  (to students) that a particular activity has been updated.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Event 2]]&lt;br /&gt;
* Moodlerooms developed a &amp;quot;[http://kb.moodlerooms.com/article/81/administrator Personalized Learning Designer]&amp;quot; that has some of these features (mostly for individual students only).&lt;br /&gt;
* Real time means “as soon as possible” - this depends on the cron configuration of the site.&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Task_API&amp;diff=44936</id>
		<title>Task API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Task_API&amp;diff=44936"/>
		<updated>2014-05-26T03:26:58Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* Caches */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.7}}&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Task&lt;br /&gt;
|state = Integrated&lt;br /&gt;
|tracker = MDL-25505&lt;br /&gt;
|discussion = https://moodle.org/mod/forum/discuss.php?d=229139&lt;br /&gt;
|assignee = Damyon&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
= Tasks =&lt;br /&gt;
&lt;br /&gt;
A task is a unit of work that needs to be done later. Good uses for tasks:&lt;br /&gt;
&lt;br /&gt;
* Run a slow operation in the background&lt;br /&gt;
* Run a maintenance task on a regular schedule&lt;br /&gt;
&lt;br /&gt;
In general any operation that takes more than a few seconds should be a candidate for a task.&lt;br /&gt;
&lt;br /&gt;
= Benefits =&lt;br /&gt;
&lt;br /&gt;
* Better user experience (give them feedback immediately, that their task has been queued)&lt;br /&gt;
* Prevent browser timeouts&lt;br /&gt;
* Better performance for clusters (tasks can be run on separate, non-webserving cluster node, tasks can run in parallel)&lt;br /&gt;
* Failed tasks will be retried&lt;br /&gt;
* A better user interface will prevent users queuing multiple tasks, because they thought it had &amp;quot;got stuck&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
= Types of task =&lt;br /&gt;
&lt;br /&gt;
== Scheduled tasks ==&lt;br /&gt;
Scheduled tasks are tasks that will run on a regular schedule. A default schedule can be set, but admins have the ability to change the default schedule if required. Note: Tasks will only run as often as cron is run in Moodle. In 2.7 it is recommended to run cron once per minute to get the benefit from the new task scheduling (don&#039;t worry - it will do much less work each time it runs).&lt;br /&gt;
&lt;br /&gt;
== Adhoc tasks ==&lt;br /&gt;
Adhoc tasks are for when you need to queue something to run in the background immediately. Adhoc tasks can contain custom data, specific to this specific instance of the task.&lt;br /&gt;
&lt;br /&gt;
= Usage =&lt;br /&gt;
&lt;br /&gt;
== Scheduled task usage ==&lt;br /&gt;
&lt;br /&gt;
Scheduled tasks are created by subclassing \core\task\scheduled_task. They also require an entry in &amp;quot;db/tasks.php&amp;quot; for your plugin.&lt;br /&gt;
&lt;br /&gt;
1. Create a subclass of \core\task\scheduled_task that contains your code to run in a schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class cut_my_toe_nails extends \core\task\scheduled_task {      &lt;br /&gt;
    public function get_name() {&lt;br /&gt;
        // Shown in admin screens&lt;br /&gt;
        return get_string(&#039;cutmytoenails&#039;, &#039;mod_hygene&#039;);&lt;br /&gt;
    }&lt;br /&gt;
                                                                     &lt;br /&gt;
    public function execute() {       &lt;br /&gt;
        // apply fungus cream&lt;br /&gt;
        // apply chainsaw&lt;br /&gt;
        // apply olive oil&lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
} &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
2. Create entry in db/tasks.php for your plugin:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$tasks = array(                                                                                                                     &lt;br /&gt;
    array(                                                                                                                          &lt;br /&gt;
        &#039;classname&#039; =&amp;gt; &#039;mod_hygene\task\cut_my_toe_nails&#039;,                                                                            &lt;br /&gt;
        &#039;blocking&#039; =&amp;gt; 0,                                                                                                            &lt;br /&gt;
        &#039;minute&#039; =&amp;gt; &#039;*&#039;,                                                                                                            &lt;br /&gt;
        &#039;hour&#039; =&amp;gt; &#039;*&#039;,                                                                                                              &lt;br /&gt;
        &#039;day&#039; =&amp;gt; &#039;*&#039;,                                                                                                               &lt;br /&gt;
        &#039;dayofweek&#039; =&amp;gt; &#039;*&#039;,                                                                                                         &lt;br /&gt;
        &#039;month&#039; =&amp;gt; &#039;1,6&#039;                                                                                                              &lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The field required in the db/tasks.php file are:&lt;br /&gt;
* classname - the fully namespaced classname of your task. This needs to comply with the autoloading rules. &lt;br /&gt;
* blocking - if this is set to 1, no other scheduled task will run at the same time as this task. Do not set this to 1 unless you really need it as it will impact the performance of the task queue.&lt;br /&gt;
* minute, hour, day, dayofweek, month - This is the default schedule for running the task. The syntax matches the syntax of unix cron. &lt;br /&gt;
=== Cron syntax examples ===&lt;br /&gt;
* day - Day of month field for task schedule. &lt;br /&gt;
** &amp;quot;*&amp;quot; - Every day&lt;br /&gt;
** &amp;quot;*/2&amp;quot; - Every 2nd day&lt;br /&gt;
** &amp;quot;1&amp;quot; - The first of every month&lt;br /&gt;
** &amp;quot;1,15&amp;quot; - The first and fifteenth of every month&lt;br /&gt;
* dayofweek - Day of week field for task schedule.&lt;br /&gt;
** &amp;quot;*&amp;quot; - Every day&lt;br /&gt;
** &amp;quot;0&amp;quot; - Every Sunday&lt;br /&gt;
** &amp;quot;6&amp;quot; - Every Saturday&lt;br /&gt;
** &amp;quot;1,5&amp;quot; - Every Monday and Friday&lt;br /&gt;
* hour - Hour field for task schedule.&lt;br /&gt;
** &amp;quot;*&amp;quot; - Every hour&lt;br /&gt;
** &amp;quot;*/2&amp;quot; - Every 2 hours&lt;br /&gt;
** &amp;quot;2-10&amp;quot; - Every hour from 2am until 10am (inclusive)&lt;br /&gt;
** &amp;quot;2,6,9&amp;quot; - 2am, 6am and 9am&lt;br /&gt;
* minute - Minute field for task schedule.&lt;br /&gt;
** &amp;quot;*&amp;quot; - Every minute&lt;br /&gt;
** &amp;quot;*/5&amp;quot; - Every 5 minutes&lt;br /&gt;
** &amp;quot;2-10&amp;quot; - Every minute between 2 and 10 minutes past the hour (inclusive)&lt;br /&gt;
** &amp;quot;2,6,9&amp;quot; - 2, 6 and 9 minutes past the hour&lt;br /&gt;
* month - Month field for task schedule.&lt;br /&gt;
** &amp;quot;*&amp;quot; - Every month&lt;br /&gt;
** &amp;quot;*/2&amp;quot; - Every second month&lt;br /&gt;
** &amp;quot;1&amp;quot; - Every January&lt;br /&gt;
** &amp;quot;1,5&amp;quot; - Every January and May&lt;br /&gt;
&lt;br /&gt;
== Adhoc task usage ==&lt;br /&gt;
&lt;br /&gt;
This is even easier than scheduled tasks. &lt;br /&gt;
&lt;br /&gt;
1. Create a subclass of \core\task\adhoc_task that contains your code to run in the background.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
class take_over_the_world extends \core\task\adhoc_task {                                                                           &lt;br /&gt;
    public function execute() {       &lt;br /&gt;
        // gain 100,000,000 friends on facebook.&lt;br /&gt;
        // crash the stock market.&lt;br /&gt;
        // run for president.&lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
} &lt;br /&gt;
                                      &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Create an instance of the task and queue it (adding custom data if required).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   // create the instance&lt;br /&gt;
   $domination = new take_over_the_world();&lt;br /&gt;
   // set blocking if required (it probably isn&#039;t)&lt;br /&gt;
   // $domination-&amp;gt;set_blocking(true);&lt;br /&gt;
   // add custom data&lt;br /&gt;
   $domination-&amp;gt;set_custom_data(array(&lt;br /&gt;
       &#039;plansfortomorrownight&#039; =&amp;gt; &#039;The same thing we do every night, Pinky!&#039;&lt;br /&gt;
   ));&lt;br /&gt;
&lt;br /&gt;
   // queue it&lt;br /&gt;
   \core\task\manager::queue_adhoc_task($domination);&lt;br /&gt;
&lt;br /&gt;
   // profit&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. There is no 3.&lt;br /&gt;
&lt;br /&gt;
== Failures ==&lt;br /&gt;
A task, either scheduled or adhoc can sometimes fail. An example would be updating an RSS field when the network is temporarily down. This is handled by the task system automatically - all the failing task needs to do is throw an exception. The task will be retried after 1 minute. If the task keeps failing, the retry algorithm will add more time between each successive attempts up to a max of 24 hours.&lt;br /&gt;
&lt;br /&gt;
== Caches ==&lt;br /&gt;
There is one special case that needs to be considered with this new system. If a particular scheduled or adhoc task runs for a long time and updates many DB records - particularly something related to enrolment - the next task in the queue may suffer because various API&#039;s in moodle use static caching to speed up requests, but assume that the data will not change much between the start and end of the request. In this case, you can force the cron to exit after running a task that has done many DB updates. The next cron will be run in the next minute, and will have all static caches cleared because it&#039;s a new process. To do this call \core\task\manager::clear_static_caches();&lt;br /&gt;
&lt;br /&gt;
== Security ==&lt;br /&gt;
When scheduling a task to run in the background - or creating a scheduled task, the task will run in the context of the cron user (see &amp;quot;cron_setup_user()&amp;quot;). If you need to perform access checks in your background task, you should pass the userid/context in custom_data and then pass that userid to the access check functions (&amp;quot;require_capability(&#039;moodle/course:update&#039;,  $context, $userid)&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Legacy cron ==&lt;br /&gt;
The older syntax of cron.php or modname_cron() is still supported - but is not as good as this new API. This is because:&lt;br /&gt;
* the legacy cron functions run serially - a long running cron in one plugin will hold up the other plugins crons&lt;br /&gt;
* the legacy cron functions are fragile - a failure in one cron in one plugin will prevent the cron in other functions from running at all&lt;br /&gt;
* the scheduling cannot be changed by admins&lt;br /&gt;
&lt;br /&gt;
= For Admins =&lt;br /&gt;
Admins have a new screen where they can adjust the schedules for any scheduled task. They can also reset any scheduled task to it&#039;s default schedule.&lt;br /&gt;
[[File:task_admin_screenshot.png|Screenshot of admin page]]&lt;br /&gt;
&lt;br /&gt;
= Specification =&lt;br /&gt;
The specification for this feature is here: https://docs.moodle.org/dev/Scheduled_Tasks_Proposal&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Writing_log_managers&amp;diff=44774</id>
		<title>Writing log managers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Writing_log_managers&amp;diff=44774"/>
		<updated>2014-05-12T06:17:17Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: Created page with &amp;quot;{{Moodle 2.7}} &amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt; This is an advanced developer documenation.&amp;lt;/p&amp;gt; For majority of sites the log manager provided with Moodle standard distribution should be suff...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.7}}&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt; This is an advanced developer documenation.&amp;lt;/p&amp;gt;&lt;br /&gt;
For majority of sites the log manager provided with Moodle standard distribution should be sufficient, and you would rarely need to implement a new log manager. Think really hard before you decide to go for a new logmanager, You would need it only if you want to radically change the behaviour of how logs work with Moodle.&lt;br /&gt;
&lt;br /&gt;
So you decided to go for a new logmanager. Now let us get started with implementing it:-&lt;br /&gt;
&lt;br /&gt;
= You shall not pass =&lt;br /&gt;
Writing a logmanager needs advanced understanding of how certain things work in Moodle. Please make sure you are fully familiar with following concepts and their implementation in Moodle, before moving forward:-&lt;br /&gt;
* [[Automatic class loading]]&lt;br /&gt;
* Namespaces&lt;br /&gt;
* [[Event 2|Events API]]&lt;br /&gt;
* [[Logging 2]]&lt;br /&gt;
* [[Migrating logging calls in plugins]]&lt;br /&gt;
* [[Migrating reports accessing logs]]&lt;br /&gt;
&lt;br /&gt;
= Steps to write a log manager = &lt;br /&gt;
Although it is not required, but the best way to add a logmanager is by creating a new admin tool. Let us call this as &#039;mylog&#039; admin tool.&lt;br /&gt;
&lt;br /&gt;
== Let us get started ==&lt;br /&gt;
The first thing needed is a manager class that implements the interface \core\log\manager . Let us call our class as tool_mylog\log\manager which would be located in admin/tool/mylog/classes/log/manager.php&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
namespace tool_mylog\log;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
class manager implements \core\log\manager {&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Return list of available log readers.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $interface All returned readers must implement this interface.&lt;br /&gt;
     *&lt;br /&gt;
     * @return \core\log\reader[]&lt;br /&gt;
     */&lt;br /&gt;
    public function get_readers($interface = null) {&lt;br /&gt;
           // code for fetching instances of readers installed in the site.&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Dispose all initialised stores.&lt;br /&gt;
     * @return void&lt;br /&gt;
     */&lt;br /&gt;
    public function dispose() {&lt;br /&gt;
         // Dispose off all instances of stores.&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * For a given report, returns a list of log stores that are supported.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $component component.&lt;br /&gt;
     *&lt;br /&gt;
     * @return false|array list of logstores that support the given report. It returns false if the given $component doesn&#039;t&lt;br /&gt;
     *      require logstores.&lt;br /&gt;
     */&lt;br /&gt;
    public function get_supported_logstores($component) {&lt;br /&gt;
           // You can use the callback report_x_supports_logstore() here&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Besides those methods you might also want apis to manage writers and potentially a process to write logs using those writers. There are no core limitation on how to implement that.&lt;br /&gt;
&lt;br /&gt;
== I am watching you ==&lt;br /&gt;
So we got our manager class up, but it is useless unless it monitors events. We need to setup an observer for monitoring the events we are interesed in. For this we first create a class \tool_log\mylog\observer located in admin/tool/mylog/classes/log/observer.php&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace tool_log\log;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
class observer {&lt;br /&gt;
    /**&lt;br /&gt;
     * Redirect all events to this log manager, but only if this&lt;br /&gt;
     * log manager is actually used.&lt;br /&gt;
     *&lt;br /&gt;
     * @param \core\event\base $event&lt;br /&gt;
     */&lt;br /&gt;
    public static function store(\core\event\base $event) {&lt;br /&gt;
        $logmanager = get_log_manager();&lt;br /&gt;
        // Process the event.&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Once we got the observer in place, now we need to tell Moodle about it. We do this by adding an entry in admin/tool/mylog/db/events.php&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$observers = array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;eventname&#039; =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;callback&#039;  =&amp;gt; &#039;\tool_mylog\log\observer::store&#039;,&lt;br /&gt;
        &#039;internal&#039;  =&amp;gt; false, // This means that we get events only after transaction commit.&lt;br /&gt;
        &#039;priority&#039;  =&amp;gt; 1000,&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
== Do you know me? == &lt;br /&gt;
Now we need to tell Moodle about our logmanager, so it doesn&#039;t go looking for the standard manager. We do this by adding the following line to the config.php&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
define(&#039;LOG_MANAGER_CLASS&#039;, &#039;\tool_mylog\log\manager&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_2.7_release_notes&amp;diff=44566</id>
		<title>Moodle 2.7 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_2.7_release_notes&amp;diff=44566"/>
		<updated>2014-04-29T08:53:26Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* Interface */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
&lt;br /&gt;
Release date: Expected in May 2014&lt;br /&gt;
 &lt;br /&gt;
==Server requirements==&lt;br /&gt;
&lt;br /&gt;
These are just minimums.  We recommend keeping all your software updated. &lt;br /&gt;
&lt;br /&gt;
* Moodle upgrade:  Moodle 2.2 or later (if upgrading from earlier versions, you must upgrade to 2.2.11 as a first step)&lt;br /&gt;
* Minimum Database versions: &lt;br /&gt;
** PostgreSQL 9.1&lt;br /&gt;
** MySQL 5.5.31&lt;br /&gt;
** MariaDB 5.5.31&lt;br /&gt;
** MSSQL 2008, or &lt;br /&gt;
** Oracle 10.2&lt;br /&gt;
* Minimum PHP version: PHP 5.4.4 (always use latest PHP 5.4.x or 5.5.x on Windows - http://windows.php.net/download/)&lt;br /&gt;
*Ghostscript should be installed for pdf annotation.&lt;br /&gt;
&lt;br /&gt;
==Browser requirements==&lt;br /&gt;
&lt;br /&gt;
* Recent Google Chrome, recent Mozilla Firefox, Safari 6 or later, Internet Explorer 9 or later (IE 10 required for drag and drop of files from outside the browser into Moodle)&lt;br /&gt;
&lt;br /&gt;
==Before you upgrade==&lt;br /&gt;
&lt;br /&gt;
Questions: In Moodle 2.1 there was a major upgrade to questions. As explained in [https://docs.moodle.org/21/en/Upgrading_to_Moodle_2.1#Planning_the_question_engine_upgrade the upgrade documentation for that version], it was possible to delay parts of the database upgrade to be run later. Before you upgrade to Moodle 2.7, this upgrade must be completed.  You can check for this by looking at the bottom of the the [[:en:Environment]] check page in your site.&lt;br /&gt;
&lt;br /&gt;
Themes: &lt;br /&gt;
Several core themes have been removed from Moodle 2.7 (see MDL-43784).  If you wish to continue using one of these themes then it&#039;s best to reinstall it explicitly *BEFORE* running the upgrade.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;After burner&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_afterburner plugins db] [https://github.com/moodlehq/moodle-theme_afterburner github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Anomaly&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_anomaly plugins db] [https://github.com/moodlehq/moodle-theme_anomaly github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Arialist&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_arialist plugins db] [https://github.com/moodlehq/moodle-theme_arialist github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Binarius&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_binarius plugins db] [https://github.com/moodlehq/moodle-theme_binarius github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Boxxie&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_boxxie plugins db] [https://github.com/moodlehq/moodle-theme_boxxie github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Brick&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_brick plugins db] [https://github.com/moodlehq/moodle-theme_brick github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Formal_white&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_formal_white plugins db] [https://github.com/andreabix/moodle-theme_formal_white github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Form factor&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_formfactor plugins db] [https://github.com/moodlehq/moodle-theme_formfactor github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Fusion&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_fusion plugins db] [https://github.com/moodlehq/moodle-theme_fusion github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Leatherbound&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_leatherbound plugins db] [https://github.com/moodlehq/moodle-theme_leatherbound github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Magazine&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_magazine plugins db] [https://github.com/moodlehq/moodle-theme_magazine github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Nimble&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_nimble plugins db] [https://github.com/moodlehq/moodle-theme_nimble github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Nonzero&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_nonzero plugins db] [https://github.com/moodlehq/moodle-theme_nonzero github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Overlay&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_overlay plugins db] [https://github.com/moodlehq/moodle-theme_overlay github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Serenity&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_serenity plugins db] [https://github.com/moodlehq/moodle-theme_serenity github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Sky high&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_sky_high plugins db] [https://github.com/moodlehq/moodle-theme_sky_high github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Splash&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_splash plugins db] [https://github.com/moodlehq/moodle-theme_splash github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Standard&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_standard plugins db] [https://github.com/moodlehq/moodle-theme_standard github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Standard old&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_standardold plugins db] [https://github.com/moodlehq/moodle-theme_standardold github]&lt;br /&gt;
&lt;br /&gt;
==Headline core features==&lt;br /&gt;
&lt;br /&gt;
===Interface===&lt;br /&gt;
* Atto - our new Moodle editor, tightly integrated in Moodle and focussing on usability and accessibility (TinyMCE still available as an option)&lt;br /&gt;
* Themes clean-up - Moodle is focussed on Bootstrap and improved responsive design.  Clean is now the default theme and most other old themes have been removed from core (still available from Plugins database).  Many small improvements have been made all through the interface.&lt;br /&gt;
* More - a completely new theme called More that provides easy configuration though the UI while retaining the power of LESS and Bootstrap.&lt;br /&gt;
* Improved conditional activities - complex boolean combinations now supported, plus plugin conditions and a better interface.  And faster!&lt;br /&gt;
* Reports - User interface for loglive and log reports has been imporved with more information and filtering support (MDL-43682 and MDL-43681).&lt;br /&gt;
&lt;br /&gt;
===Platform===&lt;br /&gt;
* Logging - a new logging subsystem with plugins allowing Moodle logs to be very detailed and external.  Many new events have been added which developers can take advantage of. MDL-37658  These advancements will support better analytics as well as things like TinCan.&lt;br /&gt;
* Performance - many improvements that improve overall performance in most cases&lt;br /&gt;
* Tasks - an improved scheduling system (like Unix cron) that allows precise scheduling of tasks even on complex clustered servers&lt;br /&gt;
&lt;br /&gt;
===Long-term support (LTS) until June 2017===&lt;br /&gt;
&lt;br /&gt;
Most of our releases receive 1 year of backported general bug fixes and 1.5 years of security and dataloss fixes from Moodle HQ.  Due to popular demand, we are committing to giving Moodle 2.7 extended support of &#039;&#039;&#039;&#039;3 years security and data loss fixes&#039;&#039;&#039;&#039; (that&#039;s an extra 1.5 years support).&lt;br /&gt;
&lt;br /&gt;
If you are stuck on an old version then this might be the perfect time to upgrade!&lt;br /&gt;
&lt;br /&gt;
==Details==&lt;br /&gt;
&lt;br /&gt;
===Quiz &amp;amp; Question bank===&lt;br /&gt;
&lt;br /&gt;
* Quiz reports improved. MDL-41727&lt;br /&gt;
** Responses from all tries are available for analysis when using or &amp;quot;Adaptive&amp;quot;, &amp;quot;Interactive with multiple tries&amp;quot; or similar behaviours.&lt;br /&gt;
** Break-down by question variant, for question types like Calculated, STACK and Variable-numeric, which one question can have different random variants.&lt;br /&gt;
** Progress bar during long calculations to prevent time-outs.&lt;br /&gt;
** Low-level calculation code moved into the question component, where it could potentially be reused by other activities.&lt;br /&gt;
** Much more automated testing of this complex area of code.&lt;br /&gt;
* Some minor improvements to the usability of the question bank - Some of MDL-40987&lt;br /&gt;
** To duplicate a question, you now start by clicking the x2 icon, like for activities. MDL-33653&lt;br /&gt;
** The various different ways to move questions in the question bank have been rationalised. MDL-33839&lt;br /&gt;
** There is now a &#039;Save changes and continue editing&#039; button when editing questions. Useful when you are working on a complex question with the preview open in another window. MDL-33653&lt;br /&gt;
* New plugin point, so that plugins can add columns to the question bank, or new search conditions. MDL-40313 &amp;amp; MDL-40457&lt;br /&gt;
* Essay questions can now require an attachment, with the text optional, rather than the other way around. MDL-39756&lt;br /&gt;
* Random short-answer matching question type brought back from the dead. (This was in stable branches, but worth mentioning again.) MDL-27414&lt;br /&gt;
&lt;br /&gt;
===Assignment===&lt;br /&gt;
&lt;br /&gt;
The old Assignment (2.2) module has been removed from core (MDL-33952). It has been replaced by a stub to support transparently remapping urls and restoring course backups from the old module to the new one. &lt;br /&gt;
&lt;br /&gt;
If you are still using the old assignment module - all instances of the old assignment module will be hidden after upgrading to Moodle 2.7. Once the upgrade tool is run on those assignments they will become visible again. &lt;br /&gt;
&lt;br /&gt;
It is recommended to upgrade, and then convert any remaining assignments because logic has been added to the assignment upgrade code for Moodle 2.7 to transparently map urls from the old assignment module to the new one.&lt;br /&gt;
&lt;br /&gt;
If you really, really need to keep using the old module, you should update the code to Moodle 2.7, and then replace the &amp;quot;mod/assignment&amp;quot; folder with the one from the plugins database before completing the upgrade.&lt;br /&gt;
&lt;br /&gt;
A new capability &#039;&#039;mod/assign:editothersubmission&#039;&#039; can be given to teachers to allow them to edit or delete student submissions.&lt;br /&gt;
&lt;br /&gt;
A checkbox &#039;Notify students&#039; is available to control when to send feedback during the grading process.&lt;br /&gt;
&lt;br /&gt;
Teachers can comment directly on student&#039;s work on online text assignments MDL-34432&lt;br /&gt;
&lt;br /&gt;
===Cron===&lt;br /&gt;
&lt;br /&gt;
Cron has received a major update and now has support for both scheduled and adhoc tasks - MDL-25499.&lt;br /&gt;
The benefits of these changes are:&lt;br /&gt;
* The schedule for every task can be configured by the admin&lt;br /&gt;
* Tasks can run in parallel&lt;br /&gt;
* Cron processes use locking to prevent the same task running at the same time by different processes&lt;br /&gt;
&lt;br /&gt;
A result of this is that cron can be run much more often, which means (for example) forum posts can be sent out sooner. Admins can keep cron running at the same schedule as before, but it is strongly recommended that they increase the frequency of running cron to at least once per minute.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Developer Notes ==&lt;br /&gt;
&lt;br /&gt;
=== API changes ===&lt;br /&gt;
* Reports: Reports that use log table, should be updated to use the new logging frame work. Old reports will continue to work as before as long as legacy logging is enabled in the site. See [[Migrating log access in reports]] for details.&lt;br /&gt;
&lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 2.7]]&lt;br /&gt;
&lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 2.7]]&lt;br /&gt;
[[es:Notas de Moodle 2.7]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_2.7_release_notes&amp;diff=44565</id>
		<title>Moodle 2.7 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_2.7_release_notes&amp;diff=44565"/>
		<updated>2014-04-29T08:49:06Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* API changes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
&lt;br /&gt;
Release date: Expected in May 2014&lt;br /&gt;
 &lt;br /&gt;
==Server requirements==&lt;br /&gt;
&lt;br /&gt;
These are just minimums.  We recommend keeping all your software updated. &lt;br /&gt;
&lt;br /&gt;
* Moodle upgrade:  Moodle 2.2 or later (if upgrading from earlier versions, you must upgrade to 2.2.11 as a first step)&lt;br /&gt;
* Minimum Database versions: &lt;br /&gt;
** PostgreSQL 9.1&lt;br /&gt;
** MySQL 5.5.31&lt;br /&gt;
** MariaDB 5.5.31&lt;br /&gt;
** MSSQL 2008, or &lt;br /&gt;
** Oracle 10.2&lt;br /&gt;
* Minimum PHP version: PHP 5.4.4 (always use latest PHP 5.4.x or 5.5.x on Windows - http://windows.php.net/download/)&lt;br /&gt;
*Ghostscript should be installed for pdf annotation.&lt;br /&gt;
&lt;br /&gt;
==Browser requirements==&lt;br /&gt;
&lt;br /&gt;
* Recent Google Chrome, recent Mozilla Firefox, Safari 6 or later, Internet Explorer 9 or later (IE 10 required for drag and drop of files from outside the browser into Moodle)&lt;br /&gt;
&lt;br /&gt;
==Before you upgrade==&lt;br /&gt;
&lt;br /&gt;
Questions: In Moodle 2.1 there was a major upgrade to questions. As explained in [https://docs.moodle.org/21/en/Upgrading_to_Moodle_2.1#Planning_the_question_engine_upgrade the upgrade documentation for that version], it was possible to delay parts of the database upgrade to be run later. Before you upgrade to Moodle 2.7, this upgrade must be completed.  You can check for this by looking at the bottom of the the [[:en:Environment]] check page in your site.&lt;br /&gt;
&lt;br /&gt;
Themes: &lt;br /&gt;
Several core themes have been removed from Moodle 2.7 (see MDL-43784).  If you wish to continue using one of these themes then it&#039;s best to reinstall it explicitly *BEFORE* running the upgrade.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;After burner&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_afterburner plugins db] [https://github.com/moodlehq/moodle-theme_afterburner github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Anomaly&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_anomaly plugins db] [https://github.com/moodlehq/moodle-theme_anomaly github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Arialist&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_arialist plugins db] [https://github.com/moodlehq/moodle-theme_arialist github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Binarius&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_binarius plugins db] [https://github.com/moodlehq/moodle-theme_binarius github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Boxxie&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_boxxie plugins db] [https://github.com/moodlehq/moodle-theme_boxxie github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Brick&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_brick plugins db] [https://github.com/moodlehq/moodle-theme_brick github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Formal_white&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_formal_white plugins db] [https://github.com/andreabix/moodle-theme_formal_white github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Form factor&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_formfactor plugins db] [https://github.com/moodlehq/moodle-theme_formfactor github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Fusion&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_fusion plugins db] [https://github.com/moodlehq/moodle-theme_fusion github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Leatherbound&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_leatherbound plugins db] [https://github.com/moodlehq/moodle-theme_leatherbound github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Magazine&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_magazine plugins db] [https://github.com/moodlehq/moodle-theme_magazine github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Nimble&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_nimble plugins db] [https://github.com/moodlehq/moodle-theme_nimble github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Nonzero&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_nonzero plugins db] [https://github.com/moodlehq/moodle-theme_nonzero github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Overlay&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_overlay plugins db] [https://github.com/moodlehq/moodle-theme_overlay github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Serenity&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_serenity plugins db] [https://github.com/moodlehq/moodle-theme_serenity github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Sky high&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_sky_high plugins db] [https://github.com/moodlehq/moodle-theme_sky_high github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Splash&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_splash plugins db] [https://github.com/moodlehq/moodle-theme_splash github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Standard&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_standard plugins db] [https://github.com/moodlehq/moodle-theme_standard github]&lt;br /&gt;
* &amp;lt;b style=&amp;quot;display:inline-block; min-width: 200px;&amp;quot;&amp;gt;Standard old&amp;lt;/b&amp;gt; [https://moodle.org/plugins/view.php?plugin=theme_standardold plugins db] [https://github.com/moodlehq/moodle-theme_standardold github]&lt;br /&gt;
&lt;br /&gt;
==Headline core features==&lt;br /&gt;
&lt;br /&gt;
===Interface===&lt;br /&gt;
* Atto - our new Moodle editor, tightly integrated in Moodle and focussing on usability and accessibility (TinyMCE still available as an option)&lt;br /&gt;
* Themes clean-up - Moodle is focussed on Bootstrap and improved responsive design.  Clean is now the default theme and most other old themes have been removed from core (still available from Plugins database).  Many small improvements have been made all through the interface.&lt;br /&gt;
* More - a completely new theme called More that provides easy configuration though the UI while retaining the power of LESS and Bootstrap.&lt;br /&gt;
* Improved conditional activities - complex boolean combinations now supported, plus plugin conditions and a better interface.  And faster!&lt;br /&gt;
&lt;br /&gt;
===Platform===&lt;br /&gt;
* Logging - a new logging subsystem with plugins allowing Moodle logs to be very detailed and external.  Many new events have been added which developers can take advantage of. MDL-37658  These advancements will support better analytics as well as things like TinCan.&lt;br /&gt;
* Performance - many improvements that improve overall performance in most cases&lt;br /&gt;
* Tasks - an improved scheduling system (like Unix cron) that allows precise scheduling of tasks even on complex clustered servers&lt;br /&gt;
&lt;br /&gt;
===Long-term support (LTS) until June 2017===&lt;br /&gt;
&lt;br /&gt;
Most of our releases receive 1 year of backported general bug fixes and 1.5 years of security and dataloss fixes from Moodle HQ.  Due to popular demand, we are committing to giving Moodle 2.7 extended support of &#039;&#039;&#039;&#039;3 years security and data loss fixes&#039;&#039;&#039;&#039; (that&#039;s an extra 1.5 years support).&lt;br /&gt;
&lt;br /&gt;
If you are stuck on an old version then this might be the perfect time to upgrade!&lt;br /&gt;
&lt;br /&gt;
==Details==&lt;br /&gt;
&lt;br /&gt;
===Quiz &amp;amp; Question bank===&lt;br /&gt;
&lt;br /&gt;
* Quiz reports improved. MDL-41727&lt;br /&gt;
** Responses from all tries are available for analysis when using or &amp;quot;Adaptive&amp;quot;, &amp;quot;Interactive with multiple tries&amp;quot; or similar behaviours.&lt;br /&gt;
** Break-down by question variant, for question types like Calculated, STACK and Variable-numeric, which one question can have different random variants.&lt;br /&gt;
** Progress bar during long calculations to prevent time-outs.&lt;br /&gt;
** Low-level calculation code moved into the question component, where it could potentially be reused by other activities.&lt;br /&gt;
** Much more automated testing of this complex area of code.&lt;br /&gt;
* Some minor improvements to the usability of the question bank - Some of MDL-40987&lt;br /&gt;
** To duplicate a question, you now start by clicking the x2 icon, like for activities. MDL-33653&lt;br /&gt;
** The various different ways to move questions in the question bank have been rationalised. MDL-33839&lt;br /&gt;
** There is now a &#039;Save changes and continue editing&#039; button when editing questions. Useful when you are working on a complex question with the preview open in another window. MDL-33653&lt;br /&gt;
* New plugin point, so that plugins can add columns to the question bank, or new search conditions. MDL-40313 &amp;amp; MDL-40457&lt;br /&gt;
* Essay questions can now require an attachment, with the text optional, rather than the other way around. MDL-39756&lt;br /&gt;
* Random short-answer matching question type brought back from the dead. (This was in stable branches, but worth mentioning again.) MDL-27414&lt;br /&gt;
&lt;br /&gt;
===Assignment===&lt;br /&gt;
&lt;br /&gt;
The old Assignment (2.2) module has been removed from core (MDL-33952). It has been replaced by a stub to support transparently remapping urls and restoring course backups from the old module to the new one. &lt;br /&gt;
&lt;br /&gt;
If you are still using the old assignment module - all instances of the old assignment module will be hidden after upgrading to Moodle 2.7. Once the upgrade tool is run on those assignments they will become visible again. &lt;br /&gt;
&lt;br /&gt;
It is recommended to upgrade, and then convert any remaining assignments because logic has been added to the assignment upgrade code for Moodle 2.7 to transparently map urls from the old assignment module to the new one.&lt;br /&gt;
&lt;br /&gt;
If you really, really need to keep using the old module, you should update the code to Moodle 2.7, and then replace the &amp;quot;mod/assignment&amp;quot; folder with the one from the plugins database before completing the upgrade.&lt;br /&gt;
&lt;br /&gt;
A new capability &#039;&#039;mod/assign:editothersubmission&#039;&#039; can be given to teachers to allow them to edit or delete student submissions.&lt;br /&gt;
&lt;br /&gt;
A checkbox &#039;Notify students&#039; is available to control when to send feedback during the grading process.&lt;br /&gt;
&lt;br /&gt;
Teachers can comment directly on student&#039;s work on online text assignments MDL-34432&lt;br /&gt;
&lt;br /&gt;
===Cron===&lt;br /&gt;
&lt;br /&gt;
Cron has received a major update and now has support for both scheduled and adhoc tasks - MDL-25499.&lt;br /&gt;
The benefits of these changes are:&lt;br /&gt;
* The schedule for every task can be configured by the admin&lt;br /&gt;
* Tasks can run in parallel&lt;br /&gt;
* Cron processes use locking to prevent the same task running at the same time by different processes&lt;br /&gt;
&lt;br /&gt;
A result of this is that cron can be run much more often, which means (for example) forum posts can be sent out sooner. Admins can keep cron running at the same schedule as before, but it is strongly recommended that they increase the frequency of running cron to at least once per minute.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Developer Notes ==&lt;br /&gt;
&lt;br /&gt;
=== API changes ===&lt;br /&gt;
* Reports: Reports that use log table, should be updated to use the new logging frame work. Old reports will continue to work as before as long as legacy logging is enabled in the site. See [[Migrating log access in reports]] for details.&lt;br /&gt;
&lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 2.7]]&lt;br /&gt;
&lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 2.7]]&lt;br /&gt;
[[es:Notas de Moodle 2.7]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Logging_2&amp;diff=44550</id>
		<title>Logging 2</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Logging_2&amp;diff=44550"/>
		<updated>2014-04-29T02:08:29Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* Mockups */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Project&lt;br /&gt;
|name = Logging stage 2&lt;br /&gt;
|state = Completed&lt;br /&gt;
|tracker = MDL-37658&lt;br /&gt;
|discussion = https://moodle.org/mod/forum/discuss.php?d=235318&lt;br /&gt;
|assignee = moodle.com BACKEND team&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
= Benefits of the new logging system =&lt;br /&gt;
A few benefits of the new logging system are :-&lt;br /&gt;
* allows for capturing of richer information from plugins/core about actions;&lt;br /&gt;
* provides control over how much information is logged;&lt;br /&gt;
* abstracts log writing and reading so logging can be scaled;&lt;br /&gt;
* lets you write/read logs from any external system by the use of logstore plugins;&lt;br /&gt;
* control how much logging history is kept; and&lt;br /&gt;
* support research, reporting and analytics.&lt;br /&gt;
&lt;br /&gt;
== Why is Logging an important topic? ==&lt;br /&gt;
&lt;br /&gt;
Logging is fundamental to research, reporting and analytics. &lt;br /&gt;
&lt;br /&gt;
Not much of new Moodle development is based on measured data.  We need to be able to:&lt;br /&gt;
* prove there is a problem and&lt;br /&gt;
* prove that a given change is an improvement.&lt;br /&gt;
&lt;br /&gt;
Logging data can be used by different Moodle users.&lt;br /&gt;
*Better data would allow researchers to study what happens in online teaching.&lt;br /&gt;
*Better data would give admins more feedback on how to run their site - both technically and process (please note this issue is not about profiling).&lt;br /&gt;
*Better data would give teachers better feedback to improve their teaching process.&lt;br /&gt;
*Better data would give students better feedback to improve their learning.&lt;br /&gt;
&lt;br /&gt;
We can&#039;t predict all forms of analysis that might happen in future.&lt;br /&gt;
* The logging system needs to be flexible in order to accommodate applications by these different users.&lt;br /&gt;
* The logging API needs to be constructed in a way that is possible to improve in future.&lt;br /&gt;
&lt;br /&gt;
== Problems with old logging ==&lt;br /&gt;
&lt;br /&gt;
The old logging infrastructure had a number of issues that were resolved by this project. A few of these are:-&lt;br /&gt;
&lt;br /&gt;
* Logging was added ad-hoc by developers and has spotty coverage.&lt;br /&gt;
* Some logged actions did not contain important information needed later.&lt;br /&gt;
* There were performance and scalability problems, such as:&lt;br /&gt;
** log tables were joined in many popular queries and were slow;&lt;br /&gt;
** all logs used to go to one standard moodle database table, which was not scalable;&lt;br /&gt;
** it was not possible to configure level of logging ; and&lt;br /&gt;
** it was not possible to disable logging completely.&lt;br /&gt;
&lt;br /&gt;
= Logging =&lt;br /&gt;
&lt;br /&gt;
The new [[Event 2|Events API]] introduced in Moodle 2.6 provides a notification mechanism and single collection point for actions within Moodle. The Events system also defines information about events that can be extended with additional information and functionality by core code and plugins, as needed.&lt;br /&gt;
&lt;br /&gt;
In order to capture events a logging API was specified, consisting of a number of plugin types.&lt;br /&gt;
&lt;br /&gt;
To transition from the old logging system to the new, work was required in a number of areas.&lt;br /&gt;
&lt;br /&gt;
* In places where we previously added information to &#039;the&#039; log table, we must instead generate a new event.&lt;br /&gt;
* The standard Moodle distribution now includes 2 simple DB logging storage plugin that will store events in new format (internal and external database)&lt;br /&gt;
* The original logging code and DB tables are available for full backwards compatibility for users of customised reports. It is possible to enable logging to the old {log} table if required.&lt;br /&gt;
* All standard reports have been upgraded to use the new logging system and uses logging retrieval plugin to access log information.&lt;br /&gt;
* Custom report plugins (add-ons) will be able to query the {log} table, but should ideally shift to the new logging system over time, so that sites are not forced to continue double logging.&lt;br /&gt;
&lt;br /&gt;
== Old log usage analysis ==&lt;br /&gt;
&lt;br /&gt;
See [[Logging_usage|this analysis]] to see log usage in Moodle 2.5 core code.&lt;br /&gt;
&lt;br /&gt;
== Example scenario ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Writing to the log&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# A student submits an assignment.&lt;br /&gt;
# An event is triggered by the Assignment module.&lt;br /&gt;
# The log manager plugin observes the event and determines if it is log-worthy depending on some admin settings.&lt;br /&gt;
# The log manager sends the event to all enabled log storage subplugins implementing \tool_log\log\writer. Storage plugins may decide to filter out some events based on their admin settings.&lt;br /&gt;
# The log store plugin(s) stores the event data optionally including extra information such as remote IP or original logged-in-as user id.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Reading from the log&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# A teacher opens activity report.&lt;br /&gt;
# Activity reports queries available log readers from the current log manager (implementing \core\log\manager).&lt;br /&gt;
# If there is more than one log reader (implementing \core\log\sql_select_reader) available they can select the source of data for the report.&lt;br /&gt;
# A teacher requests report of student assignment submissions.&lt;br /&gt;
# The report requests events from the log reader and displays them.&lt;br /&gt;
&lt;br /&gt;
== From event to report ==&lt;br /&gt;
&lt;br /&gt;
There are four steps of how event is captured, logged and potentially presented in a report. These steps are summarised in [[#Figure1|Figure 1]] below and can be described as follows.&lt;br /&gt;
&lt;br /&gt;
# Handling of events and filtering what needs to be logged. See interface \core\log\manager below.&lt;br /&gt;
# Storing the events data in the log storage (DB, filesystem, etc.). See interface \tool_log\log\writer below.&lt;br /&gt;
# Retrieving the data from log storage - each plugin implements some methods to query and extract logs back to Moodle. See interfaces \core\log\reader and \core\log\sql_reader below.&lt;br /&gt;
# Displaying the data in the report.&lt;br /&gt;
&lt;br /&gt;
One plugin may cover multiple steps. For example we expect that most of log writer plugins will also implement log reader. It is also possible to create a report that has built-in event handling, log writing and reading and report presentation (all four steps). Also external logging systems may not wish to allow log data they capture to be reported within Moodle, handling it through an external system, so they may not implement steps 3 and 4 at all.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Figure1&amp;quot; style=&amp;quot;text-align:center&amp;quot;&amp;gt;&lt;br /&gt;
[[File:logging_plugins_relation.png]]&lt;br /&gt;
&#039;&#039;&#039;Figure 1. Logging plugins relationship diagram&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The [[#Figure2|Figure 2]] below shows how the requests are made between user actions, plugins and core when:&lt;br /&gt;
&lt;br /&gt;
* configuring logging - which log writer plugins are enabled&lt;br /&gt;
* event occurs&lt;br /&gt;
* report - selecting log store&lt;br /&gt;
* viewing report&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Figure2&amp;quot; style=&amp;quot;text-align:center&amp;quot;&amp;gt;&lt;br /&gt;
[[Image:logging_sequence.png|logging_sequence.png]]&lt;br /&gt;
&#039;&#039;&#039;Figure 2. Logging plugins sequence diagram&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Public API ==&lt;br /&gt;
&lt;br /&gt;
This section describes all interfaces that need to be implemented by log manager and each log storage class.&lt;br /&gt;
&lt;br /&gt;
=== Reading API ===&lt;br /&gt;
* &#039;&#039;&#039;function \get_log_manager()&#039;&#039;&#039; - returns the current log manager if configured or some dummy instance otherwise, it uses the signleton pattern.&lt;br /&gt;
* &#039;&#039;&#039;interface \core\log\manager&#039;&#039;&#039; - log manager interface, in standard distribution implemented by \tool_log\log\manager and \core\log\dummy_manager&lt;br /&gt;
** public function get_readers($interface = null) returns the active storages implementing reader interface, returns array(classname =&amp;gt; storage instance, ...)&lt;br /&gt;
* &#039;&#039;&#039;interface \core\log\reader&#039;&#039;&#039; - general event reader&lt;br /&gt;
** public function get_name() - returns name of the log storage, this will be used when selection data source in reports.&lt;br /&gt;
** public function get_description() - some help for admins.&lt;br /&gt;
** public function is_logging() - is latest data available?&lt;br /&gt;
* &#039;&#039;&#039;interface \core\log\sql_select_reader&#039;&#039;&#039; extends \core\log\reader - general log storage that supports sql selects (or emulates them)&lt;br /&gt;
** public function get_events_select($selectwhere, array $params, $order, $limitfrom, $limitnum) - returns event object instances matching given parameters.&lt;br /&gt;
** public function get_events_select_count($selectwhere, array $params) - returns number of events that would be returned from get_events() with the same parameters.&lt;br /&gt;
*** $selectwhere is supposed to be a limited sql predicate.&lt;br /&gt;
*** The set of operators allowed in $selectwhere are :- =, &amp;lt;&amp;gt;, &amp;gt;, &amp;gt;=, &amp;lt;, &amp;lt;=&lt;br /&gt;
*** The set of keywords allowed in $selectwhere are :- IN, BETWEEN, LIKE, IS NULL, IS NOT NULL&lt;br /&gt;
*** Logical operators OR, AND&lt;br /&gt;
*** NOT operator&lt;br /&gt;
*** ( and ) brackets&lt;br /&gt;
*** ? and :named parameter placeholders &lt;br /&gt;
*** Use of anything besides the mentioned keywords/operators is strictly forbidden.&lt;br /&gt;
* &#039;&#039;&#039;interface \core\log\sql_internal_reader&#039;&#039;&#039; extends \core\log\reader - log storage that can expose data as read-only database view or table.&lt;br /&gt;
** public function get_internal_log_table_name() - returns database table or view; structure is described in phpdocs, it will include all columns defined by log_sql&lt;br /&gt;
&lt;br /&gt;
Reports are expected to use only the reading API. Please note that all non-sql readers need to somehow translate the $selectwhere SQL query syntax.&lt;br /&gt;
&lt;br /&gt;
When reports are searching for log readers they use the get_log_manager()-&amp;gt;get_readers($interface = null) where $interface is the name of reader interface that the report supports.&lt;br /&gt;
If there are multiple readers returned by the log manager, then the report is responsible for letting the user choose which storage to create the report on.&lt;br /&gt;
&lt;br /&gt;
=== Writing API ===&lt;br /&gt;
* &#039;&#039;&#039;interface \tool_log\log\store&#039;&#039;&#039; - must be implemented by each store subplugin.&lt;br /&gt;
** public function __construct(\tool_log\log\manager $manager) - no parameters, configuration is taken from admin settings.&lt;br /&gt;
** public function dispose() - called when reading/writing finished.&lt;br /&gt;
* &#039;&#039;&#039;interface \tool_log\log\writer&#039;&#039;&#039; extends \tool_log\log\store - interface indicating the log store may be used for writing.&lt;br /&gt;
** public function write(\core\event\base $event) - called from event observer defined in log manager.&lt;br /&gt;
&lt;br /&gt;
The writing API is defined in tool_log plugin, the log stores are defined as new subplugin of this plugin.&lt;br /&gt;
&lt;br /&gt;
Each log store plugin will be responsible for filtering of events, it may use standardised admin settings and filtering or decide to implement custom filtering.&lt;br /&gt;
&lt;br /&gt;
== Standard logging plugins ==&lt;br /&gt;
&lt;br /&gt;
Standard Moodle distribution will include four plugins.&lt;br /&gt;
&lt;br /&gt;
=== Logging management plugin (tool_log) ===&lt;br /&gt;
&lt;br /&gt;
Defines:&lt;br /&gt;
&lt;br /&gt;
  class \tool_log\log\manager implements \core\log\manager;&lt;br /&gt;
&lt;br /&gt;
The log manager is responsible for step 1 from [[#Figure1|Figure 1]] above. It allows admins to configure which log store subplugin is enabled and in which order they appear. The log store plugins are implemented as tool_log subplugins with class &amp;quot;store&amp;quot; in their namespace (\logstore_xxxx\log\store).&lt;br /&gt;
&lt;br /&gt;
The log manager registers a &#039;*&#039; event observer, this observer is external - it means that events are received only when database transactions are not in progress.&lt;br /&gt;
&lt;br /&gt;
=== Standard log storage plugin (logstore_standard) ===&lt;br /&gt;
&lt;br /&gt;
Defines:&lt;br /&gt;
&lt;br /&gt;
  class \logstore_standard\log\store implements \core\log\sql_internal_reader, \tool_log\log\writer;&lt;br /&gt;
&lt;br /&gt;
The name logstore_standard does not seem to be optimal - &#039;&#039;logstore_db&#039;&#039; is not allowed because it collides with standard /db/ subdirectory in plugins and &#039;&#039;logstore_database&#039;&#039; should be probably reserved for external database logging (to prevent any confusion).&lt;br /&gt;
&lt;br /&gt;
This log storage plugin is responsible for steps 2 and 3 from [[#Figure1|Figure 1]] above. It is the primary replacement for the former {log} table. The performance will be similar to former log table, but for smaller sites, this simple default will suffice.&lt;br /&gt;
&lt;br /&gt;
Each plugin decides how much data is kept, when it is deleted, etc.&lt;br /&gt;
&lt;br /&gt;
==== Storage settings ====&lt;br /&gt;
&lt;br /&gt;
Each storage plugin with writer interface is responsible for backlisting or filtering of events. Some of the examples of filtering that can done is as below:-&lt;br /&gt;
* Include guests actions (default &#039;&#039;Yes&#039;&#039;).&lt;br /&gt;
* Include log levels (default &#039;&#039;empty&#039;&#039;), accepts constants from [[Event_2#Level_property]].&lt;br /&gt;
* Include by CRUD (default &#039;&#039;empty&#039;&#039;), accepts C, R, U, and D.&lt;br /&gt;
* Include by component (default &#039;&#039;empty&#039;&#039;)&lt;br /&gt;
* Include by event name (default &#039;&#039;empty&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
=== External database log storage plugin (logstore_database) ===&lt;br /&gt;
&lt;br /&gt;
Defines:&lt;br /&gt;
&lt;br /&gt;
  class \logstore_database\log\store implements \core\log\sql_select_reader, \tool_log\log\writer;&lt;br /&gt;
&lt;br /&gt;
This log storage plugin is responsible for step 2 only from [[#Figure1|Figure 1]] above. There will be no interface to read from it provided with Moodle core.&lt;br /&gt;
&lt;br /&gt;
=== Legacy log table reader (logstore_legacy) ===&lt;br /&gt;
&lt;br /&gt;
Defines:&lt;br /&gt;
&lt;br /&gt;
  class \logstore_legacy\log\store implements \core\log\sql_select_reader, \tool_log\log\store;&lt;br /&gt;
&lt;br /&gt;
This plugin will not conduct any log writing; it will translate existing {log} table data into the new event format and transforms new SQL selects to match the legacy table format. This serves as an emulation layer that allows new reports to access historical data stored in mdl_log table. Users will have to select this datasource manually if they want to see historical data that is not present in new log tables.&lt;br /&gt;
&lt;br /&gt;
In new reports the legacy data will be presented using a special legacy event class that can not be triggered: \logstore_legacy\event\legacy&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
Compared to older Moodle version the new system will need to deal with higher number of log entries. This was improved by buffering of log entries together with new improved bulk insert operations in the DML layer. Helper traits were introduced \tool_log\helper\buffered_writer to help stores easily buffer the events.&lt;br /&gt;
&lt;br /&gt;
Running new and old event logging at the same time with result in 2x number of DB inserts, it will be therefore recommended to disable the old logging as soon as possible.&lt;br /&gt;
&lt;br /&gt;
In [https://tracker.moodle.org/browse/MDL-42894 MDL-42894], logging api comparison is done and it seems promising. Results are:&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Enabled Stores&lt;br /&gt;
! dbwrites&lt;br /&gt;
! dbreads&lt;br /&gt;
! Time used&lt;br /&gt;
! Session size&lt;br /&gt;
! Memory&lt;br /&gt;
! Server load&lt;br /&gt;
|-&lt;br /&gt;
| Legacy + Standard store&lt;br /&gt;
| Little increase&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Increased&lt;br /&gt;
|-&lt;br /&gt;
| Only Standard store&lt;br /&gt;
| Decrease&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Increased&lt;br /&gt;
|-&lt;br /&gt;
| Only Legacy store&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Decrease&lt;br /&gt;
|-&lt;br /&gt;
| Neither Legacy nor Standard store&lt;br /&gt;
| Decrease&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Decrease&lt;br /&gt;
|}&lt;br /&gt;
FYI: Serverload is showing worse in most cases, but as this was done on my local machine with all interference, I am ignoring this for now.&lt;br /&gt;
--[[User:Rajesh Taneja|Rajesh Taneja]] ([[User talk:Rajesh Taneja|talk]]) 16:19, 14 February 2014 (WST)&lt;br /&gt;
&lt;br /&gt;
== Screenshots ==&lt;br /&gt;
=== Log management page ===&lt;br /&gt;
[[File:event-observer.png |frame|center| Log management page]]&lt;br /&gt;
&lt;br /&gt;
=== Log store settings pages ===&lt;br /&gt;
[[File:event-observer-2.png |frame|center| settings page for a the standard log setup]]&lt;br /&gt;
[[File:external-log-settings.png |frame|center| settings page for an external log: Database setup]]&lt;br /&gt;
[[File:external-filter-logs.png |frame|center| settings page for an external log: Filtering]]&lt;br /&gt;
&lt;br /&gt;
== Overarching considerations ==&lt;br /&gt;
&lt;br /&gt;
We can&#039;t actually predict all use cases, so we must think generically and plan for worst cases. Here are some overarching principles that will be followed in the implementation of the new logging system.&lt;br /&gt;
&lt;br /&gt;
* Things that don&#039;t need to use logs should not use logs. (Recent activity, etc)&lt;br /&gt;
* Logging calls should be as cheap as possible.&lt;br /&gt;
* The Events API will be the central communication mechanism, allowing lots of potential information gathering tools to exist in future.&lt;br /&gt;
* Use plug-ins to determine where to put logs permanently (NoSQL, SAS, file...). Initially, the default will be to the current log table.&lt;br /&gt;
* Log everything we possibly can think of.&lt;br /&gt;
* Define log level settings (on each logging call) so different sites can choose what they want logged, which allows controls cotrol of log size, speed, etc..&lt;br /&gt;
* Function add_to_log should be retained for backward compatibility, without changing existing implementation, but allowing admins to disable it.&lt;br /&gt;
&lt;br /&gt;
= Reports =&lt;br /&gt;
&lt;br /&gt;
[[Logging usage#Reports]] describes current reports.&lt;br /&gt;
&lt;br /&gt;
= Migration to new logging API =&lt;br /&gt;
&lt;br /&gt;
== Follow-up Projects ==&lt;br /&gt;
&lt;br /&gt;
* Converting completion to use events - MDL-42897&lt;br /&gt;
* Developing a &#039;&#039;Timeline&#039;&#039; page/block so each user to see a stream of activity that is relevant to them individually - MDL-42898&lt;br /&gt;
&lt;br /&gt;
== Related ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Here are some ideas of how new even data and observers can be put to use:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Please note that the log storage API is not optimised for these tasks.&lt;br /&gt;
* Timely notifications of critical events (defined by users), for example more than five people posted in the same forum within an hour.&lt;br /&gt;
* &amp;quot;Red circle&amp;quot; notification badge counter icons everywhere in Moodle highlighting things that a user needs to pay attention attention to, such as ???.&lt;br /&gt;
* Colour heatmaps overlaid on course pages showing recent usage patterns of the course.&lt;br /&gt;
* Visualisation of live activity across a whole site (for admins) (is that logging or event handling?)&lt;br /&gt;
* Live engagement analytics reporting ??? that take specific actions into account, such as ???.&lt;br /&gt;
* Identification of students at risk based on their involvement in the course (or lack of it).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Logging of exceptions, errors and debugging:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Logging of Errors and warnings is not part of this specification, it meeds to be handled via a completely separate mechanism.&lt;br /&gt;
** People report errors that cannot be duplicated. Logging errors with a stack trace, session variables and other relevant data could be useful for debugging.&lt;br /&gt;
* Standard logs may theoretically produce errors and exceptions that need to be logged somewhere else.&lt;br /&gt;
* There is no synchronization with server logs to help debugging performance issues. (This will not be addressed by new logging API.)&lt;br /&gt;
* There is no logging of error information to help debug Moodle issues. (This will not be addressed by new logging API.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Performance logging and profiling&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
We need to measure the performance of logging system and store the information somewhere.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Other&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* There is no mechanism for archiving, so old logs are deleted and lost.&lt;br /&gt;
* Log deletion is indiscriminate, with no control of what log information is deleted or retained.&lt;br /&gt;
&lt;br /&gt;
== Places where we need more logs ==&lt;br /&gt;
&lt;br /&gt;
The principle work of this project is to replace the existing logging API. Once the new system is in place, the coverage of logging around Moodle can be improved.&lt;br /&gt;
&lt;br /&gt;
Suggestions for places in Moodle where logging is needed should be reported as Tracker issues and linked to the Epic MDL-28443 &amp;quot;Action logging improvements&amp;quot;. Feel free to echo significant areas here.&lt;br /&gt;
&lt;br /&gt;
* Activities on site, course and activity administration pages.&lt;br /&gt;
* Micro activities in a page (more than one per load), such as ???.&lt;br /&gt;
* AJAX calls (eg on course page), such as ???.&lt;br /&gt;
* Logging of long events (such as an LDAP synchronisation) should have:&lt;br /&gt;
** one unique identifier per event (like for example postfix mail server) to help admin monitor the cron processes and&lt;br /&gt;
** at least 2 log entries (begining and end) for each event, possibly more.&lt;br /&gt;
* Should be careful about logging confidential information. Anonymous events can be used to controll privacy.&lt;br /&gt;
* Shouldn’t delete logs when course is deleted. There is no API to delete logs, each log storage controls the rotation or deleting of old data individually.&lt;br /&gt;
&lt;br /&gt;
=See also=&lt;br /&gt;
&lt;br /&gt;
* [[Event 2]]&lt;br /&gt;
* [[Migrating logging calls in plugins]]&lt;br /&gt;
* [[Migrating reports accessing logs]]&lt;br /&gt;
&lt;br /&gt;
Other logging systems:&lt;br /&gt;
* http://logstash.net/ &lt;br /&gt;
* http://fluentd.org/&lt;br /&gt;
* http://logging.apache.org/log4php/&lt;br /&gt;
&lt;br /&gt;
Examples of data-based learning technology development:&lt;br /&gt;
* http://onlinelibrary.wiley.com/doi/10.1111/j.1467-8535.2008.00928.x/abstract &lt;br /&gt;
* http://www.sciencedirect.com/science/article/pii/S0360131510000461 -&amp;gt; qtype_pmatch&lt;br /&gt;
* http://www.tandfonline.com/doi/abs/10.1080/02680513.2011.567754&lt;br /&gt;
* http://oro.open.ac.uk/24619/&lt;br /&gt;
* [http://www.adlnet.gov/tla/lrs/ A Learning Record Store (LRS)] is a system that stores the tracking statements communicated through the [https://github.com/adlnet/xAPI-Spec Experience API (xAPI)]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=File:external-log-settings.png&amp;diff=44549</id>
		<title>File:external-log-settings.png</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=File:external-log-settings.png&amp;diff=44549"/>
		<updated>2014-04-29T02:07:00Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: Ankitfrenz uploaded a new version of &amp;amp;quot;File:external-log-settings.png&amp;amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Migrating_logging_calls_in_plugins&amp;diff=44548</id>
		<title>Migrating logging calls in plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Migrating_logging_calls_in_plugins&amp;diff=44548"/>
		<updated>2014-04-29T01:46:36Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* init() and create() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document is aimed to assist developers in replacing existing &#039;&#039;&#039;add_to_log()&#039;&#039;&#039; and &#039;&#039;&#039;events_trigger()&#039;&#039;&#039; calls with events. This can be implemented in Moodle 2.6 and will be required in 2.7.&lt;br /&gt;
&lt;br /&gt;
As a quick reminder: [[Event 2|new events]] were introduced in Moodle 2.6, a new [[Logging 2|logging system]] is being introduced in Moodle 2.7. The &#039;&#039;&#039;add_to_log()&#039;&#039;&#039; function will be deprecated, but the existing log table will still be present with existing data intact. This original logging is now called &#039;&#039;legacy logging&#039;&#039;. The new and legacy logging may coexist in the legacy logging system for purposes of transition, but this is not recommended for performance reasons. When replacing calls to add_to_log() with the triggering of an event, developers must ensure that they also generate an entry for the legacy log. It will only be used if the legacy log is enabled, since it may be enabled on systems that continue to use custom reports relying on presence of the legacy log table and it may take time to migrate such reports.&lt;br /&gt;
&lt;br /&gt;
== Quick guide ==&lt;br /&gt;
&lt;br /&gt;
If you are replacing common add_to_log() calls such as &amp;quot;view&amp;quot; and &amp;quot;view all&amp;quot; in mod/XXX/view.php and mod/XXX/index.php, see below. Otherwise do the following.&lt;br /&gt;
&lt;br /&gt;
=== Step 1. Choose a name for the event ===&lt;br /&gt;
&lt;br /&gt;
Names should follow the syntax OBJECT_VERB, for example &amp;quot;entry_added&amp;quot;, &amp;quot;work_submitted&amp;quot;, etc. It does not need to include a plugin name because this can be obtained from the PHP class namespace. See [[Event 2|the events documentation]] for more details about events names.&lt;br /&gt;
&lt;br /&gt;
Define a language string for the event name in &#039;&#039;&#039;YOURPLUGINDIR/lang/en/FULLPLUGINNAME.php&#039;&#039;&#039;.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;eventEVENTNAME] = &#039;Something has happened&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Step 2. Create event class ===&lt;br /&gt;
&lt;br /&gt;
For each event you must create an event class in &#039;&#039;&#039;YOURPLUGINDIR/classes/event/EVENTNAME.php&#039;&#039;&#039;, with the following format.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace FULLPLUGINNAME\event;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
class EVENTNAME extends \core\event\base {&lt;br /&gt;
    protected function init() {&lt;br /&gt;
        $this-&amp;gt;data[&#039;crud&#039;] = &#039;c&#039;; // c(reate), r(ead), u(pdate), d(elete)&lt;br /&gt;
        $this-&amp;gt;data[&#039;edulevel&#039;] = self::LEVEL_PARTICIPATING;&lt;br /&gt;
        $this-&amp;gt;data[&#039;objecttable&#039;] = &#039;...&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public static function get_name() {&lt;br /&gt;
        return get_string(&#039;eventEVENTNAME&#039;, &#039;FULLPLUGINNAME&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_description() {&lt;br /&gt;
        return &amp;quot;User {$this-&amp;gt;userid} has ... ... ... with id {$this-&amp;gt;objectid}.&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_url() {&lt;br /&gt;
        return new \moodle_url(&#039;....&#039;, array(&#039;parameter&#039; =&amp;gt; &#039;value&#039;, ...));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_legacy_logdata() {&lt;br /&gt;
        // Override if you are migrating an add_to_log() call.&lt;br /&gt;
        return array($this-&amp;gt;courseid, &#039;PLUGINNAME&#039;, &#039;LOGACTION&#039;,&lt;br /&gt;
            &#039;...........&#039;,&lt;br /&gt;
            $this-&amp;gt;objectid, $this-&amp;gt;contextinstanceid);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public static function get_legacy_eventname() {&lt;br /&gt;
        // Override ONLY if you are migrating events_trigger() call.&lt;br /&gt;
        return &#039;MYPLUGIN_OLD_EVENT_NAME&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function get_legacy_eventdata() {&lt;br /&gt;
        // Override if you migrating events_trigger() call.&lt;br /&gt;
        $data = new \stdClass();&lt;br /&gt;
        $data-&amp;gt;id = $this-&amp;gt;objectid;&lt;br /&gt;
        $data-&amp;gt;userid = $this-&amp;gt;relateduserid;&lt;br /&gt;
        return $data;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Step 3. Trigger the event instead of add_to_log() ===&lt;br /&gt;
&lt;br /&gt;
Replace the add_to_log() with an event trigger. The following is a common example of an event trigger inside an activity module.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
add_to_log($course-&amp;gt;id, &#039;PLUGINNAME&#039;, &#039;LOGACTION&#039;, &#039;...........&#039;, $objid, $cmid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...becomes...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event = \FULLPLUGINNAME\event\EVENTNAME::create(array(&lt;br /&gt;
    &#039;objectid&#039; =&amp;gt; $objid,&lt;br /&gt;
    &#039;context&#039; =&amp;gt; context_module::instance($cmid)&lt;br /&gt;
));&lt;br /&gt;
$event-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you need to trigger event multiple times in the code or just prefer shorter syntax you can declare your own static create function in the event class that would populate necessary fields and even add snapshots (see examples in mod_assign). In this case you can triger event in one line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
\FULLPLUGINNAME\event\EVENTNAME::create_from_someobject($someobject)-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Step 4. Increase the version number in version.php===&lt;br /&gt;
&lt;br /&gt;
The events that exist are only scanned when a plugin is installed or updated. Therefore when you change events, you need to increase version.php for you plugin.&lt;br /&gt;
&lt;br /&gt;
== Replacing &#039;view&#039; events in modules ==&lt;br /&gt;
&lt;br /&gt;
Calls to add_to_log() to report a &#039;view&#039; event are usually found in mod/PLUGINNAME/view.php (or in a lib function included by this file) and indicate that a user viewed the module. &lt;br /&gt;
&lt;br /&gt;
=== Step 1. Choosing the name ===&lt;br /&gt;
&lt;br /&gt;
Because this is a common event, the name is already chosen: &#039;&#039;&#039;course_module_viewed&#039;&#039;&#039; and the language string is defined in core.&lt;br /&gt;
&lt;br /&gt;
=== Step 2. Defining class ===&lt;br /&gt;
&lt;br /&gt;
You must create a class for this event in &#039;&#039;&#039;YOURPLUGINDIR/classes/event/course_module_viewed.php&#039;&#039;&#039; with the following format.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace FULLPLUGINNAME\event;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
class course_module_viewed extends \core\event\course_module_viewed {&lt;br /&gt;
    protected function init() {&lt;br /&gt;
        $this-&amp;gt;data[&#039;objecttable&#039;] = &#039;PLUGINNAME&#039;;&lt;br /&gt;
        parent::init();&lt;br /&gt;
    }&lt;br /&gt;
    // You might need to override get_url() and get_legacy_log_data() if view mode needs to be stored as well.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Step 3. Triggering the event ===&lt;br /&gt;
&lt;br /&gt;
This example takes data from $PAGE object but you may substitute this with ids and objects that you have fetched.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event = \FULLPLUGINNAME\event\course_module_viewed::create(array(&lt;br /&gt;
    &#039;objectid&#039; =&amp;gt; $PAGE-&amp;gt;cm-&amp;gt;instance,&lt;br /&gt;
    &#039;context&#039; =&amp;gt; $PAGE-&amp;gt;context,&lt;br /&gt;
));&lt;br /&gt;
$event-&amp;gt;add_record_snapshot(&#039;course&#039;, $PAGE-&amp;gt;course);&lt;br /&gt;
// In the next line you can use $PAGE-&amp;gt;activityrecord if you have set it, or skip this line if you don&#039;t have a record.&lt;br /&gt;
$event-&amp;gt;add_record_snapshot($PAGE-&amp;gt;cm-&amp;gt;modname, $activityrecord);&lt;br /&gt;
$event-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Step 4. Update version.php===&lt;br /&gt;
Don&#039;t forget to update the plugin version number.&lt;br /&gt;
&lt;br /&gt;
== Replacing &#039;view all&#039; events in modules ==&lt;br /&gt;
&lt;br /&gt;
Calls to add_to_log using &#039;view_all&#039; are usually found in mod/PLUGINNAME/index.php (or in a lib function included by this file). These invents indicate that a user viewed the list of all instances of this module within the course. &lt;br /&gt;
&lt;br /&gt;
=== Step 1. Choosing the name ===&lt;br /&gt;
&lt;br /&gt;
Because this is a common event, the name is already chosen: &#039;&#039;&#039;course_module_instance_list_viewed&#039;&#039;&#039; and the language string is defined in core.&lt;br /&gt;
&lt;br /&gt;
=== Step 2. Defining class ===&lt;br /&gt;
&lt;br /&gt;
You must create a class for this event in &#039;&#039;&#039;YOURPLUGINDIR/classes/event/course_module_instance_list_viewed.php&#039;&#039;&#039; with the following structure.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace FULLPLUGINNAME\event;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
class course_module_instance_list_viewed extends \core\event\course_module_instance_list_viewed {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Step 3. Triggering the event ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event = \FULLPLUGINNAME\event\course_module_instance_list_viewed::create(array(&lt;br /&gt;
    &#039;context&#039; =&amp;gt; context_course::instance($course-&amp;gt;id)&lt;br /&gt;
));&lt;br /&gt;
$event-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What to include in the event ==&lt;br /&gt;
&lt;br /&gt;
=== init() and create() ===&lt;br /&gt;
&lt;br /&gt;
Ideally all information needed when initialising and triggering events should already be available without having to run additional queries. Queries run to fill event objects with data will cause additional performance load, which should be avoided. Information that needs to be gathered from the database should be provided by other event methods, which can be called selectively when needed.&lt;br /&gt;
&lt;br /&gt;
As you noticed in the examples above you can specify additional properties either by the overriding the init() method of the event or when calling create(). The first way is used for properties that are always the same for this event, the second is for dynamic properties that may differ when the event is triggered.&lt;br /&gt;
&lt;br /&gt;
Usually you need to include the following properties.&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;context&#039;&#039;&#039; or &#039;&#039;&#039;contextid&#039;&#039;&#039;&lt;br /&gt;
| required&lt;br /&gt;
| Describes the context where the event took place.&lt;br /&gt;
| If you want to hardcode the system context, do so in init().&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;crud&#039;&#039;&#039;&lt;br /&gt;
| required&lt;br /&gt;
| Describes whether the event reflects creation (c), reading (r), updating (u) or deleting (d). This should be a single character string.&lt;br /&gt;
| Most often are specified in init().&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;edulevel&#039;&#039;&#039;&lt;br /&gt;
| required&lt;br /&gt;
| The level of educational value of the event. Can be LEVEL_TEACHING, LEVEL_PARTICIPATING or LEVEL_OTHER.&lt;br /&gt;
| Most often are specified in init().&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;objecttable&#039;&#039;&#039; and &#039;&#039;&#039;objectid&#039;&#039;&#039;&lt;br /&gt;
| &lt;br /&gt;
| Objecttable is the table that represents the event object to the best, ideally it is the object where the &amp;quot;CRUD&amp;quot; action was performend. Used by events that show the change in one record of one table, which will be the case for the most events.&lt;br /&gt;
| Since &#039;objecttable&#039; is always the same it is usually specified in init().&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;relateduserid&#039;&#039;&#039;&lt;br /&gt;
| &lt;br /&gt;
| The id of the user affected by the event.&lt;br /&gt;
| Only used if it is easy to identify a single user who is affected by this operation. For example a user who is being graded, a user who receives the message, a user being enrolled, etc. &#039;&#039;&#039;This is NOT the user who performs the action&#039;&#039;&#039; (who is identified in the userid field).&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;other&#039;&#039;&#039;&lt;br /&gt;
| &lt;br /&gt;
| Everything else that you may think is important about this event. This property will be serialised and stored by loggers.&lt;br /&gt;
| Include only necessary information. It can be used in get_description(), get_url() and get_legacy_logdata(). This property should only contain an array or scalar value, it &#039;&#039;&#039;can not use objects&#039;&#039;&#039;.&lt;br /&gt;
Example of information stored in &#039;other&#039; can be found in event course_module_deleted:&lt;br /&gt;
* Definition: https://github.com/moodle/moodle/blob/master/lib/classes/event/course_module_deleted.php#L69&lt;br /&gt;
* Triggering: https://github.com/moodle/moodle/blob/master/course/lib.php#L1716..L1727&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Usually you don&#039;t need to include the following properties as they are deduced by the base class.&lt;br /&gt;
* &#039;userid&#039;: user who performs the action, taken from $USER&lt;br /&gt;
* &#039;courseid&#039;: course affected in the operation, which will be taken from context. It need not be specified at all for events that are not related to a particular course.&lt;br /&gt;
&lt;br /&gt;
See the [[Event_2#Information_contained_in_events|full list of properties]] for more information.&lt;br /&gt;
&lt;br /&gt;
=== get_legacy_logdata() ===&lt;br /&gt;
&lt;br /&gt;
This method is used to add log data to the legacy log. You need only override this method when replacing an add_to_log() call. Since this document is a transition guide from add_to_log() to events, you will most likely need to override this method. This method needs to return an array (with 3-7 elements) that imitates the arguments that used to be passed to the add_to_log() function. From Moodle 2.7, the get_legacy_logdata() method will only be called if legacy logging is enabled through the legacy logging plugin.&lt;br /&gt;
&lt;br /&gt;
=== get_description() and get_url() ===&lt;br /&gt;
&lt;br /&gt;
Most reporting tools will display aggregated event information (for example the count of student logins) so those methods, which describe individual events, are not likely to be called often; they will only be used by detailed reports such as loglive. At the moment, use get_description() to provide a very brief internal description of the action performed, so that it can be used for error recovery like any other system log. The description is hard-coded in English but it may be possible that future versions of Moodle (2.8 or later) will allow the use of translatable language strings. These methods should not make DB queries, access global variables, etc. For example, when a course is renamed or when a user is deleted, do not retrieve the course name or user name, instead simply use their ids. These functions should return exactly the same result whenever they are called, regardless of the environment or state, even after they have been restored from logs. &lt;br /&gt;
&lt;br /&gt;
=== get_legacy_eventname() and get_legacy_eventdata() ===&lt;br /&gt;
&lt;br /&gt;
You will need to override these two functions if you are upgrading events_trigger() calls. These will allow legacy plugins to continue to listen to your new events without upgrading their listeners.&lt;br /&gt;
&lt;br /&gt;
If you need to provide more detailed information to observers, you can choose to:&lt;br /&gt;
* add more information to &#039;other&#039;, but remember that this will be logged and it&#039;s better to keep logs as small as possible;&lt;br /&gt;
* use record snapshots, which are especially useful for delete actions (you can call get_record_snapshot() inside get_legacy_eventdata() and observers are encouraged to get data from snapshots as well);&lt;br /&gt;
* add new properties to your event class and define getter/setter functions, for example set_custom_data() and get_custom_data().&lt;br /&gt;
&lt;br /&gt;
=== add_record_snapshot() ===&lt;br /&gt;
&lt;br /&gt;
A record snapshot can be added for any DB table related to the event. If it is added it must be an instance of stdClass containing all fields that are present in the corresponding DB table. You must add a record snapshot when you delete something from database. &#039;&#039;&#039;Record snapshots cannot be used from reports, it is intended for event observers only.&#039;&#039;&#039; Usually observers expect record snapshot identified by &#039;objecttable&#039; and &#039;objectid&#039; but developer may also add snapshot of related tables, i.e. when book chapter is updated the developer may decide to add snapshots of related records in tables book_chapters, book, course_modules and course. &lt;br /&gt;
&lt;br /&gt;
Record snapshots should be added only when you already have an object and do not need to perform any additional DB queries to retrieve it. Otherwise omit it, as the record will be retrieved by get_record_snapshot() automatically, and only if needed. For performance reasons the snapshots are not guaranteed to contain an exact state at the time of event triggering, it may be actually fetched at any time between the triggering of event and its observation.&lt;br /&gt;
&lt;br /&gt;
== Events DON&#039;Ts ==&lt;br /&gt;
&lt;br /&gt;
Do not put more information in &#039;other&#039; than is needed. For example, do not include a full DB record for delete/create operations or a list of all changed properties in edit operations. If observers are interested in this information, it can requested by calling get_record_snapshot(). Never include large text fields in event data. &#039;&#039;&#039;Please help to keep the log size reasonable.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Do NOT use $USER, $COURSE, $PAGE or other global variables when overriding get_* methods (with the exception of get_legacy_eventdata).&lt;br /&gt;
&lt;br /&gt;
Do NOT call $this-&amp;gt;get_record_snapshot() inside the event class (again with the exception of get_legacy_eventdata). If you need additional information for internal functions that cannot be added to existing properties, add it to the &#039;other&#039; property.&lt;br /&gt;
&lt;br /&gt;
Do NOT use $this-&amp;gt;context inside an event class. &#039;&#039;&#039;Remember that methods get_description() and get_url() may be called on events after they have been restored from logs.&#039;&#039;&#039; It is possible that the original context no longer exists when these functions are called. Instead use $this-&amp;gt;contextid, $this-&amp;gt;contextlevel, $this-&amp;gt;contextinstanceid.&lt;br /&gt;
&lt;br /&gt;
== Validation and testing ==&lt;br /&gt;
&lt;br /&gt;
You may notice that the most of events in Moodle also have function validate_data() . You can add this function for your own safety to ensure that you don&#039;t forget to define all required data when triggering event.&lt;br /&gt;
&lt;br /&gt;
We highly recommend to cover your events with unit tests. Search in standard plugins for files with the names events_test.php to see examples.&lt;br /&gt;
&lt;br /&gt;
In order to manually test the event you can perform the action and check how it appears in &#039;&#039;&#039;Course Administration &amp;gt; Reports &amp;gt; Logs&#039;&#039;&#039;. Also look up your event in the &#039;&#039;&#039;Site Administration &amp;gt; Reports &amp;gt; Events list&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Installation&amp;quot; of events ==&lt;br /&gt;
&lt;br /&gt;
Please never forget that you have to bump the plugin version in order to get all the new events &amp;quot;installed&amp;quot;&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Logging_2&amp;diff=44541</id>
		<title>Logging 2</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Logging_2&amp;diff=44541"/>
		<updated>2014-04-28T06:10:47Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* Places where we need more logs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Project&lt;br /&gt;
|name = Logging stage 2&lt;br /&gt;
|state = Completed&lt;br /&gt;
|tracker = MDL-37658&lt;br /&gt;
|discussion = https://moodle.org/mod/forum/discuss.php?d=235318&lt;br /&gt;
|assignee = moodle.com BACKEND team&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
= Benefits of the new logging system =&lt;br /&gt;
A few benefits of the new logging system are :-&lt;br /&gt;
* allows for capturing of richer information from plugins/core about actions;&lt;br /&gt;
* provides control over how much information is logged;&lt;br /&gt;
* abstracts log writing and reading so logging can be scaled;&lt;br /&gt;
* lets you write/read logs from any external system by the use of logstore plugins;&lt;br /&gt;
* control how much logging history is kept; and&lt;br /&gt;
* support research, reporting and analytics.&lt;br /&gt;
&lt;br /&gt;
== Why is Logging an important topic? ==&lt;br /&gt;
&lt;br /&gt;
Logging is fundamental to research, reporting and analytics. &lt;br /&gt;
&lt;br /&gt;
Not much of new Moodle development is based on measured data.  We need to be able to:&lt;br /&gt;
* prove there is a problem and&lt;br /&gt;
* prove that a given change is an improvement.&lt;br /&gt;
&lt;br /&gt;
Logging data can be used by different Moodle users.&lt;br /&gt;
*Better data would allow researchers to study what happens in online teaching.&lt;br /&gt;
*Better data would give admins more feedback on how to run their site - both technically and process (please note this issue is not about profiling).&lt;br /&gt;
*Better data would give teachers better feedback to improve their teaching process.&lt;br /&gt;
*Better data would give students better feedback to improve their learning.&lt;br /&gt;
&lt;br /&gt;
We can&#039;t predict all forms of analysis that might happen in future.&lt;br /&gt;
* The logging system needs to be flexible in order to accommodate applications by these different users.&lt;br /&gt;
* The logging API needs to be constructed in a way that is possible to improve in future.&lt;br /&gt;
&lt;br /&gt;
== Problems with old logging ==&lt;br /&gt;
&lt;br /&gt;
The old logging infrastructure had a number of issues that were resolved by this project. A few of these are:-&lt;br /&gt;
&lt;br /&gt;
* Logging was added ad-hoc by developers and has spotty coverage.&lt;br /&gt;
* Some logged actions did not contain important information needed later.&lt;br /&gt;
* There were performance and scalability problems, such as:&lt;br /&gt;
** log tables were joined in many popular queries and were slow;&lt;br /&gt;
** all logs used to go to one standard moodle database table, which was not scalable;&lt;br /&gt;
** it was not possible to configure level of logging ; and&lt;br /&gt;
** it was not possible to disable logging completely.&lt;br /&gt;
&lt;br /&gt;
= Logging =&lt;br /&gt;
&lt;br /&gt;
The new [[Event 2|Events API]] introduced in Moodle 2.6 provides a notification mechanism and single collection point for actions within Moodle. The Events system also defines information about events that can be extended with additional information and functionality by core code and plugins, as needed.&lt;br /&gt;
&lt;br /&gt;
In order to capture events a logging API was specified, consisting of a number of plugin types.&lt;br /&gt;
&lt;br /&gt;
To transition from the old logging system to the new, work was required in a number of areas.&lt;br /&gt;
&lt;br /&gt;
* In places where we previously added information to &#039;the&#039; log table, we must instead generate a new event.&lt;br /&gt;
* The standard Moodle distribution now includes 2 simple DB logging storage plugin that will store events in new format (internal and external database)&lt;br /&gt;
* The original logging code and DB tables are available for full backwards compatibility for users of customised reports. It is possible to enable logging to the old {log} table if required.&lt;br /&gt;
* All standard reports have been upgraded to use the new logging system and uses logging retrieval plugin to access log information.&lt;br /&gt;
* Custom report plugins (add-ons) will be able to query the {log} table, but should ideally shift to the new logging system over time, so that sites are not forced to continue double logging.&lt;br /&gt;
&lt;br /&gt;
== Old log usage analysis ==&lt;br /&gt;
&lt;br /&gt;
See [[Logging_usage|this analysis]] to see log usage in Moodle 2.5 core code.&lt;br /&gt;
&lt;br /&gt;
== Example scenario ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Writing to the log&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# A student submits an assignment.&lt;br /&gt;
# An event is triggered by the Assignment module.&lt;br /&gt;
# The log manager plugin observes the event and determines if it is log-worthy depending on some admin settings.&lt;br /&gt;
# The log manager sends the event to all enabled log storage subplugins implementing \tool_log\log\writer. Storage plugins may decide to filter out some events based on their admin settings.&lt;br /&gt;
# The log store plugin(s) stores the event data optionally including extra information such as remote IP or original logged-in-as user id.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Reading from the log&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# A teacher opens activity report.&lt;br /&gt;
# Activity reports queries available log readers from the current log manager (implementing \core\log\manager).&lt;br /&gt;
# If there is more than one log reader (implementing \core\log\sql_select_reader) available they can select the source of data for the report.&lt;br /&gt;
# A teacher requests report of student assignment submissions.&lt;br /&gt;
# The report requests events from the log reader and displays them.&lt;br /&gt;
&lt;br /&gt;
== From event to report ==&lt;br /&gt;
&lt;br /&gt;
There are four steps of how event is captured, logged and potentially presented in a report. These steps are summarised in [[#Figure1|Figure 1]] below and can be described as follows.&lt;br /&gt;
&lt;br /&gt;
# Handling of events and filtering what needs to be logged. See interface \core\log\manager below.&lt;br /&gt;
# Storing the events data in the log storage (DB, filesystem, etc.). See interface \tool_log\log\writer below.&lt;br /&gt;
# Retrieving the data from log storage - each plugin implements some methods to query and extract logs back to Moodle. See interfaces \core\log\reader and \core\log\sql_reader below.&lt;br /&gt;
# Displaying the data in the report.&lt;br /&gt;
&lt;br /&gt;
One plugin may cover multiple steps. For example we expect that most of log writer plugins will also implement log reader. It is also possible to create a report that has built-in event handling, log writing and reading and report presentation (all four steps). Also external logging systems may not wish to allow log data they capture to be reported within Moodle, handling it through an external system, so they may not implement steps 3 and 4 at all.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Figure1&amp;quot; style=&amp;quot;text-align:center&amp;quot;&amp;gt;&lt;br /&gt;
[[File:logging_plugins_relation.png]]&lt;br /&gt;
&#039;&#039;&#039;Figure 1. Logging plugins relationship diagram&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The [[#Figure2|Figure 2]] below shows how the requests are made between user actions, plugins and core when:&lt;br /&gt;
&lt;br /&gt;
* configuring logging - which log writer plugins are enabled&lt;br /&gt;
* event occurs&lt;br /&gt;
* report - selecting log store&lt;br /&gt;
* viewing report&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Figure2&amp;quot; style=&amp;quot;text-align:center&amp;quot;&amp;gt;&lt;br /&gt;
[[Image:logging_sequence.png|logging_sequence.png]]&lt;br /&gt;
&#039;&#039;&#039;Figure 2. Logging plugins sequence diagram&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Public API ==&lt;br /&gt;
&lt;br /&gt;
This section describes all interfaces that need to be implemented by log manager and each log storage class.&lt;br /&gt;
&lt;br /&gt;
=== Reading API ===&lt;br /&gt;
* &#039;&#039;&#039;function \get_log_manager()&#039;&#039;&#039; - returns the current log manager if configured or some dummy instance otherwise, it uses the signleton pattern.&lt;br /&gt;
* &#039;&#039;&#039;interface \core\log\manager&#039;&#039;&#039; - log manager interface, in standard distribution implemented by \tool_log\log\manager and \core\log\dummy_manager&lt;br /&gt;
** public function get_readers($interface = null) returns the active storages implementing reader interface, returns array(classname =&amp;gt; storage instance, ...)&lt;br /&gt;
* &#039;&#039;&#039;interface \core\log\reader&#039;&#039;&#039; - general event reader&lt;br /&gt;
** public function get_name() - returns name of the log storage, this will be used when selection data source in reports.&lt;br /&gt;
** public function get_description() - some help for admins.&lt;br /&gt;
** public function is_logging() - is latest data available?&lt;br /&gt;
* &#039;&#039;&#039;interface \core\log\sql_select_reader&#039;&#039;&#039; extends \core\log\reader - general log storage that supports sql selects (or emulates them)&lt;br /&gt;
** public function get_events_select($selectwhere, array $params, $order, $limitfrom, $limitnum) - returns event object instances matching given parameters.&lt;br /&gt;
** public function get_events_select_count($selectwhere, array $params) - returns number of events that would be returned from get_events() with the same parameters.&lt;br /&gt;
*** $selectwhere is supposed to be a limited sql predicate.&lt;br /&gt;
*** The set of operators allowed in $selectwhere are :- =, &amp;lt;&amp;gt;, &amp;gt;, &amp;gt;=, &amp;lt;, &amp;lt;=&lt;br /&gt;
*** The set of keywords allowed in $selectwhere are :- IN, BETWEEN, LIKE, IS NULL, IS NOT NULL&lt;br /&gt;
*** Logical operators OR, AND&lt;br /&gt;
*** NOT operator&lt;br /&gt;
*** ( and ) brackets&lt;br /&gt;
*** ? and :named parameter placeholders &lt;br /&gt;
*** Use of anything besides the mentioned keywords/operators is strictly forbidden.&lt;br /&gt;
* &#039;&#039;&#039;interface \core\log\sql_internal_reader&#039;&#039;&#039; extends \core\log\reader - log storage that can expose data as read-only database view or table.&lt;br /&gt;
** public function get_internal_log_table_name() - returns database table or view; structure is described in phpdocs, it will include all columns defined by log_sql&lt;br /&gt;
&lt;br /&gt;
Reports are expected to use only the reading API. Please note that all non-sql readers need to somehow translate the $selectwhere SQL query syntax.&lt;br /&gt;
&lt;br /&gt;
When reports are searching for log readers they use the get_log_manager()-&amp;gt;get_readers($interface = null) where $interface is the name of reader interface that the report supports.&lt;br /&gt;
If there are multiple readers returned by the log manager, then the report is responsible for letting the user choose which storage to create the report on.&lt;br /&gt;
&lt;br /&gt;
=== Writing API ===&lt;br /&gt;
* &#039;&#039;&#039;interface \tool_log\log\store&#039;&#039;&#039; - must be implemented by each store subplugin.&lt;br /&gt;
** public function __construct(\tool_log\log\manager $manager) - no parameters, configuration is taken from admin settings.&lt;br /&gt;
** public function dispose() - called when reading/writing finished.&lt;br /&gt;
* &#039;&#039;&#039;interface \tool_log\log\writer&#039;&#039;&#039; extends \tool_log\log\store - interface indicating the log store may be used for writing.&lt;br /&gt;
** public function write(\core\event\base $event) - called from event observer defined in log manager.&lt;br /&gt;
&lt;br /&gt;
The writing API is defined in tool_log plugin, the log stores are defined as new subplugin of this plugin.&lt;br /&gt;
&lt;br /&gt;
Each log store plugin will be responsible for filtering of events, it may use standardised admin settings and filtering or decide to implement custom filtering.&lt;br /&gt;
&lt;br /&gt;
== Standard logging plugins ==&lt;br /&gt;
&lt;br /&gt;
Standard Moodle distribution will include four plugins.&lt;br /&gt;
&lt;br /&gt;
=== Logging management plugin (tool_log) ===&lt;br /&gt;
&lt;br /&gt;
Defines:&lt;br /&gt;
&lt;br /&gt;
  class \tool_log\log\manager implements \core\log\manager;&lt;br /&gt;
&lt;br /&gt;
The log manager is responsible for step 1 from [[#Figure1|Figure 1]] above. It allows admins to configure which log store subplugin is enabled and in which order they appear. The log store plugins are implemented as tool_log subplugins with class &amp;quot;store&amp;quot; in their namespace (\logstore_xxxx\log\store).&lt;br /&gt;
&lt;br /&gt;
The log manager registers a &#039;*&#039; event observer, this observer is external - it means that events are received only when database transactions are not in progress.&lt;br /&gt;
&lt;br /&gt;
=== Standard log storage plugin (logstore_standard) ===&lt;br /&gt;
&lt;br /&gt;
Defines:&lt;br /&gt;
&lt;br /&gt;
  class \logstore_standard\log\store implements \core\log\sql_internal_reader, \tool_log\log\writer;&lt;br /&gt;
&lt;br /&gt;
The name logstore_standard does not seem to be optimal - &#039;&#039;logstore_db&#039;&#039; is not allowed because it collides with standard /db/ subdirectory in plugins and &#039;&#039;logstore_database&#039;&#039; should be probably reserved for external database logging (to prevent any confusion).&lt;br /&gt;
&lt;br /&gt;
This log storage plugin is responsible for steps 2 and 3 from [[#Figure1|Figure 1]] above. It is the primary replacement for the former {log} table. The performance will be similar to former log table, but for smaller sites, this simple default will suffice.&lt;br /&gt;
&lt;br /&gt;
Each plugin decides how much data is kept, when it is deleted, etc.&lt;br /&gt;
&lt;br /&gt;
==== Storage settings ====&lt;br /&gt;
&lt;br /&gt;
Each storage plugin with writer interface is responsible for backlisting or filtering of events. Some of the examples of filtering that can done is as below:-&lt;br /&gt;
* Include guests actions (default &#039;&#039;Yes&#039;&#039;).&lt;br /&gt;
* Include log levels (default &#039;&#039;empty&#039;&#039;), accepts constants from [[Event_2#Level_property]].&lt;br /&gt;
* Include by CRUD (default &#039;&#039;empty&#039;&#039;), accepts C, R, U, and D.&lt;br /&gt;
* Include by component (default &#039;&#039;empty&#039;&#039;)&lt;br /&gt;
* Include by event name (default &#039;&#039;empty&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
=== External database log storage plugin (logstore_database) ===&lt;br /&gt;
&lt;br /&gt;
Defines:&lt;br /&gt;
&lt;br /&gt;
  class \logstore_database\log\store implements \core\log\sql_select_reader, \tool_log\log\writer;&lt;br /&gt;
&lt;br /&gt;
This log storage plugin is responsible for step 2 only from [[#Figure1|Figure 1]] above. There will be no interface to read from it provided with Moodle core.&lt;br /&gt;
&lt;br /&gt;
=== Legacy log table reader (logstore_legacy) ===&lt;br /&gt;
&lt;br /&gt;
Defines:&lt;br /&gt;
&lt;br /&gt;
  class \logstore_legacy\log\store implements \core\log\sql_select_reader, \tool_log\log\store;&lt;br /&gt;
&lt;br /&gt;
This plugin will not conduct any log writing; it will translate existing {log} table data into the new event format and transforms new SQL selects to match the legacy table format. This serves as an emulation layer that allows new reports to access historical data stored in mdl_log table. Users will have to select this datasource manually if they want to see historical data that is not present in new log tables.&lt;br /&gt;
&lt;br /&gt;
In new reports the legacy data will be presented using a special legacy event class that can not be triggered: \logstore_legacy\event\legacy&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
Compared to older Moodle version the new system will need to deal with higher number of log entries. This was improved by buffering of log entries together with new improved bulk insert operations in the DML layer. Helper traits were introduced \tool_log\helper\buffered_writer to help stores easily buffer the events.&lt;br /&gt;
&lt;br /&gt;
Running new and old event logging at the same time with result in 2x number of DB inserts, it will be therefore recommended to disable the old logging as soon as possible.&lt;br /&gt;
&lt;br /&gt;
In [https://tracker.moodle.org/browse/MDL-42894 MDL-42894], logging api comparison is done and it seems promising. Results are:&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Enabled Stores&lt;br /&gt;
! dbwrites&lt;br /&gt;
! dbreads&lt;br /&gt;
! Time used&lt;br /&gt;
! Session size&lt;br /&gt;
! Memory&lt;br /&gt;
! Server load&lt;br /&gt;
|-&lt;br /&gt;
| Legacy + Standard store&lt;br /&gt;
| Little increase&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Increased&lt;br /&gt;
|-&lt;br /&gt;
| Only Standard store&lt;br /&gt;
| Decrease&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Increased&lt;br /&gt;
|-&lt;br /&gt;
| Only Legacy store&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Decrease&lt;br /&gt;
|-&lt;br /&gt;
| Neither Legacy nor Standard store&lt;br /&gt;
| Decrease&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Decrease&lt;br /&gt;
|}&lt;br /&gt;
FYI: Serverload is showing worse in most cases, but as this was done on my local machine with all interference, I am ignoring this for now.&lt;br /&gt;
--[[User:Rajesh Taneja|Rajesh Taneja]] ([[User talk:Rajesh Taneja|talk]]) 16:19, 14 February 2014 (WST)&lt;br /&gt;
&lt;br /&gt;
== Mockups ==&lt;br /&gt;
=== Log management page ===&lt;br /&gt;
[[File:event-observer.png |frame|center| Log management page]]&lt;br /&gt;
&lt;br /&gt;
=== Log store settings pages ===&lt;br /&gt;
[[File:event-observer-2.png |frame|center| settings page for a the standard log setup]]&lt;br /&gt;
[[File:external-log-settings.png |frame|center| settings page for an external log setup]]&lt;br /&gt;
&lt;br /&gt;
== Overarching considerations ==&lt;br /&gt;
&lt;br /&gt;
We can&#039;t actually predict all use cases, so we must think generically and plan for worst cases. Here are some overarching principles that will be followed in the implementation of the new logging system.&lt;br /&gt;
&lt;br /&gt;
* Things that don&#039;t need to use logs should not use logs. (Recent activity, etc)&lt;br /&gt;
* Logging calls should be as cheap as possible.&lt;br /&gt;
* The Events API will be the central communication mechanism, allowing lots of potential information gathering tools to exist in future.&lt;br /&gt;
* Use plug-ins to determine where to put logs permanently (NoSQL, SAS, file...). Initially, the default will be to the current log table.&lt;br /&gt;
* Log everything we possibly can think of.&lt;br /&gt;
* Define log level settings (on each logging call) so different sites can choose what they want logged, which allows controls cotrol of log size, speed, etc..&lt;br /&gt;
* Function add_to_log should be retained for backward compatibility, without changing existing implementation, but allowing admins to disable it.&lt;br /&gt;
&lt;br /&gt;
= Reports =&lt;br /&gt;
&lt;br /&gt;
[[Logging usage#Reports]] describes current reports.&lt;br /&gt;
&lt;br /&gt;
= Migration to new logging API =&lt;br /&gt;
&lt;br /&gt;
== Follow-up Projects ==&lt;br /&gt;
&lt;br /&gt;
* Converting completion to use events - MDL-42897&lt;br /&gt;
* Developing a &#039;&#039;Timeline&#039;&#039; page/block so each user to see a stream of activity that is relevant to them individually - MDL-42898&lt;br /&gt;
&lt;br /&gt;
== Related ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Here are some ideas of how new even data and observers can be put to use:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Please note that the log storage API is not optimised for these tasks.&lt;br /&gt;
* Timely notifications of critical events (defined by users), for example more than five people posted in the same forum within an hour.&lt;br /&gt;
* &amp;quot;Red circle&amp;quot; notification badge counter icons everywhere in Moodle highlighting things that a user needs to pay attention attention to, such as ???.&lt;br /&gt;
* Colour heatmaps overlaid on course pages showing recent usage patterns of the course.&lt;br /&gt;
* Visualisation of live activity across a whole site (for admins) (is that logging or event handling?)&lt;br /&gt;
* Live engagement analytics reporting ??? that take specific actions into account, such as ???.&lt;br /&gt;
* Identification of students at risk based on their involvement in the course (or lack of it).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Logging of exceptions, errors and debugging:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Logging of Errors and warnings is not part of this specification, it meeds to be handled via a completely separate mechanism.&lt;br /&gt;
** People report errors that cannot be duplicated. Logging errors with a stack trace, session variables and other relevant data could be useful for debugging.&lt;br /&gt;
* Standard logs may theoretically produce errors and exceptions that need to be logged somewhere else.&lt;br /&gt;
* There is no synchronization with server logs to help debugging performance issues. (This will not be addressed by new logging API.)&lt;br /&gt;
* There is no logging of error information to help debug Moodle issues. (This will not be addressed by new logging API.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Performance logging and profiling&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
We need to measure the performance of logging system and store the information somewhere.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Other&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* There is no mechanism for archiving, so old logs are deleted and lost.&lt;br /&gt;
* Log deletion is indiscriminate, with no control of what log information is deleted or retained.&lt;br /&gt;
&lt;br /&gt;
== Places where we need more logs ==&lt;br /&gt;
&lt;br /&gt;
The principle work of this project is to replace the existing logging API. Once the new system is in place, the coverage of logging around Moodle can be improved.&lt;br /&gt;
&lt;br /&gt;
Suggestions for places in Moodle where logging is needed should be reported as Tracker issues and linked to the Epic MDL-28443 &amp;quot;Action logging improvements&amp;quot;. Feel free to echo significant areas here.&lt;br /&gt;
&lt;br /&gt;
* Activities on site, course and activity administration pages.&lt;br /&gt;
* Micro activities in a page (more than one per load), such as ???.&lt;br /&gt;
* AJAX calls (eg on course page), such as ???.&lt;br /&gt;
* Logging of long events (such as an LDAP synchronisation) should have:&lt;br /&gt;
** one unique identifier per event (like for example postfix mail server) to help admin monitor the cron processes and&lt;br /&gt;
** at least 2 log entries (begining and end) for each event, possibly more.&lt;br /&gt;
* Should be careful about logging confidential information. Anonymous events can be used to controll privacy.&lt;br /&gt;
* Shouldn’t delete logs when course is deleted. There is no API to delete logs, each log storage controls the rotation or deleting of old data individually.&lt;br /&gt;
&lt;br /&gt;
=See also=&lt;br /&gt;
&lt;br /&gt;
* [[Event 2]]&lt;br /&gt;
* [[Migrating logging calls in plugins]]&lt;br /&gt;
* [[Migrating reports accessing logs]]&lt;br /&gt;
&lt;br /&gt;
Other logging systems:&lt;br /&gt;
* http://logstash.net/ &lt;br /&gt;
* http://fluentd.org/&lt;br /&gt;
* http://logging.apache.org/log4php/&lt;br /&gt;
&lt;br /&gt;
Examples of data-based learning technology development:&lt;br /&gt;
* http://onlinelibrary.wiley.com/doi/10.1111/j.1467-8535.2008.00928.x/abstract &lt;br /&gt;
* http://www.sciencedirect.com/science/article/pii/S0360131510000461 -&amp;gt; qtype_pmatch&lt;br /&gt;
* http://www.tandfonline.com/doi/abs/10.1080/02680513.2011.567754&lt;br /&gt;
* http://oro.open.ac.uk/24619/&lt;br /&gt;
* [http://www.adlnet.gov/tla/lrs/ A Learning Record Store (LRS)] is a system that stores the tracking statements communicated through the [https://github.com/adlnet/xAPI-Spec Experience API (xAPI)]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Logging_2&amp;diff=44540</id>
		<title>Logging 2</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Logging_2&amp;diff=44540"/>
		<updated>2014-04-28T06:06:01Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: Cleanup the doc&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Project&lt;br /&gt;
|name = Logging stage 2&lt;br /&gt;
|state = Completed&lt;br /&gt;
|tracker = MDL-37658&lt;br /&gt;
|discussion = https://moodle.org/mod/forum/discuss.php?d=235318&lt;br /&gt;
|assignee = moodle.com BACKEND team&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
= Benefits of the new logging system =&lt;br /&gt;
A few benefits of the new logging system are :-&lt;br /&gt;
* allows for capturing of richer information from plugins/core about actions;&lt;br /&gt;
* provides control over how much information is logged;&lt;br /&gt;
* abstracts log writing and reading so logging can be scaled;&lt;br /&gt;
* lets you write/read logs from any external system by the use of logstore plugins;&lt;br /&gt;
* control how much logging history is kept; and&lt;br /&gt;
* support research, reporting and analytics.&lt;br /&gt;
&lt;br /&gt;
== Why is Logging an important topic? ==&lt;br /&gt;
&lt;br /&gt;
Logging is fundamental to research, reporting and analytics. &lt;br /&gt;
&lt;br /&gt;
Not much of new Moodle development is based on measured data.  We need to be able to:&lt;br /&gt;
* prove there is a problem and&lt;br /&gt;
* prove that a given change is an improvement.&lt;br /&gt;
&lt;br /&gt;
Logging data can be used by different Moodle users.&lt;br /&gt;
*Better data would allow researchers to study what happens in online teaching.&lt;br /&gt;
*Better data would give admins more feedback on how to run their site - both technically and process (please note this issue is not about profiling).&lt;br /&gt;
*Better data would give teachers better feedback to improve their teaching process.&lt;br /&gt;
*Better data would give students better feedback to improve their learning.&lt;br /&gt;
&lt;br /&gt;
We can&#039;t predict all forms of analysis that might happen in future.&lt;br /&gt;
* The logging system needs to be flexible in order to accommodate applications by these different users.&lt;br /&gt;
* The logging API needs to be constructed in a way that is possible to improve in future.&lt;br /&gt;
&lt;br /&gt;
== Problems with old logging ==&lt;br /&gt;
&lt;br /&gt;
The old logging infrastructure had a number of issues that were resolved by this project. A few of these are:-&lt;br /&gt;
&lt;br /&gt;
* Logging was added ad-hoc by developers and has spotty coverage.&lt;br /&gt;
* Some logged actions did not contain important information needed later.&lt;br /&gt;
* There were performance and scalability problems, such as:&lt;br /&gt;
** log tables were joined in many popular queries and were slow;&lt;br /&gt;
** all logs used to go to one standard moodle database table, which was not scalable;&lt;br /&gt;
** it was not possible to configure level of logging ; and&lt;br /&gt;
** it was not possible to disable logging completely.&lt;br /&gt;
&lt;br /&gt;
= Logging =&lt;br /&gt;
&lt;br /&gt;
The new [[Event 2|Events API]] introduced in Moodle 2.6 provides a notification mechanism and single collection point for actions within Moodle. The Events system also defines information about events that can be extended with additional information and functionality by core code and plugins, as needed.&lt;br /&gt;
&lt;br /&gt;
In order to capture events a logging API was specified, consisting of a number of plugin types.&lt;br /&gt;
&lt;br /&gt;
To transition from the old logging system to the new, work was required in a number of areas.&lt;br /&gt;
&lt;br /&gt;
* In places where we previously added information to &#039;the&#039; log table, we must instead generate a new event.&lt;br /&gt;
* The standard Moodle distribution now includes 2 simple DB logging storage plugin that will store events in new format (internal and external database)&lt;br /&gt;
* The original logging code and DB tables are available for full backwards compatibility for users of customised reports. It is possible to enable logging to the old {log} table if required.&lt;br /&gt;
* All standard reports have been upgraded to use the new logging system and uses logging retrieval plugin to access log information.&lt;br /&gt;
* Custom report plugins (add-ons) will be able to query the {log} table, but should ideally shift to the new logging system over time, so that sites are not forced to continue double logging.&lt;br /&gt;
&lt;br /&gt;
== Old log usage analysis ==&lt;br /&gt;
&lt;br /&gt;
See [[Logging_usage|this analysis]] to see log usage in Moodle 2.5 core code.&lt;br /&gt;
&lt;br /&gt;
== Example scenario ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Writing to the log&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# A student submits an assignment.&lt;br /&gt;
# An event is triggered by the Assignment module.&lt;br /&gt;
# The log manager plugin observes the event and determines if it is log-worthy depending on some admin settings.&lt;br /&gt;
# The log manager sends the event to all enabled log storage subplugins implementing \tool_log\log\writer. Storage plugins may decide to filter out some events based on their admin settings.&lt;br /&gt;
# The log store plugin(s) stores the event data optionally including extra information such as remote IP or original logged-in-as user id.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Reading from the log&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# A teacher opens activity report.&lt;br /&gt;
# Activity reports queries available log readers from the current log manager (implementing \core\log\manager).&lt;br /&gt;
# If there is more than one log reader (implementing \core\log\sql_select_reader) available they can select the source of data for the report.&lt;br /&gt;
# A teacher requests report of student assignment submissions.&lt;br /&gt;
# The report requests events from the log reader and displays them.&lt;br /&gt;
&lt;br /&gt;
== From event to report ==&lt;br /&gt;
&lt;br /&gt;
There are four steps of how event is captured, logged and potentially presented in a report. These steps are summarised in [[#Figure1|Figure 1]] below and can be described as follows.&lt;br /&gt;
&lt;br /&gt;
# Handling of events and filtering what needs to be logged. See interface \core\log\manager below.&lt;br /&gt;
# Storing the events data in the log storage (DB, filesystem, etc.). See interface \tool_log\log\writer below.&lt;br /&gt;
# Retrieving the data from log storage - each plugin implements some methods to query and extract logs back to Moodle. See interfaces \core\log\reader and \core\log\sql_reader below.&lt;br /&gt;
# Displaying the data in the report.&lt;br /&gt;
&lt;br /&gt;
One plugin may cover multiple steps. For example we expect that most of log writer plugins will also implement log reader. It is also possible to create a report that has built-in event handling, log writing and reading and report presentation (all four steps). Also external logging systems may not wish to allow log data they capture to be reported within Moodle, handling it through an external system, so they may not implement steps 3 and 4 at all.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Figure1&amp;quot; style=&amp;quot;text-align:center&amp;quot;&amp;gt;&lt;br /&gt;
[[File:logging_plugins_relation.png]]&lt;br /&gt;
&#039;&#039;&#039;Figure 1. Logging plugins relationship diagram&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The [[#Figure2|Figure 2]] below shows how the requests are made between user actions, plugins and core when:&lt;br /&gt;
&lt;br /&gt;
* configuring logging - which log writer plugins are enabled&lt;br /&gt;
* event occurs&lt;br /&gt;
* report - selecting log store&lt;br /&gt;
* viewing report&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;Figure2&amp;quot; style=&amp;quot;text-align:center&amp;quot;&amp;gt;&lt;br /&gt;
[[Image:logging_sequence.png|logging_sequence.png]]&lt;br /&gt;
&#039;&#039;&#039;Figure 2. Logging plugins sequence diagram&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Public API ==&lt;br /&gt;
&lt;br /&gt;
This section describes all interfaces that need to be implemented by log manager and each log storage class.&lt;br /&gt;
&lt;br /&gt;
=== Reading API ===&lt;br /&gt;
* &#039;&#039;&#039;function \get_log_manager()&#039;&#039;&#039; - returns the current log manager if configured or some dummy instance otherwise, it uses the signleton pattern.&lt;br /&gt;
* &#039;&#039;&#039;interface \core\log\manager&#039;&#039;&#039; - log manager interface, in standard distribution implemented by \tool_log\log\manager and \core\log\dummy_manager&lt;br /&gt;
** public function get_readers($interface = null) returns the active storages implementing reader interface, returns array(classname =&amp;gt; storage instance, ...)&lt;br /&gt;
* &#039;&#039;&#039;interface \core\log\reader&#039;&#039;&#039; - general event reader&lt;br /&gt;
** public function get_name() - returns name of the log storage, this will be used when selection data source in reports.&lt;br /&gt;
** public function get_description() - some help for admins.&lt;br /&gt;
** public function is_logging() - is latest data available?&lt;br /&gt;
* &#039;&#039;&#039;interface \core\log\sql_select_reader&#039;&#039;&#039; extends \core\log\reader - general log storage that supports sql selects (or emulates them)&lt;br /&gt;
** public function get_events_select($selectwhere, array $params, $order, $limitfrom, $limitnum) - returns event object instances matching given parameters.&lt;br /&gt;
** public function get_events_select_count($selectwhere, array $params) - returns number of events that would be returned from get_events() with the same parameters.&lt;br /&gt;
*** $selectwhere is supposed to be a limited sql predicate.&lt;br /&gt;
*** The set of operators allowed in $selectwhere are :- =, &amp;lt;&amp;gt;, &amp;gt;, &amp;gt;=, &amp;lt;, &amp;lt;=&lt;br /&gt;
*** The set of keywords allowed in $selectwhere are :- IN, BETWEEN, LIKE, IS NULL, IS NOT NULL&lt;br /&gt;
*** Logical operators OR, AND&lt;br /&gt;
*** NOT operator&lt;br /&gt;
*** ( and ) brackets&lt;br /&gt;
*** ? and :named parameter placeholders &lt;br /&gt;
*** Use of anything besides the mentioned keywords/operators is strictly forbidden.&lt;br /&gt;
* &#039;&#039;&#039;interface \core\log\sql_internal_reader&#039;&#039;&#039; extends \core\log\reader - log storage that can expose data as read-only database view or table.&lt;br /&gt;
** public function get_internal_log_table_name() - returns database table or view; structure is described in phpdocs, it will include all columns defined by log_sql&lt;br /&gt;
&lt;br /&gt;
Reports are expected to use only the reading API. Please note that all non-sql readers need to somehow translate the $selectwhere SQL query syntax.&lt;br /&gt;
&lt;br /&gt;
When reports are searching for log readers they use the get_log_manager()-&amp;gt;get_readers($interface = null) where $interface is the name of reader interface that the report supports.&lt;br /&gt;
If there are multiple readers returned by the log manager, then the report is responsible for letting the user choose which storage to create the report on.&lt;br /&gt;
&lt;br /&gt;
=== Writing API ===&lt;br /&gt;
* &#039;&#039;&#039;interface \tool_log\log\store&#039;&#039;&#039; - must be implemented by each store subplugin.&lt;br /&gt;
** public function __construct(\tool_log\log\manager $manager) - no parameters, configuration is taken from admin settings.&lt;br /&gt;
** public function dispose() - called when reading/writing finished.&lt;br /&gt;
* &#039;&#039;&#039;interface \tool_log\log\writer&#039;&#039;&#039; extends \tool_log\log\store - interface indicating the log store may be used for writing.&lt;br /&gt;
** public function write(\core\event\base $event) - called from event observer defined in log manager.&lt;br /&gt;
&lt;br /&gt;
The writing API is defined in tool_log plugin, the log stores are defined as new subplugin of this plugin.&lt;br /&gt;
&lt;br /&gt;
Each log store plugin will be responsible for filtering of events, it may use standardised admin settings and filtering or decide to implement custom filtering.&lt;br /&gt;
&lt;br /&gt;
== Standard logging plugins ==&lt;br /&gt;
&lt;br /&gt;
Standard Moodle distribution will include four plugins.&lt;br /&gt;
&lt;br /&gt;
=== Logging management plugin (tool_log) ===&lt;br /&gt;
&lt;br /&gt;
Defines:&lt;br /&gt;
&lt;br /&gt;
  class \tool_log\log\manager implements \core\log\manager;&lt;br /&gt;
&lt;br /&gt;
The log manager is responsible for step 1 from [[#Figure1|Figure 1]] above. It allows admins to configure which log store subplugin is enabled and in which order they appear. The log store plugins are implemented as tool_log subplugins with class &amp;quot;store&amp;quot; in their namespace (\logstore_xxxx\log\store).&lt;br /&gt;
&lt;br /&gt;
The log manager registers a &#039;*&#039; event observer, this observer is external - it means that events are received only when database transactions are not in progress.&lt;br /&gt;
&lt;br /&gt;
=== Standard log storage plugin (logstore_standard) ===&lt;br /&gt;
&lt;br /&gt;
Defines:&lt;br /&gt;
&lt;br /&gt;
  class \logstore_standard\log\store implements \core\log\sql_internal_reader, \tool_log\log\writer;&lt;br /&gt;
&lt;br /&gt;
The name logstore_standard does not seem to be optimal - &#039;&#039;logstore_db&#039;&#039; is not allowed because it collides with standard /db/ subdirectory in plugins and &#039;&#039;logstore_database&#039;&#039; should be probably reserved for external database logging (to prevent any confusion).&lt;br /&gt;
&lt;br /&gt;
This log storage plugin is responsible for steps 2 and 3 from [[#Figure1|Figure 1]] above. It is the primary replacement for the former {log} table. The performance will be similar to former log table, but for smaller sites, this simple default will suffice.&lt;br /&gt;
&lt;br /&gt;
Each plugin decides how much data is kept, when it is deleted, etc.&lt;br /&gt;
&lt;br /&gt;
==== Storage settings ====&lt;br /&gt;
&lt;br /&gt;
Each storage plugin with writer interface is responsible for backlisting or filtering of events. Some of the examples of filtering that can done is as below:-&lt;br /&gt;
* Include guests actions (default &#039;&#039;Yes&#039;&#039;).&lt;br /&gt;
* Include log levels (default &#039;&#039;empty&#039;&#039;), accepts constants from [[Event_2#Level_property]].&lt;br /&gt;
* Include by CRUD (default &#039;&#039;empty&#039;&#039;), accepts C, R, U, and D.&lt;br /&gt;
* Include by component (default &#039;&#039;empty&#039;&#039;)&lt;br /&gt;
* Include by event name (default &#039;&#039;empty&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
=== External database log storage plugin (logstore_database) ===&lt;br /&gt;
&lt;br /&gt;
Defines:&lt;br /&gt;
&lt;br /&gt;
  class \logstore_database\log\store implements \core\log\sql_select_reader, \tool_log\log\writer;&lt;br /&gt;
&lt;br /&gt;
This log storage plugin is responsible for step 2 only from [[#Figure1|Figure 1]] above. There will be no interface to read from it provided with Moodle core.&lt;br /&gt;
&lt;br /&gt;
=== Legacy log table reader (logstore_legacy) ===&lt;br /&gt;
&lt;br /&gt;
Defines:&lt;br /&gt;
&lt;br /&gt;
  class \logstore_legacy\log\store implements \core\log\sql_select_reader, \tool_log\log\store;&lt;br /&gt;
&lt;br /&gt;
This plugin will not conduct any log writing; it will translate existing {log} table data into the new event format and transforms new SQL selects to match the legacy table format. This serves as an emulation layer that allows new reports to access historical data stored in mdl_log table. Users will have to select this datasource manually if they want to see historical data that is not present in new log tables.&lt;br /&gt;
&lt;br /&gt;
In new reports the legacy data will be presented using a special legacy event class that can not be triggered: \logstore_legacy\event\legacy&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
Compared to older Moodle version the new system will need to deal with higher number of log entries. This was improved by buffering of log entries together with new improved bulk insert operations in the DML layer. Helper traits were introduced \tool_log\helper\buffered_writer to help stores easily buffer the events.&lt;br /&gt;
&lt;br /&gt;
Running new and old event logging at the same time with result in 2x number of DB inserts, it will be therefore recommended to disable the old logging as soon as possible.&lt;br /&gt;
&lt;br /&gt;
In [https://tracker.moodle.org/browse/MDL-42894 MDL-42894], logging api comparison is done and it seems promising. Results are:&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Enabled Stores&lt;br /&gt;
! dbwrites&lt;br /&gt;
! dbreads&lt;br /&gt;
! Time used&lt;br /&gt;
! Session size&lt;br /&gt;
! Memory&lt;br /&gt;
! Server load&lt;br /&gt;
|-&lt;br /&gt;
| Legacy + Standard store&lt;br /&gt;
| Little increase&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Increased&lt;br /&gt;
|-&lt;br /&gt;
| Only Standard store&lt;br /&gt;
| Decrease&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Increased&lt;br /&gt;
|-&lt;br /&gt;
| Only Legacy store&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Decrease&lt;br /&gt;
|-&lt;br /&gt;
| Neither Legacy nor Standard store&lt;br /&gt;
| Decrease&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Same&lt;br /&gt;
| Decrease&lt;br /&gt;
|}&lt;br /&gt;
FYI: Serverload is showing worse in most cases, but as this was done on my local machine with all interference, I am ignoring this for now.&lt;br /&gt;
--[[User:Rajesh Taneja|Rajesh Taneja]] ([[User talk:Rajesh Taneja|talk]]) 16:19, 14 February 2014 (WST)&lt;br /&gt;
&lt;br /&gt;
== Mockups ==&lt;br /&gt;
=== Log management page ===&lt;br /&gt;
[[File:event-observer.png |frame|center| Log management page]]&lt;br /&gt;
&lt;br /&gt;
=== Log store settings pages ===&lt;br /&gt;
[[File:event-observer-2.png |frame|center| settings page for a the standard log setup]]&lt;br /&gt;
[[File:external-log-settings.png |frame|center| settings page for an external log setup]]&lt;br /&gt;
&lt;br /&gt;
== Overarching considerations ==&lt;br /&gt;
&lt;br /&gt;
We can&#039;t actually predict all use cases, so we must think generically and plan for worst cases. Here are some overarching principles that will be followed in the implementation of the new logging system.&lt;br /&gt;
&lt;br /&gt;
* Things that don&#039;t need to use logs should not use logs. (Recent activity, etc)&lt;br /&gt;
* Logging calls should be as cheap as possible.&lt;br /&gt;
* The Events API will be the central communication mechanism, allowing lots of potential information gathering tools to exist in future.&lt;br /&gt;
* Use plug-ins to determine where to put logs permanently (NoSQL, SAS, file...). Initially, the default will be to the current log table.&lt;br /&gt;
* Log everything we possibly can think of.&lt;br /&gt;
* Define log level settings (on each logging call) so different sites can choose what they want logged, which allows controls cotrol of log size, speed, etc..&lt;br /&gt;
* Function add_to_log should be retained for backward compatibility, without changing existing implementation, but allowing admins to disable it.&lt;br /&gt;
&lt;br /&gt;
= Reports =&lt;br /&gt;
&lt;br /&gt;
[[Logging usage#Reports]] describes current reports.&lt;br /&gt;
&lt;br /&gt;
= Migration to new logging API =&lt;br /&gt;
&lt;br /&gt;
== Follow-up Projects ==&lt;br /&gt;
&lt;br /&gt;
* Converting completion to use events - MDL-42897&lt;br /&gt;
* Developing a &#039;&#039;Timeline&#039;&#039; page/block so each user to see a stream of activity that is relevant to them individually - MDL-42898&lt;br /&gt;
&lt;br /&gt;
== Related ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Here are some ideas of how new even data and observers can be put to use:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Please note that the log storage API is not optimised for these tasks.&lt;br /&gt;
* Timely notifications of critical events (defined by users), for example more than five people posted in the same forum within an hour.&lt;br /&gt;
* &amp;quot;Red circle&amp;quot; notification badge counter icons everywhere in Moodle highlighting things that a user needs to pay attention attention to, such as ???.&lt;br /&gt;
* Colour heatmaps overlaid on course pages showing recent usage patterns of the course.&lt;br /&gt;
* Visualisation of live activity across a whole site (for admins) (is that logging or event handling?)&lt;br /&gt;
* Live engagement analytics reporting ??? that take specific actions into account, such as ???.&lt;br /&gt;
* Identification of students at risk based on their involvement in the course (or lack of it).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Logging of exceptions, errors and debugging:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Logging of Errors and warnings is not part of this specification, it meeds to be handled via a completely separate mechanism.&lt;br /&gt;
** People report errors that cannot be duplicated. Logging errors with a stack trace, session variables and other relevant data could be useful for debugging.&lt;br /&gt;
* Standard logs may theoretically produce errors and exceptions that need to be logged somewhere else.&lt;br /&gt;
* There is no synchronization with server logs to help debugging performance issues. (This will not be addressed by new logging API.)&lt;br /&gt;
* There is no logging of error information to help debug Moodle issues. (This will not be addressed by new logging API.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Performance logging and profiling&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
We need to measure the performance of logging system and store the information somewhere.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Other&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* There is no mechanism for archiving, so old logs are deleted and lost.&lt;br /&gt;
* Log deletion is indiscriminate, with no control of what log information is deleted or retained.&lt;br /&gt;
&lt;br /&gt;
== Places where we need more logs ==&lt;br /&gt;
&lt;br /&gt;
The principle work of this project is to replace the existing logging API. Once the new system is in place, the coverage of logging around Moodle can be improved.&lt;br /&gt;
&lt;br /&gt;
Suggestions for places in Moodle where logging is needed should be reported as Tracker issues and linked to the Epic MDL-28443 &amp;quot;Action logging improvements&amp;quot;. Feel free to echo significant areas here.&lt;br /&gt;
&lt;br /&gt;
* Activities on site, course and activity administration pages.&lt;br /&gt;
* Micro activities in a page (more than one per load), such as ???.&lt;br /&gt;
* AJAX calls (eg on course page), such as ???.&lt;br /&gt;
* Logging of long events (such as an LDAP synchronisation) should have:&lt;br /&gt;
** one unique identifier per event (like for example postfix mail server) to help admin monitor the cron processes and&lt;br /&gt;
** at least 2 log entries (begining and end) for each event, possibly more.&lt;br /&gt;
* Should be careful about logging confidential information. The privacy is controlled by event access control and can_access() method in each storage plugin..&lt;br /&gt;
* Shouldn’t delete logs when course is deleted. There is no API to delete logs, each log storage controls the rotation or deleting of old data individually.&lt;br /&gt;
&lt;br /&gt;
=See also=&lt;br /&gt;
&lt;br /&gt;
* [[Event 2]]&lt;br /&gt;
* [[Migrating logging calls in plugins]]&lt;br /&gt;
* [[Migrating reports accessing logs]]&lt;br /&gt;
&lt;br /&gt;
Other logging systems:&lt;br /&gt;
* http://logstash.net/ &lt;br /&gt;
* http://fluentd.org/&lt;br /&gt;
* http://logging.apache.org/log4php/&lt;br /&gt;
&lt;br /&gt;
Examples of data-based learning technology development:&lt;br /&gt;
* http://onlinelibrary.wiley.com/doi/10.1111/j.1467-8535.2008.00928.x/abstract &lt;br /&gt;
* http://www.sciencedirect.com/science/article/pii/S0360131510000461 -&amp;gt; qtype_pmatch&lt;br /&gt;
* http://www.tandfonline.com/doi/abs/10.1080/02680513.2011.567754&lt;br /&gt;
* http://oro.open.ac.uk/24619/&lt;br /&gt;
* [http://www.adlnet.gov/tla/lrs/ A Learning Record Store (LRS)] is a system that stores the tracking statements communicated through the [https://github.com/adlnet/xAPI-Spec Experience API (xAPI)]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Events_API&amp;diff=44538</id>
		<title>Events API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Events_API&amp;diff=44538"/>
		<updated>2014-04-28T04:35:18Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: Cleanup the doc&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Project&lt;br /&gt;
|name = Events 2&lt;br /&gt;
|state = Completed&lt;br /&gt;
|tracker = MDL-39797 , MDL-39952, MDL-39846&lt;br /&gt;
|discussion = https://moodle.org/mod/forum/discuss.php?d=229425&lt;br /&gt;
|assignee = Backend Team&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
= What are events? =&lt;br /&gt;
&lt;br /&gt;
Events are atomic pieces of information describing something that happened in Moodle. Events are primarily the result of user actions, but could also be the result of the [[:en:Cron|cron]] process or administration actions [[:en:Administration via command line|undertaken via the command line]].&lt;br /&gt;
&lt;br /&gt;
When an action takes place, an event is created by a [[Core APIs|core API]] or [[Plugins|plugin]]. The Events system then disseminates this event information to observers registered for this event. In this way, the events system acts as a communication backbone throughout the Moodle system.&lt;br /&gt;
&lt;br /&gt;
Event observers can not modify event data or interrupt the dispatching of events, it is a one way communication channel.&lt;br /&gt;
&lt;br /&gt;
= Why is a new events system needed? =&lt;br /&gt;
&lt;br /&gt;
The need to improve the Events system was prompted by a need for a richer and more efficient logging system, however the benefits of this improvement will be useful to other parts of Moodle that observe event information.&lt;br /&gt;
&lt;br /&gt;
* The events need to be more strictly defined if we want to use them for new logging and other advanced use cases. They need to contain a lot more information in a standardised way (such as most fields from current log table and log_actions table).&lt;br /&gt;
* Complex data types were allowed in old events which was causing major problems when serialising/storing/unserializing the data.&lt;br /&gt;
* The logging and events contain similar information and are triggered at the same places, new events would remove this code duplication. All events should be loggable and all current log entries should be triggered as events.&lt;br /&gt;
* The logging system will become an event observer, listening to all events and directing them to logging storage plugins in a controllable way.&lt;br /&gt;
* It will be possible to subscribe to &#039;*&#039; event, which would allow a system to potentially observe, and selectively deal with, all events. Current handlers do not get event name which makes this problematic.&lt;br /&gt;
* Current event handlers may trigger exceptions during site upgrade which would lead to fatal upgrade problems. The new design eliminates this.&lt;br /&gt;
* Failure in handlers blocked dispatching of subsequent events. Instead problems in new observers would be only logged and execution would continue normally.&lt;br /&gt;
* Current execution of external handlers during DB transactions blocks other handlers. This would be eliminated by in-memory buffer for external events.&lt;br /&gt;
* It would good to have observer priority.&lt;br /&gt;
* Nested events are not dispatched sequentially, it would change the order of events received in lower priority handlers.&lt;br /&gt;
&lt;br /&gt;
= Performance =&lt;br /&gt;
Some basic profiling has been conducted.&lt;br /&gt;
&lt;br /&gt;
There is a general plan to complete pre- and post-implementation testing as development happens. The new system will be imemented in parallel with the old one which should help with comparison of new and old logging and event triggering performance on each page.&lt;br /&gt;
&lt;br /&gt;
Our aim is to trigger more events and log more information, which is going to impact on performance. We hope to offset that impact by improving log storage, simplifying event dispatching and adding other core performance improvements. The proposed class structure of the base event should allow some new advanced techniques, which may also improve performance in some scenarios.&lt;br /&gt;
&lt;br /&gt;
More details will be added to this section soon.&lt;br /&gt;
&lt;br /&gt;
= Events API =&lt;br /&gt;
&lt;br /&gt;
Each plugin will define the events that it can report (trigger) by extending an abstract base class, once for each possible event. This approach will have several benefits.&lt;br /&gt;
; Events will be active objects&lt;br /&gt;
: When they are triggered and possibly after they are reinstantiated (say, when they are retrieved from a log), an event object will be able to provide callback functions for various purposes (such as capability checks).&lt;br /&gt;
; Automatic inclusion&lt;br /&gt;
: Event class definitions will be automatically included when needed, without having to maintain lists of known event types. New event definitions can be added without the need to upgrade, only purging of MUC cache is required after adding new observer.&lt;br /&gt;
; Maintainability&lt;br /&gt;
: It will be easy to add new events and migrate existing events. Code review will be simplified because there will be less duplication of code when triggering events and all event related information/code will be concentrated in one file in fixed locations.&lt;br /&gt;
; Self documenting&lt;br /&gt;
: The behaviour of events will be combined with the definition of events in one place (file). It will be easy for event observer writers to know what events a plugin can trigger. This includes support for autocompletion and code inspection in modern IDEs.&lt;br /&gt;
; Quick, self-validating data structure&lt;br /&gt;
: As events are instantiated objects, the PHP processor will validate the structure and type of event classes. This does not ensure data value validity, but does give some assurance of consistency and it also detects common typos.&lt;br /&gt;
&lt;br /&gt;
== Backwards compatibility and migration ==&lt;br /&gt;
&lt;br /&gt;
Events:&lt;br /&gt;
* All legacy events in the standard distribution has been replaced with the new events api and events_trigger() has been deprecated.&lt;br /&gt;
* For events that already exist in Moodle 2.5 the additional legacy information has been added to the event data (in properties &#039;legacyeventname&#039; and &#039;legacyeventdata&#039;)&lt;br /&gt;
* The legacy events handling code is maintained  separately and will continue being supported in Moodle 2.x.&lt;br /&gt;
* All legacy events-handlers has been migrated to the new observers in standard distribution.&lt;br /&gt;
* In future, more subsystems may be migrated to events-observers, ex.: gradebook history, completion.&lt;br /&gt;
&lt;br /&gt;
Logging:&lt;br /&gt;
* Function add_to_log() has been deprecated with a notice as of Moodle 2.7.&lt;br /&gt;
* Existing add_to_log() parameters has been migrated inside new events method get_legacy_log_data() and core_event_base::trigger() calls add_to_log() automatically (this will depend on $CFG-&amp;gt;loglifetime setting for performance reasons).&lt;br /&gt;
&lt;br /&gt;
== Event dispatching and observers ==&lt;br /&gt;
&lt;br /&gt;
The new event dispatching system is completely separate from the old events code. Original event handlers are now called observers with the description stored in the same db/events.php file, but as a new array with a different format.&lt;br /&gt;
&lt;br /&gt;
=== Event observers ===&lt;br /&gt;
&lt;br /&gt;
The observers are described in db/events.php in the array $observers, the array is not indexed and contains a list of observers defined as an array with the following properties;&lt;br /&gt;
* eventname – fully qualified event class name or &amp;quot;*&amp;quot; indicating all events, ex.: &#039;&#039;\plugintype_pluginname\event\something_happened&#039;&#039;.&lt;br /&gt;
* callback - PHP callable type.&lt;br /&gt;
* includefile - optional. File to be included before calling the observer. Path relative to dirroot.&lt;br /&gt;
* priority - optional. Defaults to 0. Observers with higher priority are notified first.&lt;br /&gt;
* internal - optional. Defaults to true. Non-internal observers are not called during database transactions, but instead after a successful commit of the transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$observers = array(&lt;br /&gt;
&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;eventname&#039;   =&amp;gt; &#039;\core\event\sample_executed&#039;,&lt;br /&gt;
        &#039;callback&#039;    =&amp;gt; &#039;core_event_sample_observer::observe_one&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;eventname&#039;   =&amp;gt; &#039;\core\event\sample_executed&#039;,&lt;br /&gt;
        &#039;callback&#039;    =&amp;gt; &#039;core_event_sample_observer::external_observer&#039;,&lt;br /&gt;
        &#039;priority&#039;    =&amp;gt; 200,&lt;br /&gt;
        &#039;internal&#039;    =&amp;gt; false,&lt;br /&gt;
    ),&lt;br /&gt;
&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;eventname&#039;   =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;callback&#039;    =&amp;gt; &#039;core_event_sample_observer::observe_all&#039;,&lt;br /&gt;
        &#039;includefile&#039; =&amp;gt; null,&lt;br /&gt;
        &#039;internal&#039;    =&amp;gt; true,&lt;br /&gt;
        &#039;priority&#039;    =&amp;gt; 9999,&lt;br /&gt;
    ),&lt;br /&gt;
&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Event dispatching ===&lt;br /&gt;
&lt;br /&gt;
A list of available observers is constructed on the fly directly from all available in &#039;events.php&#039; files. Previously handlers were installed only during installation and upgrade. There is no risk of performance regression because the list is already cached in MUC. Observers get events before installation or any upgrade, however observers are not notified during the initial installation of Moodle core tables.&lt;br /&gt;
&lt;br /&gt;
Developers of observers must make sure that execution does not end with a fatal error under any condition (before install, before upgrade or normal operation). Exceptions are automatically captured, logged in the PHP error log, and notification of other observers continues. Current handlers must not throw any exceptions at any time.&lt;br /&gt;
&lt;br /&gt;
Observers are notified sequentially in the same order in which events were triggered. This means that events triggered in observers are queued in FIFO buffer and are processed after all observers are notified.&lt;br /&gt;
&lt;br /&gt;
=== Differences from old event handling ===&lt;br /&gt;
&lt;br /&gt;
# New events contain a lot more structured information.&lt;br /&gt;
# There is separate context cache which may be used when deleting data or for observer performance improvements.&lt;br /&gt;
# No database access in new event dispatching code.&lt;br /&gt;
# There is no support for cron execution - this eliminates performance problems, simplifies events dispatching and prevents abuse of cron events.&lt;br /&gt;
# Events triggered in observers are processed in a different order.&lt;br /&gt;
# External events are buffered when a transaction is in progress, instead of being sent to the cron queue.&lt;br /&gt;
# It is possible to define multiple observers for one event in one events.php file.&lt;br /&gt;
# It is possible to subscribe an observer to all events.&lt;br /&gt;
# The new event manager is using frankenstyle autoloading - smaller memory footprint when events are not used on the current page.&lt;br /&gt;
&lt;br /&gt;
== Triggering events ==&lt;br /&gt;
&lt;br /&gt;
* All event definitions are classes extending the \core\event\base class.&lt;br /&gt;
* Events are triggered by creating a new instance of the class event and executing $event-&amp;gt;trigger().&lt;br /&gt;
* Each event class name is a unique identifier of the event.&lt;br /&gt;
* Class names and namespace follow the identifier scheme \&#039;&#039;&#039;frankenstyle_component&#039;&#039;&#039;\event\&#039;&#039;&#039;some_object_action&#039;&#039;&#039;. Core events have prefix &#039;core_&#039;.&lt;br /&gt;
* Each event class is defined in a separate file. File name and location must match the class name for the use of auto loading, for example: &#039;&#039;&#039;plugindir&#039;&#039;&#039;/classes/event/&#039;&#039;&#039;something_happened&#039;&#039;&#039;.php&lt;br /&gt;
* The event identifier suffix has the form &#039;&#039;some_object_action&#039;&#039;  (&#039;&#039;&#039;something_happened&#039;&#039;&#039; in the example above) and should follow our standard naming convention. The last word after underscore is automatically parsed as action, the rest of word is object.&lt;br /&gt;
&lt;br /&gt;
Decision:[[#Verb_list| Recommended verb list]]&lt;br /&gt;
&lt;br /&gt;
Examples: \core\event\course_completed, \mod_assign\event\submission_commented, \mod_forum\event\post_shared, \mod_forum\event\post_responded, etc.&lt;br /&gt;
&lt;br /&gt;
* Ideally, it should be possible to trigger an event without gathering additional information for the event. To reduce the cost of data gathering, specifically the cost of database reads, at least the minimal values needed to trigger an event should be already available in variables.&lt;br /&gt;
&lt;br /&gt;
An example of triggering an event:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event = \mod_myplugin\event\something_happened::create(array(&#039;context&#039; =&amp;gt; $context, &#039;objectid&#039; =&amp;gt; YYY, &#039;other&#039; =&amp;gt; ZZZ));&lt;br /&gt;
// ... code that may add some record snapshots&lt;br /&gt;
$event-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Use of php autoloading ===&lt;br /&gt;
&lt;br /&gt;
All new OOP APIs in Moodle 2.6 onwards are going to use class auto loading - see [[Automatic class loading]]. New events use PHP strictly defined namespaces which concentrate all events classes in classes/event/ subdirectory.&lt;br /&gt;
&lt;br /&gt;
=== Why separate classes? ===&lt;br /&gt;
Pros&lt;br /&gt;
* Maintainability - It is much easier to review, debug, integrate.&lt;br /&gt;
* Self documenting, behaviour is combined with definition.&lt;br /&gt;
* It is extremely flexible for plugin developers and core devs too.&lt;br /&gt;
* Automatically lists events without being installed - PHPDocs as events documentation.&lt;br /&gt;
* It is included only when needed using autoloading.&lt;br /&gt;
* Self-validating data structure (by PHP).&lt;br /&gt;
* Some developers will find it easier to copy whole class files as templates.&lt;br /&gt;
Cons&lt;br /&gt;
* Big learning curve for developers without OOP skills (all other new subsystems in Moodle already use OOP, you can not code without these skills any more).&lt;br /&gt;
* Some developers may find it harder to copy-and-paste examples because they will need to create new class first and use it afterwards (this can be viewed as a benefit because it forces developers to think more about events).&lt;br /&gt;
&lt;br /&gt;
== Information contained in events ==&lt;br /&gt;
&lt;br /&gt;
Events have to contain as much information as they can, but this should not affect the performance. That&#039;s why part of the information is available in properties, and the rest via methods. This allows for delaying the computation of the data at the time it is really needed, if it ever is.&lt;br /&gt;
&lt;br /&gt;
=== Properties ===&lt;br /&gt;
&lt;br /&gt;
List of properties that the developer has to pass to the event upon creation, or automatically generated when possible and cost free. Some of those properties not mandatory.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Property name&lt;br /&gt;
! Title&lt;br /&gt;
! Type&lt;br /&gt;
! Required&lt;br /&gt;
! Comment&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;eventname&#039;&#039;&lt;br /&gt;
| Event name&lt;br /&gt;
| &#039;&#039;static, automatic from class name&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| Automatically computed by copying class name&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;component&#039;&#039;&lt;br /&gt;
| Component&lt;br /&gt;
| &#039;&#039;static, automatic from top namespace&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| Component declaring the event, automatically computed from class name.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;action&#039;&#039;&lt;br /&gt;
| Action&lt;br /&gt;
| &#039;&#039;static, automatic from last word in class name&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| Can be automatically computed from class name.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;target&#039;&#039;&lt;br /&gt;
| target of action&lt;br /&gt;
| &#039;&#039;static, automatic from class name&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| Target on which the action is taken, can be automatically computed from class name.&lt;br /&gt;
|-&lt;br /&gt;
| objecttable&lt;br /&gt;
| Database table name&lt;br /&gt;
| static&lt;br /&gt;
| optional (Must be set if objetid present)&lt;br /&gt;
| Database table name which represents the event object to the best. Never use a relationship table here.&lt;br /&gt;
|-&lt;br /&gt;
| objectid&lt;br /&gt;
| Object ID&lt;br /&gt;
| variable&lt;br /&gt;
| Optional (Must be set if objettable present)&lt;br /&gt;
| Id of the object record from objecttable.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;&#039;&#039;crud&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
| Transaction type&lt;br /&gt;
| &#039;&#039;static&#039;&#039;&lt;br /&gt;
| optional&lt;br /&gt;
| One of [crud] letters. Statically declared in the event class method init().&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;&#039;&#039;level&#039;&#039;&#039;&#039;&#039; / &#039;&#039;&#039;&#039;&#039;edulevel&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
| Level&lt;br /&gt;
| &#039;&#039;static&#039;&#039;&lt;br /&gt;
| optional&lt;br /&gt;
| Level of educational value of the event. Statically declared in the event class method init(). Changed from &#039;&#039;&#039;&#039;&#039;level&#039;&#039;&#039;&#039;&#039; to &#039;&#039;&#039;&#039;&#039;edulevel&#039;&#039;&#039;&#039;&#039; in Moodle 2.7 (See below for more details)&lt;br /&gt;
|-&lt;br /&gt;
| contextid&lt;br /&gt;
| Context ID&lt;br /&gt;
| mandatory&lt;br /&gt;
| -&lt;br /&gt;
|-&lt;br /&gt;
| contextlevel&lt;br /&gt;
| Context level&lt;br /&gt;
| automatic from context&lt;br /&gt;
| -&lt;br /&gt;
| This tells you if it was a course, activity, course category, etc.&lt;br /&gt;
|-&lt;br /&gt;
| contextinstanceid&lt;br /&gt;
| Context instanceid&lt;br /&gt;
| automatic from context&lt;br /&gt;
| -&lt;br /&gt;
| Based on context level this may be course id , course module id, course category, etc.&lt;br /&gt;
|-&lt;br /&gt;
| userid&lt;br /&gt;
| User ID&lt;br /&gt;
| defaults to current user&lt;br /&gt;
| -&lt;br /&gt;
| User ID, or 0 when not logged in, or -1 when other (System, CLI, Cron, ...)&lt;br /&gt;
|-&lt;br /&gt;
| courseid&lt;br /&gt;
| Affected course&lt;br /&gt;
| defaults to course context from context&lt;br /&gt;
| -&lt;br /&gt;
| This is used only for contexts at and bellow course level - this can be used to filter events by course (includes all course activities)&lt;br /&gt;
|-&lt;br /&gt;
| relateduserid&lt;br /&gt;
| Affected user&lt;br /&gt;
| variable&lt;br /&gt;
| optional&lt;br /&gt;
| Is this action related to some user? This could be used for some personal timeline view.&lt;br /&gt;
|-&lt;br /&gt;
| anonymous&lt;br /&gt;
| Anonymous action&lt;br /&gt;
| variable&lt;br /&gt;
| optional (Defaults to 0)&lt;br /&gt;
| Is this action anonymous? Reports should ignore events with anonymous set to 1.&lt;br /&gt;
|-&lt;br /&gt;
| other&lt;br /&gt;
| All other data&lt;br /&gt;
| variable array&lt;br /&gt;
| optional&lt;br /&gt;
| Any other fields needed for event description - scalars or arrays, must be serialisable using json_encode()&lt;br /&gt;
|-&lt;br /&gt;
| timecreated&lt;br /&gt;
| Time of the event&lt;br /&gt;
| automatic&lt;br /&gt;
| -&lt;br /&gt;
| Time when the event was triggered.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* static: It is the same for all event instances of this class.&lt;br /&gt;
* variable: It might not be same for all instances of this event class.&lt;br /&gt;
* mandatory&#039;: Is required in order to trigger the event.&lt;br /&gt;
* optional: Is not required to trigger the event.&lt;br /&gt;
&lt;br /&gt;
==== Level property ====&lt;br /&gt;
&lt;br /&gt;
The edulevel property helps defining the educational value of the event. It is intentional that the list is limited to only 3 different constants, having too many options would make it harder for developers to pick the right one(s). We also have to keep in mind that this is not supposed to answer all the questions about a particular event, other event properties like the courseid, the context, the component name can be used with the level to get more granular reports.&lt;br /&gt;
&lt;br /&gt;
Remember that this is event based. If the user that has triggered the event is not really &amp;quot;participating&amp;quot; because he is an admin, or a manager, then it is the job of the report to filter those. The event itself has a static educational level.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Teaching&#039;&#039;&#039; (LEVEL_TEACHING: 1)&lt;br /&gt;
&lt;br /&gt;
Any event/action that is performed by someone (typically a teacher) and has a teaching value (anything that is affecting the learning experience/environment of the students). This should not be combined with &amp;quot;Participating&amp;quot; events.&lt;br /&gt;
&lt;br /&gt;
Valid events:&lt;br /&gt;
&lt;br /&gt;
* A teacher grading a student&lt;br /&gt;
* A teacher modifying the course settings&lt;br /&gt;
* A teacher adding a new section to the course page&lt;br /&gt;
* A teacher modifying a module settings&lt;br /&gt;
* A teacher adding a page to course&lt;br /&gt;
* A teacher leaving a feedback&lt;br /&gt;
&lt;br /&gt;
INVALID events:&lt;br /&gt;
&lt;br /&gt;
* A teacher posting in a forum (it might affect the learning experience, but not necessarily, so the teacher is just participating)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Participating&#039;&#039;&#039; (LEVEL_PARTICIPATING: 2)&lt;br /&gt;
&lt;br /&gt;
Any event/action that is performed by a user, that is related (or could be related) to his learning experience.&lt;br /&gt;
&lt;br /&gt;
Valid events:&lt;br /&gt;
&lt;br /&gt;
* A user posting to a forum&lt;br /&gt;
* A user submitting an assignment&lt;br /&gt;
* A user blogging&lt;br /&gt;
* A user reading someone&#039;s blog&lt;br /&gt;
* A user posting a comment&lt;br /&gt;
* A user chatting on a chat activity&lt;br /&gt;
* A user viewing the course page&lt;br /&gt;
* A user deletes a blog post&lt;br /&gt;
&lt;br /&gt;
INVALID events:&lt;br /&gt;
&lt;br /&gt;
* A user updating his profile&lt;br /&gt;
* A user visiting someone&#039;s profile&lt;br /&gt;
* A user viewing his /my/ page&lt;br /&gt;
* A user sending a message to another one&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Other&#039;&#039;&#039; (LEVEL_OTHER: 0)&lt;br /&gt;
&lt;br /&gt;
Any other action, whether they are related to the site administration, or are specific to user. They do not have any educational value.&lt;br /&gt;
&lt;br /&gt;
=== Methods ===&lt;br /&gt;
&lt;br /&gt;
The computation of this data is not required by default, but can be accessed by any event observer if need be.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Comment&lt;br /&gt;
|-&lt;br /&gt;
| get_name()&lt;br /&gt;
| Returns localised name of the event, it is the same for all instances.&lt;br /&gt;
|-&lt;br /&gt;
| get_description()&lt;br /&gt;
| Returns non-localised description of one particular event. There are plans to make this localised in future.&lt;br /&gt;
|-&lt;br /&gt;
| can_view($user)&lt;br /&gt;
| This method is deprecated, please do not use this.&lt;br /&gt;
|-&lt;br /&gt;
| get_url()&lt;br /&gt;
| Returns Moodle URL where the event can be observed afterwards. Can be null, if no valid location is present.&lt;br /&gt;
|-&lt;br /&gt;
| get_legacy_eventname()&lt;br /&gt;
| Information necessary for event backward compatibility.&lt;br /&gt;
|-&lt;br /&gt;
| get_legacy_eventdata()&lt;br /&gt;
| Information necessary for event backward compatibility.&lt;br /&gt;
|-&lt;br /&gt;
| get_legacy_logdata()&lt;br /&gt;
| Information necessary for logging backward compatibility.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Record caching===&lt;br /&gt;
&lt;br /&gt;
The standard event data may not contain all the information observers need. The built-in record snapshot support in events allows developers to attach more auxiliary information when triggering events, it may be for example course record, some record that was just deleted, etc. &lt;br /&gt;
* Snapshots are expected to be an exact snapshot of the database table at the instance when the event was triggered.&lt;br /&gt;
* Snapshot can be set and requested for any table. If not cached, it defaults to direct $DB-&amp;gt;get_record calls.&lt;br /&gt;
* Please be aware that the snapshots are not stored in the event, and cannot be restored.&lt;br /&gt;
* Snapshot are supposed to be used only by observers. They should never be used by reports or by the event itself.&lt;br /&gt;
* When using a snapshot in an observer, please make sure you are taking proper care of handling exceptions as the record you are requesting could have been deleted in the time, in between your observer is notified about the event and the trigger.&lt;br /&gt;
* We recommend all delete event must add snapshot of the deleted record.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    $event = \core\event\role_assigned::create(&lt;br /&gt;
        array(&#039;context&#039;=&amp;gt;$context, &#039;objectid&#039;=&amp;gt;$ra-&amp;gt;roleid, &#039;relateduserid&#039;=&amp;gt;$ra-&amp;gt;userid,&lt;br /&gt;
            &#039;other&#039;=&amp;gt;array(&#039;id&#039;=&amp;gt;$ra-&amp;gt;id, &#039;component&#039;=&amp;gt;$ra-&amp;gt;component, &#039;itemid&#039;=&amp;gt;$ra-&amp;gt;itemid)));&lt;br /&gt;
    $event-&amp;gt;add_record_snapshot(&#039;role_assignments&#039;, $ra);&lt;br /&gt;
    $event-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    $event = \core\event\role_unassigned::create(&lt;br /&gt;
        array(&#039;context&#039;=&amp;gt;$context, &#039;objectid&#039;=&amp;gt;$ra-&amp;gt;roleid, &#039;relateduserid&#039;=&amp;gt;$ra-&amp;gt;userid,&lt;br /&gt;
            &#039;other&#039;=&amp;gt;array(&#039;id&#039;=&amp;gt;$ra-&amp;gt;id, &#039;component&#039;=&amp;gt;$ra-&amp;gt;component, &#039;itemid&#039;=&amp;gt;$ra-&amp;gt;itemid)));&lt;br /&gt;
    $event-&amp;gt;add_record_snapshot(&#039;role_assignments&#039;, $ra);&lt;br /&gt;
    $event-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The related methods are:&lt;br /&gt;
* public function add_record_snapshot($tablename, $record)&lt;br /&gt;
* public function get_record_snapshot($tablename, $id)&lt;br /&gt;
&lt;br /&gt;
== Events naming convention ==&lt;br /&gt;
&lt;br /&gt;
Clear event names help developers when reading what events are triggered, and defining the events properties when defining the event class.&lt;br /&gt;
&lt;br /&gt;
 Decision: \&amp;lt;component&amp;gt;\event\&amp;lt;some_object&amp;gt;_&amp;lt;verb&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Existing events ===&lt;br /&gt;
&lt;br /&gt;
List of existing events in Moodle code base, along with their 2.5 couterparts.&lt;br /&gt;
&lt;br /&gt;
This list is out of date. For a full list of events check out the [https://docs.moodle.org/en/Event_list_report Event list report] which is located in &amp;quot;Site administration &amp;gt; Reports &amp;gt; Event list&amp;quot; of your Moodle installation (2.7+).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fully qualified event name&lt;br /&gt;
! 2.5 name&lt;br /&gt;
! Component&lt;br /&gt;
! Object&lt;br /&gt;
! Action (Verb)&lt;br /&gt;
! Comment&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_comments\event\comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| assignsubmission_comments&lt;br /&gt;
| comment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_comments\event\comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| assignsubmission_comments&lt;br /&gt;
| comment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_file\event\assessable_uploaded&#039;&#039;&#039;&lt;br /&gt;
| assessable_file_uploaded&lt;br /&gt;
| assignsubmission_file&lt;br /&gt;
| assessable&lt;br /&gt;
| uploaded&lt;br /&gt;
| To be deprecated MDL-35197&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_file\event\submission_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| assignsubmission_file&lt;br /&gt;
| submission&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_file\event\submission_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| assignsubmission_file&lt;br /&gt;
| submission&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_onlinetext\event\assessable_uploaded&#039;&#039;&#039;&lt;br /&gt;
| assessable_content_uploaded&lt;br /&gt;
| assignsubmission_onlinetext&lt;br /&gt;
| assessable&lt;br /&gt;
| uploaded&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_onlinetext\event\submission_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| assignsubmission_onlinetext&lt;br /&gt;
| submission&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_onlinetext\event\submission_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| assignsubmission_onlinetext&lt;br /&gt;
| submission&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;block_comments\event\comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| block_comments&lt;br /&gt;
| comment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;block_comments\event\comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| block_comments&lt;br /&gt;
| comment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;booktool_exportimscp\event\book_exported&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| booktool_exportimscp&lt;br /&gt;
| book&lt;br /&gt;
| exported&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;booktool_print\event\book_printed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| booktool_print&lt;br /&gt;
| book&lt;br /&gt;
| printed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;booktool_print\event\chapter_printed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| booktool_print&lt;br /&gt;
| chapter&lt;br /&gt;
| printed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\assessable_submitted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| assessable&lt;br /&gt;
| submitted&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\assessable_uploaded&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| assessable&lt;br /&gt;
| uploaded&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\base&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| base&lt;br /&gt;
| -&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_association_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| blog_association&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| blog_comment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| blog_comment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_entries_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| blog_entries&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_entry_created&#039;&#039;&#039;&lt;br /&gt;
| blog_entry_added&lt;br /&gt;
| core&lt;br /&gt;
| blog_entry&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_entry_deleted&#039;&#039;&#039;&lt;br /&gt;
| blog_entry_deleted&lt;br /&gt;
| core&lt;br /&gt;
| blog_entry&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_entry_updated&#039;&#039;&#039;&lt;br /&gt;
| blog_entry_edited&lt;br /&gt;
| core&lt;br /&gt;
| blog_entry&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\cohort_created&#039;&#039;&#039;&lt;br /&gt;
| cohort_added&lt;br /&gt;
| core&lt;br /&gt;
| cohort&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\cohort_deleted&#039;&#039;&#039;&lt;br /&gt;
| cohort_deleted&lt;br /&gt;
| core&lt;br /&gt;
| cohort&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\cohort_member_added&#039;&#039;&#039;&lt;br /&gt;
| cohort_member_added&lt;br /&gt;
| core&lt;br /&gt;
| cohort_member&lt;br /&gt;
| added&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\cohort_member_removed&#039;&#039;&#039;&lt;br /&gt;
| cohort_member_removed&lt;br /&gt;
| core&lt;br /&gt;
| cohort_member&lt;br /&gt;
| removed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\cohort_updated&#039;&#039;&#039;&lt;br /&gt;
| cohort_updated&lt;br /&gt;
| core&lt;br /&gt;
| cohort&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| comment&lt;br /&gt;
| created&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| comment&lt;br /&gt;
| deleted&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\comments_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| comments&lt;br /&gt;
| viewed&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\content_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| content&lt;br /&gt;
| viewed&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_category_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_category&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_category_deleted&#039;&#039;&#039;&lt;br /&gt;
| course_category_deleted&lt;br /&gt;
| core&lt;br /&gt;
| course_category&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_category_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_category&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_completed&#039;&#039;&#039;&lt;br /&gt;
| course_completed&lt;br /&gt;
| core&lt;br /&gt;
| course&lt;br /&gt;
| completed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_completion_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_completion&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_content_deleted&#039;&#039;&#039;&lt;br /&gt;
| course_content_removed&lt;br /&gt;
| core&lt;br /&gt;
| course_content&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_created&#039;&#039;&#039;&lt;br /&gt;
| course_created&lt;br /&gt;
| core&lt;br /&gt;
| course&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_deleted&#039;&#039;&#039;&lt;br /&gt;
| course_deleted&lt;br /&gt;
| core&lt;br /&gt;
| course&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_completion_updated&#039;&#039;&#039;&lt;br /&gt;
| activity_completion_changed&lt;br /&gt;
| core&lt;br /&gt;
| course_module_completion&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_created&#039;&#039;&#039;&lt;br /&gt;
| mod_created&lt;br /&gt;
| core&lt;br /&gt;
| course_module&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_deleted&#039;&#039;&#039;&lt;br /&gt;
| mod_deleted&lt;br /&gt;
| core&lt;br /&gt;
| course_module&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_instances_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_module_instances_list&lt;br /&gt;
| viewed&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_updated&#039;&#039;&#039;&lt;br /&gt;
| mod_updated&lt;br /&gt;
| core&lt;br /&gt;
| course_module&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_reset_ended&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_reset&lt;br /&gt;
| ended&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_reset_started&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_reset&lt;br /&gt;
| started&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_restored&#039;&#039;&#039;&lt;br /&gt;
| course_restored&lt;br /&gt;
| core&lt;br /&gt;
| course&lt;br /&gt;
| restored&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_section_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_section&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_updated&#039;&#039;&#039;&lt;br /&gt;
| course_updated&lt;br /&gt;
| core&lt;br /&gt;
| course&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\email_failed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| email&lt;br /&gt;
| failed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\group_created&#039;&#039;&#039;&lt;br /&gt;
| groups_group_created&lt;br /&gt;
| core&lt;br /&gt;
| group&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\group_deleted&#039;&#039;&#039;&lt;br /&gt;
| groups_group_deleted&lt;br /&gt;
| core&lt;br /&gt;
| group&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\group_member_added&#039;&#039;&#039;&lt;br /&gt;
| groups_member_added&lt;br /&gt;
| core&lt;br /&gt;
| group_member&lt;br /&gt;
| added&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\group_member_removed&#039;&#039;&#039;&lt;br /&gt;
| groups_member_removed&lt;br /&gt;
| core&lt;br /&gt;
| group_member&lt;br /&gt;
| removed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\group_updated&#039;&#039;&#039;&lt;br /&gt;
| groups_group_updated&lt;br /&gt;
| core&lt;br /&gt;
| group&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\grouping_created&#039;&#039;&#039;&lt;br /&gt;
| groups_grouping_created&lt;br /&gt;
| core&lt;br /&gt;
| grouping&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\grouping_deleted&#039;&#039;&#039;&lt;br /&gt;
| groups_grouping_deleted&lt;br /&gt;
| core&lt;br /&gt;
| grouping&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\grouping_updated&#039;&#039;&#039;&lt;br /&gt;
| groups_grouping_updated&lt;br /&gt;
| core&lt;br /&gt;
| grouping&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\manager&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| manager&lt;br /&gt;
| anager&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\mnet_access_control_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| mnet_access_control&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\mnet_access_control_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| mnet_access_control&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\note_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| note&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\note_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| note&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\note_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| note&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\notes_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| notes&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_allow_assign_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| role_allow_assign&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_allow_override_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| role_allow_override&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_allow_switch_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| role_allow_switch&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_assigned&#039;&#039;&#039;&lt;br /&gt;
| role_assigned&lt;br /&gt;
| core&lt;br /&gt;
| role&lt;br /&gt;
| assigned&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_capabilities_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| role_capabilities&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| role&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_unassigned&#039;&#039;&#039;&lt;br /&gt;
| role_unassigned&lt;br /&gt;
| core&lt;br /&gt;
| role&lt;br /&gt;
| unassigned&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_created&#039;&#039;&#039;&lt;br /&gt;
| user_created&lt;br /&gt;
| core&lt;br /&gt;
| user&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_deleted&#039;&#039;&#039;&lt;br /&gt;
| user_deleted&lt;br /&gt;
| core&lt;br /&gt;
| user&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_enrolment_created&#039;&#039;&#039;&lt;br /&gt;
| user_enrolled&lt;br /&gt;
| core&lt;br /&gt;
| user_enrolment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_enrolment_deleted&#039;&#039;&#039;&lt;br /&gt;
| user_unenrolled&lt;br /&gt;
| core&lt;br /&gt;
| user_enrolment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_enrolment_updated&#039;&#039;&#039;&lt;br /&gt;
| user_enrol_modified&lt;br /&gt;
| core&lt;br /&gt;
| user_enrolment&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| user_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_loggedin&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| user&lt;br /&gt;
| loggedin&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_loggedinas&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| user&lt;br /&gt;
| loggedinas&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_loggedout&#039;&#039;&#039;&lt;br /&gt;
| user_logout&lt;br /&gt;
| core&lt;br /&gt;
| user&lt;br /&gt;
| loggedout&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_login_failed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| user_login&lt;br /&gt;
| failed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_profile_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| user_profile&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_updated&#039;&#039;&#039;&lt;br /&gt;
| user_updated&lt;br /&gt;
| core&lt;br /&gt;
| user&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_function_called&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_function&lt;br /&gt;
| called&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_login_failed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_login&lt;br /&gt;
| failed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_service_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_service&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_service_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_service&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_service_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_service&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_service_user_added&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_service_user&lt;br /&gt;
| added&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_service_user_removed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_service_user&lt;br /&gt;
| removed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_token_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_token&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_token_sent&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_token&lt;br /&gt;
| sent&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;logstore_legacy\event\legacy_logged&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| logstore_legacy&lt;br /&gt;
| legacy&lt;br /&gt;
| logged&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\all_submissions_downloaded&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| all_submissions&lt;br /&gt;
| downloaded&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\assessable_submitted&#039;&#039;&#039;&lt;br /&gt;
| assessable_submitted&lt;br /&gt;
| mod_assign&lt;br /&gt;
| assessable&lt;br /&gt;
| submitted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\extension_granted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| extension&lt;br /&gt;
| granted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\identities_revealed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| identities&lt;br /&gt;
| revealed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\marker_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| marker&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\statement_accepted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| statement&lt;br /&gt;
| accepted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission&lt;br /&gt;
| created&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_duplicated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission&lt;br /&gt;
| duplicated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_graded&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission&lt;br /&gt;
| graded&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_locked&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission&lt;br /&gt;
| locked&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_status_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission_status&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_unlocked&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission&lt;br /&gt;
| unlocked&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission&lt;br /&gt;
| updated&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\workflow_state_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| workflow_state&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_book\event\chapter_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_book&lt;br /&gt;
| chapter&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_book\event\chapter_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_book&lt;br /&gt;
| chapter&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_book\event\chapter_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_book&lt;br /&gt;
| chapter&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_book\event\chapter_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_book&lt;br /&gt;
| chapter&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_book\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_book&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_book\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_book&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_chat\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_chat&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_chat\event\message_sent&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_chat&lt;br /&gt;
| message&lt;br /&gt;
| sent&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_chat\event\sessions_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_chat&lt;br /&gt;
| sessions&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_choice\event\answer_submitted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_choice&lt;br /&gt;
| answer&lt;br /&gt;
| submitted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_choice\event\answer_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_choice&lt;br /&gt;
| answer&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_choice\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_choice&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_choice\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_choice&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_choice\event\report_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_choice&lt;br /&gt;
| report&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| comment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| comment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\field_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| field&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\field_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| field&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\field_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| field&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\record_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| record&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\record_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| record&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\record_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| record&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\template_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| template&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\template_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| template&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_feedback\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_feedback&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_feedback\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_feedback&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_feedback\event\response_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_feedback&lt;br /&gt;
| response&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_feedback\event\response_submitted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_feedback&lt;br /&gt;
| response&lt;br /&gt;
| submitted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_folder\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_folder&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_folder\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_folder&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_folder\event\folder_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_folder&lt;br /&gt;
| folder&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\assessable_uploaded&#039;&#039;&#039;&lt;br /&gt;
| assessable_content_uploaded&lt;br /&gt;
| mod_forum&lt;br /&gt;
| assessable&lt;br /&gt;
| uploaded&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\course_searched&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| course&lt;br /&gt;
| searched&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\discussion_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| discussion&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\discussion_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| discussion&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\discussion_moved&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| discussion&lt;br /&gt;
| moved&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\discussion_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| discussion&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\discussion_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| discussion&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\forum_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| forum&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\post_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| post&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\post_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| post&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\post_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| post&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\readtracking_disabled&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| readtracking&lt;br /&gt;
| disabled&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\readtracking_enabled&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| readtracking&lt;br /&gt;
| enabled&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\subscribers_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| subscribers&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\subscription_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| subscription&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\subscription_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| subscription&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\userreport_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| userreport&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_glossary\event\comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_glossary&lt;br /&gt;
| comment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_glossary\event\comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_glossary&lt;br /&gt;
| comment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\essay_assessed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| essay&lt;br /&gt;
| assessed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\essay_attempt_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| essay_attempt&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\highscore_added&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| highscore&lt;br /&gt;
| added&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\highscores_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| highscores&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\lesson_ended&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| lesson&lt;br /&gt;
| ended&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\lesson_started&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| lesson&lt;br /&gt;
| started&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lti\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lti&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lti\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lti&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lti\event\unknown_service_api_called&#039;&#039;&#039;&lt;br /&gt;
| lti_unknown_service_api_call&lt;br /&gt;
| mod_lti&lt;br /&gt;
| unknown_service_api&lt;br /&gt;
| called&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_page\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_page&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_page\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_page&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_quiz\event\attempt_abandoned&#039;&#039;&#039;&lt;br /&gt;
| quiz_attempt_abandoned&lt;br /&gt;
| mod_quiz&lt;br /&gt;
| attempt&lt;br /&gt;
| abandoned&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_quiz\event\attempt_becameoverdue&#039;&#039;&#039;&lt;br /&gt;
| quiz_attempt_overdue&lt;br /&gt;
| mod_quiz&lt;br /&gt;
| attempt&lt;br /&gt;
| becameoverdue&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_quiz\event\attempt_started&#039;&#039;&#039;&lt;br /&gt;
| quiz_attempt_started&lt;br /&gt;
| mod_quiz&lt;br /&gt;
| attempt&lt;br /&gt;
| started&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_quiz\event\attempt_submitted&#039;&#039;&#039;&lt;br /&gt;
| quiz_attempt_submitted&lt;br /&gt;
| mod_quiz&lt;br /&gt;
| attempt&lt;br /&gt;
| submitted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_resource\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_resource&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_resource\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_resource&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\attempt_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| attempt&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\interactions_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| interactions&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\report_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| report&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\sco_launched&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| sco&lt;br /&gt;
| launched&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\tracks_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| tracks&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\user_report_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| user_report&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_url\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_url&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_url\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_url&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| comment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| comment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\comments_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| comments&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_diff_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_diff&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_history_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_history&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_locks_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_locks&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_map_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_map&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_version_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_version&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_version_restored&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_version&lt;br /&gt;
| restored&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_version_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_version&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\assessable_uploaded&#039;&#039;&#039;&lt;br /&gt;
| assessable_content_uploaded&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| assessable&lt;br /&gt;
| uploaded&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\assessment_evaluated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| assessment&lt;br /&gt;
| evaluated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\assessment_evaluations_reset&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| assessment_evaluations&lt;br /&gt;
| reset&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\assessment_reevaluated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| assessment&lt;br /&gt;
| reevaluated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| workshop_viewed&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\instances_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| instances_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\phase_switched&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| phase&lt;br /&gt;
| switched&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\submission_assessed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| submission&lt;br /&gt;
| assessed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\submission_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| submission&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\submission_reassessed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| submission&lt;br /&gt;
| reassessed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\submission_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| submission&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\submission_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| submission&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;report_log\event\content_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| report_log&lt;br /&gt;
| content&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;report_loglive\event\content_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| report_loglive&lt;br /&gt;
| content&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;report_outline\event\content_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| report_outline&lt;br /&gt;
| content&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;report_participation\event\content_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| report_participation&lt;br /&gt;
| content&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;report_stats\event\content_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| report_stats&lt;br /&gt;
| content&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Verb list ===&lt;br /&gt;
All events must use a verb from this list. New verbs should be added to this list if required.&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!verb&lt;br /&gt;
!Explanation&lt;br /&gt;
!Source&lt;br /&gt;
|-&lt;br /&gt;
|abandoned&lt;br /&gt;
|When a attempt is abandoned by user (Quiz attempt)&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|accepted&lt;br /&gt;
|Example: Accepting a statement when submitting an assignment.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|added&lt;br /&gt;
|	Used to represent &amp;quot;something that already exists is now part of/bound to another entity&amp;quot;. Examples: &amp;quot;Admin added role to user X&amp;quot;, &amp;quot;Admin added user X to group A&amp;quot;. Wrong example: &amp;quot;User added course in category&amp;quot; because it is a &#039;move&#039; action, except if a course can be part of multiple categories. The good examples work because: A user can have multiple roles, a user can be in multiple groups.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|answered&lt;br /&gt;
| Indicates the actor responded to a Question&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|assessed&lt;br /&gt;
| Some submitted material has been assessed&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|assigned&lt;br /&gt;
| Assign some privilege or role to user.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|attempted&lt;br /&gt;
| Trying to do an activity. Example: attempting a Math class.&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|awarded&lt;br /&gt;
| ex:-teacher awarded student a badge.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|backedup&lt;br /&gt;
| When a backup has been performed.&lt;br /&gt;
|Moodle	&lt;br /&gt;
|-&lt;br /&gt;
|becomeoverdue&lt;br /&gt;
| When an activity is overdue Example: Quiz attempt is overdue&lt;br /&gt;
|Moodle	&lt;br /&gt;
|-&lt;br /&gt;
|called&lt;br /&gt;
| When a call to something is made like an API @see unknown_service_api_called.php&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|commented&lt;br /&gt;
|Offered an opinion or written experience of the activity. Can be used with the learner as the actor or a system as an actor. Comments can be sent from either party with the idea that the other will read and react to the content.&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|completed&lt;br /&gt;
|To experience the activity in its entirety. Used to affirm the completion of content. This can be simply experiencing all the content, be tied to objectives or interactions, or determined in any other way. Any content that has been initialized, but not yet completed, should be considered incomplete. There is no verb to &#039;incomplete&#039; an activity, one would void the statement which completes the activity.&amp;quot;&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|created&lt;br /&gt;
|Used to represent &amp;quot;something new has been created&amp;quot;.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|deleted&lt;br /&gt;
|Used to indicate the object in context was deleted.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|disabled&lt;br /&gt;
|When an activity is disabled. Example: forum read tracking disabled.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|downloaded&lt;br /&gt;
|When a user download file from user. Example submission/report downloaded.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|duplicated&lt;br /&gt;
|For something that has been copied.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|enabled&lt;br /&gt;
|When some setting is enabled. Example: forum read tracking enabled.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|ended&lt;br /&gt;
|When a process ends. Example: Lesson ended or course reset ended.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|evaluated&lt;br /&gt;
|Material has been evaluated.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|exported&lt;br /&gt;
|When a report is exported in certain format.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|failed&lt;br /&gt;
|Learner did not perform the activity to a level of pre-determined satisfaction. Used to affirm the lack of success a learner experienced within the learning content in relation to a threshold. If the user performed below the minimum to the level of this threshold, the content is &#039;failed&#039;. The opposite of &#039;passed&#039;. This is also used in case when message sending is failed.&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|graded&lt;br /&gt;
|Used to represent an activity was graded.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|granted&lt;br /&gt;
|User is granted some extension or capability. Example: extension granted for submission.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|imported&lt;br /&gt;
|The act of moving an object into another location or system.&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|launched&lt;br /&gt;
|When an external object is launched. Try consider started if there is related stopped event.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|locked&lt;br /&gt;
|When an activity is locked. Should have a related unlocked event.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|loggedin/loggedout&lt;br /&gt;
|	For login and logout.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|loggedinas&lt;br /&gt;
|	 If user is logged in as different user. This is used by only one event (user_loggedinas). Adding this verb makes event name more clear, then using loggedin verb.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|locked&lt;br /&gt;
|&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|moved&lt;br /&gt;
|	Used to indicate the object in context was moved.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|passed&lt;br /&gt;
|Used to affirm the success a learner experienced within the learning content in relation to a threshold. If the user performed at a minimum to the level of this threshold, the content is &#039;passed&#039;. The opposite of &#039;failed&#039;.&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|printed&lt;br /&gt;
|Something is printed.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|reassessed&lt;br /&gt;
|Submitted material has been assessed again.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|reevaluated&lt;br /&gt;
|Material has been evaluated again.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|removed&lt;br /&gt;
|By opposition to &amp;quot;Added&amp;quot;. This does not mean that the object has been deleted, but removed from the entity, or not bound to it any more.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|reset&lt;br /&gt;
|Sets one or more properties back to the default value.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|restored&lt;br /&gt;
|When restoring a backup. Rolling back to a previous state.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|revealed&lt;br /&gt;
|Some identity is revealed. Example: Identities revealed after blind marking.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|searched&lt;br /&gt;
|Something is searched. Example: searched in course.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|sent&lt;br /&gt;
|Message sent.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|started&lt;br /&gt;
|Some activity started&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|submitted&lt;br /&gt;
|This is very close to &amp;quot;Attempted&amp;quot;. Depends on context which one should be used. For example:- &amp;quot;Admin submitted a form. Student attempted a quiz.&amp;quot;  is correct, however some cases might not be as clear as the previous example. We can say both &amp;quot;Student submitted an assignment&amp;quot; or &amp;quot;student attempted an assignment&amp;quot;. We need to make the difference clear.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|suspended&lt;br /&gt;
| Suspend something. (example a user)&lt;br /&gt;
| Tincan (However the context is different)&lt;br /&gt;
|-&lt;br /&gt;
|switched&lt;br /&gt;
|Something has been switched. For example:- The workshop phase has been switched to assessment&amp;quot;&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|unassigned&lt;br /&gt;
|As opposed to assigned. When some role is unassigned.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|unlocked&lt;br /&gt;
|&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|upgraded&lt;br /&gt;
|Something was upgraded, some module probably&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|updated&lt;br /&gt;
|Used to indicate the object in context was updated. Simple example is &amp;quot;Admin updated course xyz&amp;quot;.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|uploaded&lt;br /&gt;
|When an assignment is uploaded.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|viewed&lt;br /&gt;
|Something has been viewed. For example:- &amp;quot;Student viewed chapter 1 of book 1.&amp;quot;&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Rules ===&lt;br /&gt;
&lt;br /&gt;
==== Use singular ====&lt;br /&gt;
&lt;br /&gt;
Plurals must be used on objects when it&#039;s a &#039;&#039;One to Many&#039;&#039; relationship. Ex: bulk import, mass deletion, ... In any other case, use the singular.&lt;br /&gt;
&lt;br /&gt;
==== Ends with a verb ====&lt;br /&gt;
&lt;br /&gt;
The last word (after the last underscore) must be a verb.&lt;br /&gt;
&lt;br /&gt;
=== Deprecated events ===&lt;br /&gt;
Following are the events that were supported in 2.5, but deprecated in 2.6 or later&lt;br /&gt;
&lt;br /&gt;
groups_groupings_deleted (see MDL-41312)&lt;br /&gt;
&lt;br /&gt;
groups_groupings_groups_removed (see MDL-41312)&lt;br /&gt;
&lt;br /&gt;
groups_groups_deleted (see MDL-41312)&lt;br /&gt;
&lt;br /&gt;
groups_members_removed (see MDL-41312)&lt;br /&gt;
&lt;br /&gt;
== Shared events ==&lt;br /&gt;
&lt;br /&gt;
 Decision: Not supported at this stage.&lt;br /&gt;
&lt;br /&gt;
In Moodle 2.5 we have a good example of a shared event: &#039;assessable_content_uploaded&#039; which is triggered in &#039;&#039;forum&#039;&#039;, &#039;assignment&#039;&#039; and &#039;&#039;workshop&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The problem with shared events is that we cannot easily track what component triggered them. Of course we could add a new property to the event to keep track of that, but we would soon need more information and more properties. Also, in the case of a logger, the event received would be unique, where in fact it should be considered different depending on the component firing it.&lt;br /&gt;
&lt;br /&gt;
In our first implementation, we will create one specific event per module. This flexibility does not prevent any observer from capturing them, but still makes sure that the consistency and specificity of each event is maintained.&lt;br /&gt;
&lt;br /&gt;
It could happen that some events are defined in core and shared, but this should not really happen as low-level APIs should trigger the event, and a module should call that low API instead of doing the job itself.&lt;br /&gt;
&lt;br /&gt;
== One to many ==&lt;br /&gt;
&lt;br /&gt;
 Decision: Each event should have a one to one relationship. We can reconsider this at a later stage, if the performance hit is extremely high.&lt;br /&gt;
&lt;br /&gt;
In 2.5, some events are triggered when an action happens on multiple objects. We have to decide whether we want to keep supporting &#039;&#039;One to Many&#039;&#039; events or not.&lt;br /&gt;
&lt;br /&gt;
Keeping a list of all changes for multiple actions may be problematic because you would have to keep them all in memory until all things are processed. This might also result in the order of events being incorrect. The only correct solution seems to be to trigger each item individually and then many things at the end. Performance needs to be improved elsewhere...&lt;br /&gt;
&lt;br /&gt;
=== Accuracy ===&lt;br /&gt;
&lt;br /&gt;
When uploading a bunch of users using the CSV upload feature, if only one event is triggered, it means that the observers of &#039;&#039;user_created&#039;&#039; won&#039;t be triggered. And so some functionality can be lost as, as a plugin developer, I expect this &#039;&#039;user_created&#039;&#039; to be triggered regardless of the way they have been uploaded. Of course, the developer could observe the event &#039;&#039;bulk_user_imported&#039;&#039;, but that means that he could miss some relevant observers.&lt;br /&gt;
&lt;br /&gt;
This applies to existing events.&lt;br /&gt;
&lt;br /&gt;
=== Performance ===&lt;br /&gt;
&lt;br /&gt;
Triggering one event is cheaper then repeating the same events x number of times...&lt;br /&gt;
&lt;br /&gt;
=== Information tracking ===&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;bulk&#039;&#039; event, might not be verbose enough to allow for proper logging afterwards. Though this is the responsibility of the logger, we probably want to make it easy to store relevant information.&lt;br /&gt;
&lt;br /&gt;
=== Double event ===&lt;br /&gt;
&lt;br /&gt;
In the case of a bulk user import, if we were to trigger an event per user created, we probably want to trigger one event &#039;user_bulk_upload_started&#039; when the action starts.&lt;br /&gt;
&lt;br /&gt;
== Unit Testing ==&lt;br /&gt;
&lt;br /&gt;
With unit testing for this system we want to assert the following:&lt;br /&gt;
&lt;br /&gt;
* That event strict validation and custom validation works.&lt;br /&gt;
* Missing event data is auto filled with accurate data.&lt;br /&gt;
* Typos in properties passed to ::create() are captured (if we decide to validate).&lt;br /&gt;
* The legacy methods return the expected values (use assertEventLegacyData() and assertEventLegacyData())&lt;br /&gt;
* The class properties are correctly overridden (crud, level, action, object, ...).&lt;br /&gt;
* The properties automatically generated (component, name, ...) are correct.&lt;br /&gt;
* Events are dispatched to the corresponding observers.&lt;br /&gt;
* Events are dispatched to the corresponding legacy handlers.&lt;br /&gt;
* Events are dispatched to the * observers.&lt;br /&gt;
* Events perform an add_to_log() if it has legacy log data.&lt;br /&gt;
* &#039;Events restore&#039; restored the whole event data, and does not miss any information.&lt;br /&gt;
* &#039;Events restore&#039; does not generate any extra information.&lt;br /&gt;
* Event methods should check context object or avoid using it, as context might not be valid at time of event restore (use assertEventContextNotUsed())&lt;br /&gt;
&lt;br /&gt;
= PHP docs =&lt;br /&gt;
* All events php docs must include @since parameter, indicating when the event was first included in standard Moodle distribution.&lt;br /&gt;
* All events must declare the $other properties using mark down in the php docs. This later might be converted to a self documenting structure. (See MDL-45108)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * blog_association_created&lt;br /&gt;
 *&lt;br /&gt;
 * Class for event to be triggered when a new blog entry is associated with a context.&lt;br /&gt;
 *&lt;br /&gt;
 * @property-read array $other {&lt;br /&gt;
 *      Extra information about event.&lt;br /&gt;
 *&lt;br /&gt;
 *      - string associatetype: type of blog association, course/coursemodule.&lt;br /&gt;
 *      - int blogid: id of blog.&lt;br /&gt;
 *      - int associateid: id of associate.&lt;br /&gt;
 *      - string subject: blog subject.&lt;br /&gt;
 * }&lt;br /&gt;
 *&lt;br /&gt;
 * @package    core&lt;br /&gt;
 * @since      Moodle 2.7&lt;br /&gt;
 * @copyright  2013 onwards Ankit Agarwal&lt;br /&gt;
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Example events =&lt;br /&gt;
&lt;br /&gt;
== Assignment ==&lt;br /&gt;
&lt;br /&gt;
Assumption: Course contains groups with students in each group.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.&#039;&#039;&#039; Teacher creates an assignment with group mode set to &#039;Separate groups&#039; and Feedback type set to comments and files.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has created assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;2.&#039;&#039;&#039; A student views the assignment.&lt;br /&gt;
*Event: User &#039;Student&#039; has viewed assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;3.&#039;&#039;&#039; A member from one of the groups submits an assignment&lt;br /&gt;
*Event: User &#039;Student&#039; has added a submission for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to the teacher and all students in that group.&lt;br /&gt;
&#039;&#039;&#039;4.&#039;&#039;&#039; User &#039;Adrian&#039; adds some changes to the assignment and updates it.&lt;br /&gt;
*Event: User &#039;Adrian&#039; has updated the submission for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to the teacher and all students in that group.&lt;br /&gt;
&#039;&#039;&#039;5.&#039;&#039;&#039; Teacher views the assignment.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has viewed assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;6.&#039;&#039;&#039; Teacher clicks on &#039;View/grade all submissions&#039;&lt;br /&gt;
*Event: User &#039;Teacher&#039; has viewed the assignment &#039;B&#039; grade area in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;7.&#039;&#039;&#039; Teacher clicks to grade the student&#039;s submission.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has viewed the submission for user &#039;student&#039; for assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;8.&#039;&#039;&#039; Teacher marks the assignment with the setting &#039;Apply grades and feedback to entire group&#039; set to &#039;Yes&#039; leaving a comment and a file.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has marked assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has left a comment for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has uploaded a feedback file for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has uploaded a file to the course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to user &#039;Student&#039; notifying them their submission for assignment &#039;B&#039; has been marked. - This is done for all users in the group.&lt;br /&gt;
&#039;&#039;&#039;9.&#039;&#039;&#039; User &#039;Adrian&#039; views the feedback.&lt;br /&gt;
*Event: User &#039;Adrian&#039; has viewed assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;10.&#039;&#039;&#039; User &#039;Adrian&#039; opens the feedback file.&lt;br /&gt;
*Event: User &#039;Adrian&#039; has viewed the file &#039;A&#039; for assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;11.&#039;&#039;&#039; User &#039;Adrian&#039; adds some changes to the assignment insulting the teachers marking and updates it.&lt;br /&gt;
*Event: User &#039;Adrian&#039; has updated the submission for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to user &#039;Teacher&#039; notifying them that user &#039;Adrian&#039; has updated the submission for assignment &#039;B&#039;.&lt;br /&gt;
*Event: Email sent to user &#039;Student&#039; notifying them their submission for assignment &#039;B&#039; has been updated. - This is done for all users in the group.&lt;br /&gt;
&#039;&#039;&#039;12.&#039;&#039;&#039; The teacher clicks directly on the link in the email to be taken to the grading page.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has viewed the submission for user &#039;student&#039; for assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;13.&#039;&#039;&#039; The teacher is upset due to the harsh comments and decides to mark Adrian down, but not the rest of the group by setting &#039;Apply grades and feedback to entire group&#039; set to &#039;No&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has marked assignment &#039;B&#039; for user &#039;Adrian&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has left a comment for assignment &#039;B&#039; for user &#039;Adrian&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has uploaded a feedback file for assignment &#039;B&#039; for user &#039;Adrian&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to user &#039;Adrian&#039; notifying them their submission for assignment &#039;B&#039; has been marked.&lt;br /&gt;
&lt;br /&gt;
= FAQs =&lt;br /&gt;
&lt;br /&gt;
; Why not use create events in core subsystems? : Because we could not see all core events in one place, it would create problems when naming event classes and finally subsystems are incomplete, we would have to add more now because we could not move the events in the future.&lt;br /&gt;
&lt;br /&gt;
= Possible future work = &lt;br /&gt;
* MDL-45108 &amp;quot;Other&amp;quot; parameters should be defined in a method similar to webservices&lt;br /&gt;
* MDL-45217 Create traits for refactoring event triggers&lt;br /&gt;
* MDL-42897 Converting completion to use events&lt;br /&gt;
* MDL-42898 Develop a timeline page/block&lt;br /&gt;
&lt;br /&gt;
= See Also =&lt;br /&gt;
[[Logging 2]]  &lt;br /&gt;
&lt;br /&gt;
[[Tin Can]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Events_API&amp;diff=44522</id>
		<title>Events API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Events_API&amp;diff=44522"/>
		<updated>2014-04-24T08:14:46Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* PHP dpcs = */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Project&lt;br /&gt;
|name = Events 2&lt;br /&gt;
|state = Implementation in progress&lt;br /&gt;
|tracker = MDL-39797 , MDL-39952, MDL-39846&lt;br /&gt;
|discussion = https://moodle.org/mod/forum/discuss.php?d=229425&lt;br /&gt;
|assignee = Backend Team&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
= What are events? =&lt;br /&gt;
&lt;br /&gt;
Events are atomic pieces of information describing something that happened in Moodle. Events are primarily the result of user actions, but could also be the result of the [[:en:Cron|cron]] process or administration actions [[:en:Administration via command line|undertaken via the command line]].&lt;br /&gt;
&lt;br /&gt;
When an action takes place, an event is created by a [[Core APIs|core API]] or [[Plugins|plugin]]. The Events system then disseminates this event information to observers registered for this event. In this way, the events system acts as a communication backbone throughout the Moodle system.&lt;br /&gt;
&lt;br /&gt;
Event observers can not modify event data or interrupt the dispatching of events, it is a one way communication channel.&lt;br /&gt;
&lt;br /&gt;
= Why is a new events system needed? =&lt;br /&gt;
&lt;br /&gt;
The need to improve the Events system was prompted by a need for a richer and more efficient logging system, however the benefits of this improvement will be useful to other parts of Moodle that observe event information.&lt;br /&gt;
&lt;br /&gt;
* The events need to be more strictly defined if we want to use them for new logging and other advanced use cases. They need to contain a lot more information in a standardised way (such as most fields from current log table and log_actions table).&lt;br /&gt;
* Complex data types were allowed in old events which was causing major problems when serialising/storing/unserializing the data.&lt;br /&gt;
* The logging and events contain similar information and are triggered at the same places, new events would remove this code duplication. All events should be loggable and all current log entries should be triggered as events.&lt;br /&gt;
* The logging system will become an event observer, listening to all events and directing them to logging storage plugins in a controllable way.&lt;br /&gt;
* It will be possible to subscribe to &#039;*&#039; event, which would allow a system to potentially observe, and selectively deal with, all events. Current handlers do not get event name which makes this problematic.&lt;br /&gt;
* Current event handlers may trigger exceptions during site upgrade which would lead to fatal upgrade problems. The new design eliminates this.&lt;br /&gt;
* Failure in handlers blocked dispatching of subsequent events. Instead problems in new observers would be only logged and execution would continue normally.&lt;br /&gt;
* Current execution of external handlers during DB transactions blocks other handlers. This would be eliminated by in-memory buffer for external events.&lt;br /&gt;
* It would good to have observer priority.&lt;br /&gt;
* Nested events are not dispatched sequentially, it would change the order of events received in lower priority handlers.&lt;br /&gt;
&lt;br /&gt;
= Performance =&lt;br /&gt;
Some basic profiling has been conducted.&lt;br /&gt;
&lt;br /&gt;
There is a general plan to complete pre- and post-implementation testing as development happens. The new system will be imemented in parallel with the old one which should help with comparison of new and old logging and event triggering performance on each page.&lt;br /&gt;
&lt;br /&gt;
Our aim is to trigger more events and log more information, which is going to impact on performance. We hope to offset that impact by improving log storage, simplifying event dispatching and adding other core performance improvements. The proposed class structure of the base event should allow some new advanced techniques, which may also improve performance in some scenarios.&lt;br /&gt;
&lt;br /&gt;
More details will be added to this section soon.&lt;br /&gt;
&lt;br /&gt;
= Events API =&lt;br /&gt;
&lt;br /&gt;
Each plugin will define the events that it can report (trigger) by extending an abstract base class, once for each possible event. This approach will have several benefits.&lt;br /&gt;
; Events will be active objects&lt;br /&gt;
: When they are triggered and possibly after they are reinstantiated (say, when they are retrieved from a log), an event object will be able to provide callback functions for various purposes (such as capability checks).&lt;br /&gt;
; Automatic inclusion&lt;br /&gt;
: Event class definitions will be automatically included when needed, without having to maintain lists of known event types. New event definitions can be added without the need to upgrade, only purging of MUC cache is required after adding new observer.&lt;br /&gt;
; Maintainability&lt;br /&gt;
: It will be easy to add new events and migrate existing events. Code review will be simplified because there will be less duplication of code when triggering events and all event related information/code will be concentrated in one file in fixed locations.&lt;br /&gt;
; Self documenting&lt;br /&gt;
: The behaviour of events will be combined with the definition of events in one place (file). It will be easy for event observer writers to know what events a plugin can trigger. This includes support for autocompletion and code inspection in modern IDEs.&lt;br /&gt;
; Quick, self-validating data structure&lt;br /&gt;
: As events are instantiated objects, the PHP processor will validate the structure and type of event classes. This does not ensure data value validity, but does give some assurance of consistency and it also detects common typos.&lt;br /&gt;
&lt;br /&gt;
== Backwards compatibility and migration ==&lt;br /&gt;
&lt;br /&gt;
Events:&lt;br /&gt;
* Moodle core and standard plugins will replace all calls to the events_trigger() function with new events classes.&lt;br /&gt;
* For events that already exist in Moodle 2.5 the additional legacy information should be added to the event data (in properties &#039;legacyeventname&#039; and &#039;legacyeventdata&#039;.&lt;br /&gt;
* The function events_trigger() will continue working as before, but it will be called automatically after a new event is processed using the &#039;legacyeventname&#039; and &#039;legacyeventdata&#039;.&lt;br /&gt;
* The legacy events handling code will be maintained  separately and will continue being supported in Moodle 2.x. New legacy events will not be added.&lt;br /&gt;
* Existing legacy event handlers will be migrated to new event handlers accepting new event class instances.&lt;br /&gt;
* More subsystems may be migrated to events-handlers, ex.: gradebook history.&lt;br /&gt;
&lt;br /&gt;
Logging:&lt;br /&gt;
* Function add_to_log() and all logging internals will continue working as before.&lt;br /&gt;
* Existing add_to_log() parameters will be migrated inside new events method get_legacy_log_data() and core_event_base::trigger() will call add_to_log() automatically (this will depend on $CFG-&amp;gt;loglifetime setting for performance reasons).&lt;br /&gt;
&lt;br /&gt;
== Event dispatching and observers ==&lt;br /&gt;
&lt;br /&gt;
The new event dispatching system is completely separate from the old events code. Original event handlers are now called observers with the description stored in the same db/events.php file, but as a new array with a different format.&lt;br /&gt;
&lt;br /&gt;
=== Event observers ===&lt;br /&gt;
&lt;br /&gt;
The observers are described in db/events.php in the array $observers, the array is not indexed and contains a list of observers defined as an array with the following properties;&lt;br /&gt;
* eventname - event class name or &amp;quot;*&amp;quot; indicating all events. All events must use namespace, ex.: &#039;&#039;\plugintype_pluginname\event\something_happened&#039;&#039;.&lt;br /&gt;
* callback - PHP callable type.&lt;br /&gt;
* includefile - optional. File to be included before calling the observer. Path relative to dirroot.&lt;br /&gt;
* priority - optional. Defaults to 0. Observers with higher priority are notified first.&lt;br /&gt;
* internal - optional. Defaults to true. Non-internal observers are not called during database transactions, but instead after a successful commit of the transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$observers = array(&lt;br /&gt;
&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;eventname&#039;   =&amp;gt; &#039;\core\event\sample_executed&#039;,&lt;br /&gt;
        &#039;callback&#039;    =&amp;gt; &#039;core_event_sample_observer::observe_one&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;eventname&#039;   =&amp;gt; &#039;\core\event\sample_executed&#039;,&lt;br /&gt;
        &#039;callback&#039;    =&amp;gt; &#039;core_event_sample_observer::external_observer&#039;,&lt;br /&gt;
        &#039;priority&#039;    =&amp;gt; 200,&lt;br /&gt;
        &#039;internal&#039;    =&amp;gt; false,&lt;br /&gt;
    ),&lt;br /&gt;
&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;eventname&#039;   =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;callback&#039;    =&amp;gt; &#039;core_event_sample_observer::observe_all&#039;,&lt;br /&gt;
        &#039;includefile&#039; =&amp;gt; null,&lt;br /&gt;
        &#039;internal&#039;    =&amp;gt; true,&lt;br /&gt;
        &#039;priority&#039;    =&amp;gt; 9999,&lt;br /&gt;
    ),&lt;br /&gt;
&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Event dispatching ===&lt;br /&gt;
&lt;br /&gt;
A list of available observers is constructed on the fly directly from all available events.php files. Previously handlers were installed only during installation and upgrade. There is no risk of performance regression because the list is already cached in MUC. Observers get events before installation or any upgrade, however observers are not notified during the initial installation of moodle core tables.&lt;br /&gt;
&lt;br /&gt;
Developers of observers must make sure that execution does not end with a fatal error under any condition (before install, before upgrade or normal operation). Exceptions are automatically captured, logged in the PHP error log, and notification of other observers continues. Current handlers must not throw any exceptions at any time.&lt;br /&gt;
&lt;br /&gt;
Observers are notified sequentially in the same order in which events were triggered. This means that events triggered in observers are queued in FIFO buffer and are processed after all observers are notified.&lt;br /&gt;
&lt;br /&gt;
=== Differences from old event handling ===&lt;br /&gt;
&lt;br /&gt;
# New events contain a lot more structured information.&lt;br /&gt;
# New event data must not contain any PHP classes.&lt;br /&gt;
# There is separate context cache which may be used when deleting data or for observer performance improvements.&lt;br /&gt;
# No database access in new event dispatching code.&lt;br /&gt;
# There is no support for cron execution - this eliminates performance problems, simplifies events dispatching and prevents abuse of cron events.&lt;br /&gt;
# Events triggered in observers are processed in a different order.&lt;br /&gt;
# External events are buffered when a transaction is in progress, instead of being sent to the cron queue.&lt;br /&gt;
# It is possible to define multiple observers for one event in one events.php file.&lt;br /&gt;
# It is possible to subscribe an observer to all events.&lt;br /&gt;
# The new event manager is using frankenstyle autoloading - smaller memory footprint when events are not used on the current page.&lt;br /&gt;
&lt;br /&gt;
== Triggering events ==&lt;br /&gt;
&lt;br /&gt;
* All event descriptions are objects extending the \core\event\base class.&lt;br /&gt;
* Events are triggered by creating a new instance of the class event and executing $event-&amp;gt;trigger().&lt;br /&gt;
* Each event class name is a unique identifier of the event.&lt;br /&gt;
* Class names and namespace follow the identifier scheme \&#039;&#039;&#039;frankenstyle_component&#039;&#039;&#039;\event\&#039;&#039;&#039;some_object_action&#039;&#039;&#039;. Core events have prefix &#039;core_&#039;.&lt;br /&gt;
* Plugins define each event class in a separate file. File name and location must match the class name, for example: &#039;&#039;&#039;plugindir&#039;&#039;&#039;/classes/event/&#039;&#039;&#039;something_happened&#039;&#039;&#039;.php&lt;br /&gt;
* The event identifier suffix has the form &#039;&#039;some_object_action&#039;&#039;  (&#039;&#039;&#039;something_happened&#039;&#039;&#039; in the example above) and should follow our standard naming convention. The last word after underscore is automatically parsed as action, the rest of words is object.&lt;br /&gt;
&lt;br /&gt;
Decision:[[#Verb_list| Recommended verb list]]&lt;br /&gt;
&lt;br /&gt;
Examples: \core\event\course_completed, \mod_assign\event\submission_commented, \mod_forum\event\post_shared, \mod_forum\event\post_responded, etc.&lt;br /&gt;
&lt;br /&gt;
* Ideally, it should be possible to trigger an event without gathering additional information for the event. To reduce the cost of data gathering, specifically the cost of database reads, at least the minimal values needed to trigger an event should be already available in variables.&lt;br /&gt;
&lt;br /&gt;
An example of triggering an event:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event = \mod_myplugin\event\something_happened::create(array(&#039;context&#039; =&amp;gt; $context, &#039;objectid&#039; =&amp;gt; YYY, &#039;other&#039; =&amp;gt; ZZZ));&lt;br /&gt;
// ... code that may add some record snapshots&lt;br /&gt;
$event-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Use of php autoloading ===&lt;br /&gt;
&lt;br /&gt;
All new OOP APIs in Moodle 2.6 are going to use class auto loading - see [[Automatic class loading]]. New events use PHP strictly defined namespaces which concentrate all events classes in classes/event/ subdirectory.&lt;br /&gt;
&lt;br /&gt;
=== Why separate classes? ===&lt;br /&gt;
There were two alternatives proposed on how to define the event structure. The first is a separate class for each event (extending the base class), the other being each event is based on a generic event instance of the base class.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Decision: Use separate class for each event.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Each plugin creates its own event class for each event&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Pros&lt;br /&gt;
* Maintainability - It is much easier to review, debug, integrate.&lt;br /&gt;
* Self documenting, behaviour is combined with definition.&lt;br /&gt;
* It is extremely flexible for plugin developers and core devs too.&lt;br /&gt;
* Automatically lists events without being installed - PHPDocs as events documentation.&lt;br /&gt;
* It is included only when needed using autoloading.&lt;br /&gt;
* Self-validating data structure (by PHP).&lt;br /&gt;
* Some developers will find it easier to copy whole class files as templates.&lt;br /&gt;
Cons&lt;br /&gt;
* Big learning curve for developers without OOP skills (all other new subsystems in Moodle already use OOP, you can not code without these skills any more).&lt;br /&gt;
* Some developers may find it harder to copy-and-paste examples because they will need to create new class first and use it afterwards (this can be viewed as a benefit because it forces developers to think more about events).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Each plugin defines events in a list based on a generic object&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Pros&lt;br /&gt;
* Easier for some developers (this can be eliminated with developer documentation).&lt;br /&gt;
* Some developers think it gives more control of event structure in core (we can easily solve that with private access and validation in the base class).&lt;br /&gt;
Cons&lt;br /&gt;
* It is not flexible enough. PHP code gives developers more freedom.&lt;br /&gt;
* It would not be possible to implement any performance hacks in custom methods. All data would have to be calculated even if it is not used.&lt;br /&gt;
* It would be necessary to define access control callbacks in other code.&lt;br /&gt;
* It would be harder and slower to integrate legacy logging.&lt;br /&gt;
* It would be harder and slower to implement support for legacy events.&lt;br /&gt;
* Event observers could not use event class names as reliable identifiers.&lt;br /&gt;
* Event object and action could not be parsed from class name, it would have to be stored in event properties every time you trigger event.&lt;br /&gt;
* Requires upgrade/install to register an event in DB table with MUC cache. Events could not be triggered earlier.&lt;br /&gt;
* The localised descriptions and names would have to be stored as properties, it would not be possible to store them in any definition.&lt;br /&gt;
* The implementation of an events infrastructure would be significantly more complex and error prone.&lt;br /&gt;
&lt;br /&gt;
== Information contained in events ==&lt;br /&gt;
&lt;br /&gt;
Events have to contain as much information as they can, but this should not affect the performance. That&#039;s why part of the information is available in properties, and the rest via methods. This allows for delaying the computation of the data at the time it is really needed, if it ever is.&lt;br /&gt;
&lt;br /&gt;
=== Properties ===&lt;br /&gt;
&lt;br /&gt;
List of properties that the developer has to pass to the event upon creation, or automatically generated when possible and cost free. Some of those properties not mandatory.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Property name&lt;br /&gt;
! Title&lt;br /&gt;
! Type&lt;br /&gt;
! Comment&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;eventname&#039;&#039;&lt;br /&gt;
| Event name&lt;br /&gt;
| &#039;&#039;static, automatic from class name&#039;&#039;&lt;br /&gt;
| Automatically computed by copying class name&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;component&#039;&#039;&lt;br /&gt;
| Component&lt;br /&gt;
| &#039;&#039;static, automatic from top namespace&#039;&#039;&lt;br /&gt;
| Component declaring the event, automatically computed from class name.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;action&#039;&#039;&lt;br /&gt;
| Action&lt;br /&gt;
| &#039;&#039;static, automatic from last word in class name&#039;&#039;&lt;br /&gt;
| Can be automatically computed from class name.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;target&#039;&#039;&lt;br /&gt;
| target of action&lt;br /&gt;
| &#039;&#039;static, automatic from class name&#039;&#039;&lt;br /&gt;
| Target on which the action is taken, can be automatically computed from class name.&lt;br /&gt;
|-&lt;br /&gt;
| objecttable&lt;br /&gt;
| Database table name&lt;br /&gt;
|&lt;br /&gt;
| optional database table name where is/was the object stored. Never use a relationship table here.&lt;br /&gt;
|-&lt;br /&gt;
| objectid&lt;br /&gt;
| Object ID&lt;br /&gt;
|&lt;br /&gt;
| optional id of the object record from objecttable&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;&#039;&#039;crud&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
| Transaction type&lt;br /&gt;
| &#039;&#039;static mandatory&#039;&#039;&lt;br /&gt;
| One of [crud] letters. Statically declared in the event class method init().&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;&#039;&#039;level&#039;&#039;&#039;&#039;&#039; / &#039;&#039;&#039;&#039;&#039;edulevel&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
| Level&lt;br /&gt;
| &#039;&#039;static mandatory&#039;&#039;&lt;br /&gt;
| Level of educational value of the event. Statically declared in the event class method init(). Changed from &#039;&#039;&#039;&#039;&#039;level&#039;&#039;&#039;&#039;&#039; to &#039;&#039;&#039;&#039;&#039;edulevel&#039;&#039;&#039;&#039;&#039; in Moodle 2.7 (See below for more details)&lt;br /&gt;
|-&lt;br /&gt;
| contextid&lt;br /&gt;
| Context ID&lt;br /&gt;
| mandatory&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| contextlevel&lt;br /&gt;
| Context level&lt;br /&gt;
| automatic from context&lt;br /&gt;
| This tells you if it was a course, activity, course category, etc.&lt;br /&gt;
|-&lt;br /&gt;
| contextinstanceid&lt;br /&gt;
| Context instanceid&lt;br /&gt;
| automatic from context&lt;br /&gt;
| Based on context level this may be course id , course module id, course category, etc.&lt;br /&gt;
|-&lt;br /&gt;
| userid&lt;br /&gt;
| User ID&lt;br /&gt;
| defaults to current user&lt;br /&gt;
| User ID, or 0 when not logged in, or -1 when other (System, CLI, Cron, ...)&lt;br /&gt;
|-&lt;br /&gt;
| courseid&lt;br /&gt;
| Affected course&lt;br /&gt;
| defaults to course context from context&lt;br /&gt;
| This is used only for contexts at and bellow course level - this can be used to filter events by course (includes all course activities)&lt;br /&gt;
|-&lt;br /&gt;
| relateduserid&lt;br /&gt;
| Affected user&lt;br /&gt;
|&lt;br /&gt;
| Is this action related to some user? This could be used for some personal timeline view.&lt;br /&gt;
|-&lt;br /&gt;
| other&lt;br /&gt;
| All other data&lt;br /&gt;
|&lt;br /&gt;
| Any other fields needed for event description - scalars or arrays, must be serialisable using json_encode()&lt;br /&gt;
|-&lt;br /&gt;
| timecreated&lt;br /&gt;
| Time of the event&lt;br /&gt;
| automatic&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;static&#039;&#039;: It is the same for all event instances of this class.&lt;br /&gt;
* &#039;&#039;&#039;mandatory&#039;&#039;&#039;: Is required in order to trigger the event.&lt;br /&gt;
&lt;br /&gt;
==== Level property ====&lt;br /&gt;
&lt;br /&gt;
The edulevel property helps defining the educational value of the event. It is intentional that the list is limited to only 3 different constants, having too many options would make it harder for developers to pick the right one(s). We also have to keep in mind that this is not supposed to answer all the questions about a particular event, other event properties like the courseid, the context, the component name can be used with the level to get more granular reports.&lt;br /&gt;
&lt;br /&gt;
Remember that this is event based. If the user that has triggered the event is not really &amp;quot;participating&amp;quot; because he is an admin, or a manager, then it is the job of the report to filter those. The event itself has a static educational level.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Teaching&#039;&#039;&#039; (LEVEL_TEACHING: 1)&lt;br /&gt;
&lt;br /&gt;
Any event/action that is performed by someone (typically a teacher) and has a teaching value (anything that is affecting the learning experience/environment of the students). This should not be combined with &amp;quot;Participating&amp;quot; events.&lt;br /&gt;
&lt;br /&gt;
Valid events:&lt;br /&gt;
&lt;br /&gt;
* A teacher grading a student&lt;br /&gt;
* A teacher modifying the course settings&lt;br /&gt;
* A teacher adding a new section to the course page&lt;br /&gt;
* A teacher modifying a module settings&lt;br /&gt;
* A teacher adding a page to course&lt;br /&gt;
* A teacher leaving a feedback&lt;br /&gt;
&lt;br /&gt;
INVALID events:&lt;br /&gt;
&lt;br /&gt;
* A teacher posting in a forum (it might affect the learning experience, but not necessarily, so the teacher is just participating)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Participating&#039;&#039;&#039; (LEVEL_PARTICIPATING: 2)&lt;br /&gt;
&lt;br /&gt;
Any event/action that is performed by a user, that is related (or could be related) to his learning experience.&lt;br /&gt;
&lt;br /&gt;
Valid events:&lt;br /&gt;
&lt;br /&gt;
* A user posting to a forum&lt;br /&gt;
* A user submitting an assignment&lt;br /&gt;
* A user blogging&lt;br /&gt;
* A user reading someone&#039;s blog&lt;br /&gt;
* A user posting a comment&lt;br /&gt;
* A user chatting on a chat activity&lt;br /&gt;
* A user viewing the course page&lt;br /&gt;
* A user deletes a blog post&lt;br /&gt;
&lt;br /&gt;
INVALID events:&lt;br /&gt;
&lt;br /&gt;
* A user updating his profile&lt;br /&gt;
* A user visiting someone&#039;s profile&lt;br /&gt;
* A user viewing his /my/ page&lt;br /&gt;
* A user sending a message to another one&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Other&#039;&#039;&#039; (LEVEL_OTHER: 0)&lt;br /&gt;
&lt;br /&gt;
Any other action, whether they are related to the site administration, or are specific to user. They do not have any educational value.&lt;br /&gt;
&lt;br /&gt;
=== Methods ===&lt;br /&gt;
&lt;br /&gt;
The computation of this data is not required by default, but can be accessed by any event observer if need be.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Comment&lt;br /&gt;
|-&lt;br /&gt;
| get_name()&lt;br /&gt;
| Returns localised name of the event, it is the same for all instances.&lt;br /&gt;
|-&lt;br /&gt;
| get_description()&lt;br /&gt;
| Returns localised description of one particular event.&lt;br /&gt;
|-&lt;br /&gt;
| can_view($user)&lt;br /&gt;
| Can the specified user view the event?&lt;br /&gt;
|-&lt;br /&gt;
| get_url()&lt;br /&gt;
| Returns Moodle URL where the event can be observed afterwards.&lt;br /&gt;
|-&lt;br /&gt;
| get_legacy_eventname()&lt;br /&gt;
| Information necessary for event BC.&lt;br /&gt;
|-&lt;br /&gt;
| get_legacy_eventdata()&lt;br /&gt;
| Information necessary for event BC.&lt;br /&gt;
|-&lt;br /&gt;
| get_legacy_logdata()&lt;br /&gt;
| Information necessary for logging BC.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Record caching===&lt;br /&gt;
&lt;br /&gt;
The standard event data may not contain all the information observers need. The built-in record snapshot support in events allows developers to attach more auxiliary information when triggering events, it may be for example course record, some record that was just deleted, etc. The snapshot is meant to be a full database record, as it will be automatically fetched from get_record_snapshot() if not set previously and assuming the property &#039;&#039;objecttable&#039;&#039; is set. Please be aware that the snapshots are not stored in the event, and cannot be restored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    $event = \core\event\role_assigned::create(&lt;br /&gt;
        array(&#039;context&#039;=&amp;gt;$context, &#039;objectid&#039;=&amp;gt;$ra-&amp;gt;roleid, &#039;relateduserid&#039;=&amp;gt;$ra-&amp;gt;userid,&lt;br /&gt;
            &#039;other&#039;=&amp;gt;array(&#039;id&#039;=&amp;gt;$ra-&amp;gt;id, &#039;component&#039;=&amp;gt;$ra-&amp;gt;component, &#039;itemid&#039;=&amp;gt;$ra-&amp;gt;itemid)));&lt;br /&gt;
    $event-&amp;gt;add_record_snapshot(&#039;role_assignments&#039;, $ra);&lt;br /&gt;
    $event-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    $event = \core\event\role_unassigned::create(&lt;br /&gt;
        array(&#039;context&#039;=&amp;gt;$context, &#039;objectid&#039;=&amp;gt;$ra-&amp;gt;roleid, &#039;relateduserid&#039;=&amp;gt;$ra-&amp;gt;userid,&lt;br /&gt;
            &#039;other&#039;=&amp;gt;array(&#039;id&#039;=&amp;gt;$ra-&amp;gt;id, &#039;component&#039;=&amp;gt;$ra-&amp;gt;component, &#039;itemid&#039;=&amp;gt;$ra-&amp;gt;itemid)));&lt;br /&gt;
    $event-&amp;gt;add_record_snapshot(&#039;role_assignments&#039;, $ra);&lt;br /&gt;
    $event-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The related methods are:&lt;br /&gt;
* public function add_record_snapshot($tablename, $record)&lt;br /&gt;
* public function get_record_snapshot($tablename, $id)&lt;br /&gt;
&lt;br /&gt;
=== Rejected properties and methods ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Property&lt;br /&gt;
! Title&lt;br /&gt;
! Why&lt;br /&gt;
|-&lt;br /&gt;
| URL&lt;br /&gt;
| relevant page URL&lt;br /&gt;
| These URLs can be constructed on the fly from other data, external log plugins may use get_url() method.&lt;br /&gt;
|-&lt;br /&gt;
| version&lt;br /&gt;
| Event specification number&lt;br /&gt;
| The event specification should never change&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| Type of event (action, error, ...)&lt;br /&gt;
| Event are not intended for error logging or debugging.&lt;br /&gt;
|-&lt;br /&gt;
| actor&lt;br /&gt;
| Whether current execution is cron, cli, user, ...&lt;br /&gt;
| Impossible to track down at a low level&lt;br /&gt;
|-&lt;br /&gt;
| severity&lt;br /&gt;
| Severity following [http://tools.ietf.org/html/rfc5424#section-6.2.1 logging standards]&lt;br /&gt;
| Our logging does not match this, as we will not (at present) log errors&lt;br /&gt;
|-&lt;br /&gt;
| coursecatname&lt;br /&gt;
| Category name&lt;br /&gt;
| Might be costly to retrieve for little gain&lt;br /&gt;
|-&lt;br /&gt;
| coursename&lt;br /&gt;
| Course name&lt;br /&gt;
| Might be costly to retrieve for little gain&lt;br /&gt;
|-&lt;br /&gt;
| cmname&lt;br /&gt;
| Course module name&lt;br /&gt;
| Might be costly to retrieve for little gain&lt;br /&gt;
|-&lt;br /&gt;
| categoryid &lt;br /&gt;
| Course category id&lt;br /&gt;
| Categories are a tree structure, we can not identify them by one integer. It would have to be a path.&lt;br /&gt;
|-&lt;br /&gt;
| cmid &lt;br /&gt;
| Course module id&lt;br /&gt;
| Can be derived from contextlevel and contextinstanceid&lt;br /&gt;
|-&lt;br /&gt;
| associatedobject&lt;br /&gt;
| Associated object&lt;br /&gt;
| Object associated to the main object. Ie: The user to whom a message is sent.&lt;br /&gt;
|-&lt;br /&gt;
| associatedobjectid&lt;br /&gt;
| Associated object ID&lt;br /&gt;
| Identifier of the associated object&lt;br /&gt;
|-&lt;br /&gt;
| realuserid&lt;br /&gt;
| Real User ID&lt;br /&gt;
| Will be tracked by log plugins only - user who &amp;quot;logged in as&amp;quot;, stores the real user ID&lt;br /&gt;
|-&lt;br /&gt;
| origin&lt;br /&gt;
| Origin of the event&lt;br /&gt;
| Will be tracked by log plugins only - CLI, cron, Webservice, ... (optionally with IP address)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Comment&lt;br /&gt;
! Why&lt;br /&gt;
|-&lt;br /&gt;
| get_all_affected_users()&lt;br /&gt;
| Returns all the users affected by this event&lt;br /&gt;
| It is expensive to fetch all users and it changes in time, so it would be unreliable too. For now we store only one user who is related to each event.&lt;br /&gt;
|-&lt;br /&gt;
| get_objecturl()&lt;br /&gt;
| Returns the URL to view the object&lt;br /&gt;
| There is usually only one URL where event changes may be observed. The URL may depend on current user capabilities too.&lt;br /&gt;
|-&lt;br /&gt;
| get_associatedobjecturl()&lt;br /&gt;
| Returns the URL to view the associated object&lt;br /&gt;
| No associated user property is present.&lt;br /&gt;
|-&lt;br /&gt;
| get_currenturl()&lt;br /&gt;
| Returns the current URL, uses $PAGE.&lt;br /&gt;
| This information may be added by logger, current page info is not part of events data.&lt;br /&gt;
|-&lt;br /&gt;
| get_useripaddress()&lt;br /&gt;
| Returns the User IP address&lt;br /&gt;
| Page access method is not part of events API, this should be implemented as logdata properties in loggers.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Events naming convention ==&lt;br /&gt;
&lt;br /&gt;
Clear event names help developers when reading what events are triggered, and defining the events properties when defining the event class.&lt;br /&gt;
&lt;br /&gt;
 Decision: \&amp;lt;component&amp;gt;\event\&amp;lt;some_object&amp;gt;_&amp;lt;verb&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Existing events ===&lt;br /&gt;
&lt;br /&gt;
List of existing events in Moodle code base, along with their 2.5 couterparts.&lt;br /&gt;
&lt;br /&gt;
This list is out of date. For a full list of events check out the [https://docs.moodle.org/en/Event_list_report Event list report] which is located in &amp;quot;Site administration &amp;gt; Reports &amp;gt; Event list&amp;quot; of your Moodle installation (2.7+).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fully qualified event name&lt;br /&gt;
! 2.5 name&lt;br /&gt;
! Component&lt;br /&gt;
! Object&lt;br /&gt;
! Action (Verb)&lt;br /&gt;
! Comment&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_comments\event\comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| assignsubmission_comments&lt;br /&gt;
| comment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_comments\event\comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| assignsubmission_comments&lt;br /&gt;
| comment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_file\event\assessable_uploaded&#039;&#039;&#039;&lt;br /&gt;
| assessable_file_uploaded&lt;br /&gt;
| assignsubmission_file&lt;br /&gt;
| assessable&lt;br /&gt;
| uploaded&lt;br /&gt;
| To be deprecated MDL-35197&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_file\event\submission_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| assignsubmission_file&lt;br /&gt;
| submission&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_file\event\submission_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| assignsubmission_file&lt;br /&gt;
| submission&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_onlinetext\event\assessable_uploaded&#039;&#039;&#039;&lt;br /&gt;
| assessable_content_uploaded&lt;br /&gt;
| assignsubmission_onlinetext&lt;br /&gt;
| assessable&lt;br /&gt;
| uploaded&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_onlinetext\event\submission_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| assignsubmission_onlinetext&lt;br /&gt;
| submission&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_onlinetext\event\submission_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| assignsubmission_onlinetext&lt;br /&gt;
| submission&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;block_comments\event\comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| block_comments&lt;br /&gt;
| comment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;block_comments\event\comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| block_comments&lt;br /&gt;
| comment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;booktool_exportimscp\event\book_exported&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| booktool_exportimscp&lt;br /&gt;
| book&lt;br /&gt;
| exported&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;booktool_print\event\book_printed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| booktool_print&lt;br /&gt;
| book&lt;br /&gt;
| printed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;booktool_print\event\chapter_printed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| booktool_print&lt;br /&gt;
| chapter&lt;br /&gt;
| printed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\assessable_submitted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| assessable&lt;br /&gt;
| submitted&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\assessable_uploaded&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| assessable&lt;br /&gt;
| uploaded&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\base&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| base&lt;br /&gt;
| -&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_association_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| blog_association&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| blog_comment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| blog_comment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_entries_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| blog_entries&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_entry_created&#039;&#039;&#039;&lt;br /&gt;
| blog_entry_added&lt;br /&gt;
| core&lt;br /&gt;
| blog_entry&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_entry_deleted&#039;&#039;&#039;&lt;br /&gt;
| blog_entry_deleted&lt;br /&gt;
| core&lt;br /&gt;
| blog_entry&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_entry_updated&#039;&#039;&#039;&lt;br /&gt;
| blog_entry_edited&lt;br /&gt;
| core&lt;br /&gt;
| blog_entry&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\cohort_created&#039;&#039;&#039;&lt;br /&gt;
| cohort_added&lt;br /&gt;
| core&lt;br /&gt;
| cohort&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\cohort_deleted&#039;&#039;&#039;&lt;br /&gt;
| cohort_deleted&lt;br /&gt;
| core&lt;br /&gt;
| cohort&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\cohort_member_added&#039;&#039;&#039;&lt;br /&gt;
| cohort_member_added&lt;br /&gt;
| core&lt;br /&gt;
| cohort_member&lt;br /&gt;
| added&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\cohort_member_removed&#039;&#039;&#039;&lt;br /&gt;
| cohort_member_removed&lt;br /&gt;
| core&lt;br /&gt;
| cohort_member&lt;br /&gt;
| removed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\cohort_updated&#039;&#039;&#039;&lt;br /&gt;
| cohort_updated&lt;br /&gt;
| core&lt;br /&gt;
| cohort&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| comment&lt;br /&gt;
| created&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| comment&lt;br /&gt;
| deleted&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\comments_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| comments&lt;br /&gt;
| viewed&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\content_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| content&lt;br /&gt;
| viewed&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_category_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_category&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_category_deleted&#039;&#039;&#039;&lt;br /&gt;
| course_category_deleted&lt;br /&gt;
| core&lt;br /&gt;
| course_category&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_category_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_category&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_completed&#039;&#039;&#039;&lt;br /&gt;
| course_completed&lt;br /&gt;
| core&lt;br /&gt;
| course&lt;br /&gt;
| completed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_completion_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_completion&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_content_deleted&#039;&#039;&#039;&lt;br /&gt;
| course_content_removed&lt;br /&gt;
| core&lt;br /&gt;
| course_content&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_created&#039;&#039;&#039;&lt;br /&gt;
| course_created&lt;br /&gt;
| core&lt;br /&gt;
| course&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_deleted&#039;&#039;&#039;&lt;br /&gt;
| course_deleted&lt;br /&gt;
| core&lt;br /&gt;
| course&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_completion_updated&#039;&#039;&#039;&lt;br /&gt;
| activity_completion_changed&lt;br /&gt;
| core&lt;br /&gt;
| course_module_completion&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_created&#039;&#039;&#039;&lt;br /&gt;
| mod_created&lt;br /&gt;
| core&lt;br /&gt;
| course_module&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_deleted&#039;&#039;&#039;&lt;br /&gt;
| mod_deleted&lt;br /&gt;
| core&lt;br /&gt;
| course_module&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_instances_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_module_instances_list&lt;br /&gt;
| viewed&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_updated&#039;&#039;&#039;&lt;br /&gt;
| mod_updated&lt;br /&gt;
| core&lt;br /&gt;
| course_module&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_reset_ended&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_reset&lt;br /&gt;
| ended&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_reset_started&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_reset&lt;br /&gt;
| started&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_restored&#039;&#039;&#039;&lt;br /&gt;
| course_restored&lt;br /&gt;
| core&lt;br /&gt;
| course&lt;br /&gt;
| restored&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_section_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_section&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_updated&#039;&#039;&#039;&lt;br /&gt;
| course_updated&lt;br /&gt;
| core&lt;br /&gt;
| course&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\email_failed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| email&lt;br /&gt;
| failed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\group_created&#039;&#039;&#039;&lt;br /&gt;
| groups_group_created&lt;br /&gt;
| core&lt;br /&gt;
| group&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\group_deleted&#039;&#039;&#039;&lt;br /&gt;
| groups_group_deleted&lt;br /&gt;
| core&lt;br /&gt;
| group&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\group_member_added&#039;&#039;&#039;&lt;br /&gt;
| groups_member_added&lt;br /&gt;
| core&lt;br /&gt;
| group_member&lt;br /&gt;
| added&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\group_member_removed&#039;&#039;&#039;&lt;br /&gt;
| groups_member_removed&lt;br /&gt;
| core&lt;br /&gt;
| group_member&lt;br /&gt;
| removed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\group_updated&#039;&#039;&#039;&lt;br /&gt;
| groups_group_updated&lt;br /&gt;
| core&lt;br /&gt;
| group&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\grouping_created&#039;&#039;&#039;&lt;br /&gt;
| groups_grouping_created&lt;br /&gt;
| core&lt;br /&gt;
| grouping&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\grouping_deleted&#039;&#039;&#039;&lt;br /&gt;
| groups_grouping_deleted&lt;br /&gt;
| core&lt;br /&gt;
| grouping&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\grouping_updated&#039;&#039;&#039;&lt;br /&gt;
| groups_grouping_updated&lt;br /&gt;
| core&lt;br /&gt;
| grouping&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\manager&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| manager&lt;br /&gt;
| anager&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\mnet_access_control_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| mnet_access_control&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\mnet_access_control_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| mnet_access_control&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\note_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| note&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\note_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| note&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\note_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| note&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\notes_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| notes&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_allow_assign_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| role_allow_assign&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_allow_override_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| role_allow_override&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_allow_switch_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| role_allow_switch&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_assigned&#039;&#039;&#039;&lt;br /&gt;
| role_assigned&lt;br /&gt;
| core&lt;br /&gt;
| role&lt;br /&gt;
| assigned&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_capabilities_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| role_capabilities&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| role&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_unassigned&#039;&#039;&#039;&lt;br /&gt;
| role_unassigned&lt;br /&gt;
| core&lt;br /&gt;
| role&lt;br /&gt;
| unassigned&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_created&#039;&#039;&#039;&lt;br /&gt;
| user_created&lt;br /&gt;
| core&lt;br /&gt;
| user&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_deleted&#039;&#039;&#039;&lt;br /&gt;
| user_deleted&lt;br /&gt;
| core&lt;br /&gt;
| user&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_enrolment_created&#039;&#039;&#039;&lt;br /&gt;
| user_enrolled&lt;br /&gt;
| core&lt;br /&gt;
| user_enrolment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_enrolment_deleted&#039;&#039;&#039;&lt;br /&gt;
| user_unenrolled&lt;br /&gt;
| core&lt;br /&gt;
| user_enrolment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_enrolment_updated&#039;&#039;&#039;&lt;br /&gt;
| user_enrol_modified&lt;br /&gt;
| core&lt;br /&gt;
| user_enrolment&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| user_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_loggedin&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| user&lt;br /&gt;
| loggedin&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_loggedinas&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| user&lt;br /&gt;
| loggedinas&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_loggedout&#039;&#039;&#039;&lt;br /&gt;
| user_logout&lt;br /&gt;
| core&lt;br /&gt;
| user&lt;br /&gt;
| loggedout&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_login_failed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| user_login&lt;br /&gt;
| failed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_profile_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| user_profile&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_updated&#039;&#039;&#039;&lt;br /&gt;
| user_updated&lt;br /&gt;
| core&lt;br /&gt;
| user&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_function_called&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_function&lt;br /&gt;
| called&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_login_failed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_login&lt;br /&gt;
| failed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_service_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_service&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_service_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_service&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_service_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_service&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_service_user_added&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_service_user&lt;br /&gt;
| added&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_service_user_removed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_service_user&lt;br /&gt;
| removed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_token_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_token&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_token_sent&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_token&lt;br /&gt;
| sent&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;logstore_legacy\event\legacy_logged&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| logstore_legacy&lt;br /&gt;
| legacy&lt;br /&gt;
| logged&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\all_submissions_downloaded&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| all_submissions&lt;br /&gt;
| downloaded&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\assessable_submitted&#039;&#039;&#039;&lt;br /&gt;
| assessable_submitted&lt;br /&gt;
| mod_assign&lt;br /&gt;
| assessable&lt;br /&gt;
| submitted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\extension_granted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| extension&lt;br /&gt;
| granted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\identities_revealed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| identities&lt;br /&gt;
| revealed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\marker_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| marker&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\statement_accepted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| statement&lt;br /&gt;
| accepted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission&lt;br /&gt;
| created&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_duplicated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission&lt;br /&gt;
| duplicated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_graded&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission&lt;br /&gt;
| graded&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_locked&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission&lt;br /&gt;
| locked&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_status_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission_status&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_unlocked&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission&lt;br /&gt;
| unlocked&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission&lt;br /&gt;
| updated&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\workflow_state_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| workflow_state&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_book\event\chapter_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_book&lt;br /&gt;
| chapter&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_book\event\chapter_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_book&lt;br /&gt;
| chapter&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_book\event\chapter_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_book&lt;br /&gt;
| chapter&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_book\event\chapter_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_book&lt;br /&gt;
| chapter&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_book\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_book&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_book\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_book&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_chat\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_chat&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_chat\event\message_sent&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_chat&lt;br /&gt;
| message&lt;br /&gt;
| sent&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_chat\event\sessions_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_chat&lt;br /&gt;
| sessions&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_choice\event\answer_submitted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_choice&lt;br /&gt;
| answer&lt;br /&gt;
| submitted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_choice\event\answer_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_choice&lt;br /&gt;
| answer&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_choice\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_choice&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_choice\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_choice&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_choice\event\report_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_choice&lt;br /&gt;
| report&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| comment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| comment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\field_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| field&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\field_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| field&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\field_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| field&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\record_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| record&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\record_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| record&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\record_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| record&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\template_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| template&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\template_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| template&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_feedback\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_feedback&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_feedback\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_feedback&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_feedback\event\response_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_feedback&lt;br /&gt;
| response&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_feedback\event\response_submitted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_feedback&lt;br /&gt;
| response&lt;br /&gt;
| submitted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_folder\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_folder&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_folder\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_folder&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_folder\event\folder_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_folder&lt;br /&gt;
| folder&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\assessable_uploaded&#039;&#039;&#039;&lt;br /&gt;
| assessable_content_uploaded&lt;br /&gt;
| mod_forum&lt;br /&gt;
| assessable&lt;br /&gt;
| uploaded&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\course_searched&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| course&lt;br /&gt;
| searched&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\discussion_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| discussion&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\discussion_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| discussion&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\discussion_moved&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| discussion&lt;br /&gt;
| moved&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\discussion_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| discussion&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\discussion_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| discussion&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\forum_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| forum&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\post_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| post&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\post_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| post&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\post_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| post&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\readtracking_disabled&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| readtracking&lt;br /&gt;
| disabled&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\readtracking_enabled&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| readtracking&lt;br /&gt;
| enabled&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\subscribers_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| subscribers&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\subscription_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| subscription&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\subscription_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| subscription&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\userreport_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| userreport&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_glossary\event\comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_glossary&lt;br /&gt;
| comment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_glossary\event\comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_glossary&lt;br /&gt;
| comment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\essay_assessed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| essay&lt;br /&gt;
| assessed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\essay_attempt_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| essay_attempt&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\highscore_added&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| highscore&lt;br /&gt;
| added&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\highscores_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| highscores&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\lesson_ended&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| lesson&lt;br /&gt;
| ended&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\lesson_started&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| lesson&lt;br /&gt;
| started&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lti\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lti&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lti\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lti&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lti\event\unknown_service_api_called&#039;&#039;&#039;&lt;br /&gt;
| lti_unknown_service_api_call&lt;br /&gt;
| mod_lti&lt;br /&gt;
| unknown_service_api&lt;br /&gt;
| called&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_page\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_page&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_page\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_page&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_quiz\event\attempt_abandoned&#039;&#039;&#039;&lt;br /&gt;
| quiz_attempt_abandoned&lt;br /&gt;
| mod_quiz&lt;br /&gt;
| attempt&lt;br /&gt;
| abandoned&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_quiz\event\attempt_becameoverdue&#039;&#039;&#039;&lt;br /&gt;
| quiz_attempt_overdue&lt;br /&gt;
| mod_quiz&lt;br /&gt;
| attempt&lt;br /&gt;
| becameoverdue&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_quiz\event\attempt_started&#039;&#039;&#039;&lt;br /&gt;
| quiz_attempt_started&lt;br /&gt;
| mod_quiz&lt;br /&gt;
| attempt&lt;br /&gt;
| started&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_quiz\event\attempt_submitted&#039;&#039;&#039;&lt;br /&gt;
| quiz_attempt_submitted&lt;br /&gt;
| mod_quiz&lt;br /&gt;
| attempt&lt;br /&gt;
| submitted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_resource\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_resource&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_resource\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_resource&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\attempt_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| attempt&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\interactions_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| interactions&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\report_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| report&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\sco_launched&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| sco&lt;br /&gt;
| launched&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\tracks_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| tracks&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\user_report_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| user_report&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_url\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_url&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_url\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_url&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| comment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| comment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\comments_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| comments&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_diff_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_diff&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_history_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_history&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_locks_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_locks&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_map_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_map&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_version_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_version&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_version_restored&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_version&lt;br /&gt;
| restored&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_version_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_version&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\assessable_uploaded&#039;&#039;&#039;&lt;br /&gt;
| assessable_content_uploaded&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| assessable&lt;br /&gt;
| uploaded&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\assessment_evaluated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| assessment&lt;br /&gt;
| evaluated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\assessment_evaluations_reset&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| assessment_evaluations&lt;br /&gt;
| reset&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\assessment_reevaluated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| assessment&lt;br /&gt;
| reevaluated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| workshop_viewed&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\instances_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| instances_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\phase_switched&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| phase&lt;br /&gt;
| switched&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\submission_assessed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| submission&lt;br /&gt;
| assessed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\submission_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| submission&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\submission_reassessed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| submission&lt;br /&gt;
| reassessed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\submission_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| submission&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\submission_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| submission&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;report_log\event\content_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| report_log&lt;br /&gt;
| content&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;report_loglive\event\content_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| report_loglive&lt;br /&gt;
| content&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;report_outline\event\content_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| report_outline&lt;br /&gt;
| content&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;report_participation\event\content_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| report_participation&lt;br /&gt;
| content&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;report_stats\event\content_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| report_stats&lt;br /&gt;
| content&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Verb list ===&lt;br /&gt;
All events must use a verb from this list. New verbs should be added to this list if required.&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!verb&lt;br /&gt;
!Explanation&lt;br /&gt;
!Source&lt;br /&gt;
|-&lt;br /&gt;
|abandoned&lt;br /&gt;
|When a attempt is abandoned by user (Quiz attempt)&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|accepted&lt;br /&gt;
|Example: Accepting a statement when submitting an assignment.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|added&lt;br /&gt;
|	Used to represent &amp;quot;something that already exists is now part of/bound to another entity&amp;quot;. Examples: &amp;quot;Admin added role to user X&amp;quot;, &amp;quot;Admin added user X to group A&amp;quot;. Wrong example: &amp;quot;User added course in category&amp;quot; because it is a &#039;move&#039; action, except if a course can be part of multiple categories. The good examples work because: A user can have multiple roles, a user can be in multiple groups.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|answered&lt;br /&gt;
| Indicates the actor responded to a Question&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|assessed&lt;br /&gt;
| Some submitted material has been assessed&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|assigned&lt;br /&gt;
| Assign some privilege or role to user.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|attempted&lt;br /&gt;
| Trying to do an activity. Example: attempting a Math class.&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|awarded&lt;br /&gt;
| ex:-teacher awarded student a badge.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|backedup&lt;br /&gt;
| When a backup has been performed.&lt;br /&gt;
|Moodle	&lt;br /&gt;
|-&lt;br /&gt;
|becomeoverdue&lt;br /&gt;
| When an activity is overdue Example: Quiz attempt is overdue&lt;br /&gt;
|Moodle	&lt;br /&gt;
|-&lt;br /&gt;
|called&lt;br /&gt;
| When a call to something is made like an API @see unknown_service_api_called.php&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|commented&lt;br /&gt;
|Offered an opinion or written experience of the activity. Can be used with the learner as the actor or a system as an actor. Comments can be sent from either party with the idea that the other will read and react to the content.&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|completed&lt;br /&gt;
|To experience the activity in its entirety. Used to affirm the completion of content. This can be simply experiencing all the content, be tied to objectives or interactions, or determined in any other way. Any content that has been initialized, but not yet completed, should be considered incomplete. There is no verb to &#039;incomplete&#039; an activity, one would void the statement which completes the activity.&amp;quot;&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|created&lt;br /&gt;
|Used to represent &amp;quot;something new has been created&amp;quot;.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|deleted&lt;br /&gt;
|Used to indicate the object in context was deleted.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|disabled&lt;br /&gt;
|When an activity is disabled. Example: forum read tracking disabled.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|downloaded&lt;br /&gt;
|When a user download file from user. Example submission/report downloaded.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|duplicated&lt;br /&gt;
|For something that has been copied.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|enabled&lt;br /&gt;
|When some setting is enabled. Example: forum read tracking enabled.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|ended&lt;br /&gt;
|When a process ends. Example: Lesson ended or course reset ended.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|evaluated&lt;br /&gt;
|Material has been evaluated.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|exported&lt;br /&gt;
|When a report is exported in certain format.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|failed&lt;br /&gt;
|Learner did not perform the activity to a level of pre-determined satisfaction. Used to affirm the lack of success a learner experienced within the learning content in relation to a threshold. If the user performed below the minimum to the level of this threshold, the content is &#039;failed&#039;. The opposite of &#039;passed&#039;. This is also used in case when message sending is failed.&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|graded&lt;br /&gt;
|Used to represent an activity was graded.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|granted&lt;br /&gt;
|User is granted some extension or capability. Example: extension granted for submission.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|imported&lt;br /&gt;
|The act of moving an object into another location or system.&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|launched&lt;br /&gt;
|When an external object is launched. Try consider started if there is related stopped event.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|locked&lt;br /&gt;
|When an activity is locked. Should have a related unlocked event.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|loggedin/loggedout&lt;br /&gt;
|	For login and logout.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|loggedinas&lt;br /&gt;
|	 If user is logged in as different user. This is used by only one event (user_loggedinas). Adding this verb makes event name more clear, then using loggedin verb.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|locked&lt;br /&gt;
|&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|moved&lt;br /&gt;
|	Used to indicate the object in context was moved.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|passed&lt;br /&gt;
|Used to affirm the success a learner experienced within the learning content in relation to a threshold. If the user performed at a minimum to the level of this threshold, the content is &#039;passed&#039;. The opposite of &#039;failed&#039;.&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|printed&lt;br /&gt;
|Something is printed.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|reassessed&lt;br /&gt;
|Submitted material has been assessed again.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|reevaluated&lt;br /&gt;
|Material has been evaluated again.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|removed&lt;br /&gt;
|By opposition to &amp;quot;Added&amp;quot;. This does not mean that the object has been deleted, but removed from the entity, or not bound to it any more.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|reset&lt;br /&gt;
|Sets one or more properties back to the default value.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|restored&lt;br /&gt;
|When restoring a backup. Rolling back to a previous state.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|revealed&lt;br /&gt;
|Some identity is revealed. Example: Identities revealed after blind marking.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|searched&lt;br /&gt;
|Something is searched. Example: searched in course.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|sent&lt;br /&gt;
|Message sent.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|started&lt;br /&gt;
|Some activity started&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|submitted&lt;br /&gt;
|This is very close to &amp;quot;Attempted&amp;quot;. Depends on context which one should be used. For example:- &amp;quot;Admin submitted a form. Student attempted a quiz.&amp;quot;  is correct, however some cases might not be as clear as the previous example. We can say both &amp;quot;Student submitted an assignment&amp;quot; or &amp;quot;student attempted an assignment&amp;quot;. We need to make the difference clear.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|suspended&lt;br /&gt;
| Suspend something. (example a user)&lt;br /&gt;
| Tincan (However the context is different)&lt;br /&gt;
|-&lt;br /&gt;
|switched&lt;br /&gt;
|Something has been switched. For example:- The workshop phase has been switched to assessment&amp;quot;&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|unassigned&lt;br /&gt;
|As opposed to assigned. When some role is unassigned.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|unlocked&lt;br /&gt;
|&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|upgraded&lt;br /&gt;
|Something was upgraded, some module probably&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|updated&lt;br /&gt;
|Used to indicate the object in context was updated. Simple example is &amp;quot;Admin updated course xyz&amp;quot;.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|uploaded&lt;br /&gt;
|When an assignment is uploaded.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|viewed&lt;br /&gt;
|Something has been viewed. For example:- &amp;quot;Student viewed chapter 1 of book 1.&amp;quot;&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Rules ===&lt;br /&gt;
&lt;br /&gt;
==== Use singular ====&lt;br /&gt;
&lt;br /&gt;
Plurals must be used on objects when it&#039;s a &#039;&#039;One to Many&#039;&#039; relationship. Ex: bulk import, mass deletion, ... In any other case, use the singular.&lt;br /&gt;
&lt;br /&gt;
==== Ends with a verb ====&lt;br /&gt;
&lt;br /&gt;
The last word (after the last underscore) must be a verb.&lt;br /&gt;
&lt;br /&gt;
=== Deprecated events ===&lt;br /&gt;
Following are the events that were supported in 2.5, but deprecated in 2.6 or later&lt;br /&gt;
&lt;br /&gt;
groups_groupings_deleted (see MDL-41312)&lt;br /&gt;
&lt;br /&gt;
groups_groupings_groups_removed (see MDL-41312)&lt;br /&gt;
&lt;br /&gt;
groups_groups_deleted (see MDL-41312)&lt;br /&gt;
&lt;br /&gt;
groups_members_removed (see MDL-41312)&lt;br /&gt;
&lt;br /&gt;
== Shared events ==&lt;br /&gt;
&lt;br /&gt;
 Decision: Not supported at this stage.&lt;br /&gt;
&lt;br /&gt;
In Moodle 2.5 we have a good example of a shared event: &#039;assessable_content_uploaded&#039; which is triggered in &#039;&#039;forum&#039;&#039;, &#039;assignment&#039;&#039; and &#039;&#039;workshop&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The problem with shared events is that we cannot easily track what component triggered them. Of course we could add a new property to the event to keep track of that, but we would soon need more information and more properties. Also, in the case of a logger, the event received would be unique, where in fact it should be considered different depending on the component firing it.&lt;br /&gt;
&lt;br /&gt;
In our first implementation, we will create one specific event per module. This flexibility does not prevent any observer from capturing them, but still makes sure that the consistency and specificity of each event is maintained.&lt;br /&gt;
&lt;br /&gt;
It could happen that some events are defined in core and shared, but this should not really happen as low-level APIs should trigger the event, and a module should call that low API instead of doing the job itself.&lt;br /&gt;
&lt;br /&gt;
== One to many ==&lt;br /&gt;
&lt;br /&gt;
 Decision: Each event should have a one to one relationship. We can reconsider this at a later stage, if the performance hit is extremely high.&lt;br /&gt;
&lt;br /&gt;
In 2.5, some events are triggered when an action happens on multiple objects. We have to decide whether we want to keep supporting &#039;&#039;One to Many&#039;&#039; events or not.&lt;br /&gt;
&lt;br /&gt;
Keeping a list of all changes for multiple actions may be problematic because you would have to keep them all in memory until all things are processed. This might also result in the order of events being incorrect. The only correct solution seems to be to trigger each item individually and then many things at the end. Performance needs to be improved elsewhere...&lt;br /&gt;
&lt;br /&gt;
=== Accuracy ===&lt;br /&gt;
&lt;br /&gt;
When uploading a bunch of users using the CSV upload feature, if only one event is triggered, it means that the observers of &#039;&#039;user_created&#039;&#039; won&#039;t be triggered. And so some functionality can be lost as, as a plugin developer, I expect this &#039;&#039;user_created&#039;&#039; to be triggered regardless of the way they have been uploaded. Of course, the developer could observe the event &#039;&#039;bulk_user_imported&#039;&#039;, but that means that he could miss some relevant observers.&lt;br /&gt;
&lt;br /&gt;
This applies to existing events.&lt;br /&gt;
&lt;br /&gt;
=== Performance ===&lt;br /&gt;
&lt;br /&gt;
Triggering one event is cheaper then repeating the same events x number of times...&lt;br /&gt;
&lt;br /&gt;
=== Information tracking ===&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;bulk&#039;&#039; event, might not be verbose enough to allow for proper logging afterwards. Though this is the responsibility of the logger, we probably want to make it easy to store relevant information.&lt;br /&gt;
&lt;br /&gt;
=== Double event ===&lt;br /&gt;
&lt;br /&gt;
In the case of a bulk user import, if we were to trigger an event per user created, we probably want to trigger one event &#039;user_bulk_upload_started&#039; when the action starts.&lt;br /&gt;
&lt;br /&gt;
== Unit Testing ==&lt;br /&gt;
&lt;br /&gt;
With unit testing for this system we want to assert the following:&lt;br /&gt;
&lt;br /&gt;
* That event strict validation and custom validation works.&lt;br /&gt;
* Missing event data is auto filled with accurate data.&lt;br /&gt;
* Typos in properties passed to ::create() are captured (if we decide to validate).&lt;br /&gt;
* The legacy methods return the expected values (use assertEventLegacyData() and assertEventLegacyData())&lt;br /&gt;
* The class properties are correctly overridden (crud, level, action, object, ...).&lt;br /&gt;
* The properties automatically generated (component, name, ...) are correct.&lt;br /&gt;
* Events are dispatched to the corresponding observers.&lt;br /&gt;
* Events are dispatched to the corresponding legacy handlers.&lt;br /&gt;
* Events are dispatched to the * observers.&lt;br /&gt;
* Events perform an add_to_log() if it has legacy log data.&lt;br /&gt;
* &#039;Events restore&#039; restored the whole event data, and does not miss any information.&lt;br /&gt;
* &#039;Events restore&#039; does not generate any extra information.&lt;br /&gt;
* Event methods should check context object or avoid using it, as context might not be valid at time of event restore (use assertEventContextNotUsed())&lt;br /&gt;
&lt;br /&gt;
= PHP docs =&lt;br /&gt;
* All events php docs must include @since parameter, indicating when the event was first included in standard Moodle distribution.&lt;br /&gt;
* All events must declare the $other properties using mark down in the php docs.&lt;br /&gt;
&lt;br /&gt;
= Example events =&lt;br /&gt;
&lt;br /&gt;
== Assignment ==&lt;br /&gt;
&lt;br /&gt;
Assumption: Course contains groups with students in each group.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.&#039;&#039;&#039; Teacher creates an assignment with group mode set to &#039;Separate groups&#039; and Feedback type set to comments and files.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has created assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;2.&#039;&#039;&#039; A student views the assignment.&lt;br /&gt;
*Event: User &#039;Student&#039; has viewed assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;3.&#039;&#039;&#039; A member from one of the groups submits an assignment&lt;br /&gt;
*Event: User &#039;Student&#039; has added a submission for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to the teacher and all students in that group.&lt;br /&gt;
&#039;&#039;&#039;4.&#039;&#039;&#039; User &#039;Adrian&#039; adds some changes to the assignment and updates it.&lt;br /&gt;
*Event: User &#039;Adrian&#039; has updated the submission for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to the teacher and all students in that group.&lt;br /&gt;
&#039;&#039;&#039;5.&#039;&#039;&#039; Teacher views the assignment.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has viewed assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;6.&#039;&#039;&#039; Teacher clicks on &#039;View/grade all submissions&#039;&lt;br /&gt;
*Event: User &#039;Teacher&#039; has viewed the assignment &#039;B&#039; grade area in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;7.&#039;&#039;&#039; Teacher clicks to grade the student&#039;s submission.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has viewed the submission for user &#039;student&#039; for assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;8.&#039;&#039;&#039; Teacher marks the assignment with the setting &#039;Apply grades and feedback to entire group&#039; set to &#039;Yes&#039; leaving a comment and a file.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has marked assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has left a comment for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has uploaded a feedback file for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has uploaded a file to the course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to user &#039;Student&#039; notifying them their submission for assignment &#039;B&#039; has been marked. - This is done for all users in the group.&lt;br /&gt;
&#039;&#039;&#039;9.&#039;&#039;&#039; User &#039;Adrian&#039; views the feedback.&lt;br /&gt;
*Event: User &#039;Adrian&#039; has viewed assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;10.&#039;&#039;&#039; User &#039;Adrian&#039; opens the feedback file.&lt;br /&gt;
*Event: User &#039;Adrian&#039; has viewed the file &#039;A&#039; for assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;11.&#039;&#039;&#039; User &#039;Adrian&#039; adds some changes to the assignment insulting the teachers marking and updates it.&lt;br /&gt;
*Event: User &#039;Adrian&#039; has updated the submission for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to user &#039;Teacher&#039; notifying them that user &#039;Adrian&#039; has updated the submission for assignment &#039;B&#039;.&lt;br /&gt;
*Event: Email sent to user &#039;Student&#039; notifying them their submission for assignment &#039;B&#039; has been updated. - This is done for all users in the group.&lt;br /&gt;
&#039;&#039;&#039;12.&#039;&#039;&#039; The teacher clicks directly on the link in the email to be taken to the grading page.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has viewed the submission for user &#039;student&#039; for assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;13.&#039;&#039;&#039; The teacher is upset due to the harsh comments and decides to mark Adrian down, but not the rest of the group by setting &#039;Apply grades and feedback to entire group&#039; set to &#039;No&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has marked assignment &#039;B&#039; for user &#039;Adrian&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has left a comment for assignment &#039;B&#039; for user &#039;Adrian&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has uploaded a feedback file for assignment &#039;B&#039; for user &#039;Adrian&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to user &#039;Adrian&#039; notifying them their submission for assignment &#039;B&#039; has been marked.&lt;br /&gt;
&lt;br /&gt;
= FAQs =&lt;br /&gt;
&lt;br /&gt;
; Why not use create events in core subsystems? : Because we could not see all core events in one place, it would create problems when naming event classes and finally subsystems are incomplete, we would have to add more now because we could not move the events in the future.&lt;br /&gt;
&lt;br /&gt;
= Development stages =&lt;br /&gt;
&lt;br /&gt;
== Stage 1 ==&lt;br /&gt;
&lt;br /&gt;
* Finish class loader spec and implement basic Frankenstyle class loader.&lt;br /&gt;
* Describe new observer definition - just few new flags in current db/events.php&lt;br /&gt;
* Describe new event dispatcher.&lt;br /&gt;
* Describe core_event_base class.&lt;br /&gt;
* Current (= legacy) events triggering:&lt;br /&gt;
** Re-factor current event handling code to new self-contained class - do not change functionality, keep events_trigger().&lt;br /&gt;
** Create new event handler management class that deals with installation and upgrades of both legacy and new handlers.&lt;br /&gt;
* New events:&lt;br /&gt;
** Create new core_event_base class.&lt;br /&gt;
** Create new self-contained event dispatcher class with &#039;*&#039; handler support.&lt;br /&gt;
** In function core_event_base::trigger() check if the  event has property &#039;legacyeventname&#039; execute events_trigger($this-&amp;gt;legacyeventname, $this-&amp;gt;legacyeventdata) after triggering new event.&lt;br /&gt;
** Write unit tests for all new events code.&lt;br /&gt;
* No changes to be made to the current logging system yet.&lt;br /&gt;
&lt;br /&gt;
After completing this stage everything should continue to work as it did before and we can start parallel work on further stages.&lt;br /&gt;
&lt;br /&gt;
== Stage 2 (requires completion of Stage 1) ==&lt;br /&gt;
&lt;br /&gt;
* Create event classes and replace existing calls to events_trigger() and with new event classes containing legacy information properties.&lt;br /&gt;
* Add more events throughout the standard Moodle package in places where we have add_to_log(). Implement some_event::get_legacy_log_data() which returns original parameters of add_to_log() and remove it. Old add_to_log() function is called in core_event_base::trigger() automatically with original parameters.&lt;br /&gt;
* Add even more new events all over the place.&lt;br /&gt;
&lt;br /&gt;
The difficult part is defining the new event classes properly because we must not change them after the 2.6 release.&lt;br /&gt;
&lt;br /&gt;
== Stage 3 (requires partial completion of Stage 2) ==&lt;br /&gt;
&lt;br /&gt;
* Migrate current legacy event handlers to new handlers with one event class instance parameter, ex.: enrol plugins.&lt;br /&gt;
&lt;br /&gt;
== Stage 4 (requires partial completion of Stage 2) ==&lt;br /&gt;
&lt;br /&gt;
* Implement an event logging handler.&lt;br /&gt;
* Implement logging storage plugins.&lt;br /&gt;
* Define logging apis.&lt;br /&gt;
* Create new reports.&lt;br /&gt;
* Switch to new logging everywhere after Stage 2 has been completed and new reports are usable.&lt;br /&gt;
&lt;br /&gt;
See [[Logging 2]]&lt;br /&gt;
&lt;br /&gt;
== Stage 5  ==&lt;br /&gt;
&lt;br /&gt;
* Decide how much backwards compatibility we want for old log tables. Most probably they will get only legacy log data.&lt;br /&gt;
* Implement some BC solution for old code that reads log tables directly.&lt;br /&gt;
&lt;br /&gt;
See [[Logging 2]]&lt;br /&gt;
&lt;br /&gt;
== Stage 6 (requires completion of Stage 4 and 5) ==&lt;br /&gt;
&lt;br /&gt;
Moodle 2.8dev? This is the ultimate end of old logging via the &#039;&#039;log&#039;&#039; table.&lt;br /&gt;
&lt;br /&gt;
* Deprecate the add_to_log() function with a debug message and do nothing inside.&lt;br /&gt;
* Remove all legacy logging from event classes.&lt;br /&gt;
&lt;br /&gt;
See [[Logging 2]]&lt;br /&gt;
&lt;br /&gt;
= See Also =&lt;br /&gt;
[[Logging 2]]  &lt;br /&gt;
&lt;br /&gt;
[[Tin Can]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Events_API&amp;diff=44521</id>
		<title>Events API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Events_API&amp;diff=44521"/>
		<updated>2014-04-24T08:14:15Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Project&lt;br /&gt;
|name = Events 2&lt;br /&gt;
|state = Implementation in progress&lt;br /&gt;
|tracker = MDL-39797 , MDL-39952, MDL-39846&lt;br /&gt;
|discussion = https://moodle.org/mod/forum/discuss.php?d=229425&lt;br /&gt;
|assignee = Backend Team&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
= What are events? =&lt;br /&gt;
&lt;br /&gt;
Events are atomic pieces of information describing something that happened in Moodle. Events are primarily the result of user actions, but could also be the result of the [[:en:Cron|cron]] process or administration actions [[:en:Administration via command line|undertaken via the command line]].&lt;br /&gt;
&lt;br /&gt;
When an action takes place, an event is created by a [[Core APIs|core API]] or [[Plugins|plugin]]. The Events system then disseminates this event information to observers registered for this event. In this way, the events system acts as a communication backbone throughout the Moodle system.&lt;br /&gt;
&lt;br /&gt;
Event observers can not modify event data or interrupt the dispatching of events, it is a one way communication channel.&lt;br /&gt;
&lt;br /&gt;
= Why is a new events system needed? =&lt;br /&gt;
&lt;br /&gt;
The need to improve the Events system was prompted by a need for a richer and more efficient logging system, however the benefits of this improvement will be useful to other parts of Moodle that observe event information.&lt;br /&gt;
&lt;br /&gt;
* The events need to be more strictly defined if we want to use them for new logging and other advanced use cases. They need to contain a lot more information in a standardised way (such as most fields from current log table and log_actions table).&lt;br /&gt;
* Complex data types were allowed in old events which was causing major problems when serialising/storing/unserializing the data.&lt;br /&gt;
* The logging and events contain similar information and are triggered at the same places, new events would remove this code duplication. All events should be loggable and all current log entries should be triggered as events.&lt;br /&gt;
* The logging system will become an event observer, listening to all events and directing them to logging storage plugins in a controllable way.&lt;br /&gt;
* It will be possible to subscribe to &#039;*&#039; event, which would allow a system to potentially observe, and selectively deal with, all events. Current handlers do not get event name which makes this problematic.&lt;br /&gt;
* Current event handlers may trigger exceptions during site upgrade which would lead to fatal upgrade problems. The new design eliminates this.&lt;br /&gt;
* Failure in handlers blocked dispatching of subsequent events. Instead problems in new observers would be only logged and execution would continue normally.&lt;br /&gt;
* Current execution of external handlers during DB transactions blocks other handlers. This would be eliminated by in-memory buffer for external events.&lt;br /&gt;
* It would good to have observer priority.&lt;br /&gt;
* Nested events are not dispatched sequentially, it would change the order of events received in lower priority handlers.&lt;br /&gt;
&lt;br /&gt;
= Performance =&lt;br /&gt;
Some basic profiling has been conducted.&lt;br /&gt;
&lt;br /&gt;
There is a general plan to complete pre- and post-implementation testing as development happens. The new system will be imemented in parallel with the old one which should help with comparison of new and old logging and event triggering performance on each page.&lt;br /&gt;
&lt;br /&gt;
Our aim is to trigger more events and log more information, which is going to impact on performance. We hope to offset that impact by improving log storage, simplifying event dispatching and adding other core performance improvements. The proposed class structure of the base event should allow some new advanced techniques, which may also improve performance in some scenarios.&lt;br /&gt;
&lt;br /&gt;
More details will be added to this section soon.&lt;br /&gt;
&lt;br /&gt;
= Events API =&lt;br /&gt;
&lt;br /&gt;
Each plugin will define the events that it can report (trigger) by extending an abstract base class, once for each possible event. This approach will have several benefits.&lt;br /&gt;
; Events will be active objects&lt;br /&gt;
: When they are triggered and possibly after they are reinstantiated (say, when they are retrieved from a log), an event object will be able to provide callback functions for various purposes (such as capability checks).&lt;br /&gt;
; Automatic inclusion&lt;br /&gt;
: Event class definitions will be automatically included when needed, without having to maintain lists of known event types. New event definitions can be added without the need to upgrade, only purging of MUC cache is required after adding new observer.&lt;br /&gt;
; Maintainability&lt;br /&gt;
: It will be easy to add new events and migrate existing events. Code review will be simplified because there will be less duplication of code when triggering events and all event related information/code will be concentrated in one file in fixed locations.&lt;br /&gt;
; Self documenting&lt;br /&gt;
: The behaviour of events will be combined with the definition of events in one place (file). It will be easy for event observer writers to know what events a plugin can trigger. This includes support for autocompletion and code inspection in modern IDEs.&lt;br /&gt;
; Quick, self-validating data structure&lt;br /&gt;
: As events are instantiated objects, the PHP processor will validate the structure and type of event classes. This does not ensure data value validity, but does give some assurance of consistency and it also detects common typos.&lt;br /&gt;
&lt;br /&gt;
== Backwards compatibility and migration ==&lt;br /&gt;
&lt;br /&gt;
Events:&lt;br /&gt;
* Moodle core and standard plugins will replace all calls to the events_trigger() function with new events classes.&lt;br /&gt;
* For events that already exist in Moodle 2.5 the additional legacy information should be added to the event data (in properties &#039;legacyeventname&#039; and &#039;legacyeventdata&#039;.&lt;br /&gt;
* The function events_trigger() will continue working as before, but it will be called automatically after a new event is processed using the &#039;legacyeventname&#039; and &#039;legacyeventdata&#039;.&lt;br /&gt;
* The legacy events handling code will be maintained  separately and will continue being supported in Moodle 2.x. New legacy events will not be added.&lt;br /&gt;
* Existing legacy event handlers will be migrated to new event handlers accepting new event class instances.&lt;br /&gt;
* More subsystems may be migrated to events-handlers, ex.: gradebook history.&lt;br /&gt;
&lt;br /&gt;
Logging:&lt;br /&gt;
* Function add_to_log() and all logging internals will continue working as before.&lt;br /&gt;
* Existing add_to_log() parameters will be migrated inside new events method get_legacy_log_data() and core_event_base::trigger() will call add_to_log() automatically (this will depend on $CFG-&amp;gt;loglifetime setting for performance reasons).&lt;br /&gt;
&lt;br /&gt;
== Event dispatching and observers ==&lt;br /&gt;
&lt;br /&gt;
The new event dispatching system is completely separate from the old events code. Original event handlers are now called observers with the description stored in the same db/events.php file, but as a new array with a different format.&lt;br /&gt;
&lt;br /&gt;
=== Event observers ===&lt;br /&gt;
&lt;br /&gt;
The observers are described in db/events.php in the array $observers, the array is not indexed and contains a list of observers defined as an array with the following properties;&lt;br /&gt;
* eventname - event class name or &amp;quot;*&amp;quot; indicating all events. All events must use namespace, ex.: &#039;&#039;\plugintype_pluginname\event\something_happened&#039;&#039;.&lt;br /&gt;
* callback - PHP callable type.&lt;br /&gt;
* includefile - optional. File to be included before calling the observer. Path relative to dirroot.&lt;br /&gt;
* priority - optional. Defaults to 0. Observers with higher priority are notified first.&lt;br /&gt;
* internal - optional. Defaults to true. Non-internal observers are not called during database transactions, but instead after a successful commit of the transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$observers = array(&lt;br /&gt;
&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;eventname&#039;   =&amp;gt; &#039;\core\event\sample_executed&#039;,&lt;br /&gt;
        &#039;callback&#039;    =&amp;gt; &#039;core_event_sample_observer::observe_one&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;eventname&#039;   =&amp;gt; &#039;\core\event\sample_executed&#039;,&lt;br /&gt;
        &#039;callback&#039;    =&amp;gt; &#039;core_event_sample_observer::external_observer&#039;,&lt;br /&gt;
        &#039;priority&#039;    =&amp;gt; 200,&lt;br /&gt;
        &#039;internal&#039;    =&amp;gt; false,&lt;br /&gt;
    ),&lt;br /&gt;
&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;eventname&#039;   =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;callback&#039;    =&amp;gt; &#039;core_event_sample_observer::observe_all&#039;,&lt;br /&gt;
        &#039;includefile&#039; =&amp;gt; null,&lt;br /&gt;
        &#039;internal&#039;    =&amp;gt; true,&lt;br /&gt;
        &#039;priority&#039;    =&amp;gt; 9999,&lt;br /&gt;
    ),&lt;br /&gt;
&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Event dispatching ===&lt;br /&gt;
&lt;br /&gt;
A list of available observers is constructed on the fly directly from all available events.php files. Previously handlers were installed only during installation and upgrade. There is no risk of performance regression because the list is already cached in MUC. Observers get events before installation or any upgrade, however observers are not notified during the initial installation of moodle core tables.&lt;br /&gt;
&lt;br /&gt;
Developers of observers must make sure that execution does not end with a fatal error under any condition (before install, before upgrade or normal operation). Exceptions are automatically captured, logged in the PHP error log, and notification of other observers continues. Current handlers must not throw any exceptions at any time.&lt;br /&gt;
&lt;br /&gt;
Observers are notified sequentially in the same order in which events were triggered. This means that events triggered in observers are queued in FIFO buffer and are processed after all observers are notified.&lt;br /&gt;
&lt;br /&gt;
=== Differences from old event handling ===&lt;br /&gt;
&lt;br /&gt;
# New events contain a lot more structured information.&lt;br /&gt;
# New event data must not contain any PHP classes.&lt;br /&gt;
# There is separate context cache which may be used when deleting data or for observer performance improvements.&lt;br /&gt;
# No database access in new event dispatching code.&lt;br /&gt;
# There is no support for cron execution - this eliminates performance problems, simplifies events dispatching and prevents abuse of cron events.&lt;br /&gt;
# Events triggered in observers are processed in a different order.&lt;br /&gt;
# External events are buffered when a transaction is in progress, instead of being sent to the cron queue.&lt;br /&gt;
# It is possible to define multiple observers for one event in one events.php file.&lt;br /&gt;
# It is possible to subscribe an observer to all events.&lt;br /&gt;
# The new event manager is using frankenstyle autoloading - smaller memory footprint when events are not used on the current page.&lt;br /&gt;
&lt;br /&gt;
== Triggering events ==&lt;br /&gt;
&lt;br /&gt;
* All event descriptions are objects extending the \core\event\base class.&lt;br /&gt;
* Events are triggered by creating a new instance of the class event and executing $event-&amp;gt;trigger().&lt;br /&gt;
* Each event class name is a unique identifier of the event.&lt;br /&gt;
* Class names and namespace follow the identifier scheme \&#039;&#039;&#039;frankenstyle_component&#039;&#039;&#039;\event\&#039;&#039;&#039;some_object_action&#039;&#039;&#039;. Core events have prefix &#039;core_&#039;.&lt;br /&gt;
* Plugins define each event class in a separate file. File name and location must match the class name, for example: &#039;&#039;&#039;plugindir&#039;&#039;&#039;/classes/event/&#039;&#039;&#039;something_happened&#039;&#039;&#039;.php&lt;br /&gt;
* The event identifier suffix has the form &#039;&#039;some_object_action&#039;&#039;  (&#039;&#039;&#039;something_happened&#039;&#039;&#039; in the example above) and should follow our standard naming convention. The last word after underscore is automatically parsed as action, the rest of words is object.&lt;br /&gt;
&lt;br /&gt;
Decision:[[#Verb_list| Recommended verb list]]&lt;br /&gt;
&lt;br /&gt;
Examples: \core\event\course_completed, \mod_assign\event\submission_commented, \mod_forum\event\post_shared, \mod_forum\event\post_responded, etc.&lt;br /&gt;
&lt;br /&gt;
* Ideally, it should be possible to trigger an event without gathering additional information for the event. To reduce the cost of data gathering, specifically the cost of database reads, at least the minimal values needed to trigger an event should be already available in variables.&lt;br /&gt;
&lt;br /&gt;
An example of triggering an event:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event = \mod_myplugin\event\something_happened::create(array(&#039;context&#039; =&amp;gt; $context, &#039;objectid&#039; =&amp;gt; YYY, &#039;other&#039; =&amp;gt; ZZZ));&lt;br /&gt;
// ... code that may add some record snapshots&lt;br /&gt;
$event-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Use of php autoloading ===&lt;br /&gt;
&lt;br /&gt;
All new OOP APIs in Moodle 2.6 are going to use class auto loading - see [[Automatic class loading]]. New events use PHP strictly defined namespaces which concentrate all events classes in classes/event/ subdirectory.&lt;br /&gt;
&lt;br /&gt;
=== Why separate classes? ===&lt;br /&gt;
There were two alternatives proposed on how to define the event structure. The first is a separate class for each event (extending the base class), the other being each event is based on a generic event instance of the base class.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Decision: Use separate class for each event.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Each plugin creates its own event class for each event&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Pros&lt;br /&gt;
* Maintainability - It is much easier to review, debug, integrate.&lt;br /&gt;
* Self documenting, behaviour is combined with definition.&lt;br /&gt;
* It is extremely flexible for plugin developers and core devs too.&lt;br /&gt;
* Automatically lists events without being installed - PHPDocs as events documentation.&lt;br /&gt;
* It is included only when needed using autoloading.&lt;br /&gt;
* Self-validating data structure (by PHP).&lt;br /&gt;
* Some developers will find it easier to copy whole class files as templates.&lt;br /&gt;
Cons&lt;br /&gt;
* Big learning curve for developers without OOP skills (all other new subsystems in Moodle already use OOP, you can not code without these skills any more).&lt;br /&gt;
* Some developers may find it harder to copy-and-paste examples because they will need to create new class first and use it afterwards (this can be viewed as a benefit because it forces developers to think more about events).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Each plugin defines events in a list based on a generic object&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Pros&lt;br /&gt;
* Easier for some developers (this can be eliminated with developer documentation).&lt;br /&gt;
* Some developers think it gives more control of event structure in core (we can easily solve that with private access and validation in the base class).&lt;br /&gt;
Cons&lt;br /&gt;
* It is not flexible enough. PHP code gives developers more freedom.&lt;br /&gt;
* It would not be possible to implement any performance hacks in custom methods. All data would have to be calculated even if it is not used.&lt;br /&gt;
* It would be necessary to define access control callbacks in other code.&lt;br /&gt;
* It would be harder and slower to integrate legacy logging.&lt;br /&gt;
* It would be harder and slower to implement support for legacy events.&lt;br /&gt;
* Event observers could not use event class names as reliable identifiers.&lt;br /&gt;
* Event object and action could not be parsed from class name, it would have to be stored in event properties every time you trigger event.&lt;br /&gt;
* Requires upgrade/install to register an event in DB table with MUC cache. Events could not be triggered earlier.&lt;br /&gt;
* The localised descriptions and names would have to be stored as properties, it would not be possible to store them in any definition.&lt;br /&gt;
* The implementation of an events infrastructure would be significantly more complex and error prone.&lt;br /&gt;
&lt;br /&gt;
== Information contained in events ==&lt;br /&gt;
&lt;br /&gt;
Events have to contain as much information as they can, but this should not affect the performance. That&#039;s why part of the information is available in properties, and the rest via methods. This allows for delaying the computation of the data at the time it is really needed, if it ever is.&lt;br /&gt;
&lt;br /&gt;
=== Properties ===&lt;br /&gt;
&lt;br /&gt;
List of properties that the developer has to pass to the event upon creation, or automatically generated when possible and cost free. Some of those properties not mandatory.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Property name&lt;br /&gt;
! Title&lt;br /&gt;
! Type&lt;br /&gt;
! Comment&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;eventname&#039;&#039;&lt;br /&gt;
| Event name&lt;br /&gt;
| &#039;&#039;static, automatic from class name&#039;&#039;&lt;br /&gt;
| Automatically computed by copying class name&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;component&#039;&#039;&lt;br /&gt;
| Component&lt;br /&gt;
| &#039;&#039;static, automatic from top namespace&#039;&#039;&lt;br /&gt;
| Component declaring the event, automatically computed from class name.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;action&#039;&#039;&lt;br /&gt;
| Action&lt;br /&gt;
| &#039;&#039;static, automatic from last word in class name&#039;&#039;&lt;br /&gt;
| Can be automatically computed from class name.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;target&#039;&#039;&lt;br /&gt;
| target of action&lt;br /&gt;
| &#039;&#039;static, automatic from class name&#039;&#039;&lt;br /&gt;
| Target on which the action is taken, can be automatically computed from class name.&lt;br /&gt;
|-&lt;br /&gt;
| objecttable&lt;br /&gt;
| Database table name&lt;br /&gt;
|&lt;br /&gt;
| optional database table name where is/was the object stored. Never use a relationship table here.&lt;br /&gt;
|-&lt;br /&gt;
| objectid&lt;br /&gt;
| Object ID&lt;br /&gt;
|&lt;br /&gt;
| optional id of the object record from objecttable&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;&#039;&#039;crud&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
| Transaction type&lt;br /&gt;
| &#039;&#039;static mandatory&#039;&#039;&lt;br /&gt;
| One of [crud] letters. Statically declared in the event class method init().&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;&#039;&#039;level&#039;&#039;&#039;&#039;&#039; / &#039;&#039;&#039;&#039;&#039;edulevel&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
| Level&lt;br /&gt;
| &#039;&#039;static mandatory&#039;&#039;&lt;br /&gt;
| Level of educational value of the event. Statically declared in the event class method init(). Changed from &#039;&#039;&#039;&#039;&#039;level&#039;&#039;&#039;&#039;&#039; to &#039;&#039;&#039;&#039;&#039;edulevel&#039;&#039;&#039;&#039;&#039; in Moodle 2.7 (See below for more details)&lt;br /&gt;
|-&lt;br /&gt;
| contextid&lt;br /&gt;
| Context ID&lt;br /&gt;
| mandatory&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| contextlevel&lt;br /&gt;
| Context level&lt;br /&gt;
| automatic from context&lt;br /&gt;
| This tells you if it was a course, activity, course category, etc.&lt;br /&gt;
|-&lt;br /&gt;
| contextinstanceid&lt;br /&gt;
| Context instanceid&lt;br /&gt;
| automatic from context&lt;br /&gt;
| Based on context level this may be course id , course module id, course category, etc.&lt;br /&gt;
|-&lt;br /&gt;
| userid&lt;br /&gt;
| User ID&lt;br /&gt;
| defaults to current user&lt;br /&gt;
| User ID, or 0 when not logged in, or -1 when other (System, CLI, Cron, ...)&lt;br /&gt;
|-&lt;br /&gt;
| courseid&lt;br /&gt;
| Affected course&lt;br /&gt;
| defaults to course context from context&lt;br /&gt;
| This is used only for contexts at and bellow course level - this can be used to filter events by course (includes all course activities)&lt;br /&gt;
|-&lt;br /&gt;
| relateduserid&lt;br /&gt;
| Affected user&lt;br /&gt;
|&lt;br /&gt;
| Is this action related to some user? This could be used for some personal timeline view.&lt;br /&gt;
|-&lt;br /&gt;
| other&lt;br /&gt;
| All other data&lt;br /&gt;
|&lt;br /&gt;
| Any other fields needed for event description - scalars or arrays, must be serialisable using json_encode()&lt;br /&gt;
|-&lt;br /&gt;
| timecreated&lt;br /&gt;
| Time of the event&lt;br /&gt;
| automatic&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;static&#039;&#039;: It is the same for all event instances of this class.&lt;br /&gt;
* &#039;&#039;&#039;mandatory&#039;&#039;&#039;: Is required in order to trigger the event.&lt;br /&gt;
&lt;br /&gt;
==== Level property ====&lt;br /&gt;
&lt;br /&gt;
The edulevel property helps defining the educational value of the event. It is intentional that the list is limited to only 3 different constants, having too many options would make it harder for developers to pick the right one(s). We also have to keep in mind that this is not supposed to answer all the questions about a particular event, other event properties like the courseid, the context, the component name can be used with the level to get more granular reports.&lt;br /&gt;
&lt;br /&gt;
Remember that this is event based. If the user that has triggered the event is not really &amp;quot;participating&amp;quot; because he is an admin, or a manager, then it is the job of the report to filter those. The event itself has a static educational level.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Teaching&#039;&#039;&#039; (LEVEL_TEACHING: 1)&lt;br /&gt;
&lt;br /&gt;
Any event/action that is performed by someone (typically a teacher) and has a teaching value (anything that is affecting the learning experience/environment of the students). This should not be combined with &amp;quot;Participating&amp;quot; events.&lt;br /&gt;
&lt;br /&gt;
Valid events:&lt;br /&gt;
&lt;br /&gt;
* A teacher grading a student&lt;br /&gt;
* A teacher modifying the course settings&lt;br /&gt;
* A teacher adding a new section to the course page&lt;br /&gt;
* A teacher modifying a module settings&lt;br /&gt;
* A teacher adding a page to course&lt;br /&gt;
* A teacher leaving a feedback&lt;br /&gt;
&lt;br /&gt;
INVALID events:&lt;br /&gt;
&lt;br /&gt;
* A teacher posting in a forum (it might affect the learning experience, but not necessarily, so the teacher is just participating)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Participating&#039;&#039;&#039; (LEVEL_PARTICIPATING: 2)&lt;br /&gt;
&lt;br /&gt;
Any event/action that is performed by a user, that is related (or could be related) to his learning experience.&lt;br /&gt;
&lt;br /&gt;
Valid events:&lt;br /&gt;
&lt;br /&gt;
* A user posting to a forum&lt;br /&gt;
* A user submitting an assignment&lt;br /&gt;
* A user blogging&lt;br /&gt;
* A user reading someone&#039;s blog&lt;br /&gt;
* A user posting a comment&lt;br /&gt;
* A user chatting on a chat activity&lt;br /&gt;
* A user viewing the course page&lt;br /&gt;
* A user deletes a blog post&lt;br /&gt;
&lt;br /&gt;
INVALID events:&lt;br /&gt;
&lt;br /&gt;
* A user updating his profile&lt;br /&gt;
* A user visiting someone&#039;s profile&lt;br /&gt;
* A user viewing his /my/ page&lt;br /&gt;
* A user sending a message to another one&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Other&#039;&#039;&#039; (LEVEL_OTHER: 0)&lt;br /&gt;
&lt;br /&gt;
Any other action, whether they are related to the site administration, or are specific to user. They do not have any educational value.&lt;br /&gt;
&lt;br /&gt;
=== Methods ===&lt;br /&gt;
&lt;br /&gt;
The computation of this data is not required by default, but can be accessed by any event observer if need be.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Comment&lt;br /&gt;
|-&lt;br /&gt;
| get_name()&lt;br /&gt;
| Returns localised name of the event, it is the same for all instances.&lt;br /&gt;
|-&lt;br /&gt;
| get_description()&lt;br /&gt;
| Returns localised description of one particular event.&lt;br /&gt;
|-&lt;br /&gt;
| can_view($user)&lt;br /&gt;
| Can the specified user view the event?&lt;br /&gt;
|-&lt;br /&gt;
| get_url()&lt;br /&gt;
| Returns Moodle URL where the event can be observed afterwards.&lt;br /&gt;
|-&lt;br /&gt;
| get_legacy_eventname()&lt;br /&gt;
| Information necessary for event BC.&lt;br /&gt;
|-&lt;br /&gt;
| get_legacy_eventdata()&lt;br /&gt;
| Information necessary for event BC.&lt;br /&gt;
|-&lt;br /&gt;
| get_legacy_logdata()&lt;br /&gt;
| Information necessary for logging BC.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Record caching===&lt;br /&gt;
&lt;br /&gt;
The standard event data may not contain all the information observers need. The built-in record snapshot support in events allows developers to attach more auxiliary information when triggering events, it may be for example course record, some record that was just deleted, etc. The snapshot is meant to be a full database record, as it will be automatically fetched from get_record_snapshot() if not set previously and assuming the property &#039;&#039;objecttable&#039;&#039; is set. Please be aware that the snapshots are not stored in the event, and cannot be restored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    $event = \core\event\role_assigned::create(&lt;br /&gt;
        array(&#039;context&#039;=&amp;gt;$context, &#039;objectid&#039;=&amp;gt;$ra-&amp;gt;roleid, &#039;relateduserid&#039;=&amp;gt;$ra-&amp;gt;userid,&lt;br /&gt;
            &#039;other&#039;=&amp;gt;array(&#039;id&#039;=&amp;gt;$ra-&amp;gt;id, &#039;component&#039;=&amp;gt;$ra-&amp;gt;component, &#039;itemid&#039;=&amp;gt;$ra-&amp;gt;itemid)));&lt;br /&gt;
    $event-&amp;gt;add_record_snapshot(&#039;role_assignments&#039;, $ra);&lt;br /&gt;
    $event-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    $event = \core\event\role_unassigned::create(&lt;br /&gt;
        array(&#039;context&#039;=&amp;gt;$context, &#039;objectid&#039;=&amp;gt;$ra-&amp;gt;roleid, &#039;relateduserid&#039;=&amp;gt;$ra-&amp;gt;userid,&lt;br /&gt;
            &#039;other&#039;=&amp;gt;array(&#039;id&#039;=&amp;gt;$ra-&amp;gt;id, &#039;component&#039;=&amp;gt;$ra-&amp;gt;component, &#039;itemid&#039;=&amp;gt;$ra-&amp;gt;itemid)));&lt;br /&gt;
    $event-&amp;gt;add_record_snapshot(&#039;role_assignments&#039;, $ra);&lt;br /&gt;
    $event-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The related methods are:&lt;br /&gt;
* public function add_record_snapshot($tablename, $record)&lt;br /&gt;
* public function get_record_snapshot($tablename, $id)&lt;br /&gt;
&lt;br /&gt;
=== Rejected properties and methods ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Property&lt;br /&gt;
! Title&lt;br /&gt;
! Why&lt;br /&gt;
|-&lt;br /&gt;
| URL&lt;br /&gt;
| relevant page URL&lt;br /&gt;
| These URLs can be constructed on the fly from other data, external log plugins may use get_url() method.&lt;br /&gt;
|-&lt;br /&gt;
| version&lt;br /&gt;
| Event specification number&lt;br /&gt;
| The event specification should never change&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| Type of event (action, error, ...)&lt;br /&gt;
| Event are not intended for error logging or debugging.&lt;br /&gt;
|-&lt;br /&gt;
| actor&lt;br /&gt;
| Whether current execution is cron, cli, user, ...&lt;br /&gt;
| Impossible to track down at a low level&lt;br /&gt;
|-&lt;br /&gt;
| severity&lt;br /&gt;
| Severity following [http://tools.ietf.org/html/rfc5424#section-6.2.1 logging standards]&lt;br /&gt;
| Our logging does not match this, as we will not (at present) log errors&lt;br /&gt;
|-&lt;br /&gt;
| coursecatname&lt;br /&gt;
| Category name&lt;br /&gt;
| Might be costly to retrieve for little gain&lt;br /&gt;
|-&lt;br /&gt;
| coursename&lt;br /&gt;
| Course name&lt;br /&gt;
| Might be costly to retrieve for little gain&lt;br /&gt;
|-&lt;br /&gt;
| cmname&lt;br /&gt;
| Course module name&lt;br /&gt;
| Might be costly to retrieve for little gain&lt;br /&gt;
|-&lt;br /&gt;
| categoryid &lt;br /&gt;
| Course category id&lt;br /&gt;
| Categories are a tree structure, we can not identify them by one integer. It would have to be a path.&lt;br /&gt;
|-&lt;br /&gt;
| cmid &lt;br /&gt;
| Course module id&lt;br /&gt;
| Can be derived from contextlevel and contextinstanceid&lt;br /&gt;
|-&lt;br /&gt;
| associatedobject&lt;br /&gt;
| Associated object&lt;br /&gt;
| Object associated to the main object. Ie: The user to whom a message is sent.&lt;br /&gt;
|-&lt;br /&gt;
| associatedobjectid&lt;br /&gt;
| Associated object ID&lt;br /&gt;
| Identifier of the associated object&lt;br /&gt;
|-&lt;br /&gt;
| realuserid&lt;br /&gt;
| Real User ID&lt;br /&gt;
| Will be tracked by log plugins only - user who &amp;quot;logged in as&amp;quot;, stores the real user ID&lt;br /&gt;
|-&lt;br /&gt;
| origin&lt;br /&gt;
| Origin of the event&lt;br /&gt;
| Will be tracked by log plugins only - CLI, cron, Webservice, ... (optionally with IP address)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Comment&lt;br /&gt;
! Why&lt;br /&gt;
|-&lt;br /&gt;
| get_all_affected_users()&lt;br /&gt;
| Returns all the users affected by this event&lt;br /&gt;
| It is expensive to fetch all users and it changes in time, so it would be unreliable too. For now we store only one user who is related to each event.&lt;br /&gt;
|-&lt;br /&gt;
| get_objecturl()&lt;br /&gt;
| Returns the URL to view the object&lt;br /&gt;
| There is usually only one URL where event changes may be observed. The URL may depend on current user capabilities too.&lt;br /&gt;
|-&lt;br /&gt;
| get_associatedobjecturl()&lt;br /&gt;
| Returns the URL to view the associated object&lt;br /&gt;
| No associated user property is present.&lt;br /&gt;
|-&lt;br /&gt;
| get_currenturl()&lt;br /&gt;
| Returns the current URL, uses $PAGE.&lt;br /&gt;
| This information may be added by logger, current page info is not part of events data.&lt;br /&gt;
|-&lt;br /&gt;
| get_useripaddress()&lt;br /&gt;
| Returns the User IP address&lt;br /&gt;
| Page access method is not part of events API, this should be implemented as logdata properties in loggers.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Events naming convention ==&lt;br /&gt;
&lt;br /&gt;
Clear event names help developers when reading what events are triggered, and defining the events properties when defining the event class.&lt;br /&gt;
&lt;br /&gt;
 Decision: \&amp;lt;component&amp;gt;\event\&amp;lt;some_object&amp;gt;_&amp;lt;verb&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Existing events ===&lt;br /&gt;
&lt;br /&gt;
List of existing events in Moodle code base, along with their 2.5 couterparts.&lt;br /&gt;
&lt;br /&gt;
This list is out of date. For a full list of events check out the [https://docs.moodle.org/en/Event_list_report Event list report] which is located in &amp;quot;Site administration &amp;gt; Reports &amp;gt; Event list&amp;quot; of your Moodle installation (2.7+).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fully qualified event name&lt;br /&gt;
! 2.5 name&lt;br /&gt;
! Component&lt;br /&gt;
! Object&lt;br /&gt;
! Action (Verb)&lt;br /&gt;
! Comment&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_comments\event\comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| assignsubmission_comments&lt;br /&gt;
| comment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_comments\event\comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| assignsubmission_comments&lt;br /&gt;
| comment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_file\event\assessable_uploaded&#039;&#039;&#039;&lt;br /&gt;
| assessable_file_uploaded&lt;br /&gt;
| assignsubmission_file&lt;br /&gt;
| assessable&lt;br /&gt;
| uploaded&lt;br /&gt;
| To be deprecated MDL-35197&lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_file\event\submission_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| assignsubmission_file&lt;br /&gt;
| submission&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_file\event\submission_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| assignsubmission_file&lt;br /&gt;
| submission&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_onlinetext\event\assessable_uploaded&#039;&#039;&#039;&lt;br /&gt;
| assessable_content_uploaded&lt;br /&gt;
| assignsubmission_onlinetext&lt;br /&gt;
| assessable&lt;br /&gt;
| uploaded&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_onlinetext\event\submission_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| assignsubmission_onlinetext&lt;br /&gt;
| submission&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;assignsubmission_onlinetext\event\submission_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| assignsubmission_onlinetext&lt;br /&gt;
| submission&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;block_comments\event\comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| block_comments&lt;br /&gt;
| comment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;block_comments\event\comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| block_comments&lt;br /&gt;
| comment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;booktool_exportimscp\event\book_exported&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| booktool_exportimscp&lt;br /&gt;
| book&lt;br /&gt;
| exported&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;booktool_print\event\book_printed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| booktool_print&lt;br /&gt;
| book&lt;br /&gt;
| printed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;booktool_print\event\chapter_printed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| booktool_print&lt;br /&gt;
| chapter&lt;br /&gt;
| printed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\assessable_submitted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| assessable&lt;br /&gt;
| submitted&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\assessable_uploaded&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| assessable&lt;br /&gt;
| uploaded&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\base&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| base&lt;br /&gt;
| -&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_association_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| blog_association&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| blog_comment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| blog_comment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_entries_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| blog_entries&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_entry_created&#039;&#039;&#039;&lt;br /&gt;
| blog_entry_added&lt;br /&gt;
| core&lt;br /&gt;
| blog_entry&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_entry_deleted&#039;&#039;&#039;&lt;br /&gt;
| blog_entry_deleted&lt;br /&gt;
| core&lt;br /&gt;
| blog_entry&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\blog_entry_updated&#039;&#039;&#039;&lt;br /&gt;
| blog_entry_edited&lt;br /&gt;
| core&lt;br /&gt;
| blog_entry&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\cohort_created&#039;&#039;&#039;&lt;br /&gt;
| cohort_added&lt;br /&gt;
| core&lt;br /&gt;
| cohort&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\cohort_deleted&#039;&#039;&#039;&lt;br /&gt;
| cohort_deleted&lt;br /&gt;
| core&lt;br /&gt;
| cohort&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\cohort_member_added&#039;&#039;&#039;&lt;br /&gt;
| cohort_member_added&lt;br /&gt;
| core&lt;br /&gt;
| cohort_member&lt;br /&gt;
| added&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\cohort_member_removed&#039;&#039;&#039;&lt;br /&gt;
| cohort_member_removed&lt;br /&gt;
| core&lt;br /&gt;
| cohort_member&lt;br /&gt;
| removed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\cohort_updated&#039;&#039;&#039;&lt;br /&gt;
| cohort_updated&lt;br /&gt;
| core&lt;br /&gt;
| cohort&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| comment&lt;br /&gt;
| created&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| comment&lt;br /&gt;
| deleted&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\comments_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| comments&lt;br /&gt;
| viewed&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\content_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| content&lt;br /&gt;
| viewed&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_category_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_category&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_category_deleted&#039;&#039;&#039;&lt;br /&gt;
| course_category_deleted&lt;br /&gt;
| core&lt;br /&gt;
| course_category&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_category_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_category&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_completed&#039;&#039;&#039;&lt;br /&gt;
| course_completed&lt;br /&gt;
| core&lt;br /&gt;
| course&lt;br /&gt;
| completed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_completion_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_completion&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_content_deleted&#039;&#039;&#039;&lt;br /&gt;
| course_content_removed&lt;br /&gt;
| core&lt;br /&gt;
| course_content&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_created&#039;&#039;&#039;&lt;br /&gt;
| course_created&lt;br /&gt;
| core&lt;br /&gt;
| course&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_deleted&#039;&#039;&#039;&lt;br /&gt;
| course_deleted&lt;br /&gt;
| core&lt;br /&gt;
| course&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_completion_updated&#039;&#039;&#039;&lt;br /&gt;
| activity_completion_changed&lt;br /&gt;
| core&lt;br /&gt;
| course_module_completion&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_created&#039;&#039;&#039;&lt;br /&gt;
| mod_created&lt;br /&gt;
| core&lt;br /&gt;
| course_module&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_deleted&#039;&#039;&#039;&lt;br /&gt;
| mod_deleted&lt;br /&gt;
| core&lt;br /&gt;
| course_module&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_instances_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_module_instances_list&lt;br /&gt;
| viewed&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_updated&#039;&#039;&#039;&lt;br /&gt;
| mod_updated&lt;br /&gt;
| core&lt;br /&gt;
| course_module&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_reset_ended&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_reset&lt;br /&gt;
| ended&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_reset_started&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_reset&lt;br /&gt;
| started&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_restored&#039;&#039;&#039;&lt;br /&gt;
| course_restored&lt;br /&gt;
| core&lt;br /&gt;
| course&lt;br /&gt;
| restored&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_section_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| course_section&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\course_updated&#039;&#039;&#039;&lt;br /&gt;
| course_updated&lt;br /&gt;
| core&lt;br /&gt;
| course&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\email_failed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| email&lt;br /&gt;
| failed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\group_created&#039;&#039;&#039;&lt;br /&gt;
| groups_group_created&lt;br /&gt;
| core&lt;br /&gt;
| group&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\group_deleted&#039;&#039;&#039;&lt;br /&gt;
| groups_group_deleted&lt;br /&gt;
| core&lt;br /&gt;
| group&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\group_member_added&#039;&#039;&#039;&lt;br /&gt;
| groups_member_added&lt;br /&gt;
| core&lt;br /&gt;
| group_member&lt;br /&gt;
| added&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\group_member_removed&#039;&#039;&#039;&lt;br /&gt;
| groups_member_removed&lt;br /&gt;
| core&lt;br /&gt;
| group_member&lt;br /&gt;
| removed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\group_updated&#039;&#039;&#039;&lt;br /&gt;
| groups_group_updated&lt;br /&gt;
| core&lt;br /&gt;
| group&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\grouping_created&#039;&#039;&#039;&lt;br /&gt;
| groups_grouping_created&lt;br /&gt;
| core&lt;br /&gt;
| grouping&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\grouping_deleted&#039;&#039;&#039;&lt;br /&gt;
| groups_grouping_deleted&lt;br /&gt;
| core&lt;br /&gt;
| grouping&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\grouping_updated&#039;&#039;&#039;&lt;br /&gt;
| groups_grouping_updated&lt;br /&gt;
| core&lt;br /&gt;
| grouping&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\manager&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| manager&lt;br /&gt;
| anager&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\mnet_access_control_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| mnet_access_control&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\mnet_access_control_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| mnet_access_control&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\note_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| note&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\note_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| note&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\note_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| note&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\notes_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| notes&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_allow_assign_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| role_allow_assign&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_allow_override_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| role_allow_override&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_allow_switch_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| role_allow_switch&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_assigned&#039;&#039;&#039;&lt;br /&gt;
| role_assigned&lt;br /&gt;
| core&lt;br /&gt;
| role&lt;br /&gt;
| assigned&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_capabilities_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| role_capabilities&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| role&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\role_unassigned&#039;&#039;&#039;&lt;br /&gt;
| role_unassigned&lt;br /&gt;
| core&lt;br /&gt;
| role&lt;br /&gt;
| unassigned&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_created&#039;&#039;&#039;&lt;br /&gt;
| user_created&lt;br /&gt;
| core&lt;br /&gt;
| user&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_deleted&#039;&#039;&#039;&lt;br /&gt;
| user_deleted&lt;br /&gt;
| core&lt;br /&gt;
| user&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_enrolment_created&#039;&#039;&#039;&lt;br /&gt;
| user_enrolled&lt;br /&gt;
| core&lt;br /&gt;
| user_enrolment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_enrolment_deleted&#039;&#039;&#039;&lt;br /&gt;
| user_unenrolled&lt;br /&gt;
| core&lt;br /&gt;
| user_enrolment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_enrolment_updated&#039;&#039;&#039;&lt;br /&gt;
| user_enrol_modified&lt;br /&gt;
| core&lt;br /&gt;
| user_enrolment&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| user_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_loggedin&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| user&lt;br /&gt;
| loggedin&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_loggedinas&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| user&lt;br /&gt;
| loggedinas&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_loggedout&#039;&#039;&#039;&lt;br /&gt;
| user_logout&lt;br /&gt;
| core&lt;br /&gt;
| user&lt;br /&gt;
| loggedout&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_login_failed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| user_login&lt;br /&gt;
| failed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_profile_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| user_profile&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\user_updated&#039;&#039;&#039;&lt;br /&gt;
| user_updated&lt;br /&gt;
| core&lt;br /&gt;
| user&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_function_called&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_function&lt;br /&gt;
| called&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_login_failed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_login&lt;br /&gt;
| failed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_service_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_service&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_service_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_service&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_service_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_service&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_service_user_added&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_service_user&lt;br /&gt;
| added&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_service_user_removed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_service_user&lt;br /&gt;
| removed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_token_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_token&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;core\event\webservice_token_sent&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| core&lt;br /&gt;
| webservice_token&lt;br /&gt;
| sent&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;logstore_legacy\event\legacy_logged&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| logstore_legacy&lt;br /&gt;
| legacy&lt;br /&gt;
| logged&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\all_submissions_downloaded&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| all_submissions&lt;br /&gt;
| downloaded&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\assessable_submitted&#039;&#039;&#039;&lt;br /&gt;
| assessable_submitted&lt;br /&gt;
| mod_assign&lt;br /&gt;
| assessable&lt;br /&gt;
| submitted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\extension_granted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| extension&lt;br /&gt;
| granted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\identities_revealed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| identities&lt;br /&gt;
| revealed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\marker_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| marker&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\statement_accepted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| statement&lt;br /&gt;
| accepted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission&lt;br /&gt;
| created&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_duplicated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission&lt;br /&gt;
| duplicated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_graded&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission&lt;br /&gt;
| graded&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_locked&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission&lt;br /&gt;
| locked&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_status_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission_status&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_unlocked&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission&lt;br /&gt;
| unlocked&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\submission_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| submission&lt;br /&gt;
| updated&lt;br /&gt;
| Abstract class &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_assign\event\workflow_state_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_assign&lt;br /&gt;
| workflow_state&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_book\event\chapter_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_book&lt;br /&gt;
| chapter&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_book\event\chapter_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_book&lt;br /&gt;
| chapter&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_book\event\chapter_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_book&lt;br /&gt;
| chapter&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_book\event\chapter_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_book&lt;br /&gt;
| chapter&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_book\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_book&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_book\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_book&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_chat\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_chat&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_chat\event\message_sent&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_chat&lt;br /&gt;
| message&lt;br /&gt;
| sent&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_chat\event\sessions_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_chat&lt;br /&gt;
| sessions&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_choice\event\answer_submitted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_choice&lt;br /&gt;
| answer&lt;br /&gt;
| submitted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_choice\event\answer_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_choice&lt;br /&gt;
| answer&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_choice\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_choice&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_choice\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_choice&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_choice\event\report_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_choice&lt;br /&gt;
| report&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| comment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| comment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\field_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| field&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\field_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| field&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\field_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| field&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\record_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| record&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\record_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| record&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\record_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| record&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\template_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| template&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_data\event\template_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_data&lt;br /&gt;
| template&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_feedback\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_feedback&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_feedback\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_feedback&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_feedback\event\response_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_feedback&lt;br /&gt;
| response&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_feedback\event\response_submitted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_feedback&lt;br /&gt;
| response&lt;br /&gt;
| submitted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_folder\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_folder&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_folder\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_folder&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_folder\event\folder_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_folder&lt;br /&gt;
| folder&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\assessable_uploaded&#039;&#039;&#039;&lt;br /&gt;
| assessable_content_uploaded&lt;br /&gt;
| mod_forum&lt;br /&gt;
| assessable&lt;br /&gt;
| uploaded&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\course_searched&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| course&lt;br /&gt;
| searched&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\discussion_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| discussion&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\discussion_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| discussion&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\discussion_moved&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| discussion&lt;br /&gt;
| moved&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\discussion_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| discussion&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\discussion_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| discussion&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\forum_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| forum&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\post_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| post&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\post_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| post&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\post_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| post&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\readtracking_disabled&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| readtracking&lt;br /&gt;
| disabled&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\readtracking_enabled&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| readtracking&lt;br /&gt;
| enabled&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\subscribers_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| subscribers&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\subscription_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| subscription&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\subscription_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| subscription&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_forum\event\userreport_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_forum&lt;br /&gt;
| userreport&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_glossary\event\comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_glossary&lt;br /&gt;
| comment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_glossary\event\comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_glossary&lt;br /&gt;
| comment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\essay_assessed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| essay&lt;br /&gt;
| assessed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\essay_attempt_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| essay_attempt&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\highscore_added&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| highscore&lt;br /&gt;
| added&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\highscores_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| highscores&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\lesson_ended&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| lesson&lt;br /&gt;
| ended&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lesson\event\lesson_started&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lesson&lt;br /&gt;
| lesson&lt;br /&gt;
| started&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lti\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lti&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lti\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_lti&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_lti\event\unknown_service_api_called&#039;&#039;&#039;&lt;br /&gt;
| lti_unknown_service_api_call&lt;br /&gt;
| mod_lti&lt;br /&gt;
| unknown_service_api&lt;br /&gt;
| called&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_page\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_page&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_page\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_page&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_quiz\event\attempt_abandoned&#039;&#039;&#039;&lt;br /&gt;
| quiz_attempt_abandoned&lt;br /&gt;
| mod_quiz&lt;br /&gt;
| attempt&lt;br /&gt;
| abandoned&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_quiz\event\attempt_becameoverdue&#039;&#039;&#039;&lt;br /&gt;
| quiz_attempt_overdue&lt;br /&gt;
| mod_quiz&lt;br /&gt;
| attempt&lt;br /&gt;
| becameoverdue&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_quiz\event\attempt_started&#039;&#039;&#039;&lt;br /&gt;
| quiz_attempt_started&lt;br /&gt;
| mod_quiz&lt;br /&gt;
| attempt&lt;br /&gt;
| started&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_quiz\event\attempt_submitted&#039;&#039;&#039;&lt;br /&gt;
| quiz_attempt_submitted&lt;br /&gt;
| mod_quiz&lt;br /&gt;
| attempt&lt;br /&gt;
| submitted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_resource\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_resource&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_resource\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_resource&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\attempt_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| attempt&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\interactions_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| interactions&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\report_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| report&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\sco_launched&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| sco&lt;br /&gt;
| launched&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\tracks_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| tracks&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_scorm\event\user_report_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_scorm&lt;br /&gt;
| user_report&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_url\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_url&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_url\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_url&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\comment_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| comment&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\comment_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| comment&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\comments_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| comments&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\course_module_instance_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| course_module_instance_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_diff_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_diff&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_history_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_history&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_locks_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_locks&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_map_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_map&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_version_deleted&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_version&lt;br /&gt;
| deleted&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_version_restored&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_version&lt;br /&gt;
| restored&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_version_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page_version&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_wiki\event\page_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_wiki&lt;br /&gt;
| page&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\assessable_uploaded&#039;&#039;&#039;&lt;br /&gt;
| assessable_content_uploaded&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| assessable&lt;br /&gt;
| uploaded&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\assessment_evaluated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| assessment&lt;br /&gt;
| evaluated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\assessment_evaluations_reset&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| assessment_evaluations&lt;br /&gt;
| reset&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\assessment_reevaluated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| assessment&lt;br /&gt;
| reevaluated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\course_module_viewed&#039;&#039;&#039;&lt;br /&gt;
| workshop_viewed&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| course_module&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\instances_list_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| instances_list&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\phase_switched&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| phase&lt;br /&gt;
| switched&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\submission_assessed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| submission&lt;br /&gt;
| assessed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\submission_created&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| submission&lt;br /&gt;
| created&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\submission_reassessed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| submission&lt;br /&gt;
| reassessed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\submission_updated&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| submission&lt;br /&gt;
| updated&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;mod_workshop\event\submission_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| mod_workshop&lt;br /&gt;
| submission&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;report_log\event\content_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| report_log&lt;br /&gt;
| content&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;report_loglive\event\content_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| report_loglive&lt;br /&gt;
| content&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;report_outline\event\content_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| report_outline&lt;br /&gt;
| content&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;report_participation\event\content_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| report_participation&lt;br /&gt;
| content&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| &#039;&#039;&#039;report_stats\event\content_viewed&#039;&#039;&#039;&lt;br /&gt;
| -&lt;br /&gt;
| report_stats&lt;br /&gt;
| content&lt;br /&gt;
| viewed&lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Verb list ===&lt;br /&gt;
All events must use a verb from this list. New verbs should be added to this list if required.&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!verb&lt;br /&gt;
!Explanation&lt;br /&gt;
!Source&lt;br /&gt;
|-&lt;br /&gt;
|abandoned&lt;br /&gt;
|When a attempt is abandoned by user (Quiz attempt)&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|accepted&lt;br /&gt;
|Example: Accepting a statement when submitting an assignment.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|added&lt;br /&gt;
|	Used to represent &amp;quot;something that already exists is now part of/bound to another entity&amp;quot;. Examples: &amp;quot;Admin added role to user X&amp;quot;, &amp;quot;Admin added user X to group A&amp;quot;. Wrong example: &amp;quot;User added course in category&amp;quot; because it is a &#039;move&#039; action, except if a course can be part of multiple categories. The good examples work because: A user can have multiple roles, a user can be in multiple groups.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|answered&lt;br /&gt;
| Indicates the actor responded to a Question&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|assessed&lt;br /&gt;
| Some submitted material has been assessed&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|assigned&lt;br /&gt;
| Assign some privilege or role to user.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|attempted&lt;br /&gt;
| Trying to do an activity. Example: attempting a Math class.&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|awarded&lt;br /&gt;
| ex:-teacher awarded student a badge.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|backedup&lt;br /&gt;
| When a backup has been performed.&lt;br /&gt;
|Moodle	&lt;br /&gt;
|-&lt;br /&gt;
|becomeoverdue&lt;br /&gt;
| When an activity is overdue Example: Quiz attempt is overdue&lt;br /&gt;
|Moodle	&lt;br /&gt;
|-&lt;br /&gt;
|called&lt;br /&gt;
| When a call to something is made like an API @see unknown_service_api_called.php&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|commented&lt;br /&gt;
|Offered an opinion or written experience of the activity. Can be used with the learner as the actor or a system as an actor. Comments can be sent from either party with the idea that the other will read and react to the content.&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|completed&lt;br /&gt;
|To experience the activity in its entirety. Used to affirm the completion of content. This can be simply experiencing all the content, be tied to objectives or interactions, or determined in any other way. Any content that has been initialized, but not yet completed, should be considered incomplete. There is no verb to &#039;incomplete&#039; an activity, one would void the statement which completes the activity.&amp;quot;&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|created&lt;br /&gt;
|Used to represent &amp;quot;something new has been created&amp;quot;.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|deleted&lt;br /&gt;
|Used to indicate the object in context was deleted.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|disabled&lt;br /&gt;
|When an activity is disabled. Example: forum read tracking disabled.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|downloaded&lt;br /&gt;
|When a user download file from user. Example submission/report downloaded.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|duplicated&lt;br /&gt;
|For something that has been copied.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|enabled&lt;br /&gt;
|When some setting is enabled. Example: forum read tracking enabled.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|ended&lt;br /&gt;
|When a process ends. Example: Lesson ended or course reset ended.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|evaluated&lt;br /&gt;
|Material has been evaluated.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|exported&lt;br /&gt;
|When a report is exported in certain format.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|failed&lt;br /&gt;
|Learner did not perform the activity to a level of pre-determined satisfaction. Used to affirm the lack of success a learner experienced within the learning content in relation to a threshold. If the user performed below the minimum to the level of this threshold, the content is &#039;failed&#039;. The opposite of &#039;passed&#039;. This is also used in case when message sending is failed.&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|graded&lt;br /&gt;
|Used to represent an activity was graded.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|granted&lt;br /&gt;
|User is granted some extension or capability. Example: extension granted for submission.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|imported&lt;br /&gt;
|The act of moving an object into another location or system.&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|launched&lt;br /&gt;
|When an external object is launched. Try consider started if there is related stopped event.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|locked&lt;br /&gt;
|When an activity is locked. Should have a related unlocked event.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|loggedin/loggedout&lt;br /&gt;
|	For login and logout.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|loggedinas&lt;br /&gt;
|	 If user is logged in as different user. This is used by only one event (user_loggedinas). Adding this verb makes event name more clear, then using loggedin verb.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|locked&lt;br /&gt;
|&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|moved&lt;br /&gt;
|	Used to indicate the object in context was moved.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|passed&lt;br /&gt;
|Used to affirm the success a learner experienced within the learning content in relation to a threshold. If the user performed at a minimum to the level of this threshold, the content is &#039;passed&#039;. The opposite of &#039;failed&#039;.&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|printed&lt;br /&gt;
|Something is printed.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|reassessed&lt;br /&gt;
|Submitted material has been assessed again.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|reevaluated&lt;br /&gt;
|Material has been evaluated again.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|removed&lt;br /&gt;
|By opposition to &amp;quot;Added&amp;quot;. This does not mean that the object has been deleted, but removed from the entity, or not bound to it any more.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|reset&lt;br /&gt;
|Sets one or more properties back to the default value.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|restored&lt;br /&gt;
|When restoring a backup. Rolling back to a previous state.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|revealed&lt;br /&gt;
|Some identity is revealed. Example: Identities revealed after blind marking.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|searched&lt;br /&gt;
|Something is searched. Example: searched in course.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|sent&lt;br /&gt;
|Message sent.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|started&lt;br /&gt;
|Some activity started&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|submitted&lt;br /&gt;
|This is very close to &amp;quot;Attempted&amp;quot;. Depends on context which one should be used. For example:- &amp;quot;Admin submitted a form. Student attempted a quiz.&amp;quot;  is correct, however some cases might not be as clear as the previous example. We can say both &amp;quot;Student submitted an assignment&amp;quot; or &amp;quot;student attempted an assignment&amp;quot;. We need to make the difference clear.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|suspended&lt;br /&gt;
| Suspend something. (example a user)&lt;br /&gt;
| Tincan (However the context is different)&lt;br /&gt;
|-&lt;br /&gt;
|switched&lt;br /&gt;
|Something has been switched. For example:- The workshop phase has been switched to assessment&amp;quot;&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|unassigned&lt;br /&gt;
|As opposed to assigned. When some role is unassigned.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|unlocked&lt;br /&gt;
|&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|upgraded&lt;br /&gt;
|Something was upgraded, some module probably&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|updated&lt;br /&gt;
|Used to indicate the object in context was updated. Simple example is &amp;quot;Admin updated course xyz&amp;quot;.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|uploaded&lt;br /&gt;
|When an assignment is uploaded.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|viewed&lt;br /&gt;
|Something has been viewed. For example:- &amp;quot;Student viewed chapter 1 of book 1.&amp;quot;&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Rules ===&lt;br /&gt;
&lt;br /&gt;
==== Use singular ====&lt;br /&gt;
&lt;br /&gt;
Plurals must be used on objects when it&#039;s a &#039;&#039;One to Many&#039;&#039; relationship. Ex: bulk import, mass deletion, ... In any other case, use the singular.&lt;br /&gt;
&lt;br /&gt;
==== Ends with a verb ====&lt;br /&gt;
&lt;br /&gt;
The last word (after the last underscore) must be a verb.&lt;br /&gt;
&lt;br /&gt;
=== Deprecated events ===&lt;br /&gt;
Following are the events that were supported in 2.5, but deprecated in 2.6 or later&lt;br /&gt;
&lt;br /&gt;
groups_groupings_deleted (see MDL-41312)&lt;br /&gt;
&lt;br /&gt;
groups_groupings_groups_removed (see MDL-41312)&lt;br /&gt;
&lt;br /&gt;
groups_groups_deleted (see MDL-41312)&lt;br /&gt;
&lt;br /&gt;
groups_members_removed (see MDL-41312)&lt;br /&gt;
&lt;br /&gt;
== Shared events ==&lt;br /&gt;
&lt;br /&gt;
 Decision: Not supported at this stage.&lt;br /&gt;
&lt;br /&gt;
In Moodle 2.5 we have a good example of a shared event: &#039;assessable_content_uploaded&#039; which is triggered in &#039;&#039;forum&#039;&#039;, &#039;assignment&#039;&#039; and &#039;&#039;workshop&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The problem with shared events is that we cannot easily track what component triggered them. Of course we could add a new property to the event to keep track of that, but we would soon need more information and more properties. Also, in the case of a logger, the event received would be unique, where in fact it should be considered different depending on the component firing it.&lt;br /&gt;
&lt;br /&gt;
In our first implementation, we will create one specific event per module. This flexibility does not prevent any observer from capturing them, but still makes sure that the consistency and specificity of each event is maintained.&lt;br /&gt;
&lt;br /&gt;
It could happen that some events are defined in core and shared, but this should not really happen as low-level APIs should trigger the event, and a module should call that low API instead of doing the job itself.&lt;br /&gt;
&lt;br /&gt;
== One to many ==&lt;br /&gt;
&lt;br /&gt;
 Decision: Each event should have a one to one relationship. We can reconsider this at a later stage, if the performance hit is extremely high.&lt;br /&gt;
&lt;br /&gt;
In 2.5, some events are triggered when an action happens on multiple objects. We have to decide whether we want to keep supporting &#039;&#039;One to Many&#039;&#039; events or not.&lt;br /&gt;
&lt;br /&gt;
Keeping a list of all changes for multiple actions may be problematic because you would have to keep them all in memory until all things are processed. This might also result in the order of events being incorrect. The only correct solution seems to be to trigger each item individually and then many things at the end. Performance needs to be improved elsewhere...&lt;br /&gt;
&lt;br /&gt;
=== Accuracy ===&lt;br /&gt;
&lt;br /&gt;
When uploading a bunch of users using the CSV upload feature, if only one event is triggered, it means that the observers of &#039;&#039;user_created&#039;&#039; won&#039;t be triggered. And so some functionality can be lost as, as a plugin developer, I expect this &#039;&#039;user_created&#039;&#039; to be triggered regardless of the way they have been uploaded. Of course, the developer could observe the event &#039;&#039;bulk_user_imported&#039;&#039;, but that means that he could miss some relevant observers.&lt;br /&gt;
&lt;br /&gt;
This applies to existing events.&lt;br /&gt;
&lt;br /&gt;
=== Performance ===&lt;br /&gt;
&lt;br /&gt;
Triggering one event is cheaper then repeating the same events x number of times...&lt;br /&gt;
&lt;br /&gt;
=== Information tracking ===&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;bulk&#039;&#039; event, might not be verbose enough to allow for proper logging afterwards. Though this is the responsibility of the logger, we probably want to make it easy to store relevant information.&lt;br /&gt;
&lt;br /&gt;
=== Double event ===&lt;br /&gt;
&lt;br /&gt;
In the case of a bulk user import, if we were to trigger an event per user created, we probably want to trigger one event &#039;user_bulk_upload_started&#039; when the action starts.&lt;br /&gt;
&lt;br /&gt;
== Unit Testing ==&lt;br /&gt;
&lt;br /&gt;
With unit testing for this system we want to assert the following:&lt;br /&gt;
&lt;br /&gt;
* That event strict validation and custom validation works.&lt;br /&gt;
* Missing event data is auto filled with accurate data.&lt;br /&gt;
* Typos in properties passed to ::create() are captured (if we decide to validate).&lt;br /&gt;
* The legacy methods return the expected values (use assertEventLegacyData() and assertEventLegacyData())&lt;br /&gt;
* The class properties are correctly overridden (crud, level, action, object, ...).&lt;br /&gt;
* The properties automatically generated (component, name, ...) are correct.&lt;br /&gt;
* Events are dispatched to the corresponding observers.&lt;br /&gt;
* Events are dispatched to the corresponding legacy handlers.&lt;br /&gt;
* Events are dispatched to the * observers.&lt;br /&gt;
* Events perform an add_to_log() if it has legacy log data.&lt;br /&gt;
* &#039;Events restore&#039; restored the whole event data, and does not miss any information.&lt;br /&gt;
* &#039;Events restore&#039; does not generate any extra information.&lt;br /&gt;
* Event methods should check context object or avoid using it, as context might not be valid at time of event restore (use assertEventContextNotUsed())&lt;br /&gt;
&lt;br /&gt;
= PHP dpcs ==&lt;br /&gt;
* All events php docs must include @since parameter, indicating when the event was first included in standard Moodle distribution.&lt;br /&gt;
* All events must declare the $other properties using mark down in the php docs.&lt;br /&gt;
&lt;br /&gt;
= Example events =&lt;br /&gt;
&lt;br /&gt;
== Assignment ==&lt;br /&gt;
&lt;br /&gt;
Assumption: Course contains groups with students in each group.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.&#039;&#039;&#039; Teacher creates an assignment with group mode set to &#039;Separate groups&#039; and Feedback type set to comments and files.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has created assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;2.&#039;&#039;&#039; A student views the assignment.&lt;br /&gt;
*Event: User &#039;Student&#039; has viewed assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;3.&#039;&#039;&#039; A member from one of the groups submits an assignment&lt;br /&gt;
*Event: User &#039;Student&#039; has added a submission for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to the teacher and all students in that group.&lt;br /&gt;
&#039;&#039;&#039;4.&#039;&#039;&#039; User &#039;Adrian&#039; adds some changes to the assignment and updates it.&lt;br /&gt;
*Event: User &#039;Adrian&#039; has updated the submission for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to the teacher and all students in that group.&lt;br /&gt;
&#039;&#039;&#039;5.&#039;&#039;&#039; Teacher views the assignment.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has viewed assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;6.&#039;&#039;&#039; Teacher clicks on &#039;View/grade all submissions&#039;&lt;br /&gt;
*Event: User &#039;Teacher&#039; has viewed the assignment &#039;B&#039; grade area in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;7.&#039;&#039;&#039; Teacher clicks to grade the student&#039;s submission.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has viewed the submission for user &#039;student&#039; for assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;8.&#039;&#039;&#039; Teacher marks the assignment with the setting &#039;Apply grades and feedback to entire group&#039; set to &#039;Yes&#039; leaving a comment and a file.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has marked assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has left a comment for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has uploaded a feedback file for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has uploaded a file to the course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to user &#039;Student&#039; notifying them their submission for assignment &#039;B&#039; has been marked. - This is done for all users in the group.&lt;br /&gt;
&#039;&#039;&#039;9.&#039;&#039;&#039; User &#039;Adrian&#039; views the feedback.&lt;br /&gt;
*Event: User &#039;Adrian&#039; has viewed assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;10.&#039;&#039;&#039; User &#039;Adrian&#039; opens the feedback file.&lt;br /&gt;
*Event: User &#039;Adrian&#039; has viewed the file &#039;A&#039; for assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;11.&#039;&#039;&#039; User &#039;Adrian&#039; adds some changes to the assignment insulting the teachers marking and updates it.&lt;br /&gt;
*Event: User &#039;Adrian&#039; has updated the submission for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to user &#039;Teacher&#039; notifying them that user &#039;Adrian&#039; has updated the submission for assignment &#039;B&#039;.&lt;br /&gt;
*Event: Email sent to user &#039;Student&#039; notifying them their submission for assignment &#039;B&#039; has been updated. - This is done for all users in the group.&lt;br /&gt;
&#039;&#039;&#039;12.&#039;&#039;&#039; The teacher clicks directly on the link in the email to be taken to the grading page.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has viewed the submission for user &#039;student&#039; for assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;13.&#039;&#039;&#039; The teacher is upset due to the harsh comments and decides to mark Adrian down, but not the rest of the group by setting &#039;Apply grades and feedback to entire group&#039; set to &#039;No&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has marked assignment &#039;B&#039; for user &#039;Adrian&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has left a comment for assignment &#039;B&#039; for user &#039;Adrian&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has uploaded a feedback file for assignment &#039;B&#039; for user &#039;Adrian&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to user &#039;Adrian&#039; notifying them their submission for assignment &#039;B&#039; has been marked.&lt;br /&gt;
&lt;br /&gt;
= FAQs =&lt;br /&gt;
&lt;br /&gt;
; Why not use create events in core subsystems? : Because we could not see all core events in one place, it would create problems when naming event classes and finally subsystems are incomplete, we would have to add more now because we could not move the events in the future.&lt;br /&gt;
&lt;br /&gt;
= Development stages =&lt;br /&gt;
&lt;br /&gt;
== Stage 1 ==&lt;br /&gt;
&lt;br /&gt;
* Finish class loader spec and implement basic Frankenstyle class loader.&lt;br /&gt;
* Describe new observer definition - just few new flags in current db/events.php&lt;br /&gt;
* Describe new event dispatcher.&lt;br /&gt;
* Describe core_event_base class.&lt;br /&gt;
* Current (= legacy) events triggering:&lt;br /&gt;
** Re-factor current event handling code to new self-contained class - do not change functionality, keep events_trigger().&lt;br /&gt;
** Create new event handler management class that deals with installation and upgrades of both legacy and new handlers.&lt;br /&gt;
* New events:&lt;br /&gt;
** Create new core_event_base class.&lt;br /&gt;
** Create new self-contained event dispatcher class with &#039;*&#039; handler support.&lt;br /&gt;
** In function core_event_base::trigger() check if the  event has property &#039;legacyeventname&#039; execute events_trigger($this-&amp;gt;legacyeventname, $this-&amp;gt;legacyeventdata) after triggering new event.&lt;br /&gt;
** Write unit tests for all new events code.&lt;br /&gt;
* No changes to be made to the current logging system yet.&lt;br /&gt;
&lt;br /&gt;
After completing this stage everything should continue to work as it did before and we can start parallel work on further stages.&lt;br /&gt;
&lt;br /&gt;
== Stage 2 (requires completion of Stage 1) ==&lt;br /&gt;
&lt;br /&gt;
* Create event classes and replace existing calls to events_trigger() and with new event classes containing legacy information properties.&lt;br /&gt;
* Add more events throughout the standard Moodle package in places where we have add_to_log(). Implement some_event::get_legacy_log_data() which returns original parameters of add_to_log() and remove it. Old add_to_log() function is called in core_event_base::trigger() automatically with original parameters.&lt;br /&gt;
* Add even more new events all over the place.&lt;br /&gt;
&lt;br /&gt;
The difficult part is defining the new event classes properly because we must not change them after the 2.6 release.&lt;br /&gt;
&lt;br /&gt;
== Stage 3 (requires partial completion of Stage 2) ==&lt;br /&gt;
&lt;br /&gt;
* Migrate current legacy event handlers to new handlers with one event class instance parameter, ex.: enrol plugins.&lt;br /&gt;
&lt;br /&gt;
== Stage 4 (requires partial completion of Stage 2) ==&lt;br /&gt;
&lt;br /&gt;
* Implement an event logging handler.&lt;br /&gt;
* Implement logging storage plugins.&lt;br /&gt;
* Define logging apis.&lt;br /&gt;
* Create new reports.&lt;br /&gt;
* Switch to new logging everywhere after Stage 2 has been completed and new reports are usable.&lt;br /&gt;
&lt;br /&gt;
See [[Logging 2]]&lt;br /&gt;
&lt;br /&gt;
== Stage 5  ==&lt;br /&gt;
&lt;br /&gt;
* Decide how much backwards compatibility we want for old log tables. Most probably they will get only legacy log data.&lt;br /&gt;
* Implement some BC solution for old code that reads log tables directly.&lt;br /&gt;
&lt;br /&gt;
See [[Logging 2]]&lt;br /&gt;
&lt;br /&gt;
== Stage 6 (requires completion of Stage 4 and 5) ==&lt;br /&gt;
&lt;br /&gt;
Moodle 2.8dev? This is the ultimate end of old logging via the &#039;&#039;log&#039;&#039; table.&lt;br /&gt;
&lt;br /&gt;
* Deprecate the add_to_log() function with a debug message and do nothing inside.&lt;br /&gt;
* Remove all legacy logging from event classes.&lt;br /&gt;
&lt;br /&gt;
See [[Logging 2]]&lt;br /&gt;
&lt;br /&gt;
= See Also =&lt;br /&gt;
[[Logging 2]]  &lt;br /&gt;
&lt;br /&gt;
[[Tin Can]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Reports&amp;diff=44520</id>
		<title>Reports</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Reports&amp;diff=44520"/>
		<updated>2014-04-24T08:06:58Z</updated>

		<summary type="html">&lt;p&gt;Ankitfrenz: /* report_myreport_supports_logstore */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.2}}&lt;br /&gt;
&lt;br /&gt;
In Moodle 2.2 the [[Course reports]] and [[Admin reports]] were combined into one Reports directory (/report) that serves both needs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
A report is a folder of code under /report. For example, you might make a folder in there called &#039;&#039;&#039;myreport&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
In there, the only code you are required to have is an index.php file. This will normally display a simple HTML form for controlling the report, and, the code for displaying the report. You will probably also want a language file, which would be called lang/en/report_myreport.php following the example above. &lt;br /&gt;
&lt;br /&gt;
In addition, you can add any other PHP code you like, and then link people to it from index.php.&lt;br /&gt;
&lt;br /&gt;
So, the minimal code layout is:&lt;br /&gt;
&lt;br /&gt;
 report/&lt;br /&gt;
  backups/&lt;br /&gt;
  completion/&lt;br /&gt;
  ...&lt;br /&gt;
  myreport/&lt;br /&gt;
   lang/&lt;br /&gt;
    en/&lt;br /&gt;
     report_myreport.php&lt;br /&gt;
   index.php&lt;br /&gt;
   version.php&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
==What to do in index.php==&lt;br /&gt;
&lt;br /&gt;
The simplest way to work this out is by example. You should look at some of the reports that ship with Moodle. [https://github.com/moodle/moodle/blob/master/report/configlog/index.php report/log] is a good one to start with. Let us go through that example to see what is there (I will put into italics the bits that are more advanced):&lt;br /&gt;
&lt;br /&gt;
# Require some libraries.&lt;br /&gt;
# Check the user is logged in and has appropriate permissions - all external admin pages use admin_externalpage_setup() which by default requires &#039;moodle/site:config&#039; capability&lt;br /&gt;
# Get the parameters from the URL that control the report, and clean them up a bit.&lt;br /&gt;
# Print the page header. Since this is an administration page, we need to do this using the admin_externalpage... functions. &lt;br /&gt;
# Display a table with data and paging controls&lt;br /&gt;
# Print the footer&lt;br /&gt;
&lt;br /&gt;
==How your report gets included in the navigation ==&lt;br /&gt;
&lt;br /&gt;
Reports can present itself in different contexts:&lt;br /&gt;
* system level - controlled by settings.php&lt;br /&gt;
* at user level - controlled by *_extend_navigation_user() callbacks&lt;br /&gt;
* at course level - controlled by *_extend_navigation_course() callbacks&lt;br /&gt;
* at module level - controlled by *_extend_navigation_module() callbacks&lt;br /&gt;
&lt;br /&gt;
In our example the configlog report is usable only at the system level, the admin tree integration is done through settings.php file&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$ADMIN-&amp;gt;add(&#039;reports&#039;, new admin_externalpage(&#039;reportconfiglog&#039;, get_string(&#039;configlog&#039;, &#039;report_configlog&#039;), &amp;quot;$CFG-&amp;gt;wwwroot/report/configlog/index.php&amp;quot;));&lt;br /&gt;
$settings = null;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;$settings = null&amp;lt;/code&amp;gt; tells moodle that plugin does not have any settings and only want to display link to external admin page.&lt;br /&gt;
&lt;br /&gt;
If you want to include your report in course navigation for example you need to create lib.php file and add following function:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function report_myreport_extend_navigation_course($navigation, $course, $context) {&lt;br /&gt;
    if (has_capability(&#039;report/myreport:view&#039;, $context)) {&lt;br /&gt;
        $url = new moodle_url(&#039;/report/myreport/index.php&#039;, array(&#039;id&#039;=&amp;gt;$course-&amp;gt;id));&lt;br /&gt;
        $navigation-&amp;gt;add(get_string(&#039;pluginname&#039;, &#039;report_myreport&#039;), $url, navigation_node::TYPE_SETTING, null, null, new pix_icon(&#039;i/report&#039;, &#039;&#039;));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You will also need access.php file with definition of  &#039;report/myreport:view&#039; capability.&lt;br /&gt;
&lt;br /&gt;
== Callbacks ==&lt;br /&gt;
This section includes the callbacks that a report should define. callbacks are normally defined in lib.php of the report.&lt;br /&gt;
&lt;br /&gt;
=== report_myreport_supports_logstore ===&lt;br /&gt;
{{Moodle 2.7}}&lt;br /&gt;
&lt;br /&gt;
You need to define this callback only if your report uses logstores to fetch information. This function takes a store instance as an argument and returns boolean true/false depending on if your report supports this store or not. This callback is used in various managment interfaces to let admins know the dependencies of your report on logstores.&lt;br /&gt;
&lt;br /&gt;
See [[Migrating log access in reports]] for further details on how to use logstores in reports.&lt;br /&gt;
Example:-&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Callback to verify if the given instance of store is supported by this report or not.&lt;br /&gt;
 *&lt;br /&gt;
 * @param string $instance store instance.&lt;br /&gt;
 *&lt;br /&gt;
 * @return bool returns true if the store is supported by the report, false otherwise.&lt;br /&gt;
 */&lt;br /&gt;
function report_myreport_supports_logstore($instance) {&lt;br /&gt;
    if ($instance instanceof \core\log\sql_select_reader) {&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
    return false;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Strings you must define in you lang/en/report_&#039;&#039;myreport&#039;&#039;.php==&lt;br /&gt;
&lt;br /&gt;
You just need to define&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 $string[&#039;pluginname&#039;] = &#039;What my report is called&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
to make the report show up properly in the admin tree, but if your report does anything interesting, you will almost certainly need more.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [http://moodle.org/mod/data/view.php?d=13&amp;amp;rid=913 System images report] this is another very simple report, in contrib. Might be a good one to look at.&lt;br /&gt;
* [[General report plugins]] - new reports in 2.2+&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Ankitfrenz</name></author>
	</entry>
</feed>