From 8d5bc315c66d76f5628a12e9af5ae51e776d7863 Mon Sep 17 00:00:00 2001
From: Thomas Fradet <t.fradet8@gmail.com>
Date: Thu, 14 Feb 2019 14:10:13 +0100
Subject: [PATCH] folder

---
 activity_modules/block_activity_modules.php   | 106 +++
 activity_modules/classes/privacy/provider.php |  46 ++
 activity_modules/db/access.php                |  41 +
 .../lang/en/block_activity_modules.php        |  27 +
 .../behat/block_activity_modules.feature      | 159 ++++
 activity_modules/version.php                  |  29 +
 ...tore_activity_results_block_task.class.php | 115 +++
 activity_results/block_activity_results.php   | 707 ++++++++++++++++
 activity_results/classes/privacy/provider.php |  46 ++
 activity_results/db/access.php                |  41 +
 activity_results/edit_form.php                | 127 +++
 .../lang/en/block_activity_results.php        |  68 ++
 activity_results/settings.php                 |  86 ++
 activity_results/styles.css                   |  28 +
 .../tests/behat/addblockinactivity.feature    | 102 +++
 .../tests/behat/addunconfiguredblock.feature  |  42 +
 .../behat/addunsupportedactivity.feature      |  39 +
 .../tests/behat/defaultsettings.feature       |  64 ++
 .../behat/highscoreswithoutgroups.feature     | 169 ++++
 .../tests/behat/highscoreswithscales.feature  | 109 +++
 .../highscoreswithscalesandgroups.feature     | 151 ++++
 .../highscoreswithseperategroups.feature      | 227 +++++
 .../behat/highscoreswithvisiblegroups.feature | 204 +++++
 .../behat/lowscoreswithoutgroups.feature      | 158 ++++
 .../tests/behat/lowscoreswithscales.feature   | 110 +++
 .../lowscoreswithscalesandgroups.feature      | 147 ++++
 .../behat/lowscoreswithseperategroups.feature | 219 +++++
 .../behat/lowscoreswithvisiblegroups.feature  | 200 +++++
 activity_results/version.php                  |  29 +
 admin_bookmarks/block_admin_bookmarks.php     | 138 ++++
 admin_bookmarks/classes/privacy/provider.php  |  46 ++
 admin_bookmarks/create.php                    |  71 ++
 admin_bookmarks/db/access.php                 |  51 ++
 admin_bookmarks/delete.php                    |  73 ++
 .../lang/en/block_admin_bookmarks.php         |  28 +
 .../tests/behat/bookmark_admin_pages.feature  |  36 +
 admin_bookmarks/version.php                   |  29 +
 badges/block_badges.php                       | 108 +++
 badges/classes/privacy/provider.php           |  46 ++
 badges/db/access.php                          |  45 +
 badges/db/upgrade.php                         |  58 ++
 badges/edit_form.php                          |  38 +
 badges/lang/en/block_badges.php               |  31 +
 badges/tests/behat/block_badges.feature       |  32 +
 .../tests/behat/block_badges_course.feature   |  71 ++
 .../behat/block_badges_dashboard.feature      |  38 +
 .../behat/block_badges_frontpage.feature      |  44 +
 badges/tests/fixtures/badge.png               | Bin 0 -> 2116 bytes
 badges/version.php                            |  30 +
 blog_menu/block_blog_menu.php                 | 123 +++
 blog_menu/classes/privacy/provider.php        |  46 ++
 blog_menu/db/access.php                       |  41 +
 blog_menu/lang/en/block_blog_menu.php         |  28 +
 blog_menu/tests/behat/block_blog_menu.feature |  76 ++
 .../behat/block_blog_menu_activity.feature    | 213 +++++
 .../behat/block_blog_menu_course.feature      | 190 +++++
 .../behat/block_blog_menu_frontpage.feature   |  30 +
 blog_menu/version.php                         |  29 +
 blog_recent/block_blog_recent.php             | 128 +++
 blog_recent/classes/privacy/provider.php      |  46 ++
 blog_recent/db/access.php                     |  41 +
 blog_recent/edit_form.php                     |  61 ++
 blog_recent/lang/en/block_blog_recent.php     |  31 +
 .../tests/behat/block_blog_recent.feature     |  32 +
 .../behat/block_blog_recent_activity.feature  | 115 +++
 .../behat/block_blog_recent_course.feature    | 105 +++
 .../behat/block_blog_recent_frontpage.feature |  98 +++
 blog_recent/version.php                       |  29 +
 blog_tags/block_blog_tags.php                 | 229 ++++++
 blog_tags/classes/privacy/provider.php        |  46 ++
 blog_tags/db/access.php                       |  41 +
 blog_tags/edit_form.php                       |  66 ++
 blog_tags/lang/en/block_blog_tags.php         |  28 +
 blog_tags/styles.css                          |  68 ++
 blog_tags/tests/behat/blogtag.feature         |  55 ++
 blog_tags/version.php                         |  29 +
 calendar_month/block_calendar_month.php       |  65 ++
 calendar_month/classes/privacy/provider.php   |  46 ++
 calendar_month/db/access.php                  |  51 ++
 calendar_month/db/upgrade.php                 |  58 ++
 .../lang/en/block_calendar_month.php          |  28 +
 .../tests/behat/block_calendar_month.feature  | 195 +++++
 .../behat/block_calendar_month_course.feature |  27 +
 .../block_calendar_month_dashboard.feature    |  19 +
 .../block_calendar_month_frontpage.feature    |  23 +
 calendar_month/version.php                    |  29 +
 calendar_upcoming/block_calendar_upcoming.php | 127 +++
 .../classes/privacy/provider.php              |  46 ++
 calendar_upcoming/db/access.php               |  51 ++
 calendar_upcoming/db/upgrade.php              |  58 ++
 .../lang/en/block_calendar_upcoming.php       |  29 +
 .../block_calendar_upcoming_course.feature    |  26 +
 .../block_calendar_upcoming_dashboard.feature |  19 +
 .../block_calendar_upcoming_frontpage.feature |  24 +
 calendar_upcoming/upgrade.txt                 |   5 +
 calendar_upcoming/version.php                 |  29 +
 career/README.md                              |  49 ++
 career/block_career.php                       | 109 +++
 career/career_list.php                        |  38 +
 career/career_setting.php                     |  82 ++
 career/career_unit.php                        |  30 +
 career/db/access.php                          |  25 +
 career/db/install.xml                         |  21 +
 career/edit_form.php                          |  20 +
 career/entity/block_career_ressource.php      | 108 +++
 career/entity/block_career_section.php        |  91 ++
 ...\251cran 2018-06-19 \303\240 18.18.32.png" | Bin 0 -> 176862 bytes
 career/img/file.txt                           |   0
 career/img/numoc-16-9-blanc.png               | Bin 0 -> 86910 bytes
 career/img/rose-rose.jpg                      | Bin 0 -> 45517 bytes
 career/index.php                              |  12 +
 career/js/file.js                             |  48 ++
 career/js/interact.min.js                     |   5 +
 career/js/jquery-1.8.2.min.js                 |   2 +
 career/js/jquery.min.js                       |   4 +
 career/lang/en/block_career.php               |  18 +
 career/lang/fr/block_career.php               |  17 +
 career/styles.css                             | 260 ++++++
 career/version.php                            |  35 +
 career/view/view_career_list.php              |  55 ++
 career/view/view_career_setting.php           | 196 +++++
 career/view/view_career_unit.php              | 106 +++
 classes 14.04.12/external.php                 | 137 +++
 classes 14.04.12/privacy/provider.php         | 227 +++++
 comments/block_comments.php                   |  88 ++
 comments/classes/event/comment_created.php    |  38 +
 comments/classes/event/comment_deleted.php    |  38 +
 comments/classes/privacy/provider.php         | 115 +++
 comments/db/access.php                        |  51 ++
 comments/lang/en/block_comments.php           |  29 +
 comments/lib.php                              |  83 ++
 comments/tests/behat/add_comment.feature      |  98 +++
 comments/tests/behat/behat_block_comments.php | 110 +++
 .../behat/block_comment_activity.feature      |  33 +
 .../tests/behat/block_comment_course.feature  |  28 +
 .../behat/block_comment_dashboard.feature     |  29 +
 .../behat/block_comment_frontpage.feature     |  21 +
 comments/tests/behat/delete_comment.feature   |  34 +
 comments/tests/events_test.php                | 184 +++++
 comments/tests/privacy_provider_test.php      | 468 +++++++++++
 comments/version.php                          |  29 +
 community/block_community.php                 | 104 +++
 community/classes/privacy/provider.php        | 181 ++++
 community/communitycourse.php                 | 208 +++++
 community/db/access.php                       |  51 ++
 community/db/install.xml                      |  21 +
 community/db/upgrade.php                      |  59 ++
 community/forms.php                           | 173 ++++
 community/lang/en/block_community.php         | 121 +++
 community/locallib.php                        |  88 ++
 community/renderer.php                        | 400 +++++++++
 community/styles.css                          | 355 ++++++++
 community/tests/privacy_test.php              | 267 ++++++
 community/version.php                         |  29 +
 community/yui/comments/comments.js            |  97 +++
 community/yui/imagegallery/imagegallery.js    | 206 +++++
 completionstatus/block_completionstatus.php   | 256 ++++++
 completionstatus/classes/privacy/provider.php |  46 ++
 completionstatus/db/access.php                |  41 +
 completionstatus/db/upgrade.php               |  61 ++
 completionstatus/details.php                  | 263 ++++++
 .../lang/en/block_completionstatus.php        |  32 +
 .../behat/block_completionstatus.feature      |  54 ++
 ...mpletionstatus_activity_completion.feature |  70 ++
 ...lock_completionstatus_manual_other.feature | 103 +++
 ...block_completionstatus_manual_self.feature |  45 +
 completionstatus/version.php                  |  31 +
 course_list/block_course_list.php             | 177 ++++
 course_list/classes/privacy/provider.php      |  46 ++
 course_list/db/access.php                     |  51 ++
 course_list/lang/en/block_course_list.php     |  34 +
 course_list/settings.php                      |  37 +
 course_list/styles.css                        |   7 +
 .../behat/block_course_list_category.feature  |  78 ++
 .../behat/block_course_list_course.feature    |  87 ++
 .../behat/block_course_list_dashboard.feature |  61 ++
 .../behat/block_course_list_frontpage.feature |  86 ++
 course_list/version.php                       |  29 +
 course_summary/block_course_summary.php       |  79 ++
 course_summary/classes/privacy/provider.php   |  46 ++
 course_summary/db/access.php                  |  41 +
 course_summary/db/upgrade.php                 |  61 ++
 .../lang/en/block_course_summary.php          |  29 +
 course_summary/styles.css                     |   7 +
 .../behat/block_course_summary_course.feature |  36 +
 .../block_course_summary_frontpage.feature    |  30 +
 course_summary/version.php                    |  29 +
 edit_form 14.04.12.php                        | 313 +++++++
 feedback/block_feedback.php                   |  73 ++
 feedback/classes/privacy/provider.php         |  46 ++
 feedback/db/access.php                        |  41 +
 feedback/db/install.php                       |  29 +
 feedback/lang/en/block_feedback.php           |  28 +
 feedback/version.php                          |  31 +
 globalsearch/block_globalsearch.php           |  96 +++
 globalsearch/classes/privacy/provider.php     |  46 ++
 globalsearch/db/access.php                    |  48 ++
 globalsearch/lang/en/block_globalsearch.php   |  28 +
 globalsearch/styles.css                       |   7 +
 globalsearch/version.php                      |  30 +
 ...store_glossary_random_block_task.class.php |  95 +++
 glossary_random/block_glossary_random.php     | 258 ++++++
 glossary_random/classes/privacy/provider.php  |  46 ++
 glossary_random/db/access.php                 |  51 ++
 glossary_random/edit_form.php                 |  79 ++
 .../lang/en/block_glossary_random.php         |  48 ++
 .../tests/behat/glossary_random.feature       | 108 +++
 .../behat/glossary_random_frontpage.feature   |  27 +
 .../behat/glossary_random_global.feature      |  79 ++
 glossary_random/version.php                   |  31 +
 html/backup/moodle1/lib.php                   |  64 ++
 .../moodle2/backup_html_block_task.class.php  |  50 ++
 .../moodle2/restore_html_block_task.class.php |  93 +++
 html/block_html.php                           | 177 ++++
 html/classes/privacy/provider.php             | 196 +++++
 html/classes/search/content.php               |  91 ++
 html/db/access.php                            |  51 ++
 html/db/upgrade.php                           |  46 ++
 html/edit_form.php                            |  91 ++
 html/lang/en/block_html.php                   |  36 +
 html/lib.php                                  | 112 +++
 html/settings.php                             |  32 +
 .../behat/configuring_html_block.feature      |  41 +
 html/tests/behat/course_block.feature         |  35 +
 html/tests/behat/multiple_instances.feature   |  42 +
 html/tests/privacy_provider_test.php          | 344 ++++++++
 html/tests/search_content_test.php            | 191 +++++
 html/version.php                              |  29 +
 index.html                                    |   1 +
 login/block_login.php                         | 126 +++
 login/classes/privacy/provider.php            |  46 ++
 login/db/access.php                           |  41 +
 login/lang/en/block_login.php                 |  27 +
 login/tests/behat/login_block.feature         |  28 +
 login/version.php                             |  29 +
 lp/block_lp.php                               |  84 ++
 .../output/competencies_to_review_page.php    |  87 ++
 lp/classes/output/plans_to_review_page.php    |  82 ++
 lp/classes/output/renderer.php                |  70 ++
 lp/classes/output/summary.php                 | 156 ++++
 lp/classes/privacy/provider.php               |  46 ++
 lp/competencies_to_review.php                 |  48 ++
 lp/db/access.php                              |  57 ++
 lp/lang/en/block_lp.php                       |  37 +
 lp/plans_to_review.php                        |  48 ++
 lp/styles.css                                 |  17 +
 .../competencies_to_review_page.mustache      |  49 ++
 lp/templates/plans_to_review_page.mustache    |  49 ++
 lp/templates/summary.mustache                 |  87 ++
 lp/version.php                                |  32 +
 mahara_iena                                   |   1 +
 mentees/block_mentees.php                     |  82 ++
 mentees/classes/privacy/provider.php          |  46 ++
 mentees/db/access.php                         |  51 ++
 mentees/edit_form.php                         |  39 +
 mentees/lang/en/block_mentees.php             |  32 +
 .../behat/configuring_mentees_block.feature   |  18 +
 mentees/version.php                           |  29 +
 mnet_hosts/block_mnet_hosts.php               | 156 ++++
 mnet_hosts/classes/privacy/provider.php       |  46 ++
 mnet_hosts/db/access.php                      |  51 ++
 mnet_hosts/lang/en/block_mnet_hosts.php       |  32 +
 mnet_hosts/version.php                        |  29 +
 moodleblock.class.php                         | 778 ++++++++++++++++++
 .../build/calendar_events_repository.min.js   |   1 +
 myoverview/amd/build/event_list.min.js        |   1 +
 .../amd/build/event_list_by_course.min.js     |   1 +
 myoverview/amd/build/paging_bar.min.js        |   1 +
 myoverview/amd/build/paging_content.min.js    |   1 +
 myoverview/amd/build/tab_preferences.min.js   |   1 +
 .../amd/src/calendar_events_repository.js     | 168 ++++
 myoverview/amd/src/event_list.js              | 414 ++++++++++
 myoverview/amd/src/event_list_by_course.js    | 108 +++
 myoverview/amd/src/paging_bar.js              | 102 +++
 myoverview/amd/src/paging_content.js          | 105 +++
 myoverview/amd/src/tab_preferences.js         |  61 ++
 myoverview/block_myoverview.php               |  89 ++
 myoverview/classes/output/courses_view.php    | 190 +++++
 myoverview/classes/output/main.php            | 111 +++
 myoverview/classes/output/renderer.php        |  48 ++
 myoverview/classes/privacy/provider.php       |  61 ++
 myoverview/db/access.php                      |  50 ++
 myoverview/lang/en/block_myoverview.php       |  47 ++
 myoverview/lib.php                            |  52 ++
 myoverview/pix/activities.svg                 |  41 +
 myoverview/pix/courses.svg                    |  52 ++
 myoverview/settings.php                       |  39 +
 .../templates/course-event-list-item.mustache |  69 ++
 .../course-event-list-items.mustache          |  63 ++
 .../templates/course-event-list.mustache      | 110 +++
 myoverview/templates/course-item.mustache     |  44 +
 .../course-paging-content-item.mustache       |  47 ++
 .../templates/course-paging-content.mustache  |  48 ++
 myoverview/templates/course-summary.mustache  |  49 ++
 .../templates/courses-view-by-status.mustache |  45 +
 .../courses-view-course-item.mustache         |  49 ++
 myoverview/templates/courses-view.mustache    | 115 +++
 .../templates/event-list-group.mustache       |  75 ++
 myoverview/templates/event-list-item.mustache |  76 ++
 .../templates/event-list-items.mustache       |  68 ++
 myoverview/templates/event-list.mustache      |  87 ++
 myoverview/templates/main.mustache            |  55 ++
 myoverview/templates/paging-bar-item.mustache |  41 +
 myoverview/templates/paging-bar.mustache      |  96 +++
 .../templates/paging-content-item.mustache    |  36 +
 myoverview/templates/paging-content.mustache  |  44 +
 myoverview/templates/progress-chart.mustache  |  50 ++
 .../templates/timeline-view-courses.mustache  | 121 +++
 .../templates/timeline-view-dates.mustache    |  35 +
 myoverview/templates/timeline-view.mustache   |  49 ++
 .../behat/block_myoverview_dashboard.feature  |  72 ++
 .../behat/block_myoverview_progress.feature   |  63 ++
 myoverview/tests/privacy_test.php             |  80 ++
 myoverview/version.php                        |  29 +
 myprofile/block_myprofile.php                 | 238 ++++++
 myprofile/classes/privacy/provider.php        |  46 ++
 myprofile/db/access.php                       |  51 ++
 myprofile/edit_form.php                       | 151 ++++
 myprofile/lang/en/block_myprofile.php         |  51 ++
 myprofile/lang/en/deprecated.txt              |   1 +
 myprofile/styles.css                          |  14 +
 myprofile/tests/behat/block_myprofile.feature | 309 +++++++
 .../behat/block_myprofile_activity.feature    |  24 +
 .../behat/block_myprofile_course.feature      |  20 +
 .../behat/block_myprofile_dashboard.feature   |  14 +
 .../behat/block_myprofile_frontpage.feature   |  25 +
 myprofile/version.php                         |  30 +
 .../amd/build/ajax_response_renderer.min.js   |   1 +
 navigation/amd/build/nav_loader.min.js        |   1 +
 navigation/amd/build/navblock.min.js          |   1 +
 navigation/amd/build/site_admin_loader.min.js |   1 +
 navigation/amd/src/ajax_response_renderer.js  | 165 ++++
 navigation/amd/src/nav_loader.js              |  64 ++
 navigation/amd/src/navblock.js                |  46 ++
 navigation/amd/src/site_admin_loader.js       |  52 ++
 navigation/block_navigation.php               | 336 ++++++++
 navigation/classes/privacy/provider.php       |  46 ++
 navigation/db/access.php                      |  51 ++
 navigation/db/upgrade.php                     |  68 ++
 navigation/edit_form.php                      |  71 ++
 navigation/lang/en/block_navigation.php       |  42 +
 navigation/renderer.php                       | 192 +++++
 navigation/styles.css                         |  76 ++
 .../tests/behat/expand_courses_node.feature   | 202 +++++
 .../tests/behat/participants_link.feature     |  54 ++
 .../tests/behat/view_my_courses.feature       | 104 +++
 navigation/version.php                        |  29 +
 news_items/block_news_items.php               | 156 ++++
 news_items/classes/privacy/provider.php       |  46 ++
 news_items/db/access.php                      |  51 ++
 news_items/lang/en/block_news_items.php       |  28 +
 news_items/tests/behat/display_news.feature   |  47 ++
 news_items/version.php                        |  30 +
 online_users/block_online_users.php           | 147 ++++
 online_users/classes/fetcher.php              | 165 ++++
 online_users/classes/privacy/provider.php     |  46 ++
 online_users/db/access.php                    |  65 ++
 online_users/lang/en/block_online_users.php   |  36 +
 online_users/settings.php                     |  31 +
 online_users/styles.css                       |  21 +
 .../behat/block_online_users_course.feature   |  41 +
 .../block_online_users_dashboard.feature      |  28 +
 .../block_online_users_frontpage.feature      |  51 ++
 online_users/tests/generator/lib.php          |  90 ++
 online_users/tests/generator_test.php         |  57 ++
 online_users/tests/online_users_test.php      | 151 ++++
 online_users/version.php                      |  29 +
 participants/block_participants.php           |  85 ++
 participants/classes/privacy/provider.php     |  46 ++
 participants/db/access.php                    |  41 +
 participants/lang/en/block_participants.php   |  27 +
 .../behat/block_participants_course.feature   |  40 +
 .../block_participants_frontpage.feature      |  26 +
 participants/version.php                      |  29 +
 private_files/block_private_files.php         |  72 ++
 private_files/classes/privacy/provider.php    |  46 ++
 private_files/db/access.php                   |  51 ++
 private_files/edit.php                        |  29 +
 private_files/lang/en/block_private_files.php |  29 +
 private_files/module.js                       |  41 +
 private_files/renderer.php                    |  89 ++
 private_files/styles.css                      |  10 +
 .../block_private_files_activity.feature      |  28 +
 .../behat/block_private_files_course.feature  |  24 +
 .../block_private_files_dashboard.feature     |  17 +
 .../block_private_files_frontpage.feature     |  34 +
 private_files/tests/fixtures/testfile.txt     |   1 +
 private_files/version.php                     |  29 +
 .../restore_quiz_results_block_task.class.php | 113 +++
 quiz_results/block_quiz_results.php           |  61 ++
 quiz_results/classes/privacy/provider.php     |  46 ++
 quiz_results/db/access.php                    |  41 +
 quiz_results/db/install.php                   |  31 +
 quiz_results/db/upgrade.php                   |  58 ++
 quiz_results/lang/en/block_quiz_results.php   |  27 +
 quiz_results/lang/en/depreciated.txt          |   0
 quiz_results/version.php                      |  31 +
 recent_activity/block_recent_activity.php     | 309 +++++++
 recent_activity/classes/observer.php          |  73 ++
 recent_activity/classes/privacy/provider.php  |  97 +++
 recent_activity/db/access.php                 |  57 ++
 recent_activity/db/events.php                 |  47 ++
 recent_activity/db/install.xml                |  25 +
 recent_activity/db/upgrade.php                |  60 ++
 .../lang/en/block_recent_activity.php         |  37 +
 recent_activity/renderer.php                  | 128 +++
 recent_activity/styles.css                    |  12 +
 .../tests/behat/structural_changes.feature    | 215 +++++
 recent_activity/version.php                   |  30 +
 rss_client/backup/moodle1/lib.php             |  48 ++
 .../backup_rss_client_block_task.class.php    |  54 ++
 .../moodle2/backup_rss_client_stepslib.php    |  83 ++
 .../restore_rss_client_block_task.class.php   |  58 ++
 .../moodle2/restore_rss_client_stepslib.php   |  90 ++
 rss_client/block_rss_client.php               | 387 +++++++++
 rss_client/classes/output/block.php           | 104 +++
 rss_client/classes/output/channel_image.php   | 151 ++++
 rss_client/classes/output/feed.php            | 224 +++++
 rss_client/classes/output/footer.php          | 111 +++
 rss_client/classes/output/item.php            | 286 +++++++
 rss_client/classes/output/renderer.php        | 121 +++
 rss_client/classes/privacy/provider.php       | 152 ++++
 rss_client/db/access.php                      |  76 ++
 rss_client/db/install.xml                     |  24 +
 rss_client/db/upgrade.php                     |  46 ++
 rss_client/edit_form.php                      |  93 +++
 rss_client/editfeed.php                       | 232 ++++++
 rss_client/lang/en/block_rss_client.php       |  90 ++
 rss_client/managefeeds.php                    | 147 ++++
 rss_client/settings.php                       |  36 +
 rss_client/styles.css                         |  10 +
 rss_client/templates/block.mustache           |  91 ++
 rss_client/templates/channel_image.mustache   |  50 ++
 rss_client/templates/feed.mustache            |  79 ++
 rss_client/templates/footer.mustache          |  42 +
 rss_client/templates/item.mustache            |  63 ++
 rss_client/tests/cron_test.php                | 149 ++++
 rss_client/tests/privacy_test.php             | 148 ++++
 rss_client/version.php                        |  30 +
 rss_client/viewfeed.php                       |  99 +++
 search_forums/block_search_forums.php         |  66 ++
 search_forums/classes/output/renderer.php     |  50 ++
 search_forums/classes/output/search_form.php  |  74 ++
 search_forums/classes/privacy/provider.php    |  46 ++
 search_forums/db/access.php                   |  41 +
 search_forums/lang/en/block_search_forums.php |  28 +
 search_forums/styles.css                      |  16 +
 search_forums/templates/search_form.mustache  |  15 +
 .../behat/block_search_forums_course.feature  |  71 ++
 .../block_search_forums_frontpage.feature     |  31 +
 search_forums/version.php                     |  31 +
 section_links/block_section_links.php         | 159 ++++
 section_links/classes/privacy/provider.php    |  46 ++
 section_links/db/access.php                   |  41 +
 section_links/db/upgrade.php                  |  62 ++
 section_links/edit_form.php                   |  86 ++
 section_links/lang/en/block_section_links.php |  39 +
 section_links/renderer.php                    |  76 ++
 section_links/settings.php                    |  51 ++
 .../behat/block_section_links_course.feature  |  57 ++
 section_links/version.php                     |  29 +
 selfcompletion/block_selfcompletion.php       | 112 +++
 selfcompletion/classes/privacy/provider.php   |  46 ++
 selfcompletion/db/access.php                  |  41 +
 selfcompletion/db/upgrade.php                 |  61 ++
 .../lang/en/block_selfcompletion.php          |  30 +
 selfcompletion/version.php                    |  29 +
 settings/amd/build/settingsblock.min.js       |   1 +
 settings/amd/src/settingsblock.js             |  51 ++
 settings/block_settings.php                   | 163 ++++
 settings/classes/privacy/provider.php         |  46 ++
 settings/db/access.php                        |  51 ++
 settings/db/upgrade.php                       |  68 ++
 settings/edit_form.php                        |  46 ++
 settings/lang/en/block_settings.php           |  31 +
 settings/renderer.php                         | 156 ++++
 settings/styles.css                           |  65 ++
 settings/version.php                          |  29 +
 site_main_menu/block_site_main_menu.php       | 163 ++++
 site_main_menu/classes/privacy/provider.php   |  46 ++
 site_main_menu/db/access.php                  |  41 +
 .../lang/en/block_site_main_menu.php          |  28 +
 site_main_menu/styles.css                     |  34 +
 site_main_menu/tests/behat/add_url.feature    |  19 +
 .../behat/behat_block_site_main_menu.php      | 157 ++++
 .../tests/behat/edit_activities.feature       |  67 ++
 site_main_menu/version.php                    |  29 +
 social_activities/block_social_activities.php | 153 ++++
 .../classes/privacy/provider.php              |  46 ++
 social_activities/db/access.php               |  41 +
 .../lang/en/block_social_activities.php       |  27 +
 social_activities/styles.css                  |  16 +
 .../behat/behat_block_social_activities.php   | 157 ++++
 .../tests/behat/edit_activities.feature       |  85 ++
 social_activities/version.php                 |  29 +
 tag_flickr/block_tag_flickr.php               | 183 ++++
 tag_flickr/classes/privacy/provider.php       |  94 +++
 tag_flickr/db/access.php                      |  41 +
 tag_flickr/edit_form.php                      |  59 ++
 tag_flickr/lang/en/block_tag_flickr.php       |  41 +
 tag_flickr/styles.css                         |   3 +
 .../configuring_tag_flickr_block.feature      |  20 +
 tag_flickr/version.php                        |  29 +
 tag_youtube/block_tag_youtube.php             | 402 +++++++++
 tag_youtube/classes/privacy/provider.php      |  46 ++
 tag_youtube/db/access.php                     |  41 +
 tag_youtube/db/install.php                    |  36 +
 tag_youtube/edit_form.php                     |  48 ++
 tag_youtube/lang/en/block_tag_youtube.php     |  50 ++
 tag_youtube/settings.php                      |  30 +
 tag_youtube/styles.css                        |  10 +
 tag_youtube/tests/block_tag_youtube_test.php  |  51 ++
 tag_youtube/upgrade.txt                       |   8 +
 tag_youtube/version.php                       |  29 +
 .../moodle2/restore_tags_block_task.class.php |  88 ++
 tags/block_tags.php                           | 112 +++
 tags/classes/privacy/provider.php             |  46 ++
 tags/db/access.php                            |  51 ++
 tags/edit_form.php                            | 100 +++
 tags/lang/en/block_tags.php                   |  41 +
 tags/tests/behat/tagcloud.feature             |  49 ++
 tags/version.php                              |  29 +
 tests/behat/add_blocks.feature                |  27 +
 tests/behat/behat_blocks.php                  | 152 ++++
 .../configure_block_throughout_site.feature   |  73 ++
 tests/behat/hidden_block_region.feature       |  52 ++
 tests/behat/hide_blocks.feature               |  27 +
 tests/behat/manage_blocks.feature             |  60 ++
 tests/behat/move_blocks.feature               |  46 ++
 tests/behat/restrict_available_blocks.feature |  38 +
 .../behat/return_block_original_state.feature |  47 ++
 tests/externallib_test.php                    | 141 ++++
 tests/privacy_test.php                        | 364 ++++++++
 upgrade 14.04.12.txt                          |  82 ++
 534 files changed, 40311 insertions(+)
 create mode 100644 activity_modules/block_activity_modules.php
 create mode 100644 activity_modules/classes/privacy/provider.php
 create mode 100644 activity_modules/db/access.php
 create mode 100644 activity_modules/lang/en/block_activity_modules.php
 create mode 100644 activity_modules/tests/behat/block_activity_modules.feature
 create mode 100644 activity_modules/version.php
 create mode 100644 activity_results/backup/moodle2/restore_activity_results_block_task.class.php
 create mode 100644 activity_results/block_activity_results.php
 create mode 100644 activity_results/classes/privacy/provider.php
 create mode 100644 activity_results/db/access.php
 create mode 100644 activity_results/edit_form.php
 create mode 100644 activity_results/lang/en/block_activity_results.php
 create mode 100644 activity_results/settings.php
 create mode 100644 activity_results/styles.css
 create mode 100644 activity_results/tests/behat/addblockinactivity.feature
 create mode 100644 activity_results/tests/behat/addunconfiguredblock.feature
 create mode 100644 activity_results/tests/behat/addunsupportedactivity.feature
 create mode 100644 activity_results/tests/behat/defaultsettings.feature
 create mode 100644 activity_results/tests/behat/highscoreswithoutgroups.feature
 create mode 100644 activity_results/tests/behat/highscoreswithscales.feature
 create mode 100644 activity_results/tests/behat/highscoreswithscalesandgroups.feature
 create mode 100644 activity_results/tests/behat/highscoreswithseperategroups.feature
 create mode 100644 activity_results/tests/behat/highscoreswithvisiblegroups.feature
 create mode 100644 activity_results/tests/behat/lowscoreswithoutgroups.feature
 create mode 100644 activity_results/tests/behat/lowscoreswithscales.feature
 create mode 100644 activity_results/tests/behat/lowscoreswithscalesandgroups.feature
 create mode 100644 activity_results/tests/behat/lowscoreswithseperategroups.feature
 create mode 100644 activity_results/tests/behat/lowscoreswithvisiblegroups.feature
 create mode 100644 activity_results/version.php
 create mode 100644 admin_bookmarks/block_admin_bookmarks.php
 create mode 100644 admin_bookmarks/classes/privacy/provider.php
 create mode 100644 admin_bookmarks/create.php
 create mode 100644 admin_bookmarks/db/access.php
 create mode 100644 admin_bookmarks/delete.php
 create mode 100644 admin_bookmarks/lang/en/block_admin_bookmarks.php
 create mode 100644 admin_bookmarks/tests/behat/bookmark_admin_pages.feature
 create mode 100644 admin_bookmarks/version.php
 create mode 100644 badges/block_badges.php
 create mode 100644 badges/classes/privacy/provider.php
 create mode 100644 badges/db/access.php
 create mode 100644 badges/db/upgrade.php
 create mode 100644 badges/edit_form.php
 create mode 100644 badges/lang/en/block_badges.php
 create mode 100644 badges/tests/behat/block_badges.feature
 create mode 100644 badges/tests/behat/block_badges_course.feature
 create mode 100644 badges/tests/behat/block_badges_dashboard.feature
 create mode 100644 badges/tests/behat/block_badges_frontpage.feature
 create mode 100644 badges/tests/fixtures/badge.png
 create mode 100644 badges/version.php
 create mode 100644 blog_menu/block_blog_menu.php
 create mode 100644 blog_menu/classes/privacy/provider.php
 create mode 100644 blog_menu/db/access.php
 create mode 100644 blog_menu/lang/en/block_blog_menu.php
 create mode 100644 blog_menu/tests/behat/block_blog_menu.feature
 create mode 100644 blog_menu/tests/behat/block_blog_menu_activity.feature
 create mode 100644 blog_menu/tests/behat/block_blog_menu_course.feature
 create mode 100644 blog_menu/tests/behat/block_blog_menu_frontpage.feature
 create mode 100644 blog_menu/version.php
 create mode 100644 blog_recent/block_blog_recent.php
 create mode 100644 blog_recent/classes/privacy/provider.php
 create mode 100644 blog_recent/db/access.php
 create mode 100644 blog_recent/edit_form.php
 create mode 100644 blog_recent/lang/en/block_blog_recent.php
 create mode 100644 blog_recent/tests/behat/block_blog_recent.feature
 create mode 100644 blog_recent/tests/behat/block_blog_recent_activity.feature
 create mode 100644 blog_recent/tests/behat/block_blog_recent_course.feature
 create mode 100644 blog_recent/tests/behat/block_blog_recent_frontpage.feature
 create mode 100644 blog_recent/version.php
 create mode 100644 blog_tags/block_blog_tags.php
 create mode 100644 blog_tags/classes/privacy/provider.php
 create mode 100644 blog_tags/db/access.php
 create mode 100644 blog_tags/edit_form.php
 create mode 100644 blog_tags/lang/en/block_blog_tags.php
 create mode 100644 blog_tags/styles.css
 create mode 100644 blog_tags/tests/behat/blogtag.feature
 create mode 100644 blog_tags/version.php
 create mode 100644 calendar_month/block_calendar_month.php
 create mode 100644 calendar_month/classes/privacy/provider.php
 create mode 100644 calendar_month/db/access.php
 create mode 100644 calendar_month/db/upgrade.php
 create mode 100644 calendar_month/lang/en/block_calendar_month.php
 create mode 100644 calendar_month/tests/behat/block_calendar_month.feature
 create mode 100644 calendar_month/tests/behat/block_calendar_month_course.feature
 create mode 100644 calendar_month/tests/behat/block_calendar_month_dashboard.feature
 create mode 100644 calendar_month/tests/behat/block_calendar_month_frontpage.feature
 create mode 100644 calendar_month/version.php
 create mode 100644 calendar_upcoming/block_calendar_upcoming.php
 create mode 100644 calendar_upcoming/classes/privacy/provider.php
 create mode 100644 calendar_upcoming/db/access.php
 create mode 100644 calendar_upcoming/db/upgrade.php
 create mode 100644 calendar_upcoming/lang/en/block_calendar_upcoming.php
 create mode 100644 calendar_upcoming/tests/behat/block_calendar_upcoming_course.feature
 create mode 100644 calendar_upcoming/tests/behat/block_calendar_upcoming_dashboard.feature
 create mode 100644 calendar_upcoming/tests/behat/block_calendar_upcoming_frontpage.feature
 create mode 100644 calendar_upcoming/upgrade.txt
 create mode 100644 calendar_upcoming/version.php
 create mode 100644 career/README.md
 create mode 100644 career/block_career.php
 create mode 100644 career/career_list.php
 create mode 100644 career/career_setting.php
 create mode 100644 career/career_unit.php
 create mode 100644 career/db/access.php
 create mode 100644 career/db/install.xml
 create mode 100644 career/edit_form.php
 create mode 100644 career/entity/block_career_ressource.php
 create mode 100644 career/entity/block_career_section.php
 create mode 100644 "career/img/Capture d\342\200\231\303\251cran 2018-06-19 \303\240 18.18.32.png"
 create mode 100644 career/img/file.txt
 create mode 100644 career/img/numoc-16-9-blanc.png
 create mode 100644 career/img/rose-rose.jpg
 create mode 100644 career/index.php
 create mode 100644 career/js/file.js
 create mode 100644 career/js/interact.min.js
 create mode 100644 career/js/jquery-1.8.2.min.js
 create mode 100644 career/js/jquery.min.js
 create mode 100644 career/lang/en/block_career.php
 create mode 100644 career/lang/fr/block_career.php
 create mode 100644 career/styles.css
 create mode 100644 career/version.php
 create mode 100644 career/view/view_career_list.php
 create mode 100644 career/view/view_career_setting.php
 create mode 100644 career/view/view_career_unit.php
 create mode 100644 classes 14.04.12/external.php
 create mode 100644 classes 14.04.12/privacy/provider.php
 create mode 100644 comments/block_comments.php
 create mode 100644 comments/classes/event/comment_created.php
 create mode 100644 comments/classes/event/comment_deleted.php
 create mode 100644 comments/classes/privacy/provider.php
 create mode 100644 comments/db/access.php
 create mode 100644 comments/lang/en/block_comments.php
 create mode 100644 comments/lib.php
 create mode 100644 comments/tests/behat/add_comment.feature
 create mode 100644 comments/tests/behat/behat_block_comments.php
 create mode 100644 comments/tests/behat/block_comment_activity.feature
 create mode 100644 comments/tests/behat/block_comment_course.feature
 create mode 100644 comments/tests/behat/block_comment_dashboard.feature
 create mode 100644 comments/tests/behat/block_comment_frontpage.feature
 create mode 100644 comments/tests/behat/delete_comment.feature
 create mode 100644 comments/tests/events_test.php
 create mode 100644 comments/tests/privacy_provider_test.php
 create mode 100644 comments/version.php
 create mode 100644 community/block_community.php
 create mode 100644 community/classes/privacy/provider.php
 create mode 100644 community/communitycourse.php
 create mode 100644 community/db/access.php
 create mode 100644 community/db/install.xml
 create mode 100644 community/db/upgrade.php
 create mode 100644 community/forms.php
 create mode 100644 community/lang/en/block_community.php
 create mode 100644 community/locallib.php
 create mode 100644 community/renderer.php
 create mode 100644 community/styles.css
 create mode 100644 community/tests/privacy_test.php
 create mode 100644 community/version.php
 create mode 100644 community/yui/comments/comments.js
 create mode 100644 community/yui/imagegallery/imagegallery.js
 create mode 100644 completionstatus/block_completionstatus.php
 create mode 100644 completionstatus/classes/privacy/provider.php
 create mode 100644 completionstatus/db/access.php
 create mode 100644 completionstatus/db/upgrade.php
 create mode 100644 completionstatus/details.php
 create mode 100644 completionstatus/lang/en/block_completionstatus.php
 create mode 100644 completionstatus/tests/behat/block_completionstatus.feature
 create mode 100644 completionstatus/tests/behat/block_completionstatus_activity_completion.feature
 create mode 100644 completionstatus/tests/behat/block_completionstatus_manual_other.feature
 create mode 100644 completionstatus/tests/behat/block_completionstatus_manual_self.feature
 create mode 100644 completionstatus/version.php
 create mode 100644 course_list/block_course_list.php
 create mode 100644 course_list/classes/privacy/provider.php
 create mode 100644 course_list/db/access.php
 create mode 100644 course_list/lang/en/block_course_list.php
 create mode 100644 course_list/settings.php
 create mode 100644 course_list/styles.css
 create mode 100644 course_list/tests/behat/block_course_list_category.feature
 create mode 100644 course_list/tests/behat/block_course_list_course.feature
 create mode 100644 course_list/tests/behat/block_course_list_dashboard.feature
 create mode 100644 course_list/tests/behat/block_course_list_frontpage.feature
 create mode 100644 course_list/version.php
 create mode 100644 course_summary/block_course_summary.php
 create mode 100644 course_summary/classes/privacy/provider.php
 create mode 100644 course_summary/db/access.php
 create mode 100644 course_summary/db/upgrade.php
 create mode 100644 course_summary/lang/en/block_course_summary.php
 create mode 100644 course_summary/styles.css
 create mode 100644 course_summary/tests/behat/block_course_summary_course.feature
 create mode 100644 course_summary/tests/behat/block_course_summary_frontpage.feature
 create mode 100644 course_summary/version.php
 create mode 100644 edit_form 14.04.12.php
 create mode 100644 feedback/block_feedback.php
 create mode 100644 feedback/classes/privacy/provider.php
 create mode 100644 feedback/db/access.php
 create mode 100644 feedback/db/install.php
 create mode 100644 feedback/lang/en/block_feedback.php
 create mode 100644 feedback/version.php
 create mode 100644 globalsearch/block_globalsearch.php
 create mode 100644 globalsearch/classes/privacy/provider.php
 create mode 100644 globalsearch/db/access.php
 create mode 100644 globalsearch/lang/en/block_globalsearch.php
 create mode 100644 globalsearch/styles.css
 create mode 100644 globalsearch/version.php
 create mode 100644 glossary_random/backup/moodle2/restore_glossary_random_block_task.class.php
 create mode 100644 glossary_random/block_glossary_random.php
 create mode 100644 glossary_random/classes/privacy/provider.php
 create mode 100644 glossary_random/db/access.php
 create mode 100644 glossary_random/edit_form.php
 create mode 100644 glossary_random/lang/en/block_glossary_random.php
 create mode 100644 glossary_random/tests/behat/glossary_random.feature
 create mode 100644 glossary_random/tests/behat/glossary_random_frontpage.feature
 create mode 100644 glossary_random/tests/behat/glossary_random_global.feature
 create mode 100644 glossary_random/version.php
 create mode 100644 html/backup/moodle1/lib.php
 create mode 100644 html/backup/moodle2/backup_html_block_task.class.php
 create mode 100644 html/backup/moodle2/restore_html_block_task.class.php
 create mode 100644 html/block_html.php
 create mode 100644 html/classes/privacy/provider.php
 create mode 100644 html/classes/search/content.php
 create mode 100644 html/db/access.php
 create mode 100644 html/db/upgrade.php
 create mode 100644 html/edit_form.php
 create mode 100644 html/lang/en/block_html.php
 create mode 100644 html/lib.php
 create mode 100644 html/settings.php
 create mode 100644 html/tests/behat/configuring_html_block.feature
 create mode 100644 html/tests/behat/course_block.feature
 create mode 100644 html/tests/behat/multiple_instances.feature
 create mode 100644 html/tests/privacy_provider_test.php
 create mode 100644 html/tests/search_content_test.php
 create mode 100644 html/version.php
 create mode 100644 index.html
 create mode 100644 login/block_login.php
 create mode 100644 login/classes/privacy/provider.php
 create mode 100644 login/db/access.php
 create mode 100644 login/lang/en/block_login.php
 create mode 100644 login/tests/behat/login_block.feature
 create mode 100644 login/version.php
 create mode 100644 lp/block_lp.php
 create mode 100644 lp/classes/output/competencies_to_review_page.php
 create mode 100644 lp/classes/output/plans_to_review_page.php
 create mode 100644 lp/classes/output/renderer.php
 create mode 100644 lp/classes/output/summary.php
 create mode 100644 lp/classes/privacy/provider.php
 create mode 100644 lp/competencies_to_review.php
 create mode 100644 lp/db/access.php
 create mode 100644 lp/lang/en/block_lp.php
 create mode 100644 lp/plans_to_review.php
 create mode 100644 lp/styles.css
 create mode 100644 lp/templates/competencies_to_review_page.mustache
 create mode 100644 lp/templates/plans_to_review_page.mustache
 create mode 100644 lp/templates/summary.mustache
 create mode 100644 lp/version.php
 create mode 160000 mahara_iena
 create mode 100644 mentees/block_mentees.php
 create mode 100644 mentees/classes/privacy/provider.php
 create mode 100644 mentees/db/access.php
 create mode 100644 mentees/edit_form.php
 create mode 100644 mentees/lang/en/block_mentees.php
 create mode 100644 mentees/tests/behat/configuring_mentees_block.feature
 create mode 100644 mentees/version.php
 create mode 100644 mnet_hosts/block_mnet_hosts.php
 create mode 100644 mnet_hosts/classes/privacy/provider.php
 create mode 100644 mnet_hosts/db/access.php
 create mode 100644 mnet_hosts/lang/en/block_mnet_hosts.php
 create mode 100644 mnet_hosts/version.php
 create mode 100644 moodleblock.class.php
 create mode 100644 myoverview/amd/build/calendar_events_repository.min.js
 create mode 100644 myoverview/amd/build/event_list.min.js
 create mode 100644 myoverview/amd/build/event_list_by_course.min.js
 create mode 100644 myoverview/amd/build/paging_bar.min.js
 create mode 100644 myoverview/amd/build/paging_content.min.js
 create mode 100644 myoverview/amd/build/tab_preferences.min.js
 create mode 100644 myoverview/amd/src/calendar_events_repository.js
 create mode 100644 myoverview/amd/src/event_list.js
 create mode 100644 myoverview/amd/src/event_list_by_course.js
 create mode 100644 myoverview/amd/src/paging_bar.js
 create mode 100644 myoverview/amd/src/paging_content.js
 create mode 100644 myoverview/amd/src/tab_preferences.js
 create mode 100644 myoverview/block_myoverview.php
 create mode 100644 myoverview/classes/output/courses_view.php
 create mode 100644 myoverview/classes/output/main.php
 create mode 100644 myoverview/classes/output/renderer.php
 create mode 100644 myoverview/classes/privacy/provider.php
 create mode 100644 myoverview/db/access.php
 create mode 100644 myoverview/lang/en/block_myoverview.php
 create mode 100644 myoverview/lib.php
 create mode 100644 myoverview/pix/activities.svg
 create mode 100644 myoverview/pix/courses.svg
 create mode 100644 myoverview/settings.php
 create mode 100644 myoverview/templates/course-event-list-item.mustache
 create mode 100644 myoverview/templates/course-event-list-items.mustache
 create mode 100644 myoverview/templates/course-event-list.mustache
 create mode 100644 myoverview/templates/course-item.mustache
 create mode 100644 myoverview/templates/course-paging-content-item.mustache
 create mode 100644 myoverview/templates/course-paging-content.mustache
 create mode 100644 myoverview/templates/course-summary.mustache
 create mode 100644 myoverview/templates/courses-view-by-status.mustache
 create mode 100644 myoverview/templates/courses-view-course-item.mustache
 create mode 100644 myoverview/templates/courses-view.mustache
 create mode 100644 myoverview/templates/event-list-group.mustache
 create mode 100644 myoverview/templates/event-list-item.mustache
 create mode 100644 myoverview/templates/event-list-items.mustache
 create mode 100644 myoverview/templates/event-list.mustache
 create mode 100644 myoverview/templates/main.mustache
 create mode 100644 myoverview/templates/paging-bar-item.mustache
 create mode 100644 myoverview/templates/paging-bar.mustache
 create mode 100644 myoverview/templates/paging-content-item.mustache
 create mode 100644 myoverview/templates/paging-content.mustache
 create mode 100644 myoverview/templates/progress-chart.mustache
 create mode 100644 myoverview/templates/timeline-view-courses.mustache
 create mode 100644 myoverview/templates/timeline-view-dates.mustache
 create mode 100644 myoverview/templates/timeline-view.mustache
 create mode 100644 myoverview/tests/behat/block_myoverview_dashboard.feature
 create mode 100644 myoverview/tests/behat/block_myoverview_progress.feature
 create mode 100644 myoverview/tests/privacy_test.php
 create mode 100644 myoverview/version.php
 create mode 100644 myprofile/block_myprofile.php
 create mode 100644 myprofile/classes/privacy/provider.php
 create mode 100644 myprofile/db/access.php
 create mode 100644 myprofile/edit_form.php
 create mode 100644 myprofile/lang/en/block_myprofile.php
 create mode 100644 myprofile/lang/en/deprecated.txt
 create mode 100644 myprofile/styles.css
 create mode 100644 myprofile/tests/behat/block_myprofile.feature
 create mode 100644 myprofile/tests/behat/block_myprofile_activity.feature
 create mode 100644 myprofile/tests/behat/block_myprofile_course.feature
 create mode 100644 myprofile/tests/behat/block_myprofile_dashboard.feature
 create mode 100644 myprofile/tests/behat/block_myprofile_frontpage.feature
 create mode 100644 myprofile/version.php
 create mode 100644 navigation/amd/build/ajax_response_renderer.min.js
 create mode 100644 navigation/amd/build/nav_loader.min.js
 create mode 100644 navigation/amd/build/navblock.min.js
 create mode 100644 navigation/amd/build/site_admin_loader.min.js
 create mode 100644 navigation/amd/src/ajax_response_renderer.js
 create mode 100644 navigation/amd/src/nav_loader.js
 create mode 100644 navigation/amd/src/navblock.js
 create mode 100644 navigation/amd/src/site_admin_loader.js
 create mode 100644 navigation/block_navigation.php
 create mode 100644 navigation/classes/privacy/provider.php
 create mode 100644 navigation/db/access.php
 create mode 100644 navigation/db/upgrade.php
 create mode 100644 navigation/edit_form.php
 create mode 100644 navigation/lang/en/block_navigation.php
 create mode 100644 navigation/renderer.php
 create mode 100644 navigation/styles.css
 create mode 100644 navigation/tests/behat/expand_courses_node.feature
 create mode 100644 navigation/tests/behat/participants_link.feature
 create mode 100644 navigation/tests/behat/view_my_courses.feature
 create mode 100644 navigation/version.php
 create mode 100644 news_items/block_news_items.php
 create mode 100644 news_items/classes/privacy/provider.php
 create mode 100644 news_items/db/access.php
 create mode 100644 news_items/lang/en/block_news_items.php
 create mode 100644 news_items/tests/behat/display_news.feature
 create mode 100644 news_items/version.php
 create mode 100644 online_users/block_online_users.php
 create mode 100644 online_users/classes/fetcher.php
 create mode 100644 online_users/classes/privacy/provider.php
 create mode 100644 online_users/db/access.php
 create mode 100644 online_users/lang/en/block_online_users.php
 create mode 100644 online_users/settings.php
 create mode 100644 online_users/styles.css
 create mode 100644 online_users/tests/behat/block_online_users_course.feature
 create mode 100644 online_users/tests/behat/block_online_users_dashboard.feature
 create mode 100644 online_users/tests/behat/block_online_users_frontpage.feature
 create mode 100644 online_users/tests/generator/lib.php
 create mode 100644 online_users/tests/generator_test.php
 create mode 100644 online_users/tests/online_users_test.php
 create mode 100644 online_users/version.php
 create mode 100644 participants/block_participants.php
 create mode 100644 participants/classes/privacy/provider.php
 create mode 100644 participants/db/access.php
 create mode 100644 participants/lang/en/block_participants.php
 create mode 100644 participants/tests/behat/block_participants_course.feature
 create mode 100644 participants/tests/behat/block_participants_frontpage.feature
 create mode 100644 participants/version.php
 create mode 100644 private_files/block_private_files.php
 create mode 100644 private_files/classes/privacy/provider.php
 create mode 100644 private_files/db/access.php
 create mode 100644 private_files/edit.php
 create mode 100644 private_files/lang/en/block_private_files.php
 create mode 100644 private_files/module.js
 create mode 100644 private_files/renderer.php
 create mode 100644 private_files/styles.css
 create mode 100644 private_files/tests/behat/block_private_files_activity.feature
 create mode 100644 private_files/tests/behat/block_private_files_course.feature
 create mode 100644 private_files/tests/behat/block_private_files_dashboard.feature
 create mode 100644 private_files/tests/behat/block_private_files_frontpage.feature
 create mode 100644 private_files/tests/fixtures/testfile.txt
 create mode 100644 private_files/version.php
 create mode 100644 quiz_results/backup/moodle2/restore_quiz_results_block_task.class.php
 create mode 100644 quiz_results/block_quiz_results.php
 create mode 100644 quiz_results/classes/privacy/provider.php
 create mode 100644 quiz_results/db/access.php
 create mode 100644 quiz_results/db/install.php
 create mode 100644 quiz_results/db/upgrade.php
 create mode 100644 quiz_results/lang/en/block_quiz_results.php
 create mode 100644 quiz_results/lang/en/depreciated.txt
 create mode 100644 quiz_results/version.php
 create mode 100644 recent_activity/block_recent_activity.php
 create mode 100644 recent_activity/classes/observer.php
 create mode 100644 recent_activity/classes/privacy/provider.php
 create mode 100644 recent_activity/db/access.php
 create mode 100644 recent_activity/db/events.php
 create mode 100644 recent_activity/db/install.xml
 create mode 100644 recent_activity/db/upgrade.php
 create mode 100644 recent_activity/lang/en/block_recent_activity.php
 create mode 100644 recent_activity/renderer.php
 create mode 100644 recent_activity/styles.css
 create mode 100644 recent_activity/tests/behat/structural_changes.feature
 create mode 100644 recent_activity/version.php
 create mode 100644 rss_client/backup/moodle1/lib.php
 create mode 100644 rss_client/backup/moodle2/backup_rss_client_block_task.class.php
 create mode 100644 rss_client/backup/moodle2/backup_rss_client_stepslib.php
 create mode 100644 rss_client/backup/moodle2/restore_rss_client_block_task.class.php
 create mode 100644 rss_client/backup/moodle2/restore_rss_client_stepslib.php
 create mode 100644 rss_client/block_rss_client.php
 create mode 100644 rss_client/classes/output/block.php
 create mode 100644 rss_client/classes/output/channel_image.php
 create mode 100644 rss_client/classes/output/feed.php
 create mode 100644 rss_client/classes/output/footer.php
 create mode 100644 rss_client/classes/output/item.php
 create mode 100644 rss_client/classes/output/renderer.php
 create mode 100644 rss_client/classes/privacy/provider.php
 create mode 100644 rss_client/db/access.php
 create mode 100644 rss_client/db/install.xml
 create mode 100644 rss_client/db/upgrade.php
 create mode 100644 rss_client/edit_form.php
 create mode 100644 rss_client/editfeed.php
 create mode 100644 rss_client/lang/en/block_rss_client.php
 create mode 100644 rss_client/managefeeds.php
 create mode 100644 rss_client/settings.php
 create mode 100644 rss_client/styles.css
 create mode 100644 rss_client/templates/block.mustache
 create mode 100644 rss_client/templates/channel_image.mustache
 create mode 100644 rss_client/templates/feed.mustache
 create mode 100644 rss_client/templates/footer.mustache
 create mode 100644 rss_client/templates/item.mustache
 create mode 100644 rss_client/tests/cron_test.php
 create mode 100644 rss_client/tests/privacy_test.php
 create mode 100644 rss_client/version.php
 create mode 100644 rss_client/viewfeed.php
 create mode 100644 search_forums/block_search_forums.php
 create mode 100644 search_forums/classes/output/renderer.php
 create mode 100644 search_forums/classes/output/search_form.php
 create mode 100644 search_forums/classes/privacy/provider.php
 create mode 100644 search_forums/db/access.php
 create mode 100644 search_forums/lang/en/block_search_forums.php
 create mode 100644 search_forums/styles.css
 create mode 100644 search_forums/templates/search_form.mustache
 create mode 100644 search_forums/tests/behat/block_search_forums_course.feature
 create mode 100644 search_forums/tests/behat/block_search_forums_frontpage.feature
 create mode 100644 search_forums/version.php
 create mode 100644 section_links/block_section_links.php
 create mode 100644 section_links/classes/privacy/provider.php
 create mode 100644 section_links/db/access.php
 create mode 100644 section_links/db/upgrade.php
 create mode 100644 section_links/edit_form.php
 create mode 100644 section_links/lang/en/block_section_links.php
 create mode 100644 section_links/renderer.php
 create mode 100644 section_links/settings.php
 create mode 100644 section_links/tests/behat/block_section_links_course.feature
 create mode 100644 section_links/version.php
 create mode 100644 selfcompletion/block_selfcompletion.php
 create mode 100644 selfcompletion/classes/privacy/provider.php
 create mode 100644 selfcompletion/db/access.php
 create mode 100644 selfcompletion/db/upgrade.php
 create mode 100644 selfcompletion/lang/en/block_selfcompletion.php
 create mode 100644 selfcompletion/version.php
 create mode 100644 settings/amd/build/settingsblock.min.js
 create mode 100644 settings/amd/src/settingsblock.js
 create mode 100644 settings/block_settings.php
 create mode 100644 settings/classes/privacy/provider.php
 create mode 100644 settings/db/access.php
 create mode 100644 settings/db/upgrade.php
 create mode 100644 settings/edit_form.php
 create mode 100644 settings/lang/en/block_settings.php
 create mode 100644 settings/renderer.php
 create mode 100644 settings/styles.css
 create mode 100644 settings/version.php
 create mode 100644 site_main_menu/block_site_main_menu.php
 create mode 100644 site_main_menu/classes/privacy/provider.php
 create mode 100644 site_main_menu/db/access.php
 create mode 100644 site_main_menu/lang/en/block_site_main_menu.php
 create mode 100644 site_main_menu/styles.css
 create mode 100644 site_main_menu/tests/behat/add_url.feature
 create mode 100644 site_main_menu/tests/behat/behat_block_site_main_menu.php
 create mode 100644 site_main_menu/tests/behat/edit_activities.feature
 create mode 100644 site_main_menu/version.php
 create mode 100644 social_activities/block_social_activities.php
 create mode 100644 social_activities/classes/privacy/provider.php
 create mode 100644 social_activities/db/access.php
 create mode 100644 social_activities/lang/en/block_social_activities.php
 create mode 100644 social_activities/styles.css
 create mode 100644 social_activities/tests/behat/behat_block_social_activities.php
 create mode 100644 social_activities/tests/behat/edit_activities.feature
 create mode 100644 social_activities/version.php
 create mode 100644 tag_flickr/block_tag_flickr.php
 create mode 100644 tag_flickr/classes/privacy/provider.php
 create mode 100644 tag_flickr/db/access.php
 create mode 100644 tag_flickr/edit_form.php
 create mode 100644 tag_flickr/lang/en/block_tag_flickr.php
 create mode 100644 tag_flickr/styles.css
 create mode 100644 tag_flickr/tests/behat/configuring_tag_flickr_block.feature
 create mode 100644 tag_flickr/version.php
 create mode 100644 tag_youtube/block_tag_youtube.php
 create mode 100644 tag_youtube/classes/privacy/provider.php
 create mode 100644 tag_youtube/db/access.php
 create mode 100644 tag_youtube/db/install.php
 create mode 100644 tag_youtube/edit_form.php
 create mode 100644 tag_youtube/lang/en/block_tag_youtube.php
 create mode 100644 tag_youtube/settings.php
 create mode 100644 tag_youtube/styles.css
 create mode 100644 tag_youtube/tests/block_tag_youtube_test.php
 create mode 100644 tag_youtube/upgrade.txt
 create mode 100644 tag_youtube/version.php
 create mode 100644 tags/backup/moodle2/restore_tags_block_task.class.php
 create mode 100644 tags/block_tags.php
 create mode 100644 tags/classes/privacy/provider.php
 create mode 100644 tags/db/access.php
 create mode 100644 tags/edit_form.php
 create mode 100644 tags/lang/en/block_tags.php
 create mode 100644 tags/tests/behat/tagcloud.feature
 create mode 100644 tags/version.php
 create mode 100644 tests/behat/add_blocks.feature
 create mode 100644 tests/behat/behat_blocks.php
 create mode 100644 tests/behat/configure_block_throughout_site.feature
 create mode 100644 tests/behat/hidden_block_region.feature
 create mode 100644 tests/behat/hide_blocks.feature
 create mode 100644 tests/behat/manage_blocks.feature
 create mode 100644 tests/behat/move_blocks.feature
 create mode 100644 tests/behat/restrict_available_blocks.feature
 create mode 100644 tests/behat/return_block_original_state.feature
 create mode 100644 tests/externallib_test.php
 create mode 100644 tests/privacy_test.php
 create mode 100644 upgrade 14.04.12.txt

diff --git a/activity_modules/block_activity_modules.php b/activity_modules/block_activity_modules.php
new file mode 100644
index 0000000..af67de2
--- /dev/null
+++ b/activity_modules/block_activity_modules.php
@@ -0,0 +1,106 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file contains the Activity modules block.
+ *
+ * @package    block_activity_modules
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+require_once($CFG->libdir . '/filelib.php');
+
+class block_activity_modules extends block_list {
+    function init() {
+        $this->title = get_string('pluginname', 'block_activity_modules');
+    }
+
+    function get_content() {
+        global $CFG, $DB, $OUTPUT;
+
+        if($this->content !== NULL) {
+            return $this->content;
+        }
+
+        $this->content = new stdClass;
+        $this->content->items = array();
+        $this->content->icons = array();
+        $this->content->footer = '';
+
+        $course = $this->page->course;
+
+        require_once($CFG->dirroot.'/course/lib.php');
+
+        $modinfo = get_fast_modinfo($course);
+        $modfullnames = array();
+
+        $archetypes = array();
+
+        foreach($modinfo->cms as $cm) {
+            // Exclude activities which are not visible or have no link (=label)
+            if (!$cm->uservisible or !$cm->has_view()) {
+                continue;
+            }
+            if (array_key_exists($cm->modname, $modfullnames)) {
+                continue;
+            }
+            if (!array_key_exists($cm->modname, $archetypes)) {
+                $archetypes[$cm->modname] = plugin_supports('mod', $cm->modname, FEATURE_MOD_ARCHETYPE, MOD_ARCHETYPE_OTHER);
+            }
+            if ($archetypes[$cm->modname] == MOD_ARCHETYPE_RESOURCE) {
+                if (!array_key_exists('resources', $modfullnames)) {
+                    $modfullnames['resources'] = get_string('resources');
+                }
+            } else {
+                $modfullnames[$cm->modname] = $cm->modplural;
+            }
+        }
+
+        core_collator::asort($modfullnames);
+
+        foreach ($modfullnames as $modname => $modfullname) {
+            if ($modname === 'resources') {
+                $icon = $OUTPUT->pix_icon('icon', '', 'mod_page', array('class' => 'icon'));
+                $this->content->items[] = '<a href="'.$CFG->wwwroot.'/course/resources.php?id='.$course->id.'">'.$icon.$modfullname.'</a>';
+            } else {
+                $icon = $OUTPUT->image_icon('icon', get_string('pluginname', $modname), $modname);
+                $this->content->items[] = '<a href="'.$CFG->wwwroot.'/mod/'.$modname.'/index.php?id='.$course->id.'">'.$icon.$modfullname.'</a>';
+            }
+        }
+
+        return $this->content;
+    }
+
+    /**
+     * Returns the role that best describes this blocks contents.
+     *
+     * This returns 'navigation' as the blocks contents is a list of links to activities and resources.
+     *
+     * @return string 'navigation'
+     */
+    public function get_aria_role() {
+        return 'navigation';
+    }
+
+    function applicable_formats() {
+        return array('all' => true, 'mod' => false, 'my' => false, 'admin' => false,
+                     'tag' => false);
+    }
+}
+
+
diff --git a/activity_modules/classes/privacy/provider.php b/activity_modules/classes/privacy/provider.php
new file mode 100644
index 0000000..7f8b315
--- /dev/null
+++ b/activity_modules/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_activity_modules.
+ *
+ * @package    block_activity_modules
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_activity_modules\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_activity_modules implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/activity_modules/db/access.php b/activity_modules/db/access.php
new file mode 100644
index 0000000..b8b982f
--- /dev/null
+++ b/activity_modules/db/access.php
@@ -0,0 +1,41 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Activity modules block caps.
+ *
+ * @package    block_activity_modules
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/activity_modules:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/activity_modules/lang/en/block_activity_modules.php b/activity_modules/lang/en/block_activity_modules.php
new file mode 100644
index 0000000..1bb9de5
--- /dev/null
+++ b/activity_modules/lang/en/block_activity_modules.php
@@ -0,0 +1,27 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_activity_modules', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_activity_modules
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['activity_modules:addinstance'] = 'Add a new activities block';
+$string['pluginname'] = 'Activities';
+$string['privacy:metadata'] = 'The Activities block only shows data stored in other locations.';
diff --git a/activity_modules/tests/behat/block_activity_modules.feature b/activity_modules/tests/behat/block_activity_modules.feature
new file mode 100644
index 0000000..63e6dba
--- /dev/null
+++ b/activity_modules/tests/behat/block_activity_modules.feature
@@ -0,0 +1,159 @@
+@block @block_activity_modules
+Feature: Block activity modules
+  In order to overview activity modules in a course
+  As a manager
+  I can add activities block in a course or on the frontpage
+
+  Scenario: Add activities block on the frontpage
+    Given the following "activities" exist:
+      | activity   | name                        | intro                              | course               | idnumber    |
+      | assign     | Frontpage assignment name   | Frontpage assignment description   | Acceptance test site | assign0     |
+      | book       | Frontpage book name         | Frontpage book description         | Acceptance test site | book0       |
+      | chat       | Frontpage chat name         | Frontpage chat description         | Acceptance test site | chat0       |
+      | choice     | Frontpage choice name       | Frontpage choice description       | Acceptance test site | choice0     |
+      | data       | Frontpage database name     | Frontpage database description     | Acceptance test site | data0       |
+      | feedback   | Frontpage feedback name     | Frontpage feedback description     | Acceptance test site | feedback0   |
+      | forum      | Frontpage forum name        | Frontpage forum description        | Acceptance test site | forum0      |
+      | label      | Frontpage label name        | Frontpage label description        | Acceptance test site | label0      |
+      | lti        | Frontpage lti name          | Frontpage lti description          | Acceptance test site | lti0        |
+      | page       | Frontpage page name         | Frontpage page description         | Acceptance test site | page0       |
+      | quiz       | Frontpage quiz name         | Frontpage quiz description         | Acceptance test site | quiz0       |
+      | resource   | Frontpage resource name     | Frontpage resource description     | Acceptance test site | resource0   |
+      | imscp      | Frontpage imscp name        | Frontpage imscp description        | Acceptance test site | imscp0      |
+      | folder     | Frontpage folder name       | Frontpage folder description       | Acceptance test site | folder0     |
+      | glossary   | Frontpage glossary name     | Frontpage glossary description     | Acceptance test site | glossary0   |
+      | scorm      | Frontpage scorm name        | Frontpage scorm description        | Acceptance test site | scorm0      |
+      | lesson     | Frontpage lesson name       | Frontpage lesson description       | Acceptance test site | lesson0     |
+      | survey     | Frontpage survey name       | Frontpage survey description       | Acceptance test site | survey0     |
+      | url        | Frontpage url name          | Frontpage url description          | Acceptance test site | url0        |
+      | wiki       | Frontpage wiki name         | Frontpage wiki description         | Acceptance test site | wiki0       |
+      | workshop   | Frontpage workshop name     | Frontpage workshop description     | Acceptance test site | workshop0   |
+
+    When I log in as "admin"
+    And I am on site homepage
+    And I follow "Turn editing on"
+    And I add the "Activities" block
+    And I click on "Assignments" "link" in the "Activities" "block"
+    Then I should see "Frontpage assignment name"
+    And I am on site homepage
+    And I click on "Chats" "link" in the "Activities" "block"
+    And I should see "Frontpage chat name"
+    And I am on site homepage
+    And I click on "Choices" "link" in the "Activities" "block"
+    And I should see "Frontpage choice name"
+    And I am on site homepage
+    And I click on "Databases" "link" in the "Activities" "block"
+    And I should see "Frontpage database name"
+    And I am on site homepage
+    And I click on "Feedback" "link" in the "Activities" "block"
+    And I should see "Frontpage feedback name"
+    And I am on site homepage
+    And I click on "Forums" "link" in the "Activities" "block"
+    And I should see "Frontpage forum name"
+    And I am on site homepage
+    And I click on "External tools" "link" in the "Activities" "block"
+    And I should see "Frontpage lti name"
+    And I am on site homepage
+    And I click on "Quizzes" "link" in the "Activities" "block"
+    And I should see "Frontpage quiz name"
+    And I am on site homepage
+    And I click on "Glossaries" "link" in the "Activities" "block"
+    And I should see "Frontpage glossary name"
+    And I am on site homepage
+    And I click on "SCORM packages" "link" in the "Activities" "block"
+    And I should see "Frontpage scorm name"
+    And I am on site homepage
+    And I click on "Lessons" "link" in the "Activities" "block"
+    And I should see "Frontpage lesson name"
+    And I am on site homepage
+    And I click on "Wikis" "link" in the "Activities" "block"
+    And I should see "Frontpage wiki name"
+    And I am on site homepage
+    And I click on "Workshop" "link" in the "Activities" "block"
+    And I should see "Frontpage workshop name"
+    And I am on site homepage
+    And I click on "Resources" "link" in the "Activities" "block"
+    And I should see "Frontpage book name"
+    And I should see "Frontpage page name"
+    And I should see "Frontpage resource name"
+    And I should see "Frontpage imscp name"
+    And I should see "Frontpage folder name"
+    And I should see "Frontpage url name"
+
+  Scenario: Add activities block in a course
+    Given the following "courses" exist:
+      | fullname | shortname | format |
+      | Course 1 | C1        | topics |
+    And the following "activities" exist:
+      | activity   | name                   | intro                         | course | idnumber    |
+      | assign     | Test assignment name   | Test assignment description   | C1     | assign1     |
+      | book       | Test book name         | Test book description         | C1     | book1       |
+      | chat       | Test chat name         | Test chat description         | C1     | chat1       |
+      | choice     | Test choice name       | Test choice description       | C1     | choice1     |
+      | data       | Test database name     | Test database description     | C1     | data1       |
+      | feedback   | Test feedback name     | Test feedback description     | C1     | feedback1   |
+      | folder     | Test folder name       | Test folder description       | C1     | folder1     |
+      | forum      | Test forum name        | Test forum description        | C1     | forum1      |
+      | glossary   | Test glossary name     | Test glossary description     | C1     | glossary1   |
+      | imscp      | Test imscp name        | Test imscp description        | C1     | imscp1      |
+      | label      | Test label name        | Test label description        | C1     | label1      |
+      | lesson     | Test lesson name       | Test lesson description       | C1     | lesson1     |
+      | lti        | Test lti name          | Test lti description          | C1     | lti1        |
+      | page       | Test page name         | Test page description         | C1     | page1       |
+      | quiz       | Test quiz name         | Test quiz description         | C1     | quiz1       |
+      | resource   | Test resource name     | Test resource description     | C1     | resource1   |
+      | scorm      | Test scorm name        | Test scorm description        | C1     | scorm1      |
+      | survey     | Test survey name       | Test survey description       | C1     | survey1     |
+      | url        | Test url name          | Test url description          | C1     | url1        |
+      | wiki       | Test wiki name         | Test wiki description         | C1     | wiki1       |
+      | workshop   | Test workshop name     | Test workshop description     | C1     | workshop1   |
+
+    When I log in as "admin"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Activities" block
+    And I click on "Assignments" "link" in the "Activities" "block"
+    Then I should see "Test assignment name"
+    And I am on "Course 1" course homepage
+    And I click on "Chats" "link" in the "Activities" "block"
+    And I should see "Test chat name"
+    And I am on "Course 1" course homepage
+    And I click on "Choices" "link" in the "Activities" "block"
+    And I should see "Test choice name"
+    And I am on "Course 1" course homepage
+    And I click on "Databases" "link" in the "Activities" "block"
+    And I should see "Test database name"
+    And I am on "Course 1" course homepage
+    And I click on "Feedback" "link" in the "Activities" "block"
+    And I should see "Test feedback name"
+    And I am on "Course 1" course homepage
+    And I click on "Forums" "link" in the "Activities" "block"
+    And I should see "Test forum name"
+    And I am on "Course 1" course homepage
+    And I click on "External tools" "link" in the "Activities" "block"
+    And I should see "Test lti name"
+    And I am on "Course 1" course homepage
+    And I click on "Quizzes" "link" in the "Activities" "block"
+    And I should see "Test quiz name"
+    And I am on "Course 1" course homepage
+    And I click on "Glossaries" "link" in the "Activities" "block"
+    And I should see "Test glossary name"
+    And I am on "Course 1" course homepage
+    And I click on "SCORM packages" "link" in the "Activities" "block"
+    And I should see "Test scorm name"
+    And I am on "Course 1" course homepage
+    And I click on "Lessons" "link" in the "Activities" "block"
+    And I should see "Test lesson name"
+    And I am on "Course 1" course homepage
+    And I click on "Wikis" "link" in the "Activities" "block"
+    And I should see "Test wiki name"
+    And I am on "Course 1" course homepage
+    And I click on "Workshop" "link" in the "Activities" "block"
+    And I should see "Test workshop name"
+    And I am on "Course 1" course homepage
+    And I click on "Resources" "link" in the "Activities" "block"
+    And I should see "Test book name"
+    And I should see "Test page name"
+    And I should see "Test resource name"
+    And I should see "Test imscp name"
+    And I should see "Test folder name"
+    And I should see "Test url name"
diff --git a/activity_modules/version.php b/activity_modules/version.php
new file mode 100644
index 0000000..2edb45f
--- /dev/null
+++ b/activity_modules/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_activity_modules
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_activity_modules'; // Full name of the plugin (used for diagnostics)
diff --git a/activity_results/backup/moodle2/restore_activity_results_block_task.class.php b/activity_results/backup/moodle2/restore_activity_results_block_task.class.php
new file mode 100644
index 0000000..42be292
--- /dev/null
+++ b/activity_results/backup/moodle2/restore_activity_results_block_task.class.php
@@ -0,0 +1,115 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Define all the backup steps that will be used by the backup_block_task
+ * @package    block_activity_results
+ * @copyright  2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
+ * @copyright  2015 Stephen Bourget
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Specialised restore task for the activity_results block
+ * (using execute_after_tasks for recoding of target activity)
+ *
+ * @copyright  2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class restore_activity_results_block_task extends restore_block_task {
+
+    /**
+     * Define (add) particular settings this activity can have
+     */
+    protected function define_my_settings() {
+    }
+
+    /**
+     * Define (add) particular steps this activity can have
+     */
+    protected function define_my_steps() {
+    }
+
+    /**
+     * Define the associated file areas
+     */
+    public function get_fileareas() {
+        return array(); // No associated fileareas.
+    }
+
+    /**
+     * Define special handling of configdata.
+     */
+    public function get_configdata_encoded_attributes() {
+        return array(); // No special handling of configdata.
+    }
+
+    /**
+     * This function, executed after all the tasks in the plan
+     * have been executed, will perform the recode of the
+     * target activity for the block. This must be done here
+     * and not in normal execution steps because the activity
+     * can be restored after the block.
+     */
+    public function after_restore() {
+        global $DB;
+
+        // Get the blockid.
+        $blockid = $this->get_blockid();
+
+        if ($configdata = $DB->get_field('block_instances', 'configdata', array('id' => $blockid))) {
+            $config = unserialize(base64_decode($configdata));
+            if (!empty($config->activityparentid)) {
+                // Get the mapping and replace it in config.
+                if ($mapping = restore_dbops::get_backup_ids_record($this->get_restoreid(),
+                    $config->activityparent, $config->activityparentid)) {
+
+                    // Update the parent module id (the id from mdl_quiz etc...)
+                    $config->activityparentid = $mapping->newitemid;
+
+                    // Get the grade_items record to update the activitygradeitemid.
+                    $info = $DB->get_record('grade_items',
+                            array('iteminstance' => $config->activityparentid, 'itemmodule' => $config->activityparent));
+
+                    // Update the activitygradeitemid the id from the grade_items table.
+                    $config->activitygradeitemid = $info->id;
+
+                    // Encode and save the config.
+                    $configdata = base64_encode(serialize($config));
+                    $DB->set_field('block_instances', 'configdata', $configdata, array('id' => $blockid));
+                }
+            }
+        }
+    }
+
+    /**
+     * Define the contents in the activity that must be
+     * processed by the link decoder
+     */
+    static public function define_decode_contents() {
+        return array();
+    }
+
+    /**
+     * Define the decoding rules for links belonging
+     * to the activity to be executed by the link decoder
+     */
+    static public function define_decode_rules() {
+        return array();
+    }
+}
diff --git a/activity_results/block_activity_results.php b/activity_results/block_activity_results.php
new file mode 100644
index 0000000..2890415
--- /dev/null
+++ b/activity_results/block_activity_results.php
@@ -0,0 +1,707 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Classes to enforce the various access rules that can apply to a activity.
+ *
+ * @package    block_activity_results
+ * @copyright  2009 Tim Hunt
+ * @copyright  2015 Stephen Bourget
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once($CFG->dirroot . '/lib/grade/constants.php');
+require_once($CFG->dirroot . '/course/lib.php');
+
+define('B_ACTIVITYRESULTS_NAME_FORMAT_FULL', 1);
+define('B_ACTIVITYRESULTS_NAME_FORMAT_ID',   2);
+define('B_ACTIVITYRESULTS_NAME_FORMAT_ANON', 3);
+define('B_ACTIVITYRESULTS_GRADE_FORMAT_PCT', 1);
+define('B_ACTIVITYRESULTS_GRADE_FORMAT_FRA', 2);
+define('B_ACTIVITYRESULTS_GRADE_FORMAT_ABS', 3);
+define('B_ACTIVITYRESULTS_GRADE_FORMAT_SCALE', 4);
+
+/**
+ * Block activity_results class definition.
+ *
+ * This block can be added to a course page or a activity page to display of list of
+ * the best/worst students/groups in a particular activity.
+ *
+ * @package    block_activity_results
+ * @copyright  2009 Tim Hunt
+ * @copyright  2015 Stephen Bourget
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_activity_results extends block_base {
+
+    /**
+     * Core function used to initialize the block.
+     */
+    public function init() {
+        $this->title = get_string('pluginname', 'block_activity_results');
+    }
+
+    /**
+     * Allow the block to have a configuration page
+     *
+     * @return boolean
+     */
+    public function has_config() {
+        return true;
+    }
+
+    /**
+     * Core function, specifies where the block can be used.
+     * @return array
+     */
+    public function applicable_formats() {
+        return array('course-view' => true, 'mod' => true);
+    }
+
+    /**
+     * If this block belongs to a activity context, then return that activity's id.
+     * Otherwise, return 0.
+     * @return stdclass the activity record.
+     */
+    public function get_owning_activity() {
+        global $DB;
+
+        // Set some defaults.
+        $result = new stdClass();
+        $result->id = 0;
+
+        if (empty($this->instance->parentcontextid)) {
+            return $result;
+        }
+        $parentcontext = context::instance_by_id($this->instance->parentcontextid);
+        if ($parentcontext->contextlevel != CONTEXT_MODULE) {
+            return $result;
+        }
+        $cm = get_coursemodule_from_id($this->page->cm->modname, $parentcontext->instanceid);
+        if (!$cm) {
+            return $result;
+        }
+        // Get the grade_items id.
+        $rec = $DB->get_record('grade_items', array('iteminstance' => $cm->instance, 'itemmodule' => $this->page->cm->modname));
+        if (!$rec) {
+            return $result;
+        }
+        // See if it is a gradable activity.
+        if (($rec->gradetype != GRADE_TYPE_VALUE) && ($rec->gradetype != GRADE_TYPE_SCALE)) {
+            return $result;
+        }
+        return $rec;
+    }
+
+    /**
+     * Used to save the form config data
+     * @param stdclass $data
+     * @param bool $nolongerused
+     */
+    public function instance_config_save($data, $nolongerused = false) {
+        global $DB;
+        if (empty($data->activitygradeitemid)) {
+            // Figure out info about parent module.
+            $info = $this->get_owning_activity();
+            $data->activitygradeitemid = $info->id;
+            if ($info->id < 1) {
+                // No activity was selected.
+                $info->itemmodule = '';
+                $info->iteminstance = '';
+            } else {
+                $data->activityparent = $info->itemmodule;
+                $data->activityparentid = $info->iteminstance;
+            }
+        } else {
+            // Lookup info about the parent module (we have the id from mdl_grade_items.
+            $info = $DB->get_record('grade_items', array('id' => $data->activitygradeitemid));
+            $data->activityparent = $info->itemmodule;
+            $data->activityparentid = $info->iteminstance;
+        }
+        parent::instance_config_save($data);
+    }
+
+    /**
+     * Used to generate the content for the block.
+     * @return string
+     */
+    public function get_content() {
+        global $USER, $CFG, $DB;
+
+        if ($this->content !== null) {
+            return $this->content;
+        }
+
+        $this->content = new stdClass;
+        $this->content->text = '';
+        $this->content->footer = '';
+
+        if (empty($this->instance)) {
+            return $this->content;
+        }
+
+        // We are configured so use the configuration.
+        if (!empty($this->config->activitygradeitemid)) {
+            // We are configured.
+            $activitygradeitemid = $this->config->activitygradeitemid;
+
+            // Lookup the module in the grade_items table.
+            $activity = $DB->get_record('grade_items', array('id' => $activitygradeitemid));
+            if (empty($activity)) {
+                // Activity does not exist.
+                $this->content->text = get_string('error_emptyactivityrecord', 'block_activity_results');
+                return $this->content;
+            }
+            $courseid = $activity->courseid;
+            $inactivity = false;
+        } else {
+            // Not configured.
+            $activitygradeitemid = 0;
+        }
+
+        // Check to see if we are in the moule we are displaying results for.
+        if (!empty($this->config->activitygradeitemid)) {
+            if ($this->get_owning_activity()->id == $this->config->activitygradeitemid) {
+                $inactivity = true;
+            } else {
+                $inactivity = false;
+            }
+        }
+
+        // Activity ID is missing.
+        if (empty($activitygradeitemid)) {
+            $this->content->text = get_string('error_emptyactivityid', 'block_activity_results');
+            return $this->content;
+        }
+
+        // Check to see if we are configured.
+        if (empty($this->config->showbest) && empty($this->config->showworst)) {
+            $this->content->text = get_string('configuredtoshownothing', 'block_activity_results');
+            return $this->content;
+        }
+
+        // Check to see if it is a supported grade type.
+        if (empty($activity->gradetype) || ($activity->gradetype != GRADE_TYPE_VALUE && $activity->gradetype != GRADE_TYPE_SCALE)) {
+            $this->content->text = get_string('error_unsupportedgradetype', 'block_activity_results');
+            return $this->content;
+        }
+
+        // Get the grades for this activity.
+        $sql = 'SELECT * FROM {grade_grades}
+                 WHERE itemid = ? AND finalgrade is not NULL
+                 ORDER BY finalgrade, timemodified DESC';
+
+        $grades = $DB->get_records_sql($sql, array( $activitygradeitemid));
+
+        if (empty($grades) || $activity->hidden) {
+            // No grades available, The block will hide itself in this case.
+            return $this->content;
+        }
+
+        // Set up results.
+        $groupmode = NOGROUPS;
+        $best      = array();
+        $worst     = array();
+
+        if (!empty($this->config->nameformat)) {
+            $nameformat = $this->config->nameformat;
+        } else {
+            $nameformat = B_ACTIVITYRESULTS_NAME_FORMAT_FULL;
+        }
+
+        // Get $cm and context.
+        if ($inactivity) {
+            $cm = $this->page->cm;
+            $context = $this->page->context;
+        } else {
+            $cm = get_coursemodule_from_instance($activity->itemmodule, $activity->iteminstance, $courseid);
+            $context = context_module::instance($cm->id);
+        }
+
+        if (!empty($this->config->usegroups)) {
+            $groupmode = groups_get_activity_groupmode($cm);
+
+            if ($groupmode == SEPARATEGROUPS && has_capability('moodle/site:accessallgroups', $context)) {
+                // If you have the ability to see all groups then lets show them.
+                $groupmode = VISIBLEGROUPS;
+            }
+        }
+
+        switch ($groupmode) {
+            case VISIBLEGROUPS:
+                // Display group-mode results.
+                $groups = groups_get_all_groups($courseid);
+
+                if (empty($groups)) {
+                    // No groups exist, sorry.
+                    $this->content->text = get_string('error_nogroupsexist', 'block_activity_results');
+                    return $this->content;
+                }
+
+                // Find out all the userids which have a submitted grade.
+                $userids = array();
+                $gradeforuser = array();
+                foreach ($grades as $grade) {
+                    $userids[] = $grade->userid;
+                    $gradeforuser[$grade->userid] = (float)$grade->finalgrade;
+                }
+
+                // Now find which groups these users belong in.
+                list($usertest, $params) = $DB->get_in_or_equal($userids);
+                $params[] = $courseid;
+                $usergroups = $DB->get_records_sql('
+                        SELECT gm.id, gm.userid, gm.groupid, g.name
+                        FROM {groups} g
+                        LEFT JOIN {groups_members} gm ON g.id = gm.groupid
+                        WHERE gm.userid ' . $usertest . ' AND g.courseid = ?', $params);
+
+                // Now, iterate the grades again and sum them up for each group.
+                $groupgrades = array();
+                foreach ($usergroups as $usergroup) {
+                    if (!isset($groupgrades[$usergroup->groupid])) {
+                        $groupgrades[$usergroup->groupid] = array(
+                                'sum' => (float)$gradeforuser[$usergroup->userid],
+                                'number' => 1,
+                                'group' => $usergroup->name);
+                    } else {
+                        $groupgrades[$usergroup->groupid]['sum'] += $gradeforuser[$usergroup->userid];
+                        $groupgrades[$usergroup->groupid]['number'] += 1;
+                    }
+                }
+
+                foreach ($groupgrades as $groupid => $groupgrade) {
+                    $groupgrades[$groupid]['average'] = $groupgrades[$groupid]['sum'] / $groupgrades[$groupid]['number'];
+                }
+
+                // Sort groupgrades according to average grade, ascending.
+                uasort($groupgrades, function($a, $b) {
+                    if ($a["average"] == $b["average"]) {
+                        return 0;
+                    }
+                    return ($a["average"] > $b["average"] ? 1 : -1);
+                });
+
+                // How many groups do we have with graded member submissions to show?
+                $numbest  = empty($this->config->showbest) ? 0 : min($this->config->showbest, count($groupgrades));
+                $numworst = empty($this->config->showworst) ? 0 : min($this->config->showworst, count($groupgrades) - $numbest);
+
+                // Collect all the group results we are going to use in $best and $worst.
+                $remaining = $numbest;
+                $groupgrade = end($groupgrades);
+                while ($remaining--) {
+                    $best[key($groupgrades)] = $groupgrade['average'];
+                    $groupgrade = prev($groupgrades);
+                }
+
+                $remaining = $numworst;
+                $groupgrade = reset($groupgrades);
+                while ($remaining--) {
+                    $worst[key($groupgrades)] = $groupgrade['average'];
+                    $groupgrade = next($groupgrades);
+                }
+
+                // Ready for output!
+                if ($activity->gradetype == GRADE_TYPE_SCALE) {
+                    // We must display the results using scales.
+                    $gradeformat = B_ACTIVITYRESULTS_GRADE_FORMAT_SCALE;
+                    // Preload the scale.
+                    $scale = $this->get_scale($activity->scaleid);
+                } else if (intval(empty($this->config->gradeformat))) {
+                    $gradeformat = B_ACTIVITYRESULTS_GRADE_FORMAT_PCT;
+                } else {
+                    $gradeformat = $this->config->gradeformat;
+                }
+
+                // Generate the header.
+                $this->content->text .= $this->activity_link($activity, $cm);
+
+                if ($nameformat == B_ACTIVITYRESULTS_NAME_FORMAT_FULL) {
+                    if (has_capability('moodle/course:managegroups', $context)) {
+                        $grouplink = $CFG->wwwroot.'/group/overview.php?id='.$courseid.'&amp;group=';
+                    } else if (course_can_view_participants($context)) {
+                        $grouplink = $CFG->wwwroot.'/user/index.php?id='.$courseid.'&amp;group=';
+                    } else {
+                        $grouplink = '';
+                    }
+                }
+
+                $rank = 0;
+                if (!empty($best)) {
+                    $this->content->text .= '<table class="grades"><caption>';
+                    if ($numbest == 1) {
+                        $this->content->text .= get_string('bestgroupgrade', 'block_activity_results');
+                    } else {
+                        $this->content->text .= get_string('bestgroupgrades', 'block_activity_results', $numbest);
+                    }
+                    $this->content->text .= '</caption><colgroup class="number" />';
+                    $this->content->text .= '<colgroup class="name" /><colgroup class="grade" /><tbody>';
+                    foreach ($best as $groupid => $averagegrade) {
+                        switch ($nameformat) {
+                            case B_ACTIVITYRESULTS_NAME_FORMAT_ANON:
+                            case B_ACTIVITYRESULTS_NAME_FORMAT_ID:
+                                $thisname = get_string('group');
+                            break;
+                            default:
+                            case B_ACTIVITYRESULTS_NAME_FORMAT_FULL:
+                                if ($grouplink) {
+                                    $thisname = '<a href="'.$grouplink.$groupid.'">'.$groupgrades[$groupid]['group'].'</a>';
+                                } else {
+                                    $thisname = $groupgrades[$groupid]['group'];
+                                }
+                            break;
+                        }
+                        $this->content->text .= '<tr><td>'.(++$rank).'.</td><td>'.$thisname.'</td><td>';
+                        switch ($gradeformat) {
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_SCALE:
+                                // Round answer up and locate appropriate scale.
+                                $answer = (round($averagegrade, 0, PHP_ROUND_HALF_UP) - 1);
+                                if (isset($scale[$answer])) {
+                                    $this->content->text .= $scale[$answer];
+                                } else {
+                                    // Value is not in the scale.
+                                    $this->content->text .= get_string('unknown', 'block_activity_results');
+                                }
+                            break;
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_FRA:
+                                $this->content->text .= $this->activity_format_grade($averagegrade)
+                                    . '/' . $this->activity_format_grade($activity->grademax);
+                            break;
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_ABS:
+                                $this->content->text .= $this->activity_format_grade($averagegrade);
+                            break;
+                            default:
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_PCT:
+                                $this->content->text .= $this->activity_format_grade((float)$averagegrade /
+                                        (float)$activity->grademax * 100).'%';
+                            break;
+                        }
+                        $this->content->text .= '</td></tr>';
+                    }
+                    $this->content->text .= '</tbody></table>';
+                }
+
+                $rank = 0;
+                if (!empty($worst)) {
+                    $worst = array_reverse($worst, true);
+                    $this->content->text .= '<table class="grades"><caption>';
+                    if ($numworst == 1) {
+                        $this->content->text .= get_string('worstgroupgrade', 'block_activity_results');
+                    } else {
+                        $this->content->text .= get_string('worstgroupgrades', 'block_activity_results', $numworst);
+                    }
+                    $this->content->text .= '</caption><colgroup class="number" />';
+                    $this->content->text .= '<colgroup class="name" /><colgroup class="grade" /><tbody>';
+                    foreach ($worst as $groupid => $averagegrade) {
+                        switch ($nameformat) {
+                            case B_ACTIVITYRESULTS_NAME_FORMAT_ANON:
+                            case B_ACTIVITYRESULTS_NAME_FORMAT_ID:
+                                $thisname = get_string('group');
+                            break;
+                            default:
+                            case B_ACTIVITYRESULTS_NAME_FORMAT_FULL:
+                                if ($grouplink) {
+                                    $thisname = '<a href="'.$grouplink.$groupid.'">'.$groupgrades[$groupid]['group'].'</a>';
+                                } else {
+                                    $thisname = $groupgrades[$groupid]['group'];
+                                }
+                            break;
+                        }
+                        $this->content->text .= '<tr><td>'.(++$rank).'.</td><td>'.$thisname.'</td><td>';
+                        switch ($gradeformat) {
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_SCALE:
+                                // Round answer up and locate appropriate scale.
+                                $answer = (round($averagegrade, 0, PHP_ROUND_HALF_UP) - 1);
+                                if (isset($scale[$answer])) {
+                                    $this->content->text .= $scale[$answer];
+                                } else {
+                                    // Value is not in the scale.
+                                    $this->content->text .= get_string('unknown', 'block_activity_results');
+                                }
+                            break;
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_FRA:
+                                $this->content->text .= $this->activity_format_grade($averagegrade)
+                                    . '/' . $this->activity_format_grade($activity->grademax);
+                            break;
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_ABS:
+                                $this->content->text .= $this->activity_format_grade($averagegrade);
+                            break;
+                            default:
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_PCT:
+                                $this->content->text .= $this->activity_format_grade((float)$averagegrade /
+                                        (float)$activity->grademax * 100).'%';
+                            break;
+                        }
+                        $this->content->text .= '</td></tr>';
+                    }
+                    $this->content->text .= '</tbody></table>';
+                }
+            break;
+
+            case SEPARATEGROUPS:
+                // This is going to be just like no-groups mode, only we 'll filter
+                // out the grades from people not in our group.
+                if (!isloggedin()) {
+                    // Not logged in, so show nothing.
+                    return $this->content;
+                }
+
+                $mygroups = groups_get_all_groups($courseid, $USER->id);
+                if (empty($mygroups)) {
+                    // Not member of a group, show nothing.
+                    return $this->content;
+                }
+
+                // Get users from the same groups as me.
+                list($grouptest, $params) = $DB->get_in_or_equal(array_keys($mygroups));
+                $mygroupsusers = $DB->get_records_sql_menu(
+                        'SELECT DISTINCT userid, 1 FROM {groups_members} WHERE groupid ' . $grouptest,
+                        $params);
+
+                // Filter out the grades belonging to other users, and proceed as if there were no groups.
+                foreach ($grades as $key => $grade) {
+                    if (!isset($mygroupsusers[$grade->userid])) {
+                        unset($grades[$key]);
+                    }
+                }
+
+                // No break, fall through to the default case now we have filtered the $grades array.
+            default:
+            case NOGROUPS:
+                // Single user mode.
+                $numbest  = empty($this->config->showbest) ? 0 : min($this->config->showbest, count($grades));
+                $numworst = empty($this->config->showworst) ? 0 : min($this->config->showworst, count($grades) - $numbest);
+
+                // Collect all the usernames we are going to need.
+                $remaining = $numbest;
+                $grade = end($grades);
+                while ($remaining--) {
+                    $best[$grade->userid] = $grade->id;
+                    $grade = prev($grades);
+                }
+
+                $remaining = $numworst;
+                $grade = reset($grades);
+                while ($remaining--) {
+                    $worst[$grade->userid] = $grade->id;
+                    $grade = next($grades);
+                }
+
+                if (empty($best) && empty($worst)) {
+                    // Nothing to show, for some reason...
+                    return $this->content;
+                }
+
+                // Now grab all the users from the database.
+                $userids = array_merge(array_keys($best), array_keys($worst));
+                $fields = array_merge(array('id', 'idnumber'), get_all_user_name_fields());
+                $fields = implode(',', $fields);
+                $users = $DB->get_records_list('user', 'id', $userids, '', $fields);
+
+                // Ready for output!
+                if ($activity->gradetype == GRADE_TYPE_SCALE) {
+                    // We must display the results using scales.
+                    $gradeformat = B_ACTIVITYRESULTS_GRADE_FORMAT_SCALE;
+                    // Preload the scale.
+                    $scale = $this->get_scale($activity->scaleid);
+                } else if (intval(empty($this->config->gradeformat))) {
+                    $gradeformat = B_ACTIVITYRESULTS_GRADE_FORMAT_PCT;
+                } else {
+                    $gradeformat = $this->config->gradeformat;
+                }
+
+                // Generate the header.
+                $this->content->text .= $this->activity_link($activity, $cm);
+
+                $rank = 0;
+                if (!empty($best)) {
+                    $this->content->text .= '<table class="grades"><caption>';
+                    if ($numbest == 1) {
+                        $this->content->text .= get_string('bestgrade', 'block_activity_results');
+                    } else {
+                        $this->content->text .= get_string('bestgrades', 'block_activity_results', $numbest);
+                    }
+                    $this->content->text .= '</caption><colgroup class="number" />';
+                    $this->content->text .= '<colgroup class="name" /><colgroup class="grade" /><tbody>';
+                    foreach ($best as $userid => $gradeid) {
+                        switch ($nameformat) {
+                            case B_ACTIVITYRESULTS_NAME_FORMAT_ID:
+                                $thisname = get_string('user').' '.$users[$userid]->idnumber;
+                            break;
+                            case B_ACTIVITYRESULTS_NAME_FORMAT_ANON:
+                                $thisname = get_string('user');
+                            break;
+                            default:
+                            case B_ACTIVITYRESULTS_NAME_FORMAT_FULL:
+                                if (has_capability('moodle/user:viewdetails', $context)) {
+                                    $thisname = html_writer::link(new moodle_url('/user/view.php',
+                                        array('id' => $userid, 'course' => $courseid)), fullname($users[$userid]));
+                                } else {
+                                    $thisname = fullname($users[$userid]);
+                                }
+                            break;
+                        }
+                        $this->content->text .= '<tr><td>'.(++$rank).'.</td><td>'.$thisname.'</td><td>';
+                        switch ($gradeformat) {
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_SCALE:
+                                // Round answer up and locate appropriate scale.
+                                $answer = (round($grades[$gradeid]->finalgrade, 0, PHP_ROUND_HALF_UP) - 1);
+                                if (isset($scale[$answer])) {
+                                    $this->content->text .= $scale[$answer];
+                                } else {
+                                    // Value is not in the scale.
+                                    $this->content->text .= get_string('unknown', 'block_activity_results');
+                                }
+                            break;
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_FRA:
+                                $this->content->text .= $this->activity_format_grade($grades[$gradeid]->finalgrade);
+                                $this->content->text .= '/'.$this->activity_format_grade($activity->grademax);
+                            break;
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_ABS:
+                                $this->content->text .= $this->activity_format_grade($grades[$gradeid]->finalgrade);
+                            break;
+                            default:
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_PCT:
+                                if ($activity->grademax) {
+                                    $this->content->text .= $this->activity_format_grade((float)$grades[$gradeid]->finalgrade /
+                                            (float)$activity->grademax * 100).'%';
+                                } else {
+                                    $this->content->text .= '--%';
+                                }
+                            break;
+                        }
+                        $this->content->text .= '</td></tr>';
+                    }
+                    $this->content->text .= '</tbody></table>';
+                }
+
+                $rank = 0;
+                if (!empty($worst)) {
+                    $worst = array_reverse($worst, true);
+                    $this->content->text .= '<table class="grades"><caption>';
+                    if ($numbest == 1) {
+                        $this->content->text .= get_string('worstgrade', 'block_activity_results');
+                    } else {
+                        $this->content->text .= get_string('worstgrades', 'block_activity_results', $numworst);
+                    }
+                    $this->content->text .= '</caption><colgroup class="number" />';
+                    $this->content->text .= '<colgroup class="name" /><colgroup class="grade" /><tbody>';
+                    foreach ($worst as $userid => $gradeid) {
+                        switch ($nameformat) {
+                            case B_ACTIVITYRESULTS_NAME_FORMAT_ID:
+                                $thisname = get_string('user').' '.$users[$userid]->idnumber;
+                            break;
+                            case B_ACTIVITYRESULTS_NAME_FORMAT_ANON:
+                                $thisname = get_string('user');
+                            break;
+                            default:
+                            case B_ACTIVITYRESULTS_NAME_FORMAT_FULL:
+                                if (has_capability('moodle/user:viewdetails', $context)) {
+                                    $thisname = html_writer::link(new moodle_url('/user/view.php',
+                                        array('id' => $userid, 'course' => $courseid)), fullname($users[$userid]));
+                                } else {
+                                    $thisname = fullname($users[$userid]);
+                                }
+                            break;
+                        }
+                        $this->content->text .= '<tr><td>'.(++$rank).'.</td><td>'.$thisname.'</td><td>';
+                        switch ($gradeformat) {
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_SCALE:
+                                // Round answer up and locate appropriate scale.
+                                $answer = (round($grades[$gradeid]->finalgrade, 0, PHP_ROUND_HALF_UP) - 1);
+                                if (isset($scale[$answer])) {
+                                    $this->content->text .= $scale[$answer];
+                                } else {
+                                    // Value is not in the scale.
+                                    $this->content->text .= get_string('unknown', 'block_activity_results');
+                                }
+                            break;
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_FRA:
+                                $this->content->text .= $this->activity_format_grade($grades[$gradeid]->finalgrade);
+                                $this->content->text .= '/'.$this->activity_format_grade($activity->grademax);
+                            break;
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_ABS:
+                                $this->content->text .= $this->activity_format_grade($grades[$gradeid]->finalgrade);
+                            break;
+                            default:
+                            case B_ACTIVITYRESULTS_GRADE_FORMAT_PCT:
+                                if ($activity->grademax) {
+                                    $this->content->text .= $this->activity_format_grade((float)$grades[$gradeid]->finalgrade /
+                                            (float)$activity->grademax * 100).'%';
+                                } else {
+                                    $this->content->text .= '--%';
+                                }
+                            break;
+                        }
+                        $this->content->text .= '</td></tr>';
+                    }
+                    $this->content->text .= '</tbody></table>';
+                }
+            break;
+        }
+
+        return $this->content;
+    }
+
+    /**
+     * Allows the block to be added multiple times to a single page
+     * @return boolean
+     */
+    public function instance_allow_multiple() {
+        return true;
+    }
+
+    /**
+     * Formats the grade to the specified decimal points
+     * @param float $grade
+     * @return string
+     */
+    private function activity_format_grade($grade) {
+        if (is_null($grade)) {
+            return get_string('notyetgraded', 'block_activity_results');
+        }
+        return format_float($grade, $this->config->decimalpoints);
+    }
+
+    /**
+     * Generates the Link to the activity module when displaed outside of the module
+     * @param stdclass $activity
+     * @param stdclass $cm
+     * @return string
+     */
+    private function activity_link($activity, $cm) {
+
+        $o = html_writer::start_tag('h3');
+        $o .= html_writer::link(new moodle_url('/mod/'.$activity->itemmodule.'/view.php',
+        array('id' => $cm->id)), format_string(($activity->itemname), true, ['context' => context_module::instance($cm->id)]));
+        $o .= html_writer::end_tag('h3');
+        return $o;
+    }
+
+    /**
+     * Generates a numeric array of scale entries
+     * @param int $scaleid
+     * @return array
+     */
+    private function get_scale($scaleid) {
+        global $DB;
+        $scaletext = $DB->get_field('scale', 'scale', array('id' => $scaleid), IGNORE_MISSING);
+        $scale = explode ( ',', $scaletext);
+        return $scale;
+
+    }
+}
diff --git a/activity_results/classes/privacy/provider.php b/activity_results/classes/privacy/provider.php
new file mode 100644
index 0000000..d68134e
--- /dev/null
+++ b/activity_results/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_activity_results.
+ *
+ * @package    block_activity_results
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_activity_results\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_activity_results implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/activity_results/db/access.php b/activity_results/db/access.php
new file mode 100644
index 0000000..70cdede
--- /dev/null
+++ b/activity_results/db/access.php
@@ -0,0 +1,41 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Activity results block caps.
+ *
+ * @package    block_activity_results
+ * @copyright  2015 Stephen Bourget
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/activity_results:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/activity_results/edit_form.php b/activity_results/edit_form.php
new file mode 100644
index 0000000..0342ee6
--- /dev/null
+++ b/activity_results/edit_form.php
@@ -0,0 +1,127 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Defines the form for editing Quiz results block instances.
+ *
+ * @package    block_activity_results
+ * @copyright  2009 Tim Hunt
+ * @copyright  2015 Stephen Bourget
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+require_once($CFG->dirroot . '/lib/grade/constants.php');
+
+/**
+ * Form for editing activity results block instances.
+ *
+ * @copyright 2009 Tim Hunt
+ * @copyright 2015 Stephen Bourget
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_activity_results_edit_form extends block_edit_form {
+    /**
+     * The definition of the fields to use.
+     *
+     * @param MoodleQuickForm $mform
+     */
+    protected function specific_definition($mform) {
+        global $DB;
+
+        // Load defaults.
+        $blockconfig = get_config('block_activity_results');
+
+        // Fields for editing activity_results block title and contents.
+        $mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
+
+        // Get supported modules (Only modules using grades or scales will be listed).
+        $sql = 'SELECT id, itemname FROM {grade_items} WHERE courseid = ? and itemtype = ? and (gradetype = ? or gradetype = ?)';
+        $params = array($this->page->course->id, 'mod', GRADE_TYPE_VALUE, GRADE_TYPE_SCALE);
+        $activities = $DB->get_records_sql_menu($sql, $params);
+        core_collator::asort($activities);
+
+        if (empty($activities)) {
+            $mform->addElement('static', 'noactivitieswarning', get_string('config_select_activity', 'block_activity_results'),
+                    get_string('config_no_activities_in_course', 'block_activity_results'));
+        } else {
+            foreach ($activities as $id => $name) {
+                $activities[$id] = strip_tags(format_string($name));
+            }
+            $mform->addElement('select', 'config_activitygradeitemid',
+                    get_string('config_select_activity', 'block_activity_results'), $activities);
+            $mform->setDefault('config_activitygradeitemid', $this->block->get_owning_activity()->id);
+        }
+
+        $mform->addElement('text', 'config_showbest',
+                get_string('config_show_best', 'block_activity_results'), array('size' => 3));
+        $mform->setDefault('config_showbest', $blockconfig->config_showbest);
+        $mform->setType('config_showbest', PARAM_INT);
+        if ($blockconfig->config_showbest_locked) {
+            $mform->freeze('config_showbest');
+        }
+
+        $mform->addElement('text', 'config_showworst',
+                get_string('config_show_worst', 'block_activity_results'), array('size' => 3));
+        $mform->setDefault('config_showworst', $blockconfig->config_showworst);
+        $mform->setType('config_showworst', PARAM_INT);
+        if ($blockconfig->config_showworst_locked) {
+            $mform->freeze('config_showworst');
+        }
+
+        $mform->addElement('selectyesno', 'config_usegroups', get_string('config_use_groups', 'block_activity_results'));
+        $mform->setDefault('config_usegroups', $blockconfig->config_usegroups);
+        if ($blockconfig->config_usegroups_locked) {
+            $mform->freeze('config_usegroups');
+        }
+
+        $nameoptions = array(
+            B_ACTIVITYRESULTS_NAME_FORMAT_FULL => get_string('config_names_full', 'block_activity_results'),
+            B_ACTIVITYRESULTS_NAME_FORMAT_ID => get_string('config_names_id', 'block_activity_results'),
+            B_ACTIVITYRESULTS_NAME_FORMAT_ANON => get_string('config_names_anon', 'block_activity_results')
+        );
+        $mform->addElement('select', 'config_nameformat',
+                get_string('config_name_format', 'block_activity_results'), $nameoptions);
+        $mform->setDefault('config_nameformat', $blockconfig->config_nameformat);
+        if ($blockconfig->config_nameformat_locked) {
+            $mform->freeze('config_nameformat');
+        }
+
+        $gradeeoptions = array(
+            B_ACTIVITYRESULTS_GRADE_FORMAT_PCT => get_string('config_format_percentage', 'block_activity_results'),
+            B_ACTIVITYRESULTS_GRADE_FORMAT_FRA => get_string('config_format_fraction', 'block_activity_results'),
+            B_ACTIVITYRESULTS_GRADE_FORMAT_ABS => get_string('config_format_absolute', 'block_activity_results')
+        );
+        $mform->addElement('select', 'config_gradeformat',
+                get_string('config_grade_format', 'block_activity_results'), $gradeeoptions);
+        $mform->setDefault('config_gradeformat', $blockconfig->config_gradeformat);
+        if ($blockconfig->config_gradeformat_locked) {
+            $mform->freeze('config_gradeformat');
+        }
+
+        $options = array();
+        for ($i = 0; $i <= 5; $i++) {
+            $options[$i] = $i;
+        }
+        $mform->addElement('select', 'config_decimalpoints', get_string('config_decimalplaces', 'block_activity_results'),
+                $options);
+        $mform->setDefault('config_decimalpoints', $blockconfig->config_decimalpoints);
+        $mform->setType('config_decimalpoints', PARAM_INT);
+        if ($blockconfig->config_decimalpoints_locked) {
+            $mform->freeze('config_decimalpoints');
+        }
+    }
+}
\ No newline at end of file
diff --git a/activity_results/lang/en/block_activity_results.php b/activity_results/lang/en/block_activity_results.php
new file mode 100644
index 0000000..97dec82
--- /dev/null
+++ b/activity_results/lang/en/block_activity_results.php
@@ -0,0 +1,68 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_activity_results', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package    block_activity_results
+ * @copyright  2015 Stephen Bourget
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['activity_results:addinstance'] = 'Add a new activity results block';
+$string['bestgrade'] = 'The highest grade:';
+$string['bestgrades'] = 'The {$a} highest grades:';
+$string['bestgroupgrade'] = 'The group with the highest average:';
+$string['bestgroupgrades'] = 'The {$a} groups with the highest average:';
+$string['config_format_absolute'] = 'Absolute numbers';
+$string['config_format_fraction'] = 'Fractions';
+$string['config_format_percentage'] = 'Percentages';
+$string['config_decimalplaces'] = 'Decimal places to display';
+$string['config_grade_format'] = 'Display grades as';
+$string['config_name_format'] = 'Privacy of results';
+$string['config_names_anon'] = 'Anonymous results';
+$string['config_names_full'] = 'Display full names';
+$string['config_names_id'] = 'Display only ID numbers';
+$string['config_no_activities_in_course'] = 'There are not yet any activities in this course.';
+$string['config_select_activity'] = 'Which activity should this block display results from?';
+$string['config_show_best'] = 'How many of the highest grades should be shown (0 to disable)?';
+$string['config_show_worst'] = 'How many of the lowest grades should be shown (0 to disable)?';
+$string['configuredtoshownothing'] = 'This block\'s configuration currently does not allow it to show any results.';
+$string['config_use_groups'] = 'Show groups instead of students (only if the activity supports groups)?';
+$string['defaulthighestgrades'] = 'Default highest grades shown';
+$string['defaulthighestgrades_desc'] = 'How many of the highest grades should be shown by default?';
+$string['defaultlowestgrades'] = 'Default lowest grades shown';
+$string['defaultlowestgrades_desc'] = 'How many of the lowest grades should be shown by default?';
+$string['defaultshowgroups'] = 'Default show groups';
+$string['defaultnameoptions'] = 'Privacy of results';
+$string['defaultnameoptions_desc'] = 'How should the students be identified by default?';
+$string['defaultshowgroups_desc'] = 'Show groups instead of students by default (only if the activity supports groups)';
+$string['defaultgradedisplay'] = 'Display grades as';
+$string['defaultgradedisplay_desc'] = 'How should the grades be displayed by default?';
+$string['defaultdecimalplaces'] = 'Decimal places';
+$string['defaultdecimalplaces_desc'] = 'Number of decimal places to display by default';
+$string['error_emptyactivityid'] = 'Please configure this block and select which activity it should display results from.';
+$string['error_emptyactivityrecord'] = 'Error: the selected activity does not exist in the database.';
+$string['error_nogroupsexist'] = 'Error: the block is set to display grades in group mode, but there are no groups defined.';
+$string['error_unsupportedgradetype'] = 'Error: the activity selected uses a grading method that is not supported by this block.';
+$string['notyetgraded'] = 'Not yet graded';
+$string['pluginname'] = 'Activity results';
+$string['unknown'] = 'Unknown scale';
+$string['worstgrade'] = 'The lowest grade:';
+$string['worstgrades'] = 'The {$a} lowest grades:';
+$string['worstgroupgrade'] = 'The group with the lowest average:';
+$string['worstgroupgrades'] = 'The {$a} groups with the lowest average:';
+$string['privacy:metadata'] = 'The Activity results block only shows data stored in other locations.';
diff --git a/activity_results/settings.php b/activity_results/settings.php
new file mode 100644
index 0000000..da08088
--- /dev/null
+++ b/activity_results/settings.php
@@ -0,0 +1,86 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Defines the form for editing activity results block instances.
+ *
+ * @package    block_activity_results
+ * @copyright  2016 Stephen Bourget
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die;
+
+if ($ADMIN->fulltree) {
+
+    // Default high scores.
+    $setting = new admin_setting_configtext('block_activity_results/config_showbest',
+        new lang_string('defaulthighestgrades', 'block_activity_results'),
+        new lang_string('defaulthighestgrades_desc', 'block_activity_results'), 3, PARAM_INT);
+    $setting->set_locked_flag_options(admin_setting_flag::ENABLED, false);
+    $settings->add($setting);
+
+    // Default low scores.
+    $setting = new admin_setting_configtext('block_activity_results/config_showworst',
+        new lang_string('defaultlowestgrades', 'block_activity_results'),
+        new lang_string('defaultlowestgrades_desc', 'block_activity_results'), 0, PARAM_INT);
+    $setting->set_locked_flag_options(admin_setting_flag::ENABLED, false);
+    $settings->add($setting);
+
+    // Default group display.
+    $yesno = array(0 => get_string('no'), 1 => get_string('yes'));
+    $setting = new admin_setting_configselect('block_activity_results/config_usegroups',
+        new lang_string('defaultshowgroups', 'block_activity_results'),
+        new lang_string('defaultshowgroups_desc', 'block_activity_results'), 0, $yesno);
+    $setting->set_locked_flag_options(admin_setting_flag::ENABLED, false);
+    $settings->add($setting);
+
+    // Default privacy settings.
+    $nameoptions = array(
+        B_ACTIVITYRESULTS_NAME_FORMAT_FULL => get_string('config_names_full', 'block_activity_results'),
+        B_ACTIVITYRESULTS_NAME_FORMAT_ID => get_string('config_names_id', 'block_activity_results'),
+        B_ACTIVITYRESULTS_NAME_FORMAT_ANON => get_string('config_names_anon', 'block_activity_results')
+    );
+    $setting = new admin_setting_configselect('block_activity_results/config_nameformat',
+        new lang_string('defaultnameoptions', 'block_activity_results'),
+        new lang_string('defaultnameoptions_desc', 'block_activity_results'), B_ACTIVITYRESULTS_NAME_FORMAT_FULL, $nameoptions);
+    $setting->set_locked_flag_options(admin_setting_flag::ENABLED, false);
+    $settings->add($setting);
+
+    // Default grade display settings.
+    $gradeoptions = array(
+        B_ACTIVITYRESULTS_GRADE_FORMAT_PCT => get_string('config_format_percentage', 'block_activity_results'),
+        B_ACTIVITYRESULTS_GRADE_FORMAT_FRA => get_string('config_format_fraction', 'block_activity_results'),
+        B_ACTIVITYRESULTS_GRADE_FORMAT_ABS => get_string('config_format_absolute', 'block_activity_results')
+    );
+    $setting = new admin_setting_configselect('block_activity_results/config_gradeformat',
+        new lang_string('defaultgradedisplay', 'block_activity_results'),
+        new lang_string('defaultgradedisplay_desc', 'block_activity_results'), B_ACTIVITYRESULTS_GRADE_FORMAT_PCT, $gradeoptions);
+    $setting->set_locked_flag_options(admin_setting_flag::ENABLED, false);
+    $settings->add($setting);
+
+    // Default decimal places.
+    $places = array();
+    for ($i = 0; $i <= 5; $i++) {
+        $places[$i] = $i;
+    }
+    $setting = new admin_setting_configselect('block_activity_results/config_decimalpoints',
+        new lang_string('defaultdecimalplaces', 'block_activity_results'),
+        new lang_string('defaultdecimalplaces_desc', 'block_activity_results'), 2, $places);
+    $setting->set_locked_flag_options(admin_setting_flag::ENABLED, false);
+    $settings->add($setting);
+
+}
diff --git a/activity_results/styles.css b/activity_results/styles.css
new file mode 100644
index 0000000..83ffd7d
--- /dev/null
+++ b/activity_results/styles.css
@@ -0,0 +1,28 @@
+.block_activity_results h1 {
+    margin: 4px;
+    font-size: 1.1em;
+}
+
+.block_activity_results table.grades {
+    text-align: left;
+    width: 100%;
+}
+
+.block_activity_results table.grades .number {
+    text-align: left;
+    width: 10%;
+}
+
+.block_activity_results table.grades .name {
+    text-align: left;
+    width: 77%;
+}
+
+.block_activity_results table.grades .grade {
+    text-align: right;
+}
+
+.block_activity_results table.grades caption {
+    font-weight: bold;
+    font-size: 18px;
+}
diff --git a/activity_results/tests/behat/addblockinactivity.feature b/activity_results/tests/behat/addblockinactivity.feature
new file mode 100644
index 0000000..3191e13
--- /dev/null
+++ b/activity_results/tests/behat/addblockinactivity.feature
@@ -0,0 +1,102 @@
+@block @block_activity_results
+Feature: The activity results block displays student scores
+  In order to be display student scores
+  As a user
+  I need to see the activity results block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+      | student1 | Student | 1 | student1@example.com | S1 |
+      | student2 | Student | 2 | student2@example.com | S2 |
+      | student3 | Student | 3 | student3@example.com | S3 |
+      | student4 | Student | 4 | student4@example.com | S4 |
+      | student5 | Student | 5 | student5@example.com | S5 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+      | student2 | C1 | student |
+      | student3 | C1 | student |
+      | student4 | C1 | student |
+      | student5 | C1 | student |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment 1 |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+    And I am on "Course 1" course homepage
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment 2 |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+    And I am on "Course 1" course homepage
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment 3 |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+    And I am on "Course 1" course homepage
+    And I add a "Page" to section "1"
+    And I set the following fields to these values:
+      | Name | Test page name |
+      | Description | Test page description |
+      | Page content | This is a page |
+    And I press "Save and return to course"
+    And I am on "Course 1" course homepage
+    And I should see "Test page name"
+    And I navigate to "View > Grader report" in the course gradebook
+    And I turn editing mode on
+    And I give the grade "90.00" to the user "Student 1" for the grade item "Test assignment 1"
+    And I give the grade "80.00" to the user "Student 2" for the grade item "Test assignment 1"
+    And I give the grade "70.00" to the user "Student 3" for the grade item "Test assignment 1"
+    And I give the grade "60.00" to the user "Student 4" for the grade item "Test assignment 1"
+    And I give the grade "50.00" to the user "Student 5" for the grade item "Test assignment 1"
+    And I press "Save changes"
+    And I am on "Course 1" course homepage
+
+  Scenario: Configure the block on a non-graded activity to show 3 high scores
+    Given I follow "Test page name"
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_activitygradeitemid | Test assignment 1 |
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+    And I press "Save changes"
+    Then I should see "Student 1" in the "Activity results" "block"
+    And I should see "90.00" in the "Activity results" "block"
+    And I should see "Student 2" in the "Activity results" "block"
+    And I should see "80.00" in the "Activity results" "block"
+    And I should see "Student 3" in the "Activity results" "block"
+    And I should see "70.00" in the "Activity results" "block"
+
+  Scenario: Block should select current activity by default
+    Given I follow "Test assignment 1"
+    When I add the "Activity results" block
+    And I configure the "Activity results" block
+    Then the field "id_config_activitygradeitemid" matches value "Test assignment 1"
+    And I press "Cancel"
+    And I am on "Course 1" course homepage
+    And I follow "Test assignment 2"
+    And I add the "Activity results" block
+    And I configure the "Activity results" block
+    And the field "id_config_activitygradeitemid" matches value "Test assignment 2"
+    And I press "Cancel"
+    And I am on "Course 1" course homepage
+    And I follow "Test assignment 3"
+    And I add the "Activity results" block
+    And I configure the "Activity results" block
+    And the field "id_config_activitygradeitemid" matches value "Test assignment 3"
+    And I press "Cancel"
+    And I am on "Course 1" course homepage
+    And I follow "Test page name"
+    And I add the "Activity results" block
+    And I configure the "Activity results" block
+    And the field "id_config_activitygradeitemid" does not match value "Test page name"
diff --git a/activity_results/tests/behat/addunconfiguredblock.feature b/activity_results/tests/behat/addunconfiguredblock.feature
new file mode 100644
index 0000000..0570dbd
--- /dev/null
+++ b/activity_results/tests/behat/addunconfiguredblock.feature
@@ -0,0 +1,42 @@
+@block @block_activity_results
+Feature: The activity results block doesn't displays student scores for unconfigured block
+  In order to be display student scores
+  As a user
+  I need to see the activity results block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+
+  Scenario: Add the block to a the course
+    Given I add the "Activity results" block
+    Then I should see "Please configure this block and select which activity it should display results from." in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page in a course without activities
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I should see "There are not yet any activities in this course."
+    And I press "Save changes"
+    Then I should see "Please configure this block and select which activity it should display results from." in the "Activity results" "block"
+
+  Scenario: Try to configure the block on a resource page in a course without activities
+    Given I add a "Page" to section "1"
+    And I set the following fields to these values:
+      | Name | Test page name |
+      | Description | Test page description |
+      | page | This is a page |
+    And I press "Save and display"
+    When I add the "Activity results" block
+    And I configure the "Activity results" block
+    And I should see "There are not yet any activities in this course."
+    And I press "Save changes"
+    Then I should see "Please configure this block and select which activity it should display results from." in the "Activity results" "block"
diff --git a/activity_results/tests/behat/addunsupportedactivity.feature b/activity_results/tests/behat/addunsupportedactivity.feature
new file mode 100644
index 0000000..982510d
--- /dev/null
+++ b/activity_results/tests/behat/addunsupportedactivity.feature
@@ -0,0 +1,39 @@
+@block @block_activity_results
+Feature: The activity results block doesn't display student scores for unsupported activity
+  In order to be display student scores
+  As a user
+  I need to properly configure the activity results block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+
+  Scenario: Try to configure the block to use an activity without grades
+    Given I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+    And I am on "Course 1" course homepage
+    And I add the "Activity results" block
+    And I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 1 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+    And I press "Save changes"
+    When I follow "Test assignment"
+    And I navigate to "Edit settings" in current page administration
+    And I set the following fields to these values:
+      | id_grade_modgrade_type | None |
+    And I press "Save and return to course"
+    Then I should see "Error: the activity selected uses a grading method that is not supported by this block." in the "Activity results" "block"
diff --git a/activity_results/tests/behat/defaultsettings.feature b/activity_results/tests/behat/defaultsettings.feature
new file mode 100644
index 0000000..3af9d0e
--- /dev/null
+++ b/activity_results/tests/behat/defaultsettings.feature
@@ -0,0 +1,64 @@
+@block @block_activity_results
+Feature: The activity results block can have administrator set defaults
+  In order to be customize the activity results block
+  As an admin
+  I need can assign some site wide defaults
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+      | student1 | Student | 1 | student1@example.com | S1 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+
+  Scenario: Assign some site-wide defaults to the block.
+    Given the following config values are set as admin:
+      | config_showbest    | 0 | block_activity_results |
+      | config_showworst   | 0 | block_activity_results |
+      | config_gradeformat | 2 | block_activity_results |
+      | config_nameformat  | 2 | block_activity_results |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+    And I am on "Course 1" course homepage
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And the following fields match these values:
+      | id_config_showbest    | 0 |
+      | id_config_showworst   | 0 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat  | Display only ID numbers |
+    And I press "Save changes"
+    Then I should see "This block's configuration currently does not allow it to show any results." in the "Activity results" "block"
+
+  Scenario: Assign some site-wide defaults to the block and lock them.
+    Given the following config values are set as admin:
+      | config_showbest         | 0 | block_activity_results |
+      | config_showbest_locked  | 1 | block_activity_results |
+      | config_showworst        | 0 | block_activity_results |
+      | config_showworst_locked | 1 | block_activity_results |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+    And I am on "Course 1" course homepage
+    And I add the "Activity results" block
+    When I configure the "Activity results" block
+    And the following fields match these values:
+      | id_config_showbest    | 0 |
+      | id_config_showworst   | 0 |
+    And the "id_config_showbest" "field" should be readonly
+    And the "id_config_showworst" "field" should be readonly
+    And I press "Save changes"
+    Then I should see "This block's configuration currently does not allow it to show any results." in the "Activity results" "block"
diff --git a/activity_results/tests/behat/highscoreswithoutgroups.feature b/activity_results/tests/behat/highscoreswithoutgroups.feature
new file mode 100644
index 0000000..eb750a0
--- /dev/null
+++ b/activity_results/tests/behat/highscoreswithoutgroups.feature
@@ -0,0 +1,169 @@
+@block @block_activity_results
+Feature: The activity results block displays student high scores
+  In order to be display student scores
+  As a user
+  I need to see the activity results block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+      | student1 | Student | 1 | student1@example.com | S1 |
+      | student2 | Student | 2 | student2@example.com | S2 |
+      | student3 | Student | 3 | student3@example.com | S3 |
+      | student4 | Student | 4 | student4@example.com | S4 |
+      | student5 | Student | 5 | student5@example.com | S5 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+      | student2 | C1 | student |
+      | student3 | C1 | student |
+      | student4 | C1 | student |
+      | student5 | C1 | student |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+    And I am on "Course 1" course homepage
+    And I navigate to "View > Grader report" in the course gradebook
+    And I turn editing mode on
+    And I give the grade "90.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "60.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "50.00" to the user "Student 5" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I am on "Course 1" course homepage
+
+  Scenario: Configure the block on the course page to show 0 high scores
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+    And I press "Save changes"
+    Then I should see "This block's configuration currently does not allow it to show any results." in the "Activity results" "block"
+
+  Scenario: Configure the block on the course page to show 1 high score
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 1 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+    And I press "Save changes"
+    Then I should see "Student 1" in the "Activity results" "block"
+    And I should see "90%" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show 1 high score as a fraction
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 1 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat | Display full names |
+    And I press "Save changes"
+    Then I should see "Student 1" in the "Activity results" "block"
+    And I should see "90.00/100.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show 1 high score as a absolute numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 1 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+    And I press "Save changes"
+    Then I should see "Student 1" in the "Activity results" "block"
+    And I should see "90.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores as percentages
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+    And I press "Save changes"
+    Then I should see "Student 1" in the "Activity results" "block"
+    And I should see "90%" in the "Activity results" "block"
+    And I should see "Student 2" in the "Activity results" "block"
+    And I should see "80%" in the "Activity results" "block"
+    And I should see "Student 3" in the "Activity results" "block"
+    And I should see "70%" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores as fractions
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat | Display full names |
+    And I press "Save changes"
+    Then I should see "Student 1" in the "Activity results" "block"
+    And I should see "90.00/100.00" in the "Activity results" "block"
+    And I should see "Student 2" in the "Activity results" "block"
+    And I should see "80.00/100.00" in the "Activity results" "block"
+    And I should see "Student 3" in the "Activity results" "block"
+    And I should see "70.00/100.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores as absolute numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+    And I press "Save changes"
+    Then I should see "Student 1" in the "Activity results" "block"
+    And I should see "90.00" in the "Activity results" "block"
+    And I should see "Student 2" in the "Activity results" "block"
+    And I should see "80.00" in the "Activity results" "block"
+    And I should see "Student 3" in the "Activity results" "block"
+    And I should see "70.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores using ID numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display only ID numbers |
+    And I press "Save changes"
+    Then I should see "User S1" in the "Activity results" "block"
+    And I should see "90.00%" in the "Activity results" "block"
+    And I should see "User S2" in the "Activity results" "block"
+    And I should see "80.00%" in the "Activity results" "block"
+    And I should see "User S3" in the "Activity results" "block"
+    And I should see "70.00%" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores using anonymous names
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Anonymous results |
+    And I press "Save changes"
+    Then I should see "User" in the "Activity results" "block"
+    And I should see "90.00%" in the "Activity results" "block"
+    And I should see "80.00%" in the "Activity results" "block"
+    And I should see "70.00%" in the "Activity results" "block"
diff --git a/activity_results/tests/behat/highscoreswithscales.feature b/activity_results/tests/behat/highscoreswithscales.feature
new file mode 100644
index 0000000..2a8bcf9
--- /dev/null
+++ b/activity_results/tests/behat/highscoreswithscales.feature
@@ -0,0 +1,109 @@
+@block @block_activity_results
+Feature: The activity results block displays students high scores in group as scales
+  In order to be display student scores as scales
+  As a user
+  I need to see the activity results block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+      | student1 | Student | 1 | student1@example.com | S1 |
+      | student2 | Student | 2 | student2@example.com | S2 |
+      | student3 | Student | 3 | student3@example.com | S3 |
+      | student4 | Student | 4 | student4@example.com | S4 |
+      | student5 | Student | 5 | student5@example.com | S5 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+      | student2 | C1 | student |
+      | student3 | C1 | student |
+      | student4 | C1 | student |
+      | student5 | C1 | student |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage
+    And I navigate to "Scales" in the course gradebook
+    And I press "Add a new scale"
+    And I set the following fields to these values:
+      | Name | My Scale |
+      | Scale | Disappointing, Not good enough, Average, Good, Very good, Excellent! |
+    And I press "Save changes"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | id_grade_modgrade_type | Scale |
+      | id_grade_modgrade_scale | My Scale |
+    And I am on "Course 1" course homepage
+    And I navigate to "View > Grader report" in the course gradebook
+    And I turn editing mode on
+    And I give the grade "Excellent!" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "Very good" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "Good" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "Average" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "Not good enough" to the user "Student 5" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I am on "Course 1" course homepage
+
+  Scenario: Configure the block on the course page to show 1 high score
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 1 |
+      | id_config_showworst | 0 |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+    And I press "Save changes"
+    Then I should see "Student 1" in the "Activity results" "block"
+    And I should see "Excellent!" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores using full names
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_nameformat | Display full names |
+    And I press "Save changes"
+    Then I should see "Student 1" in the "Activity results" "block"
+    And I should see "Excellent!" in the "Activity results" "block"
+    And I should see "Student 2" in the "Activity results" "block"
+    And I should see "Very good" in the "Activity results" "block"
+    And I should see "Student 3" in the "Activity results" "block"
+    And I should see "Good" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores using ID numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_nameformat | Display only ID numbers |
+    And I press "Save changes"
+    Then I should see "User S1" in the "Activity results" "block"
+    And I should see "Excellent!" in the "Activity results" "block"
+    And I should see "User S2" in the "Activity results" "block"
+    And I should see "Very good" in the "Activity results" "block"
+    And I should see "User S3" in the "Activity results" "block"
+    And I should see "Good" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores using anonymous names
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_nameformat | Anonymous results |
+    And I press "Save changes"
+    Then I should see "User" in the "Activity results" "block"
+    And I should not see "Student 1" in the "Activity results" "block"
+    And I should see "Excellent!" in the "Activity results" "block"
+    And I should not see "Student 2" in the "Activity results" "block"
+    And I should see "Very good" in the "Activity results" "block"
+    And I should not see "Student 3" in the "Activity results" "block"
+    And I should see "Good" in the "Activity results" "block"
diff --git a/activity_results/tests/behat/highscoreswithscalesandgroups.feature b/activity_results/tests/behat/highscoreswithscalesandgroups.feature
new file mode 100644
index 0000000..9500862
--- /dev/null
+++ b/activity_results/tests/behat/highscoreswithscalesandgroups.feature
@@ -0,0 +1,151 @@
+@block @block_activity_results
+Feature: The activity results block displays student in group high scores as scales
+  In order to be display student scores as scales
+  As a user
+  I need to see the activity results block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+      | student1 | Student | 1 | student1@example.com | S1 |
+      | student2 | Student | 2 | student2@example.com | S2 |
+      | student3 | Student | 3 | student3@example.com | S3 |
+      | student4 | Student | 4 | student4@example.com | S4 |
+      | student5 | Student | 5 | student5@example.com | S5 |
+      | student6 | Student | 6 | student6@example.com | S6 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "groups" exist:
+      | name | course | idnumber |
+      | Group 1 | C1 | G1 |
+      | Group 2 | C1 | G2 |
+      | Group 3 | C1 | G3 |
+      | Group 4 | C1 | G4 |
+      | Group 5 | C1 | G5 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+      | student2 | C1 | student |
+      | student3 | C1 | student |
+      | student4 | C1 | student |
+      | student5 | C1 | student |
+      | student6 | C1 | student |
+    And the following "group members" exist:
+      | user     | group   |
+      | student1 | G1 |
+      | student2 | G1 |
+      | student3 | G2 |
+      | student4 | G2 |
+      | student5 | G3 |
+      | student6 | G3 |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage
+    And I navigate to "Scales" in the course gradebook
+    And I press "Add a new scale"
+    And I set the following fields to these values:
+      | Name | My Scale |
+      | Scale | Disappointing, Not good enough, Average, Good, Very good, Excellent! |
+    And I press "Save changes"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | id_grade_modgrade_type | Scale |
+      | id_grade_modgrade_scale | My Scale |
+      | Group mode | Separate groups |
+    And I am on "Course 1" course homepage
+    And I navigate to "View > Grader report" in the course gradebook
+    And I turn editing mode on
+    And I give the grade "Excellent!" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "Very good" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "Very good" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "Good" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "Good" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "Average" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I am on "Course 1" course homepage
+
+  Scenario: Try to configure the block on the course page to show 1 high score
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 1 |
+      | id_config_showworst | 0 |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 1" in the "Activity results" "block"
+    And I should see "Excellent!" in the "Activity results" "block"
+    And I log out
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "Student 1" in the "Activity results" "block"
+    And I should see "Excellent!" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores using full names
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 1" in the "Activity results" "block"
+    And I should see "Excellent!" in the "Activity results" "block"
+    And I should see "Group 2" in the "Activity results" "block"
+    And I should see "Very good" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "Good" in the "Activity results" "block"
+    And I log out
+    And I log in as "student3"
+    And I am on "Course 1" course homepage
+    And I should see "Student 3" in the "Activity results" "block"
+    And I should see "Very good" in the "Activity results" "block"
+    And I should see "Student 4" in the "Activity results" "block"
+    And I should see "Good" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores using ID numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_nameformat | Display only ID numbers |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group" in the "Activity results" "block"
+    And I should see "Excellent!" in the "Activity results" "block"
+    And I should see "Very good" in the "Activity results" "block"
+    And I should see "Good" in the "Activity results" "block"
+    And I log out
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "User S1" in the "Activity results" "block"
+    And I should see "Excellent!" in the "Activity results" "block"
+    And I should see "User S2" in the "Activity results" "block"
+    And I should see "Very good" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores using anonymous names
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_nameformat | Anonymous results |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group" in the "Activity results" "block"
+    And I should see "Excellent!" in the "Activity results" "block"
+    And I should see "Very good" in the "Activity results" "block"
+    And I should see "Good" in the "Activity results" "block"
+    And I log out
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "User" in the "Activity results" "block"
+    And I should see "Excellent!" in the "Activity results" "block"
+    And I should see "Very good" in the "Activity results" "block"
diff --git a/activity_results/tests/behat/highscoreswithseperategroups.feature b/activity_results/tests/behat/highscoreswithseperategroups.feature
new file mode 100644
index 0000000..ccc223d
--- /dev/null
+++ b/activity_results/tests/behat/highscoreswithseperategroups.feature
@@ -0,0 +1,227 @@
+@block @block_activity_results
+Feature: The activity results block displays student in separate groups scores
+  In order to be display student scores
+  As a user
+  I need to see the activity results block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+      | student1 | Student | 1 | student1@example.com | S1 |
+      | student2 | Student | 2 | student2@example.com | S2 |
+      | student3 | Student | 3 | student3@example.com | S3 |
+      | student4 | Student | 4 | student4@example.com | S4 |
+      | student5 | Student | 5 | student5@example.com | S5 |
+      | student6 | Student | 6 | student6@example.com | S6 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "groups" exist:
+      | name | course | idnumber |
+      | Group 1 | C1 | G1 |
+      | Group 2 | C1 | G2 |
+      | Group 3 | C1 | G3 |
+      | Group 4 | C1 | G4 |
+      | Group 5 | C1 | G5 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+      | student2 | C1 | student |
+      | student3 | C1 | student |
+      | student4 | C1 | student |
+      | student5 | C1 | student |
+      | student6 | C1 | student |
+    And the following "group members" exist:
+      | user     | group   |
+      | student1 | G1 |
+      | student2 | G1 |
+      | student3 | G2 |
+      | student4 | G2 |
+      | student5 | G3 |
+      | student6 | G3 |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Separate groups |
+    And I am on "Course 1" course homepage
+    And I navigate to "View > Grader report" in the course gradebook
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I am on "Course 1" course homepage
+
+  Scenario: Configure the block on the course page to show 1 high score
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 1 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 1" in the "Activity results" "block"
+    And I should see "95%" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show 1 high score as a fraction
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 1 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 1" in the "Activity results" "block"
+    And I should see "95.00/100.00" in the "Activity results" "block"
+    And I log out
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "Student 1" in the "Activity results" "block"
+    And I should see "100.00/100.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show 1 high score as a absolute numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 1 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 1" in the "Activity results" "block"
+    And I should see "95.00" in the "Activity results" "block"
+    And I log out
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "Student 1" in the "Activity results" "block"
+    And I should see "100.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores as percentages
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 1" in the "Activity results" "block"
+    And I should see "95%" in the "Activity results" "block"
+    And I should see "Group 2" in the "Activity results" "block"
+    And I should see "85%" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75%" in the "Activity results" "block"
+    And I log out
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "Student 1" in the "Activity results" "block"
+    And I should see "100%" in the "Activity results" "block"
+    And I should see "Student 2" in the "Activity results" "block"
+    And I should see "90%" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores as fractions
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 1" in the "Activity results" "block"
+    And I should see "95.00/100.00" in the "Activity results" "block"
+    And I should see "Group 2" in the "Activity results" "block"
+    And I should see "85.00/100.00" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75.00/100.00" in the "Activity results" "block"
+    And I log out
+    And I log in as "student3"
+    And I am on "Course 1" course homepage
+    And I should see "Student 3" in the "Activity results" "block"
+    And I should see "90.00/100.00" in the "Activity results" "block"
+    And I should see "Student 4" in the "Activity results" "block"
+    And I should see "80.00/100.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores as absolute numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 1" in the "Activity results" "block"
+    And I should see "95.00" in the "Activity results" "block"
+    And I should see "Group 2" in the "Activity results" "block"
+    And I should see "85.00" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75.00" in the "Activity results" "block"
+    And I log out
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "Student 1" in the "Activity results" "block"
+    And I should see "100.00" in the "Activity results" "block"
+    And I should see "Student 2" in the "Activity results" "block"
+    And I should see "90.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores using ID numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display only ID numbers |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group" in the "Activity results" "block"
+    And I should see "95.00%" in the "Activity results" "block"
+    And I should see "85.00%" in the "Activity results" "block"
+    And I should see "75.00%" in the "Activity results" "block"
+    And I log out
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "User S1" in the "Activity results" "block"
+    And I should see "100.00%" in the "Activity results" "block"
+    And I should see "User S2" in the "Activity results" "block"
+    And I should see "90.00%" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores using anonymous names
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Anonymous results |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group" in the "Activity results" "block"
+    And I should see "95.00%" in the "Activity results" "block"
+    And I should see "85.00%" in the "Activity results" "block"
+    And I should see "75.00%" in the "Activity results" "block"
+    And I log out
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "User" in the "Activity results" "block"
+    And I should see "100.00%" in the "Activity results" "block"
+    And I should see "90.00%" in the "Activity results" "block"
diff --git a/activity_results/tests/behat/highscoreswithvisiblegroups.feature b/activity_results/tests/behat/highscoreswithvisiblegroups.feature
new file mode 100644
index 0000000..11ee5a5
--- /dev/null
+++ b/activity_results/tests/behat/highscoreswithvisiblegroups.feature
@@ -0,0 +1,204 @@
+@block @block_activity_results
+Feature: The activity results block displays student in visible groups scores
+  In order to be display student scores
+  As a user
+  I need to see the activity results block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+      | student1 | Student | 1 | student1@example.com | S1 |
+      | student2 | Student | 2 | student2@example.com | S2 |
+      | student3 | Student | 3 | student3@example.com | S3 |
+      | student4 | Student | 4 | student4@example.com | S4 |
+      | student5 | Student | 5 | student5@example.com | S5 |
+      | student6 | Student | 6 | student6@example.com | S6 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "groups" exist:
+      | name | course | idnumber |
+      | Group 1 | C1 | G1 |
+      | Group 2 | C1 | G2 |
+      | Group 3 | C1 | G3 |
+      | Group 4 | C1 | G4 |
+      | Group 5 | C1 | G5 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+      | student2 | C1 | student |
+      | student3 | C1 | student |
+      | student4 | C1 | student |
+      | student5 | C1 | student |
+      | student6 | C1 | student |
+    And the following "group members" exist:
+      | user     | group   |
+      | student1 | G1 |
+      | student2 | G1 |
+      | student3 | G2 |
+      | student4 | G2 |
+      | student5 | G3 |
+      | student6 | G3 |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Visible groups |
+    And I am on "Course 1" course homepage
+    And I navigate to "View > Grader report" in the course gradebook
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I am on "Course 1" course homepage
+
+  Scenario: Configure the block on the course page to show 1 high score
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 1 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 1" in the "Activity results" "block"
+    And I should see "95%" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show 1 high score as a fraction
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 1 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "Group 1" in the "Activity results" "block"
+    And I should see "95.00/100.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show 1 high score as a absolute numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 1 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "Group 1" in the "Activity results" "block"
+    And I should see "95.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores as percentages
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "Group 1" in the "Activity results" "block"
+    And I should see "95%" in the "Activity results" "block"
+    And I should see "Group 2" in the "Activity results" "block"
+    And I should see "85%" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75%" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores as fractions
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "Group 1" in the "Activity results" "block"
+    And I should see "95.00/100.00" in the "Activity results" "block"
+    And I should see "Group 2" in the "Activity results" "block"
+    And I should see "85.00/100.00" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75.00/100.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores as absolute numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "Group 1" in the "Activity results" "block"
+    And I should see "95.00" in the "Activity results" "block"
+    And I should see "Group 2" in the "Activity results" "block"
+    And I should see "85.00" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores using ID numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display only ID numbers |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "Group" in the "Activity results" "block"
+    And I should see "95.00%" in the "Activity results" "block"
+    And I should see "85.00%" in the "Activity results" "block"
+    And I should see "75.00%" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores using anonymous names
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 3 |
+      | id_config_showworst | 0 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Anonymous results |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "Group" in the "Activity results" "block"
+    And I should see "95.00%" in the "Activity results" "block"
+    And I should see "85.00%" in the "Activity results" "block"
+    And I should see "75.00%" in the "Activity results" "block"
diff --git a/activity_results/tests/behat/lowscoreswithoutgroups.feature b/activity_results/tests/behat/lowscoreswithoutgroups.feature
new file mode 100644
index 0000000..f632d95
--- /dev/null
+++ b/activity_results/tests/behat/lowscoreswithoutgroups.feature
@@ -0,0 +1,158 @@
+@block @block_activity_results
+Feature: The activity results block displays student low scores
+  In order to be display student scores
+  As a user
+  I need to see the activity results block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+      | student1 | Student | 1 | student1@example.com | S1 |
+      | student2 | Student | 2 | student2@example.com | S2 |
+      | student3 | Student | 3 | student3@example.com | S3 |
+      | student4 | Student | 4 | student4@example.com | S4 |
+      | student5 | Student | 5 | student5@example.com | S5 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+      | student2 | C1 | student |
+      | student3 | C1 | student |
+      | student4 | C1 | student |
+      | student5 | C1 | student |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+    And I am on "Course 1" course homepage
+    And I navigate to "View > Grader report" in the course gradebook
+    And I turn editing mode on
+    And I give the grade "90.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "60.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "50.00" to the user "Student 5" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I am on "Course 1" course homepage
+
+  Scenario: Configure the block on the course page to show 1 low score
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 1 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+    And I press "Save changes"
+    Then I should see "Student 5" in the "Activity results" "block"
+    And I should see "50%" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show 1 low score as a fraction
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 1 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat | Display full names |
+    And I press "Save changes"
+    Then I should see "Student 5" in the "Activity results" "block"
+    And I should see "50.00/100.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show 1 low score as a absolute number
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 1 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+    And I press "Save changes"
+    Then I should see "Student 5" in the "Activity results" "block"
+    And I should see "50.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple low scores as percentages
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 3 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+    And I press "Save changes"
+    Then I should see "Student 5" in the "Activity results" "block"
+    And I should see "50%" in the "Activity results" "block"
+    And I should see "Student 4" in the "Activity results" "block"
+    And I should see "60%" in the "Activity results" "block"
+    And I should see "Student 3" in the "Activity results" "block"
+    And I should see "70%" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple low scores as fractions
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 3 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat | Display full names |
+    And I press "Save changes"
+    Then I should see "Student 5" in the "Activity results" "block"
+    And I should see "50.00/100.00" in the "Activity results" "block"
+    And I should see "Student 4" in the "Activity results" "block"
+    And I should see "60.00/100.00" in the "Activity results" "block"
+    And I should see "Student 3" in the "Activity results" "block"
+    And I should see "70.00/100.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple low scores as absolute numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 3 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+    And I press "Save changes"
+    Then I should see "Student 5" in the "Activity results" "block"
+    And I should see "50.00" in the "Activity results" "block"
+    And I should see "Student 4" in the "Activity results" "block"
+    And I should see "60.00" in the "Activity results" "block"
+    And I should see "Student 3" in the "Activity results" "block"
+    And I should see "70.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple low scores using ID numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 3 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display only ID numbers |
+    And I press "Save changes"
+    Then I should see "User S5" in the "Activity results" "block"
+    And I should see "50.00%" in the "Activity results" "block"
+    And I should see "User S4" in the "Activity results" "block"
+    And I should see "60.00%" in the "Activity results" "block"
+    And I should see "User S3" in the "Activity results" "block"
+    And I should see "70.00%" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple low scores using anonymous names
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 3 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Anonymous results |
+    And I press "Save changes"
+    Then I should see "User" in the "Activity results" "block"
+    And I should see "50.00%" in the "Activity results" "block"
+    And I should see "60.00%" in the "Activity results" "block"
+    And I should see "70.00%" in the "Activity results" "block"
diff --git a/activity_results/tests/behat/lowscoreswithscales.feature b/activity_results/tests/behat/lowscoreswithscales.feature
new file mode 100644
index 0000000..8885d70
--- /dev/null
+++ b/activity_results/tests/behat/lowscoreswithscales.feature
@@ -0,0 +1,110 @@
+@block @block_activity_results
+Feature: The activity results block displays student low scores as scales
+  In order to be display student scores as scales
+  As a user
+  I need to see the activity results block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+      | student1 | Student | 1 | student1@example.com | S1 |
+      | student2 | Student | 2 | student2@example.com | S2 |
+      | student3 | Student | 3 | student3@example.com | S3 |
+      | student4 | Student | 4 | student4@example.com | S4 |
+      | student5 | Student | 5 | student5@example.com | S5 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+      | student2 | C1 | student |
+      | student3 | C1 | student |
+      | student4 | C1 | student |
+      | student5 | C1 | student |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage
+    And I navigate to "Scales" in the course gradebook
+    And I press "Add a new scale"
+    And I set the following fields to these values:
+      | Name | My Scale |
+      | Scale | Disappointing, Not good enough, Average, Good, Very good, Excellent! |
+    And I press "Save changes"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | id_grade_modgrade_type | Scale |
+      | id_grade_modgrade_scale | My Scale |
+    And I am on "Course 1" course homepage
+    And I navigate to "View > Grader report" in the course gradebook
+    And I turn editing mode on
+    And I give the grade "Excellent!" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "Very good" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "Good" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "Average" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "Not good enough" to the user "Student 5" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I am on "Course 1" course homepage
+
+  Scenario: Configure the block on the course page to show 1 low score
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 1 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+    And I press "Save changes"
+    Then I should see "Student 5" in the "Activity results" "block"
+    And I should see "Not good enough" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple low scores using full names
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 3 |
+      | id_config_nameformat | Display full names |
+    And I press "Save changes"
+    Then I should see "Student 5" in the "Activity results" "block"
+    And I should see "Not good enough" in the "Activity results" "block"
+    And I should see "Student 4" in the "Activity results" "block"
+    And I should see "Average" in the "Activity results" "block"
+    And I should see "Student 3" in the "Activity results" "block"
+    And I should see "Good" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple low scores using ID numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 3 |
+      | id_config_nameformat | Display only ID numbers |
+    And I press "Save changes"
+    Then I should see "User S5" in the "Activity results" "block"
+    And I should see "Not good enough" in the "Activity results" "block"
+    And I should see "User S4" in the "Activity results" "block"
+    And I should see "Average" in the "Activity results" "block"
+    And I should see "User S3" in the "Activity results" "block"
+    And I should see "Good" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple low scores using anonymous names
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 3 |
+      | id_config_nameformat | Anonymous results |
+    And I press "Save changes"
+    Then I should see "User" in the "Activity results" "block"
+    And I should not see "Student 5" in the "Activity results" "block"
+    And I should see "Not good enough" in the "Activity results" "block"
+    And I should not see "Student 4" in the "Activity results" "block"
+    And I should see "Average" in the "Activity results" "block"
+    And I should not see "Student 3" in the "Activity results" "block"
+    And I should see "Good" in the "Activity results" "block"
diff --git a/activity_results/tests/behat/lowscoreswithscalesandgroups.feature b/activity_results/tests/behat/lowscoreswithscalesandgroups.feature
new file mode 100644
index 0000000..a896714
--- /dev/null
+++ b/activity_results/tests/behat/lowscoreswithscalesandgroups.feature
@@ -0,0 +1,147 @@
+@block @block_activity_results
+Feature: The activity results block displays students in groups low scores as scales
+  In order to be display student scores as scales
+  As a user
+  I need to see the activity results block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+      | student1 | Student | 1 | student1@example.com | S1 |
+      | student2 | Student | 2 | student2@example.com | S2 |
+      | student3 | Student | 3 | student3@example.com | S3 |
+      | student4 | Student | 4 | student4@example.com | S4 |
+      | student5 | Student | 5 | student5@example.com | S5 |
+      | student6 | Student | 6 | student6@example.com | S6 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "groups" exist:
+      | name | course | idnumber |
+      | Group 1 | C1 | G1 |
+      | Group 2 | C1 | G2 |
+      | Group 3 | C1 | G3 |
+      | Group 4 | C1 | G4 |
+      | Group 5 | C1 | G5 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+      | student2 | C1 | student |
+      | student3 | C1 | student |
+      | student4 | C1 | student |
+      | student5 | C1 | student |
+      | student6 | C1 | student |
+    And the following "group members" exist:
+      | user     | group   |
+      | student1 | G1 |
+      | student2 | G1 |
+      | student3 | G2 |
+      | student4 | G2 |
+      | student5 | G3 |
+      | student6 | G3 |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage
+    And I navigate to "Scales" in the course gradebook
+    And I press "Add a new scale"
+    And I set the following fields to these values:
+      | Name | My Scale |
+      | Scale | Disappointing, Not good enough, Average, Good, Very good, Excellent! |
+    And I press "Save changes"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | id_grade_modgrade_type | Scale |
+      | id_grade_modgrade_scale | My Scale |
+      | Group mode | Separate groups |
+    And I am on "Course 1" course homepage
+    And I navigate to "View > Grader report" in the course gradebook
+    And I turn editing mode on
+    And I give the grade "Excellent!" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "Very good" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "Very good" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "Good" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "Good" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "Average" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I am on "Course 1" course homepage
+
+  Scenario: Try to configure the block on the course page to show 1 low score
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 1 |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 3" in the "Activity results" "block"
+    And I should see "Good" in the "Activity results" "block"
+    And I log out
+    And I log in as "student5"
+    And I am on "Course 1" course homepage
+    And I should see "Student 6" in the "Activity results" "block"
+    And I should see "Average" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores using full names
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 2 |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 2" in the "Activity results" "block"
+    And I should see "Very good" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "Good" in the "Activity results" "block"
+    And I log out
+    And I log in as "student3"
+    And I am on "Course 1" course homepage
+    And I should see "Student 3" in the "Activity results" "block"
+    And I should see "Very good" in the "Activity results" "block"
+    And I should see "Student 4" in the "Activity results" "block"
+    And I should see "Good" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores using ID numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 2 |
+      | id_config_nameformat | Display only ID numbers |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group" in the "Activity results" "block"
+    And I should see "Very good" in the "Activity results" "block"
+    And I should see "Good" in the "Activity results" "block"
+    And I log out
+    And I log in as "student5"
+    And I am on "Course 1" course homepage
+    And I should see "User S5" in the "Activity results" "block"
+    And I should see "Good" in the "Activity results" "block"
+    And I should see "User S6" in the "Activity results" "block"
+    And I should see "Average" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple high scores using anonymous names
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 2 |
+      | id_config_nameformat | Anonymous results |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group" in the "Activity results" "block"
+    And I should see "Very good" in the "Activity results" "block"
+    And I should see "Good" in the "Activity results" "block"
+    And I log out
+    And I log in as "student5"
+    And I am on "Course 1" course homepage
+    And I should see "User" in the "Activity results" "block"
+    And I should see "Good" in the "Activity results" "block"
+    And I should see "Average" in the "Activity results" "block"
diff --git a/activity_results/tests/behat/lowscoreswithseperategroups.feature b/activity_results/tests/behat/lowscoreswithseperategroups.feature
new file mode 100644
index 0000000..264eb8f
--- /dev/null
+++ b/activity_results/tests/behat/lowscoreswithseperategroups.feature
@@ -0,0 +1,219 @@
+@block @block_activity_results
+Feature: The activity results block displays students in separate groups scores
+  In order to be display student scores
+  As a user
+  I need to see the activity results block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+      | student1 | Student | 1 | student1@example.com | S1 |
+      | student2 | Student | 2 | student2@example.com | S2 |
+      | student3 | Student | 3 | student3@example.com | S3 |
+      | student4 | Student | 4 | student4@example.com | S4 |
+      | student5 | Student | 5 | student5@example.com | S5 |
+      | student6 | Student | 6 | student6@example.com | S6 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "groups" exist:
+      | name | course | idnumber |
+      | Group 1 | C1 | G1 |
+      | Group 2 | C1 | G2 |
+      | Group 3 | C1 | G3 |
+      | Group 4 | C1 | G4 |
+      | Group 5 | C1 | G5 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+      | student2 | C1 | student |
+      | student3 | C1 | student |
+      | student4 | C1 | student |
+      | student5 | C1 | student |
+      | student6 | C1 | student |
+    And the following "group members" exist:
+      | user     | group   |
+      | student1 | G1 |
+      | student2 | G1 |
+      | student3 | G2 |
+      | student4 | G2 |
+      | student5 | G3 |
+      | student6 | G3 |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Separate groups |
+    And I am on "Course 1" course homepage
+    And I navigate to "View > Grader report" in the course gradebook
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I am on "Course 1" course homepage
+
+  Scenario: Configure the block on the course page to show 1 low score
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 1 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 3" in the "Activity results" "block"
+    And I should see "75%" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show 1 low score as a fraction
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 1 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 3" in the "Activity results" "block"
+    And I should see "75.00/100.00" in the "Activity results" "block"
+    And I log out
+    And I log in as "student5"
+    And I am on "Course 1" course homepage
+    And I should see "Student 6" in the "Activity results" "block"
+    And I should see "70.00/100.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show 1 low score as a absolute numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 1 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 3" in the "Activity results" "block"
+    And I should see "75.00" in the "Activity results" "block"
+    And I log out
+    And I log in as "student5"
+    And I am on "Course 1" course homepage
+    And I should see "Student 6" in the "Activity results" "block"
+    And I should see "70.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple low scores as percentages
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 2 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 2" in the "Activity results" "block"
+    And I should see "85%" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75%" in the "Activity results" "block"
+    And I log out
+    And I log in as "student5"
+    And I am on "Course 1" course homepage
+    And I should see "Student 6" in the "Activity results" "block"
+    And I should see "70%" in the "Activity results" "block"
+    And I should see "Student 5" in the "Activity results" "block"
+    And I should see "80%" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple low scores as fractions
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 2 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 2" in the "Activity results" "block"
+    And I should see "85.00/100.00" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75.00/100.00" in the "Activity results" "block"
+    And I log out
+    And I log in as "student3"
+    And I am on "Course 1" course homepage
+    And I should see "Student 3" in the "Activity results" "block"
+    And I should see "90.00/100.00" in the "Activity results" "block"
+    And I should see "Student 4" in the "Activity results" "block"
+    And I should see "80.00/100.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple low scores as absolute numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 2 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 2" in the "Activity results" "block"
+    And I should see "85.00" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75.00" in the "Activity results" "block"
+    And I log out
+    And I log in as "student5"
+    And I am on "Course 1" course homepage
+    And I should see "Student 5" in the "Activity results" "block"
+    And I should see "80.00" in the "Activity results" "block"
+    And I should see "Student 6" in the "Activity results" "block"
+    And I should see "70.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple low scores using ID numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 2 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display only ID numbers |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group" in the "Activity results" "block"
+    And I should see "85.00%" in the "Activity results" "block"
+    And I should see "75.00%" in the "Activity results" "block"
+    And I log out
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "User S1" in the "Activity results" "block"
+    And I should see "100.00%" in the "Activity results" "block"
+    And I should see "User S2" in the "Activity results" "block"
+    And I should see "90.00%" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple low scores using anonymous names
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 2 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Anonymous results |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group" in the "Activity results" "block"
+    And I should see "85.00%" in the "Activity results" "block"
+    And I should see "75.00%" in the "Activity results" "block"
+    And I log out
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "User" in the "Activity results" "block"
+    And I should see "100.00%" in the "Activity results" "block"
+    And I should see "90.00%" in the "Activity results" "block"
diff --git a/activity_results/tests/behat/lowscoreswithvisiblegroups.feature b/activity_results/tests/behat/lowscoreswithvisiblegroups.feature
new file mode 100644
index 0000000..4652500
--- /dev/null
+++ b/activity_results/tests/behat/lowscoreswithvisiblegroups.feature
@@ -0,0 +1,200 @@
+@block @block_activity_results
+Feature: The activity results block displays student in visible groups low scores
+  In order to be display student scores
+  As a user
+  I need to see the activity results block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+      | student1 | Student | 1 | student1@example.com | S1 |
+      | student2 | Student | 2 | student2@example.com | S2 |
+      | student3 | Student | 3 | student3@example.com | S3 |
+      | student4 | Student | 4 | student4@example.com | S4 |
+      | student5 | Student | 5 | student5@example.com | S5 |
+      | student6 | Student | 6 | student6@example.com | S6 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "groups" exist:
+      | name | course | idnumber |
+      | Group 1 | C1 | G1 |
+      | Group 2 | C1 | G2 |
+      | Group 3 | C1 | G3 |
+      | Group 4 | C1 | G4 |
+      | Group 5 | C1 | G5 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+      | student2 | C1 | student |
+      | student3 | C1 | student |
+      | student4 | C1 | student |
+      | student5 | C1 | student |
+      | student6 | C1 | student |
+    And the following "group members" exist:
+      | user     | group   |
+      | student1 | G1 |
+      | student2 | G1 |
+      | student3 | G2 |
+      | student4 | G2 |
+      | student5 | G3 |
+      | student6 | G3 |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+      | Group mode | Visible groups |
+    And I am on "Course 1" course homepage
+    And I navigate to "View > Grader report" in the course gradebook
+    And I turn editing mode on
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
+    And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
+    And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
+    And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
+    And I press "Save changes"
+    And I am on "Course 1" course homepage
+
+  Scenario: Configure the block on the course page to show 1 low score
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 1 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 3" in the "Activity results" "block"
+    And I should see "75%" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show 1 low score as a fraction
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 1 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75.00/100.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show 1 low score as a absolute numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 1 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple low scores as percentages
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 2 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display full names |
+      | id_config_decimalpoints | 0 |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    Then I should see "Group 2" in the "Activity results" "block"
+    And I should see "85%" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75%" in the "Activity results" "block"
+    And I log out
+    And I log in as "student5"
+    And I am on "Course 1" course homepage
+    Then I should see "Group 2" in the "Activity results" "block"
+    And I should see "85%" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75%" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple low scores as fractions
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 2 |
+      | id_config_gradeformat | Fractions |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "Group 2" in the "Activity results" "block"
+    And I should see "85.00/100.00" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75.00/100.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple low scores as absolute numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 2 |
+      | id_config_gradeformat | Absolute numbers |
+      | id_config_nameformat | Display full names |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "Group 2" in the "Activity results" "block"
+    And I should see "85.00" in the "Activity results" "block"
+    And I should see "Group 3" in the "Activity results" "block"
+    And I should see "75.00" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple low scores using ID numbers
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 2 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Display only ID numbers |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "Group" in the "Activity results" "block"
+    And I should see "85.00%" in the "Activity results" "block"
+    And I should see "75.00%" in the "Activity results" "block"
+
+  Scenario: Try to configure the block on the course page to show multiple low scores using anonymous names
+    Given I add the "Activity results" block
+    When I configure the "Activity results" block
+    And I set the following fields to these values:
+      | id_config_showbest | 0 |
+      | id_config_showworst | 2 |
+      | id_config_gradeformat | Percentages |
+      | id_config_nameformat | Anonymous results |
+      | id_config_usegroups | Yes |
+    And I press "Save changes"
+    And I log out
+    Then I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "Group" in the "Activity results" "block"
+    And I should see "85.00%" in the "Activity results" "block"
+    And I should see "75.00%" in the "Activity results" "block"
diff --git a/activity_results/version.php b/activity_results/version.php
new file mode 100644
index 0000000..6eb9031
--- /dev/null
+++ b/activity_results/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version information for the block_quiz_results plugin.
+ *
+ * @package    block_activity_results
+ * @copyright  2015 Stephen Bourget
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;               // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800;               // Requires this Moodle version.
+$plugin->component = 'block_activity_results'; // Full name of the plugin (used for diagnostics).
\ No newline at end of file
diff --git a/admin_bookmarks/block_admin_bookmarks.php b/admin_bookmarks/block_admin_bookmarks.php
new file mode 100644
index 0000000..c1dfa35
--- /dev/null
+++ b/admin_bookmarks/block_admin_bookmarks.php
@@ -0,0 +1,138 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Admin Bookmarks Block page.
+ *
+ * @package    block_admin_bookmarks
+ * @copyright  2011 Moodle
+ * @author     2006 vinkmar
+ *             2011 Rossiani Wijaya (updated)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * The admin bookmarks block class
+ */
+class block_admin_bookmarks extends block_base {
+
+    /** @var string */
+    public $blockname = null;
+
+    /** @var bool */
+    protected $contentgenerated = false;
+
+    /** @var bool|null */
+    protected $docked = null;
+
+    /**
+     * Set the initial properties for the block
+     */
+    function init() {
+        $this->blockname = get_class($this);
+        $this->title = get_string('pluginname', $this->blockname);
+    }
+
+    /**
+     * All multiple instances of this block
+     * @return bool Returns false
+     */
+    function instance_allow_multiple() {
+        return false;
+    }
+
+    /**
+     * Set the applicable formats for this block to all
+     * @return array
+     */
+    function applicable_formats() {
+        if (has_capability('moodle/site:config', context_system::instance())) {
+            return array('all' => true);
+        } else {
+            return array('site' => true);
+        }
+    }
+
+    /**
+     * Gets the content for this block
+     */
+    function get_content() {
+
+        global $CFG;
+
+        // First check if we have already generated, don't waste cycles
+        if ($this->contentgenerated === true) {
+            return $this->content;
+        }
+        $this->content = new stdClass();
+
+        if (get_user_preferences('admin_bookmarks')) {
+            require_once($CFG->libdir.'/adminlib.php');
+            $adminroot = admin_get_root(false, false);  // settings not required - only pages
+
+            $bookmarks = explode(',', get_user_preferences('admin_bookmarks'));
+            /// Accessibility: markup as a list.
+            $contents = array();
+            foreach($bookmarks as $bookmark) {
+                $temp = $adminroot->locate($bookmark);
+                if ($temp instanceof admin_settingpage) {
+                    $contenturl = new moodle_url('/admin/settings.php', array('section'=>$bookmark));
+                    $contentlink = html_writer::link($contenturl, $temp->visiblename);
+                    $contents[] = html_writer::tag('li', $contentlink);
+                } else if ($temp instanceof admin_externalpage) {
+                    $contenturl = new moodle_url($temp->url);
+                    $contentlink = html_writer::link($contenturl, $temp->visiblename);
+                    $contents[] = html_writer::tag('li', $contentlink);
+                }
+            }
+            $this->content->text = html_writer::tag('ol', implode('', $contents), array('class' => 'list'));
+        } else {
+            $bookmarks = array();
+        }
+
+        $this->content->footer = '';
+        $this->page->settingsnav->initialise();
+        $node = $this->page->settingsnav->get('root', navigation_node::TYPE_SITE_ADMIN);
+        if (!$node || !$node->contains_active_node()) {
+            return $this->content;
+        }
+        $section = $node->find_active_node()->key;
+
+        if ($section == 'search' || empty($section)){
+            // the search page can't be properly bookmarked at present
+            $this->content->footer = '';
+        } else if (in_array($section, $bookmarks)) {
+            $deleteurl = new moodle_url('/blocks/admin_bookmarks/delete.php', array('section'=>$section, 'sesskey'=>sesskey()));
+            $this->content->footer =  html_writer::link($deleteurl, get_string('unbookmarkthispage','admin'));
+        } else {
+            $createurl = new moodle_url('/blocks/admin_bookmarks/create.php', array('section'=>$section, 'sesskey'=>sesskey()));
+            $this->content->footer = html_writer::link($createurl, get_string('bookmarkthispage','admin'));
+        }
+
+        return $this->content;
+    }
+
+    /**
+     * Returns the role that best describes the admin bookmarks block.
+     *
+     * @return string
+     */
+    public function get_aria_role() {
+        return 'navigation';
+    }
+}
+
+
diff --git a/admin_bookmarks/classes/privacy/provider.php b/admin_bookmarks/classes/privacy/provider.php
new file mode 100644
index 0000000..ac5ef87
--- /dev/null
+++ b/admin_bookmarks/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_admin_bookmarks.
+ *
+ * @package    block_admin_bookmarks
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_admin_bookmarks\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_admin_bookmarks implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/admin_bookmarks/create.php b/admin_bookmarks/create.php
new file mode 100644
index 0000000..ab559a3
--- /dev/null
+++ b/admin_bookmarks/create.php
@@ -0,0 +1,71 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Create admin bookmarks.
+ *
+ * @package    block_admin_bookmarks
+ * @copyright  2006 vinkmar
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require('../../config.php');
+
+require_once($CFG->libdir.'/adminlib.php');
+require_login();
+$context = context_system::instance();
+$PAGE->set_context($context);
+$adminroot = admin_get_root(false, false);  // settings not required - only pages
+
+if ($section = optional_param('section', '', PARAM_SAFEDIR) and confirm_sesskey()) {
+
+    if (get_user_preferences('admin_bookmarks')) {
+        $bookmarks = explode(',', get_user_preferences('admin_bookmarks'));
+
+        if (in_array($section, $bookmarks)) {
+            print_error('bookmarkalreadyexists','admin');
+            die;
+        }
+
+    } else {
+        $bookmarks = array();
+    }
+
+    $temp = $adminroot->locate($section);
+
+    if ($temp instanceof admin_settingpage || $temp instanceof admin_externalpage) {
+        $bookmarks[] = $section;
+        $bookmarks = implode(',', $bookmarks);
+        set_user_preference('admin_bookmarks', $bookmarks);
+
+    } else {
+        print_error('invalidsection','admin');
+        die;
+    }
+
+    if ($temp instanceof admin_settingpage) {
+        redirect($CFG->wwwroot . '/' . $CFG->admin . '/settings.php?section=' . $section);
+
+    } elseif ($temp instanceof admin_externalpage) {
+        redirect($temp->url);
+    }
+
+} else {
+    print_error('invalidsection','admin');
+    die;
+}
+
+
diff --git a/admin_bookmarks/db/access.php b/admin_bookmarks/db/access.php
new file mode 100644
index 0000000..7c8b418
--- /dev/null
+++ b/admin_bookmarks/db/access.php
@@ -0,0 +1,51 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Admin bookmarks block caps.
+ *
+ * @package    block_admin_bookmarks
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/admin_bookmarks:myaddinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/my:manageblocks'
+    ),
+
+    'block/admin_bookmarks:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/admin_bookmarks/delete.php b/admin_bookmarks/delete.php
new file mode 100644
index 0000000..602ef79
--- /dev/null
+++ b/admin_bookmarks/delete.php
@@ -0,0 +1,73 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Delete admin bookmarks.
+ *
+ * @package    block_admin_bookmarks
+ * @copyright  2006 vinkmar
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require('../../config.php');
+
+require_once($CFG->libdir.'/adminlib.php');
+
+require_login();
+$context = context_system::instance();
+$PAGE->set_context($context);
+$adminroot = admin_get_root(false, false); // settings not required - only pages
+
+if ($section = optional_param('section', '', PARAM_SAFEDIR) and confirm_sesskey()) {
+
+    if (get_user_preferences('admin_bookmarks')) {
+
+        $bookmarks = explode(',', get_user_preferences('admin_bookmarks'));
+
+        $key = array_search($section, $bookmarks);
+
+        if ($key === false) {
+            print_error('nonexistentbookmark','admin');
+            die;
+        }
+
+        unset($bookmarks[$key]);
+        $bookmarks = implode(',', $bookmarks);
+        set_user_preference('admin_bookmarks', $bookmarks);
+
+        $temp = $adminroot->locate($section);
+
+        if ($temp instanceof admin_externalpage) {
+            redirect($temp->url, get_string('bookmarkdeleted','admin'));
+        } elseif ($temp instanceof admin_settingpage) {
+            redirect($CFG->wwwroot . '/' . $CFG->admin . '/settings.php?section=' . $section);
+        } else {
+            redirect($CFG->wwwroot);
+        }
+        die;
+
+
+    }
+
+    print_error('nobookmarksforuser','admin');
+    die;
+
+} else {
+    print_error('invalidsection', 'admin');
+    die;
+}
+
+
diff --git a/admin_bookmarks/lang/en/block_admin_bookmarks.php b/admin_bookmarks/lang/en/block_admin_bookmarks.php
new file mode 100644
index 0000000..956319b
--- /dev/null
+++ b/admin_bookmarks/lang/en/block_admin_bookmarks.php
@@ -0,0 +1,28 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_admin_bookmarks', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_admin_bookmarks
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['admin_bookmarks:addinstance'] = 'Add a new admin bookmarks block';
+$string['admin_bookmarks:myaddinstance'] = 'Add a new admin bookmarks block to Dashboard';
+$string['pluginname'] = 'Admin bookmarks';
+$string['privacy:metadata'] = 'The Admin bookmarks block only shows data stored in other locations.';
diff --git a/admin_bookmarks/tests/behat/bookmark_admin_pages.feature b/admin_bookmarks/tests/behat/bookmark_admin_pages.feature
new file mode 100644
index 0000000..1574fe8
--- /dev/null
+++ b/admin_bookmarks/tests/behat/bookmark_admin_pages.feature
@@ -0,0 +1,36 @@
+@block @block_admin_bookmarks
+Feature: Add a bookmarks to an admin pages
+  In order to speed up common tasks
+  As an admin
+  I need to add and access pages through bookmarks
+
+  Background:
+    Given I log in as "admin"
+    And I navigate to "Scheduled tasks" node in "Site administration > Server"
+    And I click on "Bookmark this page" "link" in the "Admin bookmarks" "block"
+    And I log out
+
+  # Test bookmark functionality using the "User profile fields" page as our bookmark.
+  Scenario: Admin page can be bookmarked
+    Given I log in as "admin"
+    And I navigate to "User profile fields" node in "Site administration > Users > Accounts"
+    When I click on "Bookmark this page" "link" in the "Admin bookmarks" "block"
+    Then I should see "User profile fields" in the "Admin bookmarks" "block"
+    # See the existing bookmark is there too.
+    And I should see "Scheduled tasks" in the "Admin bookmarks" "block"
+
+  Scenario: Admin page can be accessed through bookmarks block
+    Given I log in as "admin"
+    And I navigate to "Notifications" node in "Site administration"
+    And I click on "Scheduled tasks" "link" in the "Admin bookmarks" "block"
+    # Verify that we are on the right page.
+    Then I should see "Scheduled tasks" in the "h1" "css_element"
+
+  Scenario: Admin page can be removed from bookmarks
+    Given I log in as "admin"
+    And I navigate to "Notifications" node in "Site administration"
+    And I click on "Scheduled tasks" "link" in the "Admin bookmarks" "block"
+    When I click on "Unbookmark this page" "link" in the "Admin bookmarks" "block"
+    Then I should see "Bookmark deleted"
+    And I wait to be redirected
+    And I should not see "Scheduled tasks" in the "Admin bookmarks" "block"
diff --git a/admin_bookmarks/version.php b/admin_bookmarks/version.php
new file mode 100644
index 0000000..ee047c1
--- /dev/null
+++ b/admin_bookmarks/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_admin_bookmarks
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_admin_bookmarks'; // Full name of the plugin (used for diagnostics)
diff --git a/badges/block_badges.php b/badges/block_badges.php
new file mode 100644
index 0000000..8fb51b6
--- /dev/null
+++ b/badges/block_badges.php
@@ -0,0 +1,108 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Block for displaying earned local badges to users
+ *
+ * @package    block_badges
+ * @copyright  2012 onwards Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @author     Yuliya Bozhko <yuliya.bozhko@totaralms.com>
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once($CFG->libdir . "/badgeslib.php");
+
+/**
+ * Displays recent badges
+ */
+class block_badges extends block_base {
+
+    public function init() {
+        $this->title = get_string('pluginname', 'block_badges');
+    }
+
+    public function instance_allow_multiple() {
+        return true;
+    }
+
+    public function has_config() {
+        return false;
+    }
+
+    public function instance_allow_config() {
+        return true;
+    }
+
+    public function applicable_formats() {
+        return array(
+                'admin' => false,
+                'site-index' => true,
+                'course-view' => true,
+                'mod' => false,
+                'my' => true
+        );
+    }
+
+    public function specialization() {
+        if (empty($this->config->title)) {
+            $this->title = get_string('pluginname', 'block_badges');
+        } else {
+            $this->title = $this->config->title;
+        }
+    }
+
+    public function get_content() {
+        global $USER, $PAGE, $CFG;
+
+        if ($this->content !== null) {
+            return $this->content;
+        }
+
+        if (empty($this->config)) {
+            $this->config = new stdClass();
+        }
+
+        // Number of badges to display.
+        if (!isset($this->config->numberofbadges)) {
+            $this->config->numberofbadges = 10;
+        }
+
+        // Create empty content.
+        $this->content = new stdClass();
+        $this->content->text = '';
+
+        if (empty($CFG->enablebadges)) {
+            $this->content->text .= get_string('badgesdisabled', 'badges');
+            return $this->content;
+        }
+
+        $courseid = $this->page->course->id;
+        if ($courseid == SITEID) {
+            $courseid = null;
+        }
+
+        if ($badges = badges_get_user_badges($USER->id, $courseid, 0, $this->config->numberofbadges)) {
+            $output = $this->page->get_renderer('core', 'badges');
+            $this->content->text = $output->print_badges_list($badges, $USER->id, true);
+        } else {
+            $this->content->text .= get_string('nothingtodisplay', 'block_badges');
+        }
+
+        return $this->content;
+    }
+}
\ No newline at end of file
diff --git a/badges/classes/privacy/provider.php b/badges/classes/privacy/provider.php
new file mode 100644
index 0000000..bf9721c
--- /dev/null
+++ b/badges/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_badges.
+ *
+ * @package    block_badges
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_badges\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_badges implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/badges/db/access.php b/badges/db/access.php
new file mode 100644
index 0000000..eee5e88
--- /dev/null
+++ b/badges/db/access.php
@@ -0,0 +1,45 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Latest badges block capabilities.
+ *
+ * @package    block_badges
+ * @copyright  2012 onwards Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @author     Yuliya Bozhko <yuliya.bozhko@totaralms.com>
+ */
+
+$capabilities = array(
+        'block/badges:addinstance' => array(
+                'captype'      => 'read',
+                'contextlevel' => CONTEXT_BLOCK,
+                'archetypes' => array(
+                    'editingteacher' => CAP_ALLOW,
+                    'manager' => CAP_ALLOW
+                ),
+                'clonepermissionsfrom' => 'moodle/site:manageblocks'
+        ),
+        'block/badges:myaddinstance' => array(
+                'riskbitmask'  => RISK_PERSONAL,
+                'captype'      => 'read',
+                'contextlevel' => CONTEXT_SYSTEM,
+                'archetypes'   => array(
+                        'user' => CAP_ALLOW,
+                ),
+                'clonepermissionsfrom' => 'moodle/my:manageblocks'
+        ),
+);
\ No newline at end of file
diff --git a/badges/db/upgrade.php b/badges/db/upgrade.php
new file mode 100644
index 0000000..bb9b3cf
--- /dev/null
+++ b/badges/db/upgrade.php
@@ -0,0 +1,58 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file keeps track of upgrades to the badges block
+ *
+ * Sometimes, changes between versions involve alterations to database structures
+ * and other major things that may break installations.
+ *
+ * The upgrade function in this file will attempt to perform all the necessary
+ * actions to upgrade your older installation to the current version.
+ *
+ * If there's something it cannot do itself, it will tell you what you need to do.
+ *
+ * The commands in here will all be database-neutral, using the methods of
+ * database_manager class
+ *
+ * Please do not forget to use upgrade_set_timeout()
+ * before any action that may take longer time to finish.
+ *
+ * @since Moodle 2.8
+ * @package block_badges
+ * @copyright 2014 Andrew Davis
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Upgrade the badges block
+ * @param int $oldversion
+ * @param object $block
+ */
+function xmldb_block_badges_upgrade($oldversion, $block) {
+    global $CFG;
+
+    // Automatically generated Moodle v3.2.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.3.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.4.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    return true;
+}
diff --git a/badges/edit_form.php b/badges/edit_form.php
new file mode 100644
index 0000000..eb0767d
--- /dev/null
+++ b/badges/edit_form.php
@@ -0,0 +1,38 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Form for editing badges block instances.
+ *
+ * @package    block_badges
+ * @copyright  2012 onwards Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @author     Yuliya Bozhko <yuliya.bozhko@totaralms.com>
+ */
+
+class block_badges_edit_form extends block_edit_form {
+    protected function specific_definition($mform) {
+        $mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
+
+        $numberofbadges = array('0' => get_string('all'));
+        for ($i = 1; $i <= 20; $i++) {
+            $numberofbadges[$i] = $i;
+        }
+
+        $mform->addElement('select', 'config_numberofbadges', get_string('numbadgestodisplay', 'block_badges'), $numberofbadges);
+        $mform->setDefault('config_numberofbadges', 10);
+    }
+}
\ No newline at end of file
diff --git a/badges/lang/en/block_badges.php b/badges/lang/en/block_badges.php
new file mode 100644
index 0000000..d1cb144
--- /dev/null
+++ b/badges/lang/en/block_badges.php
@@ -0,0 +1,31 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Language file for block "badges"
+ *
+ * @package    block_badges
+ * @copyright  2012 onwards Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @author     Yuliya Bozhko <yuliya.bozhko@totaralms.com>
+ */
+
+$string['pluginname'] = 'Latest badges';
+$string['numbadgestodisplay'] = 'Number of latest badges to display';
+$string['nothingtodisplay'] = 'You have no badges to display';
+$string['badges:addinstance'] = 'Add a new My latest badges block';
+$string['badges:myaddinstance'] = 'Add a new My latest badges block to Dashboard';
+$string['privacy:metadata'] = 'The Latest badges block only shows data stored in other locations.';
diff --git a/badges/tests/behat/block_badges.feature b/badges/tests/behat/block_badges.feature
new file mode 100644
index 0000000..6586d5f
--- /dev/null
+++ b/badges/tests/behat/block_badges.feature
@@ -0,0 +1,32 @@
+@block @block_badges
+Feature: Enable Block Badges in a course without badges
+  In order to view the badges block in a course
+  As a teacher
+  I can add badges block to a course and view the contents
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+
+  Scenario: Add the block to a the course when badges are disabled
+    Given I log in as "admin"
+    And the following config values are set as admin:
+      | enablebadges | 0 |
+    And I log out
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    When I add the "Latest badges" block
+    Then I should see "Badges are not enabled on this site." in the "Latest badges" "block"
+
+  Scenario: Add the block to a the course when badges are enabled
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    When I add the "Latest badges" block
+    Then I should see "You have no badges to display" in the "Latest badges" "block"
diff --git a/badges/tests/behat/block_badges_course.feature b/badges/tests/behat/block_badges_course.feature
new file mode 100644
index 0000000..33fe576
--- /dev/null
+++ b/badges/tests/behat/block_badges_course.feature
@@ -0,0 +1,71 @@
+@block @block_badges @core_badges @_file_upload @javascript
+Feature: Enable Block Badges in a course
+  In order to enable the badges block in a course
+  As a teacher
+  I can add badges block to a course
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage
+    # Issue badge 1 of 2
+    And I navigate to "Add a new badge" node in "Course administration > Badges"
+    And I set the following fields to these values:
+      | id_name | Badge 1 |
+      | id_description | Badge 1 |
+      | id_issuername | Teacher 1 |
+    And I upload "blocks/badges/tests/fixtures/badge.png" file to "Image" filemanager
+    And I press "Create badge"
+    And I select "Manual issue by role" from the "Add badge criteria" singleselect
+    And I set the field "Teacher" to "1"
+    And I press "Save"
+    And I press "Enable access"
+    And I press "Continue"
+    And I follow "Recipients (0)"
+    And I press "Award badge"
+    And I set the field "potentialrecipients[]" to "Teacher 1 (teacher1@example.com)"
+    And I press "Award badge"
+    # Issue Badge 2 of 2
+    And I navigate to "Add a new badge" node in "Course administration > Badges"
+    And I set the following fields to these values:
+      | id_name | Badge 2 |
+      | id_description | Badge 2 |
+      | id_issuername | Teacher 1 |
+    And I upload "blocks/badges/tests/fixtures/badge.png" file to "Image" filemanager
+    And I press "Create badge"
+    And I select "Manual issue by role" from the "Add badge criteria" singleselect
+    And I set the field "Teacher" to "1"
+    And I press "Save"
+    And I press "Enable access"
+    And I press "Continue"
+    And I follow "Recipients (0)"
+    And I press "Award badge"
+    And I set the field "potentialrecipients[]" to "Teacher 1 (teacher1@example.com)"
+    And I press "Award badge"
+    And I log out
+
+  Scenario: Add the recent badges block to a course.
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    When I add the "Latest badges" block
+    Then I should see "Badge 1" in the "Latest badges" "block"
+    And I should see "Badge 2" in the "Latest badges" "block"
+
+  Scenario: Add the recent badges block to a course and limit it to only display 1 badge.
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    When I add the "Latest badges" block
+    And I configure the "Latest badges" block
+    And I set the following fields to these values:
+      | id_config_numberofbadges | 1 |
+    And I press "Save changes"
+    Then I should see "Badge 2" in the "Latest badges" "block"
+    And I should not see "Badge 1" in the "Latest badges" "block"
diff --git a/badges/tests/behat/block_badges_dashboard.feature b/badges/tests/behat/block_badges_dashboard.feature
new file mode 100644
index 0000000..2928bf3
--- /dev/null
+++ b/badges/tests/behat/block_badges_dashboard.feature
@@ -0,0 +1,38 @@
+@block @block_badges @core_badges @_file_upload @javascript
+Feature: Enable Block Badges on the dashboard and view awarded badges
+  In order to view recent badges on the dashboard
+  As a teacher
+  I can add badges block to the dashboard
+
+  Scenario: Add the recent badges block to a course.
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage
+    # Issue badge 1 of 2
+    And I navigate to "Add a new badge" node in "Course administration > Badges"
+    And I set the following fields to these values:
+      | id_name | Badge 1 |
+      | id_description | Badge 1 |
+      | id_issuername | Teacher 1 |
+    And I upload "blocks/badges/tests/fixtures/badge.png" file to "Image" filemanager
+    And I press "Create badge"
+    And I select "Manual issue by role" from the "Add badge criteria" singleselect
+    And I set the field "Teacher" to "1"
+    And I press "Save"
+    And I press "Enable access"
+    And I press "Continue"
+    And I follow "Recipients (0)"
+    And I press "Award badge"
+    And I set the field "potentialrecipients[]" to "Teacher 1 (teacher1@example.com)"
+    And I press "Award badge"
+    And I log out
+    When I log in as "teacher1"
+    Then I should see "Badge 1" in the "Latest badges" "block"
diff --git a/badges/tests/behat/block_badges_frontpage.feature b/badges/tests/behat/block_badges_frontpage.feature
new file mode 100644
index 0000000..d1daf80
--- /dev/null
+++ b/badges/tests/behat/block_badges_frontpage.feature
@@ -0,0 +1,44 @@
+@block @block_badges @core_badges @_file_upload @javascript
+Feature: Enable Block Badges on the frontpage and view awarded badges
+  In order to enable the badges block on the frontpage
+  As a admin
+  I can add badges block to the frontpage
+
+  Scenario: Add the recent badges block on the frontpage and view recent badges
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+    And I log in as "admin"
+    And I am on site homepage
+    And I navigate to "Turn editing on" node in "Front page settings"
+    And I add the "Latest badges" block
+    And I log out
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage
+    # Issue badge 1 of 2
+    And I navigate to "Add a new badge" node in "Course administration > Badges"
+    And I set the following fields to these values:
+      | id_name | Badge 1 |
+      | id_description | Badge 1 |
+      | id_issuername | Teacher 1 |
+    And I upload "blocks/badges/tests/fixtures/badge.png" file to "Image" filemanager
+    And I press "Create badge"
+    And I select "Manual issue by role" from the "Add badge criteria" singleselect
+    And I set the field "Teacher" to "1"
+    And I press "Save"
+    And I press "Enable access"
+    And I press "Continue"
+    And I follow "Recipients (0)"
+    And I press "Award badge"
+    And I set the field "potentialrecipients[]" to "Teacher 1 (teacher1@example.com)"
+    And I press "Award badge"
+    And I log out
+    When I log in as "teacher1"
+    And I am on site homepage
+    Then I should see "Badge 1" in the "Latest badges" "block"
diff --git a/badges/tests/fixtures/badge.png b/badges/tests/fixtures/badge.png
new file mode 100644
index 0000000000000000000000000000000000000000..73f2c07e52a24ed4d342635bf82c69d3ab047d79
GIT binary patch
literal 2116
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

literal 0
HcmV?d00001

diff --git a/badges/version.php b/badges/version.php
new file mode 100644
index 0000000..ff4cda3
--- /dev/null
+++ b/badges/version.php
@@ -0,0 +1,30 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_badges
+ * @copyright  2012 onwards Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @author     Yuliya Bozhko <yuliya.bozhko@totaralms.com>
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800;        // Requires this Moodle version.
+$plugin->component = 'block_badges';
diff --git a/blog_menu/block_blog_menu.php b/blog_menu/block_blog_menu.php
new file mode 100644
index 0000000..71fd422
--- /dev/null
+++ b/blog_menu/block_blog_menu.php
@@ -0,0 +1,123 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Blog Menu Block page.
+ *
+ * @package    block_blog_menu
+ * @copyright  2009 Nicolas Connault
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The blog menu block class
+ */
+class block_blog_menu extends block_base {
+
+    function init() {
+        $this->title = get_string('pluginname', 'block_blog_menu');
+    }
+
+    function instance_allow_multiple() {
+        return true;
+    }
+
+    function has_config() {
+        return false;
+    }
+
+    function applicable_formats() {
+        return array('all' => true, 'my' => false, 'tag' => false);
+    }
+
+    function instance_allow_config() {
+        return true;
+    }
+
+    function get_content() {
+        global $CFG;
+
+        // detect if blog enabled
+        if ($this->content !== NULL) {
+            return $this->content;
+        }
+
+        if (empty($CFG->enableblogs)) {
+            $this->content = new stdClass();
+            $this->content->text = '';
+            if ($this->page->user_is_editing()) {
+                $this->content->text = get_string('blogdisable', 'blog');
+            }
+            return $this->content;
+
+        } else if ($CFG->bloglevel < BLOG_GLOBAL_LEVEL and (!isloggedin() or isguestuser())) {
+            $this->content = new stdClass();
+            $this->content->text = '';
+            return $this->content;
+        }
+
+        // require necessary libs and get content
+        require_once($CFG->dirroot .'/blog/lib.php');
+
+        // Prep the content
+        $this->content = new stdClass();
+
+        $options = blog_get_all_options($this->page);
+        if (count($options) == 0) {
+            $this->content->text = '';
+            return $this->content;
+        }
+
+        // Iterate the option types
+        $menulist = array();
+        foreach ($options as $types) {
+            foreach ($types as $link) {
+                $menulist[] = html_writer::link($link['link'], $link['string']);
+            }
+            $menulist[] = '<hr />';
+        }
+        // Remove the last element (will be an HR)
+        array_pop($menulist);
+        // Display the content as a list
+        $this->content->text = html_writer::alist($menulist, array('class'=>'list'));
+
+        // Prepare the footer for this block
+        if (has_capability('moodle/blog:search', context_system::instance())) {
+            // Full-text search field
+            $form  = html_writer::tag('label', get_string('search', 'admin'), array('for'=>'blogsearchquery', 'class'=>'accesshide'));
+            $form .= html_writer::empty_tag('input', array('id'=>'blogsearchquery', 'type'=>'text', 'name'=>'search'));
+            $form .= html_writer::empty_tag('input', array('type'=>'submit', 'value'=>get_string('search')));
+            $this->content->footer = html_writer::tag('form', html_writer::tag('div', $form), array('class'=>'blogsearchform', 'method'=>'get', 'action'=>new moodle_url('/blog/index.php')));
+        } else {
+            // No footer to display
+            $this->content->footer = '';
+        }
+
+        // Return the content object
+        return $this->content;
+    }
+
+    /**
+     * Returns the role that best describes the blog menu block.
+     *
+     * @return string
+     */
+    public function get_aria_role() {
+        return 'navigation';
+    }
+}
diff --git a/blog_menu/classes/privacy/provider.php b/blog_menu/classes/privacy/provider.php
new file mode 100644
index 0000000..8850872
--- /dev/null
+++ b/blog_menu/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_blog_menu.
+ *
+ * @package    block_blog_menu
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_blog_menu\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_blog_menu implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/blog_menu/db/access.php b/blog_menu/db/access.php
new file mode 100644
index 0000000..8cbf9be
--- /dev/null
+++ b/blog_menu/db/access.php
@@ -0,0 +1,41 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Blog menu block caps.
+ *
+ * @package    block_blog_menu
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/blog_menu:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/blog_menu/lang/en/block_blog_menu.php b/blog_menu/lang/en/block_blog_menu.php
new file mode 100644
index 0000000..da6f57d
--- /dev/null
+++ b/blog_menu/lang/en/block_blog_menu.php
@@ -0,0 +1,28 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_blog_menu', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_blog_menu
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['blog_menu:addinstance'] = 'Add a new blog menu block';
+$string['pluginname'] = 'Blog menu';
+$string['privacy:metadata'] = 'The Blog menu block only shows data stored in other locations.';
diff --git a/blog_menu/tests/behat/block_blog_menu.feature b/blog_menu/tests/behat/block_blog_menu.feature
new file mode 100644
index 0000000..419406b
--- /dev/null
+++ b/blog_menu/tests/behat/block_blog_menu.feature
@@ -0,0 +1,76 @@
+@block @block_blog_menu
+Feature: Enable Block blog menu in a course
+  In order to enable the blog menu in a course
+  As a teacher
+  I can add blog menu block to a course
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+
+  Scenario: Add the block to a the course when blogs are disabled
+    Given I log in as "admin"
+    And the following config values are set as admin:
+      | enableblogs | 0 |
+    And I log out
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    When I add the "Blog menu" block
+    Then I should see "Blogging is disabled!" in the "Blog menu" "block"
+
+  Scenario: Add the block to a the course when blog associations are disabled
+    Given I log in as "admin"
+    And the following config values are set as admin:
+      | useblogassociations | 0 |
+    And I log out
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    When I add the "Blog menu" block
+    Then I should see "Blog entries" in the "Blog menu" "block"
+    And I should see "Add a new entry" in the "Blog menu" "block"
+    And I should not see "View all entries for this course" in the "Blog menu" "block"
+    And I should not see "View my entries about this course" in the "Blog menu" "block"
+    And I should not see "Add an entry about this course" in the "Blog menu" "block"
+
+  Scenario: Add the block to a the course when blog associations are enabled
+    Given I log in as "admin"
+    And the following config values are set as admin:
+      | useblogassociations | 1 |
+    And I log out
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    When I add the "Blog menu" block
+    Then I should see "Blog entries" in the "Blog menu" "block"
+    And I should see "Add a new entry" in the "Blog menu" "block"
+    And I should see "View all entries for this course" in the "Blog menu" "block"
+    And I should see "View my entries about this course" in the "Blog menu" "block"
+    And I should see "Add an entry about this course" in the "Blog menu" "block"
+
+  Scenario: Add the block to a the course when RSS is disabled
+    Given I log in as "admin"
+    And the following config values are set as admin:
+      | enablerssfeeds | 0 |
+    And I log out
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    When I add the "Blog menu" block
+    Then I should not see "Blog RSS feed" in the "Blog menu" "block"
+    And I should see "Add a new entry" in the "Blog menu" "block"
+
+  Scenario: Add the block to a the course when RSS is enabled
+    Given I log in as "admin"
+    And the following config values are set as admin:
+      | enablerssfeeds | 1 |
+    And I log out
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    When I add the "Blog menu" block
+    Then I should see "Blog RSS feed" in the "Blog menu" "block"
+    And I should see "Add a new entry" in the "Blog menu" "block"
diff --git a/blog_menu/tests/behat/block_blog_menu_activity.feature b/blog_menu/tests/behat/block_blog_menu_activity.feature
new file mode 100644
index 0000000..9a342d2
--- /dev/null
+++ b/blog_menu/tests/behat/block_blog_menu_activity.feature
@@ -0,0 +1,213 @@
+@block @block_blog_menu
+Feature: Enable Block blog menu in an activity
+  In order to enable the blog menu in an activity
+  As a teacher
+  I can add blog menu block to a course
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+      | student1 | Student | 1 | student1@example.com | S1 |
+      | student2 | Student | 2 | student2@example.com | S2 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+      | student2 | C1 | student |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment 1 |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+    And I follow "Test assignment 1"
+    And I add the "Blog menu" block
+    And I log out
+
+  Scenario: Students use the blog menu block to post blogs
+    Given I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I follow "Test assignment 1"
+    And I follow "Add a new entry"
+    When I set the following fields to these values:
+      | Entry title | S1 First Blog |
+      | Blog entry body | This is my awesome blog! |
+    And I press "Save changes"
+    Then I should see "S1 First Blog"
+    And I should see "This is my awesome blog!"
+    And I am on "Course 1" course homepage
+    And I follow "Test assignment 1"
+    And I follow "Blog entries"
+    And I should see "S1 First Blog"
+    And I should see "This is my awesome blog!"
+
+  Scenario: Students use the blog menu block to view their blogs about the activity
+    Given I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I follow "Test assignment 1"
+    And I follow "Add an entry about this Assignment"
+    And I set the following fields to these values:
+      | Entry title | S1 First Blog |
+      | Blog entry body | This is my awesome blog about this Assignment! |
+    And I press "Save changes"
+    And I should see "S1 First Blog"
+    And I should see "This is my awesome blog about this Assignment!"
+    And I should see "Associated Assignment: Test assignment 1"
+    And I log out
+    And I log in as "student2"
+    And I am on "Course 1" course homepage
+    And I follow "Test assignment 1"
+    And I follow "Add a new entry"
+    And I set the following fields to these values:
+      | Entry title | S2 Second Blog |
+      | Blog entry body | My unrelated blog! |
+    And I press "Save changes"
+    And I should see "S2 Second Blog"
+    And I should see "My unrelated blog!"
+    And I should not see "Associated Assignment: Test assignment 1"
+    And I am on "Course 1" course homepage
+    And I follow "Test assignment 1"
+    And I follow "Add an entry about this Assignment"
+    And I set the following fields to these values:
+      | Entry title | S2 First Blog |
+      | Blog entry body | My course blog is better! |
+    And I press "Save changes"
+    And I should see "S2 First Blog"
+    And I should see "My course blog is better!"
+    And I should see "Associated Assignment: Test assignment 1"
+    And I am on "Course 1" course homepage
+    And I follow "Test assignment 1"
+    When I follow "View my entries about this Assignment"
+    Then I should see "S2 First Blog"
+    And I should not see "S2 Second Blog"
+    And I should not see "S1 First Blog"
+
+  Scenario: Students use the blog menu block to view all blogs about the assignment
+    Given I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I follow "Test assignment 1"
+    And I follow "Add an entry about this Assignment"
+    And I set the following fields to these values:
+      | Entry title | S1 First Blog |
+      | Blog entry body | This is my awesome blog about this Assignment! |
+    And I press "Save changes"
+    And I should see "S1 First Blog"
+    And I should see "This is my awesome blog about this Assignment!"
+    And I should see "Associated Assignment: Test assignment 1"
+    And I log out
+    And I log in as "student2"
+    And I am on "Course 1" course homepage
+    And I follow "Test assignment 1"
+    And I follow "Add a new entry"
+    And I set the following fields to these values:
+      | Entry title | S2 Second Blog |
+      | Blog entry body | My unrelated blog! |
+    And I press "Save changes"
+    And I should see "S2 Second Blog"
+    And I should see "My unrelated blog!"
+    And I should not see "Associated Assignment: Test assignment 1"
+    And I am on "Course 1" course homepage
+    And I follow "Test assignment 1"
+    And I follow "Add an entry about this Assignment"
+    And I set the following fields to these values:
+      | Entry title | S2 First Blog |
+      | Blog entry body | My course blog is better! |
+    And I press "Save changes"
+    And I should see "S2 First Blog"
+    And I should see "My course blog is better!"
+    And I should see "Associated Assignment: Test assignment 1"
+    And I am on "Course 1" course homepage
+    And I follow "Test assignment 1"
+    When I follow "View all entries about this Assignment"
+    Then I should see "S1 First Blog"
+    And I should see "S2 First Blog"
+    And I should not see "S2 Second Blog"
+
+  Scenario: Students use the blog menu block to view all their blog entries
+    Given I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I follow "Test assignment 1"
+    And I follow "Add an entry about this Assignment"
+    And I set the following fields to these values:
+      | Entry title | S1 First Blog |
+      | Blog entry body | This is my awesome blog about this Assignment! |
+    And I press "Save changes"
+    And I should see "S1 First Blog"
+    And I should see "This is my awesome blog about this Assignment!"
+    And I should see "Associated Assignment: Test assignment 1"
+    And I log out
+    And I log in as "student2"
+    And I am on "Course 1" course homepage
+    And I follow "Test assignment 1"
+    And I follow "Add a new entry"
+    And I set the following fields to these values:
+      | Entry title | S2 Second Blog |
+      | Blog entry body | My unrelated blog! |
+    And I press "Save changes"
+    And I should see "S2 Second Blog"
+    And I should see "My unrelated blog!"
+    And I should not see "Associated Assignment: Test assignment 1"
+    And I am on "Course 1" course homepage
+    And I follow "Test assignment 1"
+    And I follow "Add an entry about this Assignment"
+    And I set the following fields to these values:
+      | Entry title | S2 First Blog |
+      | Blog entry body | My course blog is better! |
+    And I press "Save changes"
+    And I should see "S2 First Blog"
+    And I should see "My course blog is better!"
+    And I should see "Associated Assignment: Test assignment 1"
+    And I am on "Course 1" course homepage
+    And I follow "Test assignment 1"
+    When I follow "Blog entries"
+    Then I should see "S2 First Blog"
+    And I should see "S2 Second Blog"
+    And I should not see "S1 First Blog"
+
+  Scenario: Teacher searches for student blogs
+    Given I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I follow "Test assignment 1"
+    And I follow "Add an entry about this Assignment"
+    And I set the following fields to these values:
+      | Entry title | S1 First Blog |
+      | Blog entry body | This is my awesome blog about this Assignment! |
+    And I press "Save changes"
+    And I should see "S1 First Blog"
+    And I should see "This is my awesome blog about this Assignment!"
+    And I should see "Associated Assignment: Test assignment 1"
+    And I log out
+    And I log in as "student2"
+    And I am on "Course 1" course homepage
+    And I follow "Test assignment 1"
+    And I follow "Add a new entry"
+    And I set the following fields to these values:
+      | Entry title | S2 Second Blog |
+      | Blog entry body | My unrelated blog! |
+    And I press "Save changes"
+    And I should see "S2 Second Blog"
+    And I should see "My unrelated blog!"
+    And I should not see "Associated Assignment: Test assignment 1"
+    And I am on "Course 1" course homepage
+    And I follow "Test assignment 1"
+    And I follow "Add an entry about this Assignment"
+    And I set the following fields to these values:
+      | Entry title | S2 First Blog |
+      | Blog entry body | My course blog is better! |
+    And I press "Save changes"
+    And I should see "S2 First Blog"
+    And I should see "My course blog is better!"
+    And I should see "Associated Assignment: Test assignment 1"
+    And I log out
+    When I log in as "teacher1"
+    And I am on "Course 1" course homepage
+    And I follow "Test assignment 1"
+    And I set the field "blogsearchquery" to "First"
+    And I press "Search"
+    Then I should see "S1 First Blog"
+    And I should see "S2 First Blog"
+    And I should not see "S2 Second Blog"
diff --git a/blog_menu/tests/behat/block_blog_menu_course.feature b/blog_menu/tests/behat/block_blog_menu_course.feature
new file mode 100644
index 0000000..39821d2
--- /dev/null
+++ b/blog_menu/tests/behat/block_blog_menu_course.feature
@@ -0,0 +1,190 @@
+@block @block_blog_menu
+Feature: Students can use block blog menu in a course
+  In order students to use the blog menu in a course
+  As a student
+  I view blog menu block in a course
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+      | student1 | Student | 1 | student1@example.com | S1 |
+      | student2 | Student | 2 | student2@example.com | S2 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+      | student2 | C1 | student |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Blog menu" block
+    And I log out
+
+  Scenario: Students use the blog menu block to post blogs
+    Given I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I follow "Add a new entry"
+    When I set the following fields to these values:
+      | Entry title | S1 First Blog |
+      | Blog entry body | This is my awesome blog! |
+    And I press "Save changes"
+    Then I should see "S1 First Blog"
+    And I should see "This is my awesome blog!"
+    And I am on "Course 1" course homepage
+    And I follow "Blog entries"
+    And I should see "S1 First Blog"
+    And I should see "This is my awesome blog!"
+
+  Scenario: Students use the blog menu block to view their blogs about the course
+    Given I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I follow "Add an entry about this course"
+    And I set the following fields to these values:
+      | Entry title | S1 First Blog |
+      | Blog entry body | This is my awesome blog about this course! |
+    And I press "Save changes"
+    And I should see "S1 First Blog"
+    And I should see "This is my awesome blog about this course!"
+    And I should see "Associated Course: C1"
+    And I log out
+    And I log in as "student2"
+    And I am on "Course 1" course homepage
+    And I follow "Add a new entry"
+    And I set the following fields to these values:
+      | Entry title | S2 Second Blog |
+      | Blog entry body | My unrelated blog! |
+    And I press "Save changes"
+    And I should see "S2 Second Blog"
+    And I should see "My unrelated blog!"
+    And I should not see "Associated Course: C1"
+    And I am on "Course 1" course homepage
+    And I follow "Add an entry about this course"
+    And I set the following fields to these values:
+      | Entry title | S2 First Blog |
+      | Blog entry body | My course blog is better! |
+    And I press "Save changes"
+    And I should see "S2 First Blog"
+    And I should see "My course blog is better!"
+    And I should see "Associated Course: C1"
+    And I am on "Course 1" course homepage
+    When I follow "View my entries about this course"
+    Then I should see "S2 First Blog"
+    And I should not see "S2 Second Blog"
+    And I should not see "S1 First Blog"
+
+  Scenario: Students use the blog menu block to view all blogs about the course
+    Given I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I follow "Add an entry about this course"
+    And I set the following fields to these values:
+      | Entry title | S1 First Blog |
+      | Blog entry body | This is my awesome blog about this course! |
+    And I press "Save changes"
+    And I should see "S1 First Blog"
+    And I should see "This is my awesome blog about this course!"
+    And I should see "Associated Course: C1"
+    And I log out
+    And I log in as "student2"
+    And I am on "Course 1" course homepage
+    And I follow "Add a new entry"
+    And I set the following fields to these values:
+      | Entry title | S2 Second Blog |
+      | Blog entry body | My unrelated blog! |
+    And I press "Save changes"
+    And I should see "S2 Second Blog"
+    And I should see "My unrelated blog!"
+    And I should not see "Associated Course: C1"
+    And I am on "Course 1" course homepage
+    And I follow "Add an entry about this course"
+    And I set the following fields to these values:
+      | Entry title | S2 First Blog |
+      | Blog entry body | My course blog is better! |
+    And I press "Save changes"
+    And I should see "S2 First Blog"
+    And I should see "My course blog is better!"
+    And I should see "Associated Course: C1"
+    And I am on "Course 1" course homepage
+    When I follow "View all entries for this course"
+    Then I should see "S1 First Blog"
+    And I should see "S2 First Blog"
+    And I should not see "S2 Second Blog"
+
+  Scenario: Students use the blog menu block to view all their blog entries
+    Given I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I follow "Add an entry about this course"
+    And I set the following fields to these values:
+      | Entry title | S1 First Blog |
+      | Blog entry body | This is my awesome blog about this course! |
+    And I press "Save changes"
+    And I should see "S1 First Blog"
+    And I should see "This is my awesome blog about this course!"
+    And I should see "Associated Course: C1"
+    And I log out
+    And I log in as "student2"
+    And I am on "Course 1" course homepage
+    And I follow "Add a new entry"
+    And I set the following fields to these values:
+      | Entry title | S2 Second Blog |
+      | Blog entry body | My unrelated blog! |
+    And I press "Save changes"
+    And I should see "S2 Second Blog"
+    And I should see "My unrelated blog!"
+    And I should not see "Associated Course: C1"
+    And I am on "Course 1" course homepage
+    And I follow "Add an entry about this course"
+    And I set the following fields to these values:
+      | Entry title | S2 First Blog |
+      | Blog entry body | My course blog is better! |
+    And I press "Save changes"
+    And I should see "S2 First Blog"
+    And I should see "My course blog is better!"
+    And I should see "Associated Course: C1"
+    And I am on "Course 1" course homepage
+    When I follow "Blog entries"
+    Then I should see "S2 First Blog"
+    And I should see "S2 Second Blog"
+    And I should not see "S1 First Blog"
+
+  Scenario: Teacher searches for student blogs
+    Given I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I follow "Add an entry about this course"
+    And I set the following fields to these values:
+      | Entry title | S1 First Blog |
+      | Blog entry body | This is my awesome blog about this course! |
+    And I press "Save changes"
+    And I should see "S1 First Blog"
+    And I should see "This is my awesome blog about this course!"
+    And I should see "Associated Course: C1"
+    And I log out
+    And I log in as "student2"
+    And I am on "Course 1" course homepage
+    And I follow "Add a new entry"
+    And I set the following fields to these values:
+      | Entry title | S2 Second Blog |
+      | Blog entry body | My unrelated blog! |
+    And I press "Save changes"
+    And I should see "S2 Second Blog"
+    And I should see "My unrelated blog!"
+    And I should not see "Associated Course: C1"
+    And I am on "Course 1" course homepage
+    And I follow "Add an entry about this course"
+    And I set the following fields to these values:
+      | Entry title | S2 First Blog |
+      | Blog entry body | My course blog is better! |
+    And I press "Save changes"
+    And I should see "S2 First Blog"
+    And I should see "My course blog is better!"
+    And I should see "Associated Course: C1"
+    And I log out
+    When I log in as "teacher1"
+    And I am on "Course 1" course homepage
+    And I set the field "blogsearchquery" to "First"
+    And I press "Search"
+    Then I should see "S1 First Blog"
+    And I should see "S2 First Blog"
+    And I should not see "S2 Second Blog"
diff --git a/blog_menu/tests/behat/block_blog_menu_frontpage.feature b/blog_menu/tests/behat/block_blog_menu_frontpage.feature
new file mode 100644
index 0000000..3c2936a
--- /dev/null
+++ b/blog_menu/tests/behat/block_blog_menu_frontpage.feature
@@ -0,0 +1,30 @@
+@block @block_blog_menu
+Feature: Enable Block blog menu on the frontpage
+  In order to enable the blog menu on the frontpage
+  As an admin
+  I can add blog menu block to the frontpage
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | student1 | Student | 1 | student1@example.com | S1 |
+    And I log in as "admin"
+    And I am on site homepage
+    And I navigate to "Turn editing on" node in "Front page settings"
+    And I add the "Blog menu" block
+    And I log out
+
+  Scenario: Students use the blog menu block to post blogs
+    Given I log in as "student1"
+    And I am on site homepage
+    And I follow "Add a new entry"
+    When I set the following fields to these values:
+      | Entry title | S1 First Blog |
+      | Blog entry body | This is my awesome blog! |
+    And I press "Save changes"
+    Then I should see "S1 First Blog"
+    And I should see "This is my awesome blog!"
+    And I am on site homepage
+    And I follow "Blog entries"
+    And I should see "S1 First Blog"
+    And I should see "This is my awesome blog!"
diff --git a/blog_menu/version.php b/blog_menu/version.php
new file mode 100644
index 0000000..0d96478
--- /dev/null
+++ b/blog_menu/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_blog_menu
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_blog_menu'; // Full name of the plugin (used for diagnostics)
diff --git a/blog_recent/block_blog_recent.php b/blog_recent/block_blog_recent.php
new file mode 100644
index 0000000..80befeb
--- /dev/null
+++ b/blog_recent/block_blog_recent.php
@@ -0,0 +1,128 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Recent Blog Entries Block page.
+ *
+ * @package   block_blog_recent
+ * @copyright 2009 Nicolas Connault
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * This block simply outputs a list of links to recent blog entries, depending on
+ * the context of the current page.
+ */
+class block_blog_recent extends block_base {
+
+    function init() {
+        $this->title = get_string('pluginname', 'block_blog_recent');
+        $this->content_type = BLOCK_TYPE_TEXT;
+    }
+
+    function applicable_formats() {
+        return array('all' => true, 'my' => false, 'tag' => false);
+    }
+
+    function instance_allow_config() {
+        return true;
+    }
+
+    function get_content() {
+        global $CFG;
+
+        if ($this->content !== NULL) {
+            return $this->content;
+        }
+
+        // verify blog is enabled
+        if (empty($CFG->enableblogs)) {
+            $this->content = new stdClass();
+            $this->content->text = '';
+            if ($this->page->user_is_editing()) {
+                $this->content->text = get_string('blogdisable', 'blog');
+            }
+            return $this->content;
+
+        } else if ($CFG->bloglevel < BLOG_GLOBAL_LEVEL and (!isloggedin() or isguestuser())) {
+            $this->content = new stdClass();
+            $this->content->text = '';
+            return $this->content;
+        }
+
+        require_once($CFG->dirroot .'/blog/lib.php');
+        require_once($CFG->dirroot .'/blog/locallib.php');
+
+        if (empty($this->config)) {
+            $this->config = new stdClass();
+        }
+
+        if (empty($this->config->recentbloginterval)) {
+            $this->config->recentbloginterval = 8400;
+        }
+
+        if (empty($this->config->numberofrecentblogentries)) {
+            $this->config->numberofrecentblogentries = 4;
+        }
+
+        $this->content = new stdClass();
+        $this->content->footer = '';
+        $this->content->text = '';
+
+        $context = $this->page->context;
+
+        $url = new moodle_url('/blog/index.php');
+        $filter = array();
+        if ($context->contextlevel == CONTEXT_MODULE) {
+            $filter['module'] = $context->instanceid;
+            $a = new stdClass;
+            $a->type = get_string('modulename', $this->page->cm->modname);
+            $strview = get_string('viewallmodentries', 'blog', $a);
+            $url->param('modid', $context->instanceid);
+        } else if ($context->contextlevel == CONTEXT_COURSE) {
+            $filter['course'] = $context->instanceid;
+            $a = new stdClass;
+            $a->type = get_string('course');
+            $strview = get_string('viewblogentries', 'blog', $a);
+            $url->param('courseid', $context->instanceid);
+        } else {
+            $strview = get_string('viewsiteentries', 'blog');
+        }
+        $filter['since'] = $this->config->recentbloginterval;
+
+        $bloglisting = new blog_listing($filter);
+        $entries = $bloglisting->get_entries(0, $this->config->numberofrecentblogentries, 4);
+
+        if (!empty($entries)) {
+            $entrieslist = array();
+            $viewblogurl = new moodle_url('/blog/index.php');
+
+            foreach ($entries as $entryid => $entry) {
+                $viewblogurl->param('entryid', $entryid);
+                $entrylink = html_writer::link($viewblogurl, shorten_text($entry->subject));
+                $entrieslist[] = $entrylink;
+            }
+
+            $this->content->text .= html_writer::alist($entrieslist, array('class'=>'list'));
+            $viewallentrieslink = html_writer::link($url, $strview);
+            $this->content->text .= $viewallentrieslink;
+        } else {
+            $this->content->text .= get_string('norecentblogentries', 'block_blog_recent');
+        }
+    }
+}
diff --git a/blog_recent/classes/privacy/provider.php b/blog_recent/classes/privacy/provider.php
new file mode 100644
index 0000000..2b33898
--- /dev/null
+++ b/blog_recent/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_blog_recent.
+ *
+ * @package    block_blog_recent
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_blog_recent\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_blog_recent implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/blog_recent/db/access.php b/blog_recent/db/access.php
new file mode 100644
index 0000000..c501ac7
--- /dev/null
+++ b/blog_recent/db/access.php
@@ -0,0 +1,41 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Blog recent block caps.
+ *
+ * @package    block_blog_recent
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/blog_recent:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/blog_recent/edit_form.php b/blog_recent/edit_form.php
new file mode 100644
index 0000000..6583ba8
--- /dev/null
+++ b/blog_recent/edit_form.php
@@ -0,0 +1,61 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Form for editing tag block instances.
+ *
+ * @package   block_blog_recent
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Form for editing tag block instances.
+ *
+ * @package   block_blog_recent
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class block_blog_recent_edit_form extends block_edit_form {
+    protected function specific_definition($mform) {
+        // Fields for editing HTML block title and contents.
+        $mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
+
+        $numberofentries = array();
+        for ($i = 1; $i <= 20; $i++) {
+            $numberofentries[$i] = $i;
+        }
+
+        $mform->addElement('select', 'config_numberofrecentblogentries', get_string('numentriestodisplay', 'block_blog_recent'), $numberofentries);
+        $mform->setDefault('config_numberofrecentblogentries', 4);
+
+
+        $intervals = array(
+                7200 => get_string('numhours', '', 2),
+                14400 => get_string('numhours', '', 4),
+                21600 => get_string('numhours', '', 6),
+                43200 => get_string('numhours', '', 12),
+                86400 => get_string('numhours', '', 24),
+                172800 => get_string('numdays', '', 2),
+                604800 => get_string('numdays', '', 7)
+                );
+
+        $mform->addElement('select', 'config_recentbloginterval', get_string('recentinterval', 'block_blog_recent'), $intervals);
+        $mform->setDefault('config_recentbloginterval', 86400);
+    }
+}
diff --git a/blog_recent/lang/en/block_blog_recent.php b/blog_recent/lang/en/block_blog_recent.php
new file mode 100644
index 0000000..021c491
--- /dev/null
+++ b/blog_recent/lang/en/block_blog_recent.php
@@ -0,0 +1,31 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_blog_recent', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_blog_recent
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['blog_recent:addinstance'] = 'Add a new recent blog entries block';
+$string['norecentblogentries'] = 'No recent entries';
+$string['numentriestodisplay'] = 'Number of recent entries to display';
+$string['pluginname'] = 'Recent blog entries';
+$string['recentinterval'] = 'Interval of time considered "recent"';
+$string['privacy:metadata'] = 'The Recent blog entries block only shows data stored in other locations.';
diff --git a/blog_recent/tests/behat/block_blog_recent.feature b/blog_recent/tests/behat/block_blog_recent.feature
new file mode 100644
index 0000000..ccb4c64
--- /dev/null
+++ b/blog_recent/tests/behat/block_blog_recent.feature
@@ -0,0 +1,32 @@
+@block @block_blog_recent
+Feature: Feature: Users can use the recent blog entries block to view recent blog entries.
+  In order to enable the recent blog entries in a course
+  As a teacher
+  I can add recent blog entries block to a course
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+
+  Scenario: Add the recent blogs block to a course when blogs are disabled
+    Given I log in as "admin"
+    And the following config values are set as admin:
+      | enableblogs | 0 |
+    And I log out
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    When I add the "Recent blog entries" block
+    Then I should see "Blogging is disabled!" in the "Recent blog entries" "block"
+
+  Scenario: Add the recent blogs block to a course when there are not any blog posts
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    When I add the "Recent blog entries" block
+    Then I should see "No recent entries" in the "Recent blog entries" "block"
diff --git a/blog_recent/tests/behat/block_blog_recent_activity.feature b/blog_recent/tests/behat/block_blog_recent_activity.feature
new file mode 100644
index 0000000..09112b7
--- /dev/null
+++ b/blog_recent/tests/behat/block_blog_recent_activity.feature
@@ -0,0 +1,115 @@
+@block @block_blog_menu @mod_assign @block_blog_recent
+Feature: Students can use the recent blog entries block to view recent entries on an activity page
+  In order to enable the recent blog entries block an activity page
+  As a teacher
+  I can add the recent blog entries block to an activity page
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+      | student1 | Student | 1 | student1@example.com | S1 |
+      | student2 | Student | 2 | student2@example.com | S2 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+      | student2 | C1 | student |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Test assignment 1 |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+    And I follow "Test assignment 1"
+    And I add the "Blog menu" block
+    And I add the "Recent blog entries" block
+    And I log out
+
+  Scenario: Students use the recent blog entries block to view blogs
+    Given I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I follow "Test assignment 1"
+    And I follow "Add an entry about this Assignment"
+    When I set the following fields to these values:
+      | Entry title | S1 First Blog |
+      | Blog entry body | This is my awesome blog! |
+    And I press "Save changes"
+    Then I should see "S1 First Blog"
+    And I should see "This is my awesome blog!"
+    And I follow "Test assignment 1"
+    And I should see "S1 First Blog"
+    And I follow "S1 First Blog"
+    And I should see "This is my awesome blog!"
+
+  Scenario: Students only see a few entries in the recent blog entries block
+    Given I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I follow "Test assignment 1"
+    And I follow "Add an entry about this Assignment"
+    # Blog 1 of 5
+    And I set the following fields to these values:
+      | Entry title | S1 First Blog |
+      | Blog entry body | This is my awesome blog! |
+    And I press "Save changes"
+    And I wait "1" seconds
+    And I follow "Test assignment 1"
+    And I follow "Add an entry about this Assignment"
+    # Blog 2 of 5
+    And I set the following fields to these values:
+      | Entry title | S1 Second Blog |
+      | Blog entry body | This is my awesome blog! |
+    And I press "Save changes"
+    And I wait "1" seconds
+    And I should see "S1 Second Blog"
+    And I should see "This is my awesome blog!"
+    And I follow "Test assignment 1"
+    And I follow "Add an entry about this Assignment"
+    # Blog 3 of 5
+    And I set the following fields to these values:
+      | Entry title | S1 Third Blog |
+      | Blog entry body | This is my awesome blog! |
+    And I press "Save changes"
+    And I wait "1" seconds
+    And I should see "S1 Third Blog"
+    And I should see "This is my awesome blog!"
+    And I follow "Test assignment 1"
+    And I follow "Add an entry about this Assignment"
+    # Blog 4 of 5
+    And I set the following fields to these values:
+      | Entry title | S1 Fourth Blog |
+      | Blog entry body | This is my awesome blog! |
+    And I press "Save changes"
+    And I wait "1" seconds
+    And I should see "S1 Fourth Blog"
+    And I should see "This is my awesome blog!"
+    And I follow "Test assignment 1"
+    And I follow "Add an entry about this Assignment"
+    # Blog 5 of 5
+    And I set the following fields to these values:
+      | Entry title | S1 Fifth Blog |
+      | Blog entry body | This is my awesome blog! |
+    And I press "Save changes"
+    And I should see "S1 Fifth Blog"
+    And I should see "This is my awesome blog!"
+    When I follow "Test assignment 1"
+    And I should not see "S1 First Blog"
+    And I should see "S1 Second Blog"
+    And I should see "S1 Third Blog"
+    And I should see "S1 Fourth Blog"
+    And I should see "S1 Fifth Blog"
+    And I follow "S1 Fifth Blog"
+    And I should see "This is my awesome blog!"
+    Then I log out
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I follow "Test assignment 1"
+    And I configure the "Recent blog entries" block
+    And I set the following fields to these values:
+      | id_config_numberofrecentblogentries | 2 |
+    And I press "Save changes"
+    And I should see "S1 Fourth Blog"
+    And I should see "S1 Fifth Blog"
diff --git a/blog_recent/tests/behat/block_blog_recent_course.feature b/blog_recent/tests/behat/block_blog_recent_course.feature
new file mode 100644
index 0000000..8814cc4
--- /dev/null
+++ b/blog_recent/tests/behat/block_blog_recent_course.feature
@@ -0,0 +1,105 @@
+@block @block_blog_menu @block_blog_recent
+Feature: Students can use the recent blog entries block to view recent entries on a course page
+  In order to enable the recent blog entries block a course page
+  As a teacher
+  I can add the recent blog entries block to a course page
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | student1 | Student | 1 | student1@example.com | S1 |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Blog menu" block
+    And I add the "Recent blog entries" block
+    And I log out
+
+  Scenario: Students use the recent blog entries block to view blogs
+    Given I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I follow "Add an entry about this course"
+    When I set the following fields to these values:
+      | Entry title | S1 First Blog |
+      | Blog entry body | This is my awesome blog! |
+    And I press "Save changes"
+    Then I should see "S1 First Blog"
+    And I should see "This is my awesome blog!"
+    And I am on "Course 1" course homepage
+    And I should see "S1 First Blog"
+    And I follow "S1 First Blog"
+    And I should see "This is my awesome blog!"
+
+  Scenario: Students only see a few entries in the recent blog entries block
+    Given I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I follow "Add an entry about this course"
+    # Blog 1 of 5
+    And I set the following fields to these values:
+      | Entry title | S1 First Blog |
+      | Blog entry body | This is my awesome blog! |
+    And I press "Save changes"
+    And I wait "1" seconds
+    And I am on "Course 1" course homepage
+    And I follow "Add an entry about this course"
+    # Blog 2 of 5
+    And I set the following fields to these values:
+      | Entry title | S1 Second Blog |
+      | Blog entry body | This is my awesome blog! |
+    And I press "Save changes"
+    And I wait "1" seconds
+    And I should see "S1 Second Blog"
+    And I should see "This is my awesome blog!"
+    And I am on "Course 1" course homepage
+    And I follow "Add an entry about this course"
+    # Blog 3 of 5
+    And I set the following fields to these values:
+      | Entry title | S1 Third Blog |
+      | Blog entry body | This is my awesome blog! |
+    And I press "Save changes"
+    And I wait "1" seconds
+    And I should see "S1 Third Blog"
+    And I should see "This is my awesome blog!"
+    And I am on "Course 1" course homepage
+    And I follow "Add an entry about this course"
+    # Blog 4 of 5
+    And I set the following fields to these values:
+      | Entry title | S1 Fourth Blog |
+      | Blog entry body | This is my awesome blog! |
+    And I press "Save changes"
+    And I wait "1" seconds
+    And I should see "S1 Fourth Blog"
+    And I should see "This is my awesome blog!"
+    And I am on "Course 1" course homepage
+    And I follow "Add an entry about this course"
+    # Blog 5 of 5
+    And I set the following fields to these values:
+      | Entry title | S1 Fifth Blog |
+      | Blog entry body | This is my awesome blog! |
+    And I press "Save changes"
+    And I should see "S1 Fifth Blog"
+    And I should see "This is my awesome blog!"
+    When I am on "Course 1" course homepage
+    And I should not see "S1 First Blog"
+    And I should see "S1 Second Blog"
+    And I should see "S1 Third Blog"
+    And I should see "S1 Fourth Blog"
+    And I should see "S1 Fifth Blog"
+    And I follow "S1 Fifth Blog"
+    And I should see "This is my awesome blog!"
+    Then I log out
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I configure the "Recent blog entries" block
+    And I set the following fields to these values:
+      | id_config_numberofrecentblogentries | 2 |
+    And I press "Save changes"
+    And I should see "S1 Fourth Blog"
+    And I should see "S1 Fifth Blog"
diff --git a/blog_recent/tests/behat/block_blog_recent_frontpage.feature b/blog_recent/tests/behat/block_blog_recent_frontpage.feature
new file mode 100644
index 0000000..3b838df
--- /dev/null
+++ b/blog_recent/tests/behat/block_blog_recent_frontpage.feature
@@ -0,0 +1,98 @@
+@block @block_blog_recent
+Feature: Feature: Students can use the recent blog entries block to view recent entries on the frontpage
+  In order to enable the recent blog entries block on the frontpage
+  As an admin
+  I can add the recent blog entries block to the frontpage
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | student1 | Student | 1 | student1@example.com | S1 |
+    And I log in as "admin"
+    And I am on site homepage
+    And I navigate to "Turn editing on" node in "Front page settings"
+    And I add the "Recent blog entries" block
+    # TODO MDL-57120 site "Blogs" link not accessible without navigation block.
+    And I add the "Navigation" block if not present
+    And I log out
+
+  Scenario: Students use the recent blog entries block to view blogs
+    Given I log in as "student1"
+    And I am on site homepage
+    And I navigate to "Site blogs" node in "Site pages"
+    And I follow "Add a new entry"
+    When I set the following fields to these values:
+      | Entry title | S1 First Blog |
+      | Blog entry body | This is my awesome blog! |
+    And I press "Save changes"
+    Then I should see "S1 First Blog"
+    And I should see "This is my awesome blog!"
+    And I am on site homepage
+    And I should see "S1 First Blog"
+    And I follow "S1 First Blog"
+    And I should see "This is my awesome blog!"
+
+  Scenario: Students only see a few entries in the recent blog entries block
+    Given I log in as "student1"
+    And I am on site homepage
+    And I navigate to "Site blogs" node in "Site pages"
+    And I follow "Add a new entry"
+    # Blog 1 of 5
+    And I set the following fields to these values:
+      | Entry title | S1 First Blog |
+      | Blog entry body | This is my awesome blog! |
+    And I press "Save changes"
+    And I wait "1" seconds
+    And I follow "Add a new entry"
+    # Blog 2 of 5
+    And I set the following fields to these values:
+      | Entry title | S1 Second Blog |
+      | Blog entry body | This is my awesome blog! |
+    And I press "Save changes"
+    And I wait "1" seconds
+    And I should see "S1 Second Blog"
+    And I should see "This is my awesome blog!"
+    And I follow "Add a new entry"
+    # Blog 3 of 5
+    And I set the following fields to these values:
+      | Entry title | S1 Third Blog |
+      | Blog entry body | This is my awesome blog! |
+    And I press "Save changes"
+    And I wait "1" seconds
+    And I should see "S1 Third Blog"
+    And I should see "This is my awesome blog!"
+    And I follow "Add a new entry"
+    # Blog 4 of 5
+    And I set the following fields to these values:
+      | Entry title | S1 Fourth Blog |
+      | Blog entry body | This is my awesome blog! |
+    And I press "Save changes"
+    And I wait "1" seconds
+    And I should see "S1 Fourth Blog"
+    And I should see "This is my awesome blog!"
+    And I follow "Add a new entry"
+    # Blog 5 of 5
+    And I set the following fields to these values:
+      | Entry title | S1 Fifth Blog |
+      | Blog entry body | This is my awesome blog! |
+    And I press "Save changes"
+    And I should see "S1 Fifth Blog"
+    And I should see "This is my awesome blog!"
+    When I am on site homepage
+    And I should not see "S1 First Blog"
+    And I should see "S1 Second Blog"
+    And I should see "S1 Third Blog"
+    And I should see "S1 Fourth Blog"
+    And I should see "S1 Fifth Blog"
+    And I follow "S1 Fifth Blog"
+    And I should see "This is my awesome blog!"
+    Then I log out
+    And I log in as "admin"
+    And I am on site homepage
+    And I navigate to "Turn editing on" node in "Front page settings"
+    And I configure the "Recent blog entries" block
+    And I set the following fields to these values:
+      | id_config_numberofrecentblogentries | 2 |
+    And I press "Save changes"
+    And I should see "S1 Fourth Blog"
+    And I should see "S1 Fifth Blog"
diff --git a/blog_recent/version.php b/blog_recent/version.php
new file mode 100644
index 0000000..60a82e8
--- /dev/null
+++ b/blog_recent/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_blog_recent
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_blog_recent'; // Full name of the plugin (used for diagnostics)
diff --git a/blog_tags/block_blog_tags.php b/blog_tags/block_blog_tags.php
new file mode 100644
index 0000000..f46bd41
--- /dev/null
+++ b/blog_tags/block_blog_tags.php
@@ -0,0 +1,229 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Blog tags block.
+ *
+ * @package    block_blog_tags
+ * @copyright  2006 Shane Elliott
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+define('BLOCK_BLOG_TAGS_DEFAULTTIMEWITHIN', 90);
+define('BLOCK_BLOG_TAGS_DEFAULTNUMBEROFTAGS', 20);
+define('BLOCK_BLOG_TAGS_DEFAULTSORT', 'name');
+
+class block_blog_tags extends block_base {
+    function init() {
+        $this->title = get_string('pluginname', 'block_blog_tags');
+    }
+
+    function instance_allow_multiple() {
+        return true;
+    }
+
+    function has_config() {
+        return false;
+    }
+
+    function applicable_formats() {
+        return array('all' => true, 'my' => false, 'tag' => false);
+    }
+
+    function instance_allow_config() {
+        return true;
+    }
+
+    function specialization() {
+
+        // load userdefined title and make sure it's never empty
+        if (empty($this->config->title)) {
+            $this->title = get_string('pluginname', 'block_blog_tags');
+        } else {
+            $this->title = $this->config->title;
+        }
+    }
+
+    function get_content() {
+        global $CFG, $SITE, $USER, $DB, $OUTPUT;
+
+        if ($this->content !== NULL) {
+            return $this->content;
+        }
+
+        // make sure blog and tags are actually enabled
+        if (empty($CFG->bloglevel)) {
+            $this->content = new stdClass();
+            $this->content->text = '';
+            if ($this->page->user_is_editing()) {
+                $this->content->text = get_string('blogdisable', 'blog');
+            }
+            return $this->content;
+
+        } else if (!core_tag_tag::is_enabled('core', 'post')) {
+            $this->content = new stdClass();
+            $this->content->text = '';
+            if ($this->page->user_is_editing()) {
+                $this->content->text = get_string('tagsaredisabled', 'tag');
+            }
+            return $this->content;
+
+        } else if ($CFG->bloglevel < BLOG_GLOBAL_LEVEL and (!isloggedin() or isguestuser())) {
+            $this->content = new stdClass();
+            $this->content->text = '';
+            return $this->content;
+        }
+
+        // require the libs and do the work
+        require_once($CFG->dirroot .'/blog/lib.php');
+
+        if (empty($this->config)) {
+            $this->config = new stdClass();
+        }
+
+        if (empty($this->config->timewithin)) {
+            $this->config->timewithin = BLOCK_BLOG_TAGS_DEFAULTTIMEWITHIN;
+        }
+        if (empty($this->config->numberoftags)) {
+            $this->config->numberoftags = BLOCK_BLOG_TAGS_DEFAULTNUMBEROFTAGS;
+        }
+        if (empty($this->config->sort)) {
+            $this->config->sort = BLOCK_BLOG_TAGS_DEFAULTSORT;
+        }
+
+        $this->content = new stdClass();
+        $this->content->text = '';
+        $this->content->footer = '';
+
+        /// Get a list of tags
+        $timewithin = time() - $this->config->timewithin * 24 * 60 * 60; /// convert to seconds
+
+        $context = $this->page->context;
+
+        // admins should be able to read all tags
+        $type = '';
+        if (!has_capability('moodle/user:readuserblogs', context_system::instance())) {
+            $type = " AND (p.publishstate = 'site' or p.publishstate='public')";
+        }
+
+        $sql  = "SELECT t.id, t.isstandard, t.rawname, t.name, COUNT(DISTINCT ti.id) AS ct
+                   FROM {tag} t, {tag_instance} ti, {post} p, {blog_association} ba
+                  WHERE t.id = ti.tagid AND p.id = ti.itemid
+                        $type
+                        AND ti.itemtype = 'post'
+                        AND ti.component = 'core'
+                        AND ti.timemodified > $timewithin";
+
+        if ($context->contextlevel == CONTEXT_MODULE) {
+            $sql .= " AND ba.contextid = $context->id AND p.id = ba.blogid ";
+        } else if ($context->contextlevel == CONTEXT_COURSE) {
+            $sql .= " AND ba.contextid = $context->id AND p.id = ba.blogid ";
+        }
+
+        $sql .= "
+               GROUP BY t.id, t.isstandard, t.name, t.rawname
+               ORDER BY ct DESC, t.name ASC";
+
+        if ($tags = $DB->get_records_sql($sql, null, 0, $this->config->numberoftags)) {
+
+        /// There are 2 things to do:
+        /// 1. tags with the same count should have the same size class
+        /// 2. however many tags we have should be spread evenly over the
+        ///    20 size classes
+
+            $totaltags  = count($tags);
+            $currenttag = 0;
+
+            $size = 20;
+            $lasttagct = -1;
+
+            $etags = array();
+            foreach ($tags as $tag) {
+
+                $currenttag++;
+
+                if ($currenttag == 1) {
+                    $lasttagct = $tag->ct;
+                    $size = 20;
+                } else if ($tag->ct != $lasttagct) {
+                    $lasttagct = $tag->ct;
+                    $size = 20 - ( (int)((($currenttag - 1) / $totaltags) * 20) );
+                }
+
+                $tag->class = ($tag->isstandard ? "standardtag " : "") . "s$size";
+                $etags[] = $tag;
+
+            }
+
+        /// Now we sort the tag display order
+            $CFG->tagsort = $this->config->sort;
+            usort($etags, "block_blog_tags_sort");
+
+        /// Finally we create the output
+        /// Accessibility: markup as a list.
+            $this->content->text .= "\n<ul class='inline-list'>\n";
+            foreach ($etags as $tag) {
+                $blogurl = new moodle_url('/blog/index.php');
+
+                switch ($CFG->bloglevel) {
+                    case BLOG_USER_LEVEL:
+                        $blogurl->param('userid', $USER->id);
+                    break;
+
+                    default:
+                        if ($context->contextlevel == CONTEXT_MODULE) {
+                            $blogurl->param('modid', $context->instanceid);
+                        } else if ($context->contextlevel == CONTEXT_COURSE) {
+                            $blogurl->param('courseid', $context->instanceid);
+                        }
+
+                    break;
+                }
+
+                $blogurl->param('tagid', $tag->id);
+                $link = html_writer::link($blogurl, core_tag_tag::make_display_name($tag),
+                        array('class' => $tag->class,
+                            'title' => get_string('numberofentries', 'blog', $tag->ct)));
+                $this->content->text .= '<li>' . $link . '</li> ';
+            }
+            $this->content->text .= "\n</ul>\n";
+
+        }
+        return $this->content;
+    }
+}
+
+function block_blog_tags_sort($a, $b) {
+    global $CFG;
+
+    if (empty($CFG->tagsort)) {
+        return 0;
+    } else {
+        $tagsort = $CFG->tagsort;
+    }
+
+    if (is_numeric($a->$tagsort)) {
+        return ($a->$tagsort == $b->$tagsort) ? 0 : ($a->$tagsort > $b->$tagsort) ? 1 : -1;
+    } elseif (is_string($a->$tagsort)) {
+        return strcmp($a->$tagsort, $b->$tagsort); //TODO: this is not compatible with UTF-8!!
+    } else {
+        return 0;
+    }
+}
+
+
diff --git a/blog_tags/classes/privacy/provider.php b/blog_tags/classes/privacy/provider.php
new file mode 100644
index 0000000..8235cd8
--- /dev/null
+++ b/blog_tags/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_blog_tags.
+ *
+ * @package    block_blog_tags
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_blog_tags\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_blog_tags implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/blog_tags/db/access.php b/blog_tags/db/access.php
new file mode 100644
index 0000000..a6f6007
--- /dev/null
+++ b/blog_tags/db/access.php
@@ -0,0 +1,41 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Blog tags block caps.
+ *
+ * @package    block_blog_tags
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/blog_tags:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/blog_tags/edit_form.php b/blog_tags/edit_form.php
new file mode 100644
index 0000000..581e0b4
--- /dev/null
+++ b/blog_tags/edit_form.php
@@ -0,0 +1,66 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Form for editing Blog tags block instances.
+ *
+ * @package   block_blog_tags
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Form for editing Blog tags block instances.
+ *
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_blog_tags_edit_form extends block_edit_form {
+    protected function specific_definition($mform) {
+        // Fields for editing HTML block title and contents.
+        $mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
+
+        $mform->addElement('text', 'config_title', get_string('configtitle', 'block_blog_tags'));
+        $mform->setDefault('config_title', get_string('blogtags', 'blog'));
+        $mform->setType('config_title', PARAM_TEXT);
+
+        $numberoftags = array();
+        for($i = 1; $i <= 50; $i++) {
+            $numberoftags[$i] = $i;
+        }
+        $mform->addElement('select', 'config_numberoftags', get_string('numberoftags', 'blog'), $numberoftags);
+        $mform->setDefault('config_numberoftags', BLOCK_BLOG_TAGS_DEFAULTNUMBEROFTAGS);
+
+        $timewithin = array(
+            10  => get_string('numdays', '', 10),
+            30  => get_string('numdays', '', 30),
+            60  => get_string('numdays', '', 60),
+            90  => get_string('numdays', '', 90),
+            120 => get_string('numdays', '', 120),
+            240 => get_string('numdays', '', 240),
+            365 => get_string('numdays', '', 365),
+        );
+        $mform->addElement('select', 'config_timewithin', get_string('timewithin', 'blog'), $timewithin);
+        $mform->setDefault('config_timewithin', BLOCK_BLOG_TAGS_DEFAULTTIMEWITHIN);
+
+        $sort = array(
+            'name' => get_string('tagtext', 'blog'),
+            'id'   => get_string('tagdatelastused', 'blog'),
+        );
+        $mform->addElement('select', 'config_sort', get_string('tagsort', 'blog'), $sort);
+        $mform->setDefault('config_sort', BLOCK_BLOG_TAGS_DEFAULTSORT);
+    }
+}
diff --git a/blog_tags/lang/en/block_blog_tags.php b/blog_tags/lang/en/block_blog_tags.php
new file mode 100644
index 0000000..298ffe6
--- /dev/null
+++ b/blog_tags/lang/en/block_blog_tags.php
@@ -0,0 +1,28 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_blog_tags', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_blog_tags
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['blog_tags:addinstance'] = 'Add a new blog tags block';
+$string['pluginname'] = 'Blog tags';
+$string['configtitle'] = 'Blog tags block title';
+$string['privacy:metadata'] = 'The Blog tags block only shows data stored in other locations.';
diff --git a/blog_tags/styles.css b/blog_tags/styles.css
new file mode 100644
index 0000000..9fc8a17
--- /dev/null
+++ b/blog_tags/styles.css
@@ -0,0 +1,68 @@
+.block_blog_tags .s20 {
+    font-size: 1.5em;
+    font-weight: bold;
+}
+
+.block_blog_tags .s19 {
+    font-size: 1.5em;
+}
+
+.block_blog_tags .s18 {
+    font-size: 1.4em;
+    font-weight: bold;
+}
+
+.block_blog_tags .s17 {
+    font-size: 1.4em;
+}
+
+.block_blog_tags .s16 {
+    font-size: 1.3em;
+    font-weight: bold;
+}
+
+.block_blog_tags .s15 {
+    font-size: 1.3em;
+}
+
+.block_blog_tags .s14 {
+    font-size: 1.2em;
+    font-weight: bold;
+}
+
+.block_blog_tags .s13 {
+    font-size: 1.2em;
+}
+
+.block_blog_tags .s12,
+.block_blog_tags .s11 {
+    font-size: 1.1em;
+    font-weight: bold;
+}
+
+.block_blog_tags .s10,
+.block_blog_tags .s9 {
+    font-size: 1.1em;
+}
+
+.block_blog_tags .s8,
+.block_blog_tags .s7 {
+    font-size: 1em;
+    font-weight: bold;
+}
+
+.block_blog_tags .s6,
+.block_blog_tags .s5 {
+    font-size: 1em;
+}
+
+.block_blog_tags .s4,
+.block_blog_tags .s3 {
+    font-size: 0.9em;
+    font-weight: bold;
+}
+
+.block_blog_tags .s2,
+.block_blog_tags .s1 {
+    font-size: 0.9em;
+}
\ No newline at end of file
diff --git a/blog_tags/tests/behat/blogtag.feature b/blog_tags/tests/behat/blogtag.feature
new file mode 100644
index 0000000..8cf6b27
--- /dev/null
+++ b/blog_tags/tests/behat/blogtag.feature
@@ -0,0 +1,55 @@
+@block @block_blog_tag @core_blog @core_tag
+Feature: Adding blog tag block
+  In order to search blog post by tag
+  As a user
+  I need to be able to use block blog tag
+
+  @javascript
+  Scenario: Adding block blog tag to the course
+    Given the following "users" exist:
+      | username | firstname | lastname | email |
+      | teacher1 | Teacher | 1 | teacher1@example.com |
+      | student1 | Student | 1 | student1@example.com |
+    And the following "courses" exist:
+      | fullname  | shortname |
+      | Course 1  | c1        |
+    And the following "tags" exist:
+      | name         | isstandard  |
+      | Neverusedtag | 1           |
+    And the following "course enrolments" exist:
+      | user     | course | role           |
+      | teacher1 | c1     | editingteacher |
+      | student1 | c1     | student        |
+    When I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Blog tags" block
+    # TODO MDL-57120 site "Blogs" link not accessible without navigation block.
+    And I add the "Navigation" block if not present
+
+    And I navigate to course participants
+    And I click on "Course blogs" "link" in the "Navigation" "block"
+    And I follow "Blog about this Course"
+    And I set the following fields to these values:
+      | Entry title                                 | Blog post from teacher    |
+      | Blog entry body                             | Teacher blog post content |
+      | Tags                                        | Cats, dogs                 |
+    And I press "Save changes"
+    And I log out
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I navigate to course participants
+    And I click on "Course blogs" "link" in the "Navigation" "block"
+    And I follow "Blog about this Course"
+    And I set the following fields to these values:
+      | Entry title                                 | Blog post from student    |
+      | Blog entry body                             | Student blog post content |
+      | Tags                                        | dogs, mice                 |
+    And I press "Save changes"
+    And I follow "c1"
+    Then I should see "Cats" in the "Blog tags" "block"
+    And I should see "dogs" in the "Blog tags" "block"
+    And I should see "mice" in the "Blog tags" "block"
+    And I click on "Cats" "link" in the "Blog tags" "block"
+    And I should see "Blog post from teacher"
+    And I should see "Teacher blog post content"
+    And I log out
diff --git a/blog_tags/version.php b/blog_tags/version.php
new file mode 100644
index 0000000..af3a7c5
--- /dev/null
+++ b/blog_tags/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_blog_tags
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_blog_tags'; // Full name of the plugin (used for diagnostics)
diff --git a/calendar_month/block_calendar_month.php b/calendar_month/block_calendar_month.php
new file mode 100644
index 0000000..00547c6
--- /dev/null
+++ b/calendar_month/block_calendar_month.php
@@ -0,0 +1,65 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Handles displaying the calendar block.
+ *
+ * @package    block_calendar_month
+ * @copyright  2004 Eloy Lafuente (stronk7) {@link http://stronk7.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_calendar_month extends block_base {
+
+    /**
+     * Initialise the block.
+     */
+    public function init() {
+        $this->title = get_string('pluginname', 'block_calendar_month');
+    }
+
+    /**
+     * Return the content of this block.
+     *
+     * @return stdClass the content
+     */
+    public function get_content() {
+        global $CFG;
+
+        require_once($CFG->dirroot.'/calendar/lib.php');
+
+        if ($this->content !== null) {
+            return $this->content;
+        }
+
+        $this->content = new stdClass;
+        $this->content->text = '';
+        $this->content->footer = '';
+
+        $courseid = $this->page->course->id;
+        $categoryid = ($this->page->context->contextlevel === CONTEXT_COURSECAT) ? $this->page->category->id : null;
+        $calendar = \calendar_information::create(time(), $courseid, $categoryid);
+        list($data, $template) = calendar_get_view($calendar, 'mini', isloggedin(), isloggedin());
+
+        $renderer = $this->page->get_renderer('core_calendar');
+        $this->content->text .= $renderer->render_from_template($template, $data);
+
+        if ($this->page->course->id != SITEID) {
+            $this->content->text .= $renderer->event_filter();
+        }
+
+        return $this->content;
+    }
+}
diff --git a/calendar_month/classes/privacy/provider.php b/calendar_month/classes/privacy/provider.php
new file mode 100644
index 0000000..0ff00af
--- /dev/null
+++ b/calendar_month/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_calendar_month.
+ *
+ * @package    block_calendar_month
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_calendar_month\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_calendar_month implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/calendar_month/db/access.php b/calendar_month/db/access.php
new file mode 100644
index 0000000..71cb0bc
--- /dev/null
+++ b/calendar_month/db/access.php
@@ -0,0 +1,51 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Calendar month block caps.
+ *
+ * @package    block_calendar_month
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/calendar_month:myaddinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/my:manageblocks'
+    ),
+
+    'block/calendar_month:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/calendar_month/db/upgrade.php b/calendar_month/db/upgrade.php
new file mode 100644
index 0000000..4403a77
--- /dev/null
+++ b/calendar_month/db/upgrade.php
@@ -0,0 +1,58 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file keeps track of upgrades to the calendar_month block
+ *
+ * Sometimes, changes between versions involve alterations to database structures
+ * and other major things that may break installations.
+ *
+ * The upgrade function in this file will attempt to perform all the necessary
+ * actions to upgrade your older installation to the current version.
+ *
+ * If there's something it cannot do itself, it will tell you what you need to do.
+ *
+ * The commands in here will all be database-neutral, using the methods of
+ * database_manager class
+ *
+ * Please do not forget to use upgrade_set_timeout()
+ * before any action that may take longer time to finish.
+ *
+ * @since Moodle 2.8
+ * @package block_calendar_month
+ * @copyright 2014 Andrew Davis
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Upgrade the calendar_month block
+ * @param int $oldversion
+ * @param object $block
+ */
+function xmldb_block_calendar_month_upgrade($oldversion, $block) {
+    global $CFG;
+
+    // Automatically generated Moodle v3.2.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.3.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.4.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    return true;
+}
diff --git a/calendar_month/lang/en/block_calendar_month.php b/calendar_month/lang/en/block_calendar_month.php
new file mode 100644
index 0000000..38aeda7
--- /dev/null
+++ b/calendar_month/lang/en/block_calendar_month.php
@@ -0,0 +1,28 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_calendar_month', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_calendar_month
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['calendar_month:addinstance'] = 'Add a new calendar block';
+$string['calendar_month:myaddinstance'] = 'Add a new calendar block to Dashboard';
+$string['pluginname'] = 'Calendar';
+$string['privacy:metadata'] = 'The Calendar block only displays existing calendar data.';
diff --git a/calendar_month/tests/behat/block_calendar_month.feature b/calendar_month/tests/behat/block_calendar_month.feature
new file mode 100644
index 0000000..bc34346
--- /dev/null
+++ b/calendar_month/tests/behat/block_calendar_month.feature
@@ -0,0 +1,195 @@
+@block @block_calendar_month
+Feature: Enable the calendar block in a course and test it's functionality
+  In order to enable the calendar block in a course
+  As a teacher
+  I can add the calendar block to a course
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+      | student1 | Student | 1 | student1@example.com | S1 |
+      | student2 | Student | 2 | student2@example.com | S2 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+      | student2 | C1 | student |
+
+  Scenario: Add the block to a the course
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    When I add the "Calendar" block
+    Then "Calendar" "block" should exist
+
+  @javascript
+  Scenario: View a global event in the calendar block
+    Given I log in as "admin"
+    And I create a calendar event with form data:
+      | id_eventtype | Site |
+      | id_name | Site Event |
+    And I log out
+    When I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Calendar" block
+    And I hover over today in the calendar
+    Then I should see "Site Event"
+
+  @javascript
+  Scenario: Filter site events in the calendar block
+    Given I log in as "admin"
+    And I create a calendar event with form data:
+      | id_eventtype | Site |
+      | id_name | Site Event |
+    And I log out
+    When I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Calendar" block
+    And I create a calendar event with form data:
+      | id_eventtype | Course |
+      | id_name | Course Event |
+    And I am on "Course 1" course homepage
+    And I follow "Hide global events"
+    And I hover over today in the calendar
+    Then I should not see "Site Event"
+    And I should see "Course Event"
+
+  @javascript
+  Scenario: View a course event in the calendar block
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Calendar" block
+    And I create a calendar event with form data:
+      | id_eventtype | Course |
+      | id_name | Course Event |
+    When I am on "Course 1" course homepage
+    And I hover over today in the calendar
+    Then I should see "Course Event"
+
+  @javascript
+  Scenario: Filter course events in the calendar block
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Calendar" block
+    And I create a calendar event with form data:
+      | id_eventtype | Course |
+      | id_name | Course Event |
+    And I am on "Course 1" course homepage
+    And I create a calendar event with form data:
+      | id_eventtype | User |
+      | id_name | User Event |
+    And I am on "Course 1" course homepage
+    And I follow "Hide course events"
+    And I hover over today in the calendar
+    Then I should not see "Course Event"
+    And I should see "User Event"
+
+  @javascript
+  Scenario: View a user event in the calendar block
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Calendar" block
+    And I create a calendar event with form data:
+      | id_eventtype | User |
+      | id_name | User Event |
+    When I am on "Course 1" course homepage
+    And I hover over today in the calendar
+    Then I should see "User Event"
+
+  @javascript
+  Scenario: Filter user events in the calendar block
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Calendar" block
+    And I create a calendar event with form data:
+      | id_eventtype | Course |
+      | id_name | Course Event |
+    And I am on "Course 1" course homepage
+    And I create a calendar event with form data:
+      | id_eventtype | User |
+      | id_name | User Event |
+    When I am on "Course 1" course homepage
+    And I follow "Hide user events"
+    And I hover over today in the calendar
+    Then I should not see "User Event"
+    And I should see "Course Event"
+
+  @javascript
+  Scenario: View a group event in the calendar block
+    Given the following "groups" exist:
+      | name    | course | idnumber |
+      | Group 1 | C1     | G1       |
+      | Group 2 | C1     | G2       |
+    And the following "group members" exist:
+      | user     | group   |
+      | student1 | G1 |
+      | student2 | G2 |
+    When I log in as "teacher1"
+    And I am on "Course 1" course homepage
+    And I navigate to "Edit settings" node in "Course administration"
+    And I set the following fields to these values:
+      | id_groupmode | Separate groups |
+      | id_groupmodeforce | Yes |
+    And I press "Save and display"
+    And I turn editing mode on
+    And I add the "Calendar" block
+    And I click on "This month" "link"
+    And I click on "New event" "button"
+    And I set the following fields to these values:
+      | id_eventtype | Group |
+      | id_name | Group Event |
+    And I set the following fields to these values:
+      | Group | Group 1 |
+    And I press "Save"
+    And I log out
+    Then I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I hover over today in the calendar
+    And I should see "Group Event"
+    And I log out
+    And I log in as "student2"
+    And I am on "Course 1" course homepage
+    And I hover over today in the calendar
+    And I should not see "Group Event"
+
+  @javascript
+  Scenario: Filter group events in the calendar block
+    Given the following "groups" exist:
+      | name    | course | idnumber |
+      | Group 1 | C1     | G1       |
+      | Group 2 | C1     | G2       |
+    And the following "group members" exist:
+      | user     | group   |
+      | student1 | G1 |
+      | student2 | G2 |
+    When I log in as "teacher1"
+    And I am on "Course 1" course homepage
+    And I navigate to "Edit settings" node in "Course administration"
+    And I set the following fields to these values:
+      | id_groupmode | Separate groups |
+      | id_groupmodeforce | Yes |
+    And I press "Save and display"
+    And I turn editing mode on
+    And I add the "Calendar" block
+    And I create a calendar event with form data:
+      | id_eventtype | Course |
+      | id_name | Course Event 1 |
+    And I am on "Course 1" course homepage
+    And I click on "This month" "link"
+    And I click on "New event" "button"
+    And I set the following fields to these values:
+      | id_eventtype | Group |
+      | id_name | Group Event 1 |
+    And I set the following fields to these values:
+      | Group | Group 1 |
+    And I press "Save"
+    And I log out
+    Then I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I follow "Hide group events"
+    And I hover over today in the calendar
+    And I should not see "Group Event 1"
+    And I should see "Course Event 1"
diff --git a/calendar_month/tests/behat/block_calendar_month_course.feature b/calendar_month/tests/behat/block_calendar_month_course.feature
new file mode 100644
index 0000000..2360572
--- /dev/null
+++ b/calendar_month/tests/behat/block_calendar_month_course.feature
@@ -0,0 +1,27 @@
+@block @block_calendar_month
+Feature: Enable the calendar block in a course
+  In order to enable the calendar block in a course
+  As a teacher
+  I can add the calendar block to a course
+
+  @javascript
+  Scenario: View a global event in the calendar block in a course
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+    When I log in as "admin"
+    And I create a calendar event with form data:
+      | id_eventtype | Site |
+      | id_name | Site Event |
+    And I log out
+    Then I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Calendar" block
+    And I hover over today in the calendar
+    And I should see "Site Event"
diff --git a/calendar_month/tests/behat/block_calendar_month_dashboard.feature b/calendar_month/tests/behat/block_calendar_month_dashboard.feature
new file mode 100644
index 0000000..aa74c43
--- /dev/null
+++ b/calendar_month/tests/behat/block_calendar_month_dashboard.feature
@@ -0,0 +1,19 @@
+@block @block_calendar_month
+Feature: View a site event on the dashboard
+  In order to view a site event
+  As a student
+  I can view the event in the calendar
+
+  @javascript
+  Scenario: View a global event in the calendar block on the dashboard
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | student1 | Student | 1 | student1@example.com | S1 |
+    And I log in as "admin"
+    And I create a calendar event with form data:
+      | id_eventtype | Site |
+      | id_name | Site Event |
+    And I log out
+    When I log in as "student1"
+    And I hover over today in the calendar
+    Then I should see "Site Event"
diff --git a/calendar_month/tests/behat/block_calendar_month_frontpage.feature b/calendar_month/tests/behat/block_calendar_month_frontpage.feature
new file mode 100644
index 0000000..b7ef68e
--- /dev/null
+++ b/calendar_month/tests/behat/block_calendar_month_frontpage.feature
@@ -0,0 +1,23 @@
+@block @block_calendar_month
+Feature: Enable the calendar block on the site front page
+  In order to enable the calendar block on the site front page
+  As an admin
+  I can add the calendar block on the site front page
+
+  @javascript
+  Scenario: View a global event in the calendar block on the front page
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | student1 | Student | 1 | student1@example.com | S1 |
+    And I log in as "admin"
+    And I am on site homepage
+    And I turn editing mode on
+    And I add the "Calendar" block
+    And I create a calendar event with form data:
+      | id_eventtype | Site |
+      | id_name | Site Event |
+    And I log out
+    When I log in as "student1"
+    And I am on site homepage
+    And I hover over today in the calendar
+    Then I should see "Site Event"
diff --git a/calendar_month/version.php b/calendar_month/version.php
new file mode 100644
index 0000000..b91baa4
--- /dev/null
+++ b/calendar_month/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_calendar_month
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_calendar_month'; // Full name of the plugin (used for diagnostics)
diff --git a/calendar_upcoming/block_calendar_upcoming.php b/calendar_upcoming/block_calendar_upcoming.php
new file mode 100644
index 0000000..137ba26
--- /dev/null
+++ b/calendar_upcoming/block_calendar_upcoming.php
@@ -0,0 +1,127 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Handles displaying the calendar upcoming events block.
+ *
+ * @package    block_calendar_upcoming
+ * @copyright  2004 Eloy Lafuente (stronk7) {@link http://stronk7.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_calendar_upcoming extends block_base {
+
+    /**
+     * Initialise the block.
+     */
+    public function init() {
+        $this->title = get_string('pluginname', 'block_calendar_upcoming');
+    }
+
+    /**
+     * Return the content of this block.
+     *
+     * @return stdClass the content
+     */
+    public function get_content() {
+        global $CFG;
+
+        require_once($CFG->dirroot.'/calendar/lib.php');
+
+        if ($this->content !== null) {
+            return $this->content;
+        }
+        $this->content = new stdClass;
+        $this->content->text = '';
+        $this->content->footer = '';
+
+        $courseid = $this->page->course->id;
+        $categoryid = ($this->page->context->contextlevel === CONTEXT_COURSECAT) ? $this->page->category->id : null;
+        $calendar = \calendar_information::create(time(), $courseid, $categoryid);
+        list($data, $template) = calendar_get_view($calendar, 'upcoming_mini');
+
+        $renderer = $this->page->get_renderer('core_calendar');
+        $this->content->text .= $renderer->render_from_template($template, $data);
+
+        $url = new \moodle_url('/calendar/view.php', ['view' => 'upcoming']);
+        if ($courseid != SITEID) {
+            $url->param('course', $this->page->course->id);
+        } else if (!empty($categoryid)) {
+            $url->param('category', $this->page->category->id);
+        }
+
+        $this->content->footer = html_writer::div(
+            html_writer::link($url, get_string('gotocalendar', 'block_calendar_upcoming')),
+            'gotocal'
+        );
+
+        return $this->content;
+    }
+
+    /**
+     * Get the upcoming event block content.
+     *
+     * @param array $events list of events
+     * @param \moodle_url|string $linkhref link to event referer
+     * @param boolean $showcourselink whether links to courses should be shown
+     * @return string|null $content html block content
+     * @deprecated since 3.4
+     */
+    public static function get_upcoming_content($events, $linkhref = null, $showcourselink = false) {
+        debugging(
+                'get_upcoming_content() is deprecated. ' .
+                'Please see block_calendar_upcoming::get_content() for the correct API usage.',
+                DEBUG_DEVELOPER
+            );
+
+        $content = '';
+        $lines = count($events);
+
+        if (!$lines) {
+            return $content;
+        }
+
+        for ($i = 0; $i < $lines; ++$i) {
+            if (!isset($events[$i]->time)) {
+                continue;
+            }
+            $events[$i] = calendar_add_event_metadata($events[$i]);
+            $content .= '<div class="event"><span class="icon c0">' . $events[$i]->icon . '</span>';
+            if (!empty($events[$i]->referer)) {
+                // That's an activity event, so let's provide the hyperlink.
+                $content .= $events[$i]->referer;
+            } else {
+                if (!empty($linkhref)) {
+                    $href = calendar_get_link_href(new \moodle_url(CALENDAR_URL . $linkhref), 0, 0, 0,
+                        $events[$i]->timestart);
+                    $href->set_anchor('event_' . $events[$i]->id);
+                    $content .= \html_writer::link($href, $events[$i]->name);
+                } else {
+                    $content .= $events[$i]->name;
+                }
+            }
+            $events[$i]->time = str_replace('&raquo;', '<br />&raquo;', $events[$i]->time);
+            if ($showcourselink && !empty($events[$i]->courselink)) {
+                $content .= \html_writer::div($events[$i]->courselink, 'course');
+            }
+            $content .= '<div class="date">' . $events[$i]->time . '</div></div>';
+            if ($i < $lines - 1) {
+                $content .= '<hr />';
+            }
+        }
+
+        return $content;
+    }
+}
diff --git a/calendar_upcoming/classes/privacy/provider.php b/calendar_upcoming/classes/privacy/provider.php
new file mode 100644
index 0000000..ae4f01a
--- /dev/null
+++ b/calendar_upcoming/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_calendar_upcoming.
+ *
+ * @package    block_calendar_upcoming
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_calendar_upcoming\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_calendar_upcoming implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/calendar_upcoming/db/access.php b/calendar_upcoming/db/access.php
new file mode 100644
index 0000000..673cf8b
--- /dev/null
+++ b/calendar_upcoming/db/access.php
@@ -0,0 +1,51 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Calendar upcoming block caps.
+ *
+ * @package    block_calendar_upcoming
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/calendar_upcoming:myaddinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/my:manageblocks'
+    ),
+
+    'block/calendar_upcoming:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/calendar_upcoming/db/upgrade.php b/calendar_upcoming/db/upgrade.php
new file mode 100644
index 0000000..dbe19a5
--- /dev/null
+++ b/calendar_upcoming/db/upgrade.php
@@ -0,0 +1,58 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file keeps track of upgrades to the calendar_upcoming block
+ *
+ * Sometimes, changes between versions involve alterations to database structures
+ * and other major things that may break installations.
+ *
+ * The upgrade function in this file will attempt to perform all the necessary
+ * actions to upgrade your older installation to the current version.
+ *
+ * If there's something it cannot do itself, it will tell you what you need to do.
+ *
+ * The commands in here will all be database-neutral, using the methods of
+ * database_manager class
+ *
+ * Please do not forget to use upgrade_set_timeout()
+ * before any action that may take longer time to finish.
+ *
+ * @since Moodle 2.8
+ * @package block_calendar_upcoming
+ * @copyright 2014 Andrew Davis
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Upgrade the calendar_upcoming block
+ * @param int $oldversion
+ * @param object $block
+ */
+function xmldb_block_calendar_upcoming_upgrade($oldversion, $block) {
+    global $CFG;
+
+    // Automatically generated Moodle v3.2.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.3.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.4.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    return true;
+}
diff --git a/calendar_upcoming/lang/en/block_calendar_upcoming.php b/calendar_upcoming/lang/en/block_calendar_upcoming.php
new file mode 100644
index 0000000..0b951f3
--- /dev/null
+++ b/calendar_upcoming/lang/en/block_calendar_upcoming.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_calendar_upcoming', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_calendar_upcoming
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['calendar_upcoming:addinstance'] = 'Add a new upcoming events block';
+$string['calendar_upcoming:myaddinstance'] = 'Add a new upcoming events block to Dashboard';
+$string['gotocalendar'] = 'Go to calendar...';
+$string['pluginname'] = 'Upcoming events';
+$string['privacy:metadata'] = 'The Upcoming events block only displays existing calendar data.';
diff --git a/calendar_upcoming/tests/behat/block_calendar_upcoming_course.feature b/calendar_upcoming/tests/behat/block_calendar_upcoming_course.feature
new file mode 100644
index 0000000..9e092bf
--- /dev/null
+++ b/calendar_upcoming/tests/behat/block_calendar_upcoming_course.feature
@@ -0,0 +1,26 @@
+@block  @block_calendar_upcoming
+Feature: Enable the upcoming events block in a course
+  In order to enable the calendar block in a course
+  As a teacher
+  I can view the event in the upcoming events block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+
+  @javascript
+  Scenario: View a global event in the calendar block
+    Given I log in as "admin"
+    And I create a calendar event with form data:
+      | id_eventtype | Site |
+      | id_name | My Site Event |
+    And I log out
+    When I log in as "teacher1"
+    Then I should see "My Site Event" in the "Upcoming events" "block"
diff --git a/calendar_upcoming/tests/behat/block_calendar_upcoming_dashboard.feature b/calendar_upcoming/tests/behat/block_calendar_upcoming_dashboard.feature
new file mode 100644
index 0000000..0b7c739
--- /dev/null
+++ b/calendar_upcoming/tests/behat/block_calendar_upcoming_dashboard.feature
@@ -0,0 +1,19 @@
+@block @block_calendar_upcoming
+Feature: View a upcoming site event on the dashboard
+  In order to view a site event
+  As a student
+  I can view the event in the upcoming events block
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | student1 | Student | 1 | student1@example.com | S1 |
+
+  @javascript
+  Scenario: View a global event in the upcoming events block on the dashboard
+    Given I log in as "admin"
+    And I create a calendar event with form data:
+      | id_eventtype | Site |
+      | id_name | My Site Event |
+    And I log out
+    When I log in as "student1"
+    Then I should see "My Site Event"
diff --git a/calendar_upcoming/tests/behat/block_calendar_upcoming_frontpage.feature b/calendar_upcoming/tests/behat/block_calendar_upcoming_frontpage.feature
new file mode 100644
index 0000000..448b710
--- /dev/null
+++ b/calendar_upcoming/tests/behat/block_calendar_upcoming_frontpage.feature
@@ -0,0 +1,24 @@
+@block @block_calendar_upcoming
+Feature: View a site event on the frontpage
+  In order to view a site event
+  As a teacher
+  I can view the event in the upcoming events block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+
+  @javascript
+  Scenario: View a global event in the upcoming events block on the frontpage
+    Given I log in as "admin"
+    And I create a calendar event with form data:
+      | id_eventtype | Site |
+      | id_name | My Site Event |
+    And I am on site homepage
+    And I navigate to "Turn editing on" node in "Front page settings"
+    And I add the "Upcoming events" block
+    And I log out
+    When I log in as "teacher1"
+    And I am on site homepage
+    Then I should see "My Site Event" in the "Upcoming events" "block"
diff --git a/calendar_upcoming/upgrade.txt b/calendar_upcoming/upgrade.txt
new file mode 100644
index 0000000..b5c14a3
--- /dev/null
+++ b/calendar_upcoming/upgrade.txt
@@ -0,0 +1,5 @@
+=== 3.4 ===
+
+* block_calendar_upcoming::get_upcoming_content has been deprecated. Please
+  update your code to use the new APIs. You can see an example of how these
+  may be used in block_calendar_upcoming::get_content().
diff --git a/calendar_upcoming/version.php b/calendar_upcoming/version.php
new file mode 100644
index 0000000..bbd4e43
--- /dev/null
+++ b/calendar_upcoming/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_calendar_upcoming
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_calendar_upcoming'; // Full name of the plugin (used for diagnostics)
diff --git a/career/README.md b/career/README.md
new file mode 100644
index 0000000..f6614c0
--- /dev/null
+++ b/career/README.md
@@ -0,0 +1,49 @@
+# Bloc parcours
+
+Plugin MOODLE de type bloc de cours qui permet d'afficher une liste de certaines activités existante du cours sur une page à part. P.ex. pour créer des parcours de niveaux, thématiques, etc. dans un cours volumineux.
+
+## Auteurs
+
+- Vrignaud Camille <cvrignaud@softia.fr>
+- Lebeau Michaël <mlebeau@softia.fr>
+- Thomas Fradet <thomas.fradet@univ-lorraine.fr>
+
+## Compatibility
+
+MOODLE 3.5
+
+Stabilité : expérimental. 
+
+## Contribution
+
+Contributors are welcom ! Please contact <iena-contact@univ-lorraine.fr>. 
+
+## Contact
+
+Pour assistance interne (Univesité de Lorraine) : <https://helpdesk.univ-lorraine.fr>. 
+
+Pour tout autre question : <iena-contact@univ-lorraine.fr>. 
+
+Other : <iena-contact@univ-lorraine.fr>. 
+
+## Fonctionnalités
+
+L'enseignant ajoute un parcours en lui donnant un nom et en sélectionnant plusieurs ressources ou activités du cours. 
+
+L'étudiant voit une liste des parcours dans le bloc. En cliquant sur le nom d'un parcours, il voit une page qui lui présente la liste des ressoures et activités du cours choisies par l'enseignant pour ce parcours. 
+
+---
+
+Teacher add a path with name and ressources and activity subset / selection from course. 
+
+Student see path list quand by clicking one of them, can access to the list of ressources and activity choosen by the teacher for this learning path. 
+
+## Problèmes connus
+
+- Affichage peu élégant de la liste des ressources et activités. 
+- Pas de possibilité de passer d'un élément à l'autre du parcours sans revenir à la page du parcours. 
+
+## Amélioration à effectuer
+
+- Améliorer l'apparence de la liste des activités et ressources d'un parcours. 
+- Permettre de consulter les éléments d'un parcours avec un meilleur enchaînement. 
diff --git a/career/block_career.php b/career/block_career.php
new file mode 100644
index 0000000..f839e5b
--- /dev/null
+++ b/career/block_career.php
@@ -0,0 +1,109 @@
+<?php
+
+/**
+ * block_career
+ *
+ *
+ * @package    block_career
+ * @category   block
+ * @copyright  2018 Softia/Université lorraine
+ * @author     vrignaud camille/ faouzi / Thomas Fradet
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class block_career extends block_base
+{
+	/**
+	 *
+	 */
+	public function init()
+	{
+		$this->title = get_string('title_plugin', 'block_career');
+	}
+	
+	/**
+	 * @return bool
+	 */
+	function instance_allow_multiple()
+	{
+		return false;
+	}
+	
+	/**
+	 * Set the applicable formats for this block to all
+	 * @return array
+	 */
+	function applicable_formats()
+	{
+		return array('course' => true);
+	}
+	
+	/**
+	 * Allow the user to configure a block instance
+	 * @return bool Returns true
+	 */
+	function instance_allow_config()
+	{
+
+	}
+	
+	/**
+	 * @return stdClass
+	 */
+	public function get_content()
+	{
+		global $CFG;
+		global $COURSE;
+		global $DB;
+		
+		if ($this->content !== null) {
+			return $this->content;
+		}
+		if (empty($this->config)) {
+			$this->config = new stdClass();
+		}
+		
+		$request = $DB->get_records_sql('SELECT * FROM {block_career} WHERE course = ?', array($COURSE->id));
+		// var_dump($request);
+		$careerId = optional_param("career", NULL, PARAM_INT);
+		$active = "";
+		
+		$this->content = new stdClass;
+		$this->content->text .= '<a href="' . $CFG->wwwroot . '/course/view.php?id=' . $COURSE->id . '"  class="btn btn-success btn-career-block mb-3">Accueil du cours</a>';
+		
+		// $image = "";
+		
+		$this->content->text .= '<div class="list-group">';
+		
+		foreach ($request as $value) {
+			
+			// if (file_get_contents("$CFG->wwwroot/blocks/career/$value->image") != null) {
+			// 	$image = "<img src='$CFG->wwwroot/blocks/career/$value->image' class='img_moodle_list'/>";
+			// }
+			
+			if ($careerId != null && $careerId == $value->id) {
+				$active = "active";
+			} else {
+				$active = "";
+			}
+			
+			$this->content->text .= "<a href='" . $CFG->wwwroot . "/blocks/career/career_unit.php?career=" . $value->id . "' class='list-group-item $active'>$value->name</a>";
+			// $this->content->text .= "<a href='" . $CFG->wwwroot . "/blocks/career/career_unit.php?career=" . $value->id . "' class='full list-group-item list-group-item-action $active'><div class=' left img_center'>$image</div>
+			// &nbsp&nbsp $value->name</a><br>";
+		}
+		
+		$this->content->text .= '</div>';
+		
+		if (empty($request)) {
+			$this->content->text .= "<p>" . get_string('any_carrer', 'block_career') . "</p>";
+		}
+		
+		$this->content->text .= '<a href="' . $CFG->wwwroot . '/blocks/career/career_list.php?course=' . $COURSE->id . '" type="button " class="btn btn-primary btn-career-block mt-3">Gérer les parcours</a>';
+		
+		// $this->content->text .= "<p></p>";
+		
+		return $this->content;
+	}
+}
+
+?>
\ No newline at end of file
diff --git a/career/career_list.php b/career/career_list.php
new file mode 100644
index 0000000..1617256
--- /dev/null
+++ b/career/career_list.php
@@ -0,0 +1,38 @@
+<?php
+	define('NO_OUTPUT_BUFFERING', true);
+	require_once('../../config.php');
+	require_once('entity/block_career_ressource.php');
+	require_once('entity/block_career_section.php');
+	require_once('view/view_career_list.php');
+	
+	global $COURSE;
+	global $USER;
+	global $DB;
+	global $CFG;
+	require_once($CFG->libdir . '/adminlib.php');
+	
+	$id_course = required_param('course', PARAM_INT);
+	
+	$url = new moodle_url('/blocks/career/career_list.php', array('course' => $id_course));
+	//Check if the user has capability to update course
+	if (!has_capability('moodle/course:update', $context = context_course::instance($id_course), $USER->id)) {
+		header("Location: {$_SERVER['HTTP_REFERER']}");
+		exit;
+	}
+	
+	$PAGE->set_url($url);
+	$PAGE->set_pagelayout('admin');
+	
+	$course = $DB->get_record('course', array('id' => $id_course), '*', MUST_EXIST);
+	require_login($course, false, NULL);
+	
+	$PAGE->set_title(get_string('title_plugin', 'block_career'));
+	$PAGE->set_heading($OUTPUT->heading($COURSE->fullname, 2, 'headingblock header outline'));
+	
+	$ressource = new block_career_ressource();
+	$section = new block_career_section();
+	echo $OUTPUT->header();
+	echo "<link rel=\"stylesheet\" type=\"text/css\" href=\"styles.css\">";
+	$content = new view_career_list();
+	echo $content->get_content();
+	echo $OUTPUT->footer();
\ No newline at end of file
diff --git a/career/career_setting.php b/career/career_setting.php
new file mode 100644
index 0000000..d0bc22a
--- /dev/null
+++ b/career/career_setting.php
@@ -0,0 +1,82 @@
+<?php
+	
+	ob_start();
+	
+	require_once('../../config.php');
+	global $COURSE, $DB, $CFG;
+	require_once("$CFG->libdir/formslib.php");
+	require_once('entity/block_career_ressource.php');
+	require_once('entity/block_career_section.php');
+	require_once('view/view_career_setting.php');
+	
+	$id_course = required_param('course', PARAM_INT);
+	$url = new moodle_url('/blocks/career/career_setting.php', array('course' => $id_course));
+	
+	$PAGE->set_pagelayout('course');
+	$PAGE->set_url($url);
+	
+	$course = $DB->get_record('course', array('id' => $id_course), '*', MUST_EXIST);
+	require_login($course, false, NULL);
+	
+	
+	$PAGE->set_title(get_string('title_plugin', 'block_career'));
+	$PAGE->set_heading($OUTPUT->heading($COURSE->fullname, 2, 'headingblock header outline'));
+	echo $OUTPUT->header();
+	$PAGE->requires->js("/blocks/career/js/jquery.min.js");
+	$PAGE->requires->js("/blocks/career/js/file.js");
+	// echo "<link rel=\"stylesheet\" type=\"text/css\" href=\"styles.css\">";
+	
+	$content = new view_career_setting();
+	echo $content->get_content();
+
+	// Delete career
+	if (isset($_GET["delete"]) && $_GET["delete"] == 1) {
+		$DB->execute("DELETE FROM {block_career} WHERE id = ?", array($_GET["id"]));
+		header("Location: $CFG->wwwroot/blocks/career/career_list.php?course=" . $_GET["course"]);
+	}
+	
+	if (!empty($_POST["careerName"])) {
+		
+		$ressourses = "";
+		
+		foreach ($_POST["ressource"] as $value) {
+			if ($value === end($_POST["ressource"])) {
+				$ressourses .= "$value";
+			} else {
+				$ressourses .= "$value,";
+			}
+		}
+		
+		//$record is use for insert/update in database
+		$record = new stdClass();
+		$record->course = intval($_GET["course"]);
+		$record->name = $_POST["careerName"];
+		$record->description = $_POST["descriptionName"]["text"];
+		
+		// if (isset($_FILES['imageName']['tmp_name'])) {
+		// 	$pathDir = "img/";
+		// 	$pathFile = $pathDir . basename($_FILES["imageName"]["name"]);
+		// 	move_uploaded_file($_FILES['imageName']['tmp_name'], $pathFile);
+		// 	$record->image = $pathFile;
+		// } else {
+		// 	$record->image = $_POST["imagePath"];
+		// }
+		$record->image = "";
+		
+		$record->ressources = $ressourses;
+		
+		if ($_POST["careerId"] != 0) {
+			$record->id = intval($_POST["careerId"]);
+			$lastinsertid = $DB->update_record('block_career', $record);
+		} else {
+			$lastinsertid = $DB->insert_record('block_career', $record);
+		}
+		
+		if ($lastinsertid != 0) {
+			header("Location: $CFG->wwwroot/blocks/career/career_list.php?course=" . $_GET["course"]);
+		}
+		
+	}
+	
+	
+	echo $OUTPUT->footer();
diff --git a/career/career_unit.php b/career/career_unit.php
new file mode 100644
index 0000000..ee633e5
--- /dev/null
+++ b/career/career_unit.php
@@ -0,0 +1,30 @@
+<?php
+	
+	require_once('../../config.php');
+	require_once('entity/block_career_ressource.php');
+	require_once('entity/block_career_section.php');
+	
+	global $COURSE, $DB;
+	
+	$careerId = required_param('career', PARAM_INT);
+	$url = new moodle_url('/blocks/career/career_unit.php', array('career' => $careerId));
+	$requete = $DB->get_record_sql('SELECT course FROM {block_career} WHERE id = ?', array($careerId));
+	
+	$PAGE->set_pagelayout('course');
+	$PAGE->set_url($url);
+	
+	// Getting DB data for the course
+	$course = $DB->get_record('course', array('id' => $requete->course), '*', MUST_EXIST);
+	// Must be logged in
+	require_login($course, false, NULL);
+	
+	$PAGE->set_title(get_string('title_plugin', 'block_career'));
+	$PAGE->set_heading($OUTPUT->heading($COURSE->fullname, 2, 'headingblock header outline'));
+	echo $OUTPUT->header();
+	$PAGE->requires->js("/blocks/career/js/jquery.min.js");
+	$PAGE->requires->js("/blocks/career/js/file.js");
+	echo "<link rel=\"stylesheet\" type=\"text/css\" href=\"styles.css\">";
+	
+	require_once('view/view_career_unit.php');
+	
+	echo $OUTPUT->footer();
diff --git a/career/db/access.php b/career/db/access.php
new file mode 100644
index 0000000..f1dfeb2
--- /dev/null
+++ b/career/db/access.php
@@ -0,0 +1,25 @@
+<?php
+$capabilities = array(
+
+	'block/career:myaddinstance' => array(
+		'captype' => 'write',
+		'contextlevel' => CONTEXT_SYSTEM,
+		'archetypes' => array(
+			'editingteacher' => CAP_ALLOW,
+			'manager' => CAP_ALLOW
+		),
+		'clonepermissionsfrom' => 'moodle/my:manageblocks'
+	),
+
+	'block/career:addinstance' => array(
+		'riskbitmask' => RISK_SPAM | RISK_XSS,
+		'captype' => 'write',
+		'contextlevel' => CONTEXT_BLOCK,
+		'archetypes' => array(
+			'editingteacher' => CAP_ALLOW,
+			'manager' => CAP_ALLOW
+		),
+		'clonepermissionsfrom' => 'moodle/site:manageblocks'
+	),
+);
+?>
\ No newline at end of file
diff --git a/career/db/install.xml b/career/db/install.xml
new file mode 100644
index 0000000..2ec15b6
--- /dev/null
+++ b/career/db/install.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<XMLDB PATH="blocks/career/db" VERSION="20180212" COMMENT="XMLDB file for Moodle blocks/career"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
+>
+  <TABLES>
+    <TABLE NAME="block_career" COMMENT="Table du block parcours">
+      <FIELDS>
+        <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
+        <FIELD NAME="course" TYPE="int" LENGTH="8" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
+        <FIELD NAME="name" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
+        <FIELD NAME="description" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
+        <FIELD NAME="ressources" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
+        <FIELD NAME="image" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
+      </FIELDS>
+      <KEYS>
+        <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
+      </KEYS>
+    </TABLE>
+  </TABLES>
+</XMLDB>
\ No newline at end of file
diff --git a/career/edit_form.php b/career/edit_form.php
new file mode 100644
index 0000000..e0a49d0
--- /dev/null
+++ b/career/edit_form.php
@@ -0,0 +1,20 @@
+<?php
+	if (!defined('MOODLE_INTERNAL'))
+		die('Direct access to this script is forbidden.');
+	
+	class block_career_edit_form extends block_edit_form
+	{
+		
+		/**
+		 * @param $mform
+		 */
+		function specific_definition($mform)
+		{
+			// Adding an element to the form
+			$mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
+		}
+	}
+
+?>
+
+
diff --git a/career/entity/block_career_ressource.php b/career/entity/block_career_ressource.php
new file mode 100644
index 0000000..3a20667
--- /dev/null
+++ b/career/entity/block_career_ressource.php
@@ -0,0 +1,108 @@
+<?php
+	/**
+	 * The iena filter plugin transforms the moodle resource links
+	 * into a button that opens the resource in a modal
+	 *
+	 * @package    block_career
+	 * @category   block
+	 * @copyright  2018 Softia/Université lorraine
+	 * @author     vrignaud camille/ faouzi
+	 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+	 */
+	
+	/**
+	 *  block_career_ressource
+	 *
+	 *
+	 * @package    filter_iena
+	 * @copyright  2018 Softia/Université lorraine
+	 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+	 */
+	class block_career_ressource
+	{
+		
+		/** @var int Id of ressource */
+		public $id;
+		/** @var string name of ressource */
+		public $name;
+		/** @var string link of ressource */
+		public $link;
+		/** @var string type of ressource */
+		public $type;
+		/** @var int module id of ressource */
+		public $module;
+		/** @var string intro of ressource */
+		public $descrition;
+		/** @var block_career_section section of ressource */
+		public $section;
+		
+		/**
+		 * Set $id, $name, $type
+		 * @param array $id_course_modules
+		 *
+		 * @return void
+		 */
+		public function get_ressource_by_id($id_course_modules)
+		{
+			
+			global $DB;
+			if ($id_course_modules) {
+				$this->id = $id_course_modules;
+				$requete = $DB->get_record_sql('SELECT * FROM {course_modules} WHERE id = ? AND deletioninprogress = 0', array($id_course_modules));
+				$id_instance = $requete->instance;
+				$id_module = $requete->module;
+				if ($id_module) {
+					$modules = $DB->get_record_sql('SELECT * FROM {modules} WHERE id = ?', array($id_module));
+				}
+				if ($modules->name) {
+					$instance = $DB->get_record_sql('SELECT * FROM {' . $modules->name . '} WHERE id = ?', array($id_instance));
+				}
+				if ($instance->name) {
+					$this->name = $instance->name;
+				}
+				$this->descrition = $instance->intro;
+				$this->type = $modules->name;
+				$this->module = $modules->id;
+				$this->section = new block_career_section();
+				$this->section->get_section_by_id_section($requete->section);
+				$this->create_link();
+			}
+		}
+		
+		/**
+		 * Get all ressources in a section
+		 * return a array
+		 * @param array $id_section
+		 *
+		 * @return array<block_career_ressource> $ressources
+		 */
+		public function get_ressources_by_id_section($id_section)
+		{
+			global $DB;
+			$requete = $DB->get_records_sql('SELECT id FROM {course_modules} WHERE section = ? AND deletioninprogress = 0', array($id_section));
+			$ressources = array();
+			$i = 0;
+			foreach ($requete as $value) {
+				$ressource = new block_career_ressource();
+				$ressource->get_ressource_by_id($value->id);
+				$ressources[$i] = $ressource;
+				$i++;
+			}
+			
+			return $ressources;
+		}
+		
+		/**
+		 * Create and SET ($link) a correct link with $CFG->wwwroot, $type and $id
+		 * @param void
+		 *
+		 * @return void
+		 */
+		private function create_link()
+		{
+			
+			global $CFG;
+			$this->link = $CFG->wwwroot . '/mod/' . $this->type . '/view.php?id=' . $this->id;
+		}
+		
+	}
diff --git a/career/entity/block_career_section.php b/career/entity/block_career_section.php
new file mode 100644
index 0000000..a230abb
--- /dev/null
+++ b/career/entity/block_career_section.php
@@ -0,0 +1,91 @@
+<?php
+
+	/**
+	 * block_career_section
+	 *
+	 *
+	 * @package    block_career
+	 * @category   block
+	 * @copyright  2018 Softia/Université lorraine
+	 * @author     vrignaud camille/ faouzi / Thomas Fradet
+	 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+	 */
+	
+	class block_career_section
+	{
+		
+		/** @var int Id of section */
+		public $id;
+		/** @var string name of section */
+		public $name;
+		/** @var int id of course */
+		public $id_course;
+		/** @var block_career_ressources array<Object> ressources */
+		public $ressources;
+		/** @var string summary */
+		public $summary;
+		/** @var int order of section */
+		public $orde;
+		/** @var string intro of section */
+		public $intro;
+		
+		/**
+		 * Set $id, $name, $id_course and $summary
+		 * @param array $id_section
+		 *
+		 * @return void
+		 */
+		public function get_section_by_id_section($id_section)
+		{
+			global $DB;
+			$requete = $DB->get_record_sql('SELECT * FROM {course_sections} WHERE id = ?', array($id_section));
+			$this->id = $requete->id;
+			$this->name = $requete->name;
+			$this->id_course = $requete->course;
+			$this->summary = $requete->summary;
+			$this->orde = $requete->section;
+			$this->intro = $requete->summary;
+			
+			if (!$this->name) {
+				$this->name = "Section " . $requete->section;
+			}
+		}
+		
+		/**
+		 * Get all sections in a course
+		 * return a array
+		 * @param array $id_course
+		 *
+		 * @return array<block_career_section> $sections
+		 */
+		public function get_sections_by_id_course($id_course)
+		{
+
+			global $DB;
+			$requete = $DB->get_records_sql('SELECT * FROM {course_sections} WHERE course = ? ORDER BY section', array($id_course));
+			// $numsection = $DB->get_record_sql('SELECT value FROM {course_format_options} WHERE courseid = ? AND name = ?', array($id_course,"numsections"));
+			$sections = array();
+			$i = 0;
+			foreach ($requete as $value) {
+				// if ($value->section > $numsection->value){
+				// 	continue;
+				// }
+				$section = new block_career_section();
+				$section->get_section_by_id_section($value->id);
+				$sections[$i] = $section;
+				$i++;
+			}
+			
+			return $sections;
+
+		}
+
+
+
+
+
+
+
+
+		
+	}
diff --git "a/career/img/Capture d\342\200\231\303\251cran 2018-06-19 \303\240 18.18.32.png" "b/career/img/Capture d\342\200\231\303\251cran 2018-06-19 \303\240 18.18.32.png"
new file mode 100644
index 0000000000000000000000000000000000000000..963a9293ae1d940adcd2134b65a095392119cc60
GIT binary patch
literal 176862
zcmeAS@N?(olHy`uVBq!ia0y~y;P}D7!1|7Zje&vT&r+6r1_mDWOlRi+PiJR^fTH}g
z%$!sP29M6E)7c|}Pl`1>pB5q%rN9*Al;0%s@>2E^FVUP9l?ee!9voU_DS?e!7c6QL
zjTPOvmUY6>w!Jz{d+kLW1Fs!z;+<;l$q@VZUiE$J`{v*OSr$J#WBL5t+&hd8x^2p0
z>5E@6Jn8tPvT-5f8qSlNI+v0gn6(s`iyfX6EKT}9V+IF9>WhE=mF2<;pMINK?_59s
z_y5%yAASVsF?jGiF_|}IHuFybh8^1BIwzSME--&xcKP#>37rOB3sf5!oy;Z|w@teH
zbk4FT9Id`JISNlg7*3e*xldwjSY@LZW@pa)D^R!jjlv^N*9o%~eiyLH$UQkf!TsqI
zpXN1btT(mZTH8zh|1i_+&E&%;CDKy$xD?qrmp;llcjo_Qng7v6n^K*NXB=`9_BfRE
z)bjM}X{Nd{=S)sKcg+mEIKfmgUi_2Dx1x7KCk_d*y|ph`+PERDfs?`OabeRT#n;Ye
zf~oGVJg;gmwJPSE*zhf5k3qledYSG|DwmVk|1LKEap}Ph#b+KO#V2#UQX)D3HQSkU
z{dl7|zn8V?hf3<4jO={|hFqJpp8USFX2%D|+0R*<4y;g=?$imBGp>0i;W54Ch*qw_
zW|@}(aWj@XoamE!(qZFRGowhyto3x@k!8%5llA8c7>cO(%Zscz!>#?KTZrxP@l!`D
z88<e6yM5%QVe_{LVSDS4b>@wCl+N}`OWmH$E<W2RUZ&%7(xa&xA4bibQ)qZfqCi@J
zk;zdYfl)FiGePPE%b{uWe#!mtzA4OP;lO0XAb*25tIbVCv&!Xz6g$^}_z6E8tZeig
zE}mxp8Sp<fV)dR|jU}%6`;uJ5UNp^NKICZjM>n`fi1++7j(HBfAC}+TX>cv)#*<q6
zml0XcR!Ihi9TILlicycNcJRMzbw99LKF4o|^*ck6>*m!?;tP8}%qVES;J3p#G(zL2
zVv$$}%UgqE6Ar$)wC_CM_J+9F4-9vtf3@!`R9naX=7V8@TKygIb8nfp-aoD-eeOrJ
zE_-dDjD|)k%hCR%ugNT{%vR|gj(alo*FLdRJ1(`Y7PYwZIa#jp{?&f=_Ydu(lDaoG
z->`h6QpT8l=oKTkb)RX%^o@&)<l?0LMY5AKwnezwL|*9su>7Y*bMdLwYNabmUzGi@
zxxxPFhw-N;`rZ#rKKgVTI8QkKseQNU{G(!pZ{0V}k&$_*r*;4L)acXF%aZ)vXNd2A
zS>(^~AdqRQ<oyzv9qh6%nHoO6n|<z!Y0S6Nj25>}P4)aV)heb=@xXr((;v%TFgfoi
zk385jr$PGzQ=NiD5A#I@IhAJ34d<A4_^BpX&EOSlNDAPZ)_iq=P!3b{LB9>`G7MiA
zaL!>#Kd5?vE3cutU~Ng0_yX}g%zrtWCJ0y^awrj0J|eTxb&f#!5q3^Dr3n!#lAf+c
z0)k4;Y0BIagO<pwblIk0dgA>F!6zz3jG4~w6#6IRJu&^nc{D(3Rjbqju@@OvWWTx}
zzF1LWG^_F1BGwGST_UmFVT*TPwECh_#ksd}+hY9-c037M62ivE-WZhY2y`C{+EC)t
zboQv%2Cg+yx4TUbsn_ymAFtZbZy}ieK<5tMy6XlujL#qK{1LN<XZ?}#N2Nb9|49Ag
zcz<-i&<mE@Cf$RR52*PlqzEh%?&1_}dE0Wh#rVVBmnwUdg*tr}sb1vWSAFt`&m)~A
z$wKBr`Hw6cdv7?tQJ(0rOC@@ex#p}RiccqYdA|18?RnfY+;i>{{uI$of;T&5oct8K
zPqaSa`lR>C@Kflg;39k1xk-K>m$(F1Oqn?)bxQ6Ow^O2C>PzRZa@@M4D){lrnO9h^
zY`wDgit&}-SIo7vwA8fZv>u1HXnhX7w(3o|<@!$^PnCTqr#W*k@m+K>!#mSDLp`HB
zBmYIoF4nvK^PJ8v)?a%4g8xPNOZF>_Lf(enTxD~$a#iT6(pBN1@v8!_oVohv>arE0
zD?(SuhU{K+ZLweA_5l8n=PS;Kt`D+bROh|dzj@)q6@qIgE)HC_(fe`JF=O9J%UaVm
zsQGX9C|><c^DH0RF@sbVqa8i1J-I!`J$|~2rY#kV)(&1BlHDKH9kzbkvTqV^UEWIG
z3ccmN_4Z7O%S|WK(u}7Y@*CtE+4mYqJhX4JPdeGLS9x7u#d_nQ<NodIgBNY~f8KUZ
zJ$72&hP-L-xb9ZnWv|*XulHWX-j`L<U(dbx+H*zfrRgN=O({<rCzgK=td;&7@i+2U
z^jH1Y-z6oaTBJI7uSw1^dSRF%^-D5MYMqfy+Kt>J2A>Rtq}Cc)<$am6^z5hf)Xmp6
z`E9Q1{n~rDC-qo#Pjt_3Umaf|A1>c-Gi?l(&e}D5+3a;jxn^%ojg7iZX6J@wmtCKe
z^e#`&AU?V7+@HOzOI;@&RqC$lPM>BqE$1}T>8R7c!%DQ{SI4Z*TK)Q(OLqBdo!7kA
z)|##8?e0CW?9{U^-K^JH+FR}>+&1enIF&plBjoFf=rR-Q`rS3VqjtN0^ZCv3+v#`J
z@9B%rx-IXCGyHYu#d<zHzMFivW!_n4S@jj`l;o7uyiIw0q;yr$u6I7=e1-F#-+AyS
ztLLr6zZt#BdAki_lw!qpn(VGAEG?e8<6Y_7GUH<J(&+bPr(;js9@~57?;iGp$_J9?
zxlcas?jL^M<~;Mf`s$mNsg-X(RheBY(y4#5ZKLcxwR<w}b??2k)0rPK|E%5HeaH66
z+|Rmyylz>Y&HlG_{(sm0HU3-vdp}PB#{?D`z6$vlk{0S8Tm-~Kq(X$Q2(6KvBM>9`
z$KZ&Hit-Y(CFWODOTu1s8aPE%-00d6ox^N4J@)WB+2>|?=XP9vxaGr+52rpH7c>)`
z)N#ziq$uXesT02gp9L;j@hd~%Y+sz@Uxi~vYUa=SKOXsL_;~fP@}pMA&h^=fAMcng
zwO#vNY>mU8O+TtR!#Fp!JagH4#Iw`1^Zn$eNv9^?Qtz2(kbY=s%HEX3B4;j5Rm0S3
zulq+Hbgot}^DCMeV)OD@%ITBFYVk7`nX6Wxy0|hc*fN-ZnNZN=pz@`4&s>UES=MI0
z+441W?;VGCQt!Cu$>)o%pZ)%<{&RcZ?|%CJ_0t~C-DtEp`hoTefiE1)ty2$$&rF;-
z+vt9}Yx>(0QYZXQ-J9-w&hxCL(j}49PCtL+IcCXGvu}jO=;WRMdM0-6ZEeo!In$Lc
zoxId$qx)lGZDgA2Z`W@c_tp1n{XhKW$V>M0j57jfci3D`dp2pNKerQC-R#!$kIrSy
z%eARK_{P2X&-0v_-DiAf-?lkl5_fUWxt|L^m+LLiI}!CEeW7z=<-^;pp4`&iJYCPk
zOaBP{^3L6uwQ<RhYf9@~XNx`VZtaeqW}zRs{Yf_G`X@;%oikluJ~zs{c{E<OKKA$P
z1DC!m)jb_EJvYWLMlY(axb=P4+^14cS)a;kD~DfOo3vId@@v`GD_6y}j)mkzImaqT
zU*2bylzZ4}bLr{pwd+Je?ycZjacg^A{ohGn-<y9hi@Ez^d*OSvX5Xc=?Q+HP_U%<I
z@s8c<T6#3>(X~HoV{Z#>pZojl-|e&BR^9gAUVl^Z*2R6sWzSzqZJ#wO_Sf!dR~K#F
zbnD&S$z|K$ao)PT;d<WtX|-o+m;OFjck|!#{mcK=eRlZK_^kOI`*%4b`z`+r9v67Z
z2AOYOw>>W4{=ErzE|jI*nfT0Y{jtOKH~w#2d~(OiS1Z0<Og+Bhcvl~<jK0Oaa;KU_
z&r^<_?0dHI>~}w3i_*Veeq7c~KXiVMy>!vHE0+I@kDsrepTFxt<--%M-@Cs~kI}yx
zTeh?2hyQeY{_Q)qU5PE+ed)rhi??o=ZF_qo^!{q~^{lbh)pKkAUg}*Toog<fcW<BR
z%dp?M_ui(LZ+gFH*X;W3|L^_z-SS(N|B8Hw&6WCyzxuE1-)5KR+W*pcaq;Q#!v6QA
z1=evk6YYN9iM-<aepN-*mo3j`Uf#Uy-Gq17o(s<}-zTvD#e2<v-jCOR)n6MY_v`li
z_ow#?S6Rn<#_{gat6uy&?f7lO{Mo;ge#z}SU3vZgz9-G^+ULsOwV(HU%9od!|G%7H
zaz1;1L_Mg&`})t}+<}G}$`3W{SPgDm_)@|U_nx6)9?yQ+D8>bTA@k0PG-;fl%*FJ-
zbLw;R)*Vb64)Zs({A6%BkUyn&!%XL82Y3Gwwz<c@;M}>xxdBUFp7ZmHH>pTctdWqY
zNM>MIDcGPtsj=}NFEexewu1@p848rbE7hiS|KZtnGtO`A-2UE!{Gakaye~A<S#kV5
z0|NtRfk$L91A~|<2s3&HseE8yV4R;B5>XQ2>tmIipR1RclAn~SSCL!500K4@Ru#Dg
zxv3?I3Kh9IdBs*0wn|_XR(Zu%AYpwa1+bEmY+I!W-v9;Y{GwC^Q#}(s10_2y1qB70
zqLehNAQv~N_M((DTcwPWk^(Dz{qpj1y>er{{GxPyLrY6beFGzXBO~3Slr-Jq%Dj@q
z3f;V7Wr!g#b6ir3lZ!G7N;32F6hP)CCgqow*eWT3EK-00h&xj&G7&cA6+^w1oS&-?
zlF>KRGth^d4Kf}iY88-Kk(v|Xl9`*DSDcxjXJ=$&X=Ve~fFXsj(gvY55~0=5)X)N1
zE0PpctBpR$3rJpqgcn#e$i>Z$%SIm@vY=45;}TYou3%tbkjZrM4`E<nU;;%B0|V1{
z1_lNV2+j1JfiYr<@->|=3=9qoo-U3d6^w80me06y<=26a(>HBdI(@14`_L-EB_8@*
zOqX;TZd{mOwYTj3*0}2Y6&*>A0<3}))MQy+UUIbJ(A!%sR%f|6t!$IA^~p1SWk$yL
zZTNkPii(QPJ@@@Kf6sZ#nd`D<Z%}MtVB%09hG<Y`HJbR~@rfN5G+6{37#N8mVwhBZ
zd{7|Dc#tz5Brpoq$jHd-Y6J0zaTEimoeeW_?q^`)u!v}2k!NRbUq`gB9h&&h6YUlz
zJ~4%Z#}6J{m`${cCOkN7Oq4%Ck<`%4>hYnlpx}iRh)0yORDOKm84Z4%AwcWkSM>fM
zxihV`=iUZ4GdU{-&+zq1-3@P<B8^ffy>jh3)gV=x;xU(P+kO2B(lvXt*7rp3_BWHY
z(G9PVXIj{OW7o{B&o@Rn<-H8vz2r{V`Vxo79WDFkzpT8k^sv^${|^&anZQ)#gZdqb
zu1{27R{AL^_Vws1$$MM%;z=5YN&=Hu<|i7fo!sI3I;o{6(JF9(|JJBaf$i`5UffdN
zzh*k;>;Gjg@h@B|SgNk+=;fEL%zXK5;*amf6Ta&T-EVhzl&*Q=<qDC`x|b4pF0oQ4
ziiJ80Q)&diT3m|6QzCRQHkPRWSTR$5-VAGHwiObKF0;nv-c@{K{Bwn*)V#l?o1dJT
z<{I}pBGxKQQ!COqy~s-TFL&dCr`qAEzos#N`thZ==v&exoBQilz4Wo0_~-lOQ@@w(
z=U04i_Ji7*Bj?}wy{!9VyD|D!)$fCQo>$4Ny?@lwbnPDYi*|O;U7F|NjDCd%hc(<w
ztPd_fTdtgX_u!F;@{~V(0xPBl_&oa}FLZ5QiR{<iITi(8b}!<*cZF$-UE5di`2&Z~
z%_$oEK2hqXUC$<JmYaOM-Rbe~cjnXD%lFy$bMV<_s@9d2$9{kOzVq&-#_jSas@EMi
z{II*_KbQ7<$1VN(e*zb<<0~E<HaYAPuIbwQeUnP;-Y#{fMDY`oG$*Ur{RoNp9r*BT
zWRYvN{5HEPX5;TIra}*Q@0|5;@g?caDx1IA<ki1n+b`SsWdHoId***@KXgC1Fgff|
zdinKI`+xIp=*m|7ZUhAm^M3Ci>o<IobNT(_kUVP@-qJ?}96Bd<|356mc$`C~>cz_q
z-<ICV-oNYJ{?8xF65q0$^RI8X`ds1C|GHUw^LIH{EEfE8_wZl2*L4ryxqoQ7SiAJ<
zj~8E+LJz<B+5PRKYu23?=6H%Om-!5wb{EAj&ybrKd8qNO#jke1&HRhXzBhk6tex=H
zQsJQbo<gJD)jRGduRcHVriDd*e*?()H!oZNuAQ|P6x+XBcQWI#Kq0}mfki&s?@E^d
zqfm{KN<iQ}-@nb<Z?+c-)y(;;FyrX?clV-e``)}`fBRc(gOvQ<dGEvK#Akg2h1DE+
z#i|ZG8Ed1GLzDj+7b~}8o=yHeEVmvWzG7c7yH-N|;PIP{Cf)Pz?%n=N=H^}gTi<mP
zOzo;{@2|Dkf8~vB$G4A`_D){}@KmQst_>{nBRWfZdM2~Xm*CuTxP4{)2eaP>eog(G
znKQ-gcUR|swcNB@e#`sl16eg+s`f<})~&o*E%5enab3#`MLgkgq>F*mZllmk2}yNM
zJ42z2cK+c14|2aH&S8;HXTPLVSN8qhtKyV$`;7bB!699<{n4MG&EFMn9e@6Z<DxUZ
z{4UBURFkB7$<WA8s3u9}0-yY{e+O^BIc&jccaCpK<exY1_FjE{;$7W^eff;5KVE$O
zGw<lnrD>oHa{i~_qINtPL_nKK<;M}PCCMpsRDK-sSRiZX1CK&kkIg@B-mPAJe&XG~
z3u^B(g*{$;{qx<f&)#S6HD}1r|E%o7FNnM4q7cU7@u737$MF*uo*z0VI#}1t_{E;T
zng6lM4-4xFX&*Q5{vI}8dG~L}-}_kC9CKg)e7ETH>5z2y+`U6i33pC%Si>>lfw1<(
zzKMmC9tbNpmi;jJ%6~6S{+Q>7!ZL-kkJ8KEueEarCG=YEh~ECV^X1y-^i8Yz7uD9B
z>ld(f!QI$uj1W{fs2-*ytNd8ypt>8=+YgDa<oBGl>zVxE@f(L(qX~LQBxu384}x{<
z`nPDrx=Bsd(B=I2F-Rj_@8oRT_Bp!>9Q)>2YqOu5Gi~Yb@23v!-5v9LAy?M5Gc%Vi
zDAV7){quDFlb*Rcjd`ubN4?*+B(1Br+?+PGl%4;?tmgXD_a>_|<!U|n<+`Oh{nV6`
z1$Py7`NDZszsXK`kUU>kH(LAxtc==~X^{m=E_RV*mwy6<oOY30o=lv*DrEZa*XC1a
zxpqbMUEcJ!{-pKky2+8dw?*z#TifO9HEr6-z4_j+OHQ0Ro)@Fde`Ze3&b@x3TBo(w
zT6vtbsjQ7Fe)Gq&vixWMr;n$W+MQp%eM5b()u*`K>)O)P^6#oN*UwDQ*!;PHMc%qJ
z^Y*F+Sh*7BdN}wzsLVP=cA3@K;q@UicG;di7ne<*a&o%;iyv!z?x>gh&ef>)ljGmj
zn>TgUN%7b!w%WZ{x!0=wSRvUuFYjKIcU4x>%9rumawq=(U0M{dnR#g`v*_fX%<Wz^
zF=pkWrp-a8^X(=tj!Fu2%T@W2GR5TkNA(4;65Rgihxx|c^Y7YjA-i@^P!g&MVLJWT
zcl~sBX*1!+kNgj|zC6<Ux#<2EPov`J*A_@g1TAmeb8DA#z;(8wiBnnRpMHFNmU&6)
z%T0|Yy4L;jlfNbJoA7v+Yn8d_>PsrQZj0Siy(DM7vMyY6=HAx30cqbEIqk~0FYgm&
zgq5^wGTPSnflBe2<d@=o{vQHQDl6~4qZ6wY#+m7(7r#@9S-qEAi}5L^?#&kyk6mxw
zV!uyn^P~rtouk*i+3aV_GkyNPia@)lpSyK_Wlx{8x5RVSv^{QZ*K%K&e!loyd)kTa
z?q?F~c%MC3=yvw$%e1vT)9ZGYEwwRA-?dOjna|_HNsiQaiE8kmpP5o|em1CtBtOYN
z_`x!Nd;SZZ?br60ovp~REAkL~b5k?APfl#>{^v(HHRqbI57CQoStX{WW1h)raP-mV
zAA90d_m}*Am>pSeaPj%iEnN4rZb#;=PJJ`kYn5gB&!DL3ETMKE&-Z@1vS(&y-0C#5
zsFK%rgBChCmd_0q*FT|a-#hVX{rlqSE9XAi`T4|=IOe4_|EBC(wV!w2p9sDz?@ZR+
zSN$~9F8}76WU*HN*S5bm0yAxYeV$PL;_dI>st1qH_scjJyQ9YS+dK>P&gJJ$Kin+7
z)S)jYNXNfSbFTgJCtat7X3fr6`^LU9t|;rR=m|;jO=iZc6#qgSNk&>q2k#!&sXMqe
z>#x@8^Ao>{t-bn0cKfpwP>Uvet=0NzkakC$%L_q#?T%Fqi-l|Q)`$Av%ej3rJ;yI@
zhr)Wjnfmc-A{9Nu*Z*3xnCo-edA;*-*TeFz3KiApzTf)r0%PXqyB<3qE$_Y3TYq=$
z_L5ZrHv|40ICFAQ+MSapavgeieahRd*B1S+`kTqmth-vyGwTAjXB7V2dOzXsg|EMN
zKKuUUj%1tBYIe&_X;W|hZO=Fv(t3CLikTC4_5Ah<Q+-!HJ@tv-7PTLHOrHBkZh7tD
zp&>o(l)nD9^<o9lr@zTfmcRCPdS*1=shQo=_pUoX&vf&awGl3P>mr?Qg?Ln|?a}(B
zIb-|d4K@2}w&&Osc=gTo_M4$S(Y*bN-n4MJ-TNj@(VlVo{MBd6kFCG2uRQH-S$NH+
z(A1s#Y81a0t|<EgZ47Wu-C_H7#?kZhb}!qK_0`gAr&4Y8p2v+pBYXSf^fz3a8+;qm
zU{n|S!h)~C7<*tNr`^xZ&nGM`zoX4sTvdNz{@(1}f9|gjW|~#GEcYhYr@Ot|J<@Vd
zuD^0ydGqp9*I$P%*Yo>aaZ9({qxq34@AKaoo1dMzyZ3NF+V_Jkv)MhmFQwky9%w9d
zRpR5i6*pTh-Fn8iBRES;^Oargn?IH-|D3%2?y*BzT;A1tTfa<yZkqpRUqIad+Q#(2
zws-E?P5$#QYNz~+Kkk%tb5o4s&sF}mr*l`P%zK`eJ5he?6S>v1y}neg4KCH3qCI=5
zcSzG+>+Z4>?%m}cQ7@}L-rRKRb=2&+tC!jApC<Kx`K5P{pD#H*-FwTEB`V>aUQSXs
zPg@9wE4=-=dNsBZb?J8bJ&zA^MuEa_$L^N@THwa3_&<&d%y=5F4hoT=0Q|pqU9ZiB
z1uMhnl*!pIJG<la&ig82>%0GHR;+W4mJHk9c|CLMmhkR;yU$wws}r6+NG$Tb_owZ$
z?$+1lnQv2`Y|Hxa_f}EL&pX>?_E$FFF|J+o`^NP?sr^MC?r8DU2Vd#&Xv|r=PE-AH
z)i?7qT}#s525$boBC_VtR@dw%|Jj23Po7(x?tDnfqv?F(<y({T7f<i@>f<a4K53i$
z%XETQ>tkR2+V|UKKfPP@_FWb0)@<qNdJFbGpPu?O{`k{3OP?%}34M5b-`Ay;Gp8(l
zc1Qf@&A`nycNeL8uDw%!C)8W_w`sD6v8GVIF5^l6%Xa=RVQt3A=M7syE#1Xo^A~^l
z(p+v+VGC-Wv(_*F5SIz=2OU~{{w|(IG()2Z<8iegYvevPOgS~#eChIA_l_=6dHLsW
z_@-wM?za`KX1}>rb?LKj`-8Pazr;;ielq-U>hFz<r_H)m{6Be;arT^r>t?aKpKY5Q
z7#;KM%%<;+>MGsGdtCDMVl~$5ezdRlo8A?g5^_DREpL_TscW)6CR2V|YfMmHen#FR
zr0e;)$Lq@8eNxS|{Z)Lr?H#xC9^ti|c3bby)n2ZrqTjtVX`XfUwFOUSWu7#YzaMh@
z%dgG1e9ZT5eKN0?-Cy!m+SxgtR$-d2qRg}v%gZc_zAehR^a|A3f37b*dAHZo)0*~o
zZ+US2_FNL^UAXm6$;3JT(rb9Ps2*|qx-aZXk8RfN(l=|qNN)}j@}FBSdtG<p`K!xb
zA9z$RuXj^3U-!ndb$>nktu8GrYWi()#TwSLXo<4h@^<D?{VnC6^Ul61ep0)1tI)l|
zY`@H_o22CT#znog*n0<(>22-4@Z-z$?gu7v+HDo?I{D_G^PWW?-fg=7q`v!k<y7{d
z4+)3UKKXpU7B~G5v~XPi=?d$|!ka1AH@Nd2)%v*N3Hy4fQ*Z1vX0LD1kuRD5(5(O5
zOtr<=e#tjSMfvC&KHJGV%P4MH&h0mmPs;0Ep34;lKYi6^)qj4jUi_NKObzbijwWh9
zVlGTdTeZ*h_Suy}33U<|F4X2+KUXV!{nQp+cAm55`q2URUIhhrWp&!F-2V8v{>l2Z
zyfW2a74w4s$}azUy}EGElc@FQZfnigyZh8C;H2|@{_K}qw_LyTwmtPjzvk%|wROd@
zfu|cHZ(dWKH)Y;^oy%#{yyE_>4qq$u$?dsRm>%!0K3Gf8Q8@hsI28+r&0n1G`=GVl
znwU?epw6K8{kw<Cw}R^^?)f(5Zn!&Ej4VA&eLf#{ZuVoYTw2PW?7ww!obbNMKdZ~C
zrm_cJ*p|a8Ssfg|-h0iNy2W~*rbcZ3{)BVo_oMA`xwj$<_HJ{z)_+SVa^CH?lk2Cf
zyuH0btn%$@)xB3P#m&22%$<JPUAz9fj#u&i@T;?o_B`%w`@Fe4cltiz<5H&%l?wE7
z+Wq#QH~raR@m-$QnVX+S%xpYf>nLEo|Gnk1v$HlIDoCBa%Ju2pysa*(50`9RDKhJM
zdhWFKVed>sD)(3Gz6@JCW1)}zi+@*x0zECVyt8w{x2SHL#UKA<-qG}e=Ikf-xvO9J
zF8R4SP2`o?tMZ#=PkL7O%?ix8wLtCVEJn?<vn%JoI|a;V8+U_BgVUgJ{B_V;u4mRq
zDNuPJxxR0XGNdfEoVaK?zV7;4P%u`miqx*$5m>DMJ3yy7)WmN48u?!f!f$7NlQZq^
zzj<v#h33qv({J0dPXGURdTYsyg%_SN#~XjVWBOM8XXa_Q{pDe&C+qHeE9We$ZTx=)
z_mxSRpSLXC`6>1M!+rl&Y}1JZwXd1e{dS)|v{Sg3(=PkJou+x+-YaLT-2Y}jxhZ{S
za`YW>mK}>HmF((|(t6FWqJDS9>C;cnYwpkJH2k$G^53iw<EJYmi@z+94GmYlc1G@&
z&!*IqZ%SWoeScQi^mqTQd0DZMZDv}JL)}I1*e3R#xl?tabY1LHrB9LPciFwJ6tjCi
zF=t9-^sOA9{l6})C}BLWwe8JoXpx%CU4KH#v^)Mp-V`_Iu=$Hk^!zu^D7W#Q)!+x}
z>gz8!CL3}SlEXDbN?7sb@EA}IU%w?wzjoDCvzD~`D}^t8x-HnYDS<Df=+w4q`H#D<
zyyCHo)e4&!7+Wp5ZvLLq$vpp3n--pV*Q~VjQR?GZe#yMg^I11PnH;Lwsn9n0zl@1~
zsGHh1sSJy&&zBn-m4D}Rj(o*zntr-vHv6g4rM)M`v+iX5@w>Um@L>A6Z_Y+fj@#ck
z(jOo1`7Sf)TCL10*?8mXnv&$)mut>GNG^@u^?k;dzvnENFSJKVXNf7Ce|x3%bkOg+
zJKrrT-*t7$>{a6B^40HbjEg7t#QmMVdWF}-J4Uqy!RIf>{pK#0n|S;9TA`_D7Hr!s
zJ$<TrRH&EThM)DYc4rQsi`8uN?s%)&=6mnFDo(i-u!?KX<CP9gHd{cY<b>^<zf-}Z
zNBVCV7vP-_I$#e<j~k7xU?pW<;rlQ1pB_K^dhe-V@jHRL=YcwZ3oDMupMJWs(wH|@
zvT#H7jpRw%dgp3a^M~n76c;;NDF6G`%fO|(YObwpe;D#O@Nnw!kBi$jU19%zEn7!_
z%btS)HhGt=B+Zg1E!4TgesRWw&wp>#emb&c%FLPf-bDphUHLGVMVRaV^7NcZ@BexD
zEeU-4^z6LQY4!zs&)+P+v}?ZCs?3GD+S~l2<9zO0h4@YIuex%PKX!k0-~7q1?PH(l
zN#9((Zp+GmBeidKe!lf*?WdFPcgMJL?%aI(QlhS{zx21OJr1(&dJ~zK>+d+VTJ_1q
z`T5x@g?4EIMllkLm|;Qc#F7_moc3|^%Wdz{*4nwh<JNiip)b0{Xk{9xEkF60O!X~D
zsx&hw;lY<G{S=-F)#R;;iFGS6Q`@m(#di76OV`+Kxc`N*Vv8qt<(f{zjSpOPS3axN
z-Kn;CJL~p)s#m#|syOT1+8tfh^Z#1DdB~(buWJ{#YlpA*ddVL@x!cpTYU1_$t%o>`
zR^Lz1J*eFM`_8?|>PxP^5G?xSRK(Q!+hs=iBEy5v7pq!7J<EFg&Zhg{*6N=<Em9)i
zUgWO3{_2avKa1YPe3}%w>g~T$@00(nLb!jJ<!9FZ3wXVIU+Vc;kzrY#PV-LJ#QN+~
z3cWw)?Yz|IU(cB?DPJq}OSSF(@vSP$3!^qozV%Avyt?q#mbqKD{jQJG-k)Rlz-sL@
z*4Z`H$t%~K{WUpoHmtgl6rK3sU9#Bz2T@z=re1x1qN-bI&*R37pX;+hA^Cr;<@Yt<
z8mBlf<%J}^UePRvGpavouCAS4vM%7Lz;om2dS1Qf?+Jg+-nRGNvc){BV($mMt;-dg
z{eJ7soS=Ny$Hm@<A1z%n<J;<Qk2j}IR(^i&)Wgl`sq42rx$*w@w-YzLH9JLCt~a+1
zGyb?jvhs`X*;$u9obFHg-ubv{;zM)2;<U)>=l?wub1U_0Z&!WkF!}vU`0s_+;i_NH
zys`Gk67h_T@>FI0Dq|m2_d9!g_}>C?m*l4NpEqwiv0`fVoh`=gCX>BdgOgs^2{z6B
z%I@d2J@8oSy<_}2Dqp>xaqsvl>wezjwqQ5!_1fz0X>&rZ&6soL%j4Eb6<U?c=DSCQ
zP5C{0nsLlxd7fX1ThH7syis~%ZImIX{`x!RVfmxB{ZAiiYHlvHy}D}?Pj1MufaCAr
z3HME(%dcDJ-SNMo%=h1VRh)7!$cy*hN0II?@4(%pz2CX7e}$9<G4Jk(<4L&!9=Za-
zoOVk;Kb!otxy^H$&rBY^`D^3U{LlZt8ZhnJ!RfL2)7FWumh$^P>%-hL_b1x~d!AcU
zXtcu5_GQ?{Sy%Mqf_lo0VxG-1eg6G#b*y)D@9iC7leQe0>9Ea;^Jr?=|ATGbcGstI
zR~z*{J(RaH%-inGg}VX&55_M)Q7(N=;*<^lzv@`&$_0+W=aqg|JPoQWd#K|)GnfyQ
zv>QENr<_{mV*YVfd(`e}XN$x$th2)Ul+*Q3z2u(0wB+9$M&0F4Z=UOa{q6MPVDlZ_
zT~ANydA~D07xC0CGjaK0aqlPRotNJ=tyR5!=hI!T$Zg+etoCaT`uVh-k@xP`uX8s~
zpR{FWtJsN|-P2=T4{uRfP@jF$VdeI}w<aaXZmphoN#@G6FSDAAcE#83f1miu%&Bk<
zv~%UJvE^;{VV$~fcP)3Ou09{A@b`f%zsu?RSWu(jXa3op>5!53VrA#^0(eH+udyU)
z9ejSbEH=fVcUPOl>LpU9uY044PM!MZJ^%L7z|NqyRo83(uFSElim(b@q4R(DzP&44
z7CCHxd%W+|>F(zzm#m%5w5ufKdfcU@iwfNq{r_tgelIp}j^)zWon4DwRq1Ws`uIm+
z=C`ZrnQCID+NHgJN<KTBd^1sC>&Fj{ndZ;9_j^~dnluQ6_Z?%IUzZ$q;(hfb;e?`$
z(=oYKOV)b(>Ms8JcUG-Y@oUG(&)+=*jkQ<mW<T=@T9=@=GD@XC#P@{m_A7dttwpKD
zbB%w$KYBCzNw=uxX4a)s3zDz()zzKouRk&8ZTlDJmyw%y?76yh+3$$AJwG4oS7y1L
zDz+~T5MDWL!tsFgFR%7LnK|=h>6OnGzN;r!ozyk`$Cw<xYwf3$^IDhL&8G@g7E9bZ
z)d5fVMoLl#?;qBwJGedPt=H=F6SrQQl>M=febLkX>p;_Bf3`onvl*Q5&+nYLFdbi;
zESt%2@`KB3gG_%e^7dc<!|zY=VxGCbCWlu>v7Uan!~fJ%{RE5H!XME^@qdqfTJLsU
z@>H|skF2{|l|}D(c9uNtT6%i5sFu=aHa=68hby?R%lVY(E?hc|Av@}mRCrKOSZ=4@
z`M2|43a9>gHsxlN&H1M%r^P<Yep{uc9qZ#&r22h@iv04ti!&Zve)sw4rne^~#VaLq
z%jQ*<$3OS#s?7aoW?6WzrgJ-!<>MzirB``<e|6O7@Uxvf(^lPC=@t0%$Ff_?t}hLJ
z*!faA*3;wH&us4}lR3AWUE+`3pY?6wHs!j>w#U!!?CXAZPH+DARobTA&q`J2pZ)WB
zfsIM!-f1Dz{`jpZ+;jbGb>%w2(`Bbm7ymEW{<rM<tV@gC3cnY+y?X&|woRTG$oVHO
z?IZV|qX*V)_$9-7N$Y)uLe#(4QK0#m`s{PI+2HQ*9BIiae5+M9stE{l+G%;F-fLKR
zYm?he-jBAm9~Z^^f6H;R_|uMsckUlN_gil2otr^v&X)B*H)TJYD;{<4!TU`O=XC#N
z_w&s7vUkP5$eV3fG8OdW?)yCoQvL8__qWfc+D|fbHT7$+O}|olH7G92Q~&(ipRJpp
z9-g|tTFf%fUP`!TU2Xn6ng8k&mnW`dy0j_Au`>JNw}!X3!@VX<w+fl8^ilJC{wue<
ze`Pb*+?sAQ`)cl2uhXC3_IO`fy6@QikGG@j?IZRaj$N9xu;S;}b7}9AYtwH{V=nrC
z{x#3}<fdsa7EgN?bh_{5>{(OOFTL$un$s9lHSu+M_cor0@9U@Sn%rO&uB#<~SE43q
z(!!4ld|zPWTTJH6`i9-}@5XKfg(&~Mj}BY@T;B?sX#Ia}PW3fNgTvhD3*H8Yufi+g
znxeGc$@8oEr(}0e`_T3F@aDRS`PctH44oI&n3aA0Z@;A9YS)QIl3tVeuY3yM|L%@j
z{ah=}`uTR6T7oOQ4ju|xThJ78{a>g~z=;hpVXxGdz5fxMH~UMoivF%Czt();7-g2T
z#LPKxW5wf3ZY#6r?XL0sXPUk0&yLF4SHbU+<2TE$T(Vg1@qSa4gdO??7yP!U{#bD{
zS8KoF>Ax~7Sf&Tdaq8dPs=9mDbWN4(8OFawPR{k^o3l$n>!$19%afaI4hL`b$eUT?
zE_~f6Zr;;hb?p<qpPWCu{HycN^3z>LYcegr7cQ{AzviCy|G7JF)<$l$xtV&hR`>4l
zdDh)!vJ?N$-r{%VQu02ttKa>ru1qvqIjQ=}89Vc=leV+B8m{&|%V1LL5qxsK^0{zh
z$)IJhg1fCn`NixRNA+K{>BePzwcK=L&T1)g6ZBP1yDZOD`MbVOlRg#trR(($-`6QO
zdOYKv{^Pph<FK0T{`>V^J~uWw+Wk-7sq?>j{{1S|qUTe$-zxib)BNwD?bCH9g^QiP
z&hJ~_{iJJpyOi1F?Cz-(q*}YZ*6n!0!oKy+^|ai`wOiYTo?gCsI(71V)ooqJo=*cc
z99fH>l-z%R<tX>MnSI~p`OLg|wDwY>^~GrqCa+L^WAeA6ae7hBHl1}(X3sPA&M*#6
z{c5#7Elp}?P5+*~1+%Bcq{X~@yYRKviRQDXt78{)&Ek*O`0YQhe17%bV&0drr>!l|
z#U4ya-?eSewY~Oh3$J&bpB8$}{?4u1IaTg=tN;A^yGifkk~Q`PUXLDc+A;0bs!*Ht
zUseYP6=fY?xjp<@?$q<s-W7@0UtK=W>~x^w_d*NAu&#T_n){b^>aIm|ty^~WxyFQR
zmB*Pceu}>inyvpAUHmQ*+?9TQ=fnkLJj0S5rj09nKLl=mwdel6*<aSa+v{`wR&(d2
z$~)mjj<ZA6C#<d8ILT=5ds#dEz|)zwM%Amd4<1i%HQ~By6rsO0OaJHQ=O0#0T%ww}
z<;Sz&n^j*ru3K(yIy2MAQ#E(m0-0NDoM-pRT$!flWwiT<sqn=cvwwNb-XzLXDnG+A
z@>pI>w#Mhu1@Bg-sjXUbHe|^(+uJoyCM^B^D@*&vrVQ^7k@XLjlt^#Aa$w=Koxj$k
z$7+UO*x@sE;U#<a-F<VX?%v8W+y4K|yKbWCXXkh>%h>!Q<YL+p&%G;Cl%|F($<Hrc
zscD-ncAcO3-`uTlC-BJ5H}an5<rDS4V0Oc8&(}>$tNT6w8*1M*_FlSm$&9M$Vs9*z
zq)q&%S}c+EI-69v#O>mqbtwv|LZ^J8ix=hxtZLt<yZJ}!zrJH)Ywg^Rt^OnbvG4bH
z&L?X?6(v*VZO>9jJ7sc`W4r*KcFH!^MP>(|@4vovBD<8y*RH%rGlMS`zR|e3Tz9VM
zi)$NeQhzS1&R>7}3Xi$$u{y~RrM|2+G5?s1@(%=j@3Ed|{^RF)-=gPNIOn-;d&|Er
zI6f}>?!^oLrsU2}y)flto6&jZsbYoYdyie(8x(qYjpM4mS(X{y)1DaDpZBXQJy~<z
zD0SZTTN~wbIqg1|$xL&!UsD$R^jg~MnMKvf>r+?V5v_T%;_0qkeZOL_6vh9#wjiYL
zXQG4i-wS_lL+jP=ABERyoxIz7dRIU5UCG^P^KC3^7ysVGlKXSb(!(|S7oV<6DRkEj
zz4o$Ob<_L#lI^F&d#(#jm#RMdsrbbi*PZ{LZ{6hM&Gu=lW;cKSnzvE6PGA3-a0*_Q
zyO}>;X9$|Pq^vC060Ui-`hLW`{KDpNolqse>xJ>B-R!+XDr27n7G$5ze)?A0s(Omb
z`&BFwQ#mHj%gwmk_Gy#ZWdB#bOH)iFO=HSr>}UN7@#w#L#=4k|XX2b&J@&uK9-PU{
z{P~u{vg+NMxRf8EoB3+5Y}~y?Km26CyVnVa7cv{YnEr9o=N<1=xZ|(01dHWz+C}rv
z7c}MW+jmuaroYs5y#?}7|KP*xzaqEXoM!fCb#Kb~SvO;sl~vVj_W5^X{w9&z6WUUr
z%ru+ITgqhlBjF=o?#vBSey>uQbJKY?>m`?2rT<M+_x{=PF#md`Df9UsjlD~@ZJRRv
z`L@R|Bwzl%%N6Kp_ivli&P^w8{Nr^w+b7b6NWU4kueU}1d9%B?2sHHO@av$p+^q7L
znbDwmj0qN&E7w6fltDT#xbbx;w>ex<{c$I5^}Ibdw@nTYxte2CTQ8-|{q5Z+tMsi4
zVt01k@-e;2bJaZKq|^L0MtTcVRwR6M(9Jhp`F-uB9WI&cwdc+Jzq)2u)y(k96<nLr
z&gopv+v)sD%vA5_mHbEFjk2$s&ELK<WW$7-`e1v_x#siFf8NLCAGhPdtlo@w?_~G+
zwJ*`RB~;_ow8*sR*`w5zU(dyO&OGd%vdQeWuWxRr*7>*B-iM!D6szfdsC0dt&%M`S
zr#E{!{Qf_8XXL)fz1M4dy$<~Rx$W4y#|h=j^6V52Z;7n@^7i3ttrP!E_1DYqs(*iR
zn)>XI&mFICtU7+B$K~!S(W`yNC%5RbKdCSNC$hC>`mI}GI!g2J$6Vh!|K5LC!u4Fg
zW$*RbN6+8e9qq5cxkP@?<As&Sr|!J^J!ZYQ$DBDK*CDMCO|dU{2jij@RteSQfx2}s
zF2w#W$-i@j{m;VS`bj6F%_aRU-mFNQxX7sdz}&dKL7axQTb`)w-lje)PQTw|-?<Ba
zR%~7U<f7$ep455l_FvxUuU)74Jn~7@x13{rYd8HmP`5H>!-g%o(T=Oc{XVR^oN?uN
zk)h_v0J&AnLN%AB?fG}vb<^`7mgTMHyRS@`ojt8Ue)ZhtX*rV&>;F8}%dYZu{JAc^
z7Sw|Hp2cZ)`M>9e!0Tme!+h*s$kiO0koEY$OYTdBPlPP%{!Ox)vP<>T&S}!Yn}1Z~
zy%zHK`o2DB())S47p}S!cYlV%@?)!xt;rY8%T>9a^>%6bW$027^}UzA#pR3HSHI7*
zZB&_1_o1)-nQZv8u=~Y(;}i;uf?^?+*^-D0;`l1F+{P829|DbE*Ie7#zG7*+jk&4$
z@&9M%=p>sjJM-;f<vq{eS#1+z56hYAOkVnH`7|-@{~u>>E7_X(agx!_^KaR<zdhdP
z_4?xc(>qU}<P=$%e`imK<jfn{3l>)F-NthL>|^)S7e8xqs$``t@VCDE#Ps#VxyC{h
zA0%^hKYXx`v;M^T=-_F;rEab0vAKF{$De7la^27FTAcrs>)9kr=h?5@8UNq=^VTSG
ztA6Uq_4V7=XdIp;C487EGi2}i@}6i_?lQIWMpLx)y8jrh=$xWE;q>a6>dW(|Y|Q?)
z^VH|(9g~-S-##TLvd4Q;?7pJVSv6Z6`sVn?9a>$!R_IgJbE&vo)+pE-1pft_B%|-^
z)Rlcd_NrLK!@lCU^XES8Vo-0IRY+a^swsF4m|qubtt0NKipCpa9bGK*zdhADxgu|`
zil4WJ=U!XG^0uCs%}S*kll#-ZNvm8JGd;IzkyZ4o!`Gi2dU{&%ZTY$#7BkHgR!lh^
zf8g%B)LhNY>mKi$HnsC)r{FtbIqTs3ov~74`cL%&IX!sy{Wvk<&f@tYoZ-g5d8ggt
zJo-h+vgTWl$&XLTmc^QuD-YEwu~@78Skn9B!jsZZpO3kex7L+<pFAzw<9%-JkJmfC
z$nCuo>;Cr4?$tY|e4OZzyyD5@2RC+lUwU!)=b}j&Uvg8{@4B?iN${`1gZt~l-%d@h
z_w{tBT3Kr<S&(~b^NX7a{|&WMPtIGsZjqd6*Xi4_*;Vt(-rL*dF7An*{b!H4PN>5%
z-i!x!;&0#+KnJ<f&y<2DF2uv;FQ%aMJfi+1X1%Vk>8@(|lk-ehhpWtwwulC;KMCJC
znfqS$_0V6}S3JIYbeFPyfo|i|QYBf|{H<?wwqM<K?ZTni-r}dSy~RM|JRytDz4_;C
z(|shza(#4moOb^G3pWeSHt+YF_}*-d;gr@#3b%x6!rocy-Qp^Kx7O{V&7|PjTh(T)
zy)5pX@_FIqci!?DVR8SiE^7K6@pjJM87g1xW-M2o99uZu{>Gj?HYIa6&ilP&{@g1k
zEwpZC&ot}yI~a5GPt4SBE8n`G^SB<k|MbuLU)OdyCH`DA{o~KCdw%VD$enus<mYut
zrr8r_*`B!m?cAcbpZ?`r$1H~oBW1r_9p#V;o1kPlGV9?~&=SS=HFoZepebRK_dATX
zgNEHn%IzI~A2MSWZRvS^(f^8%$;$2jb?2$S*ZZwoy76(peBPCqd0E#^t)72&|G$ub
zHdQxP+uUg4d#ZhMdsNbt=i9Uj_m@b1pKA8l%d4pUdF9soi@i#Jt_kLMF8pm6f9e(U
zZ{E~->^nE7PWCOg)v>ghwBcU-Mwhr4ljEDCJiaZ~J*Zw9bk6#gj){5Z=8G)5Rz{Yr
z+HdQwr@HjWx2t_upH8z<-8*a7_vNNWf6q6+`(*U9_|%@=>x<>1@4oza*63&Qf6nr+
z&r-QgZLfX3yPx@H;NSNvw{F+_xa9RFCd<bu$0no&soX2yG+|Zz*RwY#eeo~5ve`Uj
zqV=oz$DgOo^A=ml`fuBx-D{65jXHJud21aPY~km}<`)gYpfuVIN~6CITF?6jtKlzL
zST5ZMso}k3Ua;e-;S~fna@u7{uKsBLeY(xfP1UX!bHt?9bIXK$$lI-Fw7@NPy<F(;
zH?h|*g~h2iX=qF_p02a!tDfd0?R&Lfcb=ZU<m`)yo8I0KET6f4Zu=INCCh_V6{h}q
z5V~{5lqaiq?S8ZU_Pc4PSh;uitLNTTaju*Bz>e=KsI$Arpt`$eXHx&{<=I=4J~@7m
zdY8P~+IUOL-0CeyWY6bb+^f4J<(|wu*L8na&gMU{Vg7ZgQ}r@80$xo&ldti)e8cM-
zk(qyI8XkNns=IK-`u-NB`nNBh-;3H2YZtS}*?!7H+gBdPPjS9Wj<+_wKT|n<i)81O
zZ$G|HeKJoiHTL()|I!<Cw(qg|?jK&*w`OMQW93{|)n7}};nkDvsc-SwpjFWcUoE+|
z$nSalvK~~u|9J70sdsYltJ&a%;>(XT*5TO}z`!Ip^Fi?5f+n9grU6_}PP`O7_<frG
zwCQ!TUx&`S*R<&4&ZTvR?{E4|dvja)___Js`JdmtPX8jS^0jL!s5;iZrK586e*Mv}
z*%pFN4qm@o<-MG1DsQ+wq)<K-@a(lhDbuBo+|QR@`mntw)O3pPj>?8D8nM@6w>^7s
zzvysz{EmL-t-`sScAK}!PFnc*f5GP!Pj{-_yXK)Ke(tTF@ome>hnu$iuGuJKQ+qIW
zYu3a&M!5yS-#0$*i(*=Rb$R!b2KT>WPq|Kp*S?DMtND3-%GXbq+xFi*`|Px!I`_Ms
zexK65$9bKP)$E-c`rFTA{>9UGH-Eenv$<u@&82QqTZ6l7)9t0MJdpaCe_Kma-S%5Z
zQNP!x!04riJ{kqjmekk_pZRz>b=&u<%|C8dm%rvzY5dk)Zu1vZHvF3RnzXQ<{vdc|
zg5u08ufsIo82;{&JLVszJN3WLjHU8zU$#4boMiNNn)RMrHCgw3BtIT6TK_45%P9Sn
ziuL>IE7>PE9x-0N<XXq~=FCg4rA)0ScwPE<=h>TEdfR<uUPn%OR`<$fuI{Z(iPtkv
zx6jO-U$VzDZ{4g(Qx;BIq*ecE+s#zQ`Tg5i<fqQL{NwP?MRq4%N58DGjP<l*E&drd
z&ujhix~oB<|No`#{j<mL;^qjueJi(>tO~jk@T}4x@2y>B%`La{N|l>JRd=o~jC7v4
zzPVHS|Fm}X_2zS`cKN36+?*)sJacOE=36{AbN9z6?e14szc}^MF}vIV;gh+FfiK>1
zW~V&6_GIa?S(&Gsd;O9tH{3qHb`q=g<n(n}!3#Tj-aNH!o;Gz~)wPSzrq}V{vz5O=
zWyW!eCgcUDJ_uHeubX-2x0&WV>;CYVD{qXm#H4m_`*XAS#I<Vqk6Cs1=FPoSeW*O{
z=|PbY?GP8S4Da-%_v-HKiF-HqU-7F)4gFK^|7mnqwbN5Ie6nI%#^q15&p$aZ^YXM?
zzazcZWre+xD!=RN&bM=2x%iTep9_ymFD<`1>)mE`{g??{hwqojw`Zx}5~`Wf?RBm)
z<C7J0;LoOyizcPr3h{{ib|%2l`bN!*EjDJQ&1<}EGA*t`JGS7d>Fki}f!?W?4+ggd
ze>d0G|DP48cy?yZzPPR7aWl3awY}Z9YlqLjIiFt7J*%SUo#q@J#y4-yzQAMaZa!bN
zO6b9{FRS%?y~H;Zt*rU<Tdy+rUs!nT)+g7T<h>`YjO?0Kzvsf;`_Q?m%~$sA_kz`d
zKZ1GwTY|P0IIlh*Xz=%eEWg{?ieAuILQlB+xryMSx_get#bA65-m=CH&kvdtt=Id!
zES^2(-0bt(YWLT~>-L|Sr4_#ST+6nEs}FwfeOGU&>A9-r*S0zPDh%(MORv{WzIrKH
zQhV>g>Sg{@KF&6O(eC&+?cyY5wak-&y<Ss{V(foR=QOH(t>!#)fAja-rBmxnU+q{e
zV_P03{onfC<1J-%Z*In~+pnftm~{7`OXlahC$_9&kCp4?wBvfb)Uy86iKiz|dsIF$
zxi%>_YO21@Q|_lirknjAt>pgn{Nd$If!=3k?)uq~%_e{Tm+I$d7t;P`>a;!%p0vm2
zeD%Bcc4c9pu5jPn-A^KQQn{Z@V!S?WQq<8;UQRXO<x|=-U+lL3_sNR`G?G>)b0gr&
zq=d%2&0C+IeD@_{p3hmiC24}2cFo;c5gApp>BQaot!Hj@%qvx`zV^grvA1XVlX>&6
zotpEuJ;rxc>JhQb(;bmBWlyZ(hegT^&$jP-Kx>faUVW}{qwYf=yY}>&xu8h7RKEQ~
zY%X|s{*e0lx%gJAF)ns+QTZWqaoXb`<L@CF0T*smzs-1aZ0o0bWA)qf?kvvx<Ma92
zr-Z|4cE3L~Tx<W5v;EqhuzUL!ZVnfIt{*?`*8KhYS)QxE<nWtj>G_*yr)DJGSypP4
zb4<l~=FNlqrDE0n&3505^;Hd>TJv9YXNhVmr{;IhepyrFiL(}Z++UV+Tc>$h&vkz1
zZ_;Zy?Xp&`b+lhI&2{&r>65tFe9kWUT)94bY0|=q)6>`ADtBV*iA{`9I`isiq;dMC
zX}foYMP+rGHs)z%t~h)`b=?!i(%h{rHlIG{_A<?5eX)7z?k7_#Pj3FPqHI-0r`ubt
ztn&+}eK2$PRtV}0`1S3@SJ9{Y)HFRaswxfk!$Op0@$ACupiNNoB5M0CUFN^{@xfQn
zMi=ova}QN71*dZE^>*d%xVs{ZEI}+X^B)8oxckk#@jJ}9sN-I(>FTq!#&u#_uXwoS
zOyv@rbaeaO$DhOW^=2u*Umx-4^PI?qv*u=8%q{nvmveLPs(ssQHtzXyJ7)bS2d-Bt
zBGWT#-%r?aM$=p6t!<@KRIi+3*2*;w+h(u6Ho@QOUdj#^-H%JBz4FRFJ<oJ?&d%S7
zhc6|_ulo}_FW$m>t#^}N|1}nQ)<yF^%U^#x-CR6pvU57qY{ON~PgyGW7W1B*ZJT{y
zTbA2`df!NWX}%>Yhi8~BnkG=aJll6=tj+q!(D~2Xvy8u=xg=C@WtwmFt?Wy0dt*;p
z+G+pR4CxHiKX*?l>!m^c>{%0E+}sw*<fq`Z8ortAl2D1;PEguhdiA-+UQmJIcL6lm
zd+@I6pYWNW7RbI2?hSHyTOcQy`uskeoNc??=fbqLL7ZAE&9|<(a$%*tXAqm}_ZQ#)
zZ*VT(xim`m?}fjsgL>rV+WKB8N^De-DP0%f8kc`Lu<Ka0e&Uj}x0yel9xr-ysPcO)
z)7_H`Rj;3UXYZmVuJdMJ$k+AHe_Z@@JN}-x-A?VL8-v$JaL&9~KH=dT_oz+hit8qo
zR)wupoL^?7#tIrtuGyQnb>Z9q8JFUw{&&USk|yz7Ph0jg%sa}m?%s}?X>sm<pIw-?
zDCl(1%E-)D(>}!AI=6Y<&3#@|0zHki4rWX~zQ%mz`ruAm+ibDv2YJ^`oKqMXG=E#k
zpTDzeKOOnf`)-&2)^$40(o+lN**6;(KED6y*q_`@|CfA>)mo<;`R%=!XlyOtvb$T>
z!Ky-aUB~n(pw;_vQMG+e7y0jfJRrLEnEQJ1AF^`_Tfu3y*iGaGE563_0^N|}(A$@o
z6R)$siYYAolzjf*r41FD>))Ndu`x9I-b?q(sSEe$@i;cl3e5QU_PfWzIXi2%ZTokD
z@%kB)&)?pBsf^PPxxW9_uI4)-J9mM`869_edne5Lk?ysqd12Gh=IPN}r!Op(mddK%
zQ?$}%cfquUXI?p~tzG0Lv1)3-nc9;NH>WRoCoX@AHP_NGezw=8tiWAseoyg=SoQy?
z`%ABwBJ*ik>c_)wbHL655EH7gX<svK)2+fUJ#Q?E!ph|BUwf_6oM1eAivA35sVS%4
z&-#08bDhSw?Q(X?v-#&vIua}%<DDUTLQ>uJbINqD)*|oTMU_s4+_!I8l)am@#^2^;
z)TQ;yu3c~1x#?z+K4fLk?tgW+j5OqXLHjwI`@NMHozST(<9GUg`bFJ`zUXf72>P0>
zul7WxosZwrf4)+1p*y~*=GCC(R)OADy*odOIR|;TvAk%UIXU&sv8~It2c6VfRljO}
zX0EpI_fD^GH_P6v$g!?+ITyE2Ba~aT@bBt43&$)m&8&z`TBX+Ob>`{k>qk%7WwGG#
zwbWCmzuW%m^g4BMyKg)HDc<CL6F{qm0uStedn$Cw`z;@<^NP#gPl#6k|6uBq&o$lB
zPxk%lwOtKfI$(Xe&Ui}es{=X@6+*syu9p4ly!<Bn#VzZW+gP!zv114A^}F}5u79na
z`?;{5d-uR=N`h3+fHn}uFFDp*r;KNt-xp2`ql50cjZ3E;I`!ggR#X40>0a}GZmX8h
zZJY97n&Kz(ZRf-ECog~g|JC}gmphqm`8a=O=bQRyXK-3bpr`HI<8_+STaGOLk_Q@Q
zl@ig<%y`z%Tz~rftsdvqTjRH?%<y6f`fsy+@$++Dwz=Qt8Bf=%5^K+y&oX~P;H3a7
z7We=sdl6eqmYDtS-3esx3vEyquK5+VURQq0`)LmiIaCh1m#$kl?ZGEdQ!Zy8lj6(Q
zmARd(>(9^Ax}P64{oOaa_jiKx*2J8>aE`nC*$H;-X%eTJY<FzS;FPSstQ%y|yYy7e
z*408iZD(gpd6#;;X6xGN6CW)0{vhqg2uXE9HHRcsKUdE_dVWvqm#Z6o$t-=Z7bCj{
zyz8`Sum6tq#^8~#hu@z6!;{(?8uT2R`t=t6Wt;V2v0iWgX|?m)GL)IK<FpHB8dq--
zyYX(#+}lrD??3B`a?;)#y?&Kx>W*m@Pj-T)+P_HrUmLTt>gr~T*xyS(J(;S%>z<C*
z&Eq+@%U><w`Iow9jn|$0Fw@xQo*z8L<;B}Q9AJ}80*$w?^hEy2*|m0e<m&Sie>0UC
zg@E_rO5WNjaPJIwG`V%cq-A*KnHU;NI43-Kd{Eq{slTpr;}4sn^t)`A{Abr{DB5k0
zd-MJKk=D;f`QQD17CaRSJRRMd6zpmKnf;z><>vHq^YT}ZSa<%rEx76X6VCF;6=he1
zQqRX-ciR=ZDlLM~C;$JApT(OB-s@GCoGS@DU3_!z#0SaS4c<lz!dLlrrTusXuJtL{
z2X%sFzQ^(P5ep`mXhue@64B9N-J-gN>)8oS&`}4<QJcEGiac#<y~N(%R?gnCWZn{i
zb1Q`NwjbL0Xla>~;q@J%Mi*x_*WaEL@+5zb%8wtHAI7+G!dGGh3Ua=)OZ&*ZF7$PH
zWNqJ??H*?XxWH>?r+hzmVjCoDx<wW1<7s_6902Vt|5sumUdW{K!zJd#qD_Zk%^nNu
zKcGI<=;q$h-Ref8yVXHwVvO!qM=DB^Tovwe+8w=D9XV-TT(7A9v6l&rIx~$tA2s{8
zZfzHho39$a<$L1m#pWK@&dfY?OFU0buJLsEI<KYXX`X3sEARZf!CPl7c(UGp?VkK!
zzaNMnT&TYG$oY5cUW1P;vHI|hx$^v13%0uHAL0|Ag3g0zwdeYRuZtz%A?8uu<Ujkp
z+o@g6ofS#~WsOmsM^pU%D<-~m2aWf)F)x48{BG-#?5#<OZ@JC+`wvX<?fi6LNommH
z47r&_?!x=$c2ND4kn|_BL_Zz5BMEj-cy##$#Zsx3t@82fZ)u<Zw=1$J^|aFZ(lvUr
zt3^`P=5KIQd7QT{?aPdPPaACPY8QiMHO_Bet+oBC_S@~u@bg{j1ZAo&dHs3wZr8ix
z_l0*aUAtZWO!d0s7k|ah3BG&^e8PpF$qP<AZTus<K&PpQJlG&PIpxl>(v5j1e;n4h
zuslll=L+ZV2HzB(UhDs}DNb$8f9s_UduIs0fG*fvTIl}h{&|Oc+dXRJnL6h$Ram|_
zNafek<Q;;gnF{AURgO*k=z8U`M>?LN1qC)1r%4YM&$;3wve<mh#NKv3k4slq8#){p
zIIKHCHCSzB+>#YMD+1Nu7=K@~Ex=d`>Fl4N&n{03)81CDnKmK%*A=}?t78AG29F=V
zXU_YsD|D~@%Mtxj8|PXX&bozin}ctApDz~TEKI5KtNrvs98XXvC<tw0kvG8OWVA%5
z@P$d`N6Wn_Vnl1<n90Ctr?_~DB2xCj*X&_rang5a@_*r*DTr^KHu3_U#tEDg9tazG
zNjagp7AJSq8>6v-GjTv9MibQ_%i>F{4?ce|@v-7-9^Te?g@pnCK9o1%A1y=b74Bg5
z_)r+UVKIxxhliHPWe1)zW{#>uQ~%~ig5T~<cp&^u-~t|{$OYN~1&5~o#%5-rnhG{#
zaY(YlYDhY$r?;k}Wv{u)j}}{&5<E(g^Q{5Lga^qF9yGAX&%<ggvRa6r4@5Gl{IJlL
zOMK7EX_v^)C<_rLXde%g$`1((3x$L2=>*k6{9G`Nfz$3>m-~%s=O+If&JOGlVS@HG
zGjQ6m@$q?lcqmCwEyRDL(F6~u(P#ptveDcG3I%ZHASX8o1ajI{e}6aCH2d0#oyE^{
zLUlq`OxTif(dp5nM>%`@g{9RG9`6iX=#Nyo;-0e*IL#zD`N8I*r&^Ui9=1QdwA5Qt
zXgw1v*NN=)d$qP^T|G77x8+kcl^+(WLSLAPE5tm+I%crUe?G4|F73>Wi3<y}Z*E$u
zeNx>yU+UTHi4TOIF%(pT{Z5cjnCfsu<wwbz8=ii1EGDk{{Y~!J@#Cl0MDD*;E!@7<
zuc`kqlT$f7DDfGm@QhVS?O^(a1qU}(etyQo8}atm)~A>K?LDvC*8hAeUiotA|D~&Y
z&&{<yUH|X1&#qe=sth^p!j`UR$8&ZdQt+nqfE=n5u^~XN{?Esrz@N|c*6;r}YfHvO
zrMusK{3rRlseND3IO)OUcLkS;Gf_bx2sHB?xcJ|%*XvV%eE4#9MRI8VjSat39vo;4
zTRr<4x7tbd#gnVAD0qA@<W&_VDijzRc|<!_u*j<#SAEI&`C@VZ(^pqlZ*#m`{eExJ
z?cD8cd;U61syQ_A&SEy7CjS$M{hE=yh&u%}IP79kQakwk`F!=0z2;@*yk##hrGC2P
zt$*_2;r7d>Kdy+2>&1A?tNWFid1*=K>nlq<Coie~{-k=@I_WnXr>e{^Q2oBbaN+~u
zoRpn>#3ir|?g~jlHM7ie)tK47h@0;Ao2C=_<jTt6PrqL0pI8&Q*-7d0GGFP+KOc{)
z<loyfY04Cp`E|cm)_gv@eN)QGM-#TZzuB>0WqyI$_Z4=N9z2%R{6<_us__H2OGs1y
zqg7E`SN-|E|Nq3Ir>Ay)Njo=3Gk?#=WpnImtu)Tw*;#yAx!*=f*1D`9c7OHvyvlz+
z#ZxXX^Iey0EmRY7c;BR&Lv!ye{^i=#AC%xsTva_s8FWZnm!6)U-@ARk^Il$Gzdq&M
zoJc-78x8$^KPIh-*r=p%^ViqcC+q)xme-8hvLa@0Rp_x^Y4yYH^-AJ;F$LR`!<+hd
zHKtGM7oJodGT-AvAXg4?QQJ_=qGWW?{rT$X?d!75=07^xy<51%?q9`@m^~GN>mPj%
zSLL`{{oeM{_WbyhQ#2>5sHyD|Y6)8#^)&SUITra+<Ec+JXI;(Gz4$_MeRccd2A25+
zD~kQ`WmH6nDC9PF_<aaGd}^xpbelgP4qw`uEq-02{LPJ(s(=54Z_B^`uK0?mR>%bL
zxQe(_)Aiq5+2`IWseHY5`;#*>jqP5iyEL7Db+!J4@p+rKpZ`h5dNldFbr;(cXZL~q
z4oB2~yf~bFb=6dxpHGA*ndistEO|Mp=G#pUN#nF06;;)pt5Qx*a*e*Udj6f#>jBq=
z;+Ol)ope2}IyUY6ytU>JKVN^xB0t}pH(8O>F7e3oYeWV&KX`q0vbTpv!P$Gk`|E74
z2Yi2jU*9<WT*=$*`S;_zrf5986~D7+s#*7W?xGJ59ItQO|KH=o$K{7DiSro)<8IbP
zS_j<|Q_szbtor^=x0&s(;?GY{jepFwD0JHQr)Wx#w7K89xV>2x)2}gd+GU;$=p(Yk
znjpv&IQ_xm#ZOO7^}e+wQ+I3D)gsZg(cAr=otdefetzE7)e*l`4;~j1o=RL{#mJH)
z)NzYten92K2f|vOx9}{cMkzKp+!|Qqg-wNOd>Sn99jc5RB?+q;IPKK-sQj40P$-3B
z8ocR-;phWlpb|Rs`ntVy>}qd?^<3$Fer|4b-QUu*SC3ZM`DskCUv>QW0}O456pqAd
z^biKsndSE?-H-MDR&=iY{pF=Dzx|(rwtL2R%#{zS-w}L(cMc5^M-73X!Vy$B$k+Xt
zcxJY_zh3OF6dBi!{zs1<EeTy6R`mbxVHHJ1#UpF2cUub8%#oF^BCeX-s4ig0X;+ou
zH`hv4-EYnX{@kBur|Zvua&q$VY1`)B)8Mr8>lgS-RH4=wA>6TpWqt&AfLs4`miawm
z&+Cw*1NUrgLp`HV&7a>#?nDaJB<VfjksvCvWI!{Fhnc5bysLareeuzq^7uyF5SBlP
zZ(x!CZ)aFOjb;7}ZcApoCl5g)`bYh@ch+att-2@u!>iH6iBt26%PI{<9yS+655bA|
z_QVOWxa?2}-=G)~Ah3t)j)up_TN+h?HI6Q?LRnmuJgzjDyfjs85#Ui=BH;AQcE9ZR
zXLC-b%t$%sbMEHnNSniY>C?B`?dPqpoxhbsAftehaXy=VKzX_Uf#ti8?(Jt_WMbhE
zP;h9#$+)nup~3&Ro$b4D#`$vLMa*h=)Iy}BVjK=EKgfOM?p@&zFY^lDD?^0wS+hl7
z;lbs7{{6p04=g`E^-cpPUMD#;Ff_7>3w+4@z*JiPouy`1^qt@MOotlwmYd_pmiLz*
z*NJ|3S*U8BK*;9~3l6ff)JW}dxO>-@asE58?{)-rG&uZbVzPVt`^%1a)|#rAle{x<
zhAS*kMx$hSM2W+4X1llc_tq20PS9vCadSAZ+_>tUDwGdRqS!TGILgFi7t8bJBX(&t
zBdnAa9$c2R{Vs$rSHtwYNMdB1ugCVSf^gDiU}TyrDDdHB&%A1a*%MT%lx%Eh@E2#U
zwgGYQ`VW+!&v9`4C~-T#mnbjpif}lvyt~nM9>LtD;LzZZ&cae-wfK1)QC^JIQFw6q
z=m9x@+$AC`>=Yap7&9^1&AnKxPm~w+!~{OPOiJiiM;L(Hk_(cIjPuXE*g2gjFN$+>
z{3tQpa9o(EIPYm_@K678#~Zip2p2BsW@V|_C2`|1adAEpk~Ju&AD64n5ih?;T&S$6
zXq5l+fL(iuFq55j%Uy3`f^wFx!-3^DwU+HCCPUbIIUHE-KJ|9OsL2eBOrxQJTxN`h
z#%O5Zsuf1l#%S6YO&f!thLt{jcXjxBlavz^Oe#J+*z#)C>Sc9*e=VIJSEaf4!y)d>
zb8{^3-k5xJy_8{+%dbDr?dSjc_ICE%ipRa?mt4hTr_8JS^)m0hw{2X-i-qmW%J=`i
zdvvi}&4+^}Csn5}nKo_Oqd9Zm32WT`ezmsfo(rK?UluD%O_uGeI+2Gn%lE#H&Ft3Q
z<}o{eU!~Z)%-5=dA37JDe{yp2<+JAZ=cJvPaq(JesrB{c{_{&tX)a$9xY$kf{GLZ$
z+Lv;--wl&7zkF_nVe+NI<Fer;mA}5cd>MWJSJ*7;^1Q-zH_O`iWM}o+|NF7%_Q&3u
z-?#7U^+ms5v-{nymv8gyt7n;H2F)_f4tqU+_tzac_rte8s+1(u#?DYxcyO6(NnE>O
z^!XbblP@!}%S^ZyQ+zhHD(B3S;@@w#FQ1*aOLOn1Q`)CX^4<0C<?sJ{X<qfa$QZlC
zLoFpgpH3G)es+uSX2rQ>w=y%QhK8NoWt)F*Psz2&^re}XmziERnD*lJt?c!4{p|mK
zdGzPa&CQoR)#rxDguj2Y_xruf`L*9p`sqe((TJ^h*s7Uk5EZ!A=l=CBqb~%z9TT`Y
zemoH>y~8JEqEY*4@_e7!Ih#C}&--;Nd;QY;f8UkAY?IDg@!BX@I(JK;n8?e!yUVZb
zKQ33TGq?KPPR%CQvp4)K9=4cNeR;9w^+uWSmT0+(2aRbmUcU3Kr9N~<E;?uT`;F2A
z5&oaY?f*^O_xtYqYc}h5^PT!uTRMIAcY@urrJNi;bbQk+&mYgRRi9Up6qUVp>#Z6m
zoxP%`3y$XKe13l3-?@#)^Kculx3XK0$KT)I^FPmv&fBRPTY5D#_usZP>c79fp1$wf
z*7Zvx{%PLw*55ltH&yg+=CN&;{j8Td^I0x=@#|`M{9N6_usIoz=B9G~IMU<V%+9ap
zCcXLloce!1j~0IQJEJG+T^YLFU9NJ8p5mrWweeToz7cBa9_SJh_^@(ujgIKosq1T0
z*Y5lE%GAGiW?|m$x7$jN%a$*BKCgP+v+aKroWyVE?asZGy?*be4gPg@_v0#`PJMYT
zI{z&H^y=y#58Ic&-G1M0w|yFi)$=*Um!@b2Py1b|{plEo>)fhWD>I)?4L`Tbu<+3l
zP*z)WLhtI=yRy7Lj(C5+k=(!K|G(eq@8fqAB${<!bmq6cl2(7{brZMVil4e^j!_#D
z9MA52YN>Jg`&OIB<@|(F_X{pY#`#t&-5k`Ngh09RtnmEWZ#PRm9u;4nd3o8@Iq|m~
zb!KmU+-JS4ncvRhsPShpZ~wn9-0i(4tNEVt*Zo{}W`^O*9gq7?zw3Vf_d~nAPx<}Y
z??(2^1@m59UhZ%8bV~506@iO4y|elI<#OhqA0J<Sy&j+6^6u(V{?kGqI>nEz2{bhJ
zzp`bo<jh@K4}zDyU#-XbMSxI`IzS!dXvcTEUaxzpEdSHv?B#hCk2-UfO{x6+?CPBN
zCmhdg`n<8fc8%H-;fGTv``cNbool^axj*93EXQUx(am>{tZ`bu=hG>n>n5i=Ier}J
z@vNL}obDH!w&3La>m0XJd4H5_IUg(fLG$wWtAXCv1#wkn&;q{koq)iHmCZ%_>;7Jf
zOrJZIjZY@RM%T%9V@x=U|FrG3ADZQT*kwxs&c2-<UspNHAkpcpCHqs6jBO46ma7v&
zpr+uAsDz{396zosWV3$1r+C|vu&;~P?S8kb<Z-Wg*!-wxe<RktK4W~|$GM$P_g!yf
z<2lRca~|FBt7K)VITanPOmK+ww35Pu%{o!JF}GKTuh(fY&bhJS(e;~~)6+M9-}CKO
z_R*bB@7~N@KKGJhyG&5=@0H8v&5En}cyv~=w{^#a3vSZ6Q?}hm>fZ8fR<_vbsH2}^
zKKA^6zu(^W>y_Zli;G;nt6k3ie0aEhd9V4s9Twlu7@r5{4huPh1czH?w{tI7y<R)L
zjYo2lE~i=Utt}>{udck=1uBBJZrLJoUH`S8&grdJ!=jh+n%z)XyX{ui%{88e-a$R;
zhx`ra_37D)8SC%;efPcIE`#D{XTDr;=1)ET@iw3Jn+a~cQd4`CYm~Np{qeY8{QCB-
z!jJo^A60kkfARRV{{A`3{O8ZBbeB)wubdmnWH&o+*GnPC4dQVX3oCrTzTdd#W@5W+
z*dH-#L*o#g+taoi)I4Zp|8#h1-s``$Tk8UC>c70WsHszQxs_XdnMAaO-#i=3)zz<m
z%McnOX*A;G_))TH*6TH!{jA<@xtukx=;_q(WzqS2w?4b`Np8)SOI|NeDEIpao;q=R
zZuz~L?{>f6_h-Y|T$cWOpXYsF!pvu(04i*9<0j9qdAW4@B~a<6<~wW3{HRyoYTsAK
zTRrMf?z+Ez=d)Q~X5as#_Vw*;bJ>aqjhT0L6h^LCzGK1FbBp`!X6fyIvq|KA%rvpY
zg%Rs?m@EyqE#1n&|M%zldcXbuzOKK#CUWz%vdA(!Cja|?o|$)NgKPVLKc6o@Yj#^l
zw)l)8s0P!l>z?baw^PM;j>X1jF?AcRMP)Dj`~ALsucWb>{nck?O-_OPU$5V9$Ng_h
z<;DGedfo?~+y8rPpLNJ9Jf_ff*V}EkyN=6OzuB1idhK?-zWZ6vPpZ%NNuOW)ElB_M
zs`uLUi8l3bZfwlFU;EuxP%C@AtH$f;`~RfQGD`KTp8m5JxoM3p@0hG@Xz*9}-VQ3W
zocV3HRCuvifT}W)%{^;Yh;2SEQ+}uL<=po*&y7kS>ev7D7TdRS-pQq3nQw9ZxKnss
z_T`Vq{r=K<I}%@?zHKwlzP|3)OaJ;?3mpP&6w=;U{(7<aHZR}Sx{G&q7GG`^kGt{i
zjb1KmP2Jbk@k>DkO>5%oZCe`7->ZH<_uH-P^&*?kmTb|D*q~ti<8}Q1U00%|OdnjH
zdOtkDCF0EyVSk_e`ro&wXI=i)&QW%^;4tsa_}BLdC!{oSfe$ZJSo^JBt;kt6=a1pW
zH=#NUw=Rlm(YO0N^ZXXcZJiI!eLinLpEWgU=i+T?hju=nSAFUG{{MfMmhE5La9(Y8
z&LrK%A+^Ce!D5QbXV|V-``zWl^VRWxUq$OJ7u~$0=8^FH3}YMN_Z>4ElD^IP_xE@B
ze!JWK0%vzVpEo<nY}U4@XvX<3idnjDW#zKgY`dMe`^(4v`kKzu$^}Bk9Ih8M(&VF}
z{wJ|5T;UnLb{^w=4v(jsxm|5nrMGmIAKxChw<JpEwprbuAF8{qUcDc_=R>mm?}%+S
zQD09dOKy8{xku7C=uDRA{d^tU>s2xz?YHcHzi;=iu;18X8o8CR;3X?djaB3!j+JY+
z->W(roV0Vn=X2KUE#AGGTl?*%`q3VvtGY~j8*^?vIXSs|W~<VQjW3tYUe;gtWpO0K
z(qF&2^>$^f^lsS7_rqtt-QEbN%x7n2-mC_#pi$Z({QhP_Gw-E??DBJzHU!;GTDfZe
zpC{^9muG!r=arhW?_+QNl165BvFGvif4`Qz-Fki5j9iWQCT%8d=XO5d-EX%=SN;Ee
zKR!m<`n=6&pI_Iu?+X=<JE@-``=RrL$DHoxt}mW_-~YdM+neAX?Oy_llc&emS?;&(
zl`_?u{Z>6~&dF#S<!L&*U$5I8^u;t^@YBuW^R}12-Oi5}4x43FnzhX*;_KF*wqJRE
zJUQR<_LTPeIeI%DG`$MGxh7b!qiXfFtM{*)-OibO_S%&1%1-XrW6NW=J-M5`e($vT
z=e7lY?yq^GY}&YnqwlD>u%k7>tTn~e;lT3AQ*B<a*?dVVdrhEC>Y*0Sm!D4S>-X(0
zR!=)^`MAe8Yufa#)b6}JACHN6w{N|wv_r`FLe9>o(~h1O%<Fu<rPTj*gMZ!S`~Uxa
z*I6TMd~M6sq-#?n%yPcGxOnuu;JqKWuJ4<sq;e&!`@^wyyWd6q`ErO`KV>twt43O;
zZrc4$$$F)TDcigC_gQeWJU#w%Tj>FHd-;Ql=l}on+>~+dpY5;SCbr8?JJu^5K4+F$
zZj{+;-!nQ}wumv#Kg@5x=h^em=k4une>`Y5eg0^{MJBtuA8WVH6V%>!|MmL)b)2*R
zxU{Uc`+f8LvR?Ch7WPw<W^TRz@7wmH8)XT#M=rbpjn}V9Xfa-OSVh|?M&RH?jtNiR
zuAO%K)Ou-y1P8Gfk)>BdKL@`|xBnfv>+iSQ-H&UQuWj%@vqac&?hM<dd(CQoeE9Np
zef{1vw%PLkKD1|ETH@(_N6gz`Zr!h!n)7AV54jl%pWl4mZugO`YyIEs`~B|a0cL(3
zzvD)67xzcht=_d&^h4*&_(yx!u3x)P|9=0|t&b!tyElaED1Qypofc4i-1=T%Oxan}
z>nWT6iKzeEdO3q}{<|OhlD^GdQG0LSkE8m_W;m|gyX|J$>{P}1e`fuDw_E?HPKXrF
zHVL$^r_l{6YPBREPQK>Yw3Ib$+P7H~mEF_4opj%R-*)bJkgH*|Pib`e+|o?~-a7iC
zx%c)|zT9%zPkY+NRr|KB{rh&?ZN1qi)&IYp|Nl?=uS?VSO_3M7y^YCkdQ6e$EQ`XV
zLf>j@P*%IV``*`ek0wRry<RpuPpj|q+~ht>wO(0kGkYKN`!&V8e!W`V{rFqiuP-kr
z_tqZi5ImZ?Q6%Ebnc%y(xPFwB=oo&!xUgL=%0@5k?a!n7b%8S5w{Jc!SH0x#_xt;I
zJjt*B9sTQKe_e>obL(D_4=?-PYwx@JzV>~!D}zp2#jh{R?dL}6pPl;q$?X;21>I#P
zCQ0i~3+k4fVL~WT1c)&*&i4!1RQ~?n%ld!M>$B!vxY*!P7tA8{DZ#1k-P&!2-aco<
zg722yt9)Ma;UK&Ca!`A=<mJ-oV#o8h3MVd|(Ys=ozTmnHTWwIDX)*A#`FLbY!ojBP
zRj%Kv&#VzPe)A+Z^Y5Q?<@+YH@k&jJpSJJQ)b&dwjnhPq=WpG7-tPC3z2EQc-tlHy
zbe?B;Y-wnr%*kw(X4qK(*14=TNz3L(aIMjfW|^b(V#@aA^Xsf;&(*L$w;dD?>)vap
z`F9mQ*WLH<hZ{l9UYHCne*eC&`@VZ+{r`VQgV*i<_p9VEuQ|vu!Rs6RTdI{>CT`bW
zw?pY}+3nn)iS64AAN!xVGHH86)2o^3^G@<_&VAi*{!-enl{;6yO1QJ5@a2ZXeA?%1
zzFcsAx##ma?Y?C7CR@P|C!^2w6<_jHf7&j4D{t@DYcFpk_v^09&Az$p8sq#3wm0_w
zKidcA?B3KXXKOXL;1K6g?OBQsF2~-#e%$`wN0H5*Pj%DYciyaMsVNeSCJ=)!I>EWR
zswF{5W775rHmzyRuQFDLA5c%bc(dm7+3xG$F5S=P^Y#0zH*LNiSG^R}&fQ@$t+(sx
z;#JYF8_pl*x1V#)_WPYz-nZ`dr*2RBxpvQ1(GNEZ4)b2tTs~(~{G@rHzSddO>mtWx
zZ+6ZKVed@x+{|GRy8RmCe2&R2$+l5C=AsAJ{{WRCXXAVFr^l9Q#$D!Nod53EzC~(*
z%j^FB61CeX{Ixs(qx}CL?qXKaI|>rdzUSjWt{I_u6}c1RFcTbGcO$H_o}8F?G+3_s
z%|?^DKR+J*SX-tPBAhtkTNI1as>9a(HlIAs@|YLCum5|!e(6Hz_HEy1r2cz*D|@}K
z`Q4J>v$boP?Y`fyuiy3I5O?;v%=ZbibGLcA%h#3^dPXxYoN-V!t!QO>x5J6$c3)SD
zcy~PoH3t$8w=FeHKDMOvdaU_uR?TTMqcWFH{S>}+cWzsQe|c>@<JWoL_o&Mj9uYJ>
zeKeGL-@jk4UxM0){dT`Hc74BBefi1B$*b$P5u8W$Qdf9z`Q#+Ix*rcSf4|+XKhFr%
zOE{`ux6xwV@pJorzniVZF=hMi_xr3v#n<`Iw~IWnto;4GpQ@!d{bm>_#@79OYI^=v
zUxWYakJm~T2(zotuPFkJ9DQu5VyOv>ul>5l>?5y>?6l>kRR@+^?_YmM->KMLwlt(`
z!IkK(FE1}&?m1a)X>|Tx)1yUsgv-&{4yAretdCz?Z8Z7R?BJC;$7lE3e!KB>$LfFE
zT{b8?*;RHY);=?y@A>)p`SbpzRn>n!9$&t8+pSd<ey<<+o?#H#{Nl^o+uL`fott9`
z>UbUf`00($91BCxV2SDWGWP@N=WW0H{C>MV{^PwF8<)z>OP^Pn7Rzi0>Wgff5}|YW
zYFu}|(zO4x%=6>EiGN+ix6TCOtE}Tc<|RK{mAn0}S?<oK(?G)#>;6@C{^j`o=g)I{
zf5C>!gp(R*mOS#Tpt9Q%<8u~^pJ`r?udm(puuVGaT<Nn1v+w^&>$;it>D%l0|5ktR
z|Nk3bHzU{I{_mGr7d%=bm-);LD)zPI+ok-#xa`f1k~4<KMego}HD@2~h_jwM^I-ac
z2F91C<Np;&+0|6|mdjPWSeSEj#q;^~c4uc8DxaNeZO*M8+P>DUUv4g_8}MkK8~+a%
z_ua35YXwBT{qp*{e(s)+$1*4Tnw|W2@7uQRS6ObY(%=7LQTL_V?{~v%PuUTw1T(Tg
z<@_}LH1nUouJ50x^kVY%87ox}$qT-Fk<+bkvhw-d@Xs@f&snP5emo*<`aJ6VC*jt&
zT{C@lDL>f!@7L?)!Tz>eCGKBY8EpLck;~jNE8!16x7YvP{-u$>X2A>3Ge#ntHEjQU
zIDB;H(ziJqkBYqvp8qT4W3e$y%`T7^?j@x!of_u#P{KIFHDT4Ry<aYQgQ{5XKw-kI
zIY);B%lSg@!20)}m&{01PrLOpr+ewDq?4=mxMnC$V*r&Xby~OUejJwf1GQxf-@$T!
zVa)ou?>K%O$<cj2zrOC`Q;F;|6~VULejk(7L7uP#4gIu9=SA%KdrEt~&-Qy&*@buR
z`LQ%BDNNa(#_^-%`uC}`bxxNZmo4{cm#fM+tD8Q*wyf&YN%ib=mdJ$_*8bjEErkcc
z?WbH7p03$^&Wo9yPiG#ezqNFI%~S2nZ*OiM-I;o~li{TJz7MTec9*|@bZ!5ir}{4+
zb?fW(eV$wR_}J3JeAYVlKA-~b*SYe2!7|sgms>O0UA#VHX~x#8VcNTF>;C-sawEB4
z^!V2sk@p(>uP8Hl7<T*IOX6G|F>ST-TjBXXTtH(O-QKemA6%BbA3oo%Hf!Hk^LrJG
z4=-HzBR}`aiHWT*{p){S28{}e94{l7QH(*uJS(dVtNqRt1>H@OT+7jPX1@LYUnT9|
z!s9BRe!057&XiZ)ZqJT=OP8w7t$a4~<<95xw9h@Y&R(<8&FXQFanPOV+d&PNm-njQ
zpXI-O_gL-6H=*INrn~j-iN5cD+P5mYoVA9}?#F{IpU+u~udjPHGyT%`eP7p#{C(xo
z9a+R@^<u%JOZNYNp4W7eznWXgY?mln+WYk8Co%6$TeqF6Uwv=gzF)6iX2<`Ik}}B%
zDBQK1*-p@>>*<kIx0l=heOb2u^1C1VqRtD67%Lq;;~|@QT&CDZ%DOD4@a6gXf1ke`
zxBs`%Vw*FT+6X0rXGJ<3SnhYVdxN{q+^sj$W?!{2oW{xZWO{tv&Sy2%?1shuI+k1R
zRlU9%Q}+FCdHVTPmXW0!U~L@><K$yKI$JJJY`6$2;6W+k(LHzhT9ew}poxIbbKi0O
zaA9~RegB8s*)<-p!H7@mbV{WamvUU>k+a#cL+zMQ@~XVk(jPk0U1nr~T9c3U_I|lk
zay_<O^my*uBj%rWp0Cx*-Su*rseO6*0rj}LdzH_ZGBUG?{QUvS|I7U5M#*g7dim=8
z@EtY(KF`;Wll_0zr9dm~Q{`&0hg)75#K`#1G<v!=@3S?*k_9|AJ54h!y)!aDEHZWK
ztmVgwV$JUqID-ZeL520%{HyF6k6dqLmzz;`Be8wf&BRBuI9}I$o_*h^_}Q72`<ABJ
zPvh!-;Q2*4zwo~5^q5IWW(&808x`|jB?QEj-%OppbjH_ZrLWgD`0pvd9$W4!|MP@<
zm)?;#w)H;_%U@bw_jUD`U$57TKVMz0R8oA1Q+-L|;Wp9bhaX%C_K!{aHvb$;P1Jdb
z&#zXmPc!B@y8Bj^A@e!Kc9}`rZe^`r^Zx4T>a`sW{wxcw#g^Y)w0i&VyYDaQ*Z(~I
zXvf;Q>;COa>RiW>6w2PO<~L`ClFik7XME*<U1-0=$SxC5V#$;%xGnqryhlma1iSv6
zEG#vzVwP;Z9%p^D$X)P7#@!^fN$v7=7DtPMH>aIFHO-|<!RwB2y&<#b{e893_ov00
z*ZuinQu*nLYF&2iqrLBI^Q}IeP|o(#kJ_T~_v`w4UqO}5NMBI%4m5SP1yo9d#!obx
z^seS!TH^Wgxc$GvuHRAH-|_r#dGPqlW&iavXR7`(&b_sz<h<?ol;qCH^rVw(7CN^t
z1GRM4Zog;cnxUC5xUTDFR+8G%Yio@e=g-JhOMARBZkhHyQN|^pK~wG&*ZtQb)8~HK
zwtcVe+fAqSG?|Pp)_vPNKh@ae>EB2}#`%x?to1&h`Ymw#ha0Gp(`nh3aIopi0cQS?
z|8w4!fBi0c|FOIMuZy$3yIJTmdGy==tC(e5UG^=y<)K@j%*>r`8LM`=257FkPOv13
zWMQe<wP2FqJj;(qgg0OCOP9B={q^O`-uJcow*UWpmaPh5@dK3>TW;s=E`9Oqnz-u<
z<$K$=q)yyr{6M%iTi@X7uJ>#E#r0xlfW{(pLazSWZt>3Nfcm@p_5c4~maBdvxLY=_
z{?B9i%ca+2!#DrA*~RfAXVXcwmrEx5MP==uzRe{%ygvTo!WmmN)AF-cA3ftMXmk2-
z(AxE#s&|q!%?Vd*o}guXt0av-);wUAKf$E%_xJbsXWLyYo}ROQ?{ht-*mst7`8%Wg
z`#+zvPG_9bx6issSg>!$w_DlMcl`-1S+twk?&G-`yf0TQ?(;It_H&OuGfBjFr%OO;
z=Gx7S^Ji$j*l?Kdw9l&aPnoZ41-&|>?$vxgds8THqe$qzFqZ@B_iDdfbYGsk?WWp$
zx3guLjPw62TK8+;qn{6@yz`D)ubOUj`u^Q(W@$2AHz(KqeI38u@^eV^cMErdB_n9?
zrCWO|Xc8AxgXwO+W7I2Ux+=|c`L?*fpkWeko4ZA)bwNW{xv`fX7B{o=`|W<euX>wE
zuukIDu-WGMabhaJ&gR!m*1dc6n(5W&Ajj6%>m1#3+0Q!FasIYxM%kH}p6Bg;=j{4;
zO#1TP@Aqck-*zQ8o!RbZb28_;`v2eS{iSm@92EN6yC6)bw)FMd?PA_*)^0kbrCq}|
zf6x2m<9%nHGL+qVR&ZY46M8`X-TSWh+V8`2!lQGyep$$0tC73^?>Fzc8`J;&`3b5T
zgMYovufM(U{q|o!3C_DYYz8glOkS$=MmTW-hue{V2O61!S#siPzg{(|{`Tg}m0<s+
zpi08K%B1GU2a}u|8{XXg*d!ibV|esa{KtD~*&A)Z(+!et5oy=fMBa=5?FUo}*t{s}
zi}sxBQQ2#CUI_o4X_kAd=<I<jcau9LJ08uJG06xpYYwhyH(VX;4oZ?A@B7s37d+J^
zS@-C7@BXwub=Fz0tO)cX6(IAl+X$6n;OLhMa5%7>v3rp>QL2j=8Ry3wnubz;;>g?%
z%v>BlOcDZ1I*C%Pr|@91_YI;}`erzQmj3H>=?M~Sw6SmqoM2_CDdHs5^M;tjtD*4V
za)awdRYD;QURAoYp}}7-(Hk6$I06CY^#zQe_4gYzb`e~&05V8HT;Rh=)f_?-!(hWr
z7Bn>YGmE)S2WceelqXC~b~{^i2{i*iq0z`DBJd&ez@isIM5&H(IG{d#gDN;+2qdKo
z4NOdSyb&U?O2nuhP0UC!JDQl0($;8VMk=O8OJ<~EYS@>|8MhkFpP6YaJt3I5a{o$r
zLa*ty74Mm?e{6}<oqFwH_U%1B2bTMasS{Jlc&RBo2;S5r#fKEcNcj+D=+|K<3ro$Z
zQ2)h>L=^5CGaDNGPjY2h;4%$d#X-$~DkShhGu*bf4OtL}#sw)%Om?c;D;`4i;!p;u
zFQ<4r99SOn)kF#@J0X?1pvn;L@y1D<96zS4S<pssSb;-8AwZ9jaemR&%Ne*#gB#1p
z#4;Ml@X#0yWJKN>P05HXJX%~J%CXVnVzjtGloF7NOhCb5w73{8F0eIYMvDvN;=&~N
z!19z*0~u@~h0#{yRlTr!=_RRE?pDOK`5YP?6cru>2izd0{i|@Hf{DqlH(c13sG*Pm
z4vrrpA_V94!0ls`c?}KzkFUD)WB3PAhajXxn3(KXTM4c@0~a{Gpk)pfrWcio3cc2b
z27kxIcCeceSresA4T~9v$DABLOyYdMbP%O_G?-xl$H2%m8q7$^dNeg7<+Ra416*oB
zlE;uOn_d5wr=5?UQfFG|SM}{^Yv#Lb-LLfri);!L_Qz!|-Wuk`o@cJ{HGbvwBAbJ{
z5WnItMDJ=UJh<$7>$BLFCGTU*jrUsZSKS)2$yRV_XNUj#Q+~=a{IOg8trE{)4YF69
zulI||hKNa@0C`5n`M)gmK2BNvuEx~2DydG&YDxaBisq@8w3w^)_o?~+dQx8U`Qz&1
zs7uWKXZ(w`Zs(f6oX&S6Z|WX(qNc0B6Ev=_mY+{e*V_DD$Ln@}a3t62O*+?R2mc6(
zo8kL(^P_E_wY=N^{>=Y;DXY0^xxTE)l5Q4a9Ph9|j)}?cYe3Fp$@o7nyCeJ3r^~X1
zPkWN(>F?XQbZ3;7cgfeNJuczfLc+hx=bLOQzt(^IU4`lE`#0P9vloB&BW5znq^qI9
zUp(~Dl=*(=(_Y=o{OxsM`KP|+YRC77*W51n>vdqorC$4cme#ND-*o4R|2X#&GZA%c
z<5Dh;A39T)72D7GG}-IGa-pR+Kh~~Jy{+>gc;><7My>v3bJpJ6%G75raZ|ne|69Qi
zE5E#dqwE&4jo>0d(2+BXxj2551g84^Jjs1CDCV)!gJ8~2Hnx?4s(zF8PlnzM`xhyA
zT)OAY?61%L%lA(D`hJcwYt60~!XF|CyWAlbw2I=;jwjB3JJ$$(Sovr3;p*`9ESXW4
zj3?h;A)`C*fV$edpI`D;>r@7d&$0YJEqt?rzg>O+OU)wta<>D^Kb^O9Uw4%?|EmXK
zyBHd)I5~b?@!oW`*l%A>lv(h(-`k>-3lF59Ius$e+T%w}+V_KN-@TZ1_;X&J>1+4Y
zLkr&g&6nO8bZx%<|J1Oue{=fR-!;|$7D9|oyEr(0Txl&l**>S{<>#9x-`?BoCbpzf
zjr&K4klkJ_&)GUJf`3{r`}FeJ<3Q!`bN8yR$H$%frT$=Z%G)_aG#X7Nfz!}q?&*GK
zn{3|SEc1BEtNZfi$@TkZzFs-!<n%MI-o0J%Rhx0Xm%rM-(zI*)|J!BF)e|BnLKqsW
zKu&kw*qg4y_hZYF-0hLZ+~0iW?OCuXcO^@8RqE}@-(uGG?tWGO>bCjbpwIULUw>aM
zv;52T{eL$LeaQ6uUwdWO*ZP&}#LVJe0i6nyH)SjTuS2TmQ?(0ng&F62O-TDRg*9?P
z+Q&&Tx-Yq_*T+>mi_8A~-n%*Lo^?^m|26iL)&3g4zW>9Y<41|$-s42r^GZqKL9qBS
zRryU84=zu-_xIhxoBfm3&&SsU?o$h|^EQ`XzrXJPo3rKj{|1SDk^JBJ_0v3}CZWO8
zuHvFkmvk>rF@D}t`F+DFv!$BB&r*$_eR;LDqH~?j^<c~WPd*;HvikhymErFr^W)-Y
zGOj3!j_qsbe?Q&!#mD2?-sPe5exKai7S0lNNs8Ibqd9Edmr#QHCs{ZIGBiL(U1=Tn
z6!$;ZWc&VBRfO1?%5@w+QkGwy{w+GW)BL{m*RGQ1#?P0sa>vKY{5jcVJJlgzdrtN8
zt?c`?b9bIQ`10-HZ&8c#{gB!TNVOzt&9O!TWLuH_%j4(M4$fP9jHjQo=2G$G=hybU
zJk8Ft(sEz*snnO>)Q>NpadY|oQ_Yta{9B#AKi&9mNbJqf<AO@FOw+5PwqzvUdMx|+
z^0LErAz#CG6H`HHgH8hKej?6Z6Lm@Kz0^eCo5o*v?hG~lc;r&d)XPWD*l6-b{5^5%
zQjGtyi_&jq+%romSsE_*^yNLX;%{3@o;UCJI?SFw&u-UO{axRm-gASGkl<!qSk}<s
zKU-(6{m-BBw!)nAw)_msPUWxux6|@wk6m}OZRLUIXWt$$EngY4U*ql1d&$A?<Mv+8
z=1%{!S~%7;-QVum(ev-GmuEzURQ~rZ|GVJRzkM%_-|tu7e}IUp(;<NsRL~06$$hAN
zJ}o<Z+KVjD%UX={UzNRb%np-Z_Wn=e={LJ-@0G`t{ku3_?`&Un=-DU2=U=XR?0fxB
z#kYIX@BTPG)zz%6d;UA?*Y%st*TwX_F2_~cR-c*G{A*e0udgrPDBmTxf}KO)g&^pF
zwvcD%|9*IRYI5`?>uoDoYP33MiZ2UevfC&e{3GOC{nx|J+4pSzeUCo&a?AT~$J3t6
z&nxsStgMR;&%1B<X2qMm*WC{+ztlguY;FF5=kE2h=AGN|a_1Xac{yX1xxe!lXB~Ur
zfSSUvrosiejEwWQ#ah*VE4HuE;(oKIw!3sw!uc;=2h`^`E?@ihfa317gR^SOE!3*N
zJ73mco1^VHdzEC(u1`N?4~w6FQ2bZc{?xCJt^9XxXEwiLe^Ynx@Jspg=TH0b#_TNL
z_55`7k{emXBtytii<|H4uY1StpZ0N%uX(&V_m4e4{;UpVoPTuVT=Ql-P2Py)>u+Lz
z_gY)swzGJ9N$H-j;rxexk6)9~pU19Ie{NHL`kDXHXFt2G-)ixo_-%`P`g{Az?Y~%S
zlx_$!&VMCl{Nsp^9Z{7r<VZ%H@9QHEEZ=nPs@m-J;WGu7tDc?lElcdn$!RaLlGm<f
zbS^uccJ5~WokvSI$yNN@bZWQu#d#5zR&V<Gp{-oMJpR_MkJJ70Vn6@6m@Pjuw(RbF
zF@4^$Q|$lmUCTXPsyFRfm+G!-ak)!Piahq4d|VlRnNOP6FT5t{@zbh#vk?OZSfdOS
zt+tSraDQ*Ux1VTRxwt%p$!=<W+$^)-XZQH+`xG|s{>q%+>pvbm^;I`>f1!KY_q+CA
z)hE8z6nk;2^6pXN*D3bb9>&*Kyn8Y0dH%+8f;WTL&lY%}>luG%uN~ujbFr;Ua?jNn
z?6vs)wdBo?hcD-5^LxzS_i5&p-IJn!eLgvRd1+X5<xcm{zod0Dm)aRlzxZkUIlIN1
zzdyH)kC61f@7JUH>*Dq%smcvcbLYNv-eaG2Oa0$c!VR}lQGpLDwV%)Cw|?2~zl39Z
z&W4-6rcUl&Y-Kpvf4xrQ#Yz7nIsbflciDRFwr2~jtS<K|e!ky)ch>$w`O|Vm_pkh4
zdnat?`*`CYDW3E7Z0;4^J^Frc-l6|#e}7zRe^*&-F!#pqzsl>EDA#SWc=M%x{w<wc
zgDvq=pX0wTuUxP1wY;Wa?w6Hw-M0MxqOAS>+>FfzvNmOBOKxm)-h8uu-TwbiORfiR
zzP$MI^W~=OUw!lC4Hf=A|Lwk{P?|sQbL7_ww|@`3JTL$Et1-O$@5h@j0jV!HYU=Bs
z_$6>~>Due^Q|xv=?l38M>g9Ml<8gka-Q905v@<`S+L|tJU}XFG{Pj!!XMZ_=Dk9Fe
ze!h+R*VnhLb8XhdTdmksa#Qd&Z}sU7=ic_8_1nMa`BD+@1-2g_Wk))^$j$z?`b%=c
zuQPht>BeeXFZMpVvZgYBN%y}WPQQLnv3z-O<>yOxSi3K|P5qv~@7sZrC)MrC45xnF
za{bZX=l>I<c75NuGc)Vx!gAF+!i{Uc=k4&aS|{}ERz<}BZ+YLPkw!eQXWk2rjEwX7
zoOEBO-rreORAt7bq1?74G;DQCg_h&o8ItPUKSG+UHmB{G#l|l=rL{)vO#B3~W#7{q
z=lw0S(W$<=H&}~teukl<muiSn(t{gs4D91-K0JGWy6VrNJNvKN<gflJ#$K~-?uX55
z<m2ycwqu<Cxc+0wu7CSxM&5YLKfl)f+qrG$ME~Y*-F!BZe@W*0J@f4Lo{q}A^FRH)
z-Ge6@uk9M_9bTw@5mVsY+Y-0bgPn0DQ_vC(jwXe!hJ@uD`lq@TIJAPEOx1H;)zI`s
z&vv1(7sp;Up<mYjIXBO|dt1ADXZQ4z-yb@cm6xTJJ^TIU?b)|~p8ZcbT=ll(S@6rn
z{zenjbPqWRN@eBPZtRPA?)|=I%D(!G#V`BPH$A*|E0a5oaoOa3b{e|I3A@aSYu+Dv
z`0^6_J+IX~vlRapE<c$0IauCbf8W=@**}vGWi_XJJg?1uxGc1GQPerZ{}q~le|`)9
z%oDL$)W`Vglb6$H^LkjPFI<uKcHi^+{=ZXeg&CKo>8|3G-Sp5VG9Z23GRMUn+O9j)
zjndCXJ-O6(JFRic->%K3)wc-l>vLGZ%E&lhY(vz{uP@gqoqDfdZ^-Z9!uF_pj-S+y
z7fh9{bI#lS)#3l%Q(0e9ReB^l^IT*6`Q`aPpUQroUiqMPqvPz22Nz7)x6$Q1&&<#_
zhvVCIr?XdfebqPrf9_}S^!qh++hpf2pP%z<e$utP`}@qFUEcENV*e6;`=2_pTMpV(
zdZ>q${oPQ0Y5TwTGi&ySzu6rTmA7wO;*3YG-38~`y1)B>w=vf`J1g|f&u7!0d32|R
zRww-}PraIdZqMVbUp&L2)SXnr(_UxuT>o;!YSFH<w~q6lJ?yqI_qC2ya93_r%DK!>
z6VAw<cQKu7{`p^D!I`i3qxbl-&Q^LLeA;E|{Pej025+}MoAdMAu@6zs@p5zh_Wqpu
zB`s{D#;x<_vJ>{rwY`7io8|kPC8=RYHKIb^biQ)icwRpB;CzmEb1HvlXI^Qa|I9gU
z?$+B*nRj!dPrse`X7A3Qn*Gny1X;RrBT_GX$!uG>{Dk(;BW5B8=cnBk`2Dk4=Y@#w
zue|QmbkF#>ie-OH7fW4?e_v%AZ`bzv*X_9OB~!&-><|j5ynTo8S)aGKIDTv~eYsIn
zc@x9&spb3T%{#62vt~kTpwf%Y2Np4J7Vs$3_g-A{<KT=hzq}(wr|HZw`h7s>#$@07
zk50#*fA-5pdeh52J65VTo5|Hw_2-7Kd2#Du^_8{tJ6X$4EvuWiZpYI_HNWeAUH!=a
zV@~yX>6h-)?dIoy*R_u^;$M8Ed4<E~KNtCzODJizEwak${`skL*5BZk;zv6<uFl!^
z`GLs7DMh>gZPYO+`F7*Lg*4|hzxora9#4t(U-Q`fdjHx8;n%tO85^_P_f7t0`~T*i
zLl>&L&rbO_sWto5T8<w_w(LxwW%RdpzUybjwWmJ2Y+Y1ZZ*9VTx@KDYOu0WNFFjrU
z+2QiG<+d~ZyA@9+#i!3o>)KV>mg>0hY~BBgcQ*e2H801u^Q>HbX!GHh{!4GqtJ6Pg
z6uZCV<h|}KoJy_*S<j8<`+ZM8+;-OHt;ox5&C^#^_vZfl;Uc!J%Kqqv6u}j<jJQpv
z-d=q3LTq%()y_qiF8OJnpT_SVR(G$KV25;pDI??jYkPLte*f-YsnmVGX5O>tlz_OW
zPahk~FT3uxXHI*L*zEdUUyh|jKRr0>?EXEz|D^bB>J!Umhb}$&uY1n<8`rA)r$;CJ
z{-e5X&(lja)^*!{)*kIH`&~BM-gf3YNjt6edc{}E#aBn4SB(7de2)%;h~nhmeA1WH
zRD#aLv=lFUWgfZfCA;^spJ_8!Rjhhv#-z*N`$J*%8)M&J*BO)BnY7a+?w9WQcJFxR
z*T-$k4CU*mg)iRu#kyN;bzbrB&DwE3>8YZvi()rCSIYd#n!e&}FyD_kb9f(bO%40G
zEYkYbEWwxk+xN_}7iFBkA}VBy@8-WX7Prr@{Ovn0&%WZM$@89IG5@P~k9~*~^y(@r
z40Ba)W9=?`Ec||1?D;CI{r_*jWm}dzeZJ}b`#=0!O3ZA3Zk&>O{?hl&4=>iu2u;ws
zm9)Rcz}0negxR%=YkE(#{p+e!>M^aiuDzCHNpL43L*q6kCc9kUs?<}Akp{|4)}Qrk
zENcHebbt9(=g#M!>GPKz{OmJ*-|nY>Ud~t@c5eRvSJStjiT~gD{NJ?p`cE78ZqodG
zW`b>e$d{APPo&F7KU^-|@7}j-d0y>l-aBUTr>C07&s+cFd2~<wf#*BT?R~P-7S719
zzpo>mmDT%e;j+B?w2)uF<{uAR)VazgJ~HcB&AnswT?OYZefFEa?%sMkm5_Pg7kJO}
z7r*n{O|GW$RY&S+|D_*ekC#TK&a?ezwaw|m%li=qxm!~H@A^7je$SV4?wMDU<<F}B
zP58U>a^vfM?qgG!?GD#%^s!S3tGxN>-_e@_5%>QmajaSKY4f2!$?ZG361PvY__MHP
zTWt7j+rL@eKf7IT-Eo_^;$ozNW>m}KB#sRk?lGoHbIWe8&b*~lVQg}{Evf2X%3=H0
z^DT62Kc1RV)3JVYxqNtU#@+jT-u`>d)VA-_lkUnncyoDP#3g6KDPNtHrKT!qb91RE
z<9ti88TNZYXU^$JFUvacCU`0HHpv;w&K(kSkJ(ogXPJI^tJ&G>pDq+nPpzC+C|dn3
zrY>j0;^yfYFIQfEAHOW`?`gg}TJis8MXx`({jqrTz1x?5Nu}HUi&ws!|Nm=ISIo(~
z_EM9cooZX6wS5K8=2IK{mxOOpTxoWW$+-SplkwRo!E-ljUPfNhwC2k)^R`=S({k;@
z;%VN&HG&zP>c`7v>vw&<TJq$o@~7)NKTlYCsbS{qaKTgQC;mk~ThV?wTE1q|wo_VP
z=1d8Fr5PpoVP<Vx-OGRS*ZKE`o)O-@J?(J%+ZnuzMc?kR74ys1GfA$q*Aj7Ex+vp#
zzO_N_cBjv;tbg*n{Uhu=^XP=M?(?>}R{yfOw-{f)adQ8!<K905;shV;e0e}M`}04=
z)p}o6uQ?U4rQlw|$C;PDX`h)ECTrvTYCi8vB3j9|+6oUYZ=Uyd-P?xy_S4wYm%X^I
zU;FE%dgi&vWq$TQZXKBMQ2i+EEC7?gCdtf#`}gQ*{aCW)WR&#N?fiWGURKH6UtAu}
zJ1cH$Tz@C{f6T`t=AT1dW2Z;_-_*SAg#7=<(_Vi%zW<Ka>JOLCid{{<_UHb>mp|8Z
zoquq1ncx0DuWEd+mmGV$e(CIaHRfMuCvEyNKWD}|iFK<tiawmfvDszC(!JmI|CgER
zw?k3-lTP+q)|y?r`wr_>EB^iZ?)v8}^FY}ZGICklY-i7#!@KzFCHBmlKbLujzq4NV
zDnRhVOnq*SyAxSkZ)HDy<@U7Ud@BFGso(Y|RP4KPf8SmYxfPlDvTuF$SH0izy=L>v
zi}wDqc6s~l&t8gjkNq5E_4r%(XT?2TscNV1`E;K*%?;~aS#S5}hSO&MV4J6eM+YSM
z85!q)JdmAwk=ajf8hg4@fbnOZ;APC)rKkMzx7WMy>9lwFN$poPsb{}_x@!03&eckV
zj7>VGf{imbI?h?M$Y0+!uI$2%Q;yf~RVD9}ZO^~^x8eNV!|qGh|IK{!Av)I7s_662
zOYh=mEk66ER`EgcgZuNm#s5A(TeD*Ia=v)I*Ue_LBh3>}2haETU-|Iw7MCzp^|lRK
zw|=nIoN_LY-SmA?=F`UH_IFy>?oYj~|M%C$FOP1^FMYXumd)AQo~nyJ{aW|$T~g+(
zHJ3tm+Ro#>UwV=`e_6I%rM2zvW9?6ue>&w`opN~7--^eTpBcjMPL{*jvxGPJbvZeH
zY&mlE@67$>pDyePIoA_8b(VaNwZ_?d`|D;bpC7-;>))TY>~%BupE!JY{ptMUY}Lp1
z=H=VQRe{6cep&WDS@)W^?+W#AJ=*K6S8F%7{JeCfK-#Xh0FTG3j@5js?CLT&%`-zU
zc517KRCGMYk2xiePrtl=z5k54t`_fE!{omO$-TGtJTmNG5`O=;Mee36XI}bS^RKhD
z-N!hegV(h}<5uTwexKVq*MAAb8h#1qVZ0U*yJFkKyL*IxS6|<}_);qW-l^;4zxl~|
zb%)m0@7;Ns-+adM+1Xnq2zGA-n3(K@U(|lsJGpIH=JI(qwe`0TX3mRTp7(i`{r-xp
zdy3BeTD^Xj{r4Bek*agol=!br@}KtR<=NxTY-?xlf5*H1{@idWt54bGTW=m)=Ogj?
zV|r$*&Vx_)X82zQHEq-1>`G|wmYvSKw)By>bN1aIe^oCXD!#`5`ieM{UAWDkuv_2v
zJp5S~GljQz>#YZpx9%>#@qTGvjRyaYH@m;Zyxg#+$@k(h^9P@=vCm(U+E--}f7dR4
zp7!4#+K;cr?r}@sZvXE$_sjq9s%(8{v#yu>{d801(z)lRWq$p+JWh79nf23;Uk<v@
zUpjO7TqWB-n^U7=TYnN<o!kf-4d+~J{{G*GD~T_wZ}WIDKcBVj<>^0<CYfGdKEH0x
zwMgBzhFLncpFjPrRGq7T?3vcF7q7P7W_=!M$1iZV<T`WYi{w)!Kdx``vb&oxJzX?r
zU-iEaH7D=CH_*u4ct%Hd-P4uVk1Z*!x7L~ee0QY6vkO5AYHHtF8~l0fw|@KR{Q1JU
zWuUg?oy?ffdB^5jzr4SGNqqeGAiJMeWZ9Rm*Rw6oo%WIU$C0jUHhCFU@6PfE|JSi7
zey-@fRC3w8Mce*;np<!CFVE`fvhYuyf-F&mjT;YF&Yc|^_A4+fQS+AkroT6IZqNUA
zYj<SC%f)LB1?|^VJKbz$7#|Y->&xbi-aa#Z^YeFXTGSPM#`2B$=`FkGCSQLNPq<=K
zW@Mb-S5oz1r@H%|`C^g=W+@kQwl4qoIr`;M^Y&#+#pP$D&E5Hz%kb>9w<|N>@3ptO
z`~QS-<^dh=CADT2o1<6X{kmrP<zD|ivzN`!`c(4Yf7&_iqb1uG`TEuA*nYb7!o>f-
z=H?5hChS^eRIB(v_;x+4M6tP0^evBjX{p%Um1px@BQj^(+s#~b>0HofpV{l~<$v5&
z`?9m){8aw^b3vV)KU>RVDz}xKnf7_PrrP;a)>CguzptNUW>FYXReMD}bJrSqxih~K
zXX&?j{r++J{AY*ImX>F;D_7-6i+gWQIeg4?+wA!@`n8|`&pXF#cRw!q+?UU1*`92^
zGmZECR%f#_;al#8%~qD(dbH-}-(&S<R*zSfoDP1!^k>>kt-FOEf_nX{eL%xm@InV0
zV~c{qgUd`|`R9IJ_<Vi&=l4G%UtQ1dGATHallklAro=s)6nFhPZxZ`9^?q%BiCs-t
zoR^x{@|5$>J15KSID2i%yxNCbO<w)wzkE$wep*;u!RcGC%f6n=eqTE$%<kL8J*Q4z
zJAHOi-S)o=^mKo<N5}c@-<9TK_kQR7D2ugQKlE&U`pfIU^Qq<be(~p4{W!8Ac;fP#
z`Ez$(cJuz?-<{&zwfDz0_m}6=-Ipe>lbz^RYq4$5S=MU3Nn!CD>{eVAW}M$}^I5<D
zlInTY_U2L56K7t!mwk5TG)aTls+V*7KLwm!%D-nO`?91q=IispExyl{-Swvw7w$|u
zwaT=%bl;X&3nVZ3T=tnLC;8KHmwEK}!t4D$i#I>Krle4ExzT&s&dom;xw6g=t^b?B
z)t|w>#=QJjRv2r>#x+J)XZYKBf9I*UkDavl-_h^;XWHLiqZRzGrJms6Vxu1DZitzy
zzNhbbc+vQhy}adGz3rQSc`<($ugm%&{qpK{_pc%Imf!uVv-!ZU%=WAOXWZCUujjfv
zb?^VnYu7JRUN0wo<)?Sp)3m)uZ-wp5+%}J6*_vssZc59)Y<-&UtDa+CHb42^KA{ht
zxjX;P41D=poY!CZzNB<sXJ)T1lc9S`<IMHzO`;zMuUyV#w?55r6|-KA-rZTDmtU^P
z-TLOngwV~2TNbVF+xczj7tgSZ%QFHwHJEH%XB%?=nX~t|Q|40rw(nZY?5&DQZvES$
z9?bJFbc=+M&LRIm#T6Oxky&pF(s)_hx|ZK1JgF5cBJkm*(v_B3xkqOAFMS?YZxLH}
zKY#P|KQ?PO9kO}3GX0)c{=UD7|0*uXoK6!>Q9J+6ok9JOh;6a;?;h?YqHOt-lK$S!
zmHzu~qsg167c;ND{Jr!ypY)_(TPM7^VaDBaXKLud&W1Dfb$d$ej)dp9$8-HS@@<dp
zugfJzLiLx;-u!TRmzJ5KEt8)18T(qRn$JHkJ-E5)mA7w{KWk0W)rp6HKGt2og!_H9
zvF+zyGyW8QoYZ~R)Yq!waOLG=-rw}qO!wAi9ASU?VYOSz)jGQqhb@o#81A|CP5a!m
zZ&AhPYC6^?RsH<dx+d$Q{HE*sHLCxv_!6AwopyNg+wJFKGB+!3zQP+AHt#qQ{odE0
znT+kT78J`>y?a$zv%KES<dXHx0uRB*H?y8LU&`vvF?QU3xO=PqhiAX%FIgV{-+*^U
z<tdZ=|0{3J-#C4KXT#aY>w7$dzt7g;om2YCM&;@$Z?}kyAJX#6%-w3|Jeym&s>Wj7
zif5Oniiy^{rM*8tF~5FF+6k?HIurKRv9u5|&h?yyrKalKCim+lCoHp5SgSTYIV%2G
zJ9qo7#LTCy`)(~>pO}iR)Io0`)y6v<Sl<8bqGEll^7;qDhYR2CdG;`KX5;Ix7j?Hr
z5@W(%&{~k$yB=?R*ZeR4tjNQ8cdz{mjmrAB^;oj67%^KqXUt$_sri-hUiQ=V(o5T~
z{hhz%N5j=$FT`%?5Uh(D7#cYh6&@HXPTBoY%D-=qzOK>vuDcPJl!$S7DClJ5p!{3n
z#8`8RljBFoI`6jv1Y21S4GvRTSZY>Xnf<Mmn3<{~CMLV7uY;^z2-X+^3IVE&jPtd=
zE~_PCs$XEmoQ4Mfr@OB35uT%9;Rx|`II!GnZ)QBff|QYoMN3`bLGVt!t<Iyt%rP3w
z$VJM6(bSB{^Npj022#;FT4*2@t)peL0%FO~XrX~r^^X=B$SthVLSwYhKnj7;LIWuT
zMhgw35Ev~qkV60|%Z#=(kh08ZO9Ls(jJ7n8v&?8qV`LQ?$E+V1AMbPzKY4hc&l0BF
zJhgdBcZ+8GBIOU{)PV>aA04LpKab`AYtPnt@Hsy5`yyLig$I`}FS<tXKuiu3(3yr^
z6+X~4if6nCT2=x&Tqrt6Ovxb3;lOe0M#R_xcE<_4$Yo@le@|@NKQC^MA0fM{-^$=n
z2rm?02s1I+)h?3GIdVix;eqkSZ*$(NA-ZPRT`1h&&~X09<?wA=__;WKd^za1(UZ_f
z;DRJ3COgsB0lSS8Sy^h-)@%<axL0NJqK1a^OK!aWw(~e>th?t@7a|sr$DEMd*jUEG
zQgf@(aHc~z=uFr}DRM{y5ZHAm)UdGB9CJUvY4V<ihVv@_#TW?ro~0_*;lT3ioqHXo
zva-~yy0iNm!4qD;@G>&a-*=IJTauEfz=xS0*5}d)-oMr9;cy^b>6OmxTi;n&YJSDd
zzoA6PGXbF0daJ&!_&aj}XsUn8?QTLtzm1+j4hPaFy(zQ48_dLHXRDfNODHBA9IBa^
z?B1T7;kSSrG)dxM#7!uTDHy~tG1)ynn*Pu;*5N>UP(AyNdP07=@SBOrZg2h@Q7s*X
z2f+`|ZOta+um$}b96!EH?AstIyd0E1Z{}~CMJU7g_<#Z`IREA~JJ7)d&vzYRBN$|`
zQN0T-A_5;~PPi4<P0*HEOiXr@)ArwfEhi-K;iaO-YQp39w?qX#WKKUO%wh$)KI_g2
z8A9G~IPim$<44c@`AgLc85!q${^3pdPG|+h0Tuy)4>K7~#4Xyz#AJ8%ZFDuktxmr{
zyHMj_a^5x!<l^|@Gv#jDVuH4~s46@#4lJGC`!*X?*sOKWA$ZT@3eX7@Uw>VZ^97yP
z%GvRDDfaB!;NZ#vI<0%lF{$h&jLd9HPO8t}qg0)04p#0^%4+xf&1RFNBON8TbGI**
z&foKK|E9%EcK=1o^rJ)>8RxJ1vg9wkEJR}nyFCEi_Yjr4^{U#L?n+Tel3j3|_1&J&
z=SrT<O#k+y$~t;sgMYfyJoO8W4GsS67V~hP#qo+|QPFwOb$|Z9zg+eY4q?6kb|OP#
zr?bMUcfN*4MSdQeSO4#)@SaKi4d;)1wA(nfHUu;|SJrbDm!Y)*50=~i&74*L@8{$K
zfB82uvmvucyA%RiYT_y$ww7E8bT3WpoHyI`!1CuhYcqvFNtVU>t{#r!r!kLfPSvZG
zntnWWe?A_+8`FFg>d61w4onI5n;HJ_cKZBUwHM1ce)t6B>4(7z99-#nuX@0o8Nwf4
z+9qd1YL&gZ0*v!Bs^9M|&)*+%_gDAhj$NI?4-TfxPtUE1OYalzmz#f7*L#6GsKjr%
z=moJIqkK7_q6jv3rpm6{exNyT2Uk{>ny5DsjPu0~p1G$DDmo5jEya;#7EA(7xxERq
zb_G=(lV>zE_;<_dJ-Dni<7PGJ(CYArwNr3p>5w3Y1Is7f%~}p}Sb~tSz=zC@hgoZ)
zSd6RJgGwK+)l)&v!J@m-i;Lq&$foGGA|T)RfT}~?vK<Zn-3e*$K?yM~acdAHfq@)_
z;_?7bM#lMGWvl0cl0l=VkHdlGNBP7*WD1^nvsX#s!Da0=VYr$STAB(Ef=}jc4F(x#
z&<R@mcH<$Foo>_2y`UPhs`aWDj@;{@%F0rsb#rZ57sxYehM;W~)-eZ`yBci%4k`lH
zZ-~+a`2<T%ykbd1gTLzTtKePj2UOG)9$Zdp=l-#UBkfz9pumThqG8&&=7pz<2z*$X
zvi+7OC@5weVF5*I!AOeKmlA9KU%9;GXZox8&t@hbGr1fRygdA#{8YDn|KqCO&E0-k
zeSYn=kB4Gw%DPUfd2@f6Z@JedD@5w=$>XsxtD-jh`Y_H1-I#qdZMN=N!{aiUt5z=a
zTEFjC*1!LtdnFE9r9Piq?x($ON7CD`a<yMBmK>8zUvl35{~oimxX$kh2n7|B-`4zv
zq(0C*@zHzlx*6wdZ@a7db$-<=vF}TMzNxQxFt6m@Vt%vwO><WY?zmZWQT6h-Zhp^f
zeFKZHvui$?74I|r)m-vY*!gn2e5HczuV1Tk=e^H4lyZ}&T7SRSH!JTYikr_*U3St*
zd4Af%p5^zdl<$6fRQz(q?SFIc{eE%yT-fD@pO3HE92k{+fa#}=eBH0iTTi>XFP)Bb
zSgF5lpWKJYoQ+2>wMpmAcs95Ep2_Pqo0py3^xb2p>xO4<x8L{E-~Xowd`NsV|F&=Q
zwAZiR{QI>2{u=OIDzkN&+(4Iq{Cd#LpLO|;;suR@1B~oT{{8)ZU2Q(-66_}@CT>0c
z)cRw0$<wLfe((2u_LH(IS@9r3^7vml@s0ye{H)(jNt>BE?bfb#Ug>FiyIw51m0S)g
zAkcEM371bt!+FqE;GiofK$lqEI(@u+xw~9t%B(#ncP_r=^A4JuVnNLWq02jF{)#%F
ze#k`sZGFb7e*d1^_rl)Gmfr4td8GRNi%&_->GM?Q?)o?_^XSg!Z!a0mPd(UoKlSzh
zuXD|p_wSClnEq^y)`gSOx%1583MQ7tKc2b$zR&LXQctOCy&nSBl$>^*=23sI<n^sz
z{QJMQm3*o#zb5y6t97mE17pzL>sP~~mmU?5-=n%|`MfHv*qV<=U(QUQmzlZqT-v<M
zWiv17*M00ZIm~1HWOJXKt<~T2|Nr>Q>AcE`Jnw&t>7$({y9W4<(dYB)_wk-8x$HZ=
z&+63*lfPdsKR<u8`ltE+pT4ty`Y2owW?H>wlUG+)%4Hv8-@C8=eV+e+$s_JryVPya
z>S9p&^`X__<KK(N<-fl>!SR0I@4UK;Zy)#D$8GNCz6QGQ=bGGZ=owoj{tgG0yKdhn
z_F-oBFUd>F)phHS?#-zG7RF>3Kd(OE*Z#BHy)UO;)sD*jzV}bit!I;pFR{m3OxW`#
z+j_a_GwF!x&h-0r+IN3{>e%w&%;sfJpUqNtWnGx@zV1h2)XO!&m!gy1u0MNwYOaLe
zn`Lvq`)u|x&b9mfR(YO(bbO6pmqAc`ZmsSE;gi2(%Wi^i+<xp@_W7*&^5S!r>3gmP
z##Q|P`yF&$_(^rws|zOk+gaLvI-&eD@{an2kOiw5=dTFa`gYsxYil3hNbZ08aYNKy
z?h1pGoGuH}L01p0Ub`*oa;^A>%u`897{#xHXMz)J%_G&>t&n?j4)a-0*>)lpRF*0@
zECA(Wv7^7D4y2!uDPAgFerxeIarsnd@7fQZ-!EU^zw`67FUxagtUGt>(dM%g*WJpy
zZW4U>LPCDMg<9;VAB$g}G{5grSies)-D~wZ>-wnr3r@MKcw+y*3I1siVR$91I(Kf)
ziS^yv?rr?`MgIMM>%U)~)nAj#-}GQn<<q$<m(5U`UltTr`n+S!FTe0;mu9^a*Y@Xq
zv$~ixWBu0iKZ~m#-Yx%hy!Pw-eIg$^A8!A4D|`KxLtNTh9{zeV**_@6r1J0A>zAeT
z_e|uEHTnH!^YS0{2U*2^f_+UxXQwWjbiVX@?De#&)xw|)N&d7{Y>e?=yFFt5?JVvR
z(+8UmvPmy_yY2QmKILh(-)^SAUgq1uUVO&Tz3buZE;0M!^?ScXeJq%?qxbw`38f8p
z9(gU~_~E-I_re0lOwcW47x%w4Wt{&l#Rqc>n+A(o$^rGb&vVP~d4gIrRi93(fA;O*
zZe9GVvZj1Jv?FmB)JV9vc0Fs&HQ5~ry9!npc0Rv<uQuB1SKsWYJFBmy^>^8Bf43=o
zR{gPmrQHAi*_SU%e!oMtH&4hQDrMTuOD}H<M0lUEOTTNRey6zl*VVWG*Ub*AD|mao
z++VxK@Xz(dH$OzbPI)-{*tc%e>)yZDT5MZ&aE4C6rb9FL`>(J4Q1>{;SN{FZH(oDi
zl$x!w-TuEce97l_+nDM*;qSjJZ8(1`d;Q!+d(w6uwb*TbuOj(hz048wY~ynl$+s#V
z_Xg|4^Zlxs#(THylBYW8LOrwSHQtw>&B|W)<?{T0TejWX{ce}`+`?m$u~FB2Se!tq
zS7OoY4~O~v4P|1sa7>n||MT(ZU(UbhukZV|b<0J!$9CtHG{g^X^IUl}-Ls}{N_5Dl
zUoRH-pPH=J^;<Bk>--7bZ8wyBKe~2oz42lDy{grD9F~mposMB%Ip9#uBy9CS`1Z$d
zxAT`T?zgkr`~TmKVza=Nzd%=(&Z>Mi^Y(3@%b=#s0&b?liQhrjD~0=Lr`=EPx4qS4
z6=?H(n-vq2o$j~Pc<vuHwVg{ZpOnsxyWQ>lzc$zE@4??${nd}pDXv~Sl`pPz?XFPy
zZ|`4UnlHa+dtTJz=9kOoXstiC`I8NEmcQ%Kg;&r0bH3bVDX3DFcfUFN^S15z+-Hrl
zcNJfMf92WjuU-3>X3wi!^lisp>+W+_)xWOy-S@iu<@NOQMNfnKm*&TndRA}#zVc<Q
z>I37_u!AqJ@BdfY)%<CZ>kf4$zVo)<V+>awzTL>ozO0$gYK7Rb&YAW<9yFKSNNisk
z5x!d2ujN1JYWt1%G7h)%`yZDrk9qaBur>Ow-{<eSjqBKIlJtM2&Q}E0_I0kO>NiLA
zH29ygcV8v&p;O;t-`BPITUWY?%<p|Zw><9O%-x^QSzoW~V5!Lxfz?8wG8Z}+vPJpB
zeU2YnHfsu(6oq`>_jcRuS8>HNQ>U$r-6H9K<a-|IlBZqY?^R#kbXsrrwfOqKyPm%m
z`_|yV%913pw_UDkMV>$C5<-!w+g4oz-BT2$y79*L%4ajxb+=q_ntJ1`M!|;rb-$Nt
z%oET(cY9v(Im^rs4>l@a4@pvg>mtp_INwY~*8fE|<NOsd!lF4{+kQ_KU%q-?-JXgY
zkGB{5+dJ>d-d-EjlHc|1yL$Ul+x7dlRNQ#@_K)#b|Nr+g&+l5eSFbiH<JRk0r*G+q
zU#-i#S9$){7vA&s#<m|$ow)V*)7<6ziW6Shf4womljotRb7kq3WoPOf|0=KM+j3@3
z@$=1lXNCTWe7%18QgiqE3m21WpY7Zy^dYkH>D12)lTR6_&na+{GRujm3|jtudVJl_
zJt65KYc!(fEUAAo(Y>oZc3*FUf1t0bSeG`l+Ob!%vG)><zjZliGtQ5@*^sv;<iK(%
z#`!-EKiYl&Z{DoBUoT(ZW9_&77Gd>z&E}wx_dh>P-#>??=2Zoj`tXIzgZ+XZD&Oz@
z{)t=p^lUM8wZ&ZjTe9Y-DBG{u^=ehA{`cqh|1FPJb}l;FdPY2^!11F&?NjY|&;7ry
zuFvYfs~BL~$Sz-Fu>ZuCJ@Mst3f=D>{qgj<+LgZ+%f)XSCLQVc^Pk`TkHJ~%_j@uA
zG%#lFd^*kh^I7xw)3b}-Y&^b<TYt}nZ80H&x3gBS&FVj04!XpC{^Oc27u_#!K5sXh
zJ#|`4(Mgg2=M4_?JdL#8E8ofvy4teF7Idj}+?9lnN5%cUbvC+0rA&1FWZ<`4`{f}X
z(7k+ie-aH}Cw1#iJ7@R%&7VhKlA`?Y?)&rUw5DBfx7gyCGghzH96ijJuk0cDy#Mik
ziCu<zC7@1o@C+VFqa}w^cmGadv01F(`X&93yzVcfIDIbHDd)Y*znaEXzukK4*P^bV
zoc}@Ix>LnsOD=}6<nP+G?%lcYJ$^jRmWt7ZGKPxr#&Ox3)+pP{&li82%{c$?^(gzd
zyASPPp1eM$AZ*wBr_+z6i(AKR+gNpex#aUr%jZvttE>-cKRtDR&nx?l^A^=kTbumS
z{=c5<iDh^8ZF->e^1s>rb!M3}-;}!bRjvQFqvrXy*zbOZJP}(~sECNRT4mY)yL9U%
z`|34;vr~`nkDu_*^3Tg#kN4FrU(ZtWh^2T=hF+9P9lu>g%+;kyRpH<}sIISicjOP~
zPN-dPHf=k&e%+eWHY~@&9S)?|u>Q9`9iG^+P9jbBP?T%8Jrn32xIbKr9tpS|Sbm`p
z^QxH(p^cA@+-X@;_J8vHKPrD8%l}_-`-p_#1JL!xv&wE|zFzkITJt)Vnti{nu3t7$
z`FL!C-QynPXZMeXZk*+rZyEjmi0XywOm>26EWh6={>=5QaNWkp?)k@i&F@*%{=R*G
zo%Q@1Irlzo0hQ_e+@hBs{dqj6_*|sTnf%2}=fL;LrbO59$Inx2QUKl5SXY=AZYREI
zlOId>E$O!^=TiTCXt#f}@!^&}n@=Zp6|dU;eqZ&i`u~4V?>310u3RDNctU&qo=thS
z(s?@)yFO>iZrxz}@rdx}f4W+{rswuw^3r~KxYw0+>%1&~`@bc5e-3f$o5ZHJ98GeW
zwJxl<>p<3=)BFB@yFGiIe%<oFpQi8kk<QuRc=>sC(V_<b?pd|E4~kD6i(c|pOn!P+
z^t+zPmpi`Cs{gQc$7<j7{mR^zbpE(bP)qv}F4lEZk^A_TOKjifTi)IMdtYhypC8L!
zU(V#e6KtNleCae_^}G#{xwjSs_j$js{}cGO@TXtM<H*8ym7hJQ+x*M8^;^DP-#)gy
zern}&@9Fuwy=Oh@&N585{WHJh1MgS%8KvA`4zky(J`fI7TQnv0;<5A@GtQddw>j!q
za&cbOtChQsWE$Spg)M=u{%5*M>_aE>dE;{y%6q>A)fR*wSpNLJ^)(N)eu%(|T?bnD
ze)LEhtJz<)tori8Y)hc5`l=^B9oMEd_=kM4{CXugd-mqXeb(S==i83u?~a`OP=2p+
z`L<man(~dTy$4#vUU)Ok=lK3+<8e97bKGT1T|GW*x$JjZdt-@NJxdPgX6{=#ftKo8
z_ohULOzSjwbk_WS%)C2a{zYZ4o!V#j>xIbF>|5EriL<{w>wZ}nXX2!6xaHc9EgX4n
zrqf?s&k%I#I{!yBEF!TcY_`7i^Sb(v-SJy2{RREY#6EPM-|ftAYjU@?{J8S_BfFGb
zO0NXEe?9TO?ZxRAmtWlOi~5qh=h?07^>;7kR0h0exBua|yK!yO!yD}!3*K(M9(Q*Y
zU&xx}o1+=$pKFnt_dc6(e)qO}hHEz;xKa3Jk;%n|$^X=A{~Wcb=ACVKkAM2S<aH&7
z{i?65Rd2i2rMN9BH#~QHcGm*mi|-_VCf)jSXmfY_&)hfRZ{jb8*?gYz<<IVXasJnN
z$_63_7iOs6El;<4bWQrzJbgJI`==o<m*w18pLB2e{VL<N)$d+reo>bf-|Qo@z1H->
z=L5|AS7ceXH(8$6+5ANHOjqio1;5W(zt@o~tCBuk<hsfD*wi=o_t*bBZ7Q^M;+Nhj
zX;Thn>wmrd^3?trikIdDZp!Vme0Ji0|Mkk>Z?|7wy?)=UMJmyI{O-K>>Mr?kh+98q
zwke;{q9+L#m0s>VrM3FWQ?|u>Vp+r&eTkj(qW|Zjn%K=Eg&S+qw;TRBf5}^aZocyy
zcbmS2^^Z&+{jcaf7T}ovI;Y0&l$zW8BNfXo+Hd5aSkQZ2^VA356%Q{z>gv8R&EwIr
zf5*1D+}{hj{dnK+ciz36_tvr1ESi66X-sl`(wt}OwpbK&*lFDJ-+b0A`knCmg+J_n
z?O6OhSVvw}vwPd4F70bm4SN*dCEY)j`{KgFpLNrho9?zZ+<SfTn}=^UpP%>MjpyR`
z-u#-ydDH*>y1svzzy04WX1aFlyNv$C%P<`Ot@=yj*D{G;`qTR7e_ymEt-AB`E$(d<
z>RLaJ$je-hEsx#x=hNxer((rc3w_X3xq~@ER}z}w#9p&*@3&ijj+AbG+dcUSs8-*+
zys9QDoXPIvBGBc8yPnUh{`5X3dB@auJa;eMJhp!Oy{b~i`J9p^uX1kN*k^KnncCoA
zvtRBgixjg$VVvf<iAODG{IJ{q(fY4NzS#Z0<z{#8S3aLRz0dmHj;QBmt8;`KdpI_l
zY_ljAe$FHn-IAu1aAnQkxB2znpuvdQ%ax{xJYP9$ZGNxmH4o5Dl(%#)ziP247koao
zOUyZ;bgPx`MxUQ%PR@Z>HRjy5=D!qpK>ghG+P|;k{m<L~uc_Sn^Y4rO7U4H4=53DO
zUkAFX@YL^pXPsi_2)tif;cuE(JSVvO{8x+em^?$>Z^rlX&qlRON%Gi!toTf!oz^+?
zeLtVg&K2waex-ch=ecH=tFxLK{JSTCy0wW@Rnz68-QM(GlwWf6|CMTXm)|MQjj|JY
zIm5P;Z!YAYZu9oYmxs$AAG@VJ@AaFq>x!qB|BtPod@INB%Jl>H|1ZmnZT@wB(z~0r
z^KaSAjx8zM^?Rv!cK_+}dH>%X%)C_>{A@Dcu7|U}OmBa$Zy&q6-YHBl<M|q+fGz%;
z;-%uxUb{KldDhjq9qsSI!Mz}N)5#rmJqKJ=45jTSR9Ad|9VWh?CCOqohj~fK0omIk
zkIRm2h=1BrbNAG(N`voril58hd#d2RIr8yz*C}bcA9ZP4@dmEh_v=-q<^CjFLl*xj
zTD|dcg+=!N4s;55Rln_2pLfEW_1KTTwOf9qZhkr~dYOLhOYh32?Tb_2@Bja==FY<(
zs<*wmncIFWl}%jH7u7RYYN^0tne6<jt-a05D(1WW+O~L8r{T0$me1z|bN?zaeIU#}
zGq7lVhG4?0H>dhMl8(z42|npy?)nzBXFlkD_&<NIR6Gzk?b4tXbb0L-jb;hO`QL6G
z`4QJ2Ql+i=MdG!YSMs*&kBU`}J-Ju)dhKV!gxj<AmmNQU|EPHU9W{@u7meoHiqB8|
zD0%hbRW2sGxtdk;K*P5vgHa0tL5V%-$ISZwzwh_Xo@n3q{^0uk|9;(aE%i-*wXidm
z_s5qDr%QK8G0x|!w6SDl{pEE)ok`RB%?9VY^V~C@bSU?&uy((uWAXX#`+9rO)t{xO
z&FpUE@BjO$xcTT8`@b*!fBro3sIcXiRI^0(x}9lOZ#EnbnxkL&bZYpg&z$CWOM*9g
z)ctO^|D(8e&!<zRmmfL(n_G5E)Aj47MMo`{%>Vagd1Zylxj<KmC)@Y`&E56u)#~oZ
zPq#1o+wXnX^lq2>f9^LA=l8+R0^omi$Gs)xRO7<5*%t#3JYUqUmt|ZN9<xAJ^wJ?S
zoxGh-r`60WGHlrK;@6tZ=dwN*eYAdjh+F^6^xHX`&t6)$``xVh!MSq^K|TG#y3HAd
z>r7W^t=)Xi>gSS*vnytW)Sb2XFFp0ntgS2FUHcKU$8FE|v>AzQHZoNw6x)}G$IDDl
z>{!GV9$OkJ_bO}KxsP+z9$a3O5YPRC=kGVh%)Xb)&VPS&@p`=P>p7Rdoi+a|^7qo5
zo6?zGC)LhtKd70;D!c2l->r<#TMi3(Ul-eJA<gyLT9&6ZboR!Rb0e3}G_&3Jo&VLm
zn-BIFUus^zFJ`t`>Nm&lhwAKC@h&a>b9ejF<aaCnGxW~fZ<5fMb7F0wsPwkoU-o=?
z|9t-1waa&GKH1d0Y_s|OZ51>6cE7$>@@DSb>CvloFSNe{Wt=~sy7)I1X*X#-&D>jR
zueIsO>vEBn%$m0v$ICvQRDXW8Olp4iH;Yq`kLq{z9a8K)eN?}7^LaaK|KH|z;Wl|<
zA9lXocKef|ns`jX!K7_``HvM8<Cbsq@~-AS8p<x%ma+6od`rQ<f8X~numAfx{_War
zc~vc$i?(FBC$8Sbx`{ndS7Y6^46&rlIoqcm4^-9kdgjWpMqAg(ZK6xxsldIWA3D7Z
zK6cwpx*VH(k-hN3%^3mjUpAaS@+<EB$p-&FIY$oundGf^^Xj{k&%0eJWD2Hfvu@qe
zB$h4)o)SUowL(Wze-`K-ybvuOJ+1Sx(+P`@(R;#px`oB(Pg_0zxaa#FC)O>G3OUx%
zExlOi`vgVjphBiC+KlseJXjZVRdH3@krm8mqiWbC#GfDiek+jIUhh$lmQvxt?3(o3
zfv@upsP9wm>#lR}lbIP_%YV9Jtz$FW)2qj4?@h}|ZxKGVc28~L!Lk<VN7X+q)CH$r
zdc340JZg>gsz=9<PTA<Y@&D)Z_VxR0*UqWe(7Nf~+W*7OUQaGAp^-JpN<R4By&KCv
zO|S_xRQ;zP6>~;LIq-;O^HH&AoujOWVsi@xD|@O0lr3HEyE`auGhg+vyyTyTo1g|e
zr_}b96@O=_Khxb_R9|{!e&M<o3)|&R-IxCOufNM6Fm}n}YjYd?bCSPQ?)m@NH2MGI
z|BHUry05=}ueeun!iGH`k4b-i;PTk0cWRl^hL8LI|K8ub`KsLU^S)<-e;oh)yG=T8
z1$XO_pRJ#s2i1guF7>W_x**AQ<NEu*u5JIM;BKgUuHWs%@;m1&9`}6tegFSHGtD}&
zB#R9d{^r|`F{H%&kbd5{>-M9)v43oiop%h8moi9j__z7)#nxwU_r^W`t$a=J`8K_s
zPbU4@8>VwT?tr@8@5MJ9ej01=D4Sflp>#(?wB*#=Q`+m#xU*|6bCuBG@;map@*?O`
z+T~xb%ZJZUS>~>~tYZF@=$508Z1Q)y9&D93wEB+Hk;@S;6zlYlZ2D-uHe+MF{r{im
zLCv<7-Aa2x{{6X`KEL+X9Ow1X88&hv`|m&cYpob9C^B!tddc;sk>42a>@7Jh9(`*%
zlig&0v&gE<|IXQrGwONkt=@k4&izR@wq~2<B|dMxxn{8i8%-*n6|yTDid@}rJ>L89
zy$apC|4(_pyyGta=F@~Y^R&aoyeHdUYTe4;eBkWG@-4h~M9!C&S=Zce4&s>^y5)Ur
zeX3Rd3+JPU|9tC@ziE`a`9{#szY`bV^IrY$DSvL;<zJW8qL;1}m#sD`J5v3AS?Ir_
ztY0fkWW04`6jwy=`}o%6_Lk(;sdxULI+5eCVgHlRnom>xQ~rOM+Tbtq!0pw>9}1ku
zR#*vfp7MCs|GYoCeeWhvA1S%W%(|e9|CYz}V~k;&nYa8%mE*kmBlUV<bne!xm(2J7
zJZrZ3NZnD!`kH{_jS1E31s@k2JD9uqn$81ZcD|48?mLg}JEFgaqs4^#?2*Q!=j*<0
z_B(7C_)w*8rRnFczn#o4f3U{d-O$Z<583`Q=g-9zw}k5#m~4xv|KgsL{lzn8?!_CA
z`qzKZ`u{0=&hn|p1(*E1*k3p0|HT_QJ0&ig^1VyiSJa)`%X~=U{nkJ1F;l#9!`wDZ
z<+3X@5NCHNJP@B(ctNh7=O|;ulG?*7J~rsb99kZ;&yerkX?BIe195fzNA?|Ytl#On
zL$}R6J4g6)wXIX#QOEE%^^fKC5(UIuyR&?sPMUM{%ZvFQf6TdW9JP9sZh5GsFd?Q)
zZ(6@g#bd_Wk1_uDxqf`vvf?XrG#632tkMsdGeg_SeDBWVg%>mCgy=@idC~KJ$7$#5
zN6P;kH52_@`rK@l;gPD->XRN@|F%e!yLw%@MnH7;>9rqS@@l?IP2JVK?I4@<mX%C$
z_b<oS{e1efwNCIu#<fS)|9|9F?tD6JwQcP|R`DxN9KH9iAN&6GXnAj->60Ii``7D=
zmp^i;tudFseJv-YDZ)<gPS5*)rxPbcm>trXoxiX0&f2XUMn@_qS}Yf6T=?nxvWFt~
zR~~2G^LDGnb|J-<9Rb^J{?=%6FFaIvJ9m5TXWQJ$xrOT#f9ag_Hre)Kcg21e)hTJu
zjisLJ+xK;S7v#~1+Hr(+ZlTeC{raEYalK1!JdY^f!~R(2`kT$?<8&@PGkex=*Tdjs
z$r5%(;<j|{zT0`bP47PEFm;Jol<{`%m;JBT?f%4lp!?^e+CaW}TdvPH6p5?3A1l|X
z=;o_2|Gvhx$bGpy1xJbvx!g8$zj|yF8Y5DBxAgi}$!{9dy1PFf-nThWHtF6mG5hX7
z#ibb^?fL?ZW^JuF@1i<?QE5o2>a))7SNp&3eJ{FsdFl1o?eFe5#DvKH4a@tuSx|hF
z`L-W7?f-l@{95fe>yN_3+KZ2#tH0?Md)@ifH2bWUc<J&kf0lDe){km0yh%4YXX(0h
z=8wuO)fd5a^+$dlz486U?27g79_um;gIs?W@11ckqEORL`qA?ZH-Br}iObi1xtMhE
zPg#IioDTc(MN)prE7a`nKQi8T=iB}I|20ddCPlUIC*OQjylsZu_K!Cs?b>hWtk|++
zgLNB^_VyotuT{*`pO^pV&&!PYr(eH5_xI7BJq`ZiUw;K1NdKm@#YkuMgWxU2n>L(V
z_<x_--;}SVm*$;bH|1CA{yA3Jhc~UV|DAqtR?*Wr-=<YQ+}*w;^H;C6q5S&NU(MgQ
znpZEs{Qh3<{9PX|c7DG%v2WMgW4oS;%}Tvia$B$Zx|7fLy+2|=L!p;e%kP=bf3oy}
zR`!zj>-SXU&XoW6dRECd<;SP;ME&P%KKd<l@j>qA{K`+Z+}oMHWcj_S#T8YHcE8nT
zoZoP};&Jb1#ide$?fmld{%`8%f67tzC8c}H+dy~O(C?=;>I#pxXN6qS;468|Y|VE@
z$x+JLWNP#h&BxRI3Jt>R^xhqB^k^|Wl{keX>4^S<6(55Bxk@U|_cgz3;_o`0-{NtD
z_CEuS^U-_!k`Ji!r6@0y)8#v&q#~;MV$mw!7JfE<xjECddICIm9^H^oSa2(@JO0+g
zt26fTum15^T}SDSknTF4j^<k)3#J{m`*_@2=76if(#Y;DzZ==*BEE<G`6&4E3C9$X
z_l+F!NAy7>*?O)ER^EAZK>gA!+l!A5*nV4l=TWU-J;zZ-|A{UAwLK2*G8{)l*)ATk
z-*cMX+E(yG=a)R5y<uB8-X4*6ny8UiBd@pT!=cJs+wWWtyr;iyap9c{NwtO{u`)iQ
zx_sMC*H00<ES<mlOI&~R;bYBfEf#1C{p$T4S10qn(PDx2_8-aSbz+Ze<5dnn-YXcs
z`3PfSa_I_>=f|fC?Y+xVQx$#V7iba#WdP@@u*M;iv-{S+d%5>+`Tg2p7O^fd#!ikO
zE)`3D=$Y*E-v4Y?wiQpf$m#9n(hnPUyjT~J{<x-Fe_w^1T!--Qr=a>jM5gQQ+cif!
zum9-VB(YC@pYs2+`E{3XCjI=`djIdc@~uA?CArp|x3#gpekrnB_#tS9pzdRaVg6<Z
zkC0dWiMhA9HI8m7RNDWs`qB)!=h}R>UoMD<2b5h?`XKmz`y-VS!}=QkYS1Y0X}#TR
zW?Xrf+p=Vlllx=WU2pX!*j}t?vi&nHBB`_Ff+PFZ-+Qa(ICpi|N$c<HyWV*rg2iN)
zQI}IlYybQA()#z_o^9}N=}Y2Rb*z}pR`Nq<Eq`-S!@5ZMBj2B~%hwc~4&C`kCN!oZ
zddrWP4lV1apM#GU_dc8?aZ5XH^Ioy{^MAb2j7q+`;m1tPcpjPO>kqAy(b1gNTU;vm
zN4x#Yqphb8ce}c7`qcU;aH;w^Ws~f}eGk3ke+9+fKiVNuD7SL8u9L;Z|FJs@>Sm@+
zJJ~)nYmdXOz1O=+-78e=PAAXqDxTk4dm-+Cdfl@{LctdgDcbD1y({Wq`rI{1!8>oA
zJ7@j=&a*qI8+ijcl+Ilg)%~@1&soF08!rXT;kNyLr?}hoRi5$=iQ0&~kN>(q*V^9g
zIv>V3U+>hnr48qWHlLpfo~4-fUyu8Q&Q#y%`U_55Gh=st_6#e0`sDXJpZz;uPcxgE
z-}Q9)DZ49fDTh<1-Zo#qOC|Q_mE@<Mx_9>{-HyGK#e8gDKtJpGniuvjCrJOlm?rDK
zesAKhZ$)1pOYHmb&N}m*WSWm*Px!^8j!nFq6ZhGj`?mZ}ndGJztGd6w*^`f%&j^XW
zSpU%vbc9EHmCTi`)6ewA2Z4q{s@`lo{)u@%$K;ZyDb?<KZs+f>jlH?mVnavs4~vA{
z^+y>~|2*n!?pfq2W#*)JHY!;{*(>*${;yB^ZO5J}-IZiN{#1<pN$<(a75fYy1nUT&
zyw34@%Xe-|yDiFvadtO)?BkSn-qLw1_d0jY8e#To!9N=6o!!^<^OWxh?cZ@q^GZbh
z9>2%(-hxZIK5Ct2Unf}9k&?aHrFxH>j&Qxol>Y%8-@RlS#2?O1ijLab`#q_rKg#dP
zF?q*{O#K%EH;Wydu;QAC=aaOx>P&VY+r29@*8NzlxNcI$`lIrC8|9xe-{e?&be~D~
zUEUudFZbTN+u;AjJ0>vXUrmR$t<ufAKaK|`%G)b{oY%?xc#-QZ>uZ<q86B;8T&?}U
zcwf^rj5%VTDkfpA2g2$}j}JX~WWDJ}pQYZpUa_l2i?ZA<K2rJ6XZ<e1Cg<h0n*lm!
z!vsXlr1me)H+^tff~Dhn=P7|eN0n9Uj@yZfUp!X)ac*8rgXI12GV=$QC3rf&9{bt2
zBf#QZt4W=|{Bwt-js=TMxqp~!)_A6$m;85nTvg`X6Ra1fU-TFJl$o>9_pDR$*+b%i
zf0tLti@olApZ56CGmG<=EBe%#5<lLp36D-bpziaC>B+fso=1=FH~bPHn4}T6-f%^j
zPyZ_0qpoL<ZrRa0!GF$u&GpMS%2#h{@(;1hEZetWIg_1WR%iFYZtjc8^2!QA>!sNW
z4NGq-&g=eOy;<w$#+=P!@7Jy{5PmMuEvDGJVogX)i|qTa9HCRRV~(B=oAW$tO-$$-
z<-FwEj}N_E6kGfC>d*7JA9ol&5Io#_ly(2xtrq5zzhkyoY!BiqIr8`u2N!4tpo@FL
z?5#iM^gLpDD)#)-q7M$?QC~dg#An;Ei;GqtT6^>7p$dI7X{FUSU%PS?e0gy(_mE~R
z?+=#+>gRaH-yRY6_X%98b58Jh>%WgbW#`ZRXeq@wV@HC0+aay_*R`kV<~=qx{iXgU
z>E4gpAiYZhVukOP+?mDuIMhboUOljM<sGGhus!dSs#sc1y+7OcOXHlq8J}d?Ax`xx
zu|MML)_&Zn|KReXxOlD~YxW*^@MZhj<FY^Ye116NO8u+C$FAV@PoKFD2lGUWp4YYb
zye9Lc4#SokYc^jGeWb~8i~Gir&zsYnqiy$H-@%gVbNkDo&6jPJkJlO;+Y)x`<?Ot<
z+agjrZz<JRznQq@{MPB$<)*){DQ^wEeEwR@`mmGB|HRz+|9kS`ON`g!r{4SjWAU!#
zNfn#w-)~8urDuJhqwH|;`6cV)%j)jh2tRJ#C-Q-FzePkZ|IVZtbNYN9PcIEQ+`;^c
zW3$Vwtsfn>EPk3?F-K!(SWU+9UrJvB{ElwhUX#3ap@f+hleTMW->0I$%H?x-`d^vG
zdM<OnWFhp>wVV0jieHy+%wnxsbjT;i|7XLB!krZ|>^CMZ(wA2`)>yb%q%x$Tvvk_?
zUgm|f^LDMgx$5<@qyO9&?fi3Er%rMje?n5@v4?XXP0#)k_>+IuF45_7E|o`$I1g)B
zR^G~7KJ{6~-#nRsqf;eayP0Ql#G3q8UOYoR@9_aezIBfm?BCd%e?a|I;<4%#8HEpo
zw$0tDyY0rJyqpUf*%g1kUN?_jvzu}Lsy)}4m+oeq&+*LFVSPrdY@W7O+|laQb6&hZ
zRZw>Hb;<Xz1Iu?8O~crd;IoU#b;F{~?>&!)YiNlb`F_Gxdp=8lx6^6S9gm%^^{u)r
z{yL*<_w~5ytv~&2w7$9ssQUdne)8!K26I0R^KD_wcD?IGr&^u5|NdC{qry-7ZG3`a
z3U+}8;15n!Y7rE*Kc)UenL*&QOZNirkoJyi66ZSKe_!nNzv}hc>FqU-zABv&KDfB3
zJF%+k;WDY~foH@YcK)z4Ik)wQfumqi#+p0wwIa_Ay2RA4K4!XB)Lq~h(m$j6-Ok{e
z`BI796@QDm7f$P9aEo!-d)DmsmAU2}48Acgk#qKUa5+DW;(KzW&g}QOeSfTu{yo;<
zZ)m$}yZiiB-#N3pCco<y&3rV+?M(QVH1+?<OFDKKR2^tw)cmGCN9z3lBS$ZMjIF&`
zW&A*Rz2Ngxi}WAac(+(Ts`1!US5tmBP@Df?$eHUFF5zD)Ek6h`&X^(AxF(~}PkYtx
zBLNYv-48!3+7zIzdv7(nOo4-4P0YraIrF<NxW94#61gY5TkQFoM|%=j+-_wTo-_Eh
zC*$lPYr$om-(xO5`r38=WKz`6Z6Avl6l(0Z$QO666xEG0K6hO7xpDW)!rK-tp+4P$
z3Xk^QoGK=+as2n*jEAE0%RfpAJ>T`HSpQu1)brBEj(!wOk)D4|;zQ?zpr3cbH@^EZ
zM^oIV<Fi`eUkxsaE#VIo{yeTp`%_c8{OHcpKV<Z_Tim~Kuk~-DaBWncpq&=`l}E<g
zB}~<xb-(RDm2fs{&icOZ^>@T{xl)dFsM+3SsfiMK>&-YnS6qIQ-`$FCv+56btn-)8
zzyIlc$=}WXTUVwD8@qG7=-7JA-&!}cUg-DdH#^tr+o>Nli0I92oSEkLy|(!Nu9MpH
zD!r=y-F<e|;8j}A^Mi)3bEfdChS}7<HTGYYA9L~F2OI74#tON+E+l2nw0!R8ea6ha
z%8*;n_RFi&KflHOI&vY&bn9)+P5c|Qx8FBiYx4aDf0Oy~9>4g1uQOjx{qBDC+02Od
zU$!>*Ka^l!H1SlP4A-iPeK&JuJ{)UwkzpuNU2@stOHg>bV%PP)F9m-Nb-QF-eAM4A
z@o3eZM-LR3yj{EFohDkn^SYff+4t44=Q;WtE`i1YRz2OcRCaG1OW>);KaPnCOtj0(
zDQt+b`_cQ#qVPcIKi11Te0~-tXQ=R9IL*#bm>^UiG39u1Z}Y8Bp%PEOn%?W*5cI{f
zut7L+y+y<OJkj|QRx3B2iT`s^f_+(R=Evi1G7cuoT8^7P5I#Kd=v58ZZu=LH7`AK{
zyDjYbWYJMkp<Y#{?&ng!S83ZzhgPj`cP?kL>#dbr`K7{t8viY>$7$QoGUWwUt~8(B
z;Gh30${c;s+=5w5M>}8N<NIO4Cbei%-N)Fn8vQ6f`<9Y90{LHC@<L8_JP6o%^yD{-
zi!uN5%vZ&@JWxL*@$_2O0re)?#csXU+eMVQM4SsmU-#B(hcD>VQg_|4bjI?JDTOuf
zWkR#0qFekQ?eV<$XpY;@>VGrjev65lPCsl=*tCDggpH90(vOOU`xI_0*m>0R;|j09
zeFE02qNeyyIqvy~LsV3^Ni=Zc;yaI=URg|xwLAYAG)d3@^+-+N#HBVS;ni0wrB?rG
zsoh!R{nJ$X{qgU+1Zy<5r%i2n#B?Wj``vBp{1<n5R9Y<G@nf6Klt`A0M={QVZe7<o
zHd}-jpSS&fC2mvw|9_PkODg2e{@Hv<VV(b@?*AF%^Ett(OSc)y-g&9>K-k_`utMvc
z>QT!%98;zq=HK|MLf$OwXJ>%7VA$&f;aBszxbG|Lh(27f!(#v5ZO`XbKYPFOQ{}$2
z&t_rgx&oqGI!@_ovGdAWz57#?oUq&`|4#q>?oTHqKF+iF{bqCa=A*3t3-_(LqjW{=
z;697;z%3T}65^}O*<xq4PUuRN%71LULFNqi`(qQs9_`7FNr~T5@&1@W(A?JjT|Z~v
zEmM6UJb&uP;^;iVik=PL>Ca=+=9XTw`6FWQzII!5{@$&=^5$%1r(WlXacI@Ix&3!}
zvFeT$_Zt`1`JX(L0#jGqVSifMd%l)&z8JX2J%7zAUzXBSZ(l8+@9{gf+_mccV*b;U
zXWxrAU(HZ*EG^#Kc#2&}+y2jCVog7bL2Io`PrInj*<F5ndETv0>2v0^=e$ze_Tj+^
z{rn00HviGus=Dqplc#n3y}Fm1Z}r6P`FuF^nooOOW{l=K+jaX)V&{ea%FHoNZ(Lr=
zrZ<DVy)8wwFYdgSylcUWdlQu}?bYwkn6ua4=G|(>`3E}Vc??s0Lq2!L=RJ*&l6`oz
zF`#F)q~p{+t^G$DV=Ns+*gMv?I6i7vVxtrC$Ec70$GohM?OrkqMAz<Ba8Ev<{>|R*
z$!Ye-N3CYvJ?7{rvq${xIqUal_@8tgKbpHZT;|QuJ+Zlh2RbhVU3_$4yNpVg{T?NO
z;4Ky>@=fmu9GuQ^Ktz}C!KwN^BA0g;N!N=^3BI{;@5b7rjv3+CE=nkMryetZARM~x
zRPxSa^41fd<%Owj)V_TqXWl!Onpta?ufF{2R<-T6-PVlrcdS}&<Cj-$@BMb?5qY!1
z3*mCR&He?vSR)i({rdH(62|%KG-hJn^149BK#|GLu%)(!J-)^DQA%!%Nfe*!k@DM5
zS6LaR__QcQW%gdxR`L-PHB<_@d_&6r%kj@^*=m$_d^%%%{z{l^;)E4X1nys+x?g<F
z*$e09u4AjY6}ji^6ONTr+~qnNyjg-lZRR88S3cHeBxlF?v&biHY04;^SjHlMO4rFk
zP%JCw<KDWTO3x(TF0gRCXOZGRhrJ_9yjNGRsP{nNMX`v4#+nlw9u>N8?`51X;ih#@
z`ziO7?x+5CKcDO>*7|6hAEP1j{%RUy>x!0mJN4i-%MD!wFF!U-E@{o!EBT?*u4~^b
zzt=hsgcm!=R6J<h8tQ&vjSWl8+s-$BED?|X#9h3_y-xJJ`R={XW@UfU3NZZS{_*F<
zoP8W;UF}`Iu3iywC9eB(?$c9FAAgFACY{o?TYYNb9uBRk=gX%)@BQ5?TJ`8p#LguD
zkQJQ{?v*pvMd&^2c1Xy{4^i6n``zx(wLKGpc1{Yh(VJi2oqBxv(Vx4HB_7x%yh116
zIh@JvW8}?<t!jrd1ZQ-fe^KzS{@Xj2sJ>PAzW-qR`iMo*h|A^B5{DT(l{mB*MLgwV
z*isFe4zW&j40(68`&4n2-F)E>HC=aFxu*mg3b;778MGJ*rUbAFvP?0MbYNi-WsR@r
zE}MVX`fBa2Uvuo1`+qNAKlMvUXzbUOuijbht^a$U=WfSeR`D2tce`G%`=Z%(LHT&V
z)oJy52K9D2(Yt({a$fSksq7JyepFjCZ|UEYKOeu`^ysUNgvA|0(dVnHG7l_Y6rs;r
zV;3#G>6P;A{K)%F(ei(tE51kG=Rbe-p2MwN`5Oh7KlHwBvwA=C{f^h`dE@8Rryf?C
zR{u5o(0cwXAG3E6)$3-<Rjx?frDgu__uc<u-zqL|`K41_S6prJW0Cmr#I^TtKAh?s
zR#m&B;QXx{)m!<KZuMs!u9pon`g8r6_Ie?|SsSY(N?)dW&F@S+-M23*PxbO8*4|HZ
z_sV?mG@p8|%*l>ty34BR=5M~Z*v&PIQ=fVIq~gIDdj#KjPQDd#&2#mlCzq$+T_z%(
zs+|1$>iRm-KKp+^DvFOxpCaOW{7R1bgJ4sM!=8n|xLN%qK3%HaDX#9?E?-yiaze`7
zJPSv?e-k=;CzbuwXLyu+R*y4$Nqxu`skT)&jUN5|8Q`t5&(k+NljX{%LJxPT4-bE?
zym455%f`Y-ZV$BnGV9n~JNYz%y{77AM1R~|mYPqG`{NbQ%r@88+qBmEUx813?_v4s
zm(xXZb(b7+VXM(fuw2Q+rLmv^m2glr5Mz|rdiFVa#|@6pAC&KI31pn-rLi$|Wt8Ca
z#OO=!7e<%%e72Q+J#pJA#`!gKA8&fGC9eMO*TZenc@aF!&gyk<Dta$3nLd}LX2lMd
zrF{F`mo4J?tMo^?#fd|CEt65qf%b>fKAe+QW?XV`&X!lckpeAVlA)^`0=~Atdbv?h
zK&fG}d7aGcb=-_vP3CV|R(@*mUmd`8{$Sa1-8M!Ep{{*xTb3@I`=##N(QR8Fc3g6s
zFFf^r=3Sm2AFLkTc)eum+v_DA>n{6QuU&Y)Q@(k*{T09Ylaq~kPhDW2&R;vlZ+_hK
zAIo0x?#oO*q3M?MKqB#H<$T4fSrT!2>!S`EX(&0&57tpT@OsKb!ABlKA1goA9=3VO
zzx8p+$4M8JFYRmI^tii0>bPIcJB$3flZMVyrJbBNPSw@7yY_0*_l69Y{lf2gWu||z
zUiSL5(J`e5&aBc}H=p#@@wQcXb31>iO1~oLw!}mF>K2Zmu*}r;nN0J}_C+_jhE#Y*
zOW7<@U_L5!>40S7wlD0DU+#%X-=8Ee-MHdUt(u+Lq|-kvCx0vNPpN!+PWrs^t+{nu
zmPIexCM?mp>hU#i#`$lvLetG+5|{qkHmCafdTsuhTU~PB6_?e=SKOYm^6S%>{}-4O
zpS=lwy?y7VE2rb+<ShP7=KcOQTH5dRqU!f~JJz4-wY>RxUeW8b5AF5$Z#bpowY>J~
z>3BiC`umKDZ%>{U?Khrs-TK^*yoy!d+U9MGy%wo2U{rN<lJ~N5{j$H$?5_wt-|Wv_
zU;R(M+tw_u+-FLI|GUGp&E&VuDfr-c^v0Uh-Y%OZDxdisoSdc{=<W^b4?QeBM`X!C
z387hYzJzA}k!qOC^{-H9_P=CVOV9qbcN@;nEx#8zr{~Dew%sb3bNW6<h<$kIGS|>0
zd9{>M*XOOf&S*a~xDy%Gx9RGhkA{7$c3+YfyC^&^EW2cJ@X-?eZI}J+ZDVS`Uj3LB
zJzeFseY|wOdG2Dt4<`?&>dfy~@%zEyR>)IeQ})a7YH!1N7t3pp_q|ei;5=!*LQ>A3
ziQY!Ly_7G`otI;@PCM0X_f?)BCEnMbYN2P72ByE-0@lxVS-OPBEp2^&_6K9Ztrs2h
zjMM$9!ZXBdGG}P)oXBpu!t7i?LTYavn^orJFw+NzjeacDwwK7e`s3o;9!cXa`CHRM
z#a9Y_NPMBZPknjwEWY1mw+a~L-2xu8->5vjdhQa&`Fph3uD<$w!C~K?KW0<Eoo-V)
zy*#^Y_sy#3m!BVZ-JEz}#`@3?-K&%`RmJOe`2A4j?>O@OIs47b3te?HBU&~1C-yuO
zh<&^3$X6fzcJ3bnyH?)%FE;&rc7x*0TbVV}&rK-Le9V3$M6FAaO-?za?8`-W^A`1r
ze8r9_;$jQtYyDNU`|E#Prr76~$kDI<^}jB=wr>2vV4v}P@50E_tFN0_@3Yv(@h&0e
z+O``>-ANtRbvbj`lxFL$&yl=y{PTx>?q3&|xo?!{Zs31CZNJ)!-49Er{^OYUGGov6
zkC7AiwS73f`uQG<($D`-$6Zc6ta(f|z*AFpV(V|qXDg+|ZtuSLbzPg{V+kd_`Rab&
ztm>;KEv>DQ+5B>aa^bCsamTK=G0rzrt=4>S`I#2K^-b&R5!Q2do}TyhrNq7Lv%+Ha
zi>qHKyPLKo{(HQM`|!%`cVp(Se>FAx+uwkS%de-cKmYBmw0MhtjB&`Jwf`KBYRBI!
zJO1Il^!^B`53Nzpf4(a|$8+88!|%4Gdp3n-y>H`}lM1Ul+x_(RzaQ84xBTDnCjH^7
z*8TeLtaq4|+}J0b6Ey$%=J0qiza1~1f4%*<HgyqOO_6z%$dtMzLLT=l9G@K4%~hHA
z{eJ!bFY5&3)n&axXMf=}kAK0Xy(WOi(oNEKRmp~XAI}=kH`{+V@4)kG(fPbnT5`63
z^k%U0NYdu!czU>DqMNRDXXoh`PmI>jxO~#+Q{|~`s`HoK%sm$2cRDxds)m01jhuTG
z_P?jaryMaX+F5VHWT%sUZB3->&9HUTP5%Wfc2WNQ>e=jky;Jk2`G%L>&tR!hd$m!{
z){67ThWzRAbuTt+=w+)+|C4AsYpKcSQo{$6yDOp@Sw#XIP>BSK#ys|#A9{1%YglKt
zD12J=YV9=ViU-H-{}t8>)rHInV_jt*u-oaX#H!;<)@B`OuYBoX|M`q@cY%=X$+c2{
zIefe&)N<dl)kLJX{o46_UiGD$((69QYW$VXJYHwcWXH47O+d-4?t{;bMP7?naV+fL
zBG~4&zu8~@^!i}QtXEf7{=D0L_Z+hwkH5=&$4G5yw~nsgAwSM<pZW9hE3==UUUYlb
zZ|DoJ(e=5~;Qvo*@%@yQOQ)SO-}}X^an=?i-<K|1tvSmCvOM2L@n(i>i<hu$6mYw>
z@88$;;s<wB$cG;Jq!ni~E&SOc2S+)(p3@JE<l`nJ9=fCuXr;T}yG?g-eV5(*{r|qM
zcfGG<R<qyVRcjUN(!UEr@3B|rKlph$z~|SWnB^Xf=Vx!*$n`^@;PLUd8x3RR?N8)i
z`*fYNRm$$)$9{b?%XKXwr~8g>GDzRN@N0yDa>EkQXBGBJGRLa3bN2AxFT0)lG410n
zzx({J`LC=C*rOzWtiSI5+HJSA=H`T~J8qZ7Y?oW~E%`wE!<BiK4?eIpp7pb{)2aD&
zvhBCno9_=dTzj(cVd}nJ4_1BXoge;Nz+b%L`ayaA$?-o|{feEx<IkcGf1~qP-GBFl
zE426At<v|u*4$s&T4Wc_{rt(>3uo^M?fbCpZTD_Y#@zB}o)5nr7c=#l#;5r0NBlhA
z+4b+OAI{uwf8F40#oZUv8~nd0U-T$Yx1Fh6aQH)XrqSGu+>dXx7v8(LL&f*+lgYiu
ztxw06-AwI%e!J@R+S^+HBev;1mi+M0MZ-4pS#ziG!;3j@7N<RZYgH@f_w8~?&F<5R
zw&&YZt7HOi<zHNM?0T8?>BlSuGgI5z-bt@*;6Lwc(H*}jKx|X!W77lcBRvFzuXcRN
zUu`z2;k=9ewZ-078~D{P${1H3ve#RG*?X1SR;$RjB|8i4nC$`&d1IzxhsHA2U9uk%
zf4<xh`F5T7<&Te}tmfU$Ri9r|lpwL>#t%mMx&Kqw>YTXfc|bkZZ0>8&lD7x#ySLvd
z@-{39`(<(cwAG5+yg!~WvhMR%i*blQDwVw^u%_IX-Q0e`GwUZeb_sq^Tri=p>p<~G
z=C?L`M6NG<GwJ;<&d8;S%uG?i%X~Cv?|J<DQv<)fUj8-pN#T_bJuTZTrqz9(eP87M
z!{yqSbR-<_2U)FR{`?^-L4++zE+)e)g@0L3fPnO0narsbZ3k{uKA-#e@X=Ir?H>=O
zg-ySixqNQd!Yxu^2`%O~_Sq~bc(d`im~;44-B}N$@AocWxNXyQNzq^lMwM+AU!wNN
z>Yum!{l>vT!|cpTqr(&GD;MAI`gd|m#DV2@Uspado#B7`T<$bydAY;yj$YI05Rv!S
zU%AP(K*LO{_+q=)jFyYRFYYTjxSr6>J=^!VWLDVq&suJ0ok~EvU=3RmVy+b&?tgli
z<x=~!eR2_ej5e$GUd%s}{cgqLzNnlP4%gZ*`Xt>hy&l`Gc;M07FGl<u17kDZ-P!q4
z<!JGe?+?$sUbm)j&PDZ^+ltRws{7<B&zW)V^0`uGySEyum%k(*Xg~Y=ZF@h@<Y`h;
zuZynv*NN!u%-4uKZlZqnhOWVy(43I>3%mT)-^ORnUBxf+FFvs|<(Z_tmFb-iADB<t
zUR}3uotW6JSAW@Cr^c;1_4##FLVCM=oxV-@CCz`I`D-lJ?0nOmxYWD8-2cY&J)6a<
zH)Wn)FY)ZG)rPwN52ybzne+8^^y}@%KYQ(Gt=aJ8iHX12C&zQ0AvrCfKMr*FPD!hB
zl6b$q>g4PSxetno=L-^4Vxmp$T0C2ek`CJYF|7C?e7l0J#=~y;()&M}mH!EfU(a7M
zUH<ot<4h-S-?$;Kto!lTkH`Jyb3%@$@|SnocE0{`@Yt6r6H{s)t$GVO#^Ufk`LhlD
zuMf$m^cecwXjeQM@ja|J_kp+uzs-d|wwo?D_}k08zPK*y0DC!;U1sLh^m&!b9`d*B
zc%wDF=c`rqw>MgwLuOrT@K@DS4?`=}LEIIbN8Y!&|N5J2d}hxs*11d1?u&nJUAm9m
z@Ak^&^Q4yf&YpJf>X)jx%0^DfRq21fUXRa_+ZX<{`tg=tlLwRax?h7fAO86B++Lm|
z@krRUg>%_!X7M_2K5zG1B=p|nO%if%7Bus9nZKTH{bqx+v*?dJmYN^?ro30a?Dllx
z%gf7`my2F6jM$Li__ywxx~O-?Pcy??4mE3LB#8Vw&1_fm-aFl<v3-x=8-)jg()V?R
ze?7ELUbV>JNWiTZJJfY1Z1>jRyXA$q*Zb!`mPFb0GI&c}$rPJ%(m8vLyVd;&_L@%z
z1pi88Zk<_DZM`=xY~u2p8;=%mh_?{CJc0MH#nP)yFPuGp3to@PUaKS$w5>1Xk&?=E
zwl<Eb0(vK<ou3Ns>F$;16~5=uUcAWO_-+59TcQj1Y?{_S+v1-^Sa?j~(M>0%-zo2y
zy#JrXtDMbe&9Z0oDLk52&DZ<jaC5TghljS`T7>;ptmhZqU9on<+{(wt-+oD7c5u$0
zy%QBgew*I?p1R)iows}V43o?t!CMcH-^)y%FU<Dq^89}x`*-JLST=QhQC!~pDks0{
z^6X2yyIza9?0D3r{p$PW@5lc9EWWNTad7Gl{#oo#+%}xpme%`RFxS_nOISDX_Q(G+
zCqMl%eNg<m(fvyM>O;>Tbf4n}b%L3%PK?fxwcC2t`qg*a4_|^4H&5O#YsGjs^Q?JW
zaCx17ZKO`}S>b(x|Ng{07cKIex3T(0<=oQlRH0Xu;ktJwhd+IIaQam{5l->Fd%ivM
z{{3R9c#CoV|I|X;|L?`OChiHFza^*eyW#bC;eAH`SJg}^+<CX3QQq&1q@O0Q)tu66
zk*=J(JA58l+IFULEUw8pXYtlU@8^Z3N22~YdIiljG?uUX@o>=<DRp6%s7w6yLJu=N
z_kHB~VGyUG{%>R9CMU~X7jx#k*z;J{`91efJL$8}v(h8~2u@{NV_|3Ex60(0+qrfl
z>9-C3yX;g}T3Rj>68it+f`2@FVN{>#KL<~Li$}>ZWkMfbPEWSADkz%qf8)8=A9sq)
z*ZpaD_+->-h0vOHANQC%FrN3zZaZqX7}QHPFl0?S9%IgAmn!N%EA*^G|9gv<F~0kw
z^;h4x;4|y}uAg=$Z$Bk3VfZC+iSLQKT&2pJ-S7AD${yF*>~*01`JzKrIU9@o;zZ}1
z%b6y9TWxlZke}7dB^8@@oME;siI^U``MLG?l9J{<n`gHM{`@<^nJ+T})F!fVj1z3F
z6WC^2W@OB}P}eDL#_?m@j&5*`(_MU~{pX4)PV7~8w%4@J%}<Z1tDDJQQ!z(=+Gpnn
zCG~<e4|XKXO+LN)?-OU9wL729a=rSkBts$2JH%w?-){^5g&cATY3%HMZuk98@#C|P
zj_+^LQS+Y{v%g<J^!Vq+{dQ6N^Y<{@v2@)if0_No`u<P92c^@@n>1$}+xGX{ZFZ)-
z!=_HsA#**Y59cloExmNSVjk#7ftRt0>lZo8Uj=O#{$=tey>7+5H6NYpo76XM{LjHH
z6wuTA;AGwJx8YxSkNrNSb=^Say1L!RP7BXM&-+3Tr*8T9@B2dj+7$=i?0sLGAE>J~
zciqjefBsHOmX`iC?b5XU>K|`Ju+~^CySY8HUhHtJY~c~Xms(=iE9XDC;U(R;s^rTA
zZv8z5GPPeWzEp92ptpX;;ldNy=KJam4nJ&{kLyvId~OcAedXT5Hv$~q((4Q3*!Sok
zb<5~JKkJKaYn{iv<(JN1|8t|~bN{i_n)jv;E-y=4&r%Z?{rbq9ZGQqfH`MR>P_yIX
z#DysZvu6kU95aaInLc&f-RE;8*TwzV{bk*UZ<@h}Eq9wQ6DzlU-c#_Fd4K+lb#tXN
zCE8!E-1hmKahqSwtw=YkvvIF;CHDPYxA0O){GMl@KCG1%Uo!d1djH6@pdFe255L-e
zzxo~jp*_FfufFfM{?8NJ_x#aof3-bYxB2}ZU74c7->OQNpZ0wF8prXYV3N#zhZ}as
zs(k(1tZt_HeYh0BE59mJl;@P`vit{g5|*62<2P?}j+~u`<;A{U^ORLJcPgLH{kU$~
z^q#M$+g)=&4YI>?gm2y8P?_2rDJlQ{iIDo9q}k^A_f{<5@p#kiolAP+s~(;BIC<Wj
zt($vR1}_&=Z+*GtF3*o8=MR^9%@#VR)Hrwkgo&@zI%BU{asK#n8q%S7a-1i=B;f6;
z>9ZN<$KA7DHybl2U6{>um*+=-;9M@7je(x+exJg6<v%aGf7sAOXzq^8<(aF0e(tMW
z_Vjn<KJ};7p;iYaFR8BO5}Y2c`XJcM<UG6mkAsVh&BNHzrP{c>=C593JbQwJ6x+f}
z)>Cu0-6=Yq<S}>a^|;*;M{9On4Uf0|;Oy$8Q4;fcuDN2{md|q}cZ+_|<kkyVIBx>e
zU$c_D`St&PCjR^LbK;I4g4&AfZ#;MY(9RHWtKa2E+bZ!E%@^&7^EdK-S$)K<Rn+R#
z?aWk0`De;g4t)rdN&XS6+s@#0>(eR2kj&@1A8$GOPyUeI8s+sXx18d;3_3m|_eH$b
z-!GRB7ao_LuD48LQs3j|$5XoWeJ1l=J#yr+?1x0z8)9uPUA+N9wIwz7XJ1co5Ne!g
zGRJYNP+#kg`;YgW)mu4hQk(jWJWx;Wsq(6Q7dRvfbwHbdHQg?0ysLR>e@&k^RX}0q
zw_Dk-Cx1{ba0|+~_Gtsp<&XcqUhJ>iQn9yi&xe20_T|l7wx)~Q-sIVgWrzH7at{Cd
z{XRbA)4>+4@Gl>i9M0al%0zVf<hW_Pp>Fj;_GQoZHtln`*8kX;H)CVZMy?+pVk)mH
zzf;yZT&?<E`pZY5Rf+P;8fCtTKV0&q{X>rMwwPnbOrmo(y6%bGzl2M;cIw8BGQV<H
z&O2JFm1FoP=GUCtdAr{x+5hSP9K5sZd;6BcJD=>%X3zL;+oiok`KZqJJ4HudEAY-)
z_PPH{)tmX|4=yiDS<g}<(f8_Hl!m(OmDI<R_le5=`g}Pz@8pFPmI#hbOLDt|{W!k=
zecAbC-J(xtbGLfgpWgrLsCkIol25#%1*=Tjn07y2(9hQPvg_^tGy9EXs{dY)&fBwp
z?rBYLf3EO-{|{{VvR^0E$L{~Z-^>RWi_a3tzLmE1>fxQ$XIAO|lHHncQFd!XV5E1u
z>h6CF*$<t$>8!pY^>Y8!+PwlF6z87m49yAIbK>-rqsMRURdG4U8J06e?{SNr*`$jv
zXUuQu`f=ct{enkd=Ei+$XH?JF`0-)U&D7~fXY1;JKESPBnVR`{`@XMh8-;h=kXSuk
zAaHjt{|;t;n+<lB4;TMYnP^_IYUUF8rX}r{CwKp1vf8uhqMLN<VLoZDGl5S#p1i8q
zYO~=`XUwnmRO{ESzozj&+tQnQK;2GX{g8}urqVq7B8z92h5IdP)fwm4SzcT0sLm*V
z?|6lMckhzws6&SL?t4#XtEtM&-=T*&?0evdz>Ba0?eDcD)zsJCIaGd(U8candj@DL
zs!a8pjl7pP^o4xNU;g*o_Wit|voc<mFMau^#pvDc_xswqEJB&=bh=ORgq-n|{ww-=
z?e;iB7qQT~OK!{UM3pYpvB^EJer8$xY{}$n>p$-;dGr6k!z04}YwX3=2h`5<djF+Y
zV1t6hgfRX0VF%iur*CPH&fB55?$n0qE%l$yrQdlu<-GJ?r!Ub<ZXYuFBQfp$_sfYB
zK2=`6U3nnA*Yui(lSZcLl9FE)bGd%AC|%koBKP}=y8X?v`vRAR%}#88->E)NqsjO1
z*VCY;*~3}c>k<uJlVdM^xDdgA@u=5^b0PVsnp0}{&+j|geluC_S4N-JD~)yAu39X6
z@!3OrzJc=8*&M4sSndA*@3(Z@qHb<Al^K0W2R}LoD7T&9xFG1)o!DU!U-xt7`I==M
zwNJip=0Ei-X~l`d**n(=$|<shn#JGza_4w;>aFwFa&~>Gi;Hh*{d8<X$Q$!{^Ct#Z
z?Dx1G!B$f-KdEEGpTCB&^Z!^W#|iw><n9pMwCMf}g{Nm`8h6W|e7-(%ntKNK<(k`{
zpLcC9RQeKb_D1aT2ANe%Q+xkhcq5TGMdH_+T~{9&&fR~!?Dfw_MUN|8_Sl9^uQheK
zz9*9X+NvLGBDViN@>IO_{r#xDuMSMV|M6VG1vTfFM_c`ECCz@{`}p<gvhaOYwZ{t%
zxXr%)zUtS`{jFd3|33TS`mOFQcfbAPHRC*<Yri=0)Al)^?mxU||99iVePww%k=4bj
zYd&9_zUs{eJC?E=ZE3lWMZ@`~zcVgL`uT42zWZB#U6kDYM)Ka)W8IxEPuJJy-*|o8
zK4;qv!@c{(ne0}t+x04Gsq)HYhdtfYd!OjPyuD@OI{)L@PYr`!);Jt>%QEuab?mqG
z-X}|DOn&j>*@+^LW5zn+*1bhNnMox!%yw(^A1>N5<$>z-n4li+Tj#bJ@TwnpDW6o+
zur&XH_S!8$&YmupHrEtPRFLaGc2atOMMv*sr)%juCO@~Zl|S}Ja01`wqshv=KR&dF
zRV_N$>1(ZCF{j~^d!CiP`s{w&ZxJz1f2Ce+@ZT@{+Mz_~L!wTq(BqATpQhJu6p(*C
z)tlLF?<Vyae$0V|ghw1l-j{yv`!X@_pnm<&({1l3MBclZK0mf*`<<+tsfRxcsClgZ
zv3=J3<9hpkJbLu|Wt!~HkVgxe*cUc$@$$IZz<*!=^2Dm^vE{tmy<G1ziP~S1&pS4g
z!{x%mx$J5cHoQMR{51@<f4AdtpGEdz)xY9Ae_b?K|KHdp`C(xccdbL_)OkPl{8Y7X
zS+-yOZ`|xmi*G*`8o#!^!@vFI3w52%?{>X@)}3Ev&Hp1HwfX&7PJa_?H;%-QwFaWD
zpN`cn@8Vt9`%voes=_zR{u&m_IdQJ7Q}Ab1uj@JeQC_+XR9(gXD70Glw#8({xhBS1
z{!ppEVLZ>np6*?_W|Q#oG^;~we_fBu6rb6!`q0J`h7L=oJ(T+E4;mIYovX7tCU{%S
zuihVlbx}SGb9Qa|UGYC9;&9qSQzj!3289`uwr%A3@nKKM)`zu^Pie3B319rhYQ5~e
z>!<End#7g<s{gg=$(Xe7{d8YHdG({hvs$Yk+2pYQUZoQvy8PiJJFULdRjj3(kJ{xh
z+vRF~_hOX~`(D4dw*A9H-*zwmyFY&{et0*1uF$-nzl(G8d^z&#{;qoX=leTxj#Edz
z-Hp!Un7^+mZ_mwwod>zJTTkEr{+@Sg^S|$<pAY@t`*2s=%UO3TuAYt$oc+IH!?!0-
zUrmk)mVT7IJ?iLOzgrJy=S$jcKU?-S(%$I%pAUzv>q7U(mZjc|VqLh~z9!}GLjF1R
zWj}7(K2=XG{(jFsXVazE-I@OXuJ%6Mzi!74yZaS!FIyY<Z=dfxyXmxE^m2vF(-EC-
zS;Su%?=4Ba9$TJUaX49W$>PrmY@Ib;XOAB9WL2D2Hh;44X%o|v>~&EOTg~H{>|S=N
zGfv#3QWVo((aD;BXJd}S_x|z&>io3@O-DGxZpsT3T3_<^>do7FHSFu|A0PaW_aE&%
z;92#_d+XvYImxxp)WS82Pp;QUvVJ-xSd6>u=<&AQDu0f0GW<5&R<mMzMg7gxI7v-E
z<4X<v#|1J!-_VGh`R}3Vd;Q%iN8F_Bwxu;1pPC)C$Y9&UZM*OHm2R6odDb2wv85)n
z|9(7X)50ye-P|^9)f@R|kNb`PJy`NF?#PbyZ}+5&7?*sQ&p4m&!W>uB;bqW3ghWAO
z9&62~#F}M(b8mg?_jy^fOvpc{=D1n;yE}`FeD~z<@U|*?d1U#n8kv2qUHTzRi;Or<
zpJ``YCG{auR^n3U0=E0L(?g3ET;gElU3K_!=AAVcANm}4`fBxhy;Y}=l%8AN^g%gl
zm6w23hy9ADmdku+i~U$=xKN;O&g{DLcg{BW-;vW=@cD5L6I-Q6`@%^E&)ui4m3n=~
zPT62;yVZ}r`3_>o-6A8FT`fAzWLHz}eP8r&!pA-S_J1FFXlSq5;FPe0wT<I(`?j^W
z_S`D4uSxf*KmYl>ef<0>3f#5IJ=+c#UR!1OM7&n~W&aaPvzL<>oNwD_z+|-XtJi_{
zuM3s<Zu>v|T_Uk-$GSf+=E`4uH1pfqqsMRWjM<VAxL}pI=(<PQO7r_ug_k_q@w{|`
z`LCc$6Zo8WhjO0(@XPMskH_BICnitax5lJps(pRc?C;8F*6q&w_^)_da@O10N&B{f
z_Gippd#QBQGC{wcpfQBws(+_Q=kF;jjQMOgMNB2(VY2LpPHC4=xkJ+`=j-=>wo0-W
zJhIs9W`=2BXk0YQ(@WQNPp7l++9_AmCs?d4lRD^qZ@Wa(x;GN3^Dos;|5m<j^Buos
zh7W=R*G^}$yL^9x+mDNR&QrB+OzD2N*IFPV)66Dx*Urh=hihUtJg-ZftCI71`}6;T
z+kX7x)NTJ|Rd+o0(7e}q0r6MtvrZn1J!hwT=fj8QufJ!-T5b#5nSMWtb^eWik-I;g
zlb<6~xAVosityXhL-cno5j)W7Ts!yw?fWf%^(~gK{aGK){lg$c;;r`Q^<2ke>_fik
z=`}q4_iI6aYigFd&zAGCwUIy0`P%pM_rFdBH8kxy_}^^#nCP0Y?Ct^H&(G#wy%TQs
zMC7~hyoV|pwhtdM&lX<uP)gmKrQp&A7n@F>=Sw%++cN5}R+-{=zSM4l=i8uDhPiV-
z^j;T;UBkZg>7@^h-woFpI_lW<M44`DEnv}nbmP=2lZiR0x04?)ndjhhQ{J+0R)y!U
zc_O(vb2KJ3^{R?I{u`?Id4oi%q~*z--|tmN>$UM0Zc~<3(>rHyse%9T@1SL7X5SqD
zG+W&ZFFScsqF&+nF;C{#5#N5@s{8%6JHGx%=IzS9I;(4s%Zy!Qo?0hsTc<rv{%CaH
zKE&fu>18bmk>__)r^j{`P55Y5KjqWDOJ}F;Pv5qA{qCK1df4W87JO%Y^nGIGf<@o2
z@7Zhmq&jn7|8n^SZ>;Zqn`ZPUq{jU8_jVScAMW+cq7TF4DxWU8T=7HI#P4AF!y0z~
z_TtFLKVO_spW)Q7>}E;o=d#as*QE2^>=#6FI8NX4e(Buj%P!YGJk;u1Dq;1la7q5M
z%egsXA39$jGCWj}E2GR(v&t;a`p=6w`}nU-6%@E6-?weE%{SFr(J$_6HlMT7)jqgo
z^PY|K+Pu`(*gNv_{0J}Izdb6wsYE86W#JF^|9&-cP1S3^N!vI1Y4ZvmNw~MFH+j~>
z1rhvC(k-1<k$mS*e@K!kj`<Xo7GeLdH*G@e<4MVruKVsjd^6Nka_vh_HleyhEw!Gk
zx^eD{D|w#2K4s`K-}v{G+5`WV<WD+~qOQBI|4!NM+@t(^Z_d}5{C(=iEVddgukS$z
z+C$GX8{a8+&DB_W{@NjpkT03n{vE&dx^4Z{w%bt;uddIW@dUn9rS@lU==3<XGxy&=
za4?;BW8T`ml`=&iD}A*e3QS9k{T`LS!i)X$xqY9v6}&iV-`Sn{d(zX`DDLlTzF!hZ
z?VeYww&(4a_igt7p5ELxt?=5q>h`x`@tbFSEBChxY?;L&y)^f_`8xT1yDzW%x;yQh
zohfMU|Lg6?l}p2!>{M1tdK>!(UOwoXdFDsj%`;t-?M_VzR8;f*`svw^r~36fEjDV;
zHs?3`(B|VbH6?$uy`P1qisihzAH_m`Rg-^SKDJ}-ON;$eb|^0iHq#OM9LU(Rsb)!1
z<-Z@tP9@J_=t)1&UaHXIDxsabMm#g}SiNp`&5poZy1YS!m!`G(Ui#^wxB2hJ!lLu~
zl9vpVA18mD^wM+Na`nSCaVHrVBuqSA977JU99i+ec#_+WW(U70&rSnj&cA6-oh>J(
zRX_G*Ii3*ZR<wjs-jB(%dwK8Ihv8CZrOuzfaZWmSOJJ?gsl;cZS&y1k_Fn#&c9Y%k
zr~LAh`oG^sr2pplXxNgF^XF0fqyuZE)Qei?Ug}EObMI&C8Qbr7f~~ZFw-?4;ejp}n
zw5@FO<25CYvUf5MEN3=J4+K?3sI#AJF$?Z9+cEE}zWZm^fdWSPiNC@X<UjRaI8pGI
z>F?@?)4uL@c++0ivCiy!$$Hirj$L!U&->n9A6vP?c(QNhKCy@&A7jf~;;*cFb?5Vu
z$BhhUqPBY3zSiCDbR%i%)kC+J`^4sS>;JuL`|z**&p^ZXN&IQ$XJTIaK72BBw>i(-
zqbi@}_t?*={H=fZ?$+luo38Ejk;v%2zFy33!^35XORt+uyZY;Ea`&M#H<!0ApZ`00
z+n0y=bq{lIw>z6xd)FSSJ!h@G;on=cHnrb3=Q%gF=l}UL>%&#n@T=+ZPq%uv&)<`N
zf5WdO;_dTyWj%a<NUr$Y8hg8Y;Z>>+nh$HOUK7;A>$P;op1`b06Zlgv{BZv&c*tSN
z^Op_kJ0`GIKl(G};O-BHxF4TAs^_^d=vhxgz%38E`!%1>x&}>6(LX3SulvE_wAs1W
z1a2t&aah{FX_a2cx`kd|yYhVeJ31OzW&i8U&Q;&B@ow4etCQzV5tw6|9ag)wO7X$r
zG66l$_KqZ0Pp9BXlU$5nCOYx4EHJxY^ZDqpt*RU@0i7jfk;(BJ{6D4Gu8jCsSakHG
zL(|mE?KjhAE6tp(*ZtR>^Js*UaqXH{rEN)zd(!WDunFHtn7#7cp?}JXJ}37?tbFlq
z_j^4pj@%6g1D0-@$X0WMy=CU52NDO3yqJq(9v=Q>Agib>wEun0b8G1~JLM%uEH<2F
zQU{&jX=oC%>+BozY3B`3e+yh^COdB}sPQv*LU7!*NkVJhRD0c=bWJUCu6a|N{2E@*
z>1IuFXHLJK!D6%D>w#@g{NeyE6aBj<eypDIJ#}B68MEEpE2TFvyW|e_ToNB%p8xwQ
zjF(g5gXAWOE!lq_*!*p@a&B9?*qvuq`|aEJnb>Ny-rbMm{;}bg_Vp%X@$0K@3V6NT
z68QCb!~C<H_3KJ&w%z8tSJM4q>Gt;*-aX;HZ2RfV{KLD?|EjC_@N&7-yZq<J%vP_J
zd-ldqTj%4YBg^kp75_MYdUm_xEZxuS|F?zTNPHFbwSE1L|N9DZbx&+AIy;feeaA7g
z$L`Cwn6gC9*>`*TUXc%p(VWTwvg-WhA*Bi*K3tyv&m^YcAnW0CUY0g({fnynuDS(0
zioX9VOwcCNEZ^=-@aC77ey`v2=~U96QzaGi;y8Y6=wq4NXYr_`ZQ=1trTL|E3oc*Z
z|L^NE(W#I2ury2jHepMB^!IHHsEKp5*krZFm2*ayGFPl~x~g<caor^jalvPm_kZ8J
z9$=Zigi-!lBY#X&GE3JfDMtBan$@x&Zz)(fDXa)h{>d}*+M21np4an_TV0(YVZJjm
z+pI<G;VRp2Hx_e*na<vR^>0g?M6kL1>8)37=GvtlSRQQoJQzzc5PqQH{DXJD9d8yf
z+cj@mE`Hzd7x!gB)gSBr>E=sniER8Kb8qp1BccWmf(!3|O*+u-TamkV)`{cy_LTnk
zuq>a?d+(d4x%pR%w|>;!U;6mZhpnvP?c!OoCqi%gW$!bT*?zcZ!=2S}cfYL(x%KnK
zozLB?oN~{9xzsXwT2<<fqHB$=sS59QefO{DxqRM6)4(O->ah<g>Su50=4^c>J?mW8
z`M}S5e9P~ad0);v_P8;Q`$vMq)9I4NX(EkXB^is$YC#98D9JdhPA-#vD95B4qL{fo
zaA)hLnvzf3vvQa@<J-0`db~e$an$jh&*w>lj&ex4b0&`G$A*7Ak*+UPWxZBkE&C`D
z>i=O;m8W%Y?ZM(L*2fGFihle1=H}+^jas)W`^uIl?l*j<b+zV}rJALg#I~NS;C9)v
z8!OmrBJ#B)1m#X?pV@LtP3v7jjc&w-1y@s!CWmAyJqZpA?B+bhWcRmXO|b6Ev-x$!
zE5kQ8_|K{M_2p&bg<#{u7O{I$BKB2&e%AW=ob~#b0*!^YF77gUU>r3`&mBu2LWYsq
zu6gr%_EK-&A3U$-@jpBw?60Hs!@bd&-*(Fn$I?A-mooiTNjR|l(Y-fU8~pF|fQAPD
z7tem#_~5K|_Th~t+4X;3$9F02`FCIcS$T-7dhEMTTNj*pID5b9n}5eLAAa>+#UUsg
z6(GH@d%>AE*5dL~s<CmaU#q{_;azclmp<R@!v-nF*;7mNYMv|%+q|Xb&C{&{$J6ia
z%AH}F``F;;)b*?Uy>GniyCsk$zyD48!)f+5G5hz2ultg8K>e1$8-*8#16+81URia~
z@Z1E)khcpj`7ZB0aBAD_yl9r%Q>%^(C?#@eX)znBgibZvYSwZ&uKKO0#Cl`?UjdvQ
z53BWdzu8n(IvX?t<JzHQ=e|DVL+9(ms){mB`mfjR&U<OMi0R~^R_^Y<L1t3|cdgm<
z`VDiNzLM<UHuF7+hUU)>_C36P<GW3`xwLcm**TWR22aGCS3m7tc#tDw!n<cPmXvBg
z5S~9<abDTI%I8UQPicKKkPYp9c5d$N4RMA4!lqAF^W_2^2ROqlH%d^$Yq>7>k0Zx_
zzm0fqo3VUunbxYXqmyN~mF{TZzii-h3$%ZdW#g>Ys}k>C?|QwCTRgTT(6B`Ob8o2e
z1LLqucKukU4(yrOYJR21?^1or^d)_Xy;6MY)X+nq#iw=~zk`<P35O_rtCX$za4>ln
z>qna;pZQz9rFdVl`n7ucO3!PXt~1*ehORW<6s7xS^S9U2xU>D^)^XgkiRAuj^KE+i
z;q_v+LV49+_!C_OK6Xwzt(tw+=-=0`tJ_S~ef8RQM*WJP##O(9_vqIT#{TWma+MaK
zr8g<B?(Mcpo#~l)STu~Q-|lzLj=vl2OF~35)@)lfo!M?B<5jO0GX4KKjBLK$NItqB
zbdI~t&nJ@;Tl7zUdD*prE0J&B^aZ@9<F{l4eym~fa=XN#y>`c=uEeKP!}XZ7bJ!0~
zNY6fg+9j8zkmG>>$HHCbgZ*tobA)fZg)X|7@rK)P5vPy9x`kGJzgtdUyz~9-8twD`
zt<u}3|Mg6jaWZ*x{9{(g`GrDPi%#o?@9~pZ)_tAr{|>uL$J%X9tIhd##`ru-n}YPY
zz2N%m@r2|#4C23S*>>Lg__Wl&)u=B~>UUeRgg2HcoCOU`!mbKsXF`AG<t)mX{dy&6
zhIGM!1soC|R_<7??sZ`KqcqE(EW$H180T{yd-VzwHJEiANYjPspcpOMzAF$c&#VT@
zmVD+9f(6f<+^v*wV7c}hy%5Yi4sDz@?h`S1aC!RftGz*>vRcA`k=ahPd<WzFt^~h(
zqKwRTv5BP%!3JX`zASBEoWJkR+Po>Cq;{Zz6Xg8Eygx!%ia)L6kofSDYc+Q$$Y7{-
zsP0&x&&u=T%hSBl#o(24Y(57X{Ey1!9aye3V{*Ccfd>EZh}ab%gF*hpTtZr_nQ&ma
ze)($Yr675O1aNI$z-%XaaLyiWCbpVghh8~}Vzn6Lq8Hwb%yzXqqwi{f1|l07g+Vn=
zyYz>Z9M7J_3K~4PEE*=h3S=;*#atQ-9O6N(i_>>sxoLvrd1f>)&hN6m)8OxFp#HwA
zfpPx24Z8wB2BZ2IWHHD^zk&`l_{YBsGxq|?Cmdkm`4MvGAzO`BlVxQ%3(t>|)~l_f
zQ4R`O)D`x%ngxeA)mv1j#~A(j`@a7D>9@s@v?C(H!pLN&zvqLK#ghrn$4ZKm11cb8
z*PqST+&(Q~t8rWOe9vOlgaheYRAT#ZC#t{t1z#?@w`&G3YXP0!|3c!;f88=}NHTh%
z&)Bp}zxw9sLx)<q4^Q9sWvSs^3ue3IQ*S4Ko!!7VzwY+pJS=4{%o}%wXV}$N-Kc)Q
zw_Dxd$z|L0>1)90%fXx_X-9kN{}1i<JmE2guIBTWy)@$eVY2iiBWs(u!2{zx6N6EM
z0VOXUm~i0V@AvYcsoRCtdzOKXY+w@hN;ufW`mp-`?|U=WZ)TitsQ#Vvx95QdfBUz-
z+p&xrf>NbOfJ5U(!3C4fUyII{4T~+k>R`$ME4#jIJHV~KM?kLT!@+{LTd((3KAoqL
zd_di+Vx<E+6I+dyL$Mg{<POf>5Ml+W*&sAsSo?xT!hz)%4@aZ;1?qSVF@s-BY&CB8
zuc-1(XkeVrc<W}~D%??s(EV5?;XwMF2er5U2^c)MEdTrBTBtWcxek^WA?`wwSTG$_
zEPc9Hc(*F<K!gAJ_e$Xbcr`#wYUI>UIFNqmy_0!@4J*%&p5^<_uf^pbSd!q<Sa2YL
zL*j#E&)+v;WuWMpo)Ei+7_V_%VdeR8MRU(0hf+pnyQ^pCI1}MSM%GoJ68hQGD_kZV
z5+5=jd}t%et`f%s4gTT*u}>a=+&ZWB?KIql6T)i-aZGGA$Gq=7f6EOjYBx&X<sc@B
zR7D+V@b`Z&7ryQ~C?0;v75&ACB1nj%_;|(-Cbk;2e|9C@#{v&DoVR%N`wAi<;AZi3
zfD+Wri+O3~pmO*4)uqIEZNULhI#lFduNe?|pus=YC><&NU~wE&wy_ITM>SdQWLnw4
zI6vg@YuxTa%J3I>8JX?w29(ZZR!%sOo=~<`8h5>fNN@*sfV#crRr7bqv+(@*ayYI;
znwVgGk;}+zw|8%S%x*bxg9n!%Tc5a!r5A@`(gJ>vB?tXVgpc_jXgL4l=I=Aa_>Bit
zRXX0hoR?0x)<Yz$1rACH2h<OKSj7~|%JU;cw780xbS1JvE8)QMRWmMYPvDUF;Ayaj
zm{4qBg0%&#G?>_G*i!v>&n3oVJ@XqF=YQP%edce60}cN2Z(PhBQBo^3L7<5>!o&PE
zEE=qd@!Bs?{<MGNx;^m@3(t=p>An7tngx*>u(1vt0OjTxv2WYToDVekn}@_MBdRo5
z!X#|=;PVk-|0TB{mJ;JUaBBG#l<?`v$;X>wy}>o|8Ay#xOjv@lg0Sm>hVw2rgV!x5
z%842a4mfa0e2_eG_nn(IQo_L&3@|Yt5k_V^;Z*;f^N4j6vu479bcOQW(!`YWAZrW)
zS$KZ<OtF1hMN}cvz{JI~q=9jM<DIv8TZr|yi=e>+<G^oIpj`@(wfF<TU;-#%7j55t
zkyw9^M#d12jGpiV&;K(sF#P{7B|l9ac9!s)yXAA@Lg(6lct7QgkCvv&!WI#xg`8T8
zxHUpqq*psBsd6kjv@W;&?XF!~uWyycio~{VZCJq3F?XMUL%q@lF%eBBPY)(V#l5~~
z|D4-tJlSW`%qO0o&iJ%d-rr;NedqUi)#qyOnV+=(xo6+~u4`M4`sJLSrhB_{_g!4K
z_n{u!T+h)XWxC2=Zi~}_<^FeciP3c7JPS+BubbSTcOcHKL@^ZQU^!-QhXd&ed-Ly4
z!#Fb<MIG3z1@k#Metg+1{;Uw=fI6@|st&ek4GrfHRNdc)d6f^QT@Lob0v}$c>z{cn
zgyj}6=#4bcvwc}Ocyt&U=Qn=cR~rqv=L*$gG~YJXfo>x_A2;K;D!Msv0}%{~2qq>w
z=GV2qw_))Tn#qhze|;PdET6yEpda(54NSWXHn6bNuwDE8Eti<!`!%zn!QZ|*QEobB
zXkmyXBye*4;92wi?QLR$?~5@b<NUgBhivrFPe#EKkOvM334D-@cz=64F~RpDor%fr
z@0-@j7-C|k5p+rHhI`xdi3z^ZgpHQ`MiVxA9ve;AXt{2*#730tka}ehmDpcygX%|L
zqUuM6#(SbGGJK=o>t&jv#W9vL8&p4di3)ts3_WE*l<Haqg$I|}UrbX$&r#^X2dWeU
zRy8#EuM9edaXdC!`2?<9UNAE<&bM>et^(#k;s9g_R*M>gSXpYkrW*BuJb=wKWc?2E
zpxc)jcc~Inn{rIiQg{%&YDytayOG`Z%faEma{ddto;bo5#c2yd7#ZgWE$vap>Lp}j
zIRq3gu!C+xZ^-i`Dq5Cuar~H~l`4Z~2v&<4?F0lqyksu%CZ+`-pb_eDV0nn<V-%m@
z^6eMUJ?HWZq9+j*Ei0Lr?3Q{-y5lkpIY}+x2Q^k1?oJ{qT1JyJN<tV-(kPi|G)bdm
zBAS=dw@w!RuYJC2?wrKax1*z#wX~GFYIoTrhNRB<_2-r@yA||eX5{RSQ6yZ*XJx6W
zdU>@rIgIbe5*NQEE`E~VE$>{ORTr`(e(lTa{~og+)oj1=<<j;|JSb@&yQvQT+#El?
zY$^Et=l+bX+g5Bb{;T?Q?S{{@-Df2o+%#>Qm)+~jNt*U07vioKUUGaIyL|c#9b#O$
zVP-?a`7{OF(jQ-~iw-O|P5Tpj_t-C6S>0`y7P-dGm$j&?s`S3|H6Xc1DopTe@9WF&
zV@|3+YMq?*=tid2&o5Vgo9GjE{DSQ)EHzc0zb4(jzHF))TaDPdOuf^mUI)*5ex2XM
zEj9JX!{6aY=g-gREalC7HASN8<UZ5FFLhc!r?B2qL5X-AwFBsSan&E*|H^#>Bh!yf
zEVX<t?7!ZZaem0f<!iTxRdvYfJ`4^N-0z>eD{M`qyt{mi@axO#?f<T|yk@%8^75DC
zauMS0K7l8fPmkN2N<^)ZDlYIr(>n9IaGfq|P0@pAz3xlJVx^hvGIIpq+}!zBxp;Qc
z!AD;Uf7CT6-FdMpV&Wm^dLPC4TY1-N+J^|L%La*`pRe)c^4HmgL<~%9$Oc9GrQbha
z<!U~dEM%8&lT{%2rE=9?*KqfJ%O4w-J*oJ1`RvCZf1Xv`d*Zn9|Gnl#3zu%?_<84l
zL9&U-wzEHG9d18%u$uQ(#IboqRB;RDgBl)}x_`aOUEO`kHeF_K=7Hz8qKi}K-&wV~
zcDmNPocD#fr{40&1xd2MH`d_0y<Kfq)FO_bI`Nl9_Sf&w4E@x(VoguQ-|qIK{~oWd
zekmQ@MvSd8OiXr919TGmy7SL6&c9~y`Gw-jKL2c+t!hgPE`8j(eT`rF@&<peA5T7u
z&aEn&S`{;SS3a*~j3~RGgowM(>h5V@*IwMRPx;AZneTQH^1Qy8&!)&)y<U1a`H_U;
ze4)6RibSNMSSN=A%csX3KB{?QGP89q<9rXs`OlQD7r)ij?rO3X-;?NLvV4yJsb?a;
zr-}T_^i!OBC0F}zp6<7wRd(0s^j+3#3k^N8>DaZ1JsS+?#a@^ZRdV%M_jiBB`AIcg
zKevQ`irltKv$aNQ(LTdPR(C%yOLjjpPkD9K%h^N)P(nHjOHG+uzV*Am>t}~At?)lG
zQ(tyc-7+q_)zMuC&Tlne+Tj1|>pRKEx0vmun{6#GY*xH;S@X^0^Zjer_BgwTiZ;%l
zEf*nNU$scF@5XwwtuIz-&s())eX#0$nNL6O&VRkwF7(q%znk;8{iGxpw=dflYlc$&
zAU91B(b*Uq1rD+E;Xwz~pH@6NGyQ3U|B<GvE1Udpt=n0cxv~EJ%*WlYY;#4c&BETj
zj5)eo_rv9|r|GXgoRSE?E_Pw(w|Su-Jyty^zO&Fd>HprWPew<#RjSTkDyuj@<mB?S
zfYd#IMRy<laL~!_ZA=+45f}t^&guGlTQ+h0m{WS@!j(zdp&ueAYyDXA*VJ53^IZLp
zIeX1mYOXyOi_u(qS@6Y4$GI}MGCf0Uq%OA_uB<w5H+R+hn5x&GD$-oN_xxLtXjr!W
z)g$R#p-(SEPNu(HwQR@p#!^?+`L`TJKkBcS6g9mnx_3!}Br!qtR#f1_&A5%SGW$Ib
zsGkiC`QWKJCp#}<&LQiyA3KZHmz2fiUad5H7kojz_w2!Ww^nsYL<)cWvg=yN&gDvN
z+uDm}U4C%>e~PE!J6-kuo>eC67Pp*NQ=Bg%l$F();qiF-k_qSY|8LQg3R0cFuzB^P
z`Ej;JY)^mZ5DYYj{o)b3%X06OUXR_FadFX#_3PhXd><ShF8=sfZ+CLPtyvpS=Ig90
zi@EtOoMf%3dU>?|=dqZB%T3Q&l|^ifzYuuvd3g7ymp{HltCey6*b@5TCC9HPU3QwY
zgIQ`nJ?>k#w&S4Ygy6Zmvd_le5xKv+w(`ogkYii+W+%laXRlcsFVE|{_T}eaEBueY
zF1B3ICG#h<ca}-skqM_(czoB3n{}&Y>F1w6Y}d=)^%k0@h_&cPu6nAx7A#z-xNh&a
zTPGCf-@8+^BmLKxmlK)ow|(N~_%Y@FmeZ2^YYv}U6m<Tk>jCwof3HN=d8XHWIi241
z;Oz5zW;<6Lnta%9HcR!T!gJ3>rq*0K`e*0kUlXqMzP{If?daeBCHtrBWbog0ZQkRX
z?;iWlv)p$2c^Tn8!wY++&1q-5+~sSx_{&xN|NFgP*w132|Fybx`dSYzd*}b~-X9fM
za&Fd4CcB-g*PE{Du3X^9_2bW@mtR=ceq74^{jR`=lZo?WzTA{}<|$fptKXde*Pl=3
z+DS(?tdcO@WA%zH+$}dZb=9R{!Ko`-!;7WvOj0}b{oj}6pSw%r>p#ugSW@YIWqqW)
zzh0it)w)YZOP(&;eC+F_7Q&TW<2)hIxhhqAbi<Et4i67Mz9MjO(%D(2u16Qd?0tTx
z`25=)Iq`0cjPs3>@^V)xJ(#@7#JK;w?k=Tgr6C`F{%le@WBhPNq2Zognxc<ZYBX8!
zzFwUa_;`Uy>g~egKV|Q(->J^pd1+Vr-aMy!N9_);>MmWkCppw)Sy<eEv)VJ)<n9w5
z2v{J`5mWVYX|zph-u%)thR2Wm`1rVdS8G__->n%J7iDB+b*&6u?v|RGy7AtfoyCv8
z-Old^-A~v3b?%KyM#lMb&2=){^#2)!e(=0na?Y}@LU7H@`+*0ar+>cuckRcQFTI0K
z&Xf7znOa`-bKaF~?e|fOw8D;@sL1)dB;xk2$F;BWe*T>E$nt#E-y@GK)%fH?Y>xB4
ziwS;X|Krv~)mr{$f~|<g*zknU4gR^gxo2h=Di@ttzI^-B)6<WinD~j^_My&$%fhQ-
z&-`qS*U>*$#!~ZaX@kGthnT;Y)s@q4+I{|Y^XS)iT3=jJeb-3Tcw7nZ_uL-(<dB`K
z>%5@v|4WZ1yH0ri#@t7b$?o@(2LE{vR#}IOf3Ep(<<lS5=-I0nb>r@a)J$Jj7qaxh
zCAr<aU9V34Va<u<G+8<?%YSW#j^10d9ae69>t1EeC?-^XBycyLWwtvmTOK1*aDXwo
z=k`tEpZ~Y5_nF!3K0m8#qw=apdxYDL&UpB*zB)a2_wM)u%dKY`&HrD+_u~ndoqCVP
zH_Hc?XVu02oopF6Q|oKZw=Fwk*X{6puzZoxwQzpl$F~j{uC<gh$%qKK($jP5)x*H4
zb>-Xl{@*Wu?)34S%Y8MkofWP5)cI$+?tA+$-xu%NUAp_+{Vxwb?Rc<i+lHWWbG}up
zI{qHNdi3-%zW(p?wxsi{&D6er_3n?xl7AarzkWO?f3|bK-QIOSZoRk2tEqW1WiOjh
z<9kBWP}YhYDi5STJ2TU;B;%aal>E~V=jGquru9rO@1DWS3%j~1UY~Y9GH-E9joE@J
zADbKeB@MTmU433ZPy5Ff_L@s|_f~ytIRABX_W@sb&v|_g{{FJ_Yj0iI5_jat!>dO>
z$5gs={a9kWSMq}=cis)Po>iUQ={{Z4edM-1yyNh<;OXA;$6WVE34HZk=^Oo9?ZIWm
zM1PEKhXabpQjQ$C4?8~`;`ZLT_K9I^YqeFLoZ${5yP~Q}D~{4LnfF2SN8a^9cHcLr
z9`(w%Ds<7BF`3D3XOsV}_}agZcQ*J{&s%P)6~w)Io{e4guYX5(O?Kna`WAj~<En~v
z{QKAa5v{TNwQBF<7q#ZR?{uPX%WR&X+cE!7VdS5>d$W?>-f4Q(_gzM2H~;B{iyOD=
z#$Okb-|_F{iL3pe%&Ia<bz(11D-!u2Sy3-nlZ?L>ebeLM&sMWd?A^)pHc1{_Kjx@C
z*lhfM{qAbknq8AMKmU~ZaPr{X;$X{F=NRX2bMSZHu>AYCxy*JyciMgW^@+VkZ?>gs
zT&2hL`ohn%rr-JLQ}b}za;}%b{Ia6=EwYPdUM>Io^4-k6R`=#c73s#@46%9hMZB-C
ze6E3A-~aRNUCE5|WB<!mIT3K87n7~%hnrzLmMbaF`M4?Z<DZkJyM>MyKZ^u)14HY+
zE%(07Y`1%<X!PTgp=VuJuj!i>^OL_ST5*2JLG{0{UOx78?OxaM{{FsI95R1jOS?^X
zRSI9Y^TDc{M`NP7e>`Edd{TUCyIk+@`8lhfe7>O0*PXca?)OKhAAh!&FufX?etg@r
zuWJKicRv1JzGl|^<bbQ^&KJM?F4u1@7dvxbd1}qGQsKwE`Vyk&muxsMIRCfz#wiW{
z?K^CdYfvnO))b`+!i@8CTdO}6&#k+1!6GRuSF=Ck3?B!_k2egr`tE$1IbTON&-(ik
zkq@4pQ`N(lip9E4Sgw5G^6uX;2i5J}<JoGAPFxQboqzuBov@?Nm;blWjWa2Hp|)r9
zbdw{g`{P9R*X4xjL|l~UJ-gP>&i3~d!>xt)CMG}L+Fll`xFUIy%!{30-j)1+y!z33
z?rUzfyZ(QuZ95Y9o3H<6dw(CNa`vNB)$@B-zmFG64$5A0`uyx$g|EeaN6W_v+W)@1
zsp7-R(vL?re>KeVD3#gs{DDQ$sSOpsH$E=c_%NB-&O7+_ruFkJE!BGSez*G_NawCn
z#}WX@o$&=OjYaG=UYy_eyi;|4d?It}#Y>ljLPPJ0f7AG=Epe^2p}}8V!?sY1y{0I8
z-Dkg3jZ?18n9XeW(qj9IQ;xI0EDZ1O7K?ppx$pme?e3@cRZ;K5Kb$;g{wKBa&td*s
zTK{T(e(C&pOuYBzf&YK++e*v-{<+6Pa&F%C<Zse);d?5xriWI}i@ht8|Nr5e6S*69
z-TLO?xG-D)hW)zVhcE5;@vU`Y|NGw`K5vtl<?K3tSD|Cg`|aJ^cU&ucbYXAXk?X<T
z8)a;6&3k*TJ?seQWjB}7<yj6)cDI!?bO@w?60sX$2cEB7s%uzY7%XG5P|b~R?VFm{
zV)M6~-zoll*8KSD_`k1opA{xOXJx4=ySHJ9q!oKj(bIX0n*6H|sI%9`nJrwmq_V8!
zLcW+u4u`<guWHK;yzBb*@%?xraDM;4oVbr$i@weg=9dVp+4pq4_M^4oc7ZkL4$i(D
zXJHk3Pg3e}Q1(Xk>1M~i2Vb3ge=B?Wz1l-^9}kAV*~#h4$2#}V)%Hgd(_eLeK7TvA
zV9vLui-iHJc5GH*tuKn+5VJG=d&t)3teN-jM6KD~;LoS<R3YeIoK0rNoUf1WCg0kz
zD`G}e=F?Sn_Fh-(Kbe*NSn%WPZ@xZ7)9C-~8zlBjm1nYxK3Ld^=<r|-scl*twl<t!
z!~Xj5Gy65V@7DW#^*CppSmAS9yOiNolD6ud&$pD@j(GF0(boF@q~QFYpPxY&Hor+S
zTV59Ca3DRM)qBtX%h$JueyIGc?Iw0`)=ur&m+eH~dG0TAoj;H7$DgXYziO|2r2^+p
z@6`@sogZ`P`QqjIYvu$$3V&4;!FMXA;Od)4w^EIlAJOK&S;f8fdz`uXy1%v2zc*Fe
zf7x@Rc>A_`i*rBUJuZBHKkV2Ak!e3~-sbOMK9(=laEfuB@&3Qtf4mi5og9&y`seH8
z^XFYBnB`QSvnjvlXPXmJlltq(inaGlDvIyVxvJ@6Vm)oCSY+jEtp}5xT`ueYjxPNB
zXYsLP>hac!pX`g~Zl7<zLFZoO*Ex@_{Pw$L{O{=zTdVkc@6I#X-S&OPhQH_($Pj;_
z_uzB;&ECSZ`DSk$f~WqI{`*I`{rDAIGv1$XGIprjH#PX5{}U+k;icqt-L$(#4<<*I
zEREmk8h&w=HfwFw(;c;QHQ$QXtlP2nJ(Jzeu5&N%S8d5SXj=OH){L+Bn$35djlU=H
zI=Cy{!#DJeolfh-T{nuJ&iNkyKc(>L|Jnx=Zls6!ezbf#_0bD`TZzxpO^@X@uYNR-
zUv83<L+tk-zw@$ofBhJLM*rPwtp~-g%;h@m&&5ms?p@nG`+jZ0m5}^t?=tJxaR;w>
zc}yhlRO6E0_Mi6TUC)-^cXe*V`LN0u0y9sIYdK29Km7bsdOErE?=RhVYyAGt{r4>7
z<Z|UFn{6M?v$@G@ekUO0-OCvf2bMc8+EdLq|5H_&_3ipUJJ$AIu3XvVzix(cdgv;t
z$xRx$sp+5Ew|sr{@yRzXyXp70EsFS+yf@^adVBu7$g3eCZ+E6#I}~wy$G#OE#dljT
zcYO;#dU(o@$M24Z9ld$Ka*ago+1uax7k`rttGPF?!RKH5%Z~GZRi~}Xytk<7{HwNU
z7B3dDcUjt(e2V+H?(y;R-zodObocx--1_O%ZT)+N4to*~O~^Z*_xjK`oB!LM70o4(
zaoDCglrzphAGhBoY#k^<ON&lCU#l-KSlz#}3)-Z5-Ew*A9Zh{1q2uzKHgfxyzb-9Z
zUu><X@L==fvfHKUf*(8|PW$Zlj^oD?E<4S)mjVwyzfo)U@8SJ*o!&Av-~Y7vUYk8B
zI&taO?gsy=b^X5j_1)_NomVZ+yRb|&f7<%o&Qf3L{|8UxZnc|mD{AlWmbKfrW_ez%
zDKf}-x@%fQ<o$2I{|B)y@J_Q0<|yI&ac6c^{@l9E=;*cH=Vr*Pul~1Ut=3r&-5u{d
z*X}S||KRiU<=2j_)~{T$<GcO8IwzTZ=P%?vpSgL7;=POamaU#*x_hohtiXqxv-+|L
zw5m6lHojvr=bmPEeChTzUB{k@2)#&>o?><D&Bo}^Gtrl7cRXKmnC<xK%kR%cm%lER
zd;IwvH^+}RdlEg3YhLXFb<Xe20cC-+bEdwnS1kIcD*L_U!1HyLUvtmj+;?wE$U*i0
zQ};f)CYpI)>c3g-_ieAOe|}zeW!bByE9+KG(cS*^*Q1w{cdfni`AXNZAMbaI9ep44
z<Jrgb*Sr6^tF6Ck`Jnjhf8EaSe|M}cz3%_NFltXm()WXNYVze~zrSho;Bz<ov|Nt2
zPYRdjz4vciT5nhQx^d~+v#Jj^o624%P`M^#GevXXIa9sO@}GL>i<f#&HgBygzB(^v
zZ~Eul?AN(=*FN@v{JG<9+1;In4~$o>SYn)>y6VB?y3&vjD?7U4Z10(eemE)Ga*N4s
zB9q<I^$(06f4Eq9;D_(z>Zwx&C%a!i)>zF0YBJoino_DbGdk|?Wz%A_pYEv{zNtM@
zQL@VH;YT}mt$K9p@5(O!dsgf<b@Q4m-{-7f_IdG@U9Vq!yA~U(6FjHtdjGQ{=l^ZV
z>25f`b$`6n`@MO2hH3KyO;<_<R{ap#W*ldt_V3}0Le-u(RUHlf*Y(a3n6f;ujdh#o
zj++xF_?JJN_s8URRQ_%M92ZT{Jfp_c#52p+)ta$ZEL!nk^77et0}n3eDV}cQTGtSB
zP(62Nlm9)v^P)9D7oI;hJ{5oP`KFn{kEXUSnU->Ur*6bO3H8`N0c-Li;#(^1Dn7*(
zesbJ>^oQWewGqqT!t%StWy=Sj4>WE4IBWg(t=E2C$`pRwqr6Qn&g!dl{}K7;>+dQ(
zD2~tiS{hZodj0A1v!&GK3>IB}W&1tw!1CugXMIpQ8t93-@%b(X&BobpIe+f?a$r}*
zTfykCcP|TcQup?4{07g#&yO{nUr`dDE%@Q&+Fe~-b}xVYsC~69d*55xn)IxTS1b3{
zS~J;g-?H_^t*K0QbG4t>{GL<$_(^m5>rbzrt+L+v%MTP!VQaEGpVz)>eDnv@XkUM3
zMo7)OSI0N6p8fcRzMaJDS=aIfKb*WC_hY8L`1aZ#Q}#ZZd%X93R@bKa!XGrPS90Q?
zVK+!%@#4MnWWxE>m9gQ$#p}c_eciUUz<=NBD_?iT9lQyd(+ABK)%ixV&j0K$85#0v
z=H5j+bC1OYs{f6(tV=r2R+DBMx&LI<?{{IbEOmPOODi}2JAQx1>yQsW@0|5Ndi{OP
zvWk25wO=ks%)M1qy7lkt^Usccum7G?xU%?w`g{x9(0e=0Lm#YMx2D7TeszG4Pwv58
zxBmSN=YF*5zK)jO+lg8%cfUV;o@?~x==|T_Ix#mz*q2UAGT-;QVTIS{(ygZ3w;cN<
zqH`)bPd+U8?$;gb-rfB(r{VlFr9S)~cUTb8_?Gj|naC?L_jm4nJ>mSs%UO?0^(A+m
zP2HZpH`g!CVLKC(-Q7!5z8^Z);2+I8Up=UMU0;_~u6)qBWqTL-=gYj`eS5(a?X2F@
z`F@P^x4iXYoWJ^At(o1Q%auoqORr05x0j#$G5`3Y%G&5j1)m$v*A`ztl6k*s%Z%jx
z8%saFHGeDp``tdnCzIFiFT8I2@o4n?zG>eqcX9oQsr^6c$APc@VxMc?gjOH7moZ-V
z<IYd_V6N|T>W>P8nmKN{rKxv5A9POoo*3Ic$?E>~yXlPc-=)mKxXl!~ZQsDqn9G?X
zw_~PdaT<^8t=fR)t0(xcd^pcE``VGv@Yt;<m18R&w$7HZ*643&@UN8FZh6{uWs^VO
zyE*?)1-jO$v)BA8IxSjL^mM`dyOXqkY&oWWP9l2R@trRZJ}o>Ly19F&9=Hp7;>6o|
z-!~rp`mw89Uhj~#rN-yJD^jnQFqe0GuH-tuCzW?%bVcpwb*_eXp?4~aGMx?oKVzI<
z^J)J2nbOz)7iJdLX85N5xjQAX@Wj04<if1IUw>C-Kf0Ly>hYDsZmxQ#Cf}|t75#AX
z=KSD&-wJH@6vP^ypXuJy`MF<8`tq@>qM!dLp8eeXdz#3@c{UGn^<~B9SDd|f^oHzT
z#Rr=g7ri5}$^&Jrr*-CBt)DTL*`aH4b9$5cR&|H(&o~iwyga7n$wc=@=d9nqvC#R(
zWH-BD%3Fs6%X6kg&wsH<{%Kf{<pbkgE9QK5$+|dolk&xjCtkM5<y|aw2j})!%LkKH
z_5Xfd^y3OI_ow5$(WRlTPr@Q9trKr`{P>_*E&6bF&7IH#>ftYc-dfZ8@#*b(eczO9
zD_^v|Ej=$UDt>-ONXUzm3m2|qva2lM6Wsf^z4%chYqt5F+0mt?A^%=l%zXZPy-9o?
z_cr6%4d>6j*hygZDRVT^2wfYGrtX&DRdMU?72hqr?&|Cuo!Hm+o2AA|<<xHR51Q-K
zw{Ncf<lf!gW%+!+*47tZ2PYpdW}V-6#P`;Gi<RqcSD!9?_)X-)%RTq5OuXu<y6|*<
zT-Y1?%4h3>4=#WF``(OIjJ4mEEl>J3srSExk56cgpH+d&ld{Oq(@c*Q{{MMBsUn<l
zeqZIkUtf0ZNdNZg$LZkg<j}*vDo!q0SeUZz+2-pL7FC_EUOziJg!Pr)gUQcN9$ciq
zbisx5@)2U6r<;qV$$pmK_I<*l((Bp$xvSZ(6xO+aXR@=_dTvLcU4Fyn!DLr9emR+)
zlg{rbe7tB~-t$kKU%!3@O%^OFI=`zl_ilmJYVIE;*EH^@GtU1MnOC~3mvR0@&5X;p
zG#^Y}wf9Mo@y-|Cf<Io)eJu0g<m=k^&z@%fyrvO;AbmB5b;ZY<SAw$rRxR3m{=}?B
zy4U&qF2Bvq-}$I>$Jd9V8}HxPwd1iZd#Uxh$A?z^npTk#Sj*#`yB{<vmbf)kcKRCv
z1z3Z_e6E<vr&BkUy*<Wfy7#BSPOl4=&*xm8?aeo1D|kqz{?n_Yt`nZ=u0N%_D~NUe
zl|`%dxBo5k7OlC&T=RZe$U*hD`dY!P^Y{Jnn|r-3<KeD|ZQGWvxG;J3*OKi|&7$kS
zx3VjTpFOF&P0up9sN8ujf%1isY4@H3Ya%y4y67(dcJlK%X1P%^^?yFrZu(YS8^}06
zuIjKflihkh#`#lLynNbZdv{$pOU<RvF(qM@Q6*o6o|{eod23DjBkt`sp*_2Eo=vHE
zs;Ins&-2UXdL8-q_O96R?dAUa>gQ~WzUv*gB)GQgSF=Oj?5~gI|L?fI`p1)3w#I2^
zI&R&%_3yxy_wxb|ET0~CQ@w7-iWO5PYyWuTb-O%2W}4h`Q`VYeZ@v1rUOvCcAoNM)
z(WCrFKb7hR#zqP*moqcsyPux1N8#@|-ILFBGJD?t&nvuRUhcawY~82guhHMTSD9RM
z!`oh9WMcWX*&**@>G!+k#}Bn~FJ8ECq5FO>zAtY!9+xXTV|d(!@8^vwH-`hu(_^;J
z_$q9llYKEXaO1)<e?gO*p?&kS8R!3DlB=nTJ@e;W^2U_2*KRM|oAPPHk7tpSliz%B
zjNW5TXmkhUyjooa(6r2h$MzZ7%vZfn=YBW(U-zweb(25)fmz4C7QX$j+xhzc4xMMZ
z*&2uJnpbHhJz8;VhS4&!dsCu{<{IR>951LQkfjtH8V=~GD?HeIdan@wmB~!Lx@%oe
zuUj-B$X_odkFZ{cnJg?dr&uzj2rFe^WU^IM08J%4BhUkd3~U6bf#!1@XAv`F-{9a6
zS}4%6%92nn1or}`csd+d?lWN-;aNP;IznM4COg}OS$;%$F;z(5gQoD3Oak2tQ0%gB
zd}(QD@b_OaYckkXsP#W25Rit?M}rz|-hVWxQIpLeOVwqD&+G5+)QbYGS2K&#xn7t(
zPeUtde&E!?SD&-Z^&SXgq;OR4fU<+besO^hFPDb@=#6}R$t%}!PSLyKZR+ebT9?*e
z`;z_tWAmda&RJD2qa%qaBo-_Ot$>T#QTs3dOjLBphnfE-eG0qr^Q^M(#)L@kK*<#v
zPbOcp&RGA-;^l%*>n?ly5HZWoA#lUT;Xu0agn3qfe#u%sxGZJ-Z(Uxp?EG)jVx?dG
zdUN38<<rrR*0oC|U)j*LB0pw+-E%KHLH#))!pHrBPcC16Z+RsVCDvY5P(5&I`kj4d
zYquCa*j(US92pij|B}uAx&?+>+RA+Q_iO$8<Kn$0+aoyKWlzfeSr%3HQ)^B!<q8ol
zv>fC?Tg`<2sQ%x*Y{eSm$0v5p`P{ku`mzT9cPm3DPO{kf#P8PI7a!jT&t4~*eeL)~
z_UlJ}eR=I)pWRpLTe+_znSV{U^0F0AE_<)PX@uVG#*E^|O`zoubGN+a+&_)U&a&Y1
zvBg2%>$c=`|5&oobwm2|Z~bR-yI8xgAAk6px2tgR>Lgb#{=bH;HP_6xEc+ASI;X@V
z)~0^Z1pn*#$07;)?Z7&44f_81>g`KG3%2%rTyfC#!t<5i#A0QC&g(mVW8&kR{^rLY
zf1drgax(kTf7Se5ZPTtPJt_WwxcB0P8)lEQ`Q)Y8-<z&TmL#GgWoWEZ0!5VmtJT}r
z>S=wSQ}|^W<NWOWvr}t>Jm*h2oca33)sG9mJiayMwxrDxBffj-0W#b2eNDEy2!4v(
zw@kC{e?jo7C&Gb|k{^GG^LPI}9{&B3`8J|fV_Jf$;e`>0WW?{!Vzygb`0S!{knH?x
z6<NMs50^a7&X1h?4%C$UaPqmf)z>##Uw5dL-j_1kp~W}HK%;L)n7Hoi=*5|}?kAR8
zzN_6}CpGKR8BObwYu@e0j~F`HsqQgyCZayu4XVxb_qKHhPf%wsgA9C~bzS%TR&<!i
z)M~wo!!t7cEay)-tNBe=^UviuPF5>#hyA)6_2%=}nst`4%VT*~uj)wcUAwU&G1+GK
z0>iB@R`rU%pU-4>^oPi&%=J$;=adF>{WNi@O?D~W_1yP(Ux%%G*w;(u+ldLF1Lrt6
ze!S_qS9a%jy!m>skMlZ=<E>Qw`iRzqZ5L^rpPlc;IRDG*yT-@1ve%fgRTnKtciyo)
z_=fs?`RHiL_P$kGO!nrs8`S=NadDQ}7@wPUF*MvJv@m|Tm!0L4&%5ofyVtII5<GX4
zt@s=hBR78E+TDZ~J25aa?cUPR;IF@T-ufjC{--`3nW=x8aefEu>R{ISTVjhJUrPFa
z&-l3b)#_VX-*VR6xxBN>Kl;J)wWrQsc{tT@-8$U`#cyp_KbjbF@c9ns_9OqQuRclb
z%KhwR=WXp|w{nvI*#)O6eruO?KWuKTxwZ2RF%h@~?3`);_hhCDez1H!W8q5G@Kp~s
ztA&2>{GFW_6Ex@l2g~YQjvs5z>+T5hTCRLya<i4?mdle?{V-X^ogDOaUaeK={heQ~
zJ^gs5Yg)zMz{5#z@~$2=zoqiz^2$l)FNOLRo@ajD<z=_ES?f`JoUvBcD(x!IgG7`X
zj7+z+6&`Hfn`CWKH@U%o*5VZpCI?wuzq7%jwLI#v@N++pw>xgF`kZrT`2v5b+0C|F
zLq!cYsXcmGx^`uezbj8J|5KCY2j~AkIVtH*w4a=0Xl9H%=X_r$J57}<SA;H3IHvEZ
zIRE~?%vh5pUUtsx;YaQFR;BQq`hJsOpf%R%Zzy|vYsc$#yOS<1at(}+zrXnY@^$O<
zj`d25AD64n;gP&_?dl45ahU~^xqp1Q)cyZc@6IOw>^Y@xHYDv|u(;{`da<XMKfc`V
z^G4)D=IRHR1;3mWtqn3;&hhKXaoN~t!RBCv<yNKFXYJmhxv%{9rxj~g_GDIHKeFrC
zwTS5bc2cvVE<gVoIKS`u^CAaP%O97eOf&CvC{7KW_%3#j$yQG9=bt}T$64>1u0q7>
z>n~FroSmIxs^4y%=xn!l=hK4oUtV5TX0OY63R+;iKXbZq-OskEu1n`_?r!iu^5?2%
z%;a-_UQ9nPa&Y$fy}3n!t?KQyW}M%aJf3r2Q|srF?w`fSzbdYjzP^`#ZTD|^&w9;b
z#(5=cZI5rhdwjl4anAJfZwc>Ix=_!Oc6OF%zum8l`8FRw=MbsSDR7#<=5I`V$bse4
z?|qnFw{_8rIi|*}HAUX*SXV~}InEXN@bl>9mz+_Ly~W?{R(vq|u#M%5&4y<tYyH?F
zpD*|2=hOVKBOQsMhFKM*S9sU;+`4rtWa)Axtzho;&rEix`c8TO_oe@H@z?wQJ+V!G
z`DxmU_|10nV(!dX^><14%TuoDy{}a{PlFmK44AbWl8CKp!BNrhFBQ@2`qJ00Th|x3
z*zM>n)9kJ;$DLK@cRrtYyYS||9wsKc)FXFpg}5G2Pt8n|n;%``dgk?t2cJK)y3R;H
zWcWC#qBL0RNN^xaq13hTql=C?W}e#ixbL&|uJ~eqE}^BR=d13v?CGv;3l)DIQ+a$<
zhR@nP|8jrLSZlkF(6o+2gM+=mjxU$Iw^y9HWA}PSa$o1i$H(87aId}dEBoRi*Na!K
zhy*Y9>pgYqRMOs^#m|qu-F{#0`TY8SVy~??er95_v(AsW#1sDqH0QDE<(%R_ACw}D
z_b+ZbfBxC>-_egRU!J~XlC9-~$*0~u`DDBDdf2_KE<b7<onU7Hgs$nB`0>Us&yCwk
zkN>`M_tR&~qs8;S{^~qh>?32hqM}d!&dy~w>OX8%_WmWuMtJwz?sW&AG0wkr>(&gz
zWVa_1{QdJ!PuK6CsQi?_>QLl?<?123XME<~9}zd_Eys^D-i-6-JlOebxxd@FO|{Ry
zZti}4H}pm4saX+*KPIeLFE=@F^@-Nnt}dIU@BY8;I^Lyl{$~D+7?zrEo{aNt4u+Pm
z(|h*w!OEvUxwn~xGDq#%wep8v?B5k$2bbEGNsC;a`jh*HnRvwHKksI5w)(eig<YC{
zX2-_EY)Ah+e)Z^t=HaC8A*Ck?jy-Hs+faGn`HshZ-OPLz3EA7<T-ds7+O-`<seE#^
zt2B@Gt?2sfCn1*H7XJ1^Ox~?+4GrhF^`0_%^x5*kWbGew3>MvZ-r%48tMse?Gndp=
zS3cjo{H$!}Ikm?5U8f@AZB2T!xsPvomT_T0Vql=Lk=E*V_t0N=?|%FDzs^EmK7GE~
z(g^eL4=2?>#c$j5|HA$LSMRR9wW`0|eEM<I>RX4r?%uUnv1$>=+C4e1K2*H-tUh*O
z*0!S9yS?%n&+ETVfBNxc{JH*C?d?1sysOuCeV@C<eb3Jo8xI9CKjm+EkAEbnQC8rF
z%>(1&XJ;g=OwxHzZGT#DetUkjXtB6?{*020Sl2yYpDHJv4|KAV4mkD0@xbz)8PT&}
zeYQU@T62rpF4I0gwEDpFUpHMJEL*JN@4jI9^1kzSxmi*ANsm6n@T#%ayz^k3zvcbe
z2LGsn!)A#gzA-k*L3>g@ZQy;*_Ne{;jzY(p*Y8}9hM&LMyR2_*FK9W>$<*GDM>g|b
z++??ZYscj{11r6{$4ee<mM7HCO(+J9PK(D?JbdO{_G-uK0{`PJ%534s-2L?Z*%$U%
zzP%0Ff%4M-(DS-&Ya(9ys`q)Y76%<r5C7o#d-eKy8}SR7=Ra?8bInS;I{A3I|NZ?D
z<(E1fkN!Jl9VUAI>%;3)_cxt)kKbA@v-kb7gL6}}XD63&t@-n$|Ma8ppRb8z_shhH
zmhXA~fbn+IE70uPnfJ@YvR<A)*sadnt3TIH^V{9M+cuoE|M%(2t{=;@pNZt|{`9fl
zZ@!2zpZr|=TZAgT18PjRk{@nH?NGNr(xIsNpm<ipc{TkdKI}|(sZDpTnOHuU%q;VK
zSy9MbX1m<Rd3_1~@84Rp*L*6jee(4w|Bo26Vy``)CanAa=$Wbh&d)P{9Mbg{Em<yS
zrM0i{+LK&EJN5PZ|2%33O(P`7WX&!+Ud`7fSQ<S|yZX<~Ulu=C^SdV(XM@&H?f7|@
z-A-M%Mw384;D%-6Jgy%(+INB{%Kh${&fERmf8EWU`VZdev9i?cO40m(^8CM&%<2Q_
z+f6F7ZFa8OnKAY1#Yx)#9sOrcf3X&A9o(s4!Dq|ZrypkxKdZ;EUF^e2=AskNx8&PO
zeYd|EcJlc`e;KjES=)KGi%j0yfBt{Mm5}tcvbSdiuU>tJDLZ}pADQM=Wp(qm_P&0+
zp!=W5PUh>s{cjon`+3B6SM8S1di6GW^(m<z|M1s;+OT5nx;JHOxCx{*0|VA7r3ahW
z7WhxI`@3Rc;gKu7ceB`*)t#@+W}H87^WBtZ=l`T+7S_D;)O;{`lCJ+cFWp_2*7r8f
zyE1FFcz-eL{68|ak{?bg#QTTV*p(MYi_V|_@9~z3i$@mD-f=eWlEC!8Re^u3wr-5t
zuxR6o1Y^QW;#M^j|FCm@w4%2C_?IisvJRb?wd2#h^vAD$Pd_qa;nl*QmBH3|ca!R0
zAJ%@9ULPgKzie8h|B^1N#cd(tS4;Zl80p-rd-Fq<>yOPOt?zq2zuM+-MLo_~vF~R7
z53$!}bAD`(KhyvIZ&_jCkN<WB9&e1jUTr)~a3|3%mQ%7HG*$0>-Zh=4S9$qWH*at6
zkkHcj8;7lL6*4l;m)(AQoptd6_3h8B-Y=2y$n4!|`CxKiarZizEuQjKUw33&oI3CE
z@Bh0uMf_X5{A(TSe4dKK@zajm|5>2>;M3E~>c^zxP12fQgJwx<-aP-@^~y}zFYlWo
zd(yg!&sX$Tf3n%V%ktj8!#4}hzqva5?$xp#?p$24)d&9--j$zr?C5s=o|>Bb?en)E
zy>UnEb+EbK4S{txlN_uHU&J{-dcE>!1fSg3D`l`{KA|g_E+&iH+OIkt;J9M>ysLW%
zB#;Z{Ot-my*lgXR`b;mct6A;JkrNA}-^*;?`*7au{C$>je_w@vKPz6}w;r?sKz~Q^
z0rl`#np&XM!9^FIrwYHS`r=u)c|oFcgT{Ju%ht$G#a~JfsJB=A`<ni_>;1gd&*xMe
z=y>#5w?0-dfA6QxN5y>i=6pMJapk9T7bK=fb=&UTVz_Vqs&{|Z+3xuKPWW2~|GuR2
zzJH2Nub#aBSHKf4%gX9|am|mni1+k0f0L2%4*H<Jo%Qt8>N5Y(>bMEd&aOSWi~GkD
zh9Ewrr*Dr=ZaWsKf6sPV@9OSW?b%A<Uw;O!`Zsy|#>4DK*WWKM;8}U|mwm(02XFsu
zOz|z2`8U&EJaPGSUs*Z(n%8x=Et?+_2q^;rmTh7mW`0emz4NDiE35M=UBTyb4Q!UZ
zoodBUx^b$|yUMqM&X1O|UlW~LU9=<p-=Cj_4_n2{3}**hgZd_$n^f=pfBE{h){i|u
zMU}e~&fb}NHgi7L_a*T=7y0|M*VNhWubcc;t#`$_)5k<tHu>v4{Cx4UdDuD4kJ_b{
zI_#->J65e#I-g3Pm2+!z^^SpNW)&B`oc?$1j=Fz=$&V+mpDXZFe&@N{=j9`&-O4$u
z>9_a&65Ge|es>mse!8jVUw??>i|CbCBkozTFFa+m)003o@xW5~LhOO({F|j8&$^#;
zi*dQuU-Mr-)%p5YR_924x_Pm{-%aGh%bE6GOm?=9cO6|5%~liCz3z+l_7_@FrArt1
zub0`r-gxQWrt_lPzs4R=55H*nH@aUeG;`UzIO)yzsz0!8|9M(Exz_6=&&riuciWd5
z1c^tloAdeK>-jqC{_N+M5&GS;O4Dxno*<dOOWBkEZ8~-%w;&WW4<E#_;<a4;{l9M?
z{rI8(O#FMP=!cgX-CIHPdq3~8yZL@idpYmh^IZn5v+{f%E|c-t^<Vk?>$1Jy9^T%1
z`fAU;va7<b+FP&N)`!Ft9eeV2*Zl+n)sKV)(_PjYyV|>-B4YQ~ad*7>a{pz%-_#l_
zC%fCi?@ms>TX2}y_36C6PFCdE+rP*AZ{M<*J6-F?lO@OIgs#l;;aaq1>fDp^m#%dm
zpL|>UM@-%AuB4a!UxQfZ%j~O63k?q3`g~F(cXICIUyGE^m5Tdm--;LI4}R3YTRvJe
zz5e;eq%WrVx9$6Gl}CL1IrECu>yGn(m;U(E_xRXxcfXsfZ%cl*_o;ky=?YW!=LY!d
zx@!39I_vZ6gSgk%`>fsb>05WXjDY?OgC(~&-Y$OF|M~hc>0s7{rM|C|Kh3zc<6|uQ
z6jPfmw&#-wE#-al3mh=je?LX+EIZxc|If|x$>(d+`#bg?4><~H_iZmd^zzm1d7lm`
z7XDF`-u<CudtCT;tL=|L{g1ruvE^cn^F{J3-#_VV@L%;{@+Cc4(VD)y>5t|Ay`8n=
z$iedS`8QJbYVH&bi`vieW6AShH@<w@{zA%hiPbB%+^COfKW|M_T65{+jh$<+u?I!3
zE}y^Q>$Wi6m9zZ$*w)5e7t(%xyY7GdDu$AiYtp+`TCvx>^If~$Z~vCHYs1!+O<sL3
zCwKNlCX??=!eVB#*Zli)<yOU4)qauf|Bm1H?>PKj^443E;%O#FtZ&^enYt-$yKw0)
z1M9Ot+w$$Cyn}vZoVoDo$4h%ZZ6~|AZ9hC9(?Pg9m1cr3^a?g7WERI%onDoZ<EPlD
zx6N_o;<IwQLyzuJz1v>xXO&a1$L8<5J*C^@o*UY|-_y`={+#qQlf%o`offT$dVE&%
z!Q|C9&P3k)C$987{!*bod(FF9;rGAIdHdSeQ?%w&{7vn=*ooiPe$2mIp1*tFWcz%t
z+*NuWZ&!KUEQ(&IKhJLE?Nhe?YcqQO@5>JSqt}`*SHErF?fR5YQFEE?uK&3|sp5YB
z?Wppn0cX0^%H+?S{Qhj?&v|E=?e<qB+-$qxCl~(e+dq+rU(bcN%SGI}7Q-DZy2yOV
zx73|yBl3QizGeM=d|~zU<ysfET`MEBPV?9L1J{_$KhMkU`|l}QwTt^_&fDnct88~x
zoqu-w+O^v?YaYvr3w*d)xclv{;^YJAA%ULh=T3pQG^}_KEGW9SYES;E2a~lqwzAeJ
zvDTc5KbU^(;o`>)A7`t5*V0y2>tEN){9Qsu*zMYuQjOP6M%(xNTAuwZ=TpBI->x37
zsX1<Z>$(I>LyvC#9V|M3PbuGzKQ^qz_io1dK6hVPdi~<twYzskEVKB!PX27?{J)tu
z#Te&j*Y7vESAF+R(iywOSwW_YzI;&4N#B#<^XIVPV=sxDUne|W>2>ktbUUejyI^@!
zO~uNemBEiwgWJn(Z$uI(S`;pLCPX*RmgW3eBL42=>AdW{e*MoL`+<f!S?+zi^J``H
zd|$?S8d^V|{7x$m`EYZdXIWX!KrGjj*<|^#L2z!^`<eaO($|mAykDpD&miCTRbhnS
z|KfA|K7NXe*q*+xH<G|y$b#*xUYvJw{7*bz%6{!=cK?k{MgGUXYf-q0&zd#H&#q#-
z-u}FGyC$!G|730PfpphZ4WIY;+Xl>;|L@Snk5eTlcb$*@TTxb8Ec5p$dvfgMU%E_o
zKW}l{e}4XG8~^-G;d?&s_!#ROxUJY%cWvRlr~U4HdZFQAN6gR7l39PNu_5H9+zA%~
z?T-uZ2g%yLla4dVTH3d~z%Os@)a`fdbhcl+H7~dJm+^;ltJ9C`|KDTtNhrSd@so<X
zpNl2V5FGsQ62CF;z}Y#jXFtxpy_@f+jOALhxbKq|-j1oLzIOXr3R{V`!h_4YzLokp
zJfKa!l}cM*yjrp1@;Ak&IYB3s!@s=jeOy~EJ*CKXZQ)N)xwkD=^Fi^|z2}d$*ITWx
zSoba}`RRvqlK($Pm^@GMxn;)x1GF?`&bPJh-Pxc;^!fWU@82l@-m5r2=Wp-sd7b+A
zewA$5a{glIf#<J&Pd~!Gu71;u=gI4DS^s-DqwwhSbM{3~=YC#aq4e(0?Nck(uIs6`
ztMGVZx8`*~(DUC`_2=%J*T4VsYk$qJB{K?tyf`<#Rt;%RAL|gJD&B>E#nf2%x06|S
znOt;?{Q4a~9xCmb+-&sTW9>#itAgz_rmXsKCi<Gd&erSZ@1sN>2OpiQKHW?tJ6G<*
zN%j9fXYDNfD?eTAdi%AIWA}X}#oFIkT8J&b7QKJ|b~U-$Wp;kHIU#|D>f3+6(t0p?
zv;Fd#w+|~S9_~t-XWTC#{9NADY+3JW?PouoXFX^CuB&;-w(`L3I4eE7kF)l6Z(REC
z#~)q)qpF*4X^HKv__V=7d+o-xZx7hMdURp$uJ?sI*8Ywqu%xN+`7+Qj;Nw1PJwA&E
z4QuOe-ds89{M5~1M{gawX7Oynu8ObSUcdjpaF?r8dAH~DIp1euA8xiR&H)WvEWY#0
zMf|VE_DQE0=U;SvItR3Vbc$?e$cCji{9Zg1i!EOw7CZO)?WxRml20zh>v#Fz-LQan
z`QLP6*97WrKd`If*pfv~{(QWkmUnY;$BVc2bA<VIB6dH#cW2e=#h?6-pR~DOzw~EO
z^oF4Amflj2X6XOldgY<?vAwT<eEhg@^7mT>Z<vurn6Z{8Czxil*JNd9Cm-vPG)(cx
zTsSvKwD{}1*XwrcNlD$}DlWOB{@}7=;Jv*K{*|`7=f0h69~BdF#`1sYO4o3%c{cO3
zf0U@?UHW&#v-Ix0=sxc4%NzWke_htMMo)_~w(j$$r2i+4%ja_0$=?5dEQI&PW^-H7
z&A}YYl4s9Y^<z%SgN_q#H$BtM?s@!gv#!kL&;!dK&)aXeR}ZwA@!zK_w<4}?u!}Rw
z%#fM6`sWfZ3(M}$_g+5}3vC2-@+ylqyzti4`0|;3+R;Bxds`!q|7m|~yCmc8*IUlF
zS232((NCSfT6FG*sqJ2pyG}|l&iA#D!QEg2cTOC3gOWo{)rSWMCu;xfkv7+R^{Py7
zen5P@e7Bgcme%(*(buo>E;ruS;Gf?6saEWR=KQB&>9-_4NX~6CTRWG@PBU?m_t__l
z^j#k;FYhZppuYb5-r3WaKaE}-!#IDf(whfI(}TU&TCVImXQ!OqwJpZl!gu@jy-&N;
zA6;t?KT?<c`cdC^nJaI1^l`6#75!+U>sLdat$$}3tWs;c8de&!i9l**WUAFFcse!w
z*sZP7)>pnfJN!h;@%fx$zkEH*glj^eRS|zrt`-+}oV9(A*7g@(qM+{6zB}J;>xO>t
z<o~dDb`b0QE&Esah}Qi2WL+BfdtvMAq?@;<EpqZ-ckS}sX}5F!-W8YYNe?q~&D&Ud
zQgZTc=~p&{64#BVtccl|=UXx_Kl<^w|NZ2x^Ivy!{rGZ8`kugt%2KW$OI&>Q#oxRv
z+pF|o^1SDZHlMn@X!Uf9?K{t0PqP({-|=*1(j7=YSMugl+xhzn9cw<nb3MA%|NmdR
z!gmvQms_6mB-rqgXDPb9M*jbg<9p+ds)xUyX_)MG<=VAx?91xD_b}P*{c_6g<6&3V
zrE_8qrib6!SN(X?7mKx;4~+A|tJch|o7TEg>AbdHoyN5F*`2RWby<AfFtPB5o%3VX
zm*sh$X6c^EHUG=IAMe|l-L<u7>ipIBcg2S+-AM2dk_+=$i@MkCe!tIJOfN=)mzUS}
zS7_0K^nTlK9m#!`YDFiGUo!@+C40Q<=$iRI5~I7<b#?J>t?pWIa$V7%815fW#6LW^
z{5t7bxm>qu_O^R`Z&fF^A2mNeOD4IU|JI|umX3tF2^<11vKblY$5k=Q|96a*UJ)0S
zw|n}}@0;gGi`G~%Tr*kMpZ!1IGv@#CRKxs8XTfihA)$i8?pKdZG2Hrb*_BDJTQZfc
z+HMP@t+T>X&Xid)GR}{EH??BHJdup7Ox>t5(bg$dMT*5l=sl&P@E};t<1+Tld*FZi
zd%FiuG+zI2w0}8uLV!?|(|cFfDT_>8yPA}Qb}4aaOq*}-DCnx$<rNyha#~)LWvMy0
zuWEw^(=X=<TB-s}Dgr`YRXhLJJl}NuUfTPj>1TAxcYZ&teRJ;3na^idp1=3*WzDBr
zaPa`Id>te~^KdI(5w{G_k%`HU)$tWED~=jQO-4>jqoFYx8dwSwaAu@=+PL=ebJOkg
zWy_XLsrp*=`RJl)vllJCqTMTZ(faMzZH)PR4<rfIehLl^4%@{AK4e}{wW+^zCTGbr
z1;2^?6W?|=_^*Gnf7zS;U){fY@6Nro-!VN^f=~tK(7@2RiIt`1lvv!2|34q6JrS+>
zR$IPNwCr6~PTnkw(z-ZF4gDvRd$)hgs=cfyEpF}CJcEar6Z8U<6&?gL2VHyApWof!
zA1t-|>jCrEKXm47TD^4Lc_E$s2Dx>+9#6E)JaQo}^V%HNoAXyZnS9Cm+MD@hHyl*w
zZ(6s!jzA|IR0;J834F+$@TIbT=EUAFX$PJkefgP7veI$dv!Ab-i-X?Z)6CsjH~-6n
z;Ln%O+>E@wH>m2n)!)lyuU9?^=Gfu~j&FG3i<OZ-v7y1g`N8?$pTF$cbnZqjo7*|{
zy#~tMKaR|a+Pg``Z_1sMa??tF#@{rFUGEn^VcYE`^-&Z4et-Y}oVW3Fw|dRD8!jH$
za`l$hPm>o$(nOTh0XrHR{2wm)YW*ir>_g{)vvs%Af=g2S&oa)>xovY}b4h={t+Bap
zO{U|mqP=yQPq=C?t&XgC@lWT8adKJkH2GIk%Wjq=RNa<Poc}BQSQO#7cepMFN=ILR
zKAgX)!GGF^oB6jLD=$3%*&19D`pI_c;fP63m&ebTKCdP(?pDs)y3D^<e=oiHdG@CX
z=WF}Vd2W7g^8Lp`-S#EEVXwm_k0}$AaLoll7PkI+IRD-W?eA~)$G&bjKXtoX>ijiJ
z{HGnxoVRiHrzMY1GjF<cZo$F5m(>>kUaEWT<@{&o{3}nS-}<uiWqkj+vsyowT-jaj
zRlPquBdR{+KHJ=liA2ODOP7Ga2TiAq%(Zi>vsr3pU1Ge=d+yZ_lcmp>r)$p1`FSe(
z-idGLnCv1CsbBlPYS!k}i%<XEd~-V+|EtMnQH$emWi>Zu{%cxhQtqhw#906C=L>60
zs`IWDPm{I!V0(J0p*Gjgk_VG+wqQ+1D5cE>RTh>SsS?R^XPayUZ)EcQSfca5SpWRj
zn99?uE1%9&w%?UBYx>igO*wx5EbO`epE>Phbu%aW=KN)U4CDGsKW}>aMv?dJWo_TN
zm#4&475Y_GKAMx$wT|&+?CW&K`8B_Fo^0MQ>HHP*XK9M_Z)RSbGv!y>@0yzS#LTM?
zYo$t_wGp$~AVP|fasJYauaE3|e&<h>*n7{H4c~dr{X3`iV~?Rd|DTx3V6hJ;|NTC6
zV<I=RT|Qg2(uK=H?^bgCKJsfS`xn32{Vyi7*X30uRQ>uMy!mq2Yu*#fUP#T558W3Z
zsyd(J=by(1BQwLoPA<=%_SUj!`oqjt#hZI#rHDyB)4}QW=}$+o4=0OkUN(GpJD|R_
zGe1SNW>eYG-t|xVkINWnt-p6UX5;g-r);l=*34qIKO0(iEp}bGl;sA?1;tPAu3vt9
z6PKNJo}I<o{ZaoV)bh7Zt%+ONQnSg+?(grfe(v=NKeyabP@LZyBS%E4iVbo&u-tL_
z)8FQMr?J=Y-Kq01Qw<M0m|hijP`!H3qhp#se?8`pT&wzEv%<0mr-H1eI{34cDs3^g
zU;W5fy*lyenyT|JR=u*e-(4Ct>&vS@TfT2|zI^KR_p|3$gq~QwYSMY__2+%d?G23A
zKQUeqzy8a9d8vuNzQ4Vyz<L;ayA?J0m4rDQSiU*Qdq?f+2LEgBaR=4CAI5w<K7G>%
zzhJAE!r3X83r)kHSAI6+{*`juZ9}@l{J6}D|5M^-+?*2n?&Z`r9iFFWPMg{Ny`}lH
zto^-}&DWFLR!{kmDf;Q8lT-2Y<tEm*>%7E1{rtT@ec8=O)%l9ezn1*}`QXD9{co2E
zhFxQxzCrS_o|5CT<x5UZR$m^uIc;i{9Wy(hkFtB8kM)}k&QdlzD#I2BvA<b3m-~mw
zi$n8klS4jada=JVFsYvtvGT#^_LCc}YM*~F3}u}EjLUB70{@UNCpTGEUQp*NZ)Mzj
zX@Sm!%jUCVU(cNWY+3x@)F`P7`^#@7eEpaCY|b*1<ZDeP)p^0+Y8+=x)z$APa@ec%
z<MNbW>9={M?^u65^{w{h)SOuxa%y$zGtY}ksU%7eEKL{aG~V2tzFd3#9wXNi%O~m{
zvi<#TcYfD_{;)j_4gMdOl~&vQ?qC0OY8BrpW;;#W?`~r2PF{=o_uI4b!?P{Q*G{ee
z;BsSm=mz!Zz8b%{lj_xm^TOlg=bSxOdS2Q1a&3RA{gl84_3GTjzU7xstIKaFy8Cz=
z5l8LWF+D!k>)mhv??-gef!FKz*WIdoKKK5ljnlt6vernIw4VQUc=gXSk?iS=^Jh%T
zekA>QbCXr%f#>D=Def1hoU_WBJFUULrBdm|=d>B>s~>DG*lG6S^Y7hpzK7esc`8qP
zJ)4d1)m%277jr{jzMNW>9$azuwAsA*r6RxM%I_Bc+)@30S5{T(tv@E&znZ?h@h;w!
zWq-5#ruK3fi%pI~L=;7*gm(OR)a^Zg+Um8*{jY52|2U$4tLo;jr2+yUBDwaQdozo@
zW|Pj@gVskyVl{nNgnZbUm?ZZsGWqw!%$@s+H#^zv{iJa24QuVCCzgLVDbAX%{d)SB
z!e4hICum52KhVEMkU#Uwg?&FQrr-HiHEXi()30Z1!{3~Fd4uo)v@e>N?0?@pFJ`%F
zhF$jWx7+;}yY)uB(%h1EcGgri-&s>Y!+N_eH^`P=3GD94KYEFq<A=`P#P%wS&)*|i
z=dYP{PSIL-I(zoK)gd2t{@a=Jf7zG0waZgftCb#1o_e?QlkLrz=#K{WUp?0^d-$@G
zHG7$)ueY85U0w5@^ZlO>>^=VExMAAPx}SxAo_%}y^KoG{-}?)dH#$)BK9=&~#V)3;
zjPn_p*_LcfKE90Or^wB;GczWx+w<v^N%glkVRyNHY<Z-S<9J}X!KrW7R*%asf8y0*
zoX;6~KwZdYdhGX{S9AA%y1RG&x%m9mPX4d%+V8c>xNNfeeb>#ry^A*Z$4y+mxc_;~
z9~ZeNmM<1(KV_VMG4g=A)s8RU%s<uj-CjMT;e5{;sSDouXU?8qdN00q(}PP|r@wpG
zRv+ig*ve$6d)xN$eGmUVCfc@NKfN)rkKTCBi}}(nZGNBI>ugQFJ`D3tn@PZjt5~v_
z?X2JJNWN8Yn0NIyjdw2}_uJ1q)+>E|l{4e~Fqu|ejvpd!H|yM&yB|>3`tim_r@p7b
zKlt1I)a!lzdp8Fh|NgCVSswdZCi}fr%UNsNQ*N8KC(lxnx{{yq>S}$(tGnepuc-gN
z9QOMYYyYtiFBjBaJ9oU7%WmVNNj48IPuchDp<wRYTPwes+nVUgR%RAQtXwPm`|Hc8
z*W@h?_Lkp$ddYD2nptgM`a33<<%_+seED7Ya`XA~E4nw{%xb<=Zf|6@H@RdFy9uF!
zX2S}H+yl=aH1qp8w@oRYU-|3H%a@nD^>a%FnC#YCa77Dz(Cpdtx6g0CqSg-`o*yaw
z!g28uA9g-_X;Toac`}&u%apA(7wlfAJzi>(wsYUlk1<8jVF%TtFP~`eH%su2PImcU
z^6rM|<=xk%Zf#npZnyK_{ou>b_2usuy~<u^ps;r9qXv`WcTHdJpWJ-uisa`{*B3RM
zf9k$w{<f2=erBLFbg)b?EC^d*_8_?I!Lo~wug=T&j}-fmd10#E+g~exddSz`-%!)F
zW>1s9&&ATSlPgo_K3lnMR?zw!uGK5H1Yi5)_<P;_{{7E3)ct&{x_$3F`RgC$HTN~0
z=d4~cZ(H>8QUTQ_E&udj|JdsPSH7(0y!?4%JO8W6dA~2IWiDMPX!WX6ciH1xpO5!1
zeR=asT6X%vdB)!)FKZnzF0Tu=`v1-I<r@3F6CSVGR`dVMa{at1)1+@Kf1YSb;P^d(
zjPL~)8)v)qUw?N}|FAyS50e*<+zzNWS<kPif8F3;ykNP|o6I}Or3cjeUT0T}%YXR!
z^I-P!yXLZS;TFei^tsp0DLno8=j-ZRJEghx528x9$6gDsdpaxqa_V<q&*sf5Pv!mj
z<CZyhD%%y?r|aYG761N{*MGh~w&207%=2eo-@bPDrWb+4@<NcQm+y{A)gHM*!Pj$^
zH2BL-F$$}Fzbjmft!CQ!UHM+;_u1*s*II3)8gBME$a(tpGs|Ciy}VvuX}kW(=db<i
z0#0P!|8ikV$&;o2&uh1ef9T{@db0Vvzr6o<+uJcGpHG~;&BK{}OYBs&ZT(qhe}A`K
zo3yo(dsfi>8PBscqh;Lp+j-yjmpQgA-Db+X*=Fi*cb)w7@{sej%+Dv}=2$4#8m#^z
z{Pu;c+tT&#_eIUVUDZe+e^)JYSj=qRE4My9?rM(Gie+oQUYVT#q_Y0|t?*9|?KXOg
zeK>hyer;`?*o%`|-%|eX73~i^sNVN@Ezb{@6aAaD?3UlX6La+WuJbt)?pdaJtUmqe
z%aofhpV!Zw^Y7P@*O`x27hjrF>6;l+_Qr7P)rGg$?75+3Civp#&AB)K`R|*jq+qOl
zyZ-dW=F8h&>rDT4x2Sc?u@C=VPO6SOr~P7$#ghD8FD{fu_r~unc)fW2ve*A@O>MvY
zIrHVp>CKlq4%S{)Tg`WB`Q@$yXD6}LJ^GRN=lqtM8N6=1UebM15w<C-pPx^EzW?h>
z{->|)Hvc^#61*UjU{;EPq`mOkb+#{eHuyKMD`Tlq@-BU$XSg;fxJr%5?q-qCMN!Au
zZ#<o+f7aZ!>G6-R^W#sq+b7OH7XE?rmwnp9Y5xD8z5Js!=kG?t%>Cu-X4v=dPqJE-
zf5$*ERdR;e?QgGjr|bQDva59Ur#*j;?J4<^Ki{w1{;%8Jzu_mFoWkXH*6n)rKhE>{
zzo$n<PJfr%e^cqU+lm*r&Ha4#|N8CSy(cVk<Ik+-%l(@*k117zgzf(MF#NLMbepN=
z_2+JwUOs*=@QkVU>x!?0ZUXBS&nN*E7^ZPsvU@ZhTwd@xK=wmtmu)5M{8q;K9KZII
z_ioePE>hT0?mOqMkV4nTYo`wB6w2h69#D6(iQix6RM!<~`@B|~@AUlplUgI~wi=uf
zIyk#_lfmg}i`$n>ym=+*{5~V~zgDYveeQ2PI9LD89xtnR%&WI0bp>2lXJ4aYYnB<d
zuWs{IwxzZA_Bq|MSiQqomHXe3EeU};)0eKvI)8g}U2@jOZA^B84qXaCTgum3s>uFW
zH}w*mGW#;|_}Q};tvdhoyYI>P=*pdSFV`Q>o5c40{ak(VpVxaVxi7JwuQsv$`RR>G
zmCJvVciyvgu7;$#%FW(Kp!vMuHHV2+!Q~epclDJd_q!Ze?s)J1&Sg8B&a2xS*zjMo
z`Fv~78$<0olmCi~)}G?~@#pK#$hF6!izDt!n8nTs{m?07r(W~s>?uocXCcR#%KEid
z?;ky9Uq83(zKNFD*1LT>U(GCex_{Pk{oT)3&t4ij{rob%)3+4&*BIUXcmMjO2|7B(
ze=kbw8I^{zRPgQiu>a+I|Gg92_+HGFv-_AE$g*;&>->x5TlQ{~m{_;r{S1=@`L7?G
z-TV0d2`3l-<tvS!J-vOE`-e+M#{K#K&FlYe$PM>Xf4|f1RjjGso`S>7!Iz)wNzczO
zextW~+5g)6T0cK4{i}L-b?3|ZkrFSzM9=eoy!qv+ZKswQSQpPX%-pM!u!PXQjK-)&
zH}*U!+qkzszfDPHoX-~f(v{inrbz6~dPCQ6yU=j4FPSGk9V)yQ7jf|UBm2FjjPqA4
z`n++z-8}z;Ti<yxU)qsumbp{vyzlJEVkw&Q4*vbUWNKSl;u0%et>-mAXQh7*|MzXG
z@8?ry8z(%SdZ{ekcFMfjR_eO;EBtr;-r>7hAYi_g?UFC2b8f8_uKynMFKTbY`MBry
z)85tRxkcqaZG8DmKj%u?)j5kd1zhfp+@Z<j`MoxGv)S?0)dHs4_WxF^U*2(i^Xs6i
zzrMen>i6q`)XNEL!=qFZLblFaPN0mqaF|s}c1Pxy3fr%rK$X*}`BkN#P5j!^L~E29
zjsAUIljS4klBs7c?7!*Sfu~!=!anSL;lKWwbNymR(Hf;1<CkA|R$iU=`PkkWNv~F}
z=qSD#DE;Je{8RSJ2lv0LdGxj9g8sY{+xI={_<DKUYo4?7{ZB1Bck9)b|4+`_?|!`E
z%htPL*_)5={5<<pZv0HU{E3>o?#-~Z&#gJd{BvLY-O{aJe$I8<dh@*eCe1x|lYO6x
zzAc}B*I;jL@4?)>-8;lzvDO^Qn7y@qnXS3}M82x)T`T=_B^MqoeN{?MmG_i!zRsPZ
z7we`r_=g=-_ud_%_2Z4ft~;93-__)mt^RneZ{>zfA3rzvm&M$_vHgeUE;pWcv)R67
z+s?nbMe_6IGdsDXI+CN-u1~ofRh#(y+w!fm=7)anOt_G3{CxTKG}Hf`D_5VBHrIT=
z+Uh~EzuDJo$Lp@yti4wGd;L_qPum1_A78CDGMnA>`dyCJx?5a!{C4)rwIB8z{}k)@
z_k&dC>5I;<-p*U!{c^M2?t)qC`g(4rx!>gG-*2!v_11>)O)n46n`xvTTl`=9<^IX(
zPj~0eWvxy6wfVzU0!2iF!&Yc*`75USQZXpmzs-*q6|I?dNquvJf5=A3|50HF)uW!o
zZ+g0k*{<9tgRed0ShV%(2a|bc>+Sn`_02}j+T#0DA7xD2b$5zyaA}HJY^Zyb&*{=<
z$FJpVE;|2t{W(wZJBF5jmAUWR{QR`WBt1^1@Nbyxhn<h+2VdG4Ztj1#^lrMD$9tK}
zWd`b1-MPv0Z#A5MFE`_s(5;pBS%0_2pJVcluZjQNxb#=`w!LPj&6gJc|CIFW-~9L!
z=2E+#a=rZhd)>`%d~pOutQzGsFT6P5yZHF)iQ=Z#nIMn;G-tL`{^Vu#IR3QOkCgwR
zT0g#=nq=M^6Q{oVfv{-HEM_}R?jIuY2i2W4r2C|<c<m^EKjm6fqQk9>sg9Yw5C6_i
z*T~-L`q{~+@~eG#Prm3Y$xHjor3{zkOWCdPmonSn|L<09r0D#NtBmudHzk~VE*5rq
zr_JnL*}GeV%T2%Ud2xUK{+gOy|LzBibN-0=xjy`oVYuz&_Xbri|JO(bmVJ=T_`SdQ
z=$Dso-OCbApUW2to^<p|O5o2I`SCYR%-_`Le?y+1!O|vbObvz9{oB{XZ9h79dc*lg
zEnHQ9Z-?)j!&(s(cTjy-&90z>%NP8!zTzw65W;gRD&#|FSzySAlTCK&eY*Ra{C$+S
z{$6%-O3K_E;pJyNchC9lQI-6y$>vP)opr01#+t|3^-4|i)egI=^g^g{I>?*sYUe!U
ze-(bd5|#eeSncip(BBW2?mbtpbNBz99#<y2?`grcZ#NgLTHnnVYrZ%CaAN4<{igo<
ze{Orfd~)A@I{&}bZ)V)P&)WBL?L-4D0t0<lgdz3)RqN;THuxP_?il{_Y{U7EoFmI@
z9ta1QJ{7Im^mMKpzs^^Wyz|Rmtdh&0>viDyv}c;Tb_E?+zN_e5Yx|nXWp`74?lKE3
zRbTbqWi{WAJyykax8B_5fAac!?QyP`?8&$1oqF}u{MpjC=V~<0&e@$XvB7`Ox4!pw
zGrkx9$y>ej{96mH`nV_Y{d+8o*Pjrsb$dGh>E>51Z?|T@pFb<ytSh%}$Ni|6i}U-x
zPbRpGY!<u>wgQb}ovMG`^^D7|{jHhJ`X`^ito}U9y|2qE@<RG@!>4RD$84=vU#)np
zbKji*PfW?{Ej53HzrVH;t?}Fa^XHexx7D8>|NUOr%wId@a?#anP}}C$SNphg@vHcL
z9O>#$om&3xq}GQoZ|`c~tvhop)5lCVV(+)L_C7xL`?HJwUDAqdT~OVBf6djj_f~K1
zUmm^wY+3JS&7*mL{<N+1zZSpOEWa*z)-=}cMMu9R{{4OJ{<^aJ^}aLa*%cjp{PWfO
z_q)@&GSA-14&1B0>W7Q;^tsn}X;1yVFY|rG9ztOd>kmn;*S{W-E_PwE>n-%lXRDc|
z{ljLe@5RuSD=z<0Iek-S&5O$&PfMr0pZ>IK)+JZ-bjJB>N|!dAU;2H|oWA{ePIWQ4
zzP+Lk=l=bFUpVt#6OV58R>t|&^JmWc_A|4%AZ_nd_GR4m`~0HPmzq1<CD#6voqTEL
z_I(qc>AzVVci{P^-^-S)kNKQqcg*}-gl%or?}<M@zuNyS?cuz`dUaahW=+Gsy_fGE
z&z%(}6=gpqWN*Ap|Ks~_qWPD+EEapBxa76{X2;pT?Y<m3v*o+Lod4!cS<V;#@87qr
zGK_K6HuuwnYU0VPS<L3_@-+ogMkyYeDwmi0`%jOn%3Qs#-|E$hu+w5)f&w2jj}>m*
zJ7-epht3D*5_k8X_-rlsp;9|K<U{8v$NjrhwSJf^o%}6+=Y+#MUoOmidBS`Cx!=E_
z9m;zz>*iNvhW$FQv;Wz{=^UGC%w|hvPw$=PpPd$3q2@DpZW7n}`F9L0drxV-v-y4M
z&7S|a8vNJ%c_ey%N%p&X)%seG|MxOqZ*5=Z8!kH~?$ok-U8gMj{bx=6b}PxHYmtrN
z-SE8){weikzb`I+c`-+8Z3cVJ)+DQ(+fy&IDYHNO`zQX|`TTctC$(2U`l@`-*l6yT
zg;yVEw%<NlzJHG2j)j&NwtVYiz7%e^A?sH1=7*JE7rszovfY2S$?f@{r$@h>`chdb
zy0Du+*8J^;e?_u#hua8+rZMtBkGJK|<8swHck6z?UHePyL*~)I8%+)ViBsN|mz;WP
zI5mW&ChUavb5K&7n(7|3l;QL_RsV~n(PpmUUn^oQ9|%vf|NZ*Om$&wQJ<E01=FgAQ
zTz05y+h?}Jmp<-ZJFPuGX=mI4^;KW~WZda~`Nn?l1TnFfoxahx-0ztw&9yE&yT{4D
zrR^1KP10iyLD|2zKfY}2G>-b#yK<M-)Os!L#ruml{Y#44aBf@voewd)Uc7s@a(mMK
z7s+2A{{1}R^5^yEPC6%Uv^!?|v3d3K!`rphCWzK%5%BzmHyl^kYS?%rCLHUNoz2EC
z7xTi??d!bN>vn0Kop(28#^Osm8~j}t-Ee1|pJaRc&D$rZH-B&wv#`wR&*@tC=Htl~
z4}>G9o@h$xe;-|(F#EUI$3yX(8vMUjyykm9yWLH1S7p|}icgG3S=_o-JP5YDFTFX-
z;r{NIKfipLVs6iKEG4w2>}Ezp*UL?6K659R{rPwJ=d-U&c2n!*&Mn)v>-S6ZOZD^S
zPmG(tS7C4US;frRE1qq>^<Yocc~Auy&YGqDK=`lAh8JseG)h1%{o>2_c<vm@j$UJD
zF@IO~`LnZEGalWgnrV3S`pfNmCdjSf5(@qPc^_~4QsJ_A+gyWHcfNaloiUHV;vR?Z
zLMwQG9J$CZWuoD#I)9?F`?5yn>F?%!UK6?b(vy>uKcBKSPB%N>7OboCAb4%yonprM
zk92OoeR;OwJXhp}Wh=EFOjfN~bmh#U1^%zD&Uni4!{x#AaC86DZTViVtTne>BMynj
zpIdfCYJTWN$+@9hIx}~6<+aEE3EB1aV)*4MZGNBawV98Pmi_;==I6_eCpTZZkaKIj
zsoNKSXZA0VZ|r36D%|7p_nkQv)T-+}-{f0cwR}rnS<LHoCI)MF)qH$@@8aW4vIMHg
z68=VSy`3s&XMB9dW7=!;YK2hA3B`7kq7!n)(;EDn^}e2*zIO_HCf|MKWiL)?{YVKe
z**i6N@6*j(b~hRSyjr%V$^To0m!oLSy;H@j<bF>SPhYmu_}O#Oszp)$(YniS-ul(k
zerd_|XUk?Jz25WpdRBJuYeJLp4%5XY%=2QZ{(L-sf70VS3C+Bh{H))8nbxy+4Zqfd
z%L}yc2z~gOAok&;kSVX;jmys}Di5ez&kN?$N$Xn2R;X7tL%w(Rlyf_t{;b(OUw%*7
zt=h{EOTYg-*DHM4|J|H9`@hZQ@AsR3BW>xf+mZM;Z!<En>}q!KnO*wzYPk8HF8`4C
zlGbH8QU(bQ<q5CKj)TSzyvr`-t3RJww5ZAdNWHcn>@0xrto?fmv&t-dBM+pfgj=my
zYBx=MbC-?0#rKIOxzGMw*<QYW%XP8CmqDWj+tcflyf%HjDH5^&-*NAk_tKX=Pj;O;
z|FqrKI5X8Sm-Pe(aWB-eCUvc|e!s_f?~g~_ncv>rTsqH#r7A2kb?TPC-)=AG_?hvP
zgX71P$Gbe%tN-0r*|jciZ&cRzCytZXZQ8SjwdN6%&6h)GN<Qe%^9WwH-Cp+A?(0&s
z>WUsjWj=lSOSkCm8Ujs7Py*X?m5IrYcNdfTzh#wDE7*9izf9a$dSO%O!R1T_wda~j
zp4u;8lKpP}EKvQ?Ui<6o%c;kDBqm&oD|Gl(VWxWhoHWnsoOctkv`;~XBTYYCc*??3
zv+Is(p+hRynYs6;_}`o=9;8*QP)i^qgG}ZEonyxlWKN(^gbX#G0?qI{ht4NT@u<nj
z(KH$wqoD!GM3}=0qiJI_ZH%T3%zS|<GMZCHbINE=!ORz!BBMEFG^dQ_6wG{qDKeT<
zMsvz&PQlC<m?EP&Wi+RZ<`m3)fhjU*a!SOjhV#qq|GqTp^CoW8Zr79p{`J2uZ+}w3
zQgctJteL<)a-bnZjuLZ5#`*8cj>_mG=MT(K0gE{F3kiI9894p+$x)+60|Z-fGMYlr
z#@9y!WQYgIQqDJfKA(GO`@YgYs`l&E;P?0TdP}<>2l?tkEsK~=!~`|JIWykvdcCgX
zcJB7Qs_c3XK2O^qJq294B2Dxl=a$BGY6UkE+n45UySZ$&?6k+AMO=+~Dh1!~mM@S0
z_h~w>y%OX6w#m{H2pA$TwHkDY&Yum>&d;B}D5@E<)<lab@akIs`F1}arB08%_QA`J
z$!@ClL%efQjdI!_dh=_Pd*y7cIKO|nvAsc9-J#(?604Ttd`@AtCBgo-r5kUH?`&-F
zpE&E660%>=tBnQGTrmX)SvB+SoSSRCJz8#mGw3j-#$y~`USHQ=|EcWDMR)VG1FefW
zewa+Tod60(oTinyHlFGYW}LsSqErTS6V0wZ2bP*ewZAUU&wJq*x^KCZRfbu_`ekc$
z&o1a~i<*_Z6@MKT8@-_Damaz?+41V`?hOo$+oK!~ET0?>A`;B-9`v%nmyvP4S>_(F
zOGBBM>_R1EE43b67F4~BBZeWNazT)haekl1P4Mn!mKv*{asnS-s?0cxcfvR$*x|r(
zUnzZ%$qrK+8vI4w+~;xqC~-MyhCj4i91bj3_SyzYOpJ{4{r0i5)L3z*72{nJdP_v$
zL+0dT;3JF!R23csw_cpMoXJi$a1$@Y3t%r}+AAw4@Zn|0q+C!f2nxXWARC)*&cT~t
z%~)A#ZY}x91Tr~<ljBE7V#$-04gT&^a`0}NcW`H6sj*s=A`SA1z=xMlszEl=Ey`Z_
zG0u<MTeVbB*=@<x@Hk6eX)_()nMSI<vrII7=iBX_oWA$T?EJl7uVw!K`#t|<!mBGQ
zU%uIV-p@GgOh)8$&c=0m4{GmRT|eP5uDdetf|B6xIBR#m28KpAE{-21LAzJ8*SPh`
z%=~sExqr(!tJh1WhDB+9eS5onqH#}yKTGYupXckB6+S+;wDR*a-A%rN+F>z;M@t@c
zsxNC~W`B0~>|AT}xs}gmzMPppPjgXqtw2Uc!}mhx8N8bU5)L#lX5O#;?)!S(?!0bK
z7Nzr6uh&dV^#?^H=+pqzs7|;kB=8|}+q&hO6&)HJBAJ-%=1zILigEsmE1RFst6uhY
z+iktC@9yqCoGuz#yKeWpT_x}LeqXk1*)qQO+jsCTuDY=CxZLb(@%4YF`RecaaH!<G
z?e{G@)lLgmb63chf7RZSBYS^_Ve%zGcbSQ9y;4_S9Z{N6dB*VgmZ)?byIrQqGBVCj
zeI8{c%*4VmMN{FyWzW0oBtG2CTt4^Gjg85#!(P99@zVD1m&-5b6rc0loObrr3%$2_
z+i&OXURwL@=JM3pv-5Uo##X=Gs(X5#zzaU6d&loS)GGa-+@o+)Z}*!?-|khv-!=a+
zlil6_Qr66%<c6_QV2irKgUj>!u7kpBfs(?5;E69DB!_eV09O(X%zP`VzdSzPe}4I+
zE-hQbquxHITRxrAUcN%eFz3bw*Kd^%8rd)Xd_I5wm8msu{c>~r?En3kCVkcQ>+Tbb
z(T)pT7~ek@DlEOLBryMIyKGs+t(3{WQP-~834T~9x)JN;$&IPr4hPb2?wWTFRK}!o
zf)dX*ZPuD=5y`z@zOJvg{rd9q@~1jUv)0aFdp#{W&-1+P_n6baUa8mq{^ol-e}C<*
z+V6KSe|UI!b-Y*opU3i-zg~~OpB0-f_K3Ii5U2W*(C}E(`)^yt<2;tnEsIK=+Gtg*
zvrTow5~h2{y|vQ!pX12c_w(7y3(ow$r**f-tiHR<Z|<z5TSvWwKdkhqz<Pz?flZnU
z4>sq-g{QkN&}n4l7Fz;33(oe-1!rC7J+EWmd)@zaZF|%-+elDpVO1HsJLtf3@AzLq
zw=x#@M$J9Abb8#ZcRL>Ug}uHNC1F!h5SN*LWksOwY!`<YpiKAw@B8}bYo*Ul*8P4v
z{oen7-=FVxxw_ze?fdG?Pft$HeR*gb%e^AT_m8*#5z@KLE)c&*{`ZaJK_LmN^FIER
zzASmK`u*OQM}+-zDm@P@Z#@J`WuRghwN%rY%*14O`bp~BP3m87Wv^d4qjBl3-0gSE
zR+hiNcXjo&&gYZWe6vdLTX%)5+5K+U=_5P$e!1lRa)L9Tr~dvwMW=txsrhs=bN$|L
zS&`pTZVH16G}E_QjPqCQ5uRFD_4U=&A~y4T70J8a?Rp(G&H9tdvNykOUEepYjYsm*
zrpl22JAb`e9X-wZvr6CUBA?Ca=g%!?dwu5LHq{HFEPMKQ9}0~y>sMU$)y1Ot>(%i5
z(x#86uj|)+?Edm(vj4Ksut?RpMW-}%*K_~a5>VlUnco{28dHN7oM|{Ooxf+|GT+(P
zGPnQuzj=Cm-A}*w>Fw+EKfJI1Z!KH*<KbGqFYoLBSHHTyzkYRTZ(PT3#X=cjb-y$J
zkL-PRH7r_p|ME}Yw(qw+`o?T-?(+F{Rl6Q_X-Ad)erCRZCMc6ld-_WK<K|B%l>48A
z7S5~t^>WL%TiMHf&2FmvH!gW`;gzrTmzsNfDu33_U$N=)hr|5OH-GApv$c9(K09|?
zrm44oyVaV_fnREm2)Zw^EPnQ6y<21dX}#S!6MqMkmc9M5N<6;C@Tg^IRL|B!T-qUG
zw`+S2DI`kQFS_7yr<=E1BW=^owAovCzn`>E;{S$!Gt=jtT%W%5Qeez^iTtys*K<yq
zlq~zt5$YQMG5ypO&7U9hcfDMe+01L^G4+9O`mg9ox!R9SthNXJoEJ4IIc`>MRjT-=
z%uK5claT1+QmWe?wQt?!dbHg`v22^GYG-Wu-L0wHm(Q!xI@&%L+&nwVbwr=XaBEWO
z?$_&fe~Q;jKRavc`o2|JS5-wGi=RsFx7}7Heja-RAwg1T#T|>e*5!E*(@RgPPG2Jb
z=K=fNcjj8nN9-f6PP1)XC-$N9x5ECPXY()R*Z;mPa<%o<))jhNK*gVOzl{-p`jy+u
z?(O2Q|8cl7V#TK@kuwsOMJcI<^*t}wowNV{=gaE&zgkzjg<J}|o%wA|YTp&le_b$j
z@r;cRuLS%18mFJjF%3&qJf!O`TN(l?H>~fZr{2GH-2Tr){<Uds6}NBSoA&Si|KIiA
zck@%{aKz0mJSO?_`~Ls6siFUVH1gLd=zCnsN<HgzV_x;Uoj<?!KL2_vEIN0p-S3;{
zmsz}96!oY1*N*LGiHBNt#kxhj`F;O?UHfXwz5jl_{`q(B{=aYYOMgq7WCV1*^4$Gq
zllR^0-7%UEE_<F`C-k9Hen##0yW5|>nEs5dK;_h`e7W=U?d@wncE|gq{t>!ZbYPx<
zg2MuKt`PQ`N7EaB$cKHuUth1y3EK561}euf^1+5P+#El2K2P7_JvSko>&Fq>cmB1n
zf?sy3&wDZ9;(<oy%jfI=ecrR`+@rFNSGvF7Z1z8$20A?;?(VWw*KaCXr{@$L;(Xa>
z{cc5E?DwDFZs*V6_xtYqWh-JXhplFbdi2lVJxb)!iofj-WpA!8o6T`Crsm^O-PQee
zzh1a@wQkvSqf`C=uj~6Sd8*HyGOzyMPuFizF$bPs4UhLdE?-}>>-oHDv76h=Tw7Ks
z35Yf>Uz%H}`*_x|t-0%umi8Ey-zhx)&Fu7Q2G<*g_x#^(wP@#9;99WS=y726ZT*+o
zp!)l@7UO)6`d(S<ZBJi3=H0bK^OjxhuO%AHVSn9z@BjaMzewhuzAcQ*Y)|AD1v+V;
z%5*)sPlH*E^Yrt1)q3*}8+w)L`gYeTcZdXcxvnZYDjI&KKmXH{lbT+MM=b&?S19ZD
zeV_ZjCjIoX;N^a2PdA2!xiFcW+H<u1PlurLr_Y@)iyt*>|Fik`<FTgKA>GVw`CYu`
zcMQx|f02KA)?n42&Q1BbOC_w0-fc)c{Ao(^l)mmyogW!RuN$xPR1uS}`Ebxoc!TWA
z{cCftMd$AgTY3HepXc^#k9A(E3#`pLGs7@*>C`Z<kE$}qMfMq9Pp_%G?tSc<wEjJI
z!?>kK+q0&;=@wfDIy}SfYT%yoL*|oKy{(-v{jXhL_J*I&W<P)butNTLwFQ&hN4Y-x
zz&<^>>06HeHhad?Yq;or1-}dT{U4H@+4p9C53SyJF<&L{{@-`y&z}k`{u38-yW;<`
z^Bytn7W4b!PQO^ct@WZ<bk4;6;g5_}fAxP}@u$b;_nXa{b!F4Hh`zmg@$m|lnnzVf
z^rH%Evt~E=ukA?1+S1Uu4XS3oeSMpiem#`Qu2A1()uStH4q>sSSO3U`-0AMB?)|uY
z*U{RQ92buKo$@UzgvILhn$1yWKcA@E&)oN+Rey`l@yQ%1E*(p^9j#rpLqGKPwmU_q
zZ4yFu@7pAkIOCR=`Nya`+q-AVXa#46ZtFj;bjTu6^80t~wfXn=d4~$Bb2YkzE-uJ>
zJ+HKyalXa*zu)iMAN{-Mme_UucOS3bbMHz1cd@^2O8oCzwN|@i-Y>22zbaRJXL+xV
zOYT3#Yey@O*`BY`b@DP?8vXX~o)h6mY=4BuRi;k7`^fg|%=0yA6TiBy75MOSNlG~9
zkDNUpkG-t_|Ghq1_U|OWi&s}o_S11uPzoyfcsROJdF$5dJ8$-XI;AZ>J7@LX`V$ir
ze@a-t-}5=?c*UEI$1hzCkKcR4Q0b4r%Tr$6mY?c=9F~994XW^ir(|X4`(2#jukW?R
z^}=#v-5#YGqG^ITnd@B>KxYEHEy!4TDZEC(?UFH*&(+4Yr(RDz{^LN8rOx`@?{<mE
z`?zlXk#wi*c5d{pZvC@6z6mb-aiQIA%DwOVzHgnK)vJGMhWMs$-Mf|^UZs9JcYACc
z-}+6jZe_3c4Sc7!Z1(RH?sk(Nc`w-I>a-<JVac2Cg<s^K%N`evm&@JyW6{so@&9Ml
zecydw_mk?yYjzv$)_uMfoj=#^*Tw#4jJv;W>;0bhr{~Y-`TukBH~-nXt>&=lrE?R5
z^78er{rK52f3n18V_hbLz_~h1wQsksFey8&yM2j<^^KWX$*GlF%hz08e^h^|pwI5l
z=d4$UZ?DpOaJlO+6R69D(UO@~+33br^Jw1LhwbwFA}-I+Q-3F#aeAIZIOmTewnv!x
zEEb3s+$sNeZTr5fujH<ThR06b_kHjCt+({vO$N0U^S7=md-!?&|C&1cEt~$O+y9PS
ztt9aMUiEt=$DSSGf3~i#)zw!r$h@?q<k!pP%WvoJ-+RgR-;c@j|ETC^T*yk@Cg3Wj
zbR|eOrn9;taEbCeURTCWiO+8~pU*Qb4Y`y5`||vMQy%TB2+t_Y*LN~1ti6@}mbFGn
zyx>;m@~yXQm;JT=aDch^Hpj6edpF%!X7xp+mFLmFq}<(KuSH)L4Ud_~p7m(nXLY-e
zov!a#kK4J+6uPWl5PYNV_wD<B)^E22-%IV06rH^4c+GL^dlSXGPMELw`MQZ)FXG8o
z3FUj$&h31@6a6jT?RfktNo8v6W2<9-PirIuxUGI-BsDjBWsU#TLch0PZ)*Q;%*x7d
zKDzf>#)@ry>Opns^D5I;Pgh<cv~t^0o1<a1+qMdrFG!YJ&vCkB%hAHvx}Q&9Zo8fL
z`hwo<+-;HnoF!hK>DwmpSik<K_dn))*X+JB**z@#aFG4^!q#oyR>#RdcG>Y@R`$A;
zad)46UJ>@${{LtDZr@2^<pRkr50vc~tb+_S>MnNiPx<B~e)aG1&nq&D?^Qm38gH?6
zz3$1Py$${$C7nSjfe%+M*1f0vF^;o&Thv|#uaG01{9mfp#vNGx=6m6u>yMmmS8<eX
zIl8qk-oQ$zsOv+3ii7#hl*xT%^Yg`DUj0$jGr=c%?Y#G~<#(r^Z`^s#>h+eb(W}2s
zbm`MFmE{yU+V`<_&-J+Kt<rwkrViT#uFhAo{c}RO|H{5CCyHjqb@OZ!(FQHtE;*&S
ze9ISs%ty(6mdjFaVsBXsL~LWxGWWCo%pYZ~CGcPV7k}M{=4odiKl^aE{QlidcP^@5
zUgn!^8timu&$>GY`s$DTd9k?v*=A0cr;}$CD*SWI7u5Z?u<Fbs!ObE^Y8PKz?Ebt~
ze_fUL*BcL|rn)4lb^bX1AbaiBu)3bYHE*}>I39ZUQC<Ar-vxnpm6y$0wPlBVU@gDt
zyW_3#OGEd|C3dyT*IE2$|5=z<xPSe&qkAV<{I{4Vp`Mo5@wvY`|7+j!vj4Z9s&f8t
zQBYdvEOG4b{2j+WE;m~2@>W7Navg7@%MYD*f^G$iwp|Uo)p@{;CG}QT;eOq1D_Ja+
zN(8@8Sk29Hr1t;sce~dw?VfS>>Gb`7Qti53Q&Z<;vpiBd5twNh?b%Y3bvu0jud6mI
zf+OW`yH4!9l`S&0>`~3C_sz#@7utTmvw2hYa=FJbkLB;}|8R)=XO3dviKMMp!%p9S
ze)av~zOty_|2ml13ilho>ptG2Gxb{70rk3jizJ*`mT2knD4T@b*4y*p(4Hp0ufJ9_
zi2P63cS(t7%W=8tC6%9_g@!FPK4+o4_y6Db`H_9<ft{K$tD{?vKKhqj+TA2**cx8i
zJu^Y+MeyB6|6<-qf1j_ddrrG+UC8zsscMJ3uNt2e37opJs^`^nCcCRrvK9A0)z=F3
z`87qW&CA!UW^sCSc-a~;`+&mDJMXcV)ifLtu`+ZG+I#)+45b}{@(bQ>{c)j_|6tYB
zyhrVt`&btLKc&yNwbr#lQR~W;?5|9A9~Z{hvM0Y0e=Zb%Vq<O1!YkPy7s?!5^)0IA
zVBOEt@p+dQ2R&3-_5RB0UBaH{egtH$&)s@8?B|~;U;B*hN|Jgwc&~i!(ckvt=(@$h
zbGDYtY-ODPBdM2v->m}wnhnR>3;#R{c|Rk$2Q<2(G531dYTgAdPiOyFl=s>;Q2K-B
z?^>DtbB<2GE0w+G;wzCy(>HJmt3BE8a7<sLFgEGbrdML|41uYu;$H4QRd%s{$>i6q
zxk@{P;~#zGc9yta9e-4x|7+dP6<^|CON&l=BtDztUg-9U`lI4mEi+#A3eR`F|L2*x
zc=Xha{eQnjKk43K<hLjOkgi?$tG(@yzj_3;XGgEiS-<UA?4++ucHWE9<gvCJO5z*e
z34B;Nw`zqEukRi0?rM&$!8eZB&fd`}_kI7gB}e~mU$N(6nCQe6TZF!QUW==KYqq=p
zx9;;f#eQ~+UH8_1k#U^4LtgTD)a^(2+(Y75=6!Wy`1q^8{?Fqt-SK}GrC#2VAHH+h
zMx%F$M{DnTb!X0dBwy{$*aUL9uCeG5+xZ-OLvH=}`1o^mi~0SU&q~33N6iwYzlSTu
zT$tI!xs|c+h4#DE*VqD+YVWXjX=w-kSWtFrafL0D=f`^ylN`b;+*+r2b^kt`7`on-
zb^eMc!I^JEV>@#n$**<)*y`1NGilZG*Io4)^)D8-hsB+fe_R*lb3EjB-j0WDVgC)R
z<NE6#?0dOv_O_g;^;PHB*Z+NO_J3j>OVO(L&yW9o0ct8N-QQ=^`TMD%vd@`&f%(U#
z?O>N)xbR0L@9n;AufDtQ30JNW`Cb1ic)k~?kKk=?SnZjcy0l{BwnsrMeM%w0@BfP0
zPv83emU2V*T;q-`i>(W1X-EY8H5Pq*>`Qk2@7wnuW!`%vSNkUV{lC;5NA_Ovsy<(R
z@3PTj|J2wgypPhi?24`b`?dSd@80X#_VTx_pTGJy?a9stfAy=of)1$LJyCWD_`R%0
z{(=3!kNrRSBTA*VOkRHL*|Xzv)o+w8KR?o*@+ZMfVc{gR9{D{pw6vD>tlD#N(PfTv
zN7z&L^3STU-Pf@1V{iTvkAq=RH3$CwJYRp#S^nyNg(KTQjox{;R{wj{b-{~8WmUa_
zcI{QR8l?;&`xL|QI2P8VTdRIN=yGtJ<GrR|`rXIIeMiNjLw22%SFV(h&-z-Yxgtj*
zaRsmWoei62*t>aI>|3Ce8}0eGHE>FL_sh;KXT^_C<D&nqy_Bfp=WqM<O4w!lqm@V4
zeL}KUS{(na;-l=l^KqYbSlM}b<wyzn15>lFzdGutbA_!&sW4`xo^b8)>Gez0lesqi
zII3~Z@{sPtgkJq?x5O6qZfkPi$~dLsedwfX{B}PQ;vVTS$$zZtzHt6Xr*L$gV^`s+
zI{D-J!G^t|OONVLoH(if^ZL@h*K)VRmj@nxVSWFn-`)6Wi_ZUew95BWTj-SK-JjPj
ziBP^FbU9YG<bq@OA0gTO1!3yB+Q+5(x9*#)?tf1B;m4>Yx0C01WQNztCC~YxYUQOF
zHs3u*K7N^aY)PQa+S^JNB8od+iS1W8Ha+i;&athl|6G!AT;%cO*p~FGny)SPeOUD`
zb;YjzoA$0c9(C(ElbyGAMm_dSs^91(q4Ms%$lb104}z<it(}+)^*8L*(kkTFVA8(&
zzrN1>oPORa_l8A9`3u(8K9Y+I`Lsg(LTCL8neWQ4?`p4koB#c8`T4^hfh(6>I>q<H
zrC`xF`5)ozHH$19&)f-&6<t!4v$em_U%koa;l+tzvJY0|#Ops0Ha2NVELEL$>f6=+
z!u}W9@jtzOy>PdW+FP~peDba(9GRg}EJ2GrT=v$ViI>*v{2geR7Oi_vJg{WZrAPOQ
zzkYO`*!b#z|Ba(2kyj5+I<>D*KWBPuS!Sud#j$ns;@)gJt(R^3+wYEa-|yY2TX*c2
zwQqjBS>VQ_s5!xN^6%8Y^638Vo}vWm?mzpkuYFW1YrSJM<NO`Z!)+J)-&x%Adz1Gq
ztEhwOcI;Z;?<TLAv3L1eNuxzSTx-n2q9j7)i`Vog_ce)3y>`!Z@8dq}Pb+U|-9DDQ
z=l>(Qf{SY>?anC4Tl&d1^vh43b^BA(y4IcQ+!p>-X<O$5w<Y%;9jkBgTy^?z=&u)N
zl9w1fZr^!H$wqMLsYl+M){2?`Ud$6(x^mBt1MB`RTzT*N-S>6n^BC5w={EdlU;Uji
zKQi)u_wTuf&K$VVrWM2@D6-*5TZEuX;ChM035Qo7Jk<MEYVWZHlkQZTK9lkd5t>r}
zM5<RcaO0z`NrxvTbV^-Wk+Ed)rP~*l{k>j(cFkd{>~D7I?~BjLoJ+G`KR@y9-thWs
zw~n6wZM)w*-s^9ZT%_L0gFVx)-?>n!+qhVzZTDK~51G%NbK8mf1~smT_cooSZvXS-
z<h1APZcKiAqb@C$bXs{=XxB-rzjaHVIvYLy_Vo0Q%%6f26#|`j?q1u={z-NA=NHp>
zbJkCPJ%j&Y%|kO?)eA*An=|h=_-|gzvaV>p%AHH=RaxhL&Wk_1WYg{Vb#F^|Gfqjn
z7m~OlZRXD%{lb1({AZ`i@9=#5EqkZF@v`*a?%qz}d-u)Qe0R!}?D+jtR(mTfyWfBJ
zkB05T7Gbs4D@Etit@mDg`FwUt-XW{Mbpg+QJ)M^y{>yWL=E+-e-}9T&JwGgelX5v|
zsrJdQQ$D}BF4T0oe|eef{5r=)KR>)GpJQAZdmvpc>zX3AX{Q4(xJ+c1|NYgMR-6{C
z^<eTv=}Ye~uI^u0yXWPb`fHo#U9HPJb(}MD$tu6?stptWwY~di6y@}*?bcO)p%W)g
z$o_18n&*Ar>zCYa-TIEdr^5FYJ$kAu`N8w)f-g7Aen-t}@c%c%vX%Xovh9-ps-nr4
z-p{hXcTV1Yd-STSCEAy^Jl`(QFZ7`^u}wMa-v#T}&!v{^^7@q)v~k&A_v<sKPw+mM
zcwt)h%zX#T>I0mlR^GYNvbN}KaqazY+qV1Wm`zOx+M2d%m5JrIKZdoJgJc%p4Zq7<
zk+NgspTg?>)BfF<Q+#>Xckf?}w;Sip2|whmd1S)BS1b;f^rtt8{yh9$#N&k7ZC0IG
zx%@_FCxq|pdpoUK<$Kt#j@?JuE}7q2XLL1g{cnr!*Up;X-xFz(dZEFe$@Z<{SwG9C
zQzmsqpVU?PF#X@7JGXbraUNLmDD>BZ-LAg3j!#t*+G)r6JLTq`*KZ#r{1OWmS#r0E
z_wm&;@4s43{^L}9KXoTd%dPLvjOTsq+4aL~bMH43*YI7=ZL0S#=&@alt267Ly|09E
zKBMS!>8xFcPxa28ZE^CFnyvX&tCtDqduRCl+Ou(%mVEHq%V$o13x2ig??dww1<{fF
zqjNRnZ~QEHC+hUF&BbV5yw`c(>+^mbQNI>%a<+)mY^hGd_ODz&o;d40eOlG3dF%D_
z)0%8Q3v!|+Rqt(^bZV=o#`4%sjmH+CA>*^FYL`cv+gIF5WeuLF9&h({T9>Kiyl2ch
z>o{ANI9(`t`(knbJQJPBwvS#M$up`K?e2fKHT&7~X6vgp%d+<}1^!)i<_p(?n&;N{
zXMQ`KY4`3ikLuLlD>Hvi@-nK}HSI&hz4N}_oVz!lvsztgWe6GzjSkXUmwB0Y`&FIk
z@|>Jswp>20d3U<J=-q3l&F!6v`nS|?D7}9A^B()6_uK6!3*GR%wEOm_qtoOaeP_Sg
zyfAXv%x_#-s-3s@wm(0-+H%>>8C*Zkv@XiU=#+B^C^#gPuskz<FnQm)KNtU$=rVSe
zwO4O%^1pUoUU&Z^(e*3bzj!Dp)OXC8;A|Z;!JcE@s#Ep9Erj-X8Z7^N{Krq_dtWS5
zOgciIdra;9vUO?v>P*Rx3a3qUYfauRT=(f$r~15zOOEsHCjDuwJh$BTPk79w`_mV=
z-<rnr<BIi)f0K*7C#e5j@iMqG@tpl%P0M@BR4+`jTU^$mS^wt#yW&54@BiLA$^M!A
z5?-MXC*?P7XVxz~neBT&^;b{O-Q}??iuGsyuPfi1J;8ZKgj(&<o$a?;<t|O1eZl?L
z)=T$q@AKnKSfX#zII&Lm?~=D!wtEj*ORB0bK5nwsdQH^lD&w<XGrkuuUF2^w>)P6H
zlQu-SP501HbG4}28gu^3?$rB-x6DYr?R$Ff<co1ezg!Q=a~@PVbNTIlzxwLk_jg6s
zU&u6nFgY;!*58F^%Y-gvg<tZFPjNf!+1QY`Vr`^4+s2IhkI(LLT*eu%YH&5LvVKWW
z*!pX={i!o+(zY;Xeavw?b@Go){VKJuSugLO`8z-JvY*w<B}I1%kDK~G&(V5dtn$=}
z`-e&U{6b#gbu+Y9-q5-2bJ=tLN7nt{_rCX)(qBLG{#>=M)0RYC{**X{f8Dp~CC2No
zn|SVOVVhNU&hq({(AZhe&zj`#<C%GN%M#n$@=Rx6-_5*N@YW^&+DpFQlS`{uYd$@l
zyvnM1%aZrE<OM({sJ`NIzFYeF;Jv!b&v@s`bMIX>qvZP8&%f_Hw|knZUw!k)nwI`g
ztylAY3S`#5P~SV_$SVb1`;a1=w+F)N61E;!lS#3Dn_9$g_hlh}?*0(=lebph@-(it
zIoW^eo5ftu>uNmLa`!T6{9N#6>ao1_*7DyA%TKI~yS}d0=j`J>^|u-4^E6)7WuKn<
ziS_!Q73cc*#vK19?z4Gs+~vc3)@#;1xqRmI^cpSp(rEqre<VCQvL;Mh75mfh=9W0d
ztt^*69lgIU>dO1#g*W}mZ|#i_+GadI+jqA9`n39DL(va2xm|B#Oss-3!hshYXVMR(
z2Tc7UzwQ47^IAbk-vxI+9pB4e^MLub{?sp5xBRcLRGd~eA?ebgx$2x7OMV}+`_RaL
z<*MJU?z(5j^H=_7*jK4rFED?i?Ioc)4~vy|FWy_bZPL?A{WI+M<b|)WeAJ<=<~Hrd
zCC2$Y-zQJ-``y2(I3|<Rb8EZZY55c7?Vr68l$482{%(2s-TOeo1hd!!>Wr&dJfseP
zd9I>!iO)X8e($P3Pi_?F9p3UK^7$`SnJavGrQ0Veo)&7z`kq@h{p9C&1(83UKeTk*
z(iJVcb(C{g<J@nXD(Bd}2&v7CTBW)5_q5%i*+x}Im)m_^X|>?Wn#<X<{_We-|BE%S
zYVG8UF}JQ(KbmOYmA^e^wn+5}4Q*fV#GW$7#%Et0mp8N21kHT);V}RFEhjJgS+D&U
zGh>~8@$$K4tD1A(&N;Az*Z1R-==;B}rCr}4eIs-IJ#B$2-#i6YM%SkAI^bu-vhvC0
zEh)-Dk=g5JH=Liah}-nR<jW`6%TGOg>TD<b`mNvRmwv`Ck1u(??AHY!E#2FBw>BhB
zsF|_-_|Dxw9(BJqN$g$F@C0@iz~;R-{U+b=vD{kb?XWER+=lQ2%cZ$8@)!TMkiYTP
zJb8bE%k|awKRDifYkvOoVog=<*{^JVHl3TEwA;$F$yhslT~64_cB@^VPHC&p^Z%|8
zf6mj?TsPk5u1m3T{)Ei+4gPI6vedJe-}c+C<vp$b=jnL6m)sibOPMu(E}E6K=Iolu
z*Y@f~Ke9Vlz20_9#Jb2ykDJ?eo5^Lq|NrcGYPHY#L}tUC^FOgpJ>R|Tsk`rXE&uE0
z-{ar?{>I;!_BZbGp981(+n0T{I;S@Cj?QHHE>8We-hO7EfB6cxWdDEh^J9O#O{T_<
zpPycp*AQxp^ducnuYWT~!F9XpoymP4%DkWdR&W+9)qbyHGv$Nx_NDfU54+0dyE@st
z)IM`UdgZc9TfS^popD85WYWJ$Wu*)MTr4=`oEdHP;Ij6PD>B9FA2wfN|Gs6pZSIOB
z{<Gh9U4F@Amp;Gt+Y-CGE8EJw?%x581a-#ldFh+K%6;C<io^!?`Tzesf6c@u*|>~T
z=WCSib@f{RjVCVT{Ehmx`PS6dPye#SeNI%pRL<=;nH&)DYsIgvUp|8tg$QrHeEe$N
zyoP|?9FFgfwzynMpK(Z#U9KYG@9|%j>wavzeXsg`tWlO<TmS6SWp6ef_gf`5WkQ@&
zu5m6X4R)@KWl;W|rDL=wdd~M-+3RoFiS9Q#6Tdt4%Az~YhqvuHUR?L~n(VZ-w)%?O
z$}YB^Ijx~_He1qf?cMf!bMM~^`)sl8?ZVH?b}ygxwQVlf4<5~J6PWGZ27BJpPrkPF
zP3)y9D?5ztwmY4=_q2OQJnQtl$Tj~%d3mSKuD&o$!E5&<Zzk5eTb?Yq{c3B>smrP>
zF6ZrSQrydA=NZT+)pL@+Vb8(Y)8qwLhF!}2DR5HU_p*>(R{!Ped+aV}Uf&#lbkWLf
z^AlWt&pS6`uB1@*GTrzUZ@KIYd*5!*wO?`Td-k5&@*Owh%o`@@H<ZoVdEf5&YdgO~
zHlCN4srvrD_kCaaCGkw-{27^tY&qAO=ytyR6Ct~-^!?fWe@^dTb9`@3{^HlS^-o-j
zTmE;4^_Q^qUg39t>x*{Z`*m&mHgn_G$3H(cea)Pk>u_Ls>qAAXgYm~45=5Bo{%Xzp
z!quO$r73P|)~@N_RP`%QE}6(u6&m+)-R0VO2mF4`oOO-wt;u@R%W;VdSPU*b-=WHE
z_mbKB#mZR4m6pqVE~`&gTo%N;^!BCav;W=y!&vgGD9va|;QH(@>;L~+|Ftr`o>PAB
zW7+pJZhXz#{WeVK#jC4EkG!olCf6PR_91ESwahs0iETW(SJ(1P-FJs2DQrzd;P=(3
zOM1$>9e>5%R&Fx+eEI&|x-CAJh4fDTy)F`xF|GRF=lS+4x%{qW{{L9FImY-c-@&WA
zwyH-auQGVM?YLa^mD=W&23Pa$ayieOz98f`|DW5Z{l8kYX|9_1dcwXdU&Nosznja_
zdCNKJtos3V(VU=@%WfMT@^WK4RlPd1vOjgk_MU*td7Rd&&kcM|bEy3Mld;|6`|kY9
z>*qL0zn#Vv<SV+Sh5hrtEcSEDcDvnOcv7h2m0WOjy>YG11LGwz);xw!R+Yba^t0)N
z_>F_?@-fq2oQh~ZD`5YY+1qk^$+z@~C1s~Kah^9Z_qkWF^W<&w((0de{g0>fKVJ5<
z_kv#S^*wf1P2#IOf2LW#&73srt>TeQy^c(Fmd~f}`?8dIzIR>27H5vVOm?yBWlkF?
zF4D1&ea+`N?W2nQ&y)Us+ixxT`LoGq(auay?Xt_gpti@|27e~syQ{pKbCydxcy=C=
z|M#JNa@bq8fS{dEuLS$g-Qx4z^ZTxxlfQRJ$DQ2x<nJT_?_;GszI)nh`Bh8jXa)J6
z{;~Wp%iB$HmzKZPKi1>;^Y8om{Wnu=-~QsO)}7pv*YA8&`@!cHb(@89(c5kouGg|Z
zyJx1~^V8YOj$hBVWt<<U6^C^d+JU*@33kkOFJF7_NZECb*Ja83WwJ*q9tqEnxcB3j
zdET~}JyMer{C4w7eRvrbTKRQ#{N70Qn(Ezq<(~H+v;X_j-~Y@j(><Za#<k*a>o)C~
zS2z93;=Gd${#~3)cAW^(UD!Tj`)ZM|QFh8JQd}l~dChZc8TSvB662it$(!HTeRnn9
zZ|nO%<QKzj-P&!EcB@}bKDX!2deCsOY)s~~vn$Lvl}eq1G*c%2d$>%s<l<_F1Fz%0
z@A`C9ziwmX8o8s(ta)x7IrGYKdzJ6@OK0T&f0Un|U-x<T+t62k)Bf*`GEbONZGY61
zE%#;o`4={v8^3TheZA%PZn<vkLG|Chf(>OGG#1Vad7UZlmeHsGd}7_{Z=Y69yRvrP
zWu5!^RS#RmuN~gL_4)IARUew=@6=^JDs0>STI|CK+x_S5e*5Tr-f`SE@6ro*Nu_nW
z{WceTV&i1r`n$IHyxI!$>uW3X&y?pa{W)*e>(4Xus=KwW@Ltw6x%%g4+pJd+X~z0b
z4}3aU{A8kg-nWC(r^K)7f8v&NYgOoKuTziCmU;)MHMZC3D$aA}x80(5b!tOU&<f8e
zzFTaZKU5CR6gaRTcS3{zcCP>@ho4TTO4i*<Y?lr5vv}CD^H$8>xql)~_BYJj=evt>
ze$B+%56$v2za)}N@BhA6p0pP<jyrp)`EJH3j!br+Yvt7ornzM8pQe9@Cw|(L3?`qq
zmumlB^NidTTXu8l{Wp?(=gIH7D?iEjWA1yK_!&PJWk;=V2>4!i^1oq*SG?Klvt?HC
zahq+=efz~^m&@Cab=6A2bMXu-zu?~Fb<w{vZ`JqAJ@@d>!M7W7?U?L9iz?K6Ehb!W
zIV5*@i-?iO{-Dd3?oSaEtJ*sM&lB~hmFKJPEr|r(Yw+rnL3zmmb@r)U2B39lw!gfB
zC#GFGxNY8&LuWS6|NG{e_Fs8F@eiH_uY>3Rx^jfA==>J<doyNSeC)`i%bDSGUFeNR
zeCh8!%cL%8B+h9mx~2Q~CTHT7=wI`Mt1_dw44&+JwM}GO#r@y+%s&>bVtjh*d-mOG
z<Jy?F3W4SOHLXBPqZjAzFXPJG^W66R%p0*x-kfiEF6Hg}`Rv!ew_!Y4>u-lF%=+$o
zKK#IQ$@3M*mi+tQ%x9Hx>ffWh8=4Duhwu9|_3h=A^3P*FN#1-Ncc%6V@6M;26`Xf{
z&5HkVNL;PgY4Yo-1rfUs1=vY{lDxQuXX5p}?6WH+uP)oYUSwHDf6Zkb>)R_E&QEA6
zpVr`Cd`t4O{^1nW50~@qc4__$c=^>WYrXO0<DO1+@2l_M&bfMLhGy$D{%<_4rkBgy
zS!+HyPL-GS-Ti9S>R<aF&Q5KctCo1PhuPxIu3+8&v##%1CdXW~D)rad*KB5=p3W~c
zZqL1&IQ0|jjlV&&JsDE>y?;EXyh-n;qiL*x?!r}5&U+`BJipC%!?ezOn$F7ABBhs4
zoc%M?ubOpZ+N0a|{wpxfzmx5G&|KGkNf1-fx?43>XRjKjTQk`eugr`_U0DiUa})7{
ziOEiSec*O3ueJ-GqVp4@eoejy8Z%jA6uNcJ`kJTOs<ooN-us=beg^Md5q@B~ZHxbA
zzh#oQUe5pjbG~}qDGm0srf0i<K7LkKI&EcNW|Hz+_LX^)CQ6*M{eI_H{J$4_qi?Do
zZ25BX?T*KNYfY=|=jc7SEc;AH*=WhC^D*1z_;0^&d;RT)!~E}e&TfhN<o@;T0k8E6
z9$L#%u1sF`l>g4-ySbnhg0Gsy&%WlYSaQl|eQN#p-S@B7ZhFhaxxV&o_UVns<!-Nu
z`<}e*{q8SMO%Lz&)wxpjf&c#p{-<-_*E~O>z4FKx|Nme7h0iaqy1*;El;4PPNxS`@
zhpGGjep}ss*qcM``1F0pmz@ni@H}*VRj92^#OC|&3ewKLKD))*B>q>Za76a@mM=lE
z+DC<h4m?>h*>9EmuT1^VH;&tFle@RB@~x(SrI#&B#OFP>Z`*DJ#lBdx`COKM(EG)I
zZ^c!=HC<^HQT^~vx@6v(yFw;+%J0|S)<1hPnQ^|N<ZgKr=XLuO#LrvwzHLe5+Z64o
zJom#}{T($8yixD6S4}?0ewDxOL$hc16Xxe2_p?hG8)@#XS^3oY@3iQ=n{RxJ+*xaO
z9Zo;G>bIlG%O&X_R8-$hO397VNiw)SjeiShb+Oy*muxkkoEOdgAX~E7(`8%mG)?Cl
ze$naH#+(bzJg>cDcfDpKsQb3&u$`o_iM`OWtd)zVZtz~e@YAGkIn$5E?5+B`MBX?!
zcl-T4J>HeaB-4Fn*$UtP#>U3^qon=(ss8(*`JK0C&%7#}^Zayn82hcr$OFrnA8BH3
zUcGz5<SUVKNBf70!o`2h@0s~55`s*pJu~w-q3p_XD^BvO(qBW#bDBqaXHDDJ6q1(7
zzxVQ)(=Sxt{+p<Cna6i(ZHh_nH~Ez1%=QZ#^Io%wJhOUm`ELBLk3s@3`xaf)Z@3a$
zzpKIjSJth+vtHiLVxO_=_Ux0N<3uZkrg$-S#OeM$$oXT7vzg?vm9e@Sf3x21yZnV)
zP2|$*RFCB>3AY*-)`d<864Y2YYnkev$#ti{*?wIt|96GlvDJ}kmtz*UL|1KPxo%Vv
zdpYQaBI6v#sHS{L*(I6vU)<|M;=U{rH}zLv<}O=$WywY7XW9=Ye^1l$H`P6Av+vJS
zeg9Q`m(QI3t<7q`Zr`t0&zAn0wXOZdt}mCoU%$S!@7vyc-IZ%?lTPwkzX@nB6S|YV
zJ?3*u<GQ`yZgozt=GC2U_wJoR%Skhpo~yZcU(cM_xv8%F{@t%>pJEQAdu+8%KA_H`
zsXp~mvhV2v$G3+3!4K8tSNWc9e=%*vi^*@FGi$`xyq%VkqE-Ebcg}I&73wc<E>oR3
zt0?O&q*S`<m-%dlP+G?Hnc4EsedLa>_?vilZ<_JVXF1njveg95&0O_S>-Ssz_ys>V
zUfA+yhIi=fGEj+R_x|y>joakYJGRe>uAA~K-tIv)Yn{-wQ{uV5PpjVcJXGCp`)$UJ
zlzkDq92a!X++1NGeE-`!P>RtuRb`!h<V(!9pPy!(P8Rzx)7$qp){QI&4v7nVxLMJ=
z>+rKDSK~rsg-&@|EYEz~Wg)5cd`5EL%#er6!Yh>i_DUA1yRyuhHqrRrhc<H)fA8&5
zXF#KbRXf&~?LP<Fhgr2_N!gEtZH)6n{$zgVf7*Y7-|okQ&c~;kzbL0#tSLL8xv<Nb
z-?rpZ(cXDJ;vaUt*>w7qgRAwQOZqlnUi#PXlJi<~^L(=0=NbDJPD`8VbNTt~*O&4n
z^Ry4=ea*V*|NB<T%skP#{WVXNpX%mUo<8zQ^4?n8N2iYT`0@u8C>@-<Y-#;7X89iu
zo~F~6saAZt^W1LxpJ(R#GvihrR($(={mhS-rtd4c^r2i*PVaC*srxgJ`FX!8Zht>B
z|If+!Q@+gRy%h9xMQn$%;_@;Dwc95;6hW(q)pPUqG1+PQO~}5zuRZvVV(rtrV)O4r
zzn$g~`YT}ev?d`?qwVvSdEZu@o2+=+$R^_U*Hr!LNY5YZ?*^qToU3`_x8--g>MIj<
z=6?@kO8&VfBWjfjxHnSbTWp(rw@$z8{n@m?prKKol{*BO>{i~pC>O0KzwWL6d`172
zaW<-F<bIxT_ggcIOX+S<_VPJJUXdG<jvg`MOx$8`qn38&k)z#<PY<u>d0t)C<o)~X
zjd}NN`cB^e_x8S-|Ld2sq90D4``o<PcF&C%c0;2*QNIuC#BX~$<&{cDWz{9#A4}du
zuh-x4l21KZ33Nk|aQD;ZPwDo*Zyxz<Gb58B)$ZM6Pj;)blUw@U)&Ku}z4J*+?JeD>
zoc{KIzkKsn)%;L)%iR9g?$8ZtYYh&o8-L9$Gxs>4uKDI$|5RPUpxOHCpY3^`r1ij9
zylWfQD}oy@3eGs+;D3mXGsx$<+{X_0DLiMdY-wROV)D3L6}sod9+o(vj*RUgS|{Zl
z{I6enUis(aasO3*lk7kEyUuI3`?9c<vEh$n1rx*d`1-#`o*CI(d>#M)SLbudUm90~
zZ|TZ@U3p`YK|tFMFM%a@3+LAz3rWrVKe4n+w&Xv9?O*wuVZX{Rl}~-RX4l^>n|XgM
z@!x3c<i@1V>0~0B9Q0MCKH>kn^8MA1M2ch2+x>pCtLx&C?piq?@ee1n>c589o38wI
zc2(%=S9K>tE}q=CZpWjpqGvPH{kYPXM0viOc(?5K+Vk_&_s^+bQOj#&e%=1>M_>8u
zcby@rp7qJsEw5JITG+$lVWbmwIp~bi_0{pekLuS28p(w0R`r<rTUYtPlQ_TqNz2||
zTi@lqZMxm}G6SvJ`<#+@U&no4#jL-wZ%TpZ@0g-mVS`Ne?pwcK+nxKpy4FYY(M0=-
z^M=dqZ5J-RbN_9F?>57D#`$knM}O5=|Fl+k{+Gh#@z&4hWZyW)@T5w0#WlW*OFtaH
z=q?|-|NrK>Tj~<GJrPg3vn5AeaemFTr-e=}Cxy3spSj@9{Xb{#o2>SkwX7&~H-}f+
zvwdexJ@)5uO<5AZ+t$kO*N)G2C(^G^%V4r|UZvO4;D2w)${m-t)Oe))SR<XcV_{|H
zi_CJ5B{hnwAs6%RYT5rx@DR$=i=MPW^YGOzQ;f5xf5?h^Z~B%kZqpfA$q$~djGaqO
zb>p|J%rFjLE1ltGx_D0hZ|~%F-%MYWftvOY)CzB{+hTHen~+lV@7wq7G=I*he!pt<
zx>;LZ`7mpIE|mATy1+R9iM#*3cK*r}&T7{@E*W3n@>g}T{CrL6>swT&-G2IP*7bDj
zxhwNG-*;rPYnLfHv1H3T(8BS?)BI+?XXaVO$6b~^Zt$74rtRV;9jw)=TRf=W*qpUg
zd7tg9<25WbML9ngKl{cZc3Jkl-tIR+{I92GUJkmecD3@-dxH#b);{rlA6h4i{XbW}
zFZln%uS>+O{e{Xrf2@$znVEY)o$cl1ci(=h225ZG`c-(D{d(SBty$2CH_ryGzuWFk
z@NnYhG%x-AcGKU-eb(#dlw9(B8|(Yi;_tGT?AhUVC%K~Y_m<jz^7-YYzw5;!&%-{Z
z(r0WZEnGRP>~`+<sVt_mE`}Jz+y)J$U20LB^>o)|mcv57UTkY|y!E&E?4K{m`(OIz
zXU)qq^EGT^nctSlIcJH{nFYG@#orc$Z@#zfc3yONnb-cDcc(>oJH0PIGk!2Rx#HL5
z`Ef=fw-)Fs9%!knVm%_1;q^jSbZSthwkyjm#RX~doRPNwf1Y12JL~$gS<B+B5)Z^3
z&P&}}Gi`}h!1{|JzwRo(>^}GW{IsmIwzl_oPJLFL<vlli|69FP_d2A1ot1g=^=I3w
zQlFiXlSEF>-jeBgaO?4x*>UnEv-lT%6OZ550@~x^A7vY#^>#|~sl!_*@0u(&@8RS>
z0Uk{oGd&&Da;-ePSr`4ek+I#{=)vToc*)tDGk-F8H|1ZLrhlTPWmZZ2r5&2y*J}(@
ztvMr8{~TEMbl;Ds`t>($=6=sKe=wO@;@dr+SB9MDmOb4wdCi-D9Wx;%VNK$;{UM)J
z%}%)c*X1nv6kL7x&jt_6lgmoqf368EZEwz=Hur4FvVCXm*g1bZF<$;#`NfrB|Fx4p
zpDkN9TdwlS#L35!|2{L{9~u59>l#th0w%J{?=CnTGv^??{f~pc_*b{zy#^}J3)K`R
zc1d0CRhguvzq0L;+|LD;=S4I<7A&-OaxvaNQ;lO{mJH{QCH2d1|9f-(U(PA}E$2L#
zR^FJn%G!5!?g91No--5|ujRS4e@a6jm-!c~f6r#zy6nhg7il-OFUi8gL%FtEvQlN<
z;VnInK0UAh_k4D1&9Yl=|8`hAD{PI{TDio2V<zYCFRM>o(wUt3OaAitX<oXQx2D^^
zj(i%rzUu0f=QG|u{X6G^$M*cqyZ?S+e7^5>*q&E<*K6n19slC||9Jf$_wum6HjESQ
zSiej^zcuex4O`8o^C4S3A7oD0_b){Ml;L)6MU&&UZ%k^JpOh(C?OeKja#ozC)kXa~
zmv!cU_HgX3|Gm9FJMNX`*{^5z-dR_3t@vQ%K8**)Di54Eemt45Te0=d0!`m*zS(?5
zRlX}Xe%mA|rg4~gYjm4nmb#*_$w}W^zIofOXWIKcU09Z7ys&l6{eMZP{`~!RJ3ndb
zl&!y~*Z-W}`TVcklhco`uCM#L#3(27TOZGl6q$41#6A1emp(A!xu~#Kdc%*O=j->~
z<ln%PKcyw<@+a2W0s*(T%)FjmbtTZ<*Gu5p>GjfYUTuxrf4z#erl|f2ckKlErJkN@
zELW%8JzY1c@7=V(Gp}Rk|2g4dk+RE7{(IqeuYhBHIrWWxr9GUPsz2{+nQ|q&|Mg6v
z4$0&#oOP)?6SvL(`bl}SX6wvqReQhPp08*AGCOYTaX{U1*`DX$@0Q<B+dAnXqwp`u
zCvxY0{oIt_F1%ZD`_E6aEE+8<6do9}cbH+Xfdz#GKHU71wDkSwwfVK#Ki`$_j}BWO
zXPephr8FgCT}a{0!sD{)XS3~3%1_+?zV^K~Xkfx@^|Q&jG9?!rRh@sO9BHi6{VTds
zYf|F=TYopKT=sd!ahqjw=QJ1Vo+&+`eth!2^(`j*K22ReWsdiD)fp4ARDUMFNNh4~
zW~<q>{|ozad9B5sORBuK%T~QuSjyP;MSJW2hP}J*gq+vk|L4;#uHbdSw|DII+gAJI
zVf*#xw_jH+tzRK~$&*3Dae-qrQ|QiPd(Rm@oXoN_=wil&X$BteI=@tZ&Enj&<bw0B
z^XZq2j)ed6FFtp+Abw?q$ZYXF4_HeDyY5K8{de*w-w%`LQ@{KFI&u5(E7Q+K_n%qq
z{jyYlZpfV_Gwm;Du1o&4d~*4VedR{0yqqd_+HpSTy(F~CD?#U|f7RW^FJJr2&-=s}
zy^He)kLI2LCOgk0HJ^)lKN~zwt@*8bJ#N`=3-jnnZIy@3b(bzPdJ?`n$j4Y;aTaK8
zd1cgoO`|VYO6Gp7T%2;}a9QcRIMD{9bxFtaa-t5|a{lzWK8efs>GZta%FK3_)85!W
zmNnD0cbmjCS5IW>2iGS4xBOFU9P0O)rX_5fso=xJxAM=WEpew!Ki|6iMwxMS*$fqV
zpXYPS<El3<lzTq!%-);1nvK_Goj30G**By3Z*bw#%%2<17?vGYpJ_jv;ncK!{r#5D
zW_((rZoAU5ch{Vh&yQ;!9hKw%q->Hr%S<<3pt8Q~e*E3H>N?Z)7w#!vp6y@vY4Yn!
zrDuzF-rFm5X7k6h+t@jOr0nELo_>DzxBh+owQrK2uGxI<)Emv{QwrPaeNtx}QptGF
zv0jtE<it!SJLjfI?0cn^^)7r-<oR^`l5*WDW2-+b4xo)$yOd7Z{eBb7A8hKgK-JoJ
z{%KIp*XqE;e;4<DyOq5nz{iQ{W%t?rUvl5<d_K?EYWmDIQyAQTNqpAtH}(ntXIg*8
zc5?2yl(`{Borz6SXAQUfmQ3Gt_M6qq$NL^Mai2<^9vk-m^oO9cbwzi}@0MQw_Gq%4
z`iHCQOr|KfU6bARwEvy4Oh}*dcTXl`<C}h)@3Z&@9Z?KTHTn|475n7h%vUk9O4(;F
z^Ve~{xU@g#|KIQWFDJ*ZczelPf30@b)4g*(_dDA>`y}^jUiG_$Kc3Gzrgh!8vbD@?
z(e860=Yywe9{)di{+}i9_WOAl+@5p(`=W;PA>k{I?`akKaB_Osq@1@OJowDx3p7(f
zljuH?hN_JdmRJTKRFzkIYj$;l*Ut|=rIX6iYwn4>uYF(ryDe<f-w>HB`RscRo@ckV
z%bhY*xifi!`{hk{GMCRa(~P}w=CsMnTRof0zg%>`ete39$L>FOWMw~iX0BhNcw2ti
z&r7Fwbo_0*bc#Ld-R8aD?^Qnv`Mg;9_RFa`K2{dV5@xz-lIwIeuh-eL6vu4Ltgn0$
z^<-Ac-<jL$80Y7_ceno)I9KJZsLW~GNmEMg7;ftxT(HEddh1P=fNfuD=ji{*%RDgU
zz?lz$f1~bQ);wGe9*~__7uxx0>0~Xtw;@&Q;wSCWw7j`G^>^j^EzRzcdMCez<h|N<
z^G8}VsEEiZx7fXBS|XEh*y~dM=P^M$wUT#kv+uV1|MUEHRqf4nyU(_VSJ!U_O?*T<
zzQ%fdc)}JImKwL$RhG9}RVO^~_;+A$CTH)H{*$Im<!+3O^A*>>a^n2)WP|aXz*V6t
ziMMh+Ez&erl>AbcoRQ#hDPQtb+V;C;+LFsOUYAE-N|St+v1-Ec&-1?T*;VCLeU~Lb
zNNd-VN#0&|F2Y+pzs_Xlx7lFxNU;A#PW)dd7t3QIIho7v6zOQrpPFUIX^?u`)9cxu
z%O~%L?DQ<1{YGE)<E%1w_L?FYPDK@ut9hQ^m#Rbw)p<@<`#O7r?<!^4vKxt$g$~aw
zKc%_+%E@!z%w`?u<X`$Ed|mc#)wMIL6|SpzUT;}g^tbq}{D%g1pIh!u=906GSKhw4
zCGUW`V(%1-?4Sud<%|2D?kUzSUOVec_Nm)jqx)WdU0+{2*CKcSJ)3#C45{Atj&sgc
zxiYOdKdM+>y=Llnk5z9|cHa5yS#I}jWB*){SEp*{W%>VQvfjI@;_1F$_rC87U*1)G
z_w&B~>_bVK(Kq&l&r0^HJP`8Wl_}ecoZ5EIA8$4s<|}1g^vo`^Pv7%PkNm9Ps^5#5
zd^wjdJr(@D&i|9y{MfzcRBzwD6nEC}{LzpD>3Sl$&8VA=LCYc-7?~C;D?Bi^x_)Y+
zo=szq(j_^?$Cl?S{VJbo$M5{WcSTTe1~VxB1jU06sJGAKd(ZQ9OV-s@isw^4A3bmT
z{mvwL0ZuWWt3o_pUl+7wrd=}POFfqP=6cXk)q``&Qv2#oo2`#8x#$WSNbru0%~;4<
z^GVISbk^^?@9WM!<TIVS?vuCKv;&v5<34st-euo;ul{>^efV^B=~oA;bnfu}sQL3)
ze!a8W$_qw5-dCrE<auQ*j-L$*(EG=CzLSj8e)_a(D@)BLpWVBHH^&@u;Jl}D<J$VC
ze?M+nZo8I`?Q3+}s_VjAPR&?(w@`g{Y1(URp9AW@ZGJpxetjx*Z&UkO!>_ZK#U$13
zFir0H7M15+{q@#!pLpR9Ggr>}3R*1HfF585vzVCd7FXVt`FcpeL;mIVeP7phHhccR
z?kx9dLg#ZifgQ%296xv}O~s=QsJG95*lXky{4e#z+QjH%T{fT37<)6>HE-i-{(2_e
zZu7cx#u)<7Z)LC7m3&{YDzR(U-{nT<<^LR%_X(-XjC*hDdvp?LZHlUByiw0pC+;6l
zW+Z=^vfO6rx+j<AoYq|bX|jH4m1o<{Qy0RTx3uh;_y5mxe$hQ%Ul&YS0ouXFcJt_#
z(_grLq@36h!h33u<00wmF~z>NPoj@4nzQPxS;M5<{FlEirmmRx_f7is=k`~3Zh8K+
z_R~rKx=rgkuGa0n|9DS$Q9f_d>|7O_safHix4ugKTXpk%PHj8ykCgo@O{P@u_$!y!
zxBR-v)v8a;y7S{Dqe~`iTe^qs=Jy4sIezeHrCMTLn|#NTg{9`5%=L?rcMO@{*L~lu
z{#Wpacig8*zxv<2pRssjI8$_(!+~^<`>hfmGW`@C=PUQyY_j=vv45V)kx<ZF-tmgI
zTrbtRpxw#Ad?&BQt^Zwd-uAnWyL@fQ&hLBQ$A+zoxj8r1{=7gU=&+m9=KDVOYBICl
zof<q>L)6RY%*97XyLWGX-DMpA^HjJR>twO41IsOc@J##)n%BJZec$)DmAyebpMtu&
zA6|vWF1;DIK2wYJshmga(zwJ$Z<Iy*L2Hb!9d7x0>zGgcYw-^!zZJccT&3eY;c494
zZF9bt@B2LWQ>%W>LcZ+M=jHRyn>AdzcW>IB{>}4Q!uu?r&G=P&X?2qSw39#QmtKo3
zO-Nn!z<1i)Z9Jc+eot%)DSUS|=&st~J4el(%YCn>y|$j*;NPd2xPxc;)P;YI+_Khx
zuRBy@|NrOt*9sx4zVqDP)^dHraf7R$nCyaI&Tz*_s}2nejn?xU8qUvsKg&v)iG?GF
z6O@rd#fuIsuhrrVSh9Hk&*>k0o6JC)CwD&T(tdT^n6rP&_ltFN{C@2Hc5Ahqk<Q%b
zFB|+>XT8yO7CgHw_4e*}yRto(m!DI1?8vd6>gTpq^~i*PlYZ83Lmr7Po)i3!SNh$H
z^bIvXKmD4ur0Wc*Qwut|qv+?;>DRv>C^@|0>+NSH>-|MPWL}HimJ?~a<i<Jc_c7sf
zyq-?IGaYm-)8-ShW_KrjFZ9#8?Z0&Coa%eCcfPCaKXdf=635%Q+wZ>m?)`4{mK^Kr
zwHLU|&z6ZDGI{@fkAD&W^SX1@|F`e|`*zO0@9%x$xF624WW$>L1SH}d4y0EYXM+|(
z%CNH3wC#DdSm=Y~r!6{u34SbWoIlQ-?8|9E&-L&X!v*Ss0v~oxj`3LT*uc=JtE2G1
zSY<=Q`3VVP^4g4y^Ed9g<A?JOb8s<g>9B>9iG`!5v7zDo1o6lN=^h5%{Zktn&PT-N
zspGtm^$bY4jKVDzMkbbH4h{#>Pju@%Fjkpy^thM9f%G+c+b65SoruPG22#!^klVz-
z$ds(0@WA+qtJnugp)-$?RTUl>hv7SJuNb799o(a7G!zi{Ao)p&`v(ta+Q*GT0v{w-
zpMINyby60T>?{QYKFnlxnXTZ^a6p0sR3c7ft!ZP~{3C*s<44ccr)8V4&e(yJ%W!b~
zIK#Ne7ZgK0ET9-V0dCUPtYO)9J8$=<nxCIKi{tiImG1ocY_|HmYBc{Mm)ZuA4hPaV
zwWovZx)AMfVEK0M`{ArLzb?(d+DU^ALLHdE1hx^>h)&i51zD>&ILJWe;I!_GsKAGp
z-pOnrQ$S6jD2Zkpkq?qCCynrG<55z0VB9e&736ME#8x|i(*)Kg7A%Kf03GV1-zy0+
z_=1qYhs;EtPXPzg1yoN%YjltVrb7)n4rDH$8z!b77jtb*r16PI(?Cn%8x2K04y6D6
z_4Vmd{ko5PxJ(?cRNl?py4h8FmD%jMTtCjZo!^DsJg5y@SpDpNKH2pBUiI|S*VnGf
zZhu=T2X=lVhYH88l#`Q+J{}dHzW+z}{u$vSjPom>ZZpQ7H=)Zm#TFe9be9R7_w!8p
zwRW{9n+4WSNLF%aI3TNip{2S=1hlN>^!0t;wpQ9I5M$b^1Dxt}0{E=oY-p{j=<5b$
zZLx*}me1z|-}`;<`?=o}Iewh6-YJXs(8&z}tU)KAKjg2kxLJJO_VvODu~&swdLUoS
zuy6eO`ucQl{k>aie&4=7@B1m+vyogsOoW!<4Kr9gi7jYoIM1|4gRc|hE>IeP#W6H+
zVG6-g4$2A-E_=+t>r|M&hz2GmJMIsQEL1?wga$3x6s$J&HZ=GvCwk$t9i}gVk&EMp
z&VlYn6L1@c<arY&CcEAi>=UPG1~js2C_LEApx@<;b@B}60GJ~$aBz$UG$IH`0~(ev
zz<FRaMI&eWAzE}OOMlq;Y*zNHVgsBF97F~XP$*a~8nHF&s%%kSw^>N8S+&@QnZ5H$
zakWxFH8re!b#rw%kRGyb%3~F9;z26EU@DO8k?;n!_4d5+n}uE^VbPor0vZ>2>SgIi
zL_yrRQAFT_<muDzmW(<Y6kMYrjhu-YMw16}p5+i2O&+7k10@7TlLu-Dpajln>46$J
zqov1a@<0iJ5tuyO%pMqP9q5}(L_@aWfCiV&t$?k8HU-DAo)?T7d<qT;GAt}L#~x}~
zyMvl?ctRQ^)i_a9;Dh8%@8<`IY55*=bU2VMvu;x{QO)&8M#lLQ_m=R12K4Z^>_;69
ziVNh391Urtj^AkV7)>7NAuyUeP(lD@43355(qogE)oa*U0Hl@K&t7WHFZ*^j^>AB|
znC`CH_TsNK&SoKEQ}>4J>K(t6|MRW&hYliYxr8UIEH%$w3hjIS+C04amc)^nr!zO%
za{ka+^>6#aU-ubz=ZE&$rQEccJM}J>ks*x4k(0^DIA2$HPv-CUzkd0avd&NDpL?6j
z`u@M8vx;7tzJ7Jep;U2xRz3UO(oD-&3wGW;Z)129|Lqu%3e3UX;lOg{O-twP`<%`B
zBS+)7ZOYNNr8Q=}H%$Ytr?Z`}FMhl0Q}6t{VPUzuSKKMO{p(e{*3T(L|99(Z_ge+1
z&etuq&7Dp-I1J*MnCw2Q)V>POU-hk|`oQz;tFNCsIq!OS=Dhs5)zOiAc1&TH*|6l#
zkL#~bo!uTbJ1*qZ!t(eqxibE#HP2XXx#39~Fsbqh4GrgQ4$l8I^=fJA+{b*;6X*E<
zJnI{JKs`B2chw{d&7Hx%X}|ukUp0umzBVpiuI$66P5XY`-~YcTcW0&Vw(wJn-)&uF
zlVLx#=GjZ5+eCz2!Z}b3&)M>w?f*KiA1Vc(zqE%rmxNyKWt^XN)9Qxt?w9&{F~NF!
zlWHpu*lyF>{dUWenDEy2x{%hIyj`WvQ{|&V`m9o1ciy*ivfI19C!C1(3U{=_f%JLn
z&fl-w$@L?IbN+JslGj!*if=Ac+%>DlzgWV!vhH90wQ2wNq~z}WzAt(z^S3*z?(E8Q
zmi_ee-}!v)?f147cK?6MsD1ii`Q24Fdx@D$InV)`N4?zo>$d*=i12rn#}2Ep*POG^
zo?5$Vl3gfY`s0q+v&{$R>#r}ej?Uk_LuSwSu&4XV<HN44(Jnpl{MOa%Q~Y)NmaTdc
zeCpBBr8Z9w-k!!>7H{RBo?{M4fcVo+v7!QKI|_5o<0+ekKHLnL_j5z;Dl0qbQ>m+0
zi}-#0)1!YkVr?vI&8imvxcDnlo3k%GKfUVW_H8$-Ja=A?i=N6ZyJOLs==}@VMBZ<y
zxi;<nzc15@UeC%p9a{DxlK=j?H=8$4IL|Qsj1pnDG_r!6;y?Z26s;4J51c#J;J=c|
zF8g)NdCB-)>(<@*yvY8>&NXX`>_W|!&s(?pkbU;*34W%x!oKD^+n)WiXWO=_INwv-
zyv3$w=iLri_v3Bu(^KC0tJ_{g#mUt;h<;c(eZ7<2Y^|R$#gAucJt@xK`E*;*w6NEI
zuDj>Pf4fn5(q`^XqKb(#ZVm_1&8nQ&{O;4g7jU%NtMb|5?JNI9hkn>u7%Th3@-cVl
zf#tvMpYFe%8+_pTw*-GCTj7WE!fvRqf4{4yaOe3|s-+K}b3b3F_y6DP=+n*bHtvyH
zl<is@^0jKMmmTNNn&-#2Pl;aTW#_#*=X`hHt&MNCY?9jUjdi;|TEs?N0F?kGmG|OU
zYgWnlS3Xk~`k?vrlJsgWyU^b+p08iGe0|lkccowF^@>*Kt-o`5-J{KhA2x41b^hON
zUA^6FZ%ACQd^|_`l>RC%yY~C(vx^SIPER#2eI52`=Pu5lAyaFn<!;@v=f_6tDQ~xl
zeY$xh73;+j$PH2sfe6t2{O6L$d*51Lziv3cS#IYhsY$C>J=nZ!)q`MP`(Hm-zq;;U
zbuLz&$?ml=OZe1FnM}5vuT-{dUbpH|akOdj^Ho*n@2!1h{od~NtxvmOUz@tzrsVdf
z*L>cujc18`$_)Lq^H-bc(>cZY>$HFB+|LU9`S|~)RXWkTGUkcAX+sMhi~=9DY$1Y?
zaem^_v>ktzH281r-PPnj_0Z23&)2OuWG#K_f6cqNs|7LAt3ThdTiaxJbra_|o%l^F
z-t1U2<^G*L3s>FQykgBAkyDY;x_`pw?^zZ1?q~n)jXEo*WqbYb;rbb(xX|>q*Uqg`
z|5j-|`MmyrUGdJXtDbBwdae3&zkT8HO`+E=!^%~hS)*~H_>Py$W}gBrjRLLAnI4_D
zGqro(`7TlIQ=oG@<i4(OpPIYvrp2m@Vs{_T$cs6UK2Pt@{Te&b8nY?swpq8UsxpHQ
zKHoh3`O{C!p1;4$^&@A^gUc+nK^K>wdUnNezRWwn)8bRtu68(gDXU~H_xgz7d*82S
zpZ=8EeY&w)Puu+dwuN^}PX8);J&X71<F8Mrz54lU3Ukzy2j|;1t%=I}ohvro_3Ezh
zm{?xnu)Xu1udlh}_gN*8aH(@(n$V7~*P>5Lrq2l!`ZV+Ww1V>+kIO|1{kZrHwC3lX
zZ*|_se7o}6*p<(3mL6C>#XE1!A=9hc@;~eMuWmNauY0(!RCHcTtr~0fs^=%4Uzu97
zYG&n~GxwKC^}gP1zk6rRfAOocjaVyIRn9K5akl>-fBw$a=Y`dHZ$1MjTM5}l(2DA(
zdp@7r?acS1ftgRkU8eAe?56kDzx`Nip1tJy|22L6YWH(i`?!9jc&zizj|msOvXaSe
z{!iah7U@&*^DDl0HuxX1;rw++?%7JMA30U`cz^xbpC2E-?S7eO<kq{FHYL42n)>t8
z(a@>$TvH28Tdv>AdRTh3ZPUBucBP(s?=QE>>o5Ac_4O&;)z_zYuiLS9)wkfYYo7gi
zpZ?a&U#QF(waJDh{p4sie&7H9Z*)z>x@R}0>%~Tet&Iu|TOSu2&g1oU-gCR}JJ04^
zwiFTgFw^<WO0!V*npHYyKlYy!h+P_UC**_W=Sx;+HeXjR*S@VA8!Y-LGK9S_FLwWu
zn7Z3xSJlkz^5f>eEct2~I$_1F_nYhL*ZZ8hcUy1m_s<8{-wnuH-S+9%=H&8uuRfe5
zTw1v~Jh=P5?t7a1%!ivnn>nZ5Ex%uT%{e3W#ro6w`}eGg+`R0~{{R0{KR!D8^&jYf
z>Q7hK*KGw|s4@HPeeTWT0v~4XedrKf@%sO2tsfy*OXhuk@%B~1Syf-w`Tp@iYxghQ
z^YX^(Rg-Kve}tr#2kl!fm90IwG}UwGx;GJZTmR)fUB+uHzx<tddR&0~^Ud=%`Pa()
z&e<MXEAzkP+pDTyv((>OT&Rp7+z5@>!F0Fb{HLd<PZu7S4Hx=!^U_<;DpBiq8uc4g
z=djjnYsu=*-S^b^`nC0DjPtu!H~0(L$p5?Isv5a%f6b|%U;osJR-Jm3`gGS?e$DMV
zcXvkR26FwrB3j8dci-c``&TvFod4Hc`?}%$z0d>d(myWTG{1Jc@~mO;XSUrdSFx2G
z?ah8w{POF3)zE^Mde%9i)AY`9W;ApBdA7^+>9$hIIl0NVtFL})T7S`iz?5v`HV5+u
z#XlalPp`iBdEQ&sXHP!PDwRIPzWU6;%IRx0cjxV2V)MQu_w>2jx-%!|-ahe+iOFvE
z?3{_=|FjtAhkUS1`du}v;e6Yxdij4(SW^o_S3du5^YzfY-*ZKNL~hx!CVtnZsJvv0
zH0MQ*(YeuLy0<s##O;cW4Ep=}dR*<T^P7Kvdb9jp_<M8Fnomyma%TQ}IXV1mbm@xg
z`#)UHKHY7%#c<7){G)59>1eUP*|x|g>HphPtNU&(UK6uzV@&w|r^kPOo&WFIvrkLP
z|1Mgy)=pw}*}Ie9HCJzoyk%obz~78a!l3y3cw9a{Y@N@wgm+PgY~TO<#QXG+_BFqp
zlBZp+Pg(nK?t8P*>qI(JDxW;Zk28wTLT3M3Z5(_sJ@~-#S#dRomo=PMKewLQ+}CrS
z+J((a=h^>W`8)i#cIy1MLINw9?BZ85*<CHMW461>r+zDL^|YzMeY>MAOYY~Y$9+y%
z?BHa}`CaA7<viR6ry%C37wBH#{V}KFQRmy6o9pgq-?^Mq@_ViL^y_xHd2Rw(+cI|r
zf|{=HTFmQz&8qVM|MkS%)lHV62h>GtR=sSu|2SWB!Dh|#n-}V=YTIyY()szdZy3MU
zz2EjX?CY22_}vTb)=jRff2aLp&p*!UY3+Awiwd64ntg5B=k<HG)_iimK1Due&#rsl
z`=a$V<Ex(@Or4$^x^$(Z+27|=*8kh~=j-(PVE*G@KdicS(Y$`^$0*JpTc+BmA)Jn_
z+-lr*U>eU4AJKOw4RiMUihihE)!_fT>de(-#`!xZ%}KN7{Gqbr^PN>Pq1F#J8(z4~
zQvEFd7T=F2JK}y%*~$N7PTilnrytwD)ICm{zkJ@`-JhoE$A+DjEuJ6xH1_<ha;c*q
zXV%_(pQqVx|Mj`5e4l>Rk-XG)QSVn9{6Qm~&+Q5btoo7&OYml`S;qZcXBFQU$^IML
z?&RN3JuJ8BDLZI+B}1m3*iZZUyQ+c@q_<}kOP_KzU$eITR94%QQ@#5(PVf&sxct}s
zX?1nmt2)*N*?qVw{p!HQ*Z&fh@3c7ksdau_bljJPpI_(tihelB#QD?a>-+QC_xEQc
ztInVQ_x$f^xzoSPck7>i&YXPn(u*@|*2eB%s1s}R`RnYx&n&h@8U221ay#39wey<T
ze`||w=0AV>)cgP6xTo*;SMF@^mp++HU<CJt<_1+JyUVTBMGF4aFHU`0@OS!m8#VoN
zpqlqv8*}bMef!GNy?2WHS25Xz20dLQy-IP{D+Pby7c=i?YW;X(@$N)}zr(%A(2td$
z#m&P${=6bD8zHyj{3*|Q&*Mw8E&oPOpPnCjI5@WIZtl}<TcuCEySh>R$EQ7q%XIyB
z`M>9KJnJU(qOx4H@8`ApdjWMdFMXd*%lgayX0LDMi@V#kkJ}|I-*mn2^eOiJ)u}%}
zd|$6+y*?)D-^a?|=Bx9}Y+paWKGpyKZ_}sCr{9gKt9`1QdezMP^ug+!Sial&w?92{
ze`}ZCIRE?K*P>6)+ZB77#zbqT@A=U1X+qZTvjwr18lp93yG`P-wFHq;XrnJvvFry)
zl{=q*x3AM_m))^vP4xD4I+2(5Z)oo}DQ0AxKl3*4)-)zN$yu)}-Bl-SS{O5<!T+m`
zbBSukWRv4HcI(?;tm=Er9KUnly}z&LTm2WUVfwLieoXYg+xBzgqyL?~{7uup{=vDg
zkN-SpzQ1$RoSJ7xRYh}uZFRqwy!+EX`#by7L+5Gd$3(~dIsbfm@wxpQpT8<!+2oYI
z=S9P(jq-7^>=~c_RIA^u-kd6|RrUC}zAopzFWKLBzBYS0_o_fLr`*|Pv0<$<<UaS!
zpDLXn8{cPNGX2xD<!@s1{SKs?t-6N4P(1L11AGj{t5Q%YIHmbpR9IQe&I+#?iHB|D
z|2z^uEj<6n5zXzH&(5&0)TBK#`x5oG!C&k9710_q)*7KVl}F;V+wMIx(60G?DO#P$
z<>vi;p)*vE7rL|82tBI2yIg;rzv|WEzCF*seSNI|_ju`3R{1}re=QEqUVg8B`KnLn
zPHl=d-EzY<{C=2SK<M3{=axM<ce;OvcjejS?=y}}47l+4-?#Lq;`?_mt^0eg{O&HB
zuiwkG*h59j*R5)@mlV^PT3xns)we%!TkrDdUekXtnIWjjBa?sM?NguDu)h!DyOZns
z^X=DcuT{TlmaO_WdE4u<=&AXC`<qXjonH2jVU75^&-3RLpR*0^+V|}^`_#8#IX-4w
zKfW-2HUhT~6>t`4K0-6J9(?{f|6b6(ABShZdMY0N)ni`yk+P=;c84i5e9dTXsh;;`
zLGG!;@3$^mcV}|JdDZDLL4GzLkH|%TzLdktQj?}_@!(hfuOr8}?CO8qkbRwSw)Oh@
zwaY>u&U;nA^2O$*%y##8J(=eDd-v^c-kWcK`nRgd-|NSof0^6E&q;omQl&R-!I^Hm
zk~-V>Umkzg?zc~QrMM;T>qhR=lJ++&YHpVQ|8g(2U)HRyz~=eh|B>hZJ^h-RDmv}w
zm+tqG?{@xv!Vtn_bH3)h{^|YyejVHN_S4a)_W%CWeVq_?)-iSV&9YmD-(y4X)xEJx
z{dwu+!P)O)3z9{ZtoFwgU%pkfGmde7OGlsW-|1if2+Qrt{u%FoYxNW7b$8F%e4q8{
z5`TQa{x9}@w-*2TII%qQyxfnE;;R$RbDOu$`uFeV@2TqdewSG@&To{|^+3vin1S86
zQS62Iho29BZlBs;SN(~@!h2QT7va7;>)zB)KdCr>W?MCr{)5e_dG?I+bsz7#8D`G^
zBgDBR^#5sr*sm92LNBDp&C9=azHYYGk3IiSm&Y7X4=tJZ?fdhq&INDxpZ@geYq+e<
z!?KfGw@>{V+Lb;#)%%p*?Xbipa=KHC<NkJbzq0)QNxgl_-f-R3^5K<BKW*6mFLURU
zS+`H|MeA!m-}7vO7R#0Dp8em$4(I*-nXb3;`fJe-md|4MYuN94vaF~-HhhZyzCUrP
zH!u0^O21q<H==cxU3}|oA&+1Gvftk=ub(Y;KWEdgZC{_B*#3V_O2@jz@3uNuzAt`n
zmnq3O-%|#3YaPD8agcAUW1MeZ`{q{BW8K&0(b<_-=l*LCRh_T)#Mozty7ccm&+Wp)
z-({NVJh<#}=55G<^gP?&d2jXY_7zGje;z7Y6J+?jNqW^P!%%_L<eM{XR@}0&yI&s6
zI=}wUr_!(M{O2v_vg5q}=Utm=>D76``~Tf83Kq@rbe+>bw<5vzPiU<H^S|e__wQP0
z^IN_yRR8Zqak&7ws_(h4kMCdIcCPBe?D`=4x|0ugProi#dwpN@8TR05d#k?QI@|VQ
z*T-w6PZ#{J&D;BKzTLZZPgDEv?R{Tn7tQ<dtNYb}xXk&LCv8u^f4kN9eromEio?(K
zbeGq^{!~@5etn2@@!PGBk8KFryoQ*y(7~KvxPSba?;jJrZhz+I2LEkSC!FV&+gy9I
z__^v++xUG8V=9gwn^;iw_W6t7`N49vC*Cgp@a1;=`qI5-@X}uP!^%Ut=c{9cKdjXH
z5t2E5S=0H&-}e1|CZBbfS?|wT@4UHN_Wv~!3ETSL>OrvV^^?cX{S}B^y)7~-EXQ=`
zqqAGh*J_)u-}#q$u~tIJza>)FUOjd9v0Za@*Q#0mO^(;^?^zd9fBIPc|FBR7tFN#3
zuV%f)IRAZ^bH44{yVC7ft-ebBo_2r#{Z*P%`&PF-uv#wFwL1FX^W)R+hRmyYrT?n*
z|D%)DQ`z6_-SoapZ^x@^pC<VpF5%sD{##q!zuU7<3$OaSX6?C;rTzP}D?cta;}_!m
zvE?Yi=2;!nUncYEaeKGz`R#2!<@U8O#YVZ@)mbjHcfZ-NB&H_xf5G{{?{|0EEc<mm
z@9($kamOCt<mUKs=3c=9-8~<ZS3cOh@K2)X2T#%2-0SXtY4iBEv}zxy7~An<TJQ0l
znf1RzMQc7ytNkB&J@hi~)AN0IQy>3{{P&&vszIp!s<zcqOHw1&ZMS=ySF8O!Wyh+^
z`wA<6`ibuQd0spJ<!{BwwOg6(<o|A8ed_;@AIBE%w)^VNK8^j|W&0VEOE>3Sd&yQ~
zSNzUYc;Q?f^Ni|J(TJ*}6NA~O-MZ~1p}BAgb6IrYz7SsKZ6zn41cXcz{gByRNobb*
zFUvBnJ25p+Z+)s?&1L)7$?osAnb(82s$Z?%mAmS1>GZEPpgxiDcIm9Mx0&r$zw)vY
zkBJZcu=3yakPnd|VrO4}-W@Jl6XckYd|-J9<NTfL9~9qVF4Ovcr?#jl|Kp>eZ+9~*
zcV3U(wyu4l7wh~uUFW#J-}~bXUOJ~f-E=hd>Zzrv$Jb7u@-|#&<@4J8s~%0h#`j}R
zBx`Zpu9dUSxvyHdTW(wCi*<3oPiE`?KEe9*^8dQCX^iuY>k3LMuO8Q16Mnn;>ZVmv
zfu$dqx1`$?JpXiGZs%<V?=a`de?PqXbjsN5-Q&ahJKQUO{JZ@%#{a-_^=@%a{8J_i
zlnr7Zq^T*+uX{M}P1UZyrF`cvOLB4iI3tjE<LbSNV^c#LmR}LA+4SzGFYEk7bCcOm
ziy3A!nXY^=`CI?W2f?hh|NiU%1;Ve7zo#CT590MSOWFP9*6mY)%m1voQ}Ozj)tS$;
zj^EvC^KOCcsdu--4|i?7WnN$ET=~uZ&#JnmvL7tJUz&ZYzVi98g<JpqTKRiQx=qHb
z50?zz|8o6#QPn(G?8DEv(9q{AXSe<Ob^Q6;cu;#|?cVce52xLa4h^lAvvL)9xoCC1
zwj`U*+Y7bZbtCQG{<lltzv=C#ECZKbLIZ~(OwBBLZJa-C{={jYnk=`a^65Ob>Ir{M
zPtQ6R<8UDTS()?N%IX8@p<C~@Sv{D%aMvp?yQ`nw-|tOY@s@Y@hnrUgV&DF~yO;Av
zP3B{PSZ>V+m)FhtJn#9Py*BS2$X3nETlH?qFTW`32gP^KzCN}0ensBjUmL&QU%BV+
zj@?)LtN%VfC4GHb``)k1pFT5vZO;88<=)@_pN@acQkSj0{^`=;^7mUiBlmtg5?mix
zS98<X_};Po`~TUcE?>23q8q+y1mtNYgNz4iit{h8ez@z}8sDuG?&a<(@V_QiQor~6
zgR73LEH!LXXFV;-|MB7&mz}!I-sISm&;Pu>mUkzKYh%d!sqXJLr!w2c?|%Vmr~Kyg
zetqD){k+oLz5ng&e;r!+;PW&6xUhSb-`>A^JXh<$r(OQ>F?Jv3YQKJZi*f#*4_j7!
zI#<4$%f?$=Un_n8s|B0<O?4vHe``A*7v=Z=+taUWc87>I?JK{uS6%np1M~k&{(Spo
z`gB2-$Hw#f-^@$(+`2a|_w6p;r?<2src8Tyc$)6py)or?x7R=2{&do+q>CkQmxpq^
zSiXPf&bT+<-)~=~6Tho)#|Cqm&EY36q)K77H&8`74j44f=GKdk{`YY8US~T{kKoV0
zh1$zqWz*^}=bd4yWo4=Pb?MC8p4-fJ(%L`%?2=lvdgY4EA04M|z8P{c-EQ9f+V-`p
zVlK9Q>W^Q;WEUFk!8o74_WP-#OUw1v^{>8vA%gS0&Ex<7R;`KMZ|Hf0_eah9Lsy@!
ztgnyT+gtr+*P=bo_ut!lr*`^nXS<Dc*Ujs~?^RvPKefyE_6yMuKS6z@`cIwRuino2
z(_(wNzWPbt*T>)LuZ29ECw%Y!>!NS^>(@7%gIXz@PH!uY4t<^*|I^n~LgVe7$?t>1
za*em&&Y$0Z9On=;BqR)WG2K0I7BWuqM*hl6(NB^lcQ#jjef4P}e{F`)wNCYU7B6?I
z7lXE^oA+JLds-hZS|fDF^5MtTum1Qk*_Eewv(69UtGYiu=wQ0@&-v$Xl=|^K=eFOw
zZO;qm=htsr{r&Ox)MNgeg)iRzd({<vD%t;MrR+V=fM=>#FGRTC&2BH+zKZMo(d&1j
zj9RY$|K5B0^t;fbbGz5=+j_6g{J~`L_>UL4Ppj9Jl-k;d=E-fkzwPM++iiN`A<p@K
zA3VDHbkF^}LI3`LduQXfe$_ttALY}|q}*5FWZC4%;T<6&%9yIVsbht!(rP7*+^tK)
zws>9T>R1uFGHAl8kkrYsEFs^V1b$5QO`WKk!>Q7!)ADBW86UOJ*3bRsr3k4hDxUwW
za^(BW@Mm`4?VisoeqLMo@%r<xf8{p5ZaCpuS+sloIwm{I-^C|>o<CxI*=p5una}Ue
zK3cMu?dXhyce_jf&AGPo(ZfjB9qRdCW`5`GGv>R$>c-|d`&nvEt<2QL-;>YT#k88O
z=G*Q3{Wt1<zrFs0-QQ<wjh?){{j8{4$@67*A7{URwYc}Qcf8*W1I2ecpU=CLSt#-$
zvU72cI+I=M;+W4)>9KR8J)bt5Kd`9iT=z=X@Kb#*D<@uN6wSL>TAp?BYUTc3%LkKH
z>&x!<Sp0sr^5^4Ef$`zOJ4M6f*n3_|FPAsk!g2q}=XFeWJH5{Te7yYV&hmXyr@Ov9
zS$Wz$ue9{u4nfz}c`{P3v>r@We=cw_ef=Dfe*fI4y8OJWp{xD`@0xM_cVLwMc2@20
z0v|NDufV>EAKv5Ikjb@1>O*EuPEX<EW3K1tWsBd6jGh{^_xY~Z>$;yk>pLW~^fyb5
zm(WvNt{+pb7jIoXxAN<mMM>v8+n0*PYF2!5TK6E>>&}wLjmo>$f4f&yQy9+mqvT%x
z?SEfgRTp~a&5o5hZ<F?T<%8f~)%l)R8}=2y);27>*7aYK$3L`&@7BWnCuNb7)3+a~
z`~Ne<aPR5{|IE3|<6=elePRUaE0=0MGuQ96b^Fp~TWmUip>6jo+vTy}g91e}N*U+x
z@#7QwtH9ctS5;HyGxKuLjH%b|m#&`Y`g$Gz+e?AGD@yjxac7)globWu@Q7thA6gU7
zUUy&><NQC<zrDDqT%<bxU^Bb>_jj+S`$z1lC_FR6aPf*en==C4&F7q(#bh_v^wjsr
z1IufsWyfT?9!O8%y0xX8>&KET{he2Q^nL}g)U7I>$81-*zdL{S<Zb!=MXWW~IzEW)
zuhHFlW!98cFL++x57_dws{8bsZ`&s8*BZX7NXzSyyJGw9-=V(MbHjfn{d=@+hCy=S
z7r)&7+vF|??3I4)6>mvsvtuK#R>9Aw)7^tFck!8Ct(g&{`l3bHZ^g4|^`_OFKSExH
z&ab?BM#-c2Q{qn7@Kp~cN0sEBFx(Zt>cM2W2alqIS?8D7to9MDF?(|VO6B|I%XPbM
z`sTW}&Wl-_UaGwPX4U)e^Lk!>j#A!!W7mTh6IaiEWd$j_;7JIBapMK+v3_~^^LD@A
zuvMNjOg?tx-|zSP9lzbXVlMh&<t6Djxeq@RxPB~g@tw;3ZB5yJr3aJeJztZ2`tqXH
zUUTwyo&EWE`SI_0^-E`zU;McE(S?nFckg*VCwkd2|95i(Ys$~Hw;xsierM0=N<D%h
zv%T3NZ}!*M@&9+d3au&nIuDe_lan9cZhV>hy@$yzv??_{#&YqBDU-E-<oG<EzWt0}
z|K)j1cFpF?jz_&upE*tIQ_X`t%ahM7+O}f-+D_%NxAMFBUyHu?_+R9`$#ZkmqfPAT
z#}4c3>U=vDTDR`kmlrF%i+S;vE&>W4%EV6S?s~WP`@I=vxltzO=HXxbPd3ie-F8Fi
z+s*X(Cluuu8!<82O)acFyed8B=EX&;m!(y{ou`zsY2%#yEXMhNnC8`#2Fm>Jex7{o
zkm+{k+sP^Kf1KQ?oE$JeFTWyR51Op;)jVcf8XEkk-aBBv?nMT3=+d{>Dre`*ZO;t-
zpvkC{6Df85Utw6x{}*p&*zDfP@w;U8>duGEQps1+dOvnvne@8Bu-5ysEGJ=Wq~|s?
zoOk=~WfP#v8g=_t_q147#id?(DY=9~$f3buCJRf=DV9u0!b%w!nWhQ|d|27C%9IE<
zv2aZBbU3iwX99TRH=%^A5CA$Z!fQnoQHz5|9Sv&hA`05kkVeTPqsfEv<WaWqS^fRZ
z8n<pMXJv)eM6Ub%ZBM|JBO4gE79Pp#)i(P;%ozd?a`hD+1TPJ*c=*FLb9tYFpJl)0
z?a9n`rZ1P<{>?F85-nr2ZJ}5F)LcYLMu|rhUufwnJP6KwnEE>2V&BRY4~nnIJzcw@
z_<zf_8CJX3uHXp~`Q-Wgt;H5QzFQmj{0`|nX@;*@hFQ3pgX6~<rl6IV<?qjBwtH*%
zZtvajD<31TZOX2Uoxi={->W&>ejL86Yq+4?S0^uW*1xA-c7pF^E(-ka3p}|z=>28<
zhgE<*)0oA{@gv0ZSJUoUm;AJu>@JJxX`Vjk9X#v#zT?r0wwWb;fBWiDr}*upz~ZP~
zYDxXMQc3SGYW<wTdW)C^XS^y34}w*HaQ`b$42(>_Gw*KkIrX?)FUI+If>*1l78aeH
zTT-$5dA(Qeu4j5NQq}LT2zXyUpL|}o({*j--j3Sx7jp0AmQM1Y8n>C4NJteI_@HT>
zd7XRSd?q`~g3llK26eA1dBgEz$xhb|>3{o#<Fa~J8c#p=Zt?D;4;o7i&0E{$d==*}
zd-iRL{Ho68V`cq!+qi$0{7s9&KZ65~_?$aTpmu}(|I&1>A4^)!AOHR;kfk;*^4g-+
zQ{HRZ9*ee||Kru9io{csZd9ghzmc~(@8X?naV<4+mCICTMO%g0)O?TIc=<x!(p(v0
zs;hfyVCw?^mp*S=RCNAg^?I2PJHPeC+*F_X#nW<5UtjD}{_OgDGm5NjtF9gMJG|@Y
zy4xl$+0i13^DVifAN!x*vdqg)aO+k<`C9+?H}X7cr~XU24Nd_B>b@z?4hNRYbY*Wm
zR$2a}!M|E&bNTs@<I8R1B4-3yy!><Pw)m3W!3We;Yd(FQ<!8J5+P6K5rT1UmT&!1i
zV^{Q^YM<{J(YNH*dV4F*SN(Wla`)n$rfcVHaz4Iqy+6-=pA+f2aWgduXNAUICx-*e
zz1Bb6Bl6^A<J`Um|0NCQCn;Soe*3n#`;_hSKX21EsywX;GFxu3ZRv;elSD3g-raU-
z|F=go_Mg8#ZOP}7j(er1hP#*Aruk)eUSGCtiCAp!$9Zpq4lJKB-^uQ@*3UC>7iKxx
zo!z)Yb&=iO&z-fuk4^jgdexWdw~1QhR?EUtbIm<p_TAr$xu1jgs6U$V{j1OZVAlDp
zxvmeM---@Cp#FD`Ro;h94d=TO{Q17<@P9Ai`u*f}vs8BSbjDKG2hXn^7eAJ)Z+3jQ
zyZJJ)*t^}!wcfoBIjP=WBUh7DsN*-a=2h^v=Tn-09X}AaGJm=wp>ZY-0fh~L+#Ekb
zUVi;!z*-a3r`}gt&-cT{Cw79?k0pg?b=Qj@zuYGo6!QM%iW{3375P8cvXgC`-=}4N
z``gOigLkc&tghP`*sCq!vitq^lJPd_TNAcx9$PiFCQiS#CP;ODTi(`>H~GJG+u63%
zOe?e`A|07|F*45A+B@z4p3*qM50+)~<5sGMuX?cAAoPRh@$9^rp)vM<TNa*Xw(~CL
zUN_~ECTmqufO>n`tsv3))4m){TUm8}gWuKiy0YVQX4q}lwc8c`UgFC7eLuRxxPF$b
zdh+?#pKBElKDxT9&OerC`cc1~zoYHfEG^9&L`7dLD@)C_&^Nm0;x!*kzNVq|V~NN)
zQ}gpa59fZfcsx0Jd0C9?)ygoL;0x+!&mNq2Y}c$8_XR$_TJ$Ys=W?|wUGAqko|FGS
zHs9P;sV;xV{?(;DL7elaI@xKeT)8E7an7^zUW)VoSLXzpEcde8TXp5Aef@^|lGES8
zCl+D!n9ycGK`m$hsc|QFZhyjM_qOoOzP;U#uLQBqzkmM3^v821x0iGMC<*zX$y!_F
zI)BPp%_h5_h3sb6T>3>$tn|OTHEz~TDe?QJ>Qd5K$!EfNH?CM}J4;Nz_t~{?Un(<o
z{GNLkTP~O-^Cz>v&18N4`CBVIzn`nI-OA~G{qs+8JChAwLfb%xA`vJb1R}&48RwT?
zjOyR{{GQGF6<3O51V41n*rd>!eQE0Idh@*;_iDZyD|c(zSiadDv_XCD^BTXvlj^lI
z?Wga1KXX^1?Uyf$DpH(+xn7B!o?2w{x~A@#Ve_@e>x;DsS*+mD;INd1rAAA2_o-d>
zKmOiXRDA8D=7Y)6MZU2Yrg6Pm(r`XM-q-l{WA^&(XFoOg^L>7@;Cz>X|EdR@XDvAY
z{@r}(+Un~^8|=Pb-0PleVs>qrmaS>v?5GM|PwuTtTR-hJzhkiU#`neS`I76;XLcXu
zo__4Kadgnu`Cn3hJzJB^zW&n@KVnL5Gd6I_Z&i9Qd6UWU_w%DmTz&LHKkUrR5`1>E
zYW~5C%lDazK3b{SWO3H}b&{L+_Ae!}&zHW=|GMKtqlk*vZ@J$S*M3%P`?^m5+s;4l
zeqNjuRr&XK;OtP(LqxS9UMnd)*sK@z+VK1D{obNAL8fzszr7D;$zC=^>&G1n)wQ?e
zp39hOPknQeaehdd`t<iJJrB++$>`oSL;COIpG%b&t=#)Nx~}PV{;ZHY)o<L}#m^h=
z@!$T)a@~&f#KJ$H+JEhTy7eypxn)Q^23RsO&Odc?-Ih<^>#Ubs=(E<SEpPDm`w&xl
z_;ldxeLugstBc)Vzs|}3irJAna>>bsf74!Wn-z0o`HB;pw;h*{{Z%9Q#PVIfyBOpA
zM9l}2#eZD2<?broSL0I2Waqn5>cSb;wMXw?y1IUsNX)H8@!MCdKU?1rC^W-zzv--~
z;^J*vr4O^2upQdE*@(a>5DUkiyR0lVtG=-PS7xs%Vx7<YOYFGJhfII_@V{w6SC)C%
z-naa;RBwLD(gXg!xjJj#PkmO}l6<S!WJUD*6`3#Ow|=c%r1v-a?vG3L_LH~wKkkzW
zeKTA8#}n@9;*9gZ{W#UmzUJMv(p`10Cl^1O5?|UfHLN^&`>t6x@(R9J{NGmlXiM|9
zo;Y61M_;bn_Wk_%x$r;t=j&1rUmBP7-s>&Rw!QB{uqXWBtv0A#TmD_%{3(~+X(qdu
z7M1@tHJtw{+<m}zrHa4ih2WK+ANSocdn<0Z$G`TY&Gh?owSFwozRL4s3Gej&wd^KG
zDj&NYkyEbL-~a9UkB1HNcCzQs$LzUQzpLSVRPaoKv3>6wxUJH9e{W&g#>?t_Z=$!H
z(9-(xL@f6D{(z8cFEh4Yl`~!08oF)^*de#p-KclDpLg`*r`^`8j?MWu@l*JRpSKdD
zkKVhzM&{1UyIWM$_Fa?NUs+Q2C-c*xLrd!WckTGiZGH6F-r^T8))&92xb}GCf}Ohi
zW@t&h-F^3!w&B#0vfHcDue`h%`lx{5rr6owA&|Iyz8_B>oKydw_O!v@eZg{(H!JUL
zEIy!ae|>-LmOqU1yZhut+xy<$Us`bQb5r#)@Tk;}e;u)GM_P~fy(xOPtZw7V)Xbdv
zXURwBR~|jNIC=iXe7O%dulW9{CD^(-z{SWoUsO!=@0YpKaq(gwUQYj(*+2cczGhVF
z)TpAXBH_gk=Y<?p{~PkF#^vH7?MIt-KNFu?v+vh-=F^|P-~aVwj>Xe(;qI;1L_VAp
zE;{l2#C$vH{yldBPd-0;%kSyWwYhIE2Fx$LcPnDk7TZ^+1AeO6yKmpM{h!R-`E{4p
zJiGDy&hjqr|G$6ACZCz`ZtnhXGr_G}d^P$HZE=AQD=*bE-2Zp>^-;h1HX5uoK|xQS
z{>(kyWV6)4zqEg6lYd<wujGf53if`XHT$Zg-9_h1|4a1QlU=cX>b(<3MCx|F*e6+d
z|MTbMS9hjmL|&3}zO=dj)*3^<JH-Jt8PnHkvrH8`**I_h-P!Nz6YFdYw`z(l|6MMB
z&G_4`W&Sc-e;>H9tKK>0--YbLtIC^`HphJ}JlT1BT3+qpkA3OSj`jAR?Ng7B6w%+e
z&4TUAn*O=l-UwFry^@`OxBNsj-ya)`LPwd>i^WIl`s-__C*3vAdB+4PqwrM6AHu<z
zDttb(-CNCo;zy2_6E4Z=KW*^0I<LE{=z?19idU5v7irrbPyKJb{>Hy-_ptp<{>%3N
z)GvPYe*KFTKZ@TSZ##bc{??nH%!_U|uRnS{f0m5q;?1`v-j0m@wK8}2np2-|HK~5Q
zsjYsDS<~V2)f-Bzt?O)4ckg(2e*N*va^LQne;;02?@!F)6P;Uo`pS+U|I_w8+<mDv
zw(VPw{Bp5m%Ze@Q9xpqde%wCJbR`GJ-imM5*S?m0=EN6~pvFd{Zw#nqt-quAfco|a
zT3SDJxPLrZaQ^r9bve<?elIuE=NEYT*KL`BcU>Q^?1z(z^VZ+9*jd57v+7*q?eDsF
z_y1kF^W)1?eX;q)AD*2k=ku9bUUl@rm8dsQuSY-H6jG`lzVGDYE6m$E^y?E&KPrA1
z&c`bIC*J>f%ggR=Z)^Uyg6{j06W+|wdUwX_;QTvcI^pkb+JwHXbdNIME*2eoK%IR;
zk$`6Z_nsG`$M>awmN4E??KAtj)Xr7sude*%FW3C5r2F^29l>96R_LC){w;i6z?ZYL
zmmj-O$NTX?__1SOw!C|Px$eAAyvX_UIeog9@9#eyX8ZWV+~3DHF!E;aUQ<apYpN-M
zic;~)b6;geYwW%@{&U^%Y-y$UB}377p7uKz`7dR*`|caL=Te>WuWQe9A72VNs6PF}
z&s)dCLe53XPm-Bp3CfzPdRBEIGFD}0b+`EKez$bTH-Fi;r{#W~I=3-({}n5pUg5f*
zPIo@v+4ExRAtUp;vfnrAPMl&~A@jiU+4J*9|L@(QP-TAYSn&NDy5f#ecAsWdzP0JQ
zQR?vL!-|I&BlZ`4c=phfJE$Wg=}cZ!(3#g-4=(Slz2;fX+huIOrSwYKE%o~ms}4-I
zum89}_i;Sm9i{r1*B{r0$i7&<viFAdws(^MKbc31o&WpmP+$71Jsx~~wSPCPeI)$;
z?w-%7^NCJAKYAJGUs<I6_la1n>*{qPUsj&_xvADoclCqfmvg1{9!y^SqUO!=^J2O?
zw%y%hcx?W*%b&Izruup7_-f9Z$6LCw^1X=LtE4BVEaP|md-`bh|L^OQr-yI%tXz8I
zH@p9_DK~X5u6K{M`S5h3CQHcmqg;afeR8+&`*>UPXn8DaP2Y|JCmXA!nr{5B<hIY<
z<!o|g{iJu1+g{yY8gN-x^Uf4z&;CER&#k_@es#OW*H@l}hm$vVi^Y0hx<6-ry$_ek
zTgz4DCH@PSfM%P%@3+{$W8VA!L0p2hb+XPbv2R}!oV-@}@C`KVe5v}^we{AwEauM8
z`tfARu_ZrOI(c&yl}wp?QvTA4M?X)biq`1uEY92b_4?|NgX-<!%g*QPuKE^ZP#0yg
zRYzCrQOx)9<gRbwM-Q)gy1sh;eEH*lAN@@FW;*|--nU!J%0F6e-%<6w{C`l*zdLo#
zkM8qH?z$x!efw7T&Yel;Rx!?JJ)67nab&;v_qwMK7Jl^q%^&&JYUk2x_DjOzD*t>d
zzAb*WBFwsSs=nPnd)cWSpPt@ndcDfOzwaTlboi{&|J<J+U&)T^nt5_vbgb{4d57E<
z2hTRZen2{Mmbvi-+)(Q4Zt&;YKBuBU^TA}TA4|4)uWUNM@35BiwH@VNpS^zfo?5%%
z(m&S&>bBRf_iNR6uVb`*y|{Y&RPB3bGPAl}*LqK1{d`;0|5;j>=2RV+bvtV7(o<%Z
z5+?b9(PyIXe0<-(lIa5L<K^PnrF=hZrbOk}zDYkXdR^b5Dy1f6JLBo^uU{SB(LJx5
zT}`jT`M~qe@L7+V#eFpLeqL+e-gmeC>#JAa9^G0JdG_PZ)oP;iucw_q$6fp3xNy>=
z?C#*Di}DJOo?JXVT<MjKdi}o7Gj|qVTB<KLo&WyM`ae&01g`cg^lKng9p*HF8#^o0
z<ELx?*m8V%&;j-EjWbR3LqD8Uejb0Raw)T2{fs?3ZmipKe?`ba^<3%c_YBQtZ$G}@
ze{0X<-(UaKW@iPLdS!)gHB;XH^w+=RZfmv`o!2goezgC;fwG*>!`b3N49ikI>mIFh
zf8KE3w0@3g{GU?y*Xtnl>5o^<mX%v=%<pf`Vx52A&aS#LWBKdY-TR_Wibb_AH@NUP
zcy^M@st?8Yr-yAZdHu_ih><NbR&amis3_xnMpxCjo}YtQ=YI)a^&oiiB=f5__tio_
zoD^-bVzQgaWcPIa1LM5!jT`??kkjV8e$B1N=iwCDZ7&3)zvsVr5wPu2Pv7J_pI*&h
zKXXgaisj+XxjZjI<^NV+alQYp^k{ki5-q#R622dIrZidp-?3)axvMKnuirZzRbIO0
z&$0XeOTI4I@p0qLe2yP6zn5QsyybPAR^ExVn|GCa^Y0gX{GvQptbYIb2U}<Cd>6d0
z<nQUiugaUdwxtQ5yOX<ie&*fsB6fmR`i6}hpb-+^Ikj)IH4g~8vd-W0^hglve66?f
zIg{lT!g;)u!#|vSJSpa&I&1Ad!*zc|Yaj)=*;bY4<A$Yv-ZCZkE^k~=nJM_}=cj|t
zj~~eXK00CF%C!;83*UeK{CG#aO?=EtnGYvL^NN<vwy7(4^1<TQ-E2O6*}{h{6(wGm
zrJ3ybmxsl>>t%l}J=uBt7^p_Qc4xx=bNec@{=C^Ic~sfv+t%2m1TGuN4Q9_bGB9vo
z@^o<wLC%7pDjdV32bO^bqnCc)t@OZH;q8q$mYSl~>lQWnTivgZ_}*oA(sre5`18Np
zG+Ar%-e+9gYRFn+6@KpLPtMy%4qAVGeMv3+?#Zj=pI*p(n7Mm}ZkgThkB@!@zL$}(
zmoZ=T<IdIf*Tr-?_wN6nqLUT-tF6KR-@Cc@>lW>J`^CBKnEgBRC974hy^gx~*uC6W
z`<g{g&i;z~+iI`vxOZ~;K8bQ0V{^0jvGVo*Ug>4edF@TGE0b^;QndbgW-2RM<7c&`
zKJaAvqdTgy*3Y}FG+%7~|KSu{&9VJ^Dwh7;_A)%4rA}{Wvfsx4=63r&hJ5(>E_eNr
z{`WKEY~IgWb*1L(v6F>2o7anewqmdO)Y`xFlr{fSE}O4gO$*OwS|9sxMQqLLk7w`u
z_jbQ~zoKKa>nedSA6{CoH+gG&|F1Ww(P6!8TGIAEm%jy0zxFyyCo{X>QZr(Td!GEY
zfcszfguc&>zBTWVhyRi+*Id`Fi(|fKlqUasw5{U*PXD8?xq~${x5}P=dz^;|AA=j$
z)^UO#UaolXIVtO6=&BW$KPo=WnHKtG<*}b;e|Ig739ODOist&UWTPQ#P2JZE*@eG&
zCwD)Oip^dlbI<Zu{k(ovO@+zFS250SkB^dY|M%tQqum#qcO5@(ztJ~m^Utmc{@eC_
z;J^I%cljPE%aqCP;f(WF%gq%1U-kF&(eLs0IjevCu4NOSZ~Z^Z_u;(BL8)`A=gk)H
z{krwzf$7J^M9ZwsM_zs&6gp2vZr76|xk>xq?#g5Rwsp4J@umDFEVK5_kLs8GthV;}
zwJpov!zMCtCfUaA{oonstC1_4{Q2I^DS6SLw0|<QopjL?F1wvY7mjX!4jTA6cCq=?
zCyVWNmg;^#uO3NS8`Jyj!p6VXEAKu}*X!e-^W8`A-pREq?50O0%WiSrFEMe|2cLO&
zWp=h+_y1?0+_t34T7Un&m^J&e4yecf`D3bo^lSgVxSIQ`7n<F(URB<6ca!@WpWKcA
zOezy?tZNHpur4hU6Mg+8;4G+JW!Su1{PiEpwZ%sdZ|*AapZ5W_uxQ5aZTsiVo;dIE
zA<m5(QZt`C|MRCY`bcLrU)Q{s#d5*Vw;b7?H&beV^&;h-rB&x|otlO9o&x0TY{m;N
zi;r(!cW!EU(Sh`YK+ESxuPoBO-m7U^WVPUs?yh%!y1T62Z#QJG`K0~xX07p~H?x;N
z>p$&Y8|(WdETU4zU|Ig0x)T?aY9^oG&GqAnmhJQY`C`xS{mjzQzBGBcp1l0cT!%U4
zc`ktq)!W;4as7C5($eM2O>Om~kAr7VyFYvN+bLTAr|3QVS~um|>D+_YN}qf<w=&#6
zDsJKmHC@9k@y;eoFPwj~Of+#rOz(?J{<)x0mNl=%o`DZNNA?LuO2`iedu@mD`gxHd
zXDnZCxUxu_)j#fpXpL9r>=K&-7f?wRtNGw^<^J5?*Ttu{=<UocE42AMqj!0eKj))q
zA-pfFx9<}YPA?64dGdPuaxFXdw-?NdcCR_PIXY?o|C&`Z?u8y$zU5r-dc7`oHNB4g
zdoGE5o<04ToO0FCc{^vFzcA1B>%7bBs#mVy+On&`KTe&!yKX|0lew*(^|B>hR+cs)
zQoHl6ZqB&-bz!X4D#oen*1t9k|MWAB%e1$??4ESq*~Ue8<lb!Ae{)d=^S3rmB34_>
zUIR+%ac{dC&L0rjlKEcbgXhwyq9_&dT1_VVtCr^(=kK|Hbo*J)+uPlDGTBXifVx;n
z>${wK{I8@tAJ5!5akUV%P$+-bpFc-)4Ha7ptCovJMKAZV+AIC~-j{i$Gbc2A@ASRN
z{W3nT`nTfU<TDfGTz{`CjXWMhMDYVDaBV)Xn&~>>*^|RX-RnXQs&9R9YeI6#{*Z&}
zwg--GU&dwkvLbAz){mSM`&WLx=kFgqB`SKWsAyHu)_GTZ@1(und%xOf+4=0=J4vsb
z7Q3&@TlE@e0RT@Ujl7_)mg={sjPv=IHTZj73E7!&KI^+Slikb8b5`4Iba$;f@^jhk
zIreo`HSfQLcU6kZ+H3L2-rj$@`rOXctUpigNggeKUQ-cKQ*{39?m5qu;3nf_BshcT
zKL7P-r;AK2Dq@}AoB8L{w3{yrZv`Jn|8VR}#OuF0mxEmA@z42QawhVM7^to|vhHv4
z_r$%AWM9VTd75R0dB=QvaHitN($=GKJ5QYtoi8U_nz@dM`I#FtSU`h}X6JTnTI?F`
zd-l^UTh|LI$(Hx8FxmawYWMTiB8z|G=Z~*x&CYAzcKpP>kCT(#k1epfyXs4PGcj|a
z+4>3(Hh&9yZTeX{yktvb)OuH~iqGc#x3_5hn6g4_n@(@`e+%t(^(AFK^X|s9)b6@^
z^~eXtUc;=-$9}kEoh&^tW8c!3eMH1sub;z#^u^Vxaw{e=t<8PwdV1ZW2|=pno6K;A
zI=n@_z=w&+F12Y34`HPZ42@o(#+uXBS%lrh$i#9AH1DkDaasUt`v|Q`zoMm~!Cy6G
uttZ@Nco?IOMh%?NkVdK5NKGDp>gRM;X@+kXv0`9gVDNPHb6Mw<&;$T6%~Xj1

literal 0
HcmV?d00001

diff --git a/career/img/file.txt b/career/img/file.txt
new file mode 100644
index 0000000..e69de29
diff --git a/career/img/numoc-16-9-blanc.png b/career/img/numoc-16-9-blanc.png
new file mode 100644
index 0000000000000000000000000000000000000000..e877fb5f7e5d52c439bdcf5882a2f1ce4c429d93
GIT binary patch
literal 86910
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%0Axidp8oL(2N+Od)S
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

literal 0
HcmV?d00001

diff --git a/career/img/rose-rose.jpg b/career/img/rose-rose.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..77b23e9704a58b1ec1c5399d56357d600c9b3546
GIT binary patch
literal 45517
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

literal 0
HcmV?d00001

diff --git a/career/index.php b/career/index.php
new file mode 100644
index 0000000..87fb3fa
--- /dev/null
+++ b/career/index.php
@@ -0,0 +1,12 @@
+<?php
+	header('HTTP/1.0 403 Forbidden');
+	
+	require_once('../../config.php');
+	
+	$PAGE->set_url($_SERVER['PHP_SELF']);
+	$PAGE->set_pagelayout('admin');
+	$PAGE->set_context(context_system::instance());
+	echo $OUTPUT->header();
+	echo $OUTPUT->heading(get_string('error'));
+	echo '<center>' . get_string('nopermissiontoshow', 'core_error') . '</center>';
+?>
\ No newline at end of file
diff --git a/career/js/file.js b/career/js/file.js
new file mode 100644
index 0000000..767b3fe
--- /dev/null
+++ b/career/js/file.js
@@ -0,0 +1,48 @@
+(function () {
+    $('#btnRight').click(function (e) {
+        var selectedOpts = $('#lstBox1 option:selected');
+        if (selectedOpts.length == 0) {
+            alert("Nothing to move.");
+            e.preventDefault();
+        }
+        $('#lstBox2').append($(selectedOpts).clone());
+        // $(selectedOpts).remove();
+        e.preventDefault();
+    });
+    $('#btnAllRight').click(function (e) {
+        var selectedOpts = $('#lstBox1 option');
+        if (selectedOpts.length == 0) {
+            alert("Nothing to move.");
+            e.preventDefault();
+        }
+        $('#lstBox2').append($(selectedOpts).clone());
+        // $(selectedOpts).remove();
+        e.preventDefault();
+    });
+    $('#btnLeft').click(function (e) {
+        var selectedOpts = $('#lstBox2 option:selected');
+        if (selectedOpts.length == 0) {
+            alert("Nothing to move.");
+            e.preventDefault();
+        }
+        // $('#lstBox1').append($(selectedOpts).clone());
+        $(selectedOpts).remove();
+        e.preventDefault();
+    });
+    $('#btnAllLeft').click(function (e) {
+        var selectedOpts = $('#lstBox2 option');
+        if (selectedOpts.length == 0) {
+            alert("Nothing to move.");
+            e.preventDefault();
+        }
+        // $('#lstBox1').append($(selectedOpts).clone());
+        $(selectedOpts).remove();
+        e.preventDefault();
+    });
+    $('.wrapper').find('a[href="#"]').on('click', function (e) {
+        e.preventDefault();
+        this.expand = !this.expand;
+        $(this).text(this.expand?"Réduire":"Voir la description compléte");
+        $(this).closest('.wrapper').find('.small, .big').toggleClass('small big');
+    });
+}(jQuery));
\ No newline at end of file
diff --git a/career/js/interact.min.js b/career/js/interact.min.js
new file mode 100644
index 0000000..4fdef50
--- /dev/null
+++ b/career/js/interact.min.js
@@ -0,0 +1,5 @@
+/* interact.js v1.3.3 | https://raw.github.com/taye/interact.js/master/LICENSE */
+!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.interact=t()}}(function(){return function t(e,n,r){function i(s,a){if(!n[s]){if(!e[s]){var c="function"==typeof require&&require;if(!a&&c)return c(s,!0);if(o)return o(s,!0);var l=new Error("Cannot find module '"+s+"'");throw l.code="MODULE_NOT_FOUND",l}var p=n[s]={exports:{}};e[s][0].call(p.exports,function(t){var n=e[s][1][t];return i(n||t)},p,p.exports,t,e,n,r)}return n[s].exports}for(var o="function"==typeof require&&require,s=0;s<r.length;s++)i(r[s]);return i}({1:[function(t,e,n){"use strict";"undefined"==typeof window?e.exports=function(e){return t("./src/utils/window").init(e),t("./src/index")}:e.exports=t("./src/index")},{"./src/index":19,"./src/utils/window":52}],2:[function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){for(var n=0;n<e.length;n++){var r;r=e[n];var i=r;if(t.immediatePropagationStopped)break;i(t)}}var o=t("./utils/extend.js"),s=function(){function t(e){r(this,t),this.options=o({},e||{})}return t.prototype.fire=function(t){var e=void 0,n="on"+t.type,r=this.global;(e=this[t.type])&&i(t,e),this[n]&&this[n](t),!t.propagationStopped&&r&&(e=r[t.type])&&i(t,e)},t.prototype.on=function(t,e){this[t]?this[t].push(e):this[t]=[e]},t.prototype.off=function(t,e){var n=this[t],r=n?n.indexOf(e):-1;-1!==r&&n.splice(r,1),(n&&0===n.length||!e)&&(this[t]=void 0)},t}();e.exports=s},{"./utils/extend.js":41}],3:[function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var i=t("./utils/extend"),o=t("./utils/getOriginXY"),s=t("./defaultOptions"),a=t("./utils/Signals").new(),c=function(){function t(e,n,c,l,p,u){var d=arguments.length>6&&void 0!==arguments[6]&&arguments[6];r(this,t);var f=e.target,v=(f&&f.options||s).deltaSource,g=o(f,p,c),h="start"===l,m="end"===l,y=h?e.startCoords:e.curCoords,x=e.prevEvent;p=p||e.element;var b=i({},y.page),w=i({},y.client);b.x-=g.x,b.y-=g.y,w.x-=g.x,w.y-=g.y,this.ctrlKey=n.ctrlKey,this.altKey=n.altKey,this.shiftKey=n.shiftKey,this.metaKey=n.metaKey,this.button=n.button,this.buttons=n.buttons,this.target=p,this.currentTarget=p,this.relatedTarget=u||null,this.preEnd=d,this.type=c+(l||""),this.interaction=e,this.interactable=f,this.t0=h?e.downTimes[e.downTimes.length-1]:x.t0;var E={interaction:e,event:n,action:c,phase:l,element:p,related:u,page:b,client:w,coords:y,starting:h,ending:m,deltaSource:v,iEvent:this};a.fire("set-xy",E),m?(this.pageX=x.pageX,this.pageY=x.pageY,this.clientX=x.clientX,this.clientY=x.clientY):(this.pageX=b.x,this.pageY=b.y,this.clientX=w.x,this.clientY=w.y),this.x0=e.startCoords.page.x-g.x,this.y0=e.startCoords.page.y-g.y,this.clientX0=e.startCoords.client.x-g.x,this.clientY0=e.startCoords.client.y-g.y,a.fire("set-delta",E),this.timeStamp=y.timeStamp,this.dt=e.pointerDelta.timeStamp,this.duration=this.timeStamp-this.t0,this.speed=e.pointerDelta[v].speed,this.velocityX=e.pointerDelta[v].vx,this.velocityY=e.pointerDelta[v].vy,this.swipe=m||"inertiastart"===l?this.getSwipe():null,a.fire("new",E)}return t.prototype.getSwipe=function(){var t=this.interaction;if(t.prevEvent.speed<600||this.timeStamp-t.prevEvent.timeStamp>150)return null;var e=180*Math.atan2(t.prevEvent.velocityY,t.prevEvent.velocityX)/Math.PI;e<0&&(e+=360);var n=112.5<=e&&e<247.5,r=202.5<=e&&e<337.5,i=!n&&(292.5<=e||e<67.5);return{up:r,down:!r&&22.5<=e&&e<157.5,left:n,right:i,angle:e,speed:t.prevEvent.speed,velocity:{x:t.prevEvent.velocityX,y:t.prevEvent.velocityY}}},t.prototype.preventDefault=function(){},t.prototype.stopImmediatePropagation=function(){this.immediatePropagationStopped=this.propagationStopped=!0},t.prototype.stopPropagation=function(){this.propagationStopped=!0},t}();a.on("set-delta",function(t){var e=t.iEvent,n=t.interaction,r=t.starting,i=t.deltaSource,o=r?e:n.prevEvent;"client"===i?(e.dx=e.clientX-o.clientX,e.dy=e.clientY-o.clientY):(e.dx=e.pageX-o.pageX,e.dy=e.pageY-o.pageY)}),c.signals=a,e.exports=c},{"./defaultOptions":18,"./utils/Signals":34,"./utils/extend":41,"./utils/getOriginXY":42}],4:[function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var i=t("./utils/clone"),o=t("./utils/is"),s=t("./utils/events"),a=t("./utils/extend"),c=t("./actions/base"),l=t("./scope"),p=t("./Eventable"),u=t("./defaultOptions"),d=t("./utils/Signals").new(),f=t("./utils/domUtils"),v=f.getElementRect,g=f.nodeContains,h=f.trySelector,m=f.matchesSelector,y=t("./utils/window"),x=y.getWindow,b=t("./utils/arr"),w=b.contains,E=t("./utils/browser"),T=E.wheelEvent;l.interactables=[];var S=function(){function t(e,n){r(this,t),n=n||{},this.target=e,this.events=new p,this._context=n.context||l.document,this._win=x(h(e)?this._context:e),this._doc=this._win.document,d.fire("new",{target:e,options:n,interactable:this,win:this._win}),l.addDocument(this._doc,this._win),l.interactables.push(this),this.set(n)}return t.prototype.setOnEvents=function(t,e){var n="on"+t;return o.function(e.onstart)&&(this.events[n+"start"]=e.onstart),o.function(e.onmove)&&(this.events[n+"move"]=e.onmove),o.function(e.onend)&&(this.events[n+"end"]=e.onend),o.function(e.oninertiastart)&&(this.events[n+"inertiastart"]=e.oninertiastart),this},t.prototype.setPerAction=function(t,e){for(var n in e)n in u[t]&&(o.object(e[n])?(this.options[t][n]=i(this.options[t][n]||{}),a(this.options[t][n],e[n]),o.object(u.perAction[n])&&"enabled"in u.perAction[n]&&(this.options[t][n].enabled=!1!==e[n].enabled)):o.bool(e[n])&&o.object(u.perAction[n])?this.options[t][n].enabled=e[n]:void 0!==e[n]&&(this.options[t][n]=e[n]))},t.prototype.getRect=function(t){return t=t||this.target,o.string(this.target)&&!o.element(t)&&(t=this._context.querySelector(this.target)),v(t)},t.prototype.rectChecker=function(t){return o.function(t)?(this.getRect=t,this):null===t?(delete this.options.getRect,this):this.getRect},t.prototype._backCompatOption=function(t,e){if(h(e)||o.object(e)){this.options[t]=e;for(var n=0;n<c.names.length;n++){var r;r=c.names[n];var i=r;this.options[i][t]=e}return this}return this.options[t]},t.prototype.origin=function(t){return this._backCompatOption("origin",t)},t.prototype.deltaSource=function(t){return"page"===t||"client"===t?(this.options.deltaSource=t,this):this.options.deltaSource},t.prototype.context=function(){return this._context},t.prototype.inContext=function(t){return this._context===t.ownerDocument||g(this._context,t)},t.prototype.fire=function(t){return this.events.fire(t),this},t.prototype._onOffMultiple=function(t,e,n,r){if(o.string(e)&&-1!==e.search(" ")&&(e=e.trim().split(/ +/)),o.array(e)){for(var i=0;i<e.length;i++){var s;s=e[i];var a=s;this[t](a,n,r)}return!0}if(o.object(e)){for(var c in e)this[t](c,e[c],n);return!0}},t.prototype.on=function(e,n,r){return this._onOffMultiple("on",e,n,r)?this:("wheel"===e&&(e=T),w(t.eventTypes,e)?this.events.on(e,n):o.string(this.target)?s.addDelegate(this.target,this._context,e,n,r):s.add(this.target,e,n,r),this)},t.prototype.off=function(e,n,r){return this._onOffMultiple("off",e,n,r)?this:("wheel"===e&&(e=T),w(t.eventTypes,e)?this.events.off(e,n):o.string(this.target)?s.removeDelegate(this.target,this._context,e,n,r):s.remove(this.target,e,n,r),this)},t.prototype.set=function(e){o.object(e)||(e={}),this.options=i(u.base);var n=i(u.perAction);for(var r in c.methodDict){var s=c.methodDict[r];this.options[r]=i(u[r]),this.setPerAction(r,n),this[s](e[r])}for(var a=0;a<t.settingsMethods.length;a++){var l;l=t.settingsMethods[a];var p=l;this.options[p]=u.base[p],p in e&&this[p](e[p])}return d.fire("set",{options:e,interactable:this}),this},t.prototype.unset=function(){if(s.remove(this.target,"all"),o.string(this.target))for(var t in s.delegatedEvents){var e=s.delegatedEvents[t];e.selectors[0]===this.target&&e.contexts[0]===this._context&&(e.selectors.splice(0,1),e.contexts.splice(0,1),e.listeners.splice(0,1),e.selectors.length||(e[t]=null)),s.remove(this._context,t,s.delegateListener),s.remove(this._context,t,s.delegateUseCapture,!0)}else s.remove(this,"all");d.fire("unset",{interactable:this}),l.interactables.splice(l.interactables.indexOf(this),1);for(var n=0;n<(l.interactions||[]).length;n++){var r;r=(l.interactions||[])[n];var i=r;i.target===this&&i.interacting()&&!i._ending&&i.stop()}return l.interact},t}();l.interactables.indexOfElement=function(t,e){e=e||l.document;for(var n=0;n<this.length;n++){var r=this[n];if(r.target===t&&r._context===e)return n}return-1},l.interactables.get=function(t,e,n){var r=this[this.indexOfElement(t,e&&e.context)];return r&&(o.string(t)||n||r.inContext(t))?r:null},l.interactables.forEachMatch=function(t,e){for(var n=0;n<this.length;n++){var r;r=this[n];var i=r,s=void 0;if((o.string(i.target)?o.element(t)&&m(t,i.target):t===i.target)&&i.inContext(t)&&(s=e(i)),void 0!==s)return s}},S.eventTypes=l.eventTypes=[],S.signals=d,S.settingsMethods=["deltaSource","origin","preventDefault","rectChecker"],e.exports=S},{"./Eventable":2,"./actions/base":6,"./defaultOptions":18,"./scope":33,"./utils/Signals":34,"./utils/arr":35,"./utils/browser":36,"./utils/clone":37,"./utils/domUtils":39,"./utils/events":40,"./utils/extend":41,"./utils/is":46,"./utils/window":52}],5:[function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t){return function(e){var n=c.getPointerType(e),r=c.getEventTargets(e),i=r[0],o=r[1],s=[];if(p.supportsTouch&&/touch/.test(e.type)){h=(new Date).getTime();for(var l=0;l<e.changedTouches.length;l++){var u;u=e.changedTouches[l];var f=u,v=f,g=d.search(v,e.type,i);s.push([v,g||new m({pointerType:n})])}}else{var y=!1;if(!p.supportsPointerEvent&&/mouse/.test(e.type)){for(var x=0;x<a.interactions.length&&!y;x++)y="mouse"!==a.interactions[x].pointerType&&a.interactions[x].pointerIsDown;y=y||(new Date).getTime()-h<500||0===e.timeStamp}if(!y){var b=d.search(e,e.type,i);b||(b=new m({pointerType:n})),s.push([e,b])}}for(var w=0;w<s.length;w++){var E=s[w],T=E[0],S=E[1];S._updateEventTargets(i,o),S[t](T,e,i,o)}}}function o(t){for(var e=0;e<a.interactions.length;e++){var n;n=a.interactions[e];var r=n;r.end(t),f.fire("endall",{event:t,interaction:r})}}function s(t,e){var n=t.doc,r=0===e.indexOf("add")?l.add:l.remove;for(var i in a.delegatedEvents)r(n,i,l.delegateListener),r(n,i,l.delegateUseCapture,!0);for(var o in b)r(n,o,b[o])}var a=t("./scope"),c=t("./utils"),l=t("./utils/events"),p=t("./utils/browser"),u=t("./utils/domObjects"),d=t("./utils/interactionFinder"),f=t("./utils/Signals").new(),v={},g=["pointerDown","pointerMove","pointerUp","updatePointer","removePointer"],h=0;a.interactions=[];for(var m=function(){function t(e){var n=e.pointerType;r(this,t),this.target=null,this.element=null,this.prepared={name:null,axis:null,edges:null},this.pointers=[],this.pointerIds=[],this.downTargets=[],this.downTimes=[],this.prevCoords={page:{x:0,y:0},client:{x:0,y:0},timeStamp:0},this.curCoords={page:{x:0,y:0},client:{x:0,y:0},timeStamp:0},this.startCoords={page:{x:0,y:0},client:{x:0,y:0},timeStamp:0},this.pointerDelta={page:{x:0,y:0,vx:0,vy:0,speed:0},client:{x:0,y:0,vx:0,vy:0,speed:0},timeStamp:0},this.downEvent=null,this.downPointer={},this._eventTarget=null,this._curEventTarget=null,this.prevEvent=null,this.pointerIsDown=!1,this.pointerWasMoved=!1,this._interacting=!1,this._ending=!1,this.pointerType=n,f.fire("new",this),a.interactions.push(this)}return t.prototype.pointerDown=function(t,e,n){var r=this.updatePointer(t,e,!0);f.fire("down",{pointer:t,event:e,eventTarget:n,pointerIndex:r,interaction:this})},t.prototype.start=function(t,e,n){this.interacting()||!this.pointerIsDown||this.pointerIds.length<("gesture"===t.name?2:1)||(-1===a.interactions.indexOf(this)&&a.interactions.push(this),c.copyAction(this.prepared,t),this.target=e,this.element=n,f.fire("action-start",{interaction:this,event:this.downEvent}))},t.prototype.pointerMove=function(e,n,r){this.simulation||(this.updatePointer(e),c.setCoords(this.curCoords,this.pointers));var i=this.curCoords.page.x===this.prevCoords.page.x&&this.curCoords.page.y===this.prevCoords.page.y&&this.curCoords.client.x===this.prevCoords.client.x&&this.curCoords.client.y===this.prevCoords.client.y,o=void 0,s=void 0;this.pointerIsDown&&!this.pointerWasMoved&&(o=this.curCoords.client.x-this.startCoords.client.x,s=this.curCoords.client.y-this.startCoords.client.y,this.pointerWasMoved=c.hypot(o,s)>t.pointerMoveTolerance);var a={pointer:e,pointerIndex:this.getPointerIndex(e),event:n,eventTarget:r,dx:o,dy:s,duplicate:i,interaction:this,interactingBeforeMove:this.interacting()};i||c.setCoordDeltas(this.pointerDelta,this.prevCoords,this.curCoords),f.fire("move",a),i||(this.interacting()&&this.doMove(a),this.pointerWasMoved&&c.copyCoords(this.prevCoords,this.curCoords))},t.prototype.doMove=function(t){t=c.extend({pointer:this.pointers[0],event:this.prevEvent,eventTarget:this._eventTarget,interaction:this},t||{}),f.fire("before-action-move",t),this._dontFireMove||f.fire("action-move",t),this._dontFireMove=!1},t.prototype.pointerUp=function(t,e,n,r){var i=this.getPointerIndex(t);f.fire(/cancel$/i.test(e.type)?"cancel":"up",{pointer:t,pointerIndex:i,event:e,eventTarget:n,curEventTarget:r,interaction:this}),this.simulation||this.end(e),this.pointerIsDown=!1,this.removePointer(t,e)},t.prototype.end=function(t){this._ending=!0,t=t||this.prevEvent,this.interacting()&&f.fire("action-end",{event:t,interaction:this}),this.stop(),this._ending=!1},t.prototype.currentAction=function(){return this._interacting?this.prepared.name:null},t.prototype.interacting=function(){return this._interacting},t.prototype.stop=function(){f.fire("stop",{interaction:this}),this._interacting&&(f.fire("stop-active",{interaction:this}),f.fire("stop-"+this.prepared.name,{interaction:this})),this.target=this.element=null,this._interacting=!1,this.prepared.name=this.prevEvent=null},t.prototype.getPointerIndex=function(t){return"mouse"===this.pointerType||"pen"===this.pointerType?0:this.pointerIds.indexOf(c.getPointerId(t))},t.prototype.updatePointer=function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:e&&/(down|start)$/i.test(e.type),r=c.getPointerId(t),i=this.getPointerIndex(t);return-1===i&&(i=this.pointerIds.length,this.pointerIds[i]=r),n&&f.fire("update-pointer-down",{pointer:t,event:e,down:n,pointerId:r,pointerIndex:i,interaction:this}),this.pointers[i]=t,i},t.prototype.removePointer=function(t,e){var n=this.getPointerIndex(t);-1!==n&&(f.fire("remove-pointer",{pointer:t,event:e,pointerIndex:n,interaction:this}),this.pointers.splice(n,1),this.pointerIds.splice(n,1),this.downTargets.splice(n,1),this.downTimes.splice(n,1))},t.prototype._updateEventTargets=function(t,e){this._eventTarget=t,this._curEventTarget=e},t}(),y=0;y<g.length;y++){var x=g[y];v[x]=i(x)}var b={},w=p.pEventTypes;u.PointerEvent?(b[w.down]=v.pointerDown,b[w.move]=v.pointerMove,b[w.up]=v.pointerUp,b[w.cancel]=v.pointerUp):(b.mousedown=v.pointerDown,b.mousemove=v.pointerMove,b.mouseup=v.pointerUp,b.touchstart=v.pointerDown,b.touchmove=v.pointerMove,b.touchend=v.pointerUp,b.touchcancel=v.pointerUp),b.blur=o,f.on("update-pointer-down",function(t){var e=t.interaction,n=t.pointer,r=t.pointerId,i=t.pointerIndex,o=t.event,s=t.eventTarget,a=t.down;e.pointerIds[i]=r,e.pointers[i]=n,a&&(e.pointerIsDown=!0),e.interacting()||(c.setCoords(e.startCoords,e.pointers),c.copyCoords(e.curCoords,e.startCoords),c.copyCoords(e.prevCoords,e.startCoords),e.downEvent=o,e.downTimes[i]=e.curCoords.timeStamp,e.downTargets[i]=s||o&&c.getEventTargets(o)[0],e.pointerWasMoved=!1,c.pointerExtend(e.downPointer,n))}),a.signals.on("add-document",s),a.signals.on("remove-document",s),m.pointerMoveTolerance=1,m.doOnInteractions=i,m.endAll=o,m.signals=f,m.docEvents=b,a.endAllInteractions=o,e.exports=m},{"./scope":33,"./utils":44,"./utils/Signals":34,"./utils/browser":36,"./utils/domObjects":38,"./utils/events":40,"./utils/interactionFinder":45}],6:[function(t,e,n){"use strict";function r(t,e,n,r){var i=t.prepared.name,s=new o(t,e,i,n,t.element,null,r);t.target.fire(s),t.prevEvent=s}var i=t("../Interaction"),o=t("../InteractEvent"),s={firePrepared:r,names:[],methodDict:{}};i.signals.on("action-start",function(t){var e=t.interaction,n=t.event;e._interacting=!0,r(e,n,"start")}),i.signals.on("action-move",function(t){var e=t.interaction;if(r(e,t.event,"move",t.preEnd),!e.interacting())return!1}),i.signals.on("action-end",function(t){r(t.interaction,t.event,"end")}),e.exports=s},{"../InteractEvent":3,"../Interaction":5}],7:[function(t,e,n){"use strict";var r=t("./base"),i=t("../utils"),o=t("../InteractEvent"),s=t("../Interactable"),a=t("../Interaction"),c=t("../defaultOptions"),l={defaults:{enabled:!1,mouseButtons:null,origin:null,snap:null,restrict:null,inertia:null,autoScroll:null,startAxis:"xy",lockAxis:"xy"},checker:function(t,e,n){var r=n.options.drag;return r.enabled?{name:"drag",axis:"start"===r.lockAxis?r.startAxis:r.lockAxis}:null},getCursor:function(){return"move"}};a.signals.on("before-action-move",function(t){var e=t.interaction;if("drag"===e.prepared.name){var n=e.prepared.axis;"x"===n?(e.curCoords.page.y=e.startCoords.page.y,e.curCoords.client.y=e.startCoords.client.y,e.pointerDelta.page.speed=Math.abs(e.pointerDelta.page.vx),e.pointerDelta.client.speed=Math.abs(e.pointerDelta.client.vx),e.pointerDelta.client.vy=0,e.pointerDelta.page.vy=0):"y"===n&&(e.curCoords.page.x=e.startCoords.page.x,e.curCoords.client.x=e.startCoords.client.x,e.pointerDelta.page.speed=Math.abs(e.pointerDelta.page.vy),e.pointerDelta.client.speed=Math.abs(e.pointerDelta.client.vy),e.pointerDelta.client.vx=0,e.pointerDelta.page.vx=0)}}),o.signals.on("new",function(t){var e=t.iEvent,n=t.interaction;if("dragmove"===e.type){var r=n.prepared.axis;"x"===r?(e.pageY=n.startCoords.page.y,e.clientY=n.startCoords.client.y,e.dy=0):"y"===r&&(e.pageX=n.startCoords.page.x,e.clientX=n.startCoords.client.x,e.dx=0)}}),s.prototype.draggable=function(t){return i.is.object(t)?(this.options.drag.enabled=!1!==t.enabled,this.setPerAction("drag",t),this.setOnEvents("drag",t),/^(xy|x|y|start)$/.test(t.lockAxis)&&(this.options.drag.lockAxis=t.lockAxis),/^(xy|x|y)$/.test(t.startAxis)&&(this.options.drag.startAxis=t.startAxis),this):i.is.bool(t)?(this.options.drag.enabled=t,t||(this.ondragstart=this.ondragstart=this.ondragend=null),this):this.options.drag},r.drag=l,r.names.push("drag"),i.merge(s.eventTypes,["dragstart","dragmove","draginertiastart","draginertiaresume","dragend"]),r.methodDict.drag="draggable",c.drag=l.defaults,e.exports=l},{"../InteractEvent":3,"../Interactable":4,"../Interaction":5,"../defaultOptions":18,"../utils":44,"./base":6}],8:[function(t,e,n){"use strict";function r(t,e){for(var n=[],r=[],i=0;i<u.interactables.length;i++){var o;o=u.interactables[i];var s=o;if(s.options.drop.enabled){var a=s.options.drop.accept;if(!(p.is.element(a)&&a!==e||p.is.string(a)&&!p.matchesSelector(e,a)))for(var c=p.is.string(s.target)?s._context.querySelectorAll(s.target):[s.target],l=0;l<c.length;l++){var d;d=c[l];var f=d;f!==e&&(n.push(s),r.push(f))}}}return{elements:r,dropzones:n}}function i(t,e){for(var n=void 0,r=0;r<t.dropzones.length;r++){var i=t.dropzones[r],o=t.elements[r];o!==n&&(e.target=o,i.fire(e)),n=o}}function o(t,e){var n=r(t,e);t.dropzones=n.dropzones,t.elements=n.elements,t.rects=[];for(var i=0;i<t.dropzones.length;i++)t.rects[i]=t.dropzones[i].getRect(t.elements[i])}function s(t,e,n){var r=t.interaction,i=[];y&&o(r.activeDrops,n);for(var s=0;s<r.activeDrops.dropzones.length;s++){var a=r.activeDrops.dropzones[s],c=r.activeDrops.elements[s],l=r.activeDrops.rects[s];i.push(a.dropCheck(t,e,r.target,n,c,l)?c:null)}var u=p.indexOfDeepestElement(i);return{dropzone:r.activeDrops.dropzones[u]||null,element:r.activeDrops.elements[u]||null}}function a(t,e,n){var r={enter:null,leave:null,activate:null,deactivate:null,move:null,drop:null},i={dragEvent:n,interaction:t,target:t.dropElement,dropzone:t.dropTarget,relatedTarget:n.target,draggable:n.interactable,timeStamp:n.timeStamp};return t.dropElement!==t.prevDropElement&&(t.prevDropTarget&&(r.leave=p.extend({type:"dragleave"},i),n.dragLeave=r.leave.target=t.prevDropElement,n.prevDropzone=r.leave.dropzone=t.prevDropTarget),t.dropTarget&&(r.enter={dragEvent:n,interaction:t,target:t.dropElement,dropzone:t.dropTarget,relatedTarget:n.target,draggable:n.interactable,timeStamp:n.timeStamp,type:"dragenter"},n.dragEnter=t.dropElement,n.dropzone=t.dropTarget)),"dragend"===n.type&&t.dropTarget&&(r.drop=p.extend({type:"drop"},i),n.dropzone=t.dropTarget,n.relatedTarget=t.dropElement),"dragstart"===n.type&&(r.activate=p.extend({type:"dropactivate"},i),r.activate.target=null,r.activate.dropzone=null),"dragend"===n.type&&(r.deactivate=p.extend({type:"dropdeactivate"},i),r.deactivate.target=null,r.deactivate.dropzone=null),"dragmove"===n.type&&t.dropTarget&&(r.move=p.extend({dragmove:n,type:"dropmove"},i),n.dropzone=t.dropTarget),r}function c(t,e){var n=t.activeDrops,r=t.prevDropTarget,o=t.dropTarget,s=t.dropElement;e.leave&&r.fire(e.leave),e.move&&o.fire(e.move),e.enter&&o.fire(e.enter),e.drop&&o.fire(e.drop),e.deactivate&&i(n,e.deactivate),t.prevDropTarget=o,t.prevDropElement=s}var l=t("./base"),p=t("../utils"),u=t("../scope"),d=t("../interact"),f=t("../InteractEvent"),v=t("../Interactable"),g=t("../Interaction"),h=t("../defaultOptions"),m={defaults:{enabled:!1,accept:null,overlap:"pointer"}},y=!1;g.signals.on("action-start",function(t){var e=t.interaction,n=t.event;if("drag"===e.prepared.name){e.activeDrops.dropzones=[],e.activeDrops.elements=[],e.activeDrops.rects=[],e.dropEvents=null,e.dynamicDrop||o(e.activeDrops,e.element);var r=e.prevEvent,s=a(e,n,r);s.activate&&i(e.activeDrops,s.activate)}}),f.signals.on("new",function(t){var e=t.interaction,n=t.iEvent,r=t.event;if("dragmove"===n.type||"dragend"===n.type){var i=e.element,o=n,c=s(o,r,i);e.dropTarget=c.dropzone,e.dropElement=c.element,e.dropEvents=a(e,r,o)}}),g.signals.on("action-move",function(t){var e=t.interaction;"drag"===e.prepared.name&&c(e,e.dropEvents)}),g.signals.on("action-end",function(t){var e=t.interaction;"drag"===e.prepared.name&&c(e,e.dropEvents)}),g.signals.on("stop-drag",function(t){var e=t.interaction;e.activeDrops={dropzones:null,elements:null,rects:null},e.dropEvents=null}),v.prototype.dropzone=function(t){return p.is.object(t)?(this.options.drop.enabled=!1!==t.enabled,p.is.function(t.ondrop)&&(this.events.ondrop=t.ondrop),p.is.function(t.ondropactivate)&&(this.events.ondropactivate=t.ondropactivate),p.is.function(t.ondropdeactivate)&&(this.events.ondropdeactivate=t.ondropdeactivate),p.is.function(t.ondragenter)&&(this.events.ondragenter=t.ondragenter),p.is.function(t.ondragleave)&&(this.events.ondragleave=t.ondragleave),p.is.function(t.ondropmove)&&(this.events.ondropmove=t.ondropmove),/^(pointer|center)$/.test(t.overlap)?this.options.drop.overlap=t.overlap:p.is.number(t.overlap)&&(this.options.drop.overlap=Math.max(Math.min(1,t.overlap),0)),"accept"in t&&(this.options.drop.accept=t.accept),"checker"in t&&(this.options.drop.checker=t.checker),this):p.is.bool(t)?(this.options.drop.enabled=t,t||(this.ondragenter=this.ondragleave=this.ondrop=this.ondropactivate=this.ondropdeactivate=null),this):this.options.drop},v.prototype.dropCheck=function(t,e,n,r,i,o){var s=!1;if(!(o=o||this.getRect(i)))return!!this.options.drop.checker&&this.options.drop.checker(t,e,s,this,i,n,r);var a=this.options.drop.overlap;if("pointer"===a){var c=p.getOriginXY(n,r,"drag"),l=p.getPageXY(t);l.x+=c.x,l.y+=c.y;var u=l.x>o.left&&l.x<o.right,d=l.y>o.top&&l.y<o.bottom;s=u&&d}var f=n.getRect(r);if(f&&"center"===a){var v=f.left+f.width/2,g=f.top+f.height/2;s=v>=o.left&&v<=o.right&&g>=o.top&&g<=o.bottom}if(f&&p.is.number(a)){s=Math.max(0,Math.min(o.right,f.right)-Math.max(o.left,f.left))*Math.max(0,Math.min(o.bottom,f.bottom)-Math.max(o.top,f.top))/(f.width*f.height)>=a}return this.options.drop.checker&&(s=this.options.drop.checker(t,e,s,this,i,n,r)),s},v.signals.on("unset",function(t){t.interactable.dropzone(!1)}),v.settingsMethods.push("dropChecker"),g.signals.on("new",function(t){t.dropTarget=null,t.dropElement=null,t.prevDropTarget=null,t.prevDropElement=null,t.dropEvents=null,t.activeDrops={dropzones:[],elements:[],rects:[]}}),g.signals.on("stop",function(t){var e=t.interaction;e.dropTarget=e.dropElement=e.prevDropTarget=e.prevDropElement=null}),d.dynamicDrop=function(t){return p.is.bool(t)?(y=t,d):y},p.merge(v.eventTypes,["dragenter","dragleave","dropactivate","dropdeactivate","dropmove","drop"]),l.methodDict.drop="dropzone",h.drop=m.defaults,e.exports=m},{"../InteractEvent":3,"../Interactable":4,"../Interaction":5,"../defaultOptions":18,"../interact":21,"../scope":33,"../utils":44,"./base":6}],9:[function(t,e,n){"use strict";var r=t("./base"),i=t("../utils"),o=t("../InteractEvent"),s=t("../Interactable"),a=t("../Interaction"),c=t("../defaultOptions"),l={defaults:{enabled:!1,origin:null,restrict:null},checker:function(t,e,n,r,i){return i.pointerIds.length>=2?{name:"gesture"}:null},getCursor:function(){return""}};o.signals.on("new",function(t){var e=t.iEvent,n=t.interaction;"gesturestart"===e.type&&(e.ds=0,n.gesture.startDistance=n.gesture.prevDistance=e.distance,n.gesture.startAngle=n.gesture.prevAngle=e.angle,n.gesture.scale=1)}),o.signals.on("new",function(t){var e=t.iEvent,n=t.interaction;"gesturemove"===e.type&&(e.ds=e.scale-n.gesture.scale,n.target.fire(e),n.gesture.prevAngle=e.angle,n.gesture.prevDistance=e.distance,e.scale===1/0||null===e.scale||void 0===e.scale||isNaN(e.scale)||(n.gesture.scale=e.scale))}),s.prototype.gesturable=function(t){return i.is.object(t)?(this.options.gesture.enabled=!1!==t.enabled,this.setPerAction("gesture",t),this.setOnEvents("gesture",t),this):i.is.bool(t)?(this.options.gesture.enabled=t,t||(this.ongesturestart=this.ongesturestart=this.ongestureend=null),this):this.options.gesture},o.signals.on("set-delta",function(t){var e=t.interaction,n=t.iEvent,r=t.action,s=t.event,a=t.starting,c=t.ending,l=t.deltaSource;if("gesture"===r){var p=e.pointers;n.touches=[p[0],p[1]],a?(n.distance=i.touchDistance(p,l),n.box=i.touchBBox(p),n.scale=1,n.ds=0,n.angle=i.touchAngle(p,void 0,l),n.da=0):c||s instanceof o?(n.distance=e.prevEvent.distance,n.box=e.prevEvent.box,n.scale=e.prevEvent.scale,n.ds=n.scale-1,n.angle=e.prevEvent.angle,n.da=n.angle-e.gesture.startAngle):(n.distance=i.touchDistance(p,l),n.box=i.touchBBox(p),n.scale=n.distance/e.gesture.startDistance,n.angle=i.touchAngle(p,e.gesture.prevAngle,l),n.ds=n.scale-e.gesture.prevScale,n.da=n.angle-e.gesture.prevAngle)}}),a.signals.on("new",function(t){t.gesture={start:{x:0,y:0},startDistance:0,prevDistance:0,distance:0,scale:1,startAngle:0,prevAngle:0}}),r.gesture=l,r.names.push("gesture"),i.merge(s.eventTypes,["gesturestart","gesturemove","gestureend"]),r.methodDict.gesture="gesturable",c.gesture=l.defaults,e.exports=l},{"../InteractEvent":3,"../Interactable":4,"../Interaction":5,"../defaultOptions":18,"../utils":44,"./base":6}],10:[function(t,e,n){"use strict";function r(t,e,n,r,i,s,a){if(!e)return!1;if(!0===e){var c=o.is.number(s.width)?s.width:s.right-s.left,l=o.is.number(s.height)?s.height:s.bottom-s.top;if(c<0&&("left"===t?t="right":"right"===t&&(t="left")),l<0&&("top"===t?t="bottom":"bottom"===t&&(t="top")),"left"===t)return n.x<(c>=0?s.left:s.right)+a;if("top"===t)return n.y<(l>=0?s.top:s.bottom)+a;if("right"===t)return n.x>(c>=0?s.right:s.left)-a;if("bottom"===t)return n.y>(l>=0?s.bottom:s.top)-a}return!!o.is.element(r)&&(o.is.element(e)?e===r:o.matchesUpTo(r,e,i))}var i=t("./base"),o=t("../utils"),s=t("../utils/browser"),a=t("../InteractEvent"),c=t("../Interactable"),l=t("../Interaction"),p=t("../defaultOptions"),u=s.supportsTouch||s.supportsPointerEvent?20:10,d={defaults:{enabled:!1,mouseButtons:null,origin:null,snap:null,restrict:null,inertia:null,autoScroll:null,square:!1,preserveAspectRatio:!1,axis:"xy",margin:NaN,edges:null,invert:"none"},checker:function(t,e,n,i,s,a){if(!a)return null;var c=o.extend({},s.curCoords.page),l=n.options;if(l.resize.enabled){var p=l.resize,d={left:!1,right:!1,top:!1,bottom:!1};if(o.is.object(p.edges)){for(var f in d)d[f]=r(f,p.edges[f],c,s._eventTarget,i,a,p.margin||u);if(d.left=d.left&&!d.right,d.top=d.top&&!d.bottom,d.left||d.right||d.top||d.bottom)return{name:"resize",edges:d}}else{var v="y"!==l.resize.axis&&c.x>a.right-u,g="x"!==l.resize.axis&&c.y>a.bottom-u;if(v||g)return{name:"resize",axes:(v?"x":"")+(g?"y":"")}}}return null},cursors:s.isIe9?{x:"e-resize",y:"s-resize",xy:"se-resize",top:"n-resize",left:"w-resize",bottom:"s-resize",right:"e-resize",topleft:"se-resize",bottomright:"se-resize",topright:"ne-resize",bottomleft:"ne-resize"}:{x:"ew-resize",y:"ns-resize",xy:"nwse-resize",top:"ns-resize",left:"ew-resize",bottom:"ns-resize",right:"ew-resize",topleft:"nwse-resize",bottomright:"nwse-resize",topright:"nesw-resize",bottomleft:"nesw-resize"},getCursor:function(t){if(t.axis)return d.cursors[t.name+t.axis];if(t.edges){for(var e="",n=["top","bottom","left","right"],r=0;r<4;r++)t.edges[n[r]]&&(e+=n[r]);return d.cursors[e]}}};a.signals.on("new",function(t){var e=t.iEvent,n=t.interaction;if("resizestart"===e.type&&n.prepared.edges){var r=n.target.getRect(n.element),i=n.target.options.resize;if(i.square||i.preserveAspectRatio){var s=o.extend({},n.prepared.edges);s.top=s.top||s.left&&!s.bottom,s.left=s.left||s.top&&!s.right,s.bottom=s.bottom||s.right&&!s.top,s.right=s.right||s.bottom&&!s.left,n.prepared._linkedEdges=s}else n.prepared._linkedEdges=null;i.preserveAspectRatio&&(n.resizeStartAspectRatio=r.width/r.height),n.resizeRects={start:r,current:o.extend({},r),inverted:o.extend({},r),previous:o.extend({},r),delta:{left:0,right:0,width:0,top:0,bottom:0,height:0}},e.rect=n.resizeRects.inverted,e.deltaRect=n.resizeRects.delta}}),a.signals.on("new",function(t){var e=t.iEvent,n=t.phase,r=t.interaction;if("move"===n&&r.prepared.edges){var i=r.target.options.resize,s=i.invert,a="reposition"===s||"negate"===s,c=r.prepared.edges,l=r.resizeRects.start,p=r.resizeRects.current,u=r.resizeRects.inverted,d=r.resizeRects.delta,f=o.extend(r.resizeRects.previous,u),v=c,g=e.dx,h=e.dy;if(i.preserveAspectRatio||i.square){var m=i.preserveAspectRatio?r.resizeStartAspectRatio:1;c=r.prepared._linkedEdges,v.left&&v.bottom||v.right&&v.top?h=-g/m:v.left||v.right?h=g/m:(v.top||v.bottom)&&(g=h*m)}if(c.top&&(p.top+=h),c.bottom&&(p.bottom+=h),c.left&&(p.left+=g),c.right&&(p.right+=g),a){if(o.extend(u,p),"reposition"===s){var y=void 0;u.top>u.bottom&&(y=u.top,u.top=u.bottom,u.bottom=y),u.left>u.right&&(y=u.left,u.left=u.right,u.right=y)}}else u.top=Math.min(p.top,l.bottom),u.bottom=Math.max(p.bottom,l.top),u.left=Math.min(p.left,l.right),u.right=Math.max(p.right,l.left);u.width=u.right-u.left,u.height=u.bottom-u.top;for(var x in u)d[x]=u[x]-f[x];e.edges=r.prepared.edges,e.rect=u,e.deltaRect=d}}),c.prototype.resizable=function(t){return o.is.object(t)?(this.options.resize.enabled=!1!==t.enabled,this.setPerAction("resize",t),this.setOnEvents("resize",t),/^x$|^y$|^xy$/.test(t.axis)?this.options.resize.axis=t.axis:null===t.axis&&(this.options.resize.axis=p.resize.axis),o.is.bool(t.preserveAspectRatio)?this.options.resize.preserveAspectRatio=t.preserveAspectRatio:o.is.bool(t.square)&&(this.options.resize.square=t.square),this):o.is.bool(t)?(this.options.resize.enabled=t,t||(this.onresizestart=this.onresizestart=this.onresizeend=null),this):this.options.resize},l.signals.on("new",function(t){t.resizeAxes="xy"}),a.signals.on("set-delta",function(t){var e=t.interaction,n=t.iEvent;"resize"===t.action&&e.resizeAxes&&(e.target.options.resize.square?("y"===e.resizeAxes?n.dx=n.dy:n.dy=n.dx,n.axes="xy"):(n.axes=e.resizeAxes,"x"===e.resizeAxes?n.dy=0:"y"===e.resizeAxes&&(n.dx=0)))}),i.resize=d,i.names.push("resize"),
+o.merge(c.eventTypes,["resizestart","resizemove","resizeinertiastart","resizeinertiaresume","resizeend"]),i.methodDict.resize="resizable",p.resize=d.defaults,e.exports=d},{"../InteractEvent":3,"../Interactable":4,"../Interaction":5,"../defaultOptions":18,"../utils":44,"../utils/browser":36,"./base":6}],11:[function(t,e,n){"use strict";var r=t("./utils/raf"),i=t("./utils/window").getWindow,o=t("./utils/is"),s=t("./utils/domUtils"),a=t("./Interaction"),c=t("./defaultOptions"),l={defaults:{enabled:!1,container:null,margin:60,speed:300},interaction:null,i:null,x:0,y:0,isScrolling:!1,prevTime:0,start:function(t){l.isScrolling=!0,r.cancel(l.i),l.interaction=t,l.prevTime=(new Date).getTime(),l.i=r.request(l.scroll)},stop:function(){l.isScrolling=!1,r.cancel(l.i)},scroll:function(){var t=l.interaction.target.options[l.interaction.prepared.name].autoScroll,e=t.container||i(l.interaction.element),n=(new Date).getTime(),s=(n-l.prevTime)/1e3,a=t.speed*s;a>=1&&(o.window(e)?e.scrollBy(l.x*a,l.y*a):e&&(e.scrollLeft+=l.x*a,e.scrollTop+=l.y*a),l.prevTime=n),l.isScrolling&&(r.cancel(l.i),l.i=r.request(l.scroll))},check:function(t,e){var n=t.options;return n[e].autoScroll&&n[e].autoScroll.enabled},onInteractionMove:function(t){var e=t.interaction,n=t.pointer;if(e.interacting()&&l.check(e.target,e.prepared.name)){if(e.simulation)return void(l.x=l.y=0);var r=void 0,a=void 0,c=void 0,p=void 0,u=e.target.options[e.prepared.name].autoScroll,d=u.container||i(e.element);if(o.window(d))p=n.clientX<l.margin,r=n.clientY<l.margin,a=n.clientX>d.innerWidth-l.margin,c=n.clientY>d.innerHeight-l.margin;else{var f=s.getElementClientRect(d);p=n.clientX<f.left+l.margin,r=n.clientY<f.top+l.margin,a=n.clientX>f.right-l.margin,c=n.clientY>f.bottom-l.margin}l.x=a?1:p?-1:0,l.y=c?1:r?-1:0,l.isScrolling||(l.margin=u.margin,l.speed=u.speed,l.start(e))}}};a.signals.on("stop-active",function(){l.stop()}),a.signals.on("action-move",l.onInteractionMove),c.perAction.autoScroll=l.defaults,e.exports=l},{"./Interaction":5,"./defaultOptions":18,"./utils/domUtils":39,"./utils/is":46,"./utils/raf":50,"./utils/window":52}],12:[function(t,e,n){"use strict";var r=t("../Interactable"),i=t("../actions/base"),o=t("../utils/is"),s=t("../utils/domUtils"),a=t("../utils"),c=a.warnOnce;r.prototype.getAction=function(t,e,n,r){var i=this.defaultActionChecker(t,e,n,r);return this.options.actionChecker?this.options.actionChecker(t,e,i,this,r,n):i},r.prototype.ignoreFrom=c(function(t){return this._backCompatOption("ignoreFrom",t)},"Interactable.ignoreForm() has been deprecated. Use Interactble.draggable({ignoreFrom: newValue})."),r.prototype.allowFrom=c(function(t){return this._backCompatOption("allowFrom",t)},"Interactable.allowForm() has been deprecated. Use Interactble.draggable({allowFrom: newValue})."),r.prototype.testIgnore=function(t,e,n){return!(!t||!o.element(n))&&(o.string(t)?s.matchesUpTo(n,t,e):!!o.element(t)&&s.nodeContains(t,n))},r.prototype.testAllow=function(t,e,n){return!t||!!o.element(n)&&(o.string(t)?s.matchesUpTo(n,t,e):!!o.element(t)&&s.nodeContains(t,n))},r.prototype.testIgnoreAllow=function(t,e,n){return!this.testIgnore(t.ignoreFrom,e,n)&&this.testAllow(t.allowFrom,e,n)},r.prototype.actionChecker=function(t){return o.function(t)?(this.options.actionChecker=t,this):null===t?(delete this.options.actionChecker,this):this.options.actionChecker},r.prototype.styleCursor=function(t){return o.bool(t)?(this.options.styleCursor=t,this):null===t?(delete this.options.styleCursor,this):this.options.styleCursor},r.prototype.defaultActionChecker=function(t,e,n,r){for(var o=this.getRect(r),s=e.buttons||{0:1,1:4,3:8,4:16}[e.button],a=null,c=0;c<i.names.length;c++){var l;l=i.names[c];var p=l;if((!n.pointerIsDown||!/mouse|pointer/.test(n.pointerType)||0!=(s&this.options[p].mouseButtons))&&(a=i[p].checker(t,e,this,r,n,o)))return a}}},{"../Interactable":4,"../actions/base":6,"../utils":44,"../utils/domUtils":39,"../utils/is":46}],13:[function(t,e,n){"use strict";function r(t,e,n,r){return v.is.object(t)&&e.testIgnoreAllow(e.options[t.name],n,r)&&e.options[t.name].enabled&&a(e,n,t)?t:null}function i(t,e,n,i,o,s){for(var a=0,c=i.length;a<c;a++){var l=i[a],p=o[a],u=r(l.getAction(e,n,t,p),l,p,s);if(u)return{action:u,target:l,element:p}}return{}}function o(t,e,n,r){function o(t){s.push(t),a.push(c)}for(var s=[],a=[],c=r;v.is.element(c);){s=[],a=[],f.interactables.forEachMatch(c,o);var l=i(t,e,n,s,a,r);if(l.action&&!l.target.options[l.action.name].manualStart)return l;c=v.parentNode(c)}return{}}function s(t,e){var n=e.action,r=e.target,i=e.element;if(n=n||{},t.target&&t.target.options.styleCursor&&(t.target._doc.documentElement.style.cursor=""),t.target=r,t.element=i,v.copyAction(t.prepared,n),r&&r.options.styleCursor){var o=n?u[n.name].getCursor(n):"";t.target._doc.documentElement.style.cursor=o}g.fire("prepared",{interaction:t})}function a(t,e,n){var r=t.options,i=r[n.name].max,o=r[n.name].maxPerElement,s=0,a=0,c=0;if(i&&o&&h.maxInteractions){for(var l=0;l<f.interactions.length;l++){var p;p=f.interactions[l];var u=p,d=u.prepared.name;if(u.interacting()){if(++s>=h.maxInteractions)return!1;if(u.target===t){if((a+=d===n.name|0)>=i)return!1;if(u.element===e&&(c++,d!==n.name||c>=o))return!1}}}return h.maxInteractions>0}}var c=t("../interact"),l=t("../Interactable"),p=t("../Interaction"),u=t("../actions/base"),d=t("../defaultOptions"),f=t("../scope"),v=t("../utils"),g=t("../utils/Signals").new();t("./InteractableMethods");var h={signals:g,withinInteractionLimit:a,maxInteractions:1/0,defaults:{perAction:{manualStart:!1,max:1/0,maxPerElement:1,allowFrom:null,ignoreFrom:null,mouseButtons:1}},setActionDefaults:function(t){v.extend(t.defaults,h.defaults.perAction)},validateAction:r};p.signals.on("down",function(t){var e=t.interaction,n=t.pointer,r=t.event,i=t.eventTarget;if(!e.interacting()){s(e,o(e,n,r,i))}}),p.signals.on("move",function(t){var e=t.interaction,n=t.pointer,r=t.event,i=t.eventTarget;if("mouse"===e.pointerType&&!e.pointerIsDown&&!e.interacting()){s(e,o(e,n,r,i))}}),p.signals.on("move",function(t){var e=t.interaction,n=t.event;if(e.pointerIsDown&&!e.interacting()&&e.pointerWasMoved&&e.prepared.name){g.fire("before-start",t);var r=e.target;e.prepared.name&&r&&(r.options[e.prepared.name].manualStart||!a(r,e.element,e.prepared)?e.stop(n):e.start(e.prepared,r,e.element))}}),p.signals.on("stop",function(t){var e=t.interaction,n=e.target;n&&n.options.styleCursor&&(n._doc.documentElement.style.cursor="")}),c.maxInteractions=function(t){return v.is.number(t)?(h.maxInteractions=t,c):h.maxInteractions},l.settingsMethods.push("styleCursor"),l.settingsMethods.push("actionChecker"),l.settingsMethods.push("ignoreFrom"),l.settingsMethods.push("allowFrom"),d.base.actionChecker=null,d.base.styleCursor=!0,v.extend(d.perAction,h.defaults.perAction),e.exports=h},{"../Interactable":4,"../Interaction":5,"../actions/base":6,"../defaultOptions":18,"../interact":21,"../scope":33,"../utils":44,"../utils/Signals":34,"./InteractableMethods":12}],14:[function(t,e,n){"use strict";function r(t,e){if(!e)return!1;var n=e.options.drag.startAxis;return"xy"===t||"xy"===n||n===t}var i=t("./base"),o=t("../scope"),s=t("../utils/is"),a=t("../utils/domUtils"),c=a.parentNode;i.setActionDefaults(t("../actions/drag")),i.signals.on("before-start",function(t){var e=t.interaction,n=t.eventTarget,a=t.dx,l=t.dy;if("drag"===e.prepared.name){var p=Math.abs(a),u=Math.abs(l),d=e.target.options.drag,f=d.startAxis,v=p>u?"x":p<u?"y":"xy";if(e.prepared.axis="start"===d.lockAxis?v[0]:d.lockAxis,"xy"!==v&&"xy"!==f&&f!==v){e.prepared.name=null;for(var g=n,h=function(t){if(t!==e.target){var o=e.target.options.drag;if(!o.manualStart&&t.testIgnoreAllow(o,g,n)){var s=t.getAction(e.downPointer,e.downEvent,e,g);if(s&&"drag"===s.name&&r(v,t)&&i.validateAction(s,t,g,n))return t}}};s.element(g);){var m=o.interactables.forEachMatch(g,h);if(m){e.prepared.name="drag",e.target=m,e.element=g;break}g=c(g)}}}})},{"../actions/drag":7,"../scope":33,"../utils/domUtils":39,"../utils/is":46,"./base":13}],15:[function(t,e,n){"use strict";t("./base").setActionDefaults(t("../actions/gesture"))},{"../actions/gesture":9,"./base":13}],16:[function(t,e,n){"use strict";function r(t){var e=t.prepared&&t.prepared.name;if(!e)return null;var n=t.target.options;return n[e].hold||n[e].delay}var i=t("./base"),o=t("../Interaction");i.defaults.perAction.hold=0,i.defaults.perAction.delay=0,o.signals.on("new",function(t){t.autoStartHoldTimer=null}),i.signals.on("prepared",function(t){var e=t.interaction,n=r(e);n>0&&(e.autoStartHoldTimer=setTimeout(function(){e.start(e.prepared,e.target,e.element)},n))}),o.signals.on("move",function(t){var e=t.interaction,n=t.duplicate;e.pointerWasMoved&&!n&&clearTimeout(e.autoStartHoldTimer)}),i.signals.on("before-start",function(t){var e=t.interaction;r(e)>0&&(e.prepared.name=null)}),e.exports={getHoldDuration:r}},{"../Interaction":5,"./base":13}],17:[function(t,e,n){"use strict";t("./base").setActionDefaults(t("../actions/resize"))},{"../actions/resize":10,"./base":13}],18:[function(t,e,n){"use strict";e.exports={base:{accept:null,preventDefault:"auto",deltaSource:"page"},perAction:{origin:{x:0,y:0},inertia:{enabled:!1,resistance:10,minSpeed:100,endSpeed:10,allowResume:!0,smoothEndDuration:300}}}},{}],19:[function(t,e,n){"use strict";t("./inertia"),t("./modifiers/snap"),t("./modifiers/restrict"),t("./pointerEvents/base"),t("./pointerEvents/holdRepeat"),t("./pointerEvents/interactableTargets"),t("./autoStart/hold"),t("./actions/gesture"),t("./actions/resize"),t("./actions/drag"),t("./actions/drop"),t("./modifiers/snapSize"),t("./modifiers/restrictEdges"),t("./modifiers/restrictSize"),t("./autoStart/gesture"),t("./autoStart/resize"),t("./autoStart/drag"),t("./interactablePreventDefault.js"),t("./autoScroll"),e.exports=t("./interact")},{"./actions/drag":7,"./actions/drop":8,"./actions/gesture":9,"./actions/resize":10,"./autoScroll":11,"./autoStart/drag":14,"./autoStart/gesture":15,"./autoStart/hold":16,"./autoStart/resize":17,"./inertia":20,"./interact":21,"./interactablePreventDefault.js":22,"./modifiers/restrict":24,"./modifiers/restrictEdges":25,"./modifiers/restrictSize":26,"./modifiers/snap":27,"./modifiers/snapSize":28,"./pointerEvents/base":30,"./pointerEvents/holdRepeat":31,"./pointerEvents/interactableTargets":32}],20:[function(t,e,n){"use strict";function r(t,e){var n=t.target.options[t.prepared.name].inertia,r=n.resistance,i=-Math.log(n.endSpeed/e.v0)/r;e.x0=t.prevEvent.pageX,e.y0=t.prevEvent.pageY,e.t0=e.startEvent.timeStamp/1e3,e.sx=e.sy=0,e.modifiedXe=e.xe=(e.vx0-i)/r,e.modifiedYe=e.ye=(e.vy0-i)/r,e.te=i,e.lambda_v0=r/e.v0,e.one_ve_v0=1-n.endSpeed/e.v0}function i(){s(this),p.setCoordDeltas(this.pointerDelta,this.prevCoords,this.curCoords);var t=this.inertiaStatus,e=this.target.options[this.prepared.name].inertia,n=e.resistance,r=(new Date).getTime()/1e3-t.t0;if(r<t.te){var i=1-(Math.exp(-n*r)-t.lambda_v0)/t.one_ve_v0;if(t.modifiedXe===t.xe&&t.modifiedYe===t.ye)t.sx=t.xe*i,t.sy=t.ye*i;else{var o=p.getQuadraticCurvePoint(0,0,t.xe,t.ye,t.modifiedXe,t.modifiedYe,i);t.sx=o.x,t.sy=o.y}this.doMove(),t.i=u.request(this.boundInertiaFrame)}else t.sx=t.modifiedXe,t.sy=t.modifiedYe,this.doMove(),this.end(t.startEvent),t.active=!1,this.simulation=null;p.copyCoords(this.prevCoords,this.curCoords)}function o(){s(this);var t=this.inertiaStatus,e=(new Date).getTime()-t.t0,n=this.target.options[this.prepared.name].inertia.smoothEndDuration;e<n?(t.sx=p.easeOutQuad(e,0,t.xe,n),t.sy=p.easeOutQuad(e,0,t.ye,n),this.pointerMove(t.startEvent,t.startEvent),t.i=u.request(this.boundSmoothEndFrame)):(t.sx=t.xe,t.sy=t.ye,this.pointerMove(t.startEvent,t.startEvent),this.end(t.startEvent),t.smoothEnd=t.active=!1,this.simulation=null)}function s(t){var e=t.inertiaStatus;if(e.active){var n=e.upCoords.page,r=e.upCoords.client;p.setCoords(t.curCoords,[{pageX:n.x+e.sx,pageY:n.y+e.sy,clientX:r.x+e.sx,clientY:r.y+e.sy}])}}var a=t("./InteractEvent"),c=t("./Interaction"),l=t("./modifiers/base"),p=t("./utils"),u=t("./utils/raf");c.signals.on("new",function(t){t.inertiaStatus={active:!1,smoothEnd:!1,allowResume:!1,startEvent:null,upCoords:{},xe:0,ye:0,sx:0,sy:0,t0:0,vx0:0,vys:0,duration:0,lambda_v0:0,one_ve_v0:0,i:null},t.boundInertiaFrame=function(){return i.apply(t)},t.boundSmoothEndFrame=function(){return o.apply(t)}}),c.signals.on("down",function(t){var e=t.interaction,n=t.event,r=t.pointer,i=t.eventTarget,o=e.inertiaStatus;if(o.active)for(var s=i;p.is.element(s);){if(s===e.element){u.cancel(o.i),o.active=!1,e.simulation=null,e.updatePointer(r),p.setCoords(e.curCoords,e.pointers);var d={interaction:e};c.signals.fire("before-action-move",d),c.signals.fire("action-resume",d);var f=new a(e,n,e.prepared.name,"inertiaresume",e.element);e.target.fire(f),e.prevEvent=f,l.resetStatuses(e.modifierStatuses),p.copyCoords(e.prevCoords,e.curCoords);break}s=p.parentNode(s)}}),c.signals.on("up",function(t){var e=t.interaction,n=t.event,i=e.inertiaStatus;if(e.interacting()&&!i.active){var o=e.target,s=o&&o.options,c=s&&e.prepared.name&&s[e.prepared.name].inertia,d=(new Date).getTime(),f={},v=p.extend({},e.curCoords.page),g=e.pointerDelta.client.speed,h=!1,m=void 0,y=c&&c.enabled&&"gesture"!==e.prepared.name&&n!==i.startEvent,x=y&&d-e.curCoords.timeStamp<50&&g>c.minSpeed&&g>c.endSpeed,b={interaction:e,pageCoords:v,statuses:f,preEnd:!0,requireEndOnly:!0};y&&!x&&(l.resetStatuses(f),m=l.setAll(b),m.shouldMove&&m.locked&&(h=!0)),(x||h)&&(p.copyCoords(i.upCoords,e.curCoords),e.pointers[0]=i.startEvent=new a(e,n,e.prepared.name,"inertiastart",e.element),i.t0=d,i.active=!0,i.allowResume=c.allowResume,e.simulation=i,o.fire(i.startEvent),x?(i.vx0=e.pointerDelta.client.vx,i.vy0=e.pointerDelta.client.vy,i.v0=g,r(e,i),p.extend(v,e.curCoords.page),v.x+=i.xe,v.y+=i.ye,l.resetStatuses(f),m=l.setAll(b),i.modifiedXe+=m.dx,i.modifiedYe+=m.dy,i.i=u.request(e.boundInertiaFrame)):(i.smoothEnd=!0,i.xe=m.dx,i.ye=m.dy,i.sx=i.sy=0,i.i=u.request(e.boundSmoothEndFrame)))}}),c.signals.on("stop-active",function(t){var e=t.interaction,n=e.inertiaStatus;n.active&&(u.cancel(n.i),n.active=!1,e.simulation=null)})},{"./InteractEvent":3,"./Interaction":5,"./modifiers/base":23,"./utils":44,"./utils/raf":50}],21:[function(t,e,n){"use strict";function r(t,e){var n=a.interactables.get(t,e);return n||(n=new c(t,e),n.events.global=p),n}var i=t("./utils/browser"),o=t("./utils/events"),s=t("./utils"),a=t("./scope"),c=t("./Interactable"),l=t("./Interaction"),p={};r.isSet=function(t,e){return-1!==a.interactables.indexOfElement(t,e&&e.context)},r.on=function(t,e,n){if(s.is.string(t)&&-1!==t.search(" ")&&(t=t.trim().split(/ +/)),s.is.array(t)){for(var i=0;i<t.length;i++){var l;l=t[i];var u=l;r.on(u,e,n)}return r}if(s.is.object(t)){for(var d in t)r.on(d,t[d],e);return r}return s.contains(c.eventTypes,t)?p[t]?p[t].push(e):p[t]=[e]:o.add(a.document,t,e,{options:n}),r},r.off=function(t,e,n){if(s.is.string(t)&&-1!==t.search(" ")&&(t=t.trim().split(/ +/)),s.is.array(t)){for(var i=0;i<t.length;i++){var l;l=t[i];var u=l;r.off(u,e,n)}return r}if(s.is.object(t)){for(var d in t)r.off(d,t[d],e);return r}if(s.contains(c.eventTypes,t)){var f=void 0;t in p&&-1!==(f=p[t].indexOf(e))&&p[t].splice(f,1)}else o.remove(a.document,t,e,n);return r},r.debug=function(){return a},r.getPointerAverage=s.pointerAverage,r.getTouchBBox=s.touchBBox,r.getTouchDistance=s.touchDistance,r.getTouchAngle=s.touchAngle,r.getElementRect=s.getElementRect,r.getElementClientRect=s.getElementClientRect,r.matchesSelector=s.matchesSelector,r.closest=s.closest,r.supportsTouch=function(){return i.supportsTouch},r.supportsPointerEvent=function(){return i.supportsPointerEvent},r.stop=function(t){for(var e=a.interactions.length-1;e>=0;e--)a.interactions[e].stop(t);return r},r.pointerMoveTolerance=function(t){return s.is.number(t)?(l.pointerMoveTolerance=t,r):l.pointerMoveTolerance},r.addDocument=a.addDocument,r.removeDocument=a.removeDocument,a.interact=r,e.exports=r},{"./Interactable":4,"./Interaction":5,"./scope":33,"./utils":44,"./utils/browser":36,"./utils/events":40}],22:[function(t,e,n){"use strict";function r(t){var e=t.interaction,n=t.event;e.target&&e.target.checkAndPreventDefault(n)}var i=t("./Interactable"),o=t("./Interaction"),s=t("./scope"),a=t("./utils/is"),c=t("./utils/events"),l=t("./utils/browser"),p=t("./utils/domUtils"),u=p.nodeContains,d=p.matchesSelector;i.prototype.preventDefault=function(t){return/^(always|never|auto)$/.test(t)?(this.options.preventDefault=t,this):a.bool(t)?(this.options.preventDefault=t?"always":"never",this):this.options.preventDefault},i.prototype.checkAndPreventDefault=function(t){var e=this.options.preventDefault;if("never"!==e)return"always"===e?void t.preventDefault():void(c.supportsPassive&&/^touch(start|move)$/.test(t.type)&&!l.isIOS||/^(mouse|pointer|touch)*(down|start)/i.test(t.type)||a.element(t.target)&&d(t.target,"input,select,textarea,[contenteditable=true],[contenteditable=true] *")||t.preventDefault())};for(var f=["down","move","up","cancel"],v=0;v<f.length;v++){var g=f[v];o.signals.on(g,r)}o.docEvents.dragstart=function(t){for(var e=0;e<s.interactions.length;e++){var n;n=s.interactions[e];var r=n;if(r.element&&(r.element===t.target||u(r.element,t.target)))return void r.target.checkAndPreventDefault(t)}}},{"./Interactable":4,"./Interaction":5,"./scope":33,"./utils/browser":36,"./utils/domUtils":39,"./utils/events":40,"./utils/is":46}],23:[function(t,e,n){"use strict";function r(t,e,n){return t&&t.enabled&&(e||!t.endOnly)&&(!n||t.endOnly)}var i=t("../InteractEvent"),o=t("../Interaction"),s=t("../utils/extend"),a={names:[],setOffsets:function(t){var e=t.interaction,n=t.pageCoords,r=e.target,i=e.element,o=e.startOffset,s=r.getRect(i);s?(o.left=n.x-s.left,o.top=n.y-s.top,o.right=s.right-n.x,o.bottom=s.bottom-n.y,"width"in s||(s.width=s.right-s.left),"height"in s||(s.height=s.bottom-s.top)):o.left=o.top=o.right=o.bottom=0,t.rect=s,t.interactable=r,t.element=i;for(var c=0;c<a.names.length;c++){var l;l=a.names[c];var p=l;t.options=r.options[e.prepared.name][p],t.options&&(e.modifierOffsets[p]=a[p].setOffset(t))}},setAll:function(t){var e=t.interaction,n=t.statuses,i=t.preEnd,o=t.requireEndOnly,c={dx:0,dy:0,changed:!1,locked:!1,shouldMove:!0};t.modifiedCoords=s({},t.pageCoords);for(var l=0;l<a.names.length;l++){var p;p=a.names[l];var u=p,d=a[u],f=e.target.options[e.prepared.name][u];r(f,i,o)&&(t.status=t.status=n[u],t.options=f,t.offset=t.interaction.modifierOffsets[u],d.set(t),t.status.locked&&(t.modifiedCoords.x+=t.status.dx,t.modifiedCoords.y+=t.status.dy,c.dx+=t.status.dx,c.dy+=t.status.dy,c.locked=!0))}return c.shouldMove=!t.status||!c.locked||t.status.changed,c},resetStatuses:function(t){for(var e=0;e<a.names.length;e++){var n;n=a.names[e];var r=n,i=t[r]||{};i.dx=i.dy=0,i.modifiedX=i.modifiedY=NaN,i.locked=!1,i.changed=!0,t[r]=i}return t},start:function(t,e){var n=t.interaction,r={interaction:n,pageCoords:("action-resume"===e?n.curCoords:n.startCoords).page,startOffset:n.startOffset,statuses:n.modifierStatuses,preEnd:!1,requireEndOnly:!1};a.setOffsets(r),a.resetStatuses(r.statuses),r.pageCoords=s({},n.startCoords.page),n.modifierResult=a.setAll(r)},beforeMove:function(t){var e=t.interaction,n=t.preEnd,r=t.interactingBeforeMove,i=a.setAll({interaction:e,preEnd:n,pageCoords:e.curCoords.page,statuses:e.modifierStatuses,requireEndOnly:!1});!i.shouldMove&&r&&(e._dontFireMove=!0),e.modifierResult=i},end:function(t){for(var e=t.interaction,n=t.event,i=0;i<a.names.length;i++){var o;o=a.names[i];var s=o;if(r(e.target.options[e.prepared.name][s],!0,!0)){e.doMove({event:n,preEnd:!0});break}}},setXY:function(t){for(var e=t.iEvent,n=t.interaction,r=s({},t),i=0;i<a.names.length;i++){var o=a.names[i];if(r.options=n.target.options[n.prepared.name][o],r.options){var c=a[o];r.status=n.modifierStatuses[o],e[o]=c.modifyCoords(r)}}}};o.signals.on("new",function(t){t.startOffset={left:0,right:0,top:0,bottom:0},t.modifierOffsets={},t.modifierStatuses=a.resetStatuses({}),t.modifierResult=null}),o.signals.on("action-start",a.start),o.signals.on("action-resume",a.start),o.signals.on("before-action-move",a.beforeMove),o.signals.on("action-end",a.end),i.signals.on("set-xy",a.setXY),e.exports=a},{"../InteractEvent":3,"../Interaction":5,"../utils/extend":41}],24:[function(t,e,n){"use strict";function r(t,e,n){return o.is.function(t)?o.resolveRectLike(t,e.target,e.element,[n.x,n.y,e]):o.resolveRectLike(t,e.target,e.element)}var i=t("./base"),o=t("../utils"),s=t("../defaultOptions"),a={defaults:{enabled:!1,endOnly:!1,restriction:null,elementRect:null},setOffset:function(t){var e=t.rect,n=t.startOffset,r=t.options,i=r&&r.elementRect,o={};return e&&i?(o.left=n.left-e.width*i.left,o.top=n.top-e.height*i.top,o.right=n.right-e.width*(1-i.right),o.bottom=n.bottom-e.height*(1-i.bottom)):o.left=o.top=o.right=o.bottom=0,o},set:function(t){var e=t.modifiedCoords,n=t.interaction,i=t.status,s=t.options;if(!s)return i;var a=i.useStatusXY?{x:i.x,y:i.y}:o.extend({},e),c=r(s.restriction,n,a);if(!c)return i;i.dx=0,i.dy=0,i.locked=!1;var l=c,p=a.x,u=a.y,d=n.modifierOffsets.restrict;"x"in c&&"y"in c?(p=Math.max(Math.min(l.x+l.width-d.right,a.x),l.x+d.left),u=Math.max(Math.min(l.y+l.height-d.bottom,a.y),l.y+d.top)):(p=Math.max(Math.min(l.right-d.right,a.x),l.left+d.left),u=Math.max(Math.min(l.bottom-d.bottom,a.y),l.top+d.top)),i.dx=p-a.x,i.dy=u-a.y,i.changed=i.modifiedX!==p||i.modifiedY!==u,i.locked=!(!i.dx&&!i.dy),i.modifiedX=p,i.modifiedY=u},modifyCoords:function(t){var e=t.page,n=t.client,r=t.status,i=t.phase,o=t.options,s=o&&o.elementRect;if(o&&o.enabled&&("start"!==i||!s||!r.locked)&&r.locked)return e.x+=r.dx,e.y+=r.dy,n.x+=r.dx,n.y+=r.dy,{dx:r.dx,dy:r.dy}},getRestrictionRect:r};i.restrict=a,i.names.push("restrict"),s.perAction.restrict=a.defaults,e.exports=a},{"../defaultOptions":18,"../utils":44,"./base":23}],25:[function(t,e,n){"use strict";var r=t("./base"),i=t("../utils"),o=t("../utils/rect"),s=t("../defaultOptions"),a=t("../actions/resize"),c=t("./restrict"),l=c.getRestrictionRect,p={top:1/0,left:1/0,bottom:-1/0,right:-1/0},u={top:-1/0,left:-1/0,bottom:1/0,right:1/0},d={defaults:{enabled:!1,endOnly:!1,min:null,max:null,offset:null},setOffset:function(t){var e=t.interaction,n=t.startOffset,r=t.options;if(!r)return i.extend({},n);var o=l(r.offset,e,e.startCoords.page);return o?{top:n.top+o.y,left:n.left+o.x,bottom:n.bottom+o.y,right:n.right+o.x}:n},set:function(t){var e=t.modifiedCoords,n=t.interaction,r=t.status,s=t.offset,a=t.options,c=n.prepared.linkedEdges||n.prepared.edges;if(n.interacting()&&c){var d=r.useStatusXY?{x:r.x,y:r.y}:i.extend({},e),f=o.xywhToTlbr(l(a.inner,n,d))||p,v=o.xywhToTlbr(l(a.outer,n,d))||u,g=d.x,h=d.y;r.dx=0,r.dy=0,r.locked=!1,c.top?h=Math.min(Math.max(v.top+s.top,d.y),f.top+s.top):c.bottom&&(h=Math.max(Math.min(v.bottom-s.bottom,d.y),f.bottom-s.bottom)),c.left?g=Math.min(Math.max(v.left+s.left,d.x),f.left+s.left):c.right&&(g=Math.max(Math.min(v.right-s.right,d.x),f.right-s.right)),r.dx=g-d.x,r.dy=h-d.y,r.changed=r.modifiedX!==g||r.modifiedY!==h,r.locked=!(!r.dx&&!r.dy),r.modifiedX=g,r.modifiedY=h}},modifyCoords:function(t){var e=t.page,n=t.client,r=t.status,i=t.phase,o=t.options;if(o&&o.enabled&&("start"!==i||!r.locked)&&r.locked)return e.x+=r.dx,e.y+=r.dy,n.x+=r.dx,n.y+=r.dy,{dx:r.dx,dy:r.dy}},noInner:p,noOuter:u,getRestrictionRect:l};r.restrictEdges=d,r.names.push("restrictEdges"),s.perAction.restrictEdges=d.defaults,a.defaults.restrictEdges=d.defaults,e.exports=d},{"../actions/resize":10,"../defaultOptions":18,"../utils":44,"../utils/rect":51,"./base":23,"./restrict":24}],26:[function(t,e,n){"use strict";var r=t("./base"),i=t("./restrictEdges"),o=t("../utils"),s=t("../utils/rect"),a=t("../defaultOptions"),c=t("../actions/resize"),l={width:-1/0,height:-1/0},p={width:1/0,height:1/0},u={defaults:{enabled:!1,endOnly:!1,min:null,max:null},setOffset:function(t){return t.interaction.startOffset},set:function(t){var e=t.interaction,n=t.options,r=e.prepared.linkedEdges||e.prepared.edges;if(e.interacting()&&r){var a=s.xywhToTlbr(e.resizeRects.inverted),c=s.tlbrToXywh(i.getRestrictionRect(n.min,e))||l,u=s.tlbrToXywh(i.getRestrictionRect(n.max,e))||p;t.options={enabled:n.enabled,endOnly:n.endOnly,inner:o.extend({},i.noInner),outer:o.extend({},i.noOuter)},r.top?(t.options.inner.top=a.bottom-c.height,t.options.outer.top=a.bottom-u.height):r.bottom&&(t.options.inner.bottom=a.top+c.height,t.options.outer.bottom=a.top+u.height),r.left?(t.options.inner.left=a.right-c.width,t.options.outer.left=a.right-u.width):r.right&&(t.options.inner.right=a.left+c.width,t.options.outer.right=a.left+u.width),i.set(t)}},modifyCoords:i.modifyCoords};r.restrictSize=u,r.names.push("restrictSize"),a.perAction.restrictSize=u.defaults,c.defaults.restrictSize=u.defaults,e.exports=u},{"../actions/resize":10,"../defaultOptions":18,"../utils":44,"../utils/rect":51,"./base":23,"./restrictEdges":25}],27:[function(t,e,n){"use strict";var r=t("./base"),i=t("../interact"),o=t("../utils"),s=t("../defaultOptions"),a={defaults:{enabled:!1,endOnly:!1,range:1/0,targets:null,offsets:null,relativePoints:null},setOffset:function(t){var e=t.interaction,n=t.interactable,r=t.element,i=t.rect,s=t.startOffset,a=t.options,c=[],l=o.rectToXY(o.resolveRectLike(a.origin)),p=l||o.getOriginXY(n,r,e.prepared.name);a=a||n.options[e.prepared.name].snap||{};var u=void 0;if("startCoords"===a.offset)u={x:e.startCoords.page.x-p.x,y:e.startCoords.page.y-p.y};else{var d=o.resolveRectLike(a.offset,n,r,[e]);u=o.rectToXY(d)||{x:0,y:0}}if(i&&a.relativePoints&&a.relativePoints.length)for(var f=0;f<a.relativePoints.length;f++){var v;v=a.relativePoints[f];var g=v,h=g.x,m=g.y;c.push({x:s.left-i.width*h+u.x,y:s.top-i.height*m+u.y})}else c.push(u);return c},set:function(t){var e=t.interaction,n=t.modifiedCoords,r=t.status,i=t.options,s=t.offset,a=[],c=void 0,l=void 0,p=void 0;if(r.useStatusXY)l={x:r.x,y:r.y};else{var u=o.getOriginXY(e.target,e.element,e.prepared.name);l=o.extend({},n),l.x-=u.x,l.y-=u.y}r.realX=l.x,r.realY=l.y;for(var d=i.targets?i.targets.length:0,f=0;f<s.length;f++){var v;v=s[f];for(var g=v,h=g.x,m=g.y,y=l.x-h,x=l.y-m,b=0;b<(i.targets||[]).length;b++){var w;w=(i.targets||[])[b];var E=w;c=o.is.function(E)?E(y,x,e):E,c&&a.push({x:o.is.number(c.x)?c.x+h:y,y:o.is.number(c.y)?c.y+m:x,range:o.is.number(c.range)?c.range:i.range})}}var T={target:null,inRange:!1,distance:0,range:0,dx:0,dy:0};for(p=0,d=a.length;p<d;p++){c=a[p];var S=c.range,C=c.x-l.x,I=c.y-l.y,D=o.hypot(C,I),O=D<=S;S===1/0&&T.inRange&&T.range!==1/0&&(O=!1),T.target&&!(O?T.inRange&&S!==1/0?D/S<T.distance/T.range:S===1/0&&T.range!==1/0||D<T.distance:!T.inRange&&D<T.distance)||(T.target=c,T.distance=D,T.range=S,T.inRange=O,T.dx=C,T.dy=I,r.range=S)}var M=void 0;T.target?(M=r.modifiedX!==T.target.x||r.modifiedY!==T.target.y,r.modifiedX=T.target.x,r.modifiedY=T.target.y):(M=!0,r.modifiedX=NaN,r.modifiedY=NaN),r.dx=T.dx,r.dy=T.dy,r.changed=M||T.inRange&&!r.locked,r.locked=T.inRange},modifyCoords:function(t){var e=t.page,n=t.client,r=t.status,i=t.phase,o=t.options,s=o&&o.relativePoints;if(o&&o.enabled&&("start"!==i||!s||!s.length))return r.locked&&(e.x+=r.dx,e.y+=r.dy,n.x+=r.dx,n.y+=r.dy),{range:r.range,locked:r.locked,x:r.modifiedX,y:r.modifiedY,realX:r.realX,realY:r.realY,dx:r.dx,dy:r.dy}}};i.createSnapGrid=function(t){return function(e,n){var r=t.limits||{left:-1/0,right:1/0,top:-1/0,bottom:1/0},i=0,s=0;o.is.object(t.offset)&&(i=t.offset.x,s=t.offset.y);var a=Math.round((e-i)/t.x),c=Math.round((n-s)/t.y);return{x:Math.max(r.left,Math.min(r.right,a*t.x+i)),y:Math.max(r.top,Math.min(r.bottom,c*t.y+s)),range:t.range}}},r.snap=a,r.names.push("snap"),s.perAction.snap=a.defaults,e.exports=a},{"../defaultOptions":18,"../interact":21,"../utils":44,"./base":23}],28:[function(t,e,n){"use strict";var r=t("./base"),i=t("./snap"),o=t("../defaultOptions"),s=t("../actions/resize"),a=t("../utils/"),c={defaults:{enabled:!1,endOnly:!1,range:1/0,targets:null,offsets:null},setOffset:function(t){var e=t.interaction,n=t.options,r=e.prepared.edges;if(r){t.options={relativePoints:[{x:r.left?0:1,y:r.top?0:1}],origin:{x:0,y:0},offset:"self",range:n.range};var o=i.setOffset(t);return t.options=n,o}},set:function(t){var e=t.interaction,n=t.options,r=t.offset,o=t.modifiedCoords,s=a.extend({},o),c=s.x-r[0].x,l=s.y-r[0].y;t.options=a.extend({},n),t.options.targets=[];for(var p=0;p<(n.targets||[]).length;p++){var u;u=(n.targets||[])[p];var d=u,f=void 0;f=a.is.function(d)?d(c,l,e):d,f&&("width"in f&&"height"in f&&(f.x=f.width,f.y=f.height),t.options.targets.push(f))}i.set(t)},modifyCoords:function(t){var e=t.options;t.options=a.extend({},e),t.options.enabled=e.enabled,t.options.relativePoints=[null],i.modifyCoords(t)}};r.snapSize=c,r.names.push("snapSize"),o.perAction.snapSize=c.defaults,s.defaults.snapSize=c.defaults,e.exports=c},{"../actions/resize":10,"../defaultOptions":18,"../utils/":44,"./base":23,"./snap":27}],29:[function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var i=t("../utils/pointerUtils");e.exports=function(){function t(e,n,o,s,a){if(r(this,t),i.pointerExtend(this,o),o!==n&&i.pointerExtend(this,n),this.interaction=a,this.timeStamp=(new Date).getTime(),this.originalEvent=o,this.type=e,this.pointerId=i.getPointerId(n),this.pointerType=i.getPointerType(n),this.target=s,this.currentTarget=null,"tap"===e){var c=a.getPointerIndex(n);this.dt=this.timeStamp-a.downTimes[c];var l=this.timeStamp-a.tapTime;this.double=!!(a.prevTap&&"doubletap"!==a.prevTap.type&&a.prevTap.target===this.target&&l<500)}else"doubletap"===e&&(this.dt=n.timeStamp-a.tapTime)}return t.prototype.subtractOrigin=function(t){var e=t.x,n=t.y;return this.pageX-=e,this.pageY-=n,this.clientX-=e,this.clientY-=n,this},t.prototype.addOrigin=function(t){var e=t.x,n=t.y;return this.pageX+=e,this.pageY+=n,this.clientX+=e,this.clientY+=n,this},t.prototype.preventDefault=function(){this.originalEvent.preventDefault()},t.prototype.stopPropagation=function(){this.propagationStopped=!0},t.prototype.stopImmediatePropagation=function(){this.immediatePropagationStopped=this.propagationStopped=!0},t}()},{"../utils/pointerUtils":49}],30:[function(t,e,n){"use strict";function r(t){for(var e=t.interaction,n=t.pointer,s=t.event,c=t.eventTarget,p=t.type,u=void 0===p?t.pointerEvent.type:p,d=t.targets,f=void 0===d?i(t):d,v=t.pointerEvent,g=void 0===v?new o(u,n,s,c,e):v,h={interaction:e,pointer:n,event:s,eventTarget:c,targets:f,type:u,pointerEvent:g},m=0;m<f.length;m++){var y=f[m];for(var x in y.props||{})g[x]=y.props[x];var b=a.getOriginXY(y.eventable,y.element);if(g.subtractOrigin(b),g.eventable=y.eventable,g.currentTarget=y.element,y.eventable.fire(g),g.addOrigin(b),g.immediatePropagationStopped||g.propagationStopped&&m+1<f.length&&f[m+1].element!==g.currentTarget)break}if(l.fire("fired",h),"tap"===u){var w=g.double?r({interaction:e,pointer:n,event:s,eventTarget:c,type:"doubletap"}):g;e.prevTap=w,e.tapTime=w.timeStamp}return g}function i(t){var e=t.interaction,n=t.pointer,r=t.event,i=t.eventTarget,o=t.type,s=e.getPointerIndex(n);if("tap"===o&&(e.pointerWasMoved||!e.downTargets[s]||e.downTargets[s]!==i))return[];for(var c=a.getPath(i),p={interaction:e,pointer:n,event:r,eventTarget:i,type:o,path:c,targets:[],element:null},u=0;u<c.length;u++){var d;d=c[u];var f=d;p.element=f,l.fire("collect-targets",p)}return"hold"===o&&(p.targets=p.targets.filter(function(t){return t.eventable.options.holdDuration===e.holdTimers[s].duration})),p.targets}var o=t("./PointerEvent"),s=t("../Interaction"),a=t("../utils"),c=t("../defaultOptions"),l=t("../utils/Signals").new(),p=["down","up","cancel"],u=["down","up","cancel"],d={PointerEvent:o,fire:r,collectEventTargets:i,signals:l,defaults:{holdDuration:600,ignoreFrom:null,allowFrom:null,origin:{x:0,y:0}},types:["down","move","up","cancel","tap","doubletap","hold"]};s.signals.on("update-pointer-down",function(t){var e=t.interaction,n=t.pointerIndex;e.holdTimers[n]={duration:1/0,timeout:null}}),s.signals.on("remove-pointer",function(t){var e=t.interaction,n=t.pointerIndex;e.holdTimers.splice(n,1)}),
+s.signals.on("move",function(t){var e=t.interaction,n=t.pointer,i=t.event,o=t.eventTarget,s=t.duplicateMove,a=e.getPointerIndex(n);s||e.pointerIsDown&&!e.pointerWasMoved||(e.pointerIsDown&&clearTimeout(e.holdTimers[a].timeout),r({interaction:e,pointer:n,event:i,eventTarget:o,type:"move"}))}),s.signals.on("down",function(t){for(var e=t.interaction,n=t.pointer,i=t.event,o=t.eventTarget,s=t.pointerIndex,c=e.holdTimers[s],p=a.getPath(o),u={interaction:e,pointer:n,event:i,eventTarget:o,type:"hold",targets:[],path:p,element:null},d=0;d<p.length;d++){var f;f=p[d];var v=f;u.element=v,l.fire("collect-targets",u)}if(u.targets.length){for(var g=1/0,h=0;h<u.targets.length;h++){var m;m=u.targets[h];var y=m,x=y.eventable.options.holdDuration;x<g&&(g=x)}c.duration=g,c.timeout=setTimeout(function(){r({interaction:e,eventTarget:o,pointer:n,event:i,type:"hold"})},g)}}),s.signals.on("up",function(t){var e=t.interaction,n=t.pointer,i=t.event,o=t.eventTarget;e.pointerWasMoved||r({interaction:e,eventTarget:o,pointer:n,event:i,type:"tap"})});for(var f=["up","cancel"],v=0;v<f.length;v++){var g=f[v];s.signals.on(g,function(t){var e=t.interaction,n=t.pointerIndex;e.holdTimers[n]&&clearTimeout(e.holdTimers[n].timeout)})}for(var h=0;h<p.length;h++)s.signals.on(p[h],function(t){return function(e){var n=e.interaction,i=e.pointer,o=e.event;r({interaction:n,eventTarget:e.eventTarget,pointer:i,event:o,type:t})}}(u[h]));s.signals.on("new",function(t){t.prevTap=null,t.tapTime=0,t.holdTimers=[]}),c.pointerEvents=d.defaults,e.exports=d},{"../Interaction":5,"../defaultOptions":18,"../utils":44,"../utils/Signals":34,"./PointerEvent":29}],31:[function(t,e,n){"use strict";function r(t){var e=t.pointerEvent;"hold"===e.type&&(e.count=(e.count||0)+1)}function i(t){var e=t.interaction,n=t.pointerEvent,r=t.eventTarget,i=t.targets;if("hold"===n.type&&i.length){var o=i[0].eventable.options.holdRepeatInterval;o<=0||(e.holdIntervalHandle=setTimeout(function(){s.fire({interaction:e,eventTarget:r,type:"hold",pointer:n,event:n})},o))}}function o(t){var e=t.interaction;e.holdIntervalHandle&&(clearInterval(e.holdIntervalHandle),e.holdIntervalHandle=null)}var s=t("./base"),a=t("../Interaction");s.signals.on("new",r),s.signals.on("fired",i);for(var c=["move","up","cancel","endall"],l=0;l<c.length;l++){var p=c[l];a.signals.on(p,o)}s.defaults.holdRepeatInterval=0,s.types.push("holdrepeat"),e.exports={onNew:r,onFired:i,endHoldRepeat:o}},{"../Interaction":5,"./base":30}],32:[function(t,e,n){"use strict";var r=t("./base"),i=t("../Interactable"),o=t("../utils/is"),s=t("../scope"),a=t("../utils/extend"),c=t("../utils/arr"),l=c.merge;r.signals.on("collect-targets",function(t){var e=t.targets,n=t.element,r=t.type,i=t.eventTarget;s.interactables.forEachMatch(n,function(t){var s=t.events,a=s.options;s[r]&&o.element(n)&&t.testIgnoreAllow(a,n,i)&&e.push({element:n,eventable:s,props:{interactable:t}})})}),i.signals.on("new",function(t){var e=t.interactable;e.events.getRect=function(t){return e.getRect(t)}}),i.signals.on("set",function(t){var e=t.interactable,n=t.options;a(e.events.options,r.defaults),a(e.events.options,n)}),l(i.eventTypes,r.types),i.prototype.pointerEvents=function(t){return a(this.events.options,t),this};var p=i.prototype._backCompatOption;i.prototype._backCompatOption=function(t,e){var n=p.call(this,t,e);return n===this&&(this.events.options[t]=e),n},i.settingsMethods.push("pointerEvents")},{"../Interactable":4,"../scope":33,"../utils/arr":35,"../utils/extend":41,"../utils/is":46,"./base":30}],33:[function(t,e,n){"use strict";var r=t("./utils"),i=t("./utils/events"),o=t("./utils/Signals").new(),s=t("./utils/window"),a=s.getWindow,c={signals:o,events:i,utils:r,document:t("./utils/domObjects").document,documents:[],addDocument:function(t,e){if(r.contains(c.documents,t))return!1;e=e||a(t),c.documents.push(t),i.documents.push(t),t!==c.document&&i.add(e,"unload",c.onWindowUnload),o.fire("add-document",{doc:t,win:e})},removeDocument:function(t,e){var n=c.documents.indexOf(t);e=e||a(t),i.remove(e,"unload",c.onWindowUnload),c.documents.splice(n,1),i.documents.splice(n,1),o.fire("remove-document",{win:e,doc:t})},onWindowUnload:function(){c.removeDocument(this.document,this)}};e.exports=c},{"./utils":44,"./utils/Signals":34,"./utils/domObjects":38,"./utils/events":40,"./utils/window":52}],34:[function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var i=function(){function t(){r(this,t),this.listeners={}}return t.prototype.on=function(t,e){if(!this.listeners[t])return void(this.listeners[t]=[e]);this.listeners[t].push(e)},t.prototype.off=function(t,e){if(this.listeners[t]){var n=this.listeners[t].indexOf(e);-1!==n&&this.listeners[t].splice(n,1)}},t.prototype.fire=function(t,e){var n=this.listeners[t];if(n)for(var r=0;r<n.length;r++){var i;i=n[r];var o=i;if(!1===o(e,t))return}},t}();i.new=function(){return new i},e.exports=i},{}],35:[function(t,e,n){"use strict";function r(t,e){return-1!==t.indexOf(e)}function i(t,e){for(var n=0;n<e.length;n++){var r;r=e[n];var i=r;t.push(i)}return t}e.exports={contains:r,merge:i}},{}],36:[function(t,e,n){"use strict";var r=t("./window"),i=r.window,o=t("./is"),s=t("./domObjects"),a=s.Element,c=i.navigator,l={supportsTouch:!!("ontouchstart"in i||o.function(i.DocumentTouch)&&s.document instanceof i.DocumentTouch),supportsPointerEvent:!!s.PointerEvent,isIOS:/iP(hone|od|ad)/.test(c.platform),isIOS7:/iP(hone|od|ad)/.test(c.platform)&&/OS 7[^\d]/.test(c.appVersion),isIe9:/MSIE 9/.test(c.userAgent),prefixedMatchesSelector:"matches"in a.prototype?"matches":"webkitMatchesSelector"in a.prototype?"webkitMatchesSelector":"mozMatchesSelector"in a.prototype?"mozMatchesSelector":"oMatchesSelector"in a.prototype?"oMatchesSelector":"msMatchesSelector",pEventTypes:s.PointerEvent?s.PointerEvent===i.MSPointerEvent?{up:"MSPointerUp",down:"MSPointerDown",over:"mouseover",out:"mouseout",move:"MSPointerMove",cancel:"MSPointerCancel"}:{up:"pointerup",down:"pointerdown",over:"pointerover",out:"pointerout",move:"pointermove",cancel:"pointercancel"}:null,wheelEvent:"onmousewheel"in s.document?"mousewheel":"wheel"};l.isOperaMobile="Opera"===c.appName&&l.supportsTouch&&c.userAgent.match("Presto"),e.exports=l},{"./domObjects":38,"./is":46,"./window":52}],37:[function(t,e,n){"use strict";var r=t("./is");e.exports=function t(e){var n={};for(var i in e)r.plainObject(e[i])?n[i]=t(e[i]):n[i]=e[i];return n}},{"./is":46}],38:[function(t,e,n){"use strict";function r(){}var i={},o=t("./window").window;i.document=o.document,i.DocumentFragment=o.DocumentFragment||r,i.SVGElement=o.SVGElement||r,i.SVGSVGElement=o.SVGSVGElement||r,i.SVGElementInstance=o.SVGElementInstance||r,i.Element=o.Element||r,i.HTMLElement=o.HTMLElement||i.Element,i.Event=o.Event,i.Touch=o.Touch||r,i.PointerEvent=o.PointerEvent||o.MSPointerEvent,e.exports=i},{"./window":52}],39:[function(t,e,n){"use strict";var r=t("./window"),i=t("./browser"),o=t("./is"),s=t("./domObjects"),a={nodeContains:function(t,e){for(;e;){if(e===t)return!0;e=e.parentNode}return!1},closest:function(t,e){for(;o.element(t);){if(a.matchesSelector(t,e))return t;t=a.parentNode(t)}return null},parentNode:function(t){var e=t.parentNode;if(o.docFrag(e)){for(;(e=e.host)&&o.docFrag(e););return e}return e},matchesSelector:function(t,e){return r.window!==r.realWindow&&(e=e.replace(/\/deep\//g," ")),t[i.prefixedMatchesSelector](e)},indexOfDeepestElement:function(t){var e=[],n=[],r=void 0,i=t[0],o=i?0:-1,a=void 0,c=void 0,l=void 0,p=void 0;for(l=1;l<t.length;l++)if((r=t[l])&&r!==i)if(i){if(r.parentNode!==r.ownerDocument)if(i.parentNode!==r.ownerDocument){if(!e.length)for(a=i;a.parentNode&&a.parentNode!==a.ownerDocument;)e.unshift(a),a=a.parentNode;if(i instanceof s.HTMLElement&&r instanceof s.SVGElement&&!(r instanceof s.SVGSVGElement)){if(r===i.parentNode)continue;a=r.ownerSVGElement}else a=r;for(n=[];a.parentNode!==a.ownerDocument;)n.unshift(a),a=a.parentNode;for(p=0;n[p]&&n[p]===e[p];)p++;var u=[n[p-1],n[p],e[p]];for(c=u[0].lastChild;c;){if(c===u[1]){i=r,o=l,e=[];break}if(c===u[2])break;c=c.previousSibling}}else i=r,o=l}else i=r,o=l;return o},matchesUpTo:function(t,e,n){for(;o.element(t);){if(a.matchesSelector(t,e))return!0;if((t=a.parentNode(t))===n)return a.matchesSelector(t,e)}return!1},getActualElement:function(t){return t instanceof s.SVGElementInstance?t.correspondingUseElement:t},getScrollXY:function(t){return t=t||r.window,{x:t.scrollX||t.document.documentElement.scrollLeft,y:t.scrollY||t.document.documentElement.scrollTop}},getElementClientRect:function(t){var e=t instanceof s.SVGElement?t.getBoundingClientRect():t.getClientRects()[0];return e&&{left:e.left,right:e.right,top:e.top,bottom:e.bottom,width:e.width||e.right-e.left,height:e.height||e.bottom-e.top}},getElementRect:function(t){var e=a.getElementClientRect(t);if(!i.isIOS7&&e){var n=a.getScrollXY(r.getWindow(t));e.left+=n.x,e.right+=n.x,e.top+=n.y,e.bottom+=n.y}return e},getPath:function(t){for(var e=[];t;)e.push(t),t=a.parentNode(t);return e},trySelector:function(t){return!!o.string(t)&&(s.document.querySelector(t),!0)}};e.exports=a},{"./browser":36,"./domObjects":38,"./is":46,"./window":52}],40:[function(t,e,n){"use strict";function r(t,e,n,r){var i=p(r),o=x.indexOf(t),s=b[o];s||(s={events:{},typeCount:0},o=x.push(t)-1,b.push(s)),s.events[e]||(s.events[e]=[],s.typeCount++),y(s.events[e],n)||(t.addEventListener(e,n,T?i:!!i.capture),s.events[e].push(n))}function i(t,e,n,r){var o=p(r),s=x.indexOf(t),a=b[s];if(a&&a.events)if("all"!==e){if(a.events[e]){var c=a.events[e].length;if("all"===n){for(var l=0;l<c;l++)i(t,e,a.events[e][l],o);return}for(var u=0;u<c;u++)if(a.events[e][u]===n){t.removeEventListener("on"+e,n,T?o:!!o.capture),a.events[e].splice(u,1);break}a.events[e]&&0===a.events[e].length&&(a.events[e]=null,a.typeCount--)}a.typeCount||(b.splice(s,1),x.splice(s,1))}else for(e in a.events)a.events.hasOwnProperty(e)&&i(t,e,"all")}function o(t,e,n,i,o){var s=p(o);if(!w[n]){w[n]={selectors:[],contexts:[],listeners:[]};for(var l=0;l<E.length;l++){var u=E[l];r(u,n,a),r(u,n,c,!0)}}var d=w[n],f=void 0;for(f=d.selectors.length-1;f>=0&&(d.selectors[f]!==t||d.contexts[f]!==e);f--);-1===f&&(f=d.selectors.length,d.selectors.push(t),d.contexts.push(e),d.listeners.push([])),d.listeners[f].push([i,!!s.capture,s.passive])}function s(t,e,n,r,o){var s=p(o),l=w[n],u=!1,d=void 0;if(l)for(d=l.selectors.length-1;d>=0;d--)if(l.selectors[d]===t&&l.contexts[d]===e){for(var f=l.listeners[d],v=f.length-1;v>=0;v--){var g=f[v],h=g[0],m=g[1],y=g[2];if(h===r&&m===!!s.capture&&y===s.passive){f.splice(v,1),f.length||(l.selectors.splice(d,1),l.contexts.splice(d,1),l.listeners.splice(d,1),i(e,n,a),i(e,n,c,!0),l.selectors.length||(w[n]=null)),u=!0;break}}if(u)break}}function a(t,e){var n=p(e),r={},i=w[t.type],o=f.getEventTargets(t),s=o[0],a=s;for(v(r,t),r.originalEvent=t,r.preventDefault=l;u.element(a);){for(var c=0;c<i.selectors.length;c++){var g=i.selectors[c],h=i.contexts[c];if(d.matchesSelector(a,g)&&d.nodeContains(h,s)&&d.nodeContains(h,a)){var m=i.listeners[c];r.currentTarget=a;for(var y=0;y<m.length;y++){var x=m[y],b=x[0],E=x[1],T=x[2];E===!!n.capture&&T===n.passive&&b(r)}}}a=d.parentNode(a)}}function c(t){return a.call(this,t,!0)}function l(){this.originalEvent.preventDefault()}function p(t){return u.object(t)?t:{capture:t}}var u=t("./is"),d=t("./domUtils"),f=t("./pointerUtils"),v=t("./pointerExtend"),g=t("./window"),h=g.window,m=t("./arr"),y=m.contains,x=[],b=[],w={},E=[],T=function(){var t=!1;return h.document.createElement("div").addEventListener("test",null,{get capture(){t=!0}}),t}();e.exports={add:r,remove:i,addDelegate:o,removeDelegate:s,delegateListener:a,delegateUseCapture:c,delegatedEvents:w,documents:E,supportsOptions:T,_elements:x,_targets:b}},{"./arr":35,"./domUtils":39,"./is":46,"./pointerExtend":48,"./pointerUtils":49,"./window":52}],41:[function(t,e,n){"use strict";e.exports=function(t,e){for(var n in e)t[n]=e[n];return t}},{}],42:[function(t,e,n){"use strict";var r=t("./rect"),i=r.resolveRectLike,o=r.rectToXY;e.exports=function(t,e,n){var r=t.options[n],s=r&&r.origin,a=s||t.options.origin,c=i(a,t,e,[t&&e]);return o(c)||{x:0,y:0}}},{"./rect":51}],43:[function(t,e,n){"use strict";e.exports=function(t,e){return Math.sqrt(t*t+e*e)}},{}],44:[function(t,e,n){"use strict";var r=t("./extend"),i=t("./window"),o={warnOnce:function(t,e){var n=!1;return function(){return n||(i.window.console.warn(e),n=!0),t.apply(this,arguments)}},_getQBezierValue:function(t,e,n,r){var i=1-t;return i*i*e+2*i*t*n+t*t*r},getQuadraticCurvePoint:function(t,e,n,r,i,s,a){return{x:o._getQBezierValue(a,t,n,i),y:o._getQBezierValue(a,e,r,s)}},easeOutQuad:function(t,e,n,r){return t/=r,-n*t*(t-2)+e},copyAction:function(t,e){return t.name=e.name,t.axis=e.axis,t.edges=e.edges,t},is:t("./is"),extend:r,hypot:t("./hypot"),getOriginXY:t("./getOriginXY")};r(o,t("./arr")),r(o,t("./domUtils")),r(o,t("./pointerUtils")),r(o,t("./rect")),e.exports=o},{"./arr":35,"./domUtils":39,"./extend":41,"./getOriginXY":42,"./hypot":43,"./is":46,"./pointerUtils":49,"./rect":51,"./window":52}],45:[function(t,e,n){"use strict";var r=t("../scope"),i=t("./index"),o={methodOrder:["simulationResume","mouseOrPen","hasPointer","idle"],search:function(t,e,n){for(var r=i.getPointerType(t),s=i.getPointerId(t),a={pointer:t,pointerId:s,pointerType:r,eventType:e,eventTarget:n},c=0;c<o.methodOrder.length;c++){var l;l=o.methodOrder[c];var p=l,u=o[p](a);if(u)return u}},simulationResume:function(t){var e=t.pointerType,n=t.eventType,o=t.eventTarget;if(!/down|start/i.test(n))return null;for(var s=0;s<r.interactions.length;s++){var a;a=r.interactions[s];var c=a,l=o;if(c.simulation&&c.simulation.allowResume&&c.pointerType===e)for(;l;){if(l===c.element)return c;l=i.parentNode(l)}}return null},mouseOrPen:function(t){var e=t.pointerId,n=t.pointerType,o=t.eventType;if("mouse"!==n&&"pen"!==n)return null;for(var s=void 0,a=0;a<r.interactions.length;a++){var c;c=r.interactions[a];var l=c;if(l.pointerType===n){if(l.simulation&&!i.contains(l.pointerIds,e))continue;if(l.interacting())return l;s||(s=l)}}if(s)return s;for(var p=0;p<r.interactions.length;p++){var u;u=r.interactions[p];var d=u;if(!(d.pointerType!==n||/down/i.test(o)&&d.simulation))return d}return null},hasPointer:function(t){for(var e=t.pointerId,n=0;n<r.interactions.length;n++){var o;o=r.interactions[n];var s=o;if(i.contains(s.pointerIds,e))return s}},idle:function(t){for(var e=t.pointerType,n=0;n<r.interactions.length;n++){var i;i=r.interactions[n];var o=i;if(1===o.pointerIds.length){var s=o.target;if(s&&!s.options.gesture.enabled)continue}else if(o.pointerIds.length>=2)continue;if(!o.interacting()&&e===o.pointerType)return o}return null}};e.exports=o},{"../scope":33,"./index":44}],46:[function(t,e,n){"use strict";var r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=t("./window"),o=t("./isWindow"),s={array:function(){},window:function(t){return t===i.window||o(t)},docFrag:function(t){return s.object(t)&&11===t.nodeType},object:function(t){return!!t&&"object"===(void 0===t?"undefined":r(t))},function:function(t){return"function"==typeof t},number:function(t){return"number"==typeof t},bool:function(t){return"boolean"==typeof t},string:function(t){return"string"==typeof t},element:function(t){if(!t||"object"!==(void 0===t?"undefined":r(t)))return!1;var e=i.getWindow(t)||i.window;return/object|function/.test(r(e.Element))?t instanceof e.Element:1===t.nodeType&&"string"==typeof t.nodeName},plainObject:function(t){return s.object(t)&&"Object"===t.constructor.name}};s.array=function(t){return s.object(t)&&void 0!==t.length&&s.function(t.splice)},e.exports=s},{"./isWindow":47,"./window":52}],47:[function(t,e,n){"use strict";e.exports=function(t){return!(!t||!t.Window)&&t instanceof t.Window}},{}],48:[function(t,e,n){"use strict";function r(t,n){for(var r in n){var i=e.exports.prefixedPropREs,o=!1;for(var s in i)if(0===r.indexOf(s)&&i[s].test(r)){o=!0;break}o||"function"==typeof n[r]||(t[r]=n[r])}return t}r.prefixedPropREs={webkit:/(Movement[XY]|Radius[XY]|RotationAngle|Force)$/},e.exports=r},{}],49:[function(t,e,n){"use strict";var r=t("./hypot"),i=t("./browser"),o=t("./domObjects"),s=t("./domUtils"),a=t("./domObjects"),c=t("./is"),l=t("./pointerExtend"),p={copyCoords:function(t,e){t.page=t.page||{},t.page.x=e.page.x,t.page.y=e.page.y,t.client=t.client||{},t.client.x=e.client.x,t.client.y=e.client.y,t.timeStamp=e.timeStamp},setCoordDeltas:function(t,e,n){t.page.x=n.page.x-e.page.x,t.page.y=n.page.y-e.page.y,t.client.x=n.client.x-e.client.x,t.client.y=n.client.y-e.client.y,t.timeStamp=n.timeStamp-e.timeStamp;var i=Math.max(t.timeStamp/1e3,.001);t.page.speed=r(t.page.x,t.page.y)/i,t.page.vx=t.page.x/i,t.page.vy=t.page.y/i,t.client.speed=r(t.client.x,t.page.y)/i,t.client.vx=t.client.x/i,t.client.vy=t.client.y/i},isNativePointer:function(t){return t instanceof o.Event||t instanceof o.Touch},getXY:function(t,e,n){return n=n||{},t=t||"page",n.x=e[t+"X"],n.y=e[t+"Y"],n},getPageXY:function(t,e){return e=e||{},i.isOperaMobile&&p.isNativePointer(t)?(p.getXY("screen",t,e),e.x+=window.scrollX,e.y+=window.scrollY):p.getXY("page",t,e),e},getClientXY:function(t,e){return e=e||{},i.isOperaMobile&&p.isNativePointer(t)?p.getXY("screen",t,e):p.getXY("client",t,e),e},getPointerId:function(t){return c.number(t.pointerId)?t.pointerId:t.identifier},setCoords:function(t,e,n){var r=e.length>1?p.pointerAverage(e):e[0],i={};p.getPageXY(r,i),t.page.x=i.x,t.page.y=i.y,p.getClientXY(r,i),t.client.x=i.x,t.client.y=i.y,t.timeStamp=c.number(n)?n:(new Date).getTime()},pointerExtend:l,getTouchPair:function(t){var e=[];return c.array(t)?(e[0]=t[0],e[1]=t[1]):"touchend"===t.type?1===t.touches.length?(e[0]=t.touches[0],e[1]=t.changedTouches[0]):0===t.touches.length&&(e[0]=t.changedTouches[0],e[1]=t.changedTouches[1]):(e[0]=t.touches[0],e[1]=t.touches[1]),e},pointerAverage:function(t){for(var e={pageX:0,pageY:0,clientX:0,clientY:0,screenX:0,screenY:0},n=0;n<t.length;n++){var r;r=t[n];var i=r;for(var o in e)e[o]+=i[o]}for(var s in e)e[s]/=t.length;return e},touchBBox:function(t){if(t.length||t.touches&&t.touches.length>1){var e=p.getTouchPair(t),n=Math.min(e[0].pageX,e[1].pageX),r=Math.min(e[0].pageY,e[1].pageY);return{x:n,y:r,left:n,top:r,width:Math.max(e[0].pageX,e[1].pageX)-n,height:Math.max(e[0].pageY,e[1].pageY)-r}}},touchDistance:function(t,e){var n=e+"X",i=e+"Y",o=p.getTouchPair(t),s=o[0][n]-o[1][n],a=o[0][i]-o[1][i];return r(s,a)},touchAngle:function(t,e,n){var r=n+"X",i=n+"Y",o=p.getTouchPair(t),s=o[1][r]-o[0][r],a=o[1][i]-o[0][i];return 180*Math.atan2(a,s)/Math.PI},getPointerType:function(t){return c.string(t.pointerType)?t.pointerType:c.number(t.pointerType)?[void 0,void 0,"touch","pen","mouse"][t.pointerType]:/touch/.test(t.type)||t instanceof a.Touch?"touch":"mouse"},getEventTargets:function(t){var e=c.function(t.composedPath)?t.composedPath():t.path;return[s.getActualElement(e?e[0]:t.target),s.getActualElement(t.currentTarget)]}};e.exports=p},{"./browser":36,"./domObjects":38,"./domUtils":39,"./hypot":43,"./is":46,"./pointerExtend":48}],50:[function(t,e,n){"use strict";for(var r=t("./window"),i=r.window,o=["ms","moz","webkit","o"],s=0,a=void 0,c=void 0,l=0;l<o.length&&!i.requestAnimationFrame;l++)a=i[o[l]+"RequestAnimationFrame"],c=i[o[l]+"CancelAnimationFrame"]||i[o[l]+"CancelRequestAnimationFrame"];a||(a=function(t){var e=(new Date).getTime(),n=Math.max(0,16-(e-s)),r=setTimeout(function(){t(e+n)},n);return s=e+n,r}),c||(c=function(t){clearTimeout(t)}),e.exports={request:a,cancel:c}},{"./window":52}],51:[function(t,e,n){"use strict";var r=t("./extend"),i=t("./is"),o=t("./domUtils"),s=o.closest,a=o.parentNode,c=o.getElementRect,l={getStringOptionResult:function(t,e,n){return i.string(t)?t="parent"===t?a(n):"self"===t?e.getRect(n):s(n,t):null},resolveRectLike:function(t,e,n,r){return t=l.getStringOptionResult(t,e,n)||t,i.function(t)&&(t=t.apply(null,r)),i.element(t)&&(t=c(t)),t},rectToXY:function(t){return t&&{x:"x"in t?t.x:t.left,y:"y"in t?t.y:t.top}},xywhToTlbr:function(t){return!t||"left"in t&&"top"in t||(t=r({},t),t.left=t.x||0,t.top=t.y||0,t.right=t.right||t.left+t.width,t.bottom=t.bottom||t.top+t.height),t},tlbrToXywh:function(t){return!t||"x"in t&&"y"in t||(t=r({},t),t.x=t.left||0,t.top=t.top||0,t.width=t.width||t.right-t.x,t.height=t.height||t.bottom-t.y),t}};e.exports=l},{"./domUtils":39,"./extend":41,"./is":46}],52:[function(t,e,n){"use strict";function r(t){i.realWindow=t;var e=t.document.createTextNode("");e.ownerDocument!==t.document&&"function"==typeof t.wrap&&t.wrap(e)===e&&(t=t.wrap(t)),i.window=t}var i=e.exports,o=t("./isWindow");"undefined"==typeof window?(i.window=void 0,i.realWindow=void 0):r(window),i.getWindow=function(t){if(o(t))return t;var e=t.ownerDocument||t;return e.defaultView||e.parentWindow||i.window},i.init=r},{"./isWindow":47}]},{},[1])(1)});
+
diff --git a/career/js/jquery-1.8.2.min.js b/career/js/jquery-1.8.2.min.js
new file mode 100644
index 0000000..73cd249
--- /dev/null
+++ b/career/js/jquery-1.8.2.min.js
@@ -0,0 +1,2 @@
+/*! jQuery v1.8.2 jquery.com | jquery.org/license */
+(function(a,b){function G(a){var b=F[a]={};return p.each(a.split(s),function(a,c){b[c]=!0}),b}function J(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(I,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:+d+""===d?+d:H.test(d)?p.parseJSON(d):d}catch(f){}p.data(a,c,d)}else d=b}return d}function K(a){var b;for(b in a){if(b==="data"&&p.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function ba(){return!1}function bb(){return!0}function bh(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function bi(a,b){do a=a[b];while(a&&a.nodeType!==1);return a}function bj(a,b,c){b=b||0;if(p.isFunction(b))return p.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return p.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=p.grep(a,function(a){return a.nodeType===1});if(be.test(b))return p.filter(b,d,!c);b=p.filter(b,d)}return p.grep(a,function(a,d){return p.inArray(a,b)>=0===c})}function bk(a){var b=bl.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function bC(a,b){return a.getElementsByTagName(b)[0]||a.appendChild(a.ownerDocument.createElement(b))}function bD(a,b){if(b.nodeType!==1||!p.hasData(a))return;var c,d,e,f=p._data(a),g=p._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;d<e;d++)p.event.add(b,c,h[c][d])}g.data&&(g.data=p.extend({},g.data))}function bE(a,b){var c;if(b.nodeType!==1)return;b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),c==="object"?(b.parentNode&&(b.outerHTML=a.outerHTML),p.support.html5Clone&&a.innerHTML&&!p.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):c==="input"&&bv.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):c==="option"?b.selected=a.defaultSelected:c==="input"||c==="textarea"?b.defaultValue=a.defaultValue:c==="script"&&b.text!==a.text&&(b.text=a.text),b.removeAttribute(p.expando)}function bF(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bG(a){bv.test(a.type)&&(a.defaultChecked=a.checked)}function bY(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=bW.length;while(e--){b=bW[e]+c;if(b in a)return b}return d}function bZ(a,b){return a=b||a,p.css(a,"display")==="none"||!p.contains(a.ownerDocument,a)}function b$(a,b){var c,d,e=[],f=0,g=a.length;for(;f<g;f++){c=a[f];if(!c.style)continue;e[f]=p._data(c,"olddisplay"),b?(!e[f]&&c.style.display==="none"&&(c.style.display=""),c.style.display===""&&bZ(c)&&(e[f]=p._data(c,"olddisplay",cc(c.nodeName)))):(d=bH(c,"display"),!e[f]&&d!=="none"&&p._data(c,"olddisplay",d))}for(f=0;f<g;f++){c=a[f];if(!c.style)continue;if(!b||c.style.display==="none"||c.style.display==="")c.style.display=b?e[f]||"":"none"}return a}function b_(a,b,c){var d=bP.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function ca(a,b,c,d){var e=c===(d?"border":"content")?4:b==="width"?1:0,f=0;for(;e<4;e+=2)c==="margin"&&(f+=p.css(a,c+bV[e],!0)),d?(c==="content"&&(f-=parseFloat(bH(a,"padding"+bV[e]))||0),c!=="margin"&&(f-=parseFloat(bH(a,"border"+bV[e]+"Width"))||0)):(f+=parseFloat(bH(a,"padding"+bV[e]))||0,c!=="padding"&&(f+=parseFloat(bH(a,"border"+bV[e]+"Width"))||0));return f}function cb(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=!0,f=p.support.boxSizing&&p.css(a,"boxSizing")==="border-box";if(d<=0||d==null){d=bH(a,b);if(d<0||d==null)d=a.style[b];if(bQ.test(d))return d;e=f&&(p.support.boxSizingReliable||d===a.style[b]),d=parseFloat(d)||0}return d+ca(a,b,c||(f?"border":"content"),e)+"px"}function cc(a){if(bS[a])return bS[a];var b=p("<"+a+">").appendTo(e.body),c=b.css("display");b.remove();if(c==="none"||c===""){bI=e.body.appendChild(bI||p.extend(e.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!bJ||!bI.createElement)bJ=(bI.contentWindow||bI.contentDocument).document,bJ.write("<!doctype html><html><body>"),bJ.close();b=bJ.body.appendChild(bJ.createElement(a)),c=bH(b,"display"),e.body.removeChild(bI)}return bS[a]=c,c}function ci(a,b,c,d){var e;if(p.isArray(b))p.each(b,function(b,e){c||ce.test(a)?d(a,e):ci(a+"["+(typeof e=="object"?b:"")+"]",e,c,d)});else if(!c&&p.type(b)==="object")for(e in b)ci(a+"["+e+"]",b[e],c,d);else d(a,b)}function cz(a){return function(b,c){typeof b!="string"&&(c=b,b="*");var d,e,f,g=b.toLowerCase().split(s),h=0,i=g.length;if(p.isFunction(c))for(;h<i;h++)d=g[h],f=/^\+/.test(d),f&&(d=d.substr(1)||"*"),e=a[d]=a[d]||[],e[f?"unshift":"push"](c)}}function cA(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h,i=a[f],j=0,k=i?i.length:0,l=a===cv;for(;j<k&&(l||!h);j++)h=i[j](c,d,e),typeof h=="string"&&(!l||g[h]?h=b:(c.dataTypes.unshift(h),h=cA(a,c,d,e,h,g)));return(l||!h)&&!g["*"]&&(h=cA(a,c,d,e,"*",g)),h}function cB(a,c){var d,e,f=p.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((f[d]?a:e||(e={}))[d]=c[d]);e&&p.extend(!0,a,e)}function cC(a,c,d){var e,f,g,h,i=a.contents,j=a.dataTypes,k=a.responseFields;for(f in k)f in d&&(c[k[f]]=d[f]);while(j[0]==="*")j.shift(),e===b&&(e=a.mimeType||c.getResponseHeader("content-type"));if(e)for(f in i)if(i[f]&&i[f].test(e)){j.unshift(f);break}if(j[0]in d)g=j[0];else{for(f in d){if(!j[0]||a.converters[f+" "+j[0]]){g=f;break}h||(h=f)}g=g||h}if(g)return g!==j[0]&&j.unshift(g),d[g]}function cD(a,b){var c,d,e,f,g=a.dataTypes.slice(),h=g[0],i={},j=0;a.dataFilter&&(b=a.dataFilter(b,a.dataType));if(g[1])for(c in a.converters)i[c.toLowerCase()]=a.converters[c];for(;e=g[++j];)if(e!=="*"){if(h!=="*"&&h!==e){c=i[h+" "+e]||i["* "+e];if(!c)for(d in i){f=d.split(" ");if(f[1]===e){c=i[h+" "+f[0]]||i["* "+f[0]];if(c){c===!0?c=i[d]:i[d]!==!0&&(e=f[0],g.splice(j--,0,e));break}}}if(c!==!0)if(c&&a["throws"])b=c(b);else try{b=c(b)}catch(k){return{state:"parsererror",error:c?k:"No conversion from "+h+" to "+e}}}h=e}return{state:"success",data:b}}function cL(){try{return new a.XMLHttpRequest}catch(b){}}function cM(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function cU(){return setTimeout(function(){cN=b},0),cN=p.now()}function cV(a,b){p.each(b,function(b,c){var d=(cT[b]||[]).concat(cT["*"]),e=0,f=d.length;for(;e<f;e++)if(d[e].call(a,b,c))return})}function cW(a,b,c){var d,e=0,f=0,g=cS.length,h=p.Deferred().always(function(){delete i.elem}),i=function(){var b=cN||cU(),c=Math.max(0,j.startTime+j.duration-b),d=1-(c/j.duration||0),e=0,f=j.tweens.length;for(;e<f;e++)j.tweens[e].run(d);return h.notifyWith(a,[j,d,c]),d<1&&f?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:p.extend({},b),opts:p.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:cN||cU(),duration:c.duration,tweens:[],createTween:function(b,c,d){var e=p.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(e),e},stop:function(b){var c=0,d=b?j.tweens.length:0;for(;c<d;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;cX(k,j.opts.specialEasing);for(;e<g;e++){d=cS[e].call(j,a,k,j.opts);if(d)return d}return cV(j,k),p.isFunction(j.opts.start)&&j.opts.start.call(a,j),p.fx.timer(p.extend(i,{anim:j,queue:j.opts.queue,elem:a})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}function cX(a,b){var c,d,e,f,g;for(c in a){d=p.camelCase(c),e=b[d],f=a[c],p.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=p.cssHooks[d];if(g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}}function cY(a,b,c){var d,e,f,g,h,i,j,k,l=this,m=a.style,n={},o=[],q=a.nodeType&&bZ(a);c.queue||(j=p._queueHooks(a,"fx"),j.unqueued==null&&(j.unqueued=0,k=j.empty.fire,j.empty.fire=function(){j.unqueued||k()}),j.unqueued++,l.always(function(){l.always(function(){j.unqueued--,p.queue(a,"fx").length||j.empty.fire()})})),a.nodeType===1&&("height"in b||"width"in b)&&(c.overflow=[m.overflow,m.overflowX,m.overflowY],p.css(a,"display")==="inline"&&p.css(a,"float")==="none"&&(!p.support.inlineBlockNeedsLayout||cc(a.nodeName)==="inline"?m.display="inline-block":m.zoom=1)),c.overflow&&(m.overflow="hidden",p.support.shrinkWrapBlocks||l.done(function(){m.overflow=c.overflow[0],m.overflowX=c.overflow[1],m.overflowY=c.overflow[2]}));for(d in b){f=b[d];if(cP.exec(f)){delete b[d];if(f===(q?"hide":"show"))continue;o.push(d)}}g=o.length;if(g){h=p._data(a,"fxshow")||p._data(a,"fxshow",{}),q?p(a).show():l.done(function(){p(a).hide()}),l.done(function(){var b;p.removeData(a,"fxshow",!0);for(b in n)p.style(a,b,n[b])});for(d=0;d<g;d++)e=o[d],i=l.createTween(e,q?h[e]:0),n[e]=h[e]||p.style(a,e),e in h||(h[e]=i.start,q&&(i.end=i.start,i.start=e==="width"||e==="height"?1:0))}}function cZ(a,b,c,d,e){return new cZ.prototype.init(a,b,c,d,e)}function c$(a,b){var c,d={height:a},e=0;b=b?1:0;for(;e<4;e+=2-b)c=bV[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function da(a){return p.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}var c,d,e=a.document,f=a.location,g=a.navigator,h=a.jQuery,i=a.$,j=Array.prototype.push,k=Array.prototype.slice,l=Array.prototype.indexOf,m=Object.prototype.toString,n=Object.prototype.hasOwnProperty,o=String.prototype.trim,p=function(a,b){return new p.fn.init(a,b,c)},q=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,r=/\S/,s=/\s+/,t=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,u=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,y=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,z=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,A=/^-ms-/,B=/-([\da-z])/gi,C=function(a,b){return(b+"").toUpperCase()},D=function(){e.addEventListener?(e.removeEventListener("DOMContentLoaded",D,!1),p.ready()):e.readyState==="complete"&&(e.detachEvent("onreadystatechange",D),p.ready())},E={};p.fn=p.prototype={constructor:p,init:function(a,c,d){var f,g,h,i;if(!a)return this;if(a.nodeType)return this.context=this[0]=a,this.length=1,this;if(typeof a=="string"){a.charAt(0)==="<"&&a.charAt(a.length-1)===">"&&a.length>=3?f=[null,a,null]:f=u.exec(a);if(f&&(f[1]||!c)){if(f[1])return c=c instanceof p?c[0]:c,i=c&&c.nodeType?c.ownerDocument||c:e,a=p.parseHTML(f[1],i,!0),v.test(f[1])&&p.isPlainObject(c)&&this.attr.call(a,c,!0),p.merge(this,a);g=e.getElementById(f[2]);if(g&&g.parentNode){if(g.id!==f[2])return d.find(a);this.length=1,this[0]=g}return this.context=e,this.selector=a,this}return!c||c.jquery?(c||d).find(a):this.constructor(c).find(a)}return p.isFunction(a)?d.ready(a):(a.selector!==b&&(this.selector=a.selector,this.context=a.context),p.makeArray(a,this))},selector:"",jquery:"1.8.2",length:0,size:function(){return this.length},toArray:function(){return k.call(this)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=p.merge(this.constructor(),a);return d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")"),d},each:function(a,b){return p.each(this,a,b)},ready:function(a){return p.ready.promise().done(a),this},eq:function(a){return a=+a,a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(k.apply(this,arguments),"slice",k.call(arguments).join(","))},map:function(a){return this.pushStack(p.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:j,sort:[].sort,splice:[].splice},p.fn.init.prototype=p.fn,p.extend=p.fn.extend=function(){var a,c,d,e,f,g,h=arguments[0]||{},i=1,j=arguments.length,k=!1;typeof h=="boolean"&&(k=h,h=arguments[1]||{},i=2),typeof h!="object"&&!p.isFunction(h)&&(h={}),j===i&&(h=this,--i);for(;i<j;i++)if((a=arguments[i])!=null)for(c in a){d=h[c],e=a[c];if(h===e)continue;k&&e&&(p.isPlainObject(e)||(f=p.isArray(e)))?(f?(f=!1,g=d&&p.isArray(d)?d:[]):g=d&&p.isPlainObject(d)?d:{},h[c]=p.extend(k,g,e)):e!==b&&(h[c]=e)}return h},p.extend({noConflict:function(b){return a.$===p&&(a.$=i),b&&a.jQuery===p&&(a.jQuery=h),p},isReady:!1,readyWait:1,holdReady:function(a){a?p.readyWait++:p.ready(!0)},ready:function(a){if(a===!0?--p.readyWait:p.isReady)return;if(!e.body)return setTimeout(p.ready,1);p.isReady=!0;if(a!==!0&&--p.readyWait>0)return;d.resolveWith(e,[p]),p.fn.trigger&&p(e).trigger("ready").off("ready")},isFunction:function(a){return p.type(a)==="function"},isArray:Array.isArray||function(a){return p.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):E[m.call(a)]||"object"},isPlainObject:function(a){if(!a||p.type(a)!=="object"||a.nodeType||p.isWindow(a))return!1;try{if(a.constructor&&!n.call(a,"constructor")&&!n.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||n.call(a,d)},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},error:function(a){throw new Error(a)},parseHTML:function(a,b,c){var d;return!a||typeof a!="string"?null:(typeof b=="boolean"&&(c=b,b=0),b=b||e,(d=v.exec(a))?[b.createElement(d[1])]:(d=p.buildFragment([a],b,c?null:[]),p.merge([],(d.cacheable?p.clone(d.fragment):d.fragment).childNodes)))},parseJSON:function(b){if(!b||typeof b!="string")return null;b=p.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(w.test(b.replace(y,"@").replace(z,"]").replace(x,"")))return(new Function("return "+b))();p.error("Invalid JSON: "+b)},parseXML:function(c){var d,e;if(!c||typeof c!="string")return null;try{a.DOMParser?(e=new DOMParser,d=e.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(f){d=b}return(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&p.error("Invalid XML: "+c),d},noop:function(){},globalEval:function(b){b&&r.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(A,"ms-").replace(B,C)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,c,d){var e,f=0,g=a.length,h=g===b||p.isFunction(a);if(d){if(h){for(e in a)if(c.apply(a[e],d)===!1)break}else for(;f<g;)if(c.apply(a[f++],d)===!1)break}else if(h){for(e in a)if(c.call(a[e],e,a[e])===!1)break}else for(;f<g;)if(c.call(a[f],f,a[f++])===!1)break;return a},trim:o&&!o.call(" ")?function(a){return a==null?"":o.call(a)}:function(a){return a==null?"":(a+"").replace(t,"")},makeArray:function(a,b){var c,d=b||[];return a!=null&&(c=p.type(a),a.length==null||c==="string"||c==="function"||c==="regexp"||p.isWindow(a)?j.call(d,a):p.merge(d,a)),d},inArray:function(a,b,c){var d;if(b){if(l)return l.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=c.length,e=a.length,f=0;if(typeof d=="number")for(;f<d;f++)a[e++]=c[f];else while(c[f]!==b)a[e++]=c[f++];return a.length=e,a},grep:function(a,b,c){var d,e=[],f=0,g=a.length;c=!!c;for(;f<g;f++)d=!!b(a[f],f),c!==d&&e.push(a[f]);return e},map:function(a,c,d){var e,f,g=[],h=0,i=a.length,j=a instanceof p||i!==b&&typeof i=="number"&&(i>0&&a[0]&&a[i-1]||i===0||p.isArray(a));if(j)for(;h<i;h++)e=c(a[h],h,d),e!=null&&(g[g.length]=e);else for(f in a)e=c(a[f],f,d),e!=null&&(g[g.length]=e);return g.concat.apply([],g)},guid:1,proxy:function(a,c){var d,e,f;return typeof c=="string"&&(d=a[c],c=a,a=d),p.isFunction(a)?(e=k.call(arguments,2),f=function(){return a.apply(c,e.concat(k.call(arguments)))},f.guid=a.guid=a.guid||p.guid++,f):b},access:function(a,c,d,e,f,g,h){var i,j=d==null,k=0,l=a.length;if(d&&typeof d=="object"){for(k in d)p.access(a,c,k,d[k],1,g,e);f=1}else if(e!==b){i=h===b&&p.isFunction(e),j&&(i?(i=c,c=function(a,b,c){return i.call(p(a),c)}):(c.call(a,e),c=null));if(c)for(;k<l;k++)c(a[k],d,i?e.call(a[k],k,c(a[k],d)):e,h);f=1}return f?a:j?c.call(a):l?c(a[0],d):g},now:function(){return(new Date).getTime()}}),p.ready.promise=function(b){if(!d){d=p.Deferred();if(e.readyState==="complete")setTimeout(p.ready,1);else if(e.addEventListener)e.addEventListener("DOMContentLoaded",D,!1),a.addEventListener("load",p.ready,!1);else{e.attachEvent("onreadystatechange",D),a.attachEvent("onload",p.ready);var c=!1;try{c=a.frameElement==null&&e.documentElement}catch(f){}c&&c.doScroll&&function g(){if(!p.isReady){try{c.doScroll("left")}catch(a){return setTimeout(g,50)}p.ready()}}()}}return d.promise(b)},p.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){E["[object "+b+"]"]=b.toLowerCase()}),c=p(e);var F={};p.Callbacks=function(a){a=typeof a=="string"?F[a]||G(a):p.extend({},a);var c,d,e,f,g,h,i=[],j=!a.once&&[],k=function(b){c=a.memory&&b,d=!0,h=f||0,f=0,g=i.length,e=!0;for(;i&&h<g;h++)if(i[h].apply(b[0],b[1])===!1&&a.stopOnFalse){c=!1;break}e=!1,i&&(j?j.length&&k(j.shift()):c?i=[]:l.disable())},l={add:function(){if(i){var b=i.length;(function d(b){p.each(b,function(b,c){var e=p.type(c);e==="function"&&(!a.unique||!l.has(c))?i.push(c):c&&c.length&&e!=="string"&&d(c)})})(arguments),e?g=i.length:c&&(f=b,k(c))}return this},remove:function(){return i&&p.each(arguments,function(a,b){var c;while((c=p.inArray(b,i,c))>-1)i.splice(c,1),e&&(c<=g&&g--,c<=h&&h--)}),this},has:function(a){return p.inArray(a,i)>-1},empty:function(){return i=[],this},disable:function(){return i=j=c=b,this},disabled:function(){return!i},lock:function(){return j=b,c||l.disable(),this},locked:function(){return!j},fireWith:function(a,b){return b=b||[],b=[a,b.slice?b.slice():b],i&&(!d||j)&&(e?j.push(b):k(b)),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!d}};return l},p.extend({Deferred:function(a){var b=[["resolve","done",p.Callbacks("once memory"),"resolved"],["reject","fail",p.Callbacks("once memory"),"rejected"],["notify","progress",p.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return p.Deferred(function(c){p.each(b,function(b,d){var f=d[0],g=a[b];e[d[1]](p.isFunction(g)?function(){var a=g.apply(this,arguments);a&&p.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f+"With"](this===e?c:this,[a])}:c[f])}),a=null}).promise()},promise:function(a){return a!=null?p.extend(a,d):d}},e={};return d.pipe=d.then,p.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[a^1][2].disable,b[2][2].lock),e[f[0]]=g.fire,e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=k.call(arguments),d=c.length,e=d!==1||a&&p.isFunction(a.promise)?d:0,f=e===1?a:p.Deferred(),g=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?k.call(arguments):d,c===h?f.notifyWith(b,c):--e||f.resolveWith(b,c)}},h,i,j;if(d>1){h=new Array(d),i=new Array(d),j=new Array(d);for(;b<d;b++)c[b]&&p.isFunction(c[b].promise)?c[b].promise().done(g(b,j,c)).fail(f.reject).progress(g(b,i,h)):--e}return e||f.resolveWith(j,c),f.promise()}}),p.support=function(){var b,c,d,f,g,h,i,j,k,l,m,n=e.createElement("div");n.setAttribute("className","t"),n.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",c=n.getElementsByTagName("*"),d=n.getElementsByTagName("a")[0],d.style.cssText="top:1px;float:left;opacity:.5";if(!c||!c.length)return{};f=e.createElement("select"),g=f.appendChild(e.createElement("option")),h=n.getElementsByTagName("input")[0],b={leadingWhitespace:n.firstChild.nodeType===3,tbody:!n.getElementsByTagName("tbody").length,htmlSerialize:!!n.getElementsByTagName("link").length,style:/top/.test(d.getAttribute("style")),hrefNormalized:d.getAttribute("href")==="/a",opacity:/^0.5/.test(d.style.opacity),cssFloat:!!d.style.cssFloat,checkOn:h.value==="on",optSelected:g.selected,getSetAttribute:n.className!=="t",enctype:!!e.createElement("form").enctype,html5Clone:e.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",boxModel:e.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},h.checked=!0,b.noCloneChecked=h.cloneNode(!0).checked,f.disabled=!0,b.optDisabled=!g.disabled;try{delete n.test}catch(o){b.deleteExpando=!1}!n.addEventListener&&n.attachEvent&&n.fireEvent&&(n.attachEvent("onclick",m=function(){b.noCloneEvent=!1}),n.cloneNode(!0).fireEvent("onclick"),n.detachEvent("onclick",m)),h=e.createElement("input"),h.value="t",h.setAttribute("type","radio"),b.radioValue=h.value==="t",h.setAttribute("checked","checked"),h.setAttribute("name","t"),n.appendChild(h),i=e.createDocumentFragment(),i.appendChild(n.lastChild),b.checkClone=i.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=h.checked,i.removeChild(h),i.appendChild(n);if(n.attachEvent)for(k in{submit:!0,change:!0,focusin:!0})j="on"+k,l=j in n,l||(n.setAttribute(j,"return;"),l=typeof n[j]=="function"),b[k+"Bubbles"]=l;return p(function(){var c,d,f,g,h="padding:0;margin:0;border:0;display:block;overflow:hidden;",i=e.getElementsByTagName("body")[0];if(!i)return;c=e.createElement("div"),c.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",i.insertBefore(c,i.firstChild),d=e.createElement("div"),c.appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",f=d.getElementsByTagName("td"),f[0].style.cssText="padding:0;margin:0;border:0;display:none",l=f[0].offsetHeight===0,f[0].style.display="",f[1].style.display="none",b.reliableHiddenOffsets=l&&f[0].offsetHeight===0,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",b.boxSizing=d.offsetWidth===4,b.doesNotIncludeMarginInBodyOffset=i.offsetTop!==1,a.getComputedStyle&&(b.pixelPosition=(a.getComputedStyle(d,null)||{}).top!=="1%",b.boxSizingReliable=(a.getComputedStyle(d,null)||{width:"4px"}).width==="4px",g=e.createElement("div"),g.style.cssText=d.style.cssText=h,g.style.marginRight=g.style.width="0",d.style.width="1px",d.appendChild(g),b.reliableMarginRight=!parseFloat((a.getComputedStyle(g,null)||{}).marginRight)),typeof d.style.zoom!="undefined"&&(d.innerHTML="",d.style.cssText=h+"width:1px;padding:1px;display:inline;zoom:1",b.inlineBlockNeedsLayout=d.offsetWidth===3,d.style.display="block",d.style.overflow="visible",d.innerHTML="<div></div>",d.firstChild.style.width="5px",b.shrinkWrapBlocks=d.offsetWidth!==3,c.style.zoom=1),i.removeChild(c),c=d=f=g=null}),i.removeChild(n),c=d=f=g=h=i=n=null,b}();var H=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,I=/([A-Z])/g;p.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(p.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){return a=a.nodeType?p.cache[a[p.expando]]:a[p.expando],!!a&&!K(a)},data:function(a,c,d,e){if(!p.acceptData(a))return;var f,g,h=p.expando,i=typeof c=="string",j=a.nodeType,k=j?p.cache:a,l=j?a[h]:a[h]&&h;if((!l||!k[l]||!e&&!k[l].data)&&i&&d===b)return;l||(j?a[h]=l=p.deletedIds.pop()||p.guid++:l=h),k[l]||(k[l]={},j||(k[l].toJSON=p.noop));if(typeof c=="object"||typeof c=="function")e?k[l]=p.extend(k[l],c):k[l].data=p.extend(k[l].data,c);return f=k[l],e||(f.data||(f.data={}),f=f.data),d!==b&&(f[p.camelCase(c)]=d),i?(g=f[c],g==null&&(g=f[p.camelCase(c)])):g=f,g},removeData:function(a,b,c){if(!p.acceptData(a))return;var d,e,f,g=a.nodeType,h=g?p.cache:a,i=g?a[p.expando]:p.expando;if(!h[i])return;if(b){d=c?h[i]:h[i].data;if(d){p.isArray(b)||(b in d?b=[b]:(b=p.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,f=b.length;e<f;e++)delete d[b[e]];if(!(c?K:p.isEmptyObject)(d))return}}if(!c){delete h[i].data;if(!K(h[i]))return}g?p.cleanData([a],!0):p.support.deleteExpando||h!=h.window?delete h[i]:h[i]=null},_data:function(a,b,c){return p.data(a,b,c,!0)},acceptData:function(a){var b=a.nodeName&&p.noData[a.nodeName.toLowerCase()];return!b||b!==!0&&a.getAttribute("classid")===b}}),p.fn.extend({data:function(a,c){var d,e,f,g,h,i=this[0],j=0,k=null;if(a===b){if(this.length){k=p.data(i);if(i.nodeType===1&&!p._data(i,"parsedAttrs")){f=i.attributes;for(h=f.length;j<h;j++)g=f[j].name,g.indexOf("data-")||(g=p.camelCase(g.substring(5)),J(i,g,k[g]));p._data(i,"parsedAttrs",!0)}}return k}return typeof a=="object"?this.each(function(){p.data(this,a)}):(d=a.split(".",2),d[1]=d[1]?"."+d[1]:"",e=d[1]+"!",p.access(this,function(c){if(c===b)return k=this.triggerHandler("getData"+e,[d[0]]),k===b&&i&&(k=p.data(i,a),k=J(i,a,k)),k===b&&d[1]?this.data(d[0]):k;d[1]=c,this.each(function(){var b=p(this);b.triggerHandler("setData"+e,d),p.data(this,a,c),b.triggerHandler("changeData"+e,d)})},null,c,arguments.length>1,null,!1))},removeData:function(a){return this.each(function(){p.removeData(this,a)})}}),p.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=p._data(a,b),c&&(!d||p.isArray(c)?d=p._data(a,b,p.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=p.queue(a,b),d=c.length,e=c.shift(),f=p._queueHooks(a,b),g=function(){p.dequeue(a,b)};e==="inprogress"&&(e=c.shift(),d--),e&&(b==="fx"&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return p._data(a,c)||p._data(a,c,{empty:p.Callbacks("once memory").add(function(){p.removeData(a,b+"queue",!0),p.removeData(a,c,!0)})})}}),p.fn.extend({queue:function(a,c){var d=2;return typeof a!="string"&&(c=a,a="fx",d--),arguments.length<d?p.queue(this[0],a):c===b?this:this.each(function(){var b=p.queue(this,a,c);p._queueHooks(this,a),a==="fx"&&b[0]!=="inprogress"&&p.dequeue(this,a)})},dequeue:function(a){return this.each(function(){p.dequeue(this,a)})},delay:function(a,b){return a=p.fx?p.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){var d,e=1,f=p.Deferred(),g=this,h=this.length,i=function(){--e||f.resolveWith(g,[g])};typeof a!="string"&&(c=a,a=b),a=a||"fx";while(h--)d=p._data(g[h],a+"queueHooks"),d&&d.empty&&(e++,d.empty.add(i));return i(),f.promise(c)}});var L,M,N,O=/[\t\r\n]/g,P=/\r/g,Q=/^(?:button|input)$/i,R=/^(?:button|input|object|select|textarea)$/i,S=/^a(?:rea|)$/i,T=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,U=p.support.getSetAttribute;p.fn.extend({attr:function(a,b){return p.access(this,p.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){p.removeAttr(this,a)})},prop:function(a,b){return p.access(this,p.prop,a,b,arguments.length>1)},removeProp:function(a){return a=p.propFix[a]||a,this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,f,g,h;if(p.isFunction(a))return this.each(function(b){p(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(s);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{f=" "+e.className+" ";for(g=0,h=b.length;g<h;g++)f.indexOf(" "+b[g]+" ")<0&&(f+=b[g]+" ");e.className=p.trim(f)}}}return this},removeClass:function(a){var c,d,e,f,g,h,i;if(p.isFunction(a))return this.each(function(b){p(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(s);for(h=0,i=this.length;h<i;h++){e=this[h];if(e.nodeType===1&&e.className){d=(" "+e.className+" ").replace(O," ");for(f=0,g=c.length;f<g;f++)while(d.indexOf(" "+c[f]+" ")>=0)d=d.replace(" "+c[f]+" "," ");e.className=a?p.trim(d):""}}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";return p.isFunction(a)?this.each(function(c){p(this).toggleClass(a.call(this,c,this.className,b),b)}):this.each(function(){if(c==="string"){var e,f=0,g=p(this),h=b,i=a.split(s);while(e=i[f++])h=d?h:!g.hasClass(e),g[h?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&p._data(this,"__className__",this.className),this.className=this.className||a===!1?"":p._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(O," ").indexOf(b)>=0)return!0;return!1},val:function(a){var c,d,e,f=this[0];if(!arguments.length){if(f)return c=p.valHooks[f.type]||p.valHooks[f.nodeName.toLowerCase()],c&&"get"in c&&(d=c.get(f,"value"))!==b?d:(d=f.value,typeof d=="string"?d.replace(P,""):d==null?"":d);return}return e=p.isFunction(a),this.each(function(d){var f,g=p(this);if(this.nodeType!==1)return;e?f=a.call(this,d,g.val()):f=a,f==null?f="":typeof f=="number"?f+="":p.isArray(f)&&(f=p.map(f,function(a){return a==null?"":a+""})),c=p.valHooks[this.type]||p.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,f,"value")===b)this.value=f})}}),p.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,f=a.selectedIndex,g=[],h=a.options,i=a.type==="select-one";if(f<0)return null;c=i?f:0,d=i?f+1:h.length;for(;c<d;c++){e=h[c];if(e.selected&&(p.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!p.nodeName(e.parentNode,"optgroup"))){b=p(e).val();if(i)return b;g.push(b)}}return i&&!g.length&&h.length?p(h[f]).val():g},set:function(a,b){var c=p.makeArray(b);return p(a).find("option").each(function(){this.selected=p.inArray(p(this).val(),c)>=0}),c.length||(a.selectedIndex=-1),c}}},attrFn:{},attr:function(a,c,d,e){var f,g,h,i=a.nodeType;if(!a||i===3||i===8||i===2)return;if(e&&p.isFunction(p.fn[c]))return p(a)[c](d);if(typeof a.getAttribute=="undefined")return p.prop(a,c,d);h=i!==1||!p.isXMLDoc(a),h&&(c=c.toLowerCase(),g=p.attrHooks[c]||(T.test(c)?M:L));if(d!==b){if(d===null){p.removeAttr(a,c);return}return g&&"set"in g&&h&&(f=g.set(a,d,c))!==b?f:(a.setAttribute(c,d+""),d)}return g&&"get"in g&&h&&(f=g.get(a,c))!==null?f:(f=a.getAttribute(c),f===null?b:f)},removeAttr:function(a,b){var c,d,e,f,g=0;if(b&&a.nodeType===1){d=b.split(s);for(;g<d.length;g++)e=d[g],e&&(c=p.propFix[e]||e,f=T.test(e),f||p.attr(a,e,""),a.removeAttribute(U?e:c),f&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(Q.test(a.nodeName)&&a.parentNode)p.error("type property can't be changed");else if(!p.support.radioValue&&b==="radio"&&p.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}},value:{get:function(a,b){return L&&p.nodeName(a,"button")?L.get(a,b):b in a?a.value:null},set:function(a,b,c){if(L&&p.nodeName(a,"button"))return L.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,f,g,h=a.nodeType;if(!a||h===3||h===8||h===2)return;return g=h!==1||!p.isXMLDoc(a),g&&(c=p.propFix[c]||c,f=p.propHooks[c]),d!==b?f&&"set"in f&&(e=f.set(a,d,c))!==b?e:a[c]=d:f&&"get"in f&&(e=f.get(a,c))!==null?e:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):R.test(a.nodeName)||S.test(a.nodeName)&&a.href?0:b}}}}),M={get:function(a,c){var d,e=p.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;return b===!1?p.removeAttr(a,c):(d=p.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase())),c}},U||(N={name:!0,id:!0,coords:!0},L=p.valHooks.button={get:function(a,c){var d;return d=a.getAttributeNode(c),d&&(N[c]?d.value!=="":d.specified)?d.value:b},set:function(a,b,c){var d=a.getAttributeNode(c);return d||(d=e.createAttribute(c),a.setAttributeNode(d)),d.value=b+""}},p.each(["width","height"],function(a,b){p.attrHooks[b]=p.extend(p.attrHooks[b],{set:function(a,c){if(c==="")return a.setAttribute(b,"auto"),c}})}),p.attrHooks.contenteditable={get:L.get,set:function(a,b,c){b===""&&(b="false"),L.set(a,b,c)}}),p.support.hrefNormalized||p.each(["href","src","width","height"],function(a,c){p.attrHooks[c]=p.extend(p.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),p.support.style||(p.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=b+""}}),p.support.optSelected||(p.propHooks.selected=p.extend(p.propHooks.selected,{get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}})),p.support.enctype||(p.propFix.enctype="encoding"),p.support.checkOn||p.each(["radio","checkbox"],function(){p.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),p.each(["radio","checkbox"],function(){p.valHooks[this]=p.extend(p.valHooks[this],{set:function(a,b){if(p.isArray(b))return a.checked=p.inArray(p(a).val(),b)>=0}})});var V=/^(?:textarea|input|select)$/i,W=/^([^\.]*|)(?:\.(.+)|)$/,X=/(?:^|\s)hover(\.\S+|)\b/,Y=/^key/,Z=/^(?:mouse|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=function(a){return p.event.special.hover?a:a.replace(X,"mouseenter$1 mouseleave$1")};p.event={add:function(a,c,d,e,f){var g,h,i,j,k,l,m,n,o,q,r;if(a.nodeType===3||a.nodeType===8||!c||!d||!(g=p._data(a)))return;d.handler&&(o=d,d=o.handler,f=o.selector),d.guid||(d.guid=p.guid++),i=g.events,i||(g.events=i={}),h=g.handle,h||(g.handle=h=function(a){return typeof p!="undefined"&&(!a||p.event.triggered!==a.type)?p.event.dispatch.apply(h.elem,arguments):b},h.elem=a),c=p.trim(_(c)).split(" ");for(j=0;j<c.length;j++){k=W.exec(c[j])||[],l=k[1],m=(k[2]||"").split(".").sort(),r=p.event.special[l]||{},l=(f?r.delegateType:r.bindType)||l,r=p.event.special[l]||{},n=p.extend({type:l,origType:k[1],data:e,handler:d,guid:d.guid,selector:f,needsContext:f&&p.expr.match.needsContext.test(f),namespace:m.join(".")},o),q=i[l];if(!q){q=i[l]=[],q.delegateCount=0;if(!r.setup||r.setup.call(a,e,m,h)===!1)a.addEventListener?a.addEventListener(l,h,!1):a.attachEvent&&a.attachEvent("on"+l,h)}r.add&&(r.add.call(a,n),n.handler.guid||(n.handler.guid=d.guid)),f?q.splice(q.delegateCount++,0,n):q.push(n),p.event.global[l]=!0}a=null},global:{},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,q,r=p.hasData(a)&&p._data(a);if(!r||!(m=r.events))return;b=p.trim(_(b||"")).split(" ");for(f=0;f<b.length;f++){g=W.exec(b[f])||[],h=i=g[1],j=g[2];if(!h){for(h in m)p.event.remove(a,h+b[f],c,d,!0);continue}n=p.event.special[h]||{},h=(d?n.delegateType:n.bindType)||h,o=m[h]||[],k=o.length,j=j?new RegExp("(^|\\.)"+j.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(l=0;l<o.length;l++)q=o[l],(e||i===q.origType)&&(!c||c.guid===q.guid)&&(!j||j.test(q.namespace))&&(!d||d===q.selector||d==="**"&&q.selector)&&(o.splice(l--,1),q.selector&&o.delegateCount--,n.remove&&n.remove.call(a,q));o.length===0&&k!==o.length&&((!n.teardown||n.teardown.call(a,j,r.handle)===!1)&&p.removeEvent(a,h,r.handle),delete m[h])}p.isEmptyObject(m)&&(delete r.handle,p.removeData(a,"events",!0))},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,f,g){if(!f||f.nodeType!==3&&f.nodeType!==8){var h,i,j,k,l,m,n,o,q,r,s=c.type||c,t=[];if($.test(s+p.event.triggered))return;s.indexOf("!")>=0&&(s=s.slice(0,-1),i=!0),s.indexOf(".")>=0&&(t=s.split("."),s=t.shift(),t.sort());if((!f||p.event.customEvent[s])&&!p.event.global[s])return;c=typeof c=="object"?c[p.expando]?c:new p.Event(s,c):new p.Event(s),c.type=s,c.isTrigger=!0,c.exclusive=i,c.namespace=t.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+t.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,m=s.indexOf(":")<0?"on"+s:"";if(!f){h=p.cache;for(j in h)h[j].events&&h[j].events[s]&&p.event.trigger(c,d,h[j].handle.elem,!0);return}c.result=b,c.target||(c.target=f),d=d!=null?p.makeArray(d):[],d.unshift(c),n=p.event.special[s]||{};if(n.trigger&&n.trigger.apply(f,d)===!1)return;q=[[f,n.bindType||s]];if(!g&&!n.noBubble&&!p.isWindow(f)){r=n.delegateType||s,k=$.test(r+s)?f:f.parentNode;for(l=f;k;k=k.parentNode)q.push([k,r]),l=k;l===(f.ownerDocument||e)&&q.push([l.defaultView||l.parentWindow||a,r])}for(j=0;j<q.length&&!c.isPropagationStopped();j++)k=q[j][0],c.type=q[j][1],o=(p._data(k,"events")||{})[c.type]&&p._data(k,"handle"),o&&o.apply(k,d),o=m&&k[m],o&&p.acceptData(k)&&o.apply&&o.apply(k,d)===!1&&c.preventDefault();return c.type=s,!g&&!c.isDefaultPrevented()&&(!n._default||n._default.apply(f.ownerDocument,d)===!1)&&(s!=="click"||!p.nodeName(f,"a"))&&p.acceptData(f)&&m&&f[s]&&(s!=="focus"&&s!=="blur"||c.target.offsetWidth!==0)&&!p.isWindow(f)&&(l=f[m],l&&(f[m]=null),p.event.triggered=s,f[s](),p.event.triggered=b,l&&(f[m]=l)),c.result}return},dispatch:function(c){c=p.event.fix(c||a.event);var d,e,f,g,h,i,j,l,m,n,o=(p._data(this,"events")||{})[c.type]||[],q=o.delegateCount,r=k.call(arguments),s=!c.exclusive&&!c.namespace,t=p.event.special[c.type]||{},u=[];r[0]=c,c.delegateTarget=this;if(t.preDispatch&&t.preDispatch.call(this,c)===!1)return;if(q&&(!c.button||c.type!=="click"))for(f=c.target;f!=this;f=f.parentNode||this)if(f.disabled!==!0||c.type!=="click"){h={},j=[];for(d=0;d<q;d++)l=o[d],m=l.selector,h[m]===b&&(h[m]=l.needsContext?p(m,this).index(f)>=0:p.find(m,this,null,[f]).length),h[m]&&j.push(l);j.length&&u.push({elem:f,matches:j})}o.length>q&&u.push({elem:this,matches:o.slice(q)});for(d=0;d<u.length&&!c.isPropagationStopped();d++){i=u[d],c.currentTarget=i.elem;for(e=0;e<i.matches.length&&!c.isImmediatePropagationStopped();e++){l=i.matches[e];if(s||!c.namespace&&!l.namespace||c.namespace_re&&c.namespace_re.test(l.namespace))c.data=l.data,c.handleObj=l,g=((p.event.special[l.origType]||{}).handle||l.handler).apply(i.elem,r),g!==b&&(c.result=g,g===!1&&(c.preventDefault(),c.stopPropagation()))}}return t.postDispatch&&t.postDispatch.call(this,c),c.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,c){var d,f,g,h=c.button,i=c.fromElement;return a.pageX==null&&c.clientX!=null&&(d=a.target.ownerDocument||e,f=d.documentElement,g=d.body,a.pageX=c.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=c.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?c.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0),a}},fix:function(a){if(a[p.expando])return a;var b,c,d=a,f=p.event.fixHooks[a.type]||{},g=f.props?this.props.concat(f.props):this.props;a=p.Event(d);for(b=g.length;b;)c=g[--b],a[c]=d[c];return a.target||(a.target=d.srcElement||e),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,f.filter?f.filter(a,d):a},special:{load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){p.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=p.extend(new p.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?p.event.trigger(e,null,b):p.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},p.event.handle=p.event.dispatch,p.removeEvent=e.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]=="undefined"&&(a[d]=null),a.detachEvent(d,c))},p.Event=function(a,b){if(this instanceof p.Event)a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?bb:ba):this.type=a,b&&p.extend(this,b),this.timeStamp=a&&a.timeStamp||p.now(),this[p.expando]=!0;else return new p.Event(a,b)},p.Event.prototype={preventDefault:function(){this.isDefaultPrevented=bb;var a=this.originalEvent;if(!a)return;a.preventDefault?a.preventDefault():a.returnValue=!1},stopPropagation:function(){this.isPropagationStopped=bb;var a=this.originalEvent;if(!a)return;a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=bb,this.stopPropagation()},isDefaultPrevented:ba,isPropagationStopped:ba,isImmediatePropagationStopped:ba},p.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){p.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj,g=f.selector;if(!e||e!==d&&!p.contains(d,e))a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b;return c}}}),p.support.submitBubbles||(p.event.special.submit={setup:function(){if(p.nodeName(this,"form"))return!1;p.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=p.nodeName(c,"input")||p.nodeName(c,"button")?c.form:b;d&&!p._data(d,"_submit_attached")&&(p.event.add(d,"submit._submit",function(a){a._submit_bubble=!0}),p._data(d,"_submit_attached",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&p.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){if(p.nodeName(this,"form"))return!1;p.event.remove(this,"._submit")}}),p.support.changeBubbles||(p.event.special.change={setup:function(){if(V.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")p.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),p.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),p.event.simulate("change",this,a,!0)});return!1}p.event.add(this,"beforeactivate._change",function(a){var b=a.target;V.test(b.nodeName)&&!p._data(b,"_change_attached")&&(p.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&p.event.simulate("change",this.parentNode,a,!0)}),p._data(b,"_change_attached",!0))})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){return p.event.remove(this,"._change"),!V.test(this.nodeName)}}),p.support.focusinBubbles||p.each({focus:"focusin",blur:"focusout"},function(a,b){var c=0,d=function(a){p.event.simulate(b,a.target,p.event.fix(a),!0)};p.event.special[b]={setup:function(){c++===0&&e.addEventListener(a,d,!0)},teardown:function(){--c===0&&e.removeEventListener(a,d,!0)}}}),p.fn.extend({on:function(a,c,d,e,f){var g,h;if(typeof a=="object"){typeof c!="string"&&(d=d||c,c=b);for(h in a)this.on(h,c,d,a[h],f);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=ba;else if(!e)return this;return f===1&&(g=e,e=function(a){return p().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=p.guid++)),this.each(function(){p.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,c,d){var e,f;if(a&&a.preventDefault&&a.handleObj)return e=a.handleObj,p(a.delegateTarget).off(e.namespace?e.origType+"."+e.namespace:e.origType,e.selector,e.handler),this;if(typeof a=="object"){for(f in a)this.off(f,c,a[f]);return this}if(c===!1||typeof c=="function")d=c,c=b;return d===!1&&(d=ba),this.each(function(){p.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){return p(this.context).on(a,this.selector,b,c),this},die:function(a,b){return p(this.context).off(a,this.selector||"**",b),this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length===1?this.off(a,"**"):this.off(b,a||"**",c)},trigger:function(a,b){return this.each(function(){p.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return p.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||p.guid++,d=0,e=function(c){var e=(p._data(this,"lastToggle"+a.guid)||0)%d;return p._data(this,"lastToggle"+a.guid,e+1),c.preventDefault(),b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),p.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){p.fn[b]=function(a,c){return c==null&&(c=a,a=null),arguments.length>0?this.on(b,null,a,c):this.trigger(b)},Y.test(b)&&(p.event.fixHooks[b]=p.event.keyHooks),Z.test(b)&&(p.event.fixHooks[b]=p.event.mouseHooks)}),function(a,b){function bc(a,b,c,d){c=c||[],b=b||r;var e,f,i,j,k=b.nodeType;if(!a||typeof a!="string")return c;if(k!==1&&k!==9)return[];i=g(b);if(!i&&!d)if(e=P.exec(a))if(j=e[1]){if(k===9){f=b.getElementById(j);if(!f||!f.parentNode)return c;if(f.id===j)return c.push(f),c}else if(b.ownerDocument&&(f=b.ownerDocument.getElementById(j))&&h(b,f)&&f.id===j)return c.push(f),c}else{if(e[2])return w.apply(c,x.call(b.getElementsByTagName(a),0)),c;if((j=e[3])&&_&&b.getElementsByClassName)return w.apply(c,x.call(b.getElementsByClassName(j),0)),c}return bp(a.replace(L,"$1"),b,c,d,i)}function bd(a){return function(b){var c=b.nodeName.toLowerCase();return c==="input"&&b.type===a}}function be(a){return function(b){var c=b.nodeName.toLowerCase();return(c==="input"||c==="button")&&b.type===a}}function bf(a){return z(function(b){return b=+b,z(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function bg(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}function bh(a,b){var c,d,f,g,h,i,j,k=C[o][a];if(k)return b?0:k.slice(0);h=a,i=[],j=e.preFilter;while(h){if(!c||(d=M.exec(h)))d&&(h=h.slice(d[0].length)),i.push(f=[]);c=!1;if(d=N.exec(h))f.push(c=new q(d.shift())),h=h.slice(c.length),c.type=d[0].replace(L," ");for(g in e.filter)(d=W[g].exec(h))&&(!j[g]||(d=j[g](d,r,!0)))&&(f.push(c=new q(d.shift())),h=h.slice(c.length),c.type=g,c.matches=d);if(!c)break}return b?h.length:h?bc.error(a):C(a,i).slice(0)}function bi(a,b,d){var e=b.dir,f=d&&b.dir==="parentNode",g=u++;return b.first?function(b,c,d){while(b=b[e])if(f||b.nodeType===1)return a(b,c,d)}:function(b,d,h){if(!h){var i,j=t+" "+g+" ",k=j+c;while(b=b[e])if(f||b.nodeType===1){if((i=b[o])===k)return b.sizset;if(typeof i=="string"&&i.indexOf(j)===0){if(b.sizset)return b}else{b[o]=k;if(a(b,d,h))return b.sizset=!0,b;b.sizset=!1}}}else while(b=b[e])if(f||b.nodeType===1)if(a(b,d,h))return b}}function bj(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function bk(a,b,c,d,e){var f,g=[],h=0,i=a.length,j=b!=null;for(;h<i;h++)if(f=a[h])if(!c||c(f,d,e))g.push(f),j&&b.push(h);return g}function bl(a,b,c,d,e,f){return d&&!d[o]&&(d=bl(d)),e&&!e[o]&&(e=bl(e,f)),z(function(f,g,h,i){if(f&&e)return;var j,k,l,m=[],n=[],o=g.length,p=f||bo(b||"*",h.nodeType?[h]:h,[],f),q=a&&(f||!b)?bk(p,m,a,h,i):p,r=c?e||(f?a:o||d)?[]:g:q;c&&c(q,r,h,i);if(d){l=bk(r,n),d(l,[],h,i),j=l.length;while(j--)if(k=l[j])r[n[j]]=!(q[n[j]]=k)}if(f){j=a&&r.length;while(j--)if(k=r[j])f[m[j]]=!(g[m[j]]=k)}else r=bk(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):w.apply(g,r)})}function bm(a){var b,c,d,f=a.length,g=e.relative[a[0].type],h=g||e.relative[" "],i=g?1:0,j=bi(function(a){return a===b},h,!0),k=bi(function(a){return y.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==l)||((b=c).nodeType?j(a,c,d):k(a,c,d))}];for(;i<f;i++)if(c=e.relative[a[i].type])m=[bi(bj(m),c)];else{c=e.filter[a[i].type].apply(null,a[i].matches);if(c[o]){d=++i;for(;d<f;d++)if(e.relative[a[d].type])break;return bl(i>1&&bj(m),i>1&&a.slice(0,i-1).join("").replace(L,"$1"),c,i<d&&bm(a.slice(i,d)),d<f&&bm(a=a.slice(d)),d<f&&a.join(""))}m.push(c)}return bj(m)}function bn(a,b){var d=b.length>0,f=a.length>0,g=function(h,i,j,k,m){var n,o,p,q=[],s=0,u="0",x=h&&[],y=m!=null,z=l,A=h||f&&e.find.TAG("*",m&&i.parentNode||i),B=t+=z==null?1:Math.E;y&&(l=i!==r&&i,c=g.el);for(;(n=A[u])!=null;u++){if(f&&n){for(o=0;p=a[o];o++)if(p(n,i,j)){k.push(n);break}y&&(t=B,c=++g.el)}d&&((n=!p&&n)&&s--,h&&x.push(n))}s+=u;if(d&&u!==s){for(o=0;p=b[o];o++)p(x,q,i,j);if(h){if(s>0)while(u--)!x[u]&&!q[u]&&(q[u]=v.call(k));q=bk(q)}w.apply(k,q),y&&!h&&q.length>0&&s+b.length>1&&bc.uniqueSort(k)}return y&&(t=B,l=z),x};return g.el=0,d?z(g):g}function bo(a,b,c,d){var e=0,f=b.length;for(;e<f;e++)bc(a,b[e],c,d);return c}function bp(a,b,c,d,f){var g,h,j,k,l,m=bh(a),n=m.length;if(!d&&m.length===1){h=m[0]=m[0].slice(0);if(h.length>2&&(j=h[0]).type==="ID"&&b.nodeType===9&&!f&&e.relative[h[1].type]){b=e.find.ID(j.matches[0].replace(V,""),b,f)[0];if(!b)return c;a=a.slice(h.shift().length)}for(g=W.POS.test(a)?-1:h.length-1;g>=0;g--){j=h[g];if(e.relative[k=j.type])break;if(l=e.find[k])if(d=l(j.matches[0].replace(V,""),R.test(h[0].type)&&b.parentNode||b,f)){h.splice(g,1),a=d.length&&h.join("");if(!a)return w.apply(c,x.call(d,0)),c;break}}}return i(a,m)(d,b,f,c,R.test(a)),c}function bq(){}var c,d,e,f,g,h,i,j,k,l,m=!0,n="undefined",o=("sizcache"+Math.random()).replace(".",""),q=String,r=a.document,s=r.documentElement,t=0,u=0,v=[].pop,w=[].push,x=[].slice,y=[].indexOf||function(a){var b=0,c=this.length;for(;b<c;b++)if(this[b]===a)return b;return-1},z=function(a,b){return a[o]=b==null||b,a},A=function(){var a={},b=[];return z(function(c,d){return b.push(c)>e.cacheLength&&delete a[b.shift()],a[c]=d},a)},B=A(),C=A(),D=A(),E="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",G=F.replace("w","w#"),H="([*^$|!~]?=)",I="\\["+E+"*("+F+")"+E+"*(?:"+H+E+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+G+")|)|)"+E+"*\\]",J=":("+F+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+I+")|[^:]|\\\\.)*|.*))\\)|)",K=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+E+"*((?:-\\d)?\\d*)"+E+"*\\)|)(?=[^-]|$)",L=new RegExp("^"+E+"+|((?:^|[^\\\\])(?:\\\\.)*)"+E+"+$","g"),M=new RegExp("^"+E+"*,"+E+"*"),N=new RegExp("^"+E+"*([\\x20\\t\\r\\n\\f>+~])"+E+"*"),O=new RegExp(J),P=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,Q=/^:not/,R=/[\x20\t\r\n\f]*[+~]/,S=/:not\($/,T=/h\d/i,U=/input|select|textarea|button/i,V=/\\(?!\\)/g,W={ID:new RegExp("^#("+F+")"),CLASS:new RegExp("^\\.("+F+")"),NAME:new RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:new RegExp("^("+F.replace("w","w*")+")"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+J),POS:new RegExp(K,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+E+"*(even|odd|(([+-]|)(\\d*)n|)"+E+"*(?:([+-]|)"+E+"*(\\d+)|))"+E+"*\\)|)","i"),needsContext:new RegExp("^"+E+"*[>+~]|"+K,"i")},X=function(a){var b=r.createElement("div");try{return a(b)}catch(c){return!1}finally{b=null}},Y=X(function(a){return a.appendChild(r.createComment("")),!a.getElementsByTagName("*").length}),Z=X(function(a){return a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!==n&&a.firstChild.getAttribute("href")==="#"}),$=X(function(a){a.innerHTML="<select></select>";var b=typeof a.lastChild.getAttribute("multiple");return b!=="boolean"&&b!=="string"}),_=X(function(a){return a.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",!a.getElementsByClassName||!a.getElementsByClassName("e").length?!1:(a.lastChild.className="e",a.getElementsByClassName("e").length===2)}),ba=X(function(a){a.id=o+0,a.innerHTML="<a name='"+o+"'></a><div name='"+o+"'></div>",s.insertBefore(a,s.firstChild);var b=r.getElementsByName&&r.getElementsByName(o).length===2+r.getElementsByName(o+0).length;return d=!r.getElementById(o),s.removeChild(a),b});try{x.call(s.childNodes,0)[0].nodeType}catch(bb){x=function(a){var b,c=[];for(;b=this[a];a++)c.push(b);return c}}bc.matches=function(a,b){return bc(a,null,null,b)},bc.matchesSelector=function(a,b){return bc(b,null,null,[a]).length>0},f=bc.getText=function(a){var b,c="",d=0,e=a.nodeType;if(e){if(e===1||e===9||e===11){if(typeof a.textContent=="string")return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=f(a)}else if(e===3||e===4)return a.nodeValue}else for(;b=a[d];d++)c+=f(b);return c},g=bc.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?b.nodeName!=="HTML":!1},h=bc.contains=s.contains?function(a,b){var c=a.nodeType===9?a.documentElement:a,d=b&&b.parentNode;return a===d||!!(d&&d.nodeType===1&&c.contains&&c.contains(d))}:s.compareDocumentPosition?function(a,b){return b&&!!(a.compareDocumentPosition(b)&16)}:function(a,b){while(b=b.parentNode)if(b===a)return!0;return!1},bc.attr=function(a,b){var c,d=g(a);return d||(b=b.toLowerCase()),(c=e.attrHandle[b])?c(a):d||$?a.getAttribute(b):(c=a.getAttributeNode(b),c?typeof a[b]=="boolean"?a[b]?b:null:c.specified?c.value:null:null)},e=bc.selectors={cacheLength:50,createPseudo:z,match:W,attrHandle:Z?{}:{href:function(a){return a.getAttribute("href",2)},type:function(a){return a.getAttribute("type")}},find:{ID:d?function(a,b,c){if(typeof b.getElementById!==n&&!c){var d=b.getElementById(a);return d&&d.parentNode?[d]:[]}}:function(a,c,d){if(typeof c.getElementById!==n&&!d){var e=c.getElementById(a);return e?e.id===a||typeof e.getAttributeNode!==n&&e.getAttributeNode("id").value===a?[e]:b:[]}},TAG:Y?function(a,b){if(typeof b.getElementsByTagName!==n)return b.getElementsByTagName(a)}:function(a,b){var c=b.getElementsByTagName(a);if(a==="*"){var d,e=[],f=0;for(;d=c[f];f++)d.nodeType===1&&e.push(d);return e}return c},NAME:ba&&function(a,b){if(typeof b.getElementsByName!==n)return b.getElementsByName(name)},CLASS:_&&function(a,b,c){if(typeof b.getElementsByClassName!==n&&!c)return b.getElementsByClassName(a)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(V,""),a[3]=(a[4]||a[5]||"").replace(V,""),a[2]==="~="&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),a[1]==="nth"?(a[2]||bc.error(a[0]),a[3]=+(a[3]?a[4]+(a[5]||1):2*(a[2]==="even"||a[2]==="odd")),a[4]=+(a[6]+a[7]||a[2]==="odd")):a[2]&&bc.error(a[0]),a},PSEUDO:function(a){var b,c;if(W.CHILD.test(a[0]))return null;if(a[3])a[2]=a[3];else if(b=a[4])O.test(b)&&(c=bh(b,!0))&&(c=b.indexOf(")",b.length-c)-b.length)&&(b=b.slice(0,c),a[0]=a[0].slice(0,c)),a[2]=b;return a.slice(0,3)}},filter:{ID:d?function(a){return a=a.replace(V,""),function(b){return b.getAttribute("id")===a}}:function(a){return a=a.replace(V,""),function(b){var c=typeof b.getAttributeNode!==n&&b.getAttributeNode("id");return c&&c.value===a}},TAG:function(a){return a==="*"?function(){return!0}:(a=a.replace(V,"").toLowerCase(),function(b){return b.nodeName&&b.nodeName.toLowerCase()===a})},CLASS:function(a){var b=B[o][a];return b||(b=B(a,new RegExp("(^|"+E+")"+a+"("+E+"|$)"))),function(a){return b.test(a.className||typeof a.getAttribute!==n&&a.getAttribute("class")||"")}},ATTR:function(a,b,c){return function(d,e){var f=bc.attr(d,a);return f==null?b==="!=":b?(f+="",b==="="?f===c:b==="!="?f!==c:b==="^="?c&&f.indexOf(c)===0:b==="*="?c&&f.indexOf(c)>-1:b==="$="?c&&f.substr(f.length-c.length)===c:b==="~="?(" "+f+" ").indexOf(c)>-1:b==="|="?f===c||f.substr(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d){return a==="nth"?function(a){var b,e,f=a.parentNode;if(c===1&&d===0)return!0;if(f){e=0;for(b=f.firstChild;b;b=b.nextSibling)if(b.nodeType===1){e++;if(a===b)break}}return e-=d,e===c||e%c===0&&e/c>=0}:function(b){var c=b;switch(a){case"only":case"first":while(c=c.previousSibling)if(c.nodeType===1)return!1;if(a==="first")return!0;c=b;case"last":while(c=c.nextSibling)if(c.nodeType===1)return!1;return!0}}},PSEUDO:function(a,b){var c,d=e.pseudos[a]||e.setFilters[a.toLowerCase()]||bc.error("unsupported pseudo: "+a);return d[o]?d(b):d.length>1?(c=[a,a,"",b],e.setFilters.hasOwnProperty(a.toLowerCase())?z(function(a,c){var e,f=d(a,b),g=f.length;while(g--)e=y.call(a,f[g]),a[e]=!(c[e]=f[g])}):function(a){return d(a,0,c)}):d}},pseudos:{not:z(function(a){var b=[],c=[],d=i(a.replace(L,"$1"));return d[o]?z(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)if(f=g[h])a[h]=!(b[h]=f)}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:z(function(a){return function(b){return bc(a,b).length>0}}),contains:z(function(a){return function(b){return(b.textContent||b.innerText||f(b)).indexOf(a)>-1}}),enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&!!a.checked||b==="option"&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},parent:function(a){return!e.pseudos.empty(a)},empty:function(a){var b;a=a.firstChild;while(a){if(a.nodeName>"@"||(b=a.nodeType)===3||b===4)return!1;a=a.nextSibling}return!0},header:function(a){return T.test(a.nodeName)},text:function(a){var b,c;return a.nodeName.toLowerCase()==="input"&&(b=a.type)==="text"&&((c=a.getAttribute("type"))==null||c.toLowerCase()===b)},radio:bd("radio"),checkbox:bd("checkbox"),file:bd("file"),password:bd("password"),image:bd("image"),submit:be("submit"),reset:be("reset"),button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&a.type==="button"||b==="button"},input:function(a){return U.test(a.nodeName)},focus:function(a){var b=a.ownerDocument;return a===b.activeElement&&(!b.hasFocus||b.hasFocus())&&(!!a.type||!!a.href)},active:function(a){return a===a.ownerDocument.activeElement},first:bf(function(a,b,c){return[0]}),last:bf(function(a,b,c){return[b-1]}),eq:bf(function(a,b,c){return[c<0?c+b:c]}),even:bf(function(a,b,c){for(var d=0;d<b;d+=2)a.push(d);return a}),odd:bf(function(a,b,c){for(var d=1;d<b;d+=2)a.push(d);return a}),lt:bf(function(a,b,c){for(var d=c<0?c+b:c;--d>=0;)a.push(d);return a}),gt:bf(function(a,b,c){for(var d=c<0?c+b:c;++d<b;)a.push(d);return a})}},j=s.compareDocumentPosition?function(a,b){return a===b?(k=!0,0):(!a.compareDocumentPosition||!b.compareDocumentPosition?a.compareDocumentPosition:a.compareDocumentPosition(b)&4)?-1:1}:function(a,b){if(a===b)return k=!0,0;if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,h=b.parentNode,i=g;if(g===h)return bg(a,b);if(!g)return-1;if(!h)return 1;while(i)e.unshift(i),i=i.parentNode;i=h;while(i)f.unshift(i),i=i.parentNode;c=e.length,d=f.length;for(var j=0;j<c&&j<d;j++)if(e[j]!==f[j])return bg(e[j],f[j]);return j===c?bg(a,f[j],-1):bg(e[j],b,1)},[0,0].sort(j),m=!k,bc.uniqueSort=function(a){var b,c=1;k=m,a.sort(j);if(k)for(;b=a[c];c++)b===a[c-1]&&a.splice(c--,1);return a},bc.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},i=bc.compile=function(a,b){var c,d=[],e=[],f=D[o][a];if(!f){b||(b=bh(a)),c=b.length;while(c--)f=bm(b[c]),f[o]?d.push(f):e.push(f);f=D(a,bn(e,d))}return f},r.querySelectorAll&&function(){var a,b=bp,c=/'|\\/g,d=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,e=[":focus"],f=[":active",":focus"],h=s.matchesSelector||s.mozMatchesSelector||s.webkitMatchesSelector||s.oMatchesSelector||s.msMatchesSelector;X(function(a){a.innerHTML="<select><option selected=''></option></select>",a.querySelectorAll("[selected]").length||e.push("\\["+E+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),a.querySelectorAll(":checked").length||e.push(":checked")}),X(function(a){a.innerHTML="<p test=''></p>",a.querySelectorAll("[test^='']").length&&e.push("[*^$]="+E+"*(?:\"\"|'')"),a.innerHTML="<input type='hidden'/>",a.querySelectorAll(":enabled").length||e.push(":enabled",":disabled")}),e=new RegExp(e.join("|")),bp=function(a,d,f,g,h){if(!g&&!h&&(!e||!e.test(a))){var i,j,k=!0,l=o,m=d,n=d.nodeType===9&&a;if(d.nodeType===1&&d.nodeName.toLowerCase()!=="object"){i=bh(a),(k=d.getAttribute("id"))?l=k.replace(c,"\\$&"):d.setAttribute("id",l),l="[id='"+l+"'] ",j=i.length;while(j--)i[j]=l+i[j].join("");m=R.test(a)&&d.parentNode||d,n=i.join(",")}if(n)try{return w.apply(f,x.call(m.querySelectorAll(n),0)),f}catch(p){}finally{k||d.removeAttribute("id")}}return b(a,d,f,g,h)},h&&(X(function(b){a=h.call(b,"div");try{h.call(b,"[test!='']:sizzle"),f.push("!=",J)}catch(c){}}),f=new RegExp(f.join("|")),bc.matchesSelector=function(b,c){c=c.replace(d,"='$1']");if(!g(b)&&!f.test(c)&&(!e||!e.test(c)))try{var i=h.call(b,c);if(i||a||b.document&&b.document.nodeType!==11)return i}catch(j){}return bc(c,null,null,[b]).length>0})}(),e.pseudos.nth=e.pseudos.eq,e.filters=bq.prototype=e.pseudos,e.setFilters=new bq,bc.attr=p.attr,p.find=bc,p.expr=bc.selectors,p.expr[":"]=p.expr.pseudos,p.unique=bc.uniqueSort,p.text=bc.getText,p.isXMLDoc=bc.isXML,p.contains=bc.contains}(a);var bc=/Until$/,bd=/^(?:parents|prev(?:Until|All))/,be=/^.[^:#\[\.,]*$/,bf=p.expr.match.needsContext,bg={children:!0,contents:!0,next:!0,prev:!0};p.fn.extend({find:function(a){var b,c,d,e,f,g,h=this;if(typeof a!="string")return p(a).filter(function(){for(b=0,c=h.length;b<c;b++)if(p.contains(h[b],this))return!0});g=this.pushStack("","find",a);for(b=0,c=this.length;b<c;b++){d=g.length,p.find(a,this[b],g);if(b>0)for(e=d;e<g.length;e++)for(f=0;f<d;f++)if(g[f]===g[e]){g.splice(e--,1);break}}return g},has:function(a){var b,c=p(a,this),d=c.length;return this.filter(function(){for(b=0;b<d;b++)if(p.contains(this,c[b]))return!0})},not:function(a){return this.pushStack(bj(this,a,!1),"not",a)},filter:function(a){return this.pushStack(bj(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?bf.test(a)?p(a,this.context).index(this[0])>=0:p.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c,d=0,e=this.length,f=[],g=bf.test(a)||typeof a!="string"?p(a,b||this.context):0;for(;d<e;d++){c=this[d];while(c&&c.ownerDocument&&c!==b&&c.nodeType!==11){if(g?g.index(c)>-1:p.find.matchesSelector(c,a)){f.push(c);break}c=c.parentNode}}return f=f.length>1?p.unique(f):f,this.pushStack(f,"closest",a)},index:function(a){return a?typeof a=="string"?p.inArray(this[0],p(a)):p.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(a,b){var c=typeof a=="string"?p(a,b):p.makeArray(a&&a.nodeType?[a]:a),d=p.merge(this.get(),c);return this.pushStack(bh(c[0])||bh(d[0])?d:p.unique(d))},addBack:function(a){return this.add(a==null?this.prevObject:this.prevObject.filter(a))}}),p.fn.andSelf=p.fn.addBack,p.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return p.dir(a,"parentNode")},parentsUntil:function(a,b,c){return p.dir(a,"parentNode",c)},next:function(a){return bi(a,"nextSibling")},prev:function(a){return bi(a,"previousSibling")},nextAll:function(a){return p.dir(a,"nextSibling")},prevAll:function(a){return p.dir(a,"previousSibling")},nextUntil:function(a,b,c){return p.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return p.dir(a,"previousSibling",c)},siblings:function(a){return p.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return p.sibling(a.firstChild)},contents:function(a){return p.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:p.merge([],a.childNodes)}},function(a,b){p.fn[a]=function(c,d){var e=p.map(this,b,c);return bc.test(a)||(d=c),d&&typeof d=="string"&&(e=p.filter(d,e)),e=this.length>1&&!bg[a]?p.unique(e):e,this.length>1&&bd.test(a)&&(e=e.reverse()),this.pushStack(e,a,k.call(arguments).join(","))}}),p.extend({filter:function(a,b,c){return c&&(a=":not("+a+")"),b.length===1?p.find.matchesSelector(b[0],a)?[b[0]]:[]:p.find.matches(a,b)},dir:function(a,c,d){var e=[],f=a[c];while(f&&f.nodeType!==9&&(d===b||f.nodeType!==1||!p(f).is(d)))f.nodeType===1&&e.push(f),f=f[c];return e},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var bl="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",bm=/ jQuery\d+="(?:null|\d+)"/g,bn=/^\s+/,bo=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bp=/<([\w:]+)/,bq=/<tbody/i,br=/<|&#?\w+;/,bs=/<(?:script|style|link)/i,bt=/<(?:script|object|embed|option|style)/i,bu=new RegExp("<(?:"+bl+")[\\s/>]","i"),bv=/^(?:checkbox|radio)$/,bw=/checked\s*(?:[^=]|=\s*.checked.)/i,bx=/\/(java|ecma)script/i,by=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,bz={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bA=bk(e),bB=bA.appendChild(e.createElement("div"));bz.optgroup=bz.option,bz.tbody=bz.tfoot=bz.colgroup=bz.caption=bz.thead,bz.th=bz.td,p.support.htmlSerialize||(bz._default=[1,"X<div>","</div>"]),p.fn.extend({text:function(a){return p.access(this,function(a){return a===b?p.text(this):this.empty().append((this[0]&&this[0].ownerDocument||e).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(p.isFunction(a))return this.each(function(b){p(this).wrapAll(a.call(this,b))});if(this[0]){var b=p(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return p.isFunction(a)?this.each(function(b){p(this).wrapInner(a.call(this,b))}):this.each(function(){var b=p(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=p.isFunction(a);return this.each(function(c){p(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){p.nodeName(this,"body")||p(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(a,this.firstChild)})},before:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(a,this),"before",this.selector)}},after:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(this,a),"after",this.selector)}},remove:function(a,b){var c,d=0;for(;(c=this[d])!=null;d++)if(!a||p.filter(a,[c]).length)!b&&c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),p.cleanData([c])),c.parentNode&&c.parentNode.removeChild(c);return this},empty:function(){var a,b=0;for(;(a=this[b])!=null;b++){a.nodeType===1&&p.cleanData(a.getElementsByTagName("*"));while(a.firstChild)a.removeChild(a.firstChild)}return this},clone:function(a,b){return a=a==null?!1:a,b=b==null?a:b,this.map(function(){return p.clone(this,a,b)})},html:function(a){return p.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(bm,""):b;if(typeof a=="string"&&!bs.test(a)&&(p.support.htmlSerialize||!bu.test(a))&&(p.support.leadingWhitespace||!bn.test(a))&&!bz[(bp.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(bo,"<$1></$2>");try{for(;d<e;d++)c=this[d]||{},c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),c.innerHTML=a);c=0}catch(f){}}c&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(a){return bh(this[0])?this.length?this.pushStack(p(p.isFunction(a)?a():a),"replaceWith",a):this:p.isFunction(a)?this.each(function(b){var c=p(this),d=c.html();c.replaceWith(a.call(this,b,d))}):(typeof a!="string"&&(a=p(a).detach()),this.each(function(){var b=this.nextSibling,c=this.parentNode;p(this).remove(),b?p(b).before(a):p(c).append(a)}))},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){a=[].concat.apply([],a);var e,f,g,h,i=0,j=a[0],k=[],l=this.length;if(!p.support.checkClone&&l>1&&typeof j=="string"&&bw.test(j))return this.each(function(){p(this).domManip(a,c,d)});if(p.isFunction(j))return this.each(function(e){var f=p(this);a[0]=j.call(this,e,c?f.html():b),f.domManip(a,c,d)});if(this[0]){e=p.buildFragment(a,this,k),g=e.fragment,f=g.firstChild,g.childNodes.length===1&&(g=f);if(f){c=c&&p.nodeName(f,"tr");for(h=e.cacheable||l-1;i<l;i++)d.call(c&&p.nodeName(this[i],"table")?bC(this[i],"tbody"):this[i],i===h?g:p.clone(g,!0,!0))}g=f=null,k.length&&p.each(k,function(a,b){b.src?p.ajax?p.ajax({url:b.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):p.error("no ajax"):p.globalEval((b.text||b.textContent||b.innerHTML||"").replace(by,"")),b.parentNode&&b.parentNode.removeChild(b)})}return this}}),p.buildFragment=function(a,c,d){var f,g,h,i=a[0];return c=c||e,c=!c.nodeType&&c[0]||c,c=c.ownerDocument||c,a.length===1&&typeof i=="string"&&i.length<512&&c===e&&i.charAt(0)==="<"&&!bt.test(i)&&(p.support.checkClone||!bw.test(i))&&(p.support.html5Clone||!bu.test(i))&&(g=!0,f=p.fragments[i],h=f!==b),f||(f=c.createDocumentFragment(),p.clean(a,c,f,d),g&&(p.fragments[i]=h&&f)),{fragment:f,cacheable:g}},p.fragments={},p.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){p.fn[a]=function(c){var d,e=0,f=[],g=p(c),h=g.length,i=this.length===1&&this[0].parentNode;if((i==null||i&&i.nodeType===11&&i.childNodes.length===1)&&h===1)return g[b](this[0]),this;for(;e<h;e++)d=(e>0?this.clone(!0):this).get(),p(g[e])[b](d),f=f.concat(d);return this.pushStack(f,a,g.selector)}}),p.extend({clone:function(a,b,c){var d,e,f,g;p.support.html5Clone||p.isXMLDoc(a)||!bu.test("<"+a.nodeName+">")?g=a.cloneNode(!0):(bB.innerHTML=a.outerHTML,bB.removeChild(g=bB.firstChild));if((!p.support.noCloneEvent||!p.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!p.isXMLDoc(a)){bE(a,g),d=bF(a),e=bF(g);for(f=0;d[f];++f)e[f]&&bE(d[f],e[f])}if(b){bD(a,g);if(c){d=bF(a),e=bF(g);for(f=0;d[f];++f)bD(d[f],e[f])}}return d=e=null,g},clean:function(a,b,c,d){var f,g,h,i,j,k,l,m,n,o,q,r,s=b===e&&bA,t=[];if(!b||typeof b.createDocumentFragment=="undefined")b=e;for(f=0;(h=a[f])!=null;f++){typeof h=="number"&&(h+="");if(!h)continue;if(typeof h=="string")if(!br.test(h))h=b.createTextNode(h);else{s=s||bk(b),l=b.createElement("div"),s.appendChild(l),h=h.replace(bo,"<$1></$2>"),i=(bp.exec(h)||["",""])[1].toLowerCase(),j=bz[i]||bz._default,k=j[0],l.innerHTML=j[1]+h+j[2];while(k--)l=l.lastChild;if(!p.support.tbody){m=bq.test(h),n=i==="table"&&!m?l.firstChild&&l.firstChild.childNodes:j[1]==="<table>"&&!m?l.childNodes:[];for(g=n.length-1;g>=0;--g)p.nodeName(n[g],"tbody")&&!n[g].childNodes.length&&n[g].parentNode.removeChild(n[g])}!p.support.leadingWhitespace&&bn.test(h)&&l.insertBefore(b.createTextNode(bn.exec(h)[0]),l.firstChild),h=l.childNodes,l.parentNode.removeChild(l)}h.nodeType?t.push(h):p.merge(t,h)}l&&(h=l=s=null);if(!p.support.appendChecked)for(f=0;(h=t[f])!=null;f++)p.nodeName(h,"input")?bG(h):typeof h.getElementsByTagName!="undefined"&&p.grep(h.getElementsByTagName("input"),bG);if(c){q=function(a){if(!a.type||bx.test(a.type))return d?d.push(a.parentNode?a.parentNode.removeChild(a):a):c.appendChild(a)};for(f=0;(h=t[f])!=null;f++)if(!p.nodeName(h,"script")||!q(h))c.appendChild(h),typeof h.getElementsByTagName!="undefined"&&(r=p.grep(p.merge([],h.getElementsByTagName("script")),q),t.splice.apply(t,[f+1,0].concat(r)),f+=r.length)}return t},cleanData:function(a,b){var c,d,e,f,g=0,h=p.expando,i=p.cache,j=p.support.deleteExpando,k=p.event.special;for(;(e=a[g])!=null;g++)if(b||p.acceptData(e)){d=e[h],c=d&&i[d];if(c){if(c.events)for(f in c.events)k[f]?p.event.remove(e,f):p.removeEvent(e,f,c.handle);i[d]&&(delete i[d],j?delete e[h]:e.removeAttribute?e.removeAttribute(h):e[h]=null,p.deletedIds.push(d))}}}}),function(){var a,b;p.uaMatch=function(a){a=a.toLowerCase();var b=/(chrome)[ \/]([\w.]+)/.exec(a)||/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||a.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},a=p.uaMatch(g.userAgent),b={},a.browser&&(b[a.browser]=!0,b.version=a.version),b.chrome?b.webkit=!0:b.webkit&&(b.safari=!0),p.browser=b,p.sub=function(){function a(b,c){return new a.fn.init(b,c)}p.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function c(c,d){return d&&d instanceof p&&!(d instanceof a)&&(d=a(d)),p.fn.init.call(this,c,d,b)},a.fn.init.prototype=a.fn;var b=a(e);return a}}();var bH,bI,bJ,bK=/alpha\([^)]*\)/i,bL=/opacity=([^)]*)/,bM=/^(top|right|bottom|left)$/,bN=/^(none|table(?!-c[ea]).+)/,bO=/^margin/,bP=new RegExp("^("+q+")(.*)$","i"),bQ=new RegExp("^("+q+")(?!px)[a-z%]+$","i"),bR=new RegExp("^([-+])=("+q+")","i"),bS={},bT={position:"absolute",visibility:"hidden",display:"block"},bU={letterSpacing:0,fontWeight:400},bV=["Top","Right","Bottom","Left"],bW=["Webkit","O","Moz","ms"],bX=p.fn.toggle;p.fn.extend({css:function(a,c){return p.access(this,function(a,c,d){return d!==b?p.style(a,c,d):p.css(a,c)},a,c,arguments.length>1)},show:function(){return b$(this,!0)},hide:function(){return b$(this)},toggle:function(a,b){var c=typeof a=="boolean";return p.isFunction(a)&&p.isFunction(b)?bX.apply(this,arguments):this.each(function(){(c?a:bZ(this))?p(this).show():p(this).hide()})}}),p.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bH(a,"opacity");return c===""?"1":c}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":p.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!a||a.nodeType===3||a.nodeType===8||!a.style)return;var f,g,h,i=p.camelCase(c),j=a.style;c=p.cssProps[i]||(p.cssProps[i]=bY(j,i)),h=p.cssHooks[c]||p.cssHooks[i];if(d===b)return h&&"get"in h&&(f=h.get(a,!1,e))!==b?f:j[c];g=typeof d,g==="string"&&(f=bR.exec(d))&&(d=(f[1]+1)*f[2]+parseFloat(p.css(a,c)),g="number");if(d==null||g==="number"&&isNaN(d))return;g==="number"&&!p.cssNumber[i]&&(d+="px");if(!h||!("set"in h)||(d=h.set(a,d,e))!==b)try{j[c]=d}catch(k){}},css:function(a,c,d,e){var f,g,h,i=p.camelCase(c);return c=p.cssProps[i]||(p.cssProps[i]=bY(a.style,i)),h=p.cssHooks[c]||p.cssHooks[i],h&&"get"in h&&(f=h.get(a,!0,e)),f===b&&(f=bH(a,c)),f==="normal"&&c in bU&&(f=bU[c]),d||e!==b?(g=parseFloat(f),d||p.isNumeric(g)?g||0:f):f},swap:function(a,b,c){var d,e,f={};for(e in b)f[e]=a.style[e],a.style[e]=b[e];d=c.call(a);for(e in b)a.style[e]=f[e];return d}}),a.getComputedStyle?bH=function(b,c){var d,e,f,g,h=a.getComputedStyle(b,null),i=b.style;return h&&(d=h[c],d===""&&!p.contains(b.ownerDocument,b)&&(d=p.style(b,c)),bQ.test(d)&&bO.test(c)&&(e=i.width,f=i.minWidth,g=i.maxWidth,i.minWidth=i.maxWidth=i.width=d,d=h.width,i.width=e,i.minWidth=f,i.maxWidth=g)),d}:e.documentElement.currentStyle&&(bH=function(a,b){var c,d,e=a.currentStyle&&a.currentStyle[b],f=a.style;return e==null&&f&&f[b]&&(e=f[b]),bQ.test(e)&&!bM.test(b)&&(c=f.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":e,e=f.pixelLeft+"px",f.left=c,d&&(a.runtimeStyle.left=d)),e===""?"auto":e}),p.each(["height","width"],function(a,b){p.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth===0&&bN.test(bH(a,"display"))?p.swap(a,bT,function(){return cb(a,b,d)}):cb(a,b,d)},set:function(a,c,d){return b_(a,c,d?ca(a,b,d,p.support.boxSizing&&p.css(a,"boxSizing")==="border-box"):0)}}}),p.support.opacity||(p.cssHooks.opacity={get:function(a,b){return bL.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=p.isNumeric(b)?"alpha(opacity="+b*100+")":"",f=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&p.trim(f.replace(bK,""))===""&&c.removeAttribute){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bK.test(f)?f.replace(bK,e):f+" "+e}}),p(function(){p.support.reliableMarginRight||(p.cssHooks.marginRight={get:function(a,b){return p.swap(a,{display:"inline-block"},function(){if(b)return bH(a,"marginRight")})}}),!p.support.pixelPosition&&p.fn.position&&p.each(["top","left"],function(a,b){p.cssHooks[b]={get:function(a,c){if(c){var d=bH(a,b);return bQ.test(d)?p(a).position()[b]+"px":d}}}})}),p.expr&&p.expr.filters&&(p.expr.filters.hidden=function(a){return a.offsetWidth===0&&a.offsetHeight===0||!p.support.reliableHiddenOffsets&&(a.style&&a.style.display||bH(a,"display"))==="none"},p.expr.filters.visible=function(a){return!p.expr.filters.hidden(a)}),p.each({margin:"",padding:"",border:"Width"},function(a,b){p.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bV[d]+b]=e[d]||e[d-2]||e[0];return f}},bO.test(a)||(p.cssHooks[a+b].set=b_)});var cd=/%20/g,ce=/\[\]$/,cf=/\r?\n/g,cg=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,ch=/^(?:select|textarea)/i;p.fn.extend({serialize:function(){return p.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?p.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ch.test(this.nodeName)||cg.test(this.type))}).map(function(a,b){var c=p(this).val();return c==null?null:p.isArray(c)?p.map(c,function(a,c){return{name:b.name,value:a.replace(cf,"\r\n")}}):{name:b.name,value:c.replace(cf,"\r\n")}}).get()}}),p.param=function(a,c){var d,e=[],f=function(a,b){b=p.isFunction(b)?b():b==null?"":b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=p.ajaxSettings&&p.ajaxSettings.traditional);if(p.isArray(a)||a.jquery&&!p.isPlainObject(a))p.each(a,function(){f(this.name,this.value)});else for(d in a)ci(d,a[d],c,f);return e.join("&").replace(cd,"+")};var cj,ck,cl=/#.*$/,cm=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,cn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,co=/^(?:GET|HEAD)$/,cp=/^\/\//,cq=/\?/,cr=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,cs=/([?&])_=[^&]*/,ct=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,cu=p.fn.load,cv={},cw={},cx=["*/"]+["*"];try{ck=f.href}catch(cy){ck=e.createElement("a"),ck.href="",ck=ck.href}cj=ct.exec(ck.toLowerCase())||[],p.fn.load=function(a,c,d){if(typeof a!="string"&&cu)return cu.apply(this,arguments);if(!this.length)return this;var e,f,g,h=this,i=a.indexOf(" ");return i>=0&&(e=a.slice(i,a.length),a=a.slice(0,i)),p.isFunction(c)?(d=c,c=b):c&&typeof c=="object"&&(f="POST"),p.ajax({url:a,type:f,dataType:"html",data:c,complete:function(a,b){d&&h.each(d,g||[a.responseText,b,a])}}).done(function(a){g=arguments,h.html(e?p("<div>").append(a.replace(cr,"")).find(e):a)}),this},p.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){p.fn[b]=function(a){return this.on(b,a)}}),p.each(["get","post"],function(a,c){p[c]=function(a,d,e,f){return p.isFunction(d)&&(f=f||e,e=d,d=b),p.ajax({type:c,url:a,data:d,success:e,dataType:f})}}),p.extend({getScript:function(a,c){return p.get(a,b,c,"script")},getJSON:function(a,b,c){return p.get(a,b,c,"json")},ajaxSetup:function(a,b){return b?cB(a,p.ajaxSettings):(b=a,a=p.ajaxSettings),cB(a,b),a},ajaxSettings:{url:ck,isLocal:cn.test(cj[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":cx},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":p.parseJSON,"text xml":p.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:cz(cv),ajaxTransport:cz(cw),ajax:function(a,c){function y(a,c,f,i){var k,s,t,u,w,y=c;if(v===2)return;v=2,h&&clearTimeout(h),g=b,e=i||"",x.readyState=a>0?4:0,f&&(u=cC(l,x,f));if(a>=200&&a<300||a===304)l.ifModified&&(w=x.getResponseHeader("Last-Modified"),w&&(p.lastModified[d]=w),w=x.getResponseHeader("Etag"),w&&(p.etag[d]=w)),a===304?(y="notmodified",k=!0):(k=cD(l,u),y=k.state,s=k.data,t=k.error,k=!t);else{t=y;if(!y||a)y="error",a<0&&(a=0)}x.status=a,x.statusText=(c||y)+"",k?o.resolveWith(m,[s,y,x]):o.rejectWith(m,[x,y,t]),x.statusCode(r),r=b,j&&n.trigger("ajax"+(k?"Success":"Error"),[x,l,k?s:t]),q.fireWith(m,[x,y]),j&&(n.trigger("ajaxComplete",[x,l]),--p.active||p.event.trigger("ajaxStop"))}typeof a=="object"&&(c=a,a=b),c=c||{};var d,e,f,g,h,i,j,k,l=p.ajaxSetup({},c),m=l.context||l,n=m!==l&&(m.nodeType||m instanceof p)?p(m):p.event,o=p.Deferred(),q=p.Callbacks("once memory"),r=l.statusCode||{},t={},u={},v=0,w="canceled",x={readyState:0,setRequestHeader:function(a,b){if(!v){var c=a.toLowerCase();a=u[c]=u[c]||a,t[a]=b}return this},getAllResponseHeaders:function(){return v===2?e:null},getResponseHeader:function(a){var c;if(v===2){if(!f){f={};while(c=cm.exec(e))f[c[1].toLowerCase()]=c[2]}c=f[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){return v||(l.mimeType=a),this},abort:function(a){return a=a||w,g&&g.abort(a),y(0,a),this}};o.promise(x),x.success=x.done,x.error=x.fail,x.complete=q.add,x.statusCode=function(a){if(a){var b;if(v<2)for(b in a)r[b]=[r[b],a[b]];else b=a[x.status],x.always(b)}return this},l.url=((a||l.url)+"").replace(cl,"").replace(cp,cj[1]+"//"),l.dataTypes=p.trim(l.dataType||"*").toLowerCase().split(s),l.crossDomain==null&&(i=ct.exec(l.url.toLowerCase())||!1,l.crossDomain=i&&i.join(":")+(i[3]?"":i[1]==="http:"?80:443)!==cj.join(":")+(cj[3]?"":cj[1]==="http:"?80:443)),l.data&&l.processData&&typeof l.data!="string"&&(l.data=p.param(l.data,l.traditional)),cA(cv,l,c,x);if(v===2)return x;j=l.global,l.type=l.type.toUpperCase(),l.hasContent=!co.test(l.type),j&&p.active++===0&&p.event.trigger("ajaxStart");if(!l.hasContent){l.data&&(l.url+=(cq.test(l.url)?"&":"?")+l.data,delete l.data),d=l.url;if(l.cache===!1){var z=p.now(),A=l.url.replace(cs,"$1_="+z);l.url=A+(A===l.url?(cq.test(l.url)?"&":"?")+"_="+z:"")}}(l.data&&l.hasContent&&l.contentType!==!1||c.contentType)&&x.setRequestHeader("Content-Type",l.contentType),l.ifModified&&(d=d||l.url,p.lastModified[d]&&x.setRequestHeader("If-Modified-Since",p.lastModified[d]),p.etag[d]&&x.setRequestHeader("If-None-Match",p.etag[d])),x.setRequestHeader("Accept",l.dataTypes[0]&&l.accepts[l.dataTypes[0]]?l.accepts[l.dataTypes[0]]+(l.dataTypes[0]!=="*"?", "+cx+"; q=0.01":""):l.accepts["*"]);for(k in l.headers)x.setRequestHeader(k,l.headers[k]);if(!l.beforeSend||l.beforeSend.call(m,x,l)!==!1&&v!==2){w="abort";for(k in{success:1,error:1,complete:1})x[k](l[k]);g=cA(cw,l,c,x);if(!g)y(-1,"No Transport");else{x.readyState=1,j&&n.trigger("ajaxSend",[x,l]),l.async&&l.timeout>0&&(h=setTimeout(function(){x.abort("timeout")},l.timeout));try{v=1,g.send(t,y)}catch(B){if(v<2)y(-1,B);else throw B}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var cE=[],cF=/\?/,cG=/(=)\?(?=&|$)|\?\?/,cH=p.now();p.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=cE.pop()||p.expando+"_"+cH++;return this[a]=!0,a}}),p.ajaxPrefilter("json jsonp",function(c,d,e){var f,g,h,i=c.data,j=c.url,k=c.jsonp!==!1,l=k&&cG.test(j),m=k&&!l&&typeof i=="string"&&!(c.contentType||"").indexOf("application/x-www-form-urlencoded")&&cG.test(i);if(c.dataTypes[0]==="jsonp"||l||m)return f=c.jsonpCallback=p.isFunction(c.jsonpCallback)?c.jsonpCallback():c.jsonpCallback,g=a[f],l?c.url=j.replace(cG,"$1"+f):m?c.data=i.replace(cG,"$1"+f):k&&(c.url+=(cF.test(j)?"&":"?")+c.jsonp+"="+f),c.converters["script json"]=function(){return h||p.error(f+" was not called"),h[0]},c.dataTypes[0]="json",a[f]=function(){h=arguments},e.always(function(){a[f]=g,c[f]&&(c.jsonpCallback=d.jsonpCallback,cE.push(f)),h&&p.isFunction(g)&&g(h[0]),h=g=b}),"script"}),p.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){return p.globalEval(a),a}}}),p.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),p.ajaxTransport("script",function(a){if(a.crossDomain){var c,d=e.head||e.getElementsByTagName("head")[0]||e.documentElement;return{send:function(f,g){c=e.createElement("script"),c.async="async",a.scriptCharset&&(c.charset=a.scriptCharset),c.src=a.url,c.onload=c.onreadystatechange=function(a,e){if(e||!c.readyState||/loaded|complete/.test(c.readyState))c.onload=c.onreadystatechange=null,d&&c.parentNode&&d.removeChild(c),c=b,e||g(200,"success")},d.insertBefore(c,d.firstChild)},abort:function(){c&&c.onload(0,1)}}}});var cI,cJ=a.ActiveXObject?function(){for(var a in cI)cI[a](0,1)}:!1,cK=0;p.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&cL()||cM()}:cL,function(a){p.extend(p.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(p.ajaxSettings.xhr()),p.support.ajax&&p.ajaxTransport(function(c){if(!c.crossDomain||p.support.cors){var d;return{send:function(e,f){var g,h,i=c.xhr();c.username?i.open(c.type,c.url,c.async,c.username,c.password):i.open(c.type,c.url,c.async);if(c.xhrFields)for(h in c.xhrFields)i[h]=c.xhrFields[h];c.mimeType&&i.overrideMimeType&&i.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(h in e)i.setRequestHeader(h,e[h])}catch(j){}i.send(c.hasContent&&c.data||null),d=function(a,e){var h,j,k,l,m;try{if(d&&(e||i.readyState===4)){d=b,g&&(i.onreadystatechange=p.noop,cJ&&delete cI[g]);if(e)i.readyState!==4&&i.abort();else{h=i.status,k=i.getAllResponseHeaders(),l={},m=i.responseXML,m&&m.documentElement&&(l.xml=m);try{l.text=i.responseText}catch(a){}try{j=i.statusText}catch(n){j=""}!h&&c.isLocal&&!c.crossDomain?h=l.text?200:404:h===1223&&(h=204)}}}catch(o){e||f(-1,o)}l&&f(h,j,l,k)},c.async?i.readyState===4?setTimeout(d,0):(g=++cK,cJ&&(cI||(cI={},p(a).unload(cJ)),cI[g]=d),i.onreadystatechange=d):d()},abort:function(){d&&d(0,1)}}}});var cN,cO,cP=/^(?:toggle|show|hide)$/,cQ=new RegExp("^(?:([-+])=|)("+q+")([a-z%]*)$","i"),cR=/queueHooks$/,cS=[cY],cT={"*":[function(a,b){var c,d,e=this.createTween(a,b),f=cQ.exec(b),g=e.cur(),h=+g||0,i=1,j=20;if(f){c=+f[2],d=f[3]||(p.cssNumber[a]?"":"px");if(d!=="px"&&h){h=p.css(e.elem,a,!0)||c||1;do i=i||".5",h=h/i,p.style(e.elem,a,h+d);while(i!==(i=e.cur()/g)&&i!==1&&--j)}e.unit=d,e.start=h,e.end=f[1]?h+(f[1]+1)*c:c}return e}]};p.Animation=p.extend(cW,{tweener:function(a,b){p.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");var c,d=0,e=a.length;for(;d<e;d++)c=a[d],cT[c]=cT[c]||[],cT[c].unshift(b)},prefilter:function(a,b){b?cS.unshift(a):cS.push(a)}}),p.Tween=cZ,cZ.prototype={constructor:cZ,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(p.cssNumber[c]?"":"px")},cur:function(){var a=cZ.propHooks[this.prop];return a&&a.get?a.get(this):cZ.propHooks._default.get(this)},run:function(a){var b,c=cZ.propHooks[this.prop];return this.options.duration?this.pos=b=p.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):cZ.propHooks._default.set(this),this}},cZ.prototype.init.prototype=cZ.prototype,cZ.propHooks={_default:{get:function(a){var b;return a.elem[a.prop]==null||!!a.elem.style&&a.elem.style[a.prop]!=null?(b=p.css(a.elem,a.prop,!1,""),!b||b==="auto"?0:b):a.elem[a.prop]},set:function(a){p.fx.step[a.prop]?p.fx.step[a.prop](a):a.elem.style&&(a.elem.style[p.cssProps[a.prop]]!=null||p.cssHooks[a.prop])?p.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},cZ.propHooks.scrollTop=cZ.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},p.each(["toggle","show","hide"],function(a,b){var c=p.fn[b];p.fn[b]=function(d,e,f){return d==null||typeof d=="boolean"||!a&&p.isFunction(d)&&p.isFunction(e)?c.apply(this,arguments):this.animate(c$(b,!0),d,e,f)}}),p.fn.extend({fadeTo:function(a,b,c,d){return this.filter(bZ).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=p.isEmptyObject(a),f=p.speed(b,c,d),g=function(){var b=cW(this,p.extend({},a),f);e&&b.stop(!0)};return e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,c,d){var e=function(a){var b=a.stop;delete a.stop,b(d)};return typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,c=a!=null&&a+"queueHooks",f=p.timers,g=p._data(this);if(c)g[c]&&g[c].stop&&e(g[c]);else for(c in g)g[c]&&g[c].stop&&cR.test(c)&&e(g[c]);for(c=f.length;c--;)f[c].elem===this&&(a==null||f[c].queue===a)&&(f[c].anim.stop(d),b=!1,f.splice(c,1));(b||!d)&&p.dequeue(this,a)})}}),p.each({slideDown:c$("show"),slideUp:c$("hide"),slideToggle:c$("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){p.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),p.speed=function(a,b,c){var d=a&&typeof a=="object"?p.extend({},a):{complete:c||!c&&b||p.isFunction(a)&&a,duration:a,easing:c&&b||b&&!p.isFunction(b)&&b};d.duration=p.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in p.fx.speeds?p.fx.speeds[d.duration]:p.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";return d.old=d.complete,d.complete=function(){p.isFunction(d.old)&&d.old.call(this),d.queue&&p.dequeue(this,d.queue)},d},p.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},p.timers=[],p.fx=cZ.prototype.init,p.fx.tick=function(){var a,b=p.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||p.fx.stop()},p.fx.timer=function(a){a()&&p.timers.push(a)&&!cO&&(cO=setInterval(p.fx.tick,p.fx.interval))},p.fx.interval=13,p.fx.stop=function(){clearInterval(cO),cO=null},p.fx.speeds={slow:600,fast:200,_default:400},p.fx.step={},p.expr&&p.expr.filters&&(p.expr.filters.animated=function(a){return p.grep(p.timers,function(b){return a===b.elem}).length});var c_=/^(?:body|html)$/i;p.fn.offset=function(a){if(arguments.length)return a===b?this:this.each(function(b){p.offset.setOffset(this,a,b)});var c,d,e,f,g,h,i,j={top:0,left:0},k=this[0],l=k&&k.ownerDocument;if(!l)return;return(d=l.body)===k?p.offset.bodyOffset(k):(c=l.documentElement,p.contains(c,k)?(typeof k.getBoundingClientRect!="undefined"&&(j=k.getBoundingClientRect()),e=da(l),f=c.clientTop||d.clientTop||0,g=c.clientLeft||d.clientLeft||0,h=e.pageYOffset||c.scrollTop,i=e.pageXOffset||c.scrollLeft,{top:j.top+h-f,left:j.left+i-g}):j)},p.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;return p.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(p.css(a,"marginTop"))||0,c+=parseFloat(p.css(a,"marginLeft"))||0),{top:b,left:c}},setOffset:function(a,b,c){var d=p.css(a,"position");d==="static"&&(a.style.position="relative");var e=p(a),f=e.offset(),g=p.css(a,"top"),h=p.css(a,"left"),i=(d==="absolute"||d==="fixed")&&p.inArray("auto",[g,h])>-1,j={},k={},l,m;i?(k=e.position(),l=k.top,m=k.left):(l=parseFloat(g)||0,m=parseFloat(h)||0),p.isFunction(b)&&(b=b.call(a,c,f)),b.top!=null&&(j.top=b.top-f.top+l),b.left!=null&&(j.left=b.left-f.left+m),"using"in b?b.using.call(a,j):e.css(j)}},p.fn.extend({position:function(){if(!this[0])return;var a=this[0],b=this.offsetParent(),c=this.offset(),d=c_.test(b[0].nodeName)?{top:0,left:0}:b.offset();return c.top-=parseFloat(p.css(a,"marginTop"))||0,c.left-=parseFloat(p.css(a,"marginLeft"))||0,d.top+=parseFloat(p.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(p.css(b[0],"borderLeftWidth"))||0,{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||e.body;while(a&&!c_.test(a.nodeName)&&p.css(a,"position")==="static")a=a.offsetParent;return a||e.body})}}),p.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);p.fn[a]=function(e){return p.access(this,function(a,e,f){var g=da(a);if(f===b)return g?c in g?g[c]:g.document.documentElement[e]:a[e];g?g.scrollTo(d?p(g).scrollLeft():f,d?f:p(g).scrollTop()):a[e]=f},a,e,arguments.length,null)}}),p.each({Height:"height",Width:"width"},function(a,c){p.each({padding:"inner"+a,content:c,"":"outer"+a},function(d,e){p.fn[e]=function(e,f){var g=arguments.length&&(d||typeof e!="boolean"),h=d||(e===!0||f===!0?"margin":"border");return p.access(this,function(c,d,e){var f;return p.isWindow(c)?c.document.documentElement["client"+a]:c.nodeType===9?(f=c.documentElement,Math.max(c.body["scroll"+a],f["scroll"+a],c.body["offset"+a],f["offset"+a],f["client"+a])):e===b?p.css(c,d,e,h):p.style(c,d,e,h)},c,g?e:b,g,null)}})}),a.jQuery=a.$=p,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return p})})(window);
\ No newline at end of file
diff --git a/career/js/jquery.min.js b/career/js/jquery.min.js
new file mode 100644
index 0000000..764485c
--- /dev/null
+++ b/career/js/jquery.min.js
@@ -0,0 +1,4 @@
+/*! jQuery v3.2.1 | (c) JS Foundation and other contributors | jquery.org/license */
+!function(a,b){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){"use strict";var c=[],d=a.document,e=Object.getPrototypeOf,f=c.slice,g=c.concat,h=c.push,i=c.indexOf,j={},k=j.toString,l=j.hasOwnProperty,m=l.toString,n=m.call(Object),o={};function p(a,b){b=b||d;var c=b.createElement("script");c.text=a,b.head.appendChild(c).parentNode.removeChild(c)}var q="3.2.1",r=function(a,b){return new r.fn.init(a,b)},s=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,t=/^-ms-/,u=/-([a-z])/g,v=function(a,b){return b.toUpperCase()};r.fn=r.prototype={jquery:q,constructor:r,length:0,toArray:function(){return f.call(this)},get:function(a){return null==a?f.call(this):a<0?this[a+this.length]:this[a]},pushStack:function(a){var b=r.merge(this.constructor(),a);return b.prevObject=this,b},each:function(a){return r.each(this,a)},map:function(a){return this.pushStack(r.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(f.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(a<0?b:0);return this.pushStack(c>=0&&c<b?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:h,sort:c.sort,splice:c.splice},r.extend=r.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||r.isFunction(g)||(g={}),h===i&&(g=this,h--);h<i;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(r.isPlainObject(d)||(e=Array.isArray(d)))?(e?(e=!1,f=c&&Array.isArray(c)?c:[]):f=c&&r.isPlainObject(c)?c:{},g[b]=r.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},r.extend({expando:"jQuery"+(q+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===r.type(a)},isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){var b=r.type(a);return("number"===b||"string"===b)&&!isNaN(a-parseFloat(a))},isPlainObject:function(a){var b,c;return!(!a||"[object Object]"!==k.call(a))&&(!(b=e(a))||(c=l.call(b,"constructor")&&b.constructor,"function"==typeof c&&m.call(c)===n))},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?j[k.call(a)]||"object":typeof a},globalEval:function(a){p(a)},camelCase:function(a){return a.replace(t,"ms-").replace(u,v)},each:function(a,b){var c,d=0;if(w(a)){for(c=a.length;d<c;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(s,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(w(Object(a))?r.merge(c,"string"==typeof a?[a]:a):h.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:i.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;d<c;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;f<g;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,f=0,h=[];if(w(a))for(d=a.length;f<d;f++)e=b(a[f],f,c),null!=e&&h.push(e);else for(f in a)e=b(a[f],f,c),null!=e&&h.push(e);return g.apply([],h)},guid:1,proxy:function(a,b){var c,d,e;if("string"==typeof b&&(c=a[b],b=a,a=c),r.isFunction(a))return d=f.call(arguments,2),e=function(){return a.apply(b||this,d.concat(f.call(arguments)))},e.guid=a.guid=a.guid||r.guid++,e},now:Date.now,support:o}),"function"==typeof Symbol&&(r.fn[Symbol.iterator]=c[Symbol.iterator]),r.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){j["[object "+b+"]"]=b.toLowerCase()});function w(a){var b=!!a&&"length"in a&&a.length,c=r.type(a);return"function"!==c&&!r.isWindow(a)&&("array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a)}var x=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=function(a,b){for(var c=0,d=a.length;c<d;c++)if(a[c]===b)return c;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\0-\\xa0])+",M="\\["+K+"*("+L+")(?:"+K+"*([*^$|!~]?=)"+K+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+L+"))|)"+K+"*\\]",N=":("+L+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+M+")*)|.*)\\)|)",O=new RegExp(K+"+","g"),P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(N),U=new RegExp("^"+L+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+N),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),aa=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:d<0?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ba=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ca=function(a,b){return b?"\0"===a?"\ufffd":a.slice(0,-1)+"\\"+a.charCodeAt(a.length-1).toString(16)+" ":"\\"+a},da=function(){m()},ea=ta(function(a){return a.disabled===!0&&("form"in a||"label"in a)},{dir:"parentNode",next:"legend"});try{G.apply(D=H.call(v.childNodes),v.childNodes),D[v.childNodes.length].nodeType}catch(fa){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s=b&&b.ownerDocument,w=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==w&&9!==w&&11!==w)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==w&&(l=Z.exec(a)))if(f=l[1]){if(9===w){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(s&&(j=s.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(l[2])return G.apply(d,b.getElementsByTagName(a)),d;if((f=l[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==w)s=b,r=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(ba,ca):b.setAttribute("id",k=u),o=g(a),h=o.length;while(h--)o[h]="#"+k+" "+sa(o[h]);r=o.join(","),s=$.test(a)&&qa(b.parentNode)||b}if(r)try{return G.apply(d,s.querySelectorAll(r)),d}catch(x){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(P,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("fieldset");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&a.sourceIndex-b.sourceIndex;if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return function(b){return"form"in b?b.parentNode&&b.disabled===!1?"label"in b?"label"in b.parentNode?b.parentNode.disabled===a:b.disabled===a:b.isDisabled===a||b.isDisabled!==!a&&ea(b)===a:b.disabled===a:"label"in b&&b.disabled===a}}function pa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function qa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return!!b&&"HTML"!==b.nodeName},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),v!==n&&(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(n.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){return a.getAttribute("id")===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}}):(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c,d,e,f=b.getElementById(a);if(f){if(c=f.getAttributeNode("id"),c&&c.value===a)return[f];e=b.getElementsByName(a),d=0;while(f=e[d++])if(c=f.getAttributeNode("id"),c&&c.value===a)return[f]}return[]}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){if("undefined"!=typeof b.getElementsByClassName&&p)return b.getElementsByClassName(a)},r=[],q=[],(c.qsa=Y.test(n.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\r\\' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){a.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+K+"*[*^$|!~]?="),2!==a.querySelectorAll(":enabled").length&&q.push(":enabled",":disabled"),o.appendChild(a).disabled=!0,2!==a.querySelectorAll(":disabled").length&&q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Y.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"*"),s.call(a,"[s!='']:x"),r.push("!=",N)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Y.test(o.compareDocumentPosition),t=b||Y.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?I(k,a)-I(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?I(k,a)-I(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?la(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(S,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.escape=function(a){return(a+"").replace(ba,ca)},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(_,aa),a[3]=(a[3]||a[4]||a[5]||"").replace(_,aa),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return V.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&T.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(_,aa).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:!b||(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(O," ")+" ").indexOf(c)>-1:"|="===b&&(e===c||e.slice(0,c.length+1)===c+"-"))}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(P,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(_,aa),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return U.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(_,aa).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:oa(!1),disabled:oa(!0),checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:pa(function(){return[0]}),last:pa(function(a,b){return[b-1]}),eq:pa(function(a,b,c){return[c<0?c+b:c]}),even:pa(function(a,b){for(var c=0;c<b;c+=2)a.push(c);return a}),odd:pa(function(a,b){for(var c=1;c<b;c+=2)a.push(c);return a}),lt:pa(function(a,b,c){for(var d=c<0?c+b:c;--d>=0;)a.push(d);return a}),gt:pa(function(a,b,c){for(var d=c<0?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=ma(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=na(b);function ra(){}ra.prototype=d.filters=d.pseudos,d.setFilters=new ra,g=ga.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){c&&!(e=Q.exec(h))||(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=R.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(P," ")}),h=h.slice(c.length));for(g in d.filter)!(e=V[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?ga.error(a):z(a,i).slice(0)};function sa(a){for(var b=0,c=a.length,d="";b<c;b++)d+=a[b].value;return d}function ta(a,b,c){var d=b.dir,e=b.next,f=e||d,g=c&&"parentNode"===f,h=x++;return b.first?function(b,c,e){while(b=b[d])if(1===b.nodeType||g)return a(b,c,e);return!1}:function(b,c,i){var j,k,l,m=[w,h];if(i){while(b=b[d])if((1===b.nodeType||g)&&a(b,c,i))return!0}else while(b=b[d])if(1===b.nodeType||g)if(l=b[u]||(b[u]={}),k=l[b.uniqueID]||(l[b.uniqueID]={}),e&&e===b.nodeName.toLowerCase())b=b[d]||b;else{if((j=k[f])&&j[0]===w&&j[1]===h)return m[2]=j[2];if(k[f]=m,m[2]=a(b,c,i))return!0}return!1}}function ua(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function va(a,b,c){for(var d=0,e=b.length;d<e;d++)ga(a,b[d],c);return c}function wa(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;h<i;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function xa(a,b,c,d,e,f){return d&&!d[u]&&(d=xa(d)),e&&!e[u]&&(e=xa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||va(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:wa(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=wa(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=wa(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ya(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ta(function(a){return a===b},h,!0),l=ta(function(a){return I(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];i<f;i++)if(c=d.relative[a[i].type])m=[ta(ua(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;e<f;e++)if(d.relative[a[e].type])break;return xa(i>1&&ua(m),i>1&&sa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(P,"$1"),c,i<e&&ya(a.slice(i,e)),e<f&&ya(a=a.slice(e)),e<f&&sa(a))}m.push(c)}return ua(m)}function za(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=E.call(i));u=wa(u)}G.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&ga.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=ya(b[c]),f[u]?d.push(f):e.push(f);f=A(a,za(e,d)),f.selector=a}return f},i=ga.select=function(a,b,c,e){var f,i,j,k,l,m="function"==typeof a&&a,n=!e&&g(a=m.selector||a);if(c=c||[],1===n.length){if(i=n[0]=n[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&9===b.nodeType&&p&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(_,aa),b)||[])[0],!b)return c;m&&(b=b.parentNode),a=a.slice(i.shift().value.length)}f=V.needsContext.test(a)?0:i.length;while(f--){if(j=i[f],d.relative[k=j.type])break;if((l=d.find[k])&&(e=l(j.matches[0].replace(_,aa),$.test(i[0].type)&&qa(b.parentNode)||b))){if(i.splice(f,1),a=e.length&&sa(i),!a)return G.apply(c,e),c;break}}}return(m||h(a,n))(e,b,!p,c,!b||$.test(a)&&qa(b.parentNode)||b),c},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("fieldset"))}),ja(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){if(!c)return a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){if(!c&&"input"===a.nodeName.toLowerCase())return a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(J,function(a,b,c){var d;if(!c)return a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);r.find=x,r.expr=x.selectors,r.expr[":"]=r.expr.pseudos,r.uniqueSort=r.unique=x.uniqueSort,r.text=x.getText,r.isXMLDoc=x.isXML,r.contains=x.contains,r.escapeSelector=x.escape;var y=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&r(a).is(c))break;d.push(a)}return d},z=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},A=r.expr.match.needsContext;function B(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()}var C=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,D=/^.[^:#\[\.,]*$/;function E(a,b,c){return r.isFunction(b)?r.grep(a,function(a,d){return!!b.call(a,d,a)!==c}):b.nodeType?r.grep(a,function(a){return a===b!==c}):"string"!=typeof b?r.grep(a,function(a){return i.call(b,a)>-1!==c}):D.test(b)?r.filter(b,a,c):(b=r.filter(b,a),r.grep(a,function(a){return i.call(b,a)>-1!==c&&1===a.nodeType}))}r.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?r.find.matchesSelector(d,a)?[d]:[]:r.find.matches(a,r.grep(b,function(a){return 1===a.nodeType}))},r.fn.extend({find:function(a){var b,c,d=this.length,e=this;if("string"!=typeof a)return this.pushStack(r(a).filter(function(){for(b=0;b<d;b++)if(r.contains(e[b],this))return!0}));for(c=this.pushStack([]),b=0;b<d;b++)r.find(a,e[b],c);return d>1?r.uniqueSort(c):c},filter:function(a){return this.pushStack(E(this,a||[],!1))},not:function(a){return this.pushStack(E(this,a||[],!0))},is:function(a){return!!E(this,"string"==typeof a&&A.test(a)?r(a):a||[],!1).length}});var F,G=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,H=r.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||F,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:G.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof r?b[0]:b,r.merge(this,r.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),C.test(e[1])&&r.isPlainObject(b))for(e in b)r.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&(this[0]=f,this.length=1),this}return a.nodeType?(this[0]=a,this.length=1,this):r.isFunction(a)?void 0!==c.ready?c.ready(a):a(r):r.makeArray(a,this)};H.prototype=r.fn,F=r(d);var I=/^(?:parents|prev(?:Until|All))/,J={children:!0,contents:!0,next:!0,prev:!0};r.fn.extend({has:function(a){var b=r(a,this),c=b.length;return this.filter(function(){for(var a=0;a<c;a++)if(r.contains(this,b[a]))return!0})},closest:function(a,b){var c,d=0,e=this.length,f=[],g="string"!=typeof a&&r(a);if(!A.test(a))for(;d<e;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&r.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?r.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?i.call(r(a),this[0]):i.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(r.uniqueSort(r.merge(this.get(),r(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function K(a,b){while((a=a[b])&&1!==a.nodeType);return a}r.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return y(a,"parentNode")},parentsUntil:function(a,b,c){return y(a,"parentNode",c)},next:function(a){return K(a,"nextSibling")},prev:function(a){return K(a,"previousSibling")},nextAll:function(a){return y(a,"nextSibling")},prevAll:function(a){return y(a,"previousSibling")},nextUntil:function(a,b,c){return y(a,"nextSibling",c)},prevUntil:function(a,b,c){return y(a,"previousSibling",c)},siblings:function(a){return z((a.parentNode||{}).firstChild,a)},children:function(a){return z(a.firstChild)},contents:function(a){return B(a,"iframe")?a.contentDocument:(B(a,"template")&&(a=a.content||a),r.merge([],a.childNodes))}},function(a,b){r.fn[a]=function(c,d){var e=r.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=r.filter(d,e)),this.length>1&&(J[a]||r.uniqueSort(e),I.test(a)&&e.reverse()),this.pushStack(e)}});var L=/[^\x20\t\r\n\f]+/g;function M(a){var b={};return r.each(a.match(L)||[],function(a,c){b[c]=!0}),b}r.Callbacks=function(a){a="string"==typeof a?M(a):r.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=e||a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h<f.length)f[h].apply(c[0],c[1])===!1&&a.stopOnFalse&&(h=f.length,c=!1)}a.memory||(c=!1),b=!1,e&&(f=c?[]:"")},j={add:function(){return f&&(c&&!b&&(h=f.length-1,g.push(c)),function d(b){r.each(b,function(b,c){r.isFunction(c)?a.unique&&j.has(c)||f.push(c):c&&c.length&&"string"!==r.type(c)&&d(c)})}(arguments),c&&!b&&i()),this},remove:function(){return r.each(arguments,function(a,b){var c;while((c=r.inArray(b,f,c))>-1)f.splice(c,1),c<=h&&h--}),this},has:function(a){return a?r.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||b||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j};function N(a){return a}function O(a){throw a}function P(a,b,c,d){var e;try{a&&r.isFunction(e=a.promise)?e.call(a).done(b).fail(c):a&&r.isFunction(e=a.then)?e.call(a,b,c):b.apply(void 0,[a].slice(d))}catch(a){c.apply(void 0,[a])}}r.extend({Deferred:function(b){var c=[["notify","progress",r.Callbacks("memory"),r.Callbacks("memory"),2],["resolve","done",r.Callbacks("once memory"),r.Callbacks("once memory"),0,"resolved"],["reject","fail",r.Callbacks("once memory"),r.Callbacks("once memory"),1,"rejected"]],d="pending",e={state:function(){return d},always:function(){return f.done(arguments).fail(arguments),this},"catch":function(a){return e.then(null,a)},pipe:function(){var a=arguments;return r.Deferred(function(b){r.each(c,function(c,d){var e=r.isFunction(a[d[4]])&&a[d[4]];f[d[1]](function(){var a=e&&e.apply(this,arguments);a&&r.isFunction(a.promise)?a.promise().progress(b.notify).done(b.resolve).fail(b.reject):b[d[0]+"With"](this,e?[a]:arguments)})}),a=null}).promise()},then:function(b,d,e){var f=0;function g(b,c,d,e){return function(){var h=this,i=arguments,j=function(){var a,j;if(!(b<f)){if(a=d.apply(h,i),a===c.promise())throw new TypeError("Thenable self-resolution");j=a&&("object"==typeof a||"function"==typeof a)&&a.then,r.isFunction(j)?e?j.call(a,g(f,c,N,e),g(f,c,O,e)):(f++,j.call(a,g(f,c,N,e),g(f,c,O,e),g(f,c,N,c.notifyWith))):(d!==N&&(h=void 0,i=[a]),(e||c.resolveWith)(h,i))}},k=e?j:function(){try{j()}catch(a){r.Deferred.exceptionHook&&r.Deferred.exceptionHook(a,k.stackTrace),b+1>=f&&(d!==O&&(h=void 0,i=[a]),c.rejectWith(h,i))}};b?k():(r.Deferred.getStackHook&&(k.stackTrace=r.Deferred.getStackHook()),a.setTimeout(k))}}return r.Deferred(function(a){c[0][3].add(g(0,a,r.isFunction(e)?e:N,a.notifyWith)),c[1][3].add(g(0,a,r.isFunction(b)?b:N)),c[2][3].add(g(0,a,r.isFunction(d)?d:O))}).promise()},promise:function(a){return null!=a?r.extend(a,e):e}},f={};return r.each(c,function(a,b){var g=b[2],h=b[5];e[b[1]]=g.add,h&&g.add(function(){d=h},c[3-a][2].disable,c[0][2].lock),g.add(b[3].fire),f[b[0]]=function(){return f[b[0]+"With"](this===f?void 0:this,arguments),this},f[b[0]+"With"]=g.fireWith}),e.promise(f),b&&b.call(f,f),f},when:function(a){var b=arguments.length,c=b,d=Array(c),e=f.call(arguments),g=r.Deferred(),h=function(a){return function(c){d[a]=this,e[a]=arguments.length>1?f.call(arguments):c,--b||g.resolveWith(d,e)}};if(b<=1&&(P(a,g.done(h(c)).resolve,g.reject,!b),"pending"===g.state()||r.isFunction(e[c]&&e[c].then)))return g.then();while(c--)P(e[c],h(c),g.reject);return g.promise()}});var Q=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;r.Deferred.exceptionHook=function(b,c){a.console&&a.console.warn&&b&&Q.test(b.name)&&a.console.warn("jQuery.Deferred exception: "+b.message,b.stack,c)},r.readyException=function(b){a.setTimeout(function(){throw b})};var R=r.Deferred();r.fn.ready=function(a){return R.then(a)["catch"](function(a){r.readyException(a)}),this},r.extend({isReady:!1,readyWait:1,ready:function(a){(a===!0?--r.readyWait:r.isReady)||(r.isReady=!0,a!==!0&&--r.readyWait>0||R.resolveWith(d,[r]))}}),r.ready.then=R.then;function S(){d.removeEventListener("DOMContentLoaded",S),
+a.removeEventListener("load",S),r.ready()}"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(r.ready):(d.addEventListener("DOMContentLoaded",S),a.addEventListener("load",S));var T=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===r.type(c)){e=!0;for(h in c)T(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,r.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(r(a),c)})),b))for(;h<i;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},U=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function V(){this.expando=r.expando+V.uid++}V.uid=1,V.prototype={cache:function(a){var b=a[this.expando];return b||(b={},U(a)&&(a.nodeType?a[this.expando]=b:Object.defineProperty(a,this.expando,{value:b,configurable:!0}))),b},set:function(a,b,c){var d,e=this.cache(a);if("string"==typeof b)e[r.camelCase(b)]=c;else for(d in b)e[r.camelCase(d)]=b[d];return e},get:function(a,b){return void 0===b?this.cache(a):a[this.expando]&&a[this.expando][r.camelCase(b)]},access:function(a,b,c){return void 0===b||b&&"string"==typeof b&&void 0===c?this.get(a,b):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d=a[this.expando];if(void 0!==d){if(void 0!==b){Array.isArray(b)?b=b.map(r.camelCase):(b=r.camelCase(b),b=b in d?[b]:b.match(L)||[]),c=b.length;while(c--)delete d[b[c]]}(void 0===b||r.isEmptyObject(d))&&(a.nodeType?a[this.expando]=void 0:delete a[this.expando])}},hasData:function(a){var b=a[this.expando];return void 0!==b&&!r.isEmptyObject(b)}};var W=new V,X=new V,Y=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,Z=/[A-Z]/g;function $(a){return"true"===a||"false"!==a&&("null"===a?null:a===+a+""?+a:Y.test(a)?JSON.parse(a):a)}function _(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(Z,"-$&").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c=$(c)}catch(e){}X.set(a,b,c)}else c=void 0;return c}r.extend({hasData:function(a){return X.hasData(a)||W.hasData(a)},data:function(a,b,c){return X.access(a,b,c)},removeData:function(a,b){X.remove(a,b)},_data:function(a,b,c){return W.access(a,b,c)},_removeData:function(a,b){W.remove(a,b)}}),r.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=X.get(f),1===f.nodeType&&!W.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=r.camelCase(d.slice(5)),_(f,d,e[d])));W.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){X.set(this,a)}):T(this,function(b){var c;if(f&&void 0===b){if(c=X.get(f,a),void 0!==c)return c;if(c=_(f,a),void 0!==c)return c}else this.each(function(){X.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){X.remove(this,a)})}}),r.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=W.get(a,b),c&&(!d||Array.isArray(c)?d=W.access(a,b,r.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=r.queue(a,b),d=c.length,e=c.shift(),f=r._queueHooks(a,b),g=function(){r.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return W.get(a,c)||W.access(a,c,{empty:r.Callbacks("once memory").add(function(){W.remove(a,[b+"queue",c])})})}}),r.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?r.queue(this[0],a):void 0===b?this:this.each(function(){var c=r.queue(this,a,b);r._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&r.dequeue(this,a)})},dequeue:function(a){return this.each(function(){r.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=r.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=W.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var aa=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,ba=new RegExp("^(?:([+-])=|)("+aa+")([a-z%]*)$","i"),ca=["Top","Right","Bottom","Left"],da=function(a,b){return a=b||a,"none"===a.style.display||""===a.style.display&&r.contains(a.ownerDocument,a)&&"none"===r.css(a,"display")},ea=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};function fa(a,b,c,d){var e,f=1,g=20,h=d?function(){return d.cur()}:function(){return r.css(a,b,"")},i=h(),j=c&&c[3]||(r.cssNumber[b]?"":"px"),k=(r.cssNumber[b]||"px"!==j&&+i)&&ba.exec(r.css(a,b));if(k&&k[3]!==j){j=j||k[3],c=c||[],k=+i||1;do f=f||".5",k/=f,r.style(a,b,k+j);while(f!==(f=h()/i)&&1!==f&&--g)}return c&&(k=+k||+i||0,e=c[1]?k+(c[1]+1)*c[2]:+c[2],d&&(d.unit=j,d.start=k,d.end=e)),e}var ga={};function ha(a){var b,c=a.ownerDocument,d=a.nodeName,e=ga[d];return e?e:(b=c.body.appendChild(c.createElement(d)),e=r.css(b,"display"),b.parentNode.removeChild(b),"none"===e&&(e="block"),ga[d]=e,e)}function ia(a,b){for(var c,d,e=[],f=0,g=a.length;f<g;f++)d=a[f],d.style&&(c=d.style.display,b?("none"===c&&(e[f]=W.get(d,"display")||null,e[f]||(d.style.display="")),""===d.style.display&&da(d)&&(e[f]=ha(d))):"none"!==c&&(e[f]="none",W.set(d,"display",c)));for(f=0;f<g;f++)null!=e[f]&&(a[f].style.display=e[f]);return a}r.fn.extend({show:function(){return ia(this,!0)},hide:function(){return ia(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){da(this)?r(this).show():r(this).hide()})}});var ja=/^(?:checkbox|radio)$/i,ka=/<([a-z][^\/\0>\x20\t\r\n\f]+)/i,la=/^$|\/(?:java|ecma)script/i,ma={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ma.optgroup=ma.option,ma.tbody=ma.tfoot=ma.colgroup=ma.caption=ma.thead,ma.th=ma.td;function na(a,b){var c;return c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[],void 0===b||b&&B(a,b)?r.merge([a],c):c}function oa(a,b){for(var c=0,d=a.length;c<d;c++)W.set(a[c],"globalEval",!b||W.get(b[c],"globalEval"))}var pa=/<|&#?\w+;/;function qa(a,b,c,d,e){for(var f,g,h,i,j,k,l=b.createDocumentFragment(),m=[],n=0,o=a.length;n<o;n++)if(f=a[n],f||0===f)if("object"===r.type(f))r.merge(m,f.nodeType?[f]:f);else if(pa.test(f)){g=g||l.appendChild(b.createElement("div")),h=(ka.exec(f)||["",""])[1].toLowerCase(),i=ma[h]||ma._default,g.innerHTML=i[1]+r.htmlPrefilter(f)+i[2],k=i[0];while(k--)g=g.lastChild;r.merge(m,g.childNodes),g=l.firstChild,g.textContent=""}else m.push(b.createTextNode(f));l.textContent="",n=0;while(f=m[n++])if(d&&r.inArray(f,d)>-1)e&&e.push(f);else if(j=r.contains(f.ownerDocument,f),g=na(l.appendChild(f),"script"),j&&oa(g),c){k=0;while(f=g[k++])la.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),o.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",o.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var ra=d.documentElement,sa=/^key/,ta=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,ua=/^([^.]*)(?:\.(.+)|)/;function va(){return!0}function wa(){return!1}function xa(){try{return d.activeElement}catch(a){}}function ya(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ya(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=wa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return r().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=r.guid++)),a.each(function(){r.event.add(this,b,e,d,c)})}r.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.get(a);if(q){c.handler&&(f=c,c=f.handler,e=f.selector),e&&r.find.matchesSelector(ra,e),c.guid||(c.guid=r.guid++),(i=q.events)||(i=q.events={}),(g=q.handle)||(g=q.handle=function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(L)||[""],j=b.length;while(j--)h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n&&(l=r.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=r.event.special[n]||{},k=r.extend({type:n,origType:p,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&r.expr.match.needsContext.test(e),namespace:o.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,o,g)!==!1||a.addEventListener&&a.addEventListener(n,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),r.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.hasData(a)&&W.get(a);if(q&&(i=q.events)){b=(b||"").match(L)||[""],j=b.length;while(j--)if(h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n){l=r.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+o.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&p!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,o,q.handle)!==!1||r.removeEvent(a,n,q.handle),delete i[n])}else for(n in i)r.event.remove(a,n+b[j],c,d,!0);r.isEmptyObject(i)&&W.remove(a,"handle events")}},dispatch:function(a){var b=r.event.fix(a),c,d,e,f,g,h,i=new Array(arguments.length),j=(W.get(this,"events")||{})[b.type]||[],k=r.event.special[b.type]||{};for(i[0]=b,c=1;c<arguments.length;c++)i[c]=arguments[c];if(b.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,b)!==!1){h=r.event.handlers.call(this,b,j),c=0;while((f=h[c++])&&!b.isPropagationStopped()){b.currentTarget=f.elem,d=0;while((g=f.handlers[d++])&&!b.isImmediatePropagationStopped())b.rnamespace&&!b.rnamespace.test(g.namespace)||(b.handleObj=g,b.data=g.data,e=((r.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(b.result=e)===!1&&(b.preventDefault(),b.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,b),b.result}},handlers:function(a,b){var c,d,e,f,g,h=[],i=b.delegateCount,j=a.target;if(i&&j.nodeType&&!("click"===a.type&&a.button>=1))for(;j!==this;j=j.parentNode||this)if(1===j.nodeType&&("click"!==a.type||j.disabled!==!0)){for(f=[],g={},c=0;c<i;c++)d=b[c],e=d.selector+" ",void 0===g[e]&&(g[e]=d.needsContext?r(e,this).index(j)>-1:r.find(e,this,null,[j]).length),g[e]&&f.push(d);f.length&&h.push({elem:j,handlers:f})}return j=this,i<b.length&&h.push({elem:j,handlers:b.slice(i)}),h},addProp:function(a,b){Object.defineProperty(r.Event.prototype,a,{enumerable:!0,configurable:!0,get:r.isFunction(b)?function(){if(this.originalEvent)return b(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[a]},set:function(b){Object.defineProperty(this,a,{enumerable:!0,configurable:!0,writable:!0,value:b})}})},fix:function(a){return a[r.expando]?a:new r.Event(a)},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==xa()&&this.focus)return this.focus(),!1},delegateType:"focusin"},blur:{trigger:function(){if(this===xa()&&this.blur)return this.blur(),!1},delegateType:"focusout"},click:{trigger:function(){if("checkbox"===this.type&&this.click&&B(this,"input"))return this.click(),!1},_default:function(a){return B(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}}},r.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c)},r.Event=function(a,b){return this instanceof r.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?va:wa,this.target=a.target&&3===a.target.nodeType?a.target.parentNode:a.target,this.currentTarget=a.currentTarget,this.relatedTarget=a.relatedTarget):this.type=a,b&&r.extend(this,b),this.timeStamp=a&&a.timeStamp||r.now(),void(this[r.expando]=!0)):new r.Event(a,b)},r.Event.prototype={constructor:r.Event,isDefaultPrevented:wa,isPropagationStopped:wa,isImmediatePropagationStopped:wa,isSimulated:!1,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=va,a&&!this.isSimulated&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=va,a&&!this.isSimulated&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=va,a&&!this.isSimulated&&a.stopImmediatePropagation(),this.stopPropagation()}},r.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(a){var b=a.button;return null==a.which&&sa.test(a.type)?null!=a.charCode?a.charCode:a.keyCode:!a.which&&void 0!==b&&ta.test(a.type)?1&b?1:2&b?3:4&b?2:0:a.which}},r.event.addProp),r.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){r.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return e&&(e===d||r.contains(d,e))||(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),r.fn.extend({on:function(a,b,c,d){return ya(this,a,b,c,d)},one:function(a,b,c,d){return ya(this,a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,r(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return b!==!1&&"function"!=typeof b||(c=b,b=void 0),c===!1&&(c=wa),this.each(function(){r.event.remove(this,a,c,b)})}});var za=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,Aa=/<script|<style|<link/i,Ba=/checked\s*(?:[^=]|=\s*.checked.)/i,Ca=/^true\/(.*)/,Da=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function Ea(a,b){return B(a,"table")&&B(11!==b.nodeType?b:b.firstChild,"tr")?r(">tbody",a)[0]||a:a}function Fa(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function Ga(a){var b=Ca.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ha(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(W.hasData(a)&&(f=W.access(a),g=W.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;c<d;c++)r.event.add(b,e,j[e][c])}X.hasData(a)&&(h=X.access(a),i=r.extend({},h),X.set(b,i))}}function Ia(a,b){var c=b.nodeName.toLowerCase();"input"===c&&ja.test(a.type)?b.checked=a.checked:"input"!==c&&"textarea"!==c||(b.defaultValue=a.defaultValue)}function Ja(a,b,c,d){b=g.apply([],b);var e,f,h,i,j,k,l=0,m=a.length,n=m-1,q=b[0],s=r.isFunction(q);if(s||m>1&&"string"==typeof q&&!o.checkClone&&Ba.test(q))return a.each(function(e){var f=a.eq(e);s&&(b[0]=q.call(this,e,f.html())),Ja(f,b,c,d)});if(m&&(e=qa(b,a[0].ownerDocument,!1,a,d),f=e.firstChild,1===e.childNodes.length&&(e=f),f||d)){for(h=r.map(na(e,"script"),Fa),i=h.length;l<m;l++)j=e,l!==n&&(j=r.clone(j,!0,!0),i&&r.merge(h,na(j,"script"))),c.call(a[l],j,l);if(i)for(k=h[h.length-1].ownerDocument,r.map(h,Ga),l=0;l<i;l++)j=h[l],la.test(j.type||"")&&!W.access(j,"globalEval")&&r.contains(k,j)&&(j.src?r._evalUrl&&r._evalUrl(j.src):p(j.textContent.replace(Da,""),k))}return a}function Ka(a,b,c){for(var d,e=b?r.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||r.cleanData(na(d)),d.parentNode&&(c&&r.contains(d.ownerDocument,d)&&oa(na(d,"script")),d.parentNode.removeChild(d));return a}r.extend({htmlPrefilter:function(a){return a.replace(za,"<$1></$2>")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=r.contains(a.ownerDocument,a);if(!(o.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||r.isXMLDoc(a)))for(g=na(h),f=na(a),d=0,e=f.length;d<e;d++)Ia(f[d],g[d]);if(b)if(c)for(f=f||na(a),g=g||na(h),d=0,e=f.length;d<e;d++)Ha(f[d],g[d]);else Ha(a,h);return g=na(h,"script"),g.length>0&&oa(g,!i&&na(a,"script")),h},cleanData:function(a){for(var b,c,d,e=r.event.special,f=0;void 0!==(c=a[f]);f++)if(U(c)){if(b=c[W.expando]){if(b.events)for(d in b.events)e[d]?r.event.remove(c,d):r.removeEvent(c,d,b.handle);c[W.expando]=void 0}c[X.expando]&&(c[X.expando]=void 0)}}}),r.fn.extend({detach:function(a){return Ka(this,a,!0)},remove:function(a){return Ka(this,a)},text:function(a){return T(this,function(a){return void 0===a?r.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.appendChild(a)}})},prepend:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(r.cleanData(na(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null!=a&&a,b=null==b?a:b,this.map(function(){return r.clone(this,a,b)})},html:function(a){return T(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!Aa.test(a)&&!ma[(ka.exec(a)||["",""])[1].toLowerCase()]){a=r.htmlPrefilter(a);try{for(;c<d;c++)b=this[c]||{},1===b.nodeType&&(r.cleanData(na(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return Ja(this,arguments,function(b){var c=this.parentNode;r.inArray(this,a)<0&&(r.cleanData(na(this)),c&&c.replaceChild(b,this))},a)}}),r.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){r.fn[a]=function(a){for(var c,d=[],e=r(a),f=e.length-1,g=0;g<=f;g++)c=g===f?this:this.clone(!0),r(e[g])[b](c),h.apply(d,c.get());return this.pushStack(d)}});var La=/^margin/,Ma=new RegExp("^("+aa+")(?!px)[a-z%]+$","i"),Na=function(b){var c=b.ownerDocument.defaultView;return c&&c.opener||(c=a),c.getComputedStyle(b)};!function(){function b(){if(i){i.style.cssText="box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%",i.innerHTML="",ra.appendChild(h);var b=a.getComputedStyle(i);c="1%"!==b.top,g="2px"===b.marginLeft,e="4px"===b.width,i.style.marginRight="50%",f="4px"===b.marginRight,ra.removeChild(h),i=null}}var c,e,f,g,h=d.createElement("div"),i=d.createElement("div");i.style&&(i.style.backgroundClip="content-box",i.cloneNode(!0).style.backgroundClip="",o.clearCloneStyle="content-box"===i.style.backgroundClip,h.style.cssText="border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute",h.appendChild(i),r.extend(o,{pixelPosition:function(){return b(),c},boxSizingReliable:function(){return b(),e},pixelMarginRight:function(){return b(),f},reliableMarginLeft:function(){return b(),g}}))}();function Oa(a,b,c){var d,e,f,g,h=a.style;return c=c||Na(a),c&&(g=c.getPropertyValue(b)||c[b],""!==g||r.contains(a.ownerDocument,a)||(g=r.style(a,b)),!o.pixelMarginRight()&&Ma.test(g)&&La.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function Pa(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}var Qa=/^(none|table(?!-c[ea]).+)/,Ra=/^--/,Sa={position:"absolute",visibility:"hidden",display:"block"},Ta={letterSpacing:"0",fontWeight:"400"},Ua=["Webkit","Moz","ms"],Va=d.createElement("div").style;function Wa(a){if(a in Va)return a;var b=a[0].toUpperCase()+a.slice(1),c=Ua.length;while(c--)if(a=Ua[c]+b,a in Va)return a}function Xa(a){var b=r.cssProps[a];return b||(b=r.cssProps[a]=Wa(a)||a),b}function Ya(a,b,c){var d=ba.exec(b);return d?Math.max(0,d[2]-(c||0))+(d[3]||"px"):b}function Za(a,b,c,d,e){var f,g=0;for(f=c===(d?"border":"content")?4:"width"===b?1:0;f<4;f+=2)"margin"===c&&(g+=r.css(a,c+ca[f],!0,e)),d?("content"===c&&(g-=r.css(a,"padding"+ca[f],!0,e)),"margin"!==c&&(g-=r.css(a,"border"+ca[f]+"Width",!0,e))):(g+=r.css(a,"padding"+ca[f],!0,e),"padding"!==c&&(g+=r.css(a,"border"+ca[f]+"Width",!0,e)));return g}function $a(a,b,c){var d,e=Na(a),f=Oa(a,b,e),g="border-box"===r.css(a,"boxSizing",!1,e);return Ma.test(f)?f:(d=g&&(o.boxSizingReliable()||f===a.style[b]),"auto"===f&&(f=a["offset"+b[0].toUpperCase()+b.slice(1)]),f=parseFloat(f)||0,f+Za(a,b,c||(g?"border":"content"),d,e)+"px")}r.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Oa(a,"opacity");return""===c?"1":c}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=r.camelCase(b),i=Ra.test(b),j=a.style;return i||(b=Xa(h)),g=r.cssHooks[b]||r.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:j[b]:(f=typeof c,"string"===f&&(e=ba.exec(c))&&e[1]&&(c=fa(a,b,e),f="number"),null!=c&&c===c&&("number"===f&&(c+=e&&e[3]||(r.cssNumber[h]?"":"px")),o.clearCloneStyle||""!==c||0!==b.indexOf("background")||(j[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i?j.setProperty(b,c):j[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=r.camelCase(b),i=Ra.test(b);return i||(b=Xa(h)),g=r.cssHooks[b]||r.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=Oa(a,b,d)),"normal"===e&&b in Ta&&(e=Ta[b]),""===c||c?(f=parseFloat(e),c===!0||isFinite(f)?f||0:e):e}}),r.each(["height","width"],function(a,b){r.cssHooks[b]={get:function(a,c,d){if(c)return!Qa.test(r.css(a,"display"))||a.getClientRects().length&&a.getBoundingClientRect().width?$a(a,b,d):ea(a,Sa,function(){return $a(a,b,d)})},set:function(a,c,d){var e,f=d&&Na(a),g=d&&Za(a,b,d,"border-box"===r.css(a,"boxSizing",!1,f),f);return g&&(e=ba.exec(c))&&"px"!==(e[3]||"px")&&(a.style[b]=c,c=r.css(a,b)),Ya(a,c,g)}}}),r.cssHooks.marginLeft=Pa(o.reliableMarginLeft,function(a,b){if(b)return(parseFloat(Oa(a,"marginLeft"))||a.getBoundingClientRect().left-ea(a,{marginLeft:0},function(){return a.getBoundingClientRect().left}))+"px"}),r.each({margin:"",padding:"",border:"Width"},function(a,b){r.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];d<4;d++)e[a+ca[d]+b]=f[d]||f[d-2]||f[0];return e}},La.test(a)||(r.cssHooks[a+b].set=Ya)}),r.fn.extend({css:function(a,b){return T(this,function(a,b,c){var d,e,f={},g=0;if(Array.isArray(b)){for(d=Na(a),e=b.length;g<e;g++)f[b[g]]=r.css(a,b[g],!1,d);return f}return void 0!==c?r.style(a,b,c):r.css(a,b)},a,b,arguments.length>1)}});function _a(a,b,c,d,e){return new _a.prototype.init(a,b,c,d,e)}r.Tween=_a,_a.prototype={constructor:_a,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||r.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(r.cssNumber[c]?"":"px")},cur:function(){var a=_a.propHooks[this.prop];return a&&a.get?a.get(this):_a.propHooks._default.get(this)},run:function(a){var b,c=_a.propHooks[this.prop];return this.options.duration?this.pos=b=r.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):_a.propHooks._default.set(this),this}},_a.prototype.init.prototype=_a.prototype,_a.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=r.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){r.fx.step[a.prop]?r.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[r.cssProps[a.prop]]&&!r.cssHooks[a.prop]?a.elem[a.prop]=a.now:r.style(a.elem,a.prop,a.now+a.unit)}}},_a.propHooks.scrollTop=_a.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},r.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},r.fx=_a.prototype.init,r.fx.step={};var ab,bb,cb=/^(?:toggle|show|hide)$/,db=/queueHooks$/;function eb(){bb&&(d.hidden===!1&&a.requestAnimationFrame?a.requestAnimationFrame(eb):a.setTimeout(eb,r.fx.interval),r.fx.tick())}function fb(){return a.setTimeout(function(){ab=void 0}),ab=r.now()}function gb(a,b){var c,d=0,e={height:a};for(b=b?1:0;d<4;d+=2-b)c=ca[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function hb(a,b,c){for(var d,e=(kb.tweeners[b]||[]).concat(kb.tweeners["*"]),f=0,g=e.length;f<g;f++)if(d=e[f].call(c,b,a))return d}function ib(a,b,c){var d,e,f,g,h,i,j,k,l="width"in b||"height"in b,m=this,n={},o=a.style,p=a.nodeType&&da(a),q=W.get(a,"fxshow");c.queue||(g=r._queueHooks(a,"fx"),null==g.unqueued&&(g.unqueued=0,h=g.empty.fire,g.empty.fire=function(){g.unqueued||h()}),g.unqueued++,m.always(function(){m.always(function(){g.unqueued--,r.queue(a,"fx").length||g.empty.fire()})}));for(d in b)if(e=b[d],cb.test(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}n[d]=q&&q[d]||r.style(a,d)}if(i=!r.isEmptyObject(b),i||!r.isEmptyObject(n)){l&&1===a.nodeType&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=q&&q.display,null==j&&(j=W.get(a,"display")),k=r.css(a,"display"),"none"===k&&(j?k=j:(ia([a],!0),j=a.style.display||j,k=r.css(a,"display"),ia([a]))),("inline"===k||"inline-block"===k&&null!=j)&&"none"===r.css(a,"float")&&(i||(m.done(function(){o.display=j}),null==j&&(k=o.display,j="none"===k?"":k)),o.display="inline-block")),c.overflow&&(o.overflow="hidden",m.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]})),i=!1;for(d in n)i||(q?"hidden"in q&&(p=q.hidden):q=W.access(a,"fxshow",{display:j}),f&&(q.hidden=!p),p&&ia([a],!0),m.done(function(){p||ia([a]),W.remove(a,"fxshow");for(d in n)r.style(a,d,n[d])})),i=hb(p?q[d]:0,d,m),d in q||(q[d]=i.start,p&&(i.end=i.start,i.start=0))}}function jb(a,b){var c,d,e,f,g;for(c in a)if(d=r.camelCase(c),e=b[d],f=a[c],Array.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=r.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kb(a,b,c){var d,e,f=0,g=kb.prefilters.length,h=r.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=ab||fb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;g<i;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),f<1&&i?c:(i||h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:r.extend({},b),opts:r.extend(!0,{specialEasing:{},easing:r.easing._default},c),originalProperties:b,originalOptions:c,startTime:ab||fb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=r.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;c<d;c++)j.tweens[c].run(1);return b?(h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j,b])):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jb(k,j.opts.specialEasing);f<g;f++)if(d=kb.prefilters[f].call(j,a,k,j.opts))return r.isFunction(d.stop)&&(r._queueHooks(j.elem,j.opts.queue).stop=r.proxy(d.stop,d)),d;return r.map(k,hb,j),r.isFunction(j.opts.start)&&j.opts.start.call(a,j),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always),r.fx.timer(r.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j}r.Animation=r.extend(kb,{tweeners:{"*":[function(a,b){var c=this.createTween(a,b);return fa(c.elem,a,ba.exec(b),c),c}]},tweener:function(a,b){r.isFunction(a)?(b=a,a=["*"]):a=a.match(L);for(var c,d=0,e=a.length;d<e;d++)c=a[d],kb.tweeners[c]=kb.tweeners[c]||[],kb.tweeners[c].unshift(b)},prefilters:[ib],prefilter:function(a,b){b?kb.prefilters.unshift(a):kb.prefilters.push(a)}}),r.speed=function(a,b,c){var d=a&&"object"==typeof a?r.extend({},a):{complete:c||!c&&b||r.isFunction(a)&&a,duration:a,easing:c&&b||b&&!r.isFunction(b)&&b};return r.fx.off?d.duration=0:"number"!=typeof d.duration&&(d.duration in r.fx.speeds?d.duration=r.fx.speeds[d.duration]:d.duration=r.fx.speeds._default),null!=d.queue&&d.queue!==!0||(d.queue="fx"),d.old=d.complete,d.complete=function(){r.isFunction(d.old)&&d.old.call(this),d.queue&&r.dequeue(this,d.queue)},d},r.fn.extend({fadeTo:function(a,b,c,d){return this.filter(da).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=r.isEmptyObject(a),f=r.speed(b,c,d),g=function(){var b=kb(this,r.extend({},a),f);(e||W.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=r.timers,g=W.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&db.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));!b&&c||r.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=W.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=r.timers,g=d?d.length:0;for(c.finish=!0,r.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;b<g;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),r.each(["toggle","show","hide"],function(a,b){var c=r.fn[b];r.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(gb(b,!0),a,d,e)}}),r.each({slideDown:gb("show"),slideUp:gb("hide"),slideToggle:gb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){r.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),r.timers=[],r.fx.tick=function(){var a,b=0,c=r.timers;for(ab=r.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||r.fx.stop(),ab=void 0},r.fx.timer=function(a){r.timers.push(a),r.fx.start()},r.fx.interval=13,r.fx.start=function(){bb||(bb=!0,eb())},r.fx.stop=function(){bb=null},r.fx.speeds={slow:600,fast:200,_default:400},r.fn.delay=function(b,c){return b=r.fx?r.fx.speeds[b]||b:b,c=c||"fx",this.queue(c,function(c,d){var e=a.setTimeout(c,b);d.stop=function(){a.clearTimeout(e)}})},function(){var a=d.createElement("input"),b=d.createElement("select"),c=b.appendChild(d.createElement("option"));a.type="checkbox",o.checkOn=""!==a.value,o.optSelected=c.selected,a=d.createElement("input"),a.value="t",a.type="radio",o.radioValue="t"===a.value}();var lb,mb=r.expr.attrHandle;r.fn.extend({attr:function(a,b){return T(this,r.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){r.removeAttr(this,a)})}}),r.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?r.prop(a,b,c):(1===f&&r.isXMLDoc(a)||(e=r.attrHooks[b.toLowerCase()]||(r.expr.match.bool.test(b)?lb:void 0)),void 0!==c?null===c?void r.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=r.find.attr(a,b),
+null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!o.radioValue&&"radio"===b&&B(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d=0,e=b&&b.match(L);if(e&&1===a.nodeType)while(c=e[d++])a.removeAttribute(c)}}),lb={set:function(a,b,c){return b===!1?r.removeAttr(a,c):a.setAttribute(c,c),c}},r.each(r.expr.match.bool.source.match(/\w+/g),function(a,b){var c=mb[b]||r.find.attr;mb[b]=function(a,b,d){var e,f,g=b.toLowerCase();return d||(f=mb[g],mb[g]=e,e=null!=c(a,b,d)?g:null,mb[g]=f),e}});var nb=/^(?:input|select|textarea|button)$/i,ob=/^(?:a|area)$/i;r.fn.extend({prop:function(a,b){return T(this,r.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[r.propFix[a]||a]})}}),r.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&r.isXMLDoc(a)||(b=r.propFix[b]||b,e=r.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=r.find.attr(a,"tabindex");return b?parseInt(b,10):nb.test(a.nodeName)||ob.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),o.optSelected||(r.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),r.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){r.propFix[this.toLowerCase()]=this});function pb(a){var b=a.match(L)||[];return b.join(" ")}function qb(a){return a.getAttribute&&a.getAttribute("class")||""}r.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).addClass(a.call(this,b,qb(this)))});if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=pb(d),e!==h&&c.setAttribute("class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).removeClass(a.call(this,b,qb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=pb(d),e!==h&&c.setAttribute("class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):r.isFunction(a)?this.each(function(c){r(this).toggleClass(a.call(this,c,qb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=r(this),f=a.match(L)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=qb(this),b&&W.set(this,"__className__",b),this.setAttribute&&this.setAttribute("class",b||a===!1?"":W.get(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+pb(qb(c))+" ").indexOf(b)>-1)return!0;return!1}});var rb=/\r/g;r.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=r.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,r(this).val()):a,null==e?e="":"number"==typeof e?e+="":Array.isArray(e)&&(e=r.map(e,function(a){return null==a?"":a+""})),b=r.valHooks[this.type]||r.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=r.valHooks[e.type]||r.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(rb,""):null==c?"":c)}}}),r.extend({valHooks:{option:{get:function(a){var b=r.find.attr(a,"value");return null!=b?b:pb(r.text(a))}},select:{get:function(a){var b,c,d,e=a.options,f=a.selectedIndex,g="select-one"===a.type,h=g?null:[],i=g?f+1:e.length;for(d=f<0?i:g?f:0;d<i;d++)if(c=e[d],(c.selected||d===f)&&!c.disabled&&(!c.parentNode.disabled||!B(c.parentNode,"optgroup"))){if(b=r(c).val(),g)return b;h.push(b)}return h},set:function(a,b){var c,d,e=a.options,f=r.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=r.inArray(r.valHooks.option.get(d),f)>-1)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),r.each(["radio","checkbox"],function(){r.valHooks[this]={set:function(a,b){if(Array.isArray(b))return a.checked=r.inArray(r(a).val(),b)>-1}},o.checkOn||(r.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var sb=/^(?:focusinfocus|focusoutblur)$/;r.extend(r.event,{trigger:function(b,c,e,f){var g,h,i,j,k,m,n,o=[e||d],p=l.call(b,"type")?b.type:b,q=l.call(b,"namespace")?b.namespace.split("."):[];if(h=i=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!sb.test(p+r.event.triggered)&&(p.indexOf(".")>-1&&(q=p.split("."),p=q.shift(),q.sort()),k=p.indexOf(":")<0&&"on"+p,b=b[r.expando]?b:new r.Event(p,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=q.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:r.makeArray(c,[b]),n=r.event.special[p]||{},f||!n.trigger||n.trigger.apply(e,c)!==!1)){if(!f&&!n.noBubble&&!r.isWindow(e)){for(j=n.delegateType||p,sb.test(j+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),i=h;i===(e.ownerDocument||d)&&o.push(i.defaultView||i.parentWindow||a)}g=0;while((h=o[g++])&&!b.isPropagationStopped())b.type=g>1?j:n.bindType||p,m=(W.get(h,"events")||{})[b.type]&&W.get(h,"handle"),m&&m.apply(h,c),m=k&&h[k],m&&m.apply&&U(h)&&(b.result=m.apply(h,c),b.result===!1&&b.preventDefault());return b.type=p,f||b.isDefaultPrevented()||n._default&&n._default.apply(o.pop(),c)!==!1||!U(e)||k&&r.isFunction(e[p])&&!r.isWindow(e)&&(i=e[k],i&&(e[k]=null),r.event.triggered=p,e[p](),r.event.triggered=void 0,i&&(e[k]=i)),b.result}},simulate:function(a,b,c){var d=r.extend(new r.Event,c,{type:a,isSimulated:!0});r.event.trigger(d,null,b)}}),r.fn.extend({trigger:function(a,b){return this.each(function(){r.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];if(c)return r.event.trigger(a,b,c,!0)}}),r.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(a,b){r.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),r.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),o.focusin="onfocusin"in a,o.focusin||r.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){r.event.simulate(b,a.target,r.event.fix(a))};r.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=W.access(d,b);e||d.addEventListener(a,c,!0),W.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=W.access(d,b)-1;e?W.access(d,b,e):(d.removeEventListener(a,c,!0),W.remove(d,b))}}});var tb=a.location,ub=r.now(),vb=/\?/;r.parseXML=function(b){var c;if(!b||"string"!=typeof b)return null;try{c=(new a.DOMParser).parseFromString(b,"text/xml")}catch(d){c=void 0}return c&&!c.getElementsByTagName("parsererror").length||r.error("Invalid XML: "+b),c};var wb=/\[\]$/,xb=/\r?\n/g,yb=/^(?:submit|button|image|reset|file)$/i,zb=/^(?:input|select|textarea|keygen)/i;function Ab(a,b,c,d){var e;if(Array.isArray(b))r.each(b,function(b,e){c||wb.test(a)?d(a,e):Ab(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d)});else if(c||"object"!==r.type(b))d(a,b);else for(e in b)Ab(a+"["+e+"]",b[e],c,d)}r.param=function(a,b){var c,d=[],e=function(a,b){var c=r.isFunction(b)?b():b;d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(null==c?"":c)};if(Array.isArray(a)||a.jquery&&!r.isPlainObject(a))r.each(a,function(){e(this.name,this.value)});else for(c in a)Ab(c,a[c],b,e);return d.join("&")},r.fn.extend({serialize:function(){return r.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=r.prop(this,"elements");return a?r.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!r(this).is(":disabled")&&zb.test(this.nodeName)&&!yb.test(a)&&(this.checked||!ja.test(a))}).map(function(a,b){var c=r(this).val();return null==c?null:Array.isArray(c)?r.map(c,function(a){return{name:b.name,value:a.replace(xb,"\r\n")}}):{name:b.name,value:c.replace(xb,"\r\n")}}).get()}});var Bb=/%20/g,Cb=/#.*$/,Db=/([?&])_=[^&]*/,Eb=/^(.*?):[ \t]*([^\r\n]*)$/gm,Fb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Gb=/^(?:GET|HEAD)$/,Hb=/^\/\//,Ib={},Jb={},Kb="*/".concat("*"),Lb=d.createElement("a");Lb.href=tb.href;function Mb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(L)||[];if(r.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Nb(a,b,c,d){var e={},f=a===Jb;function g(h){var i;return e[h]=!0,r.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Ob(a,b){var c,d,e=r.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&r.extend(!0,a,d),a}function Pb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}if(f)return f!==i[0]&&i.unshift(f),c[f]}function Qb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}r.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:tb.href,type:"GET",isLocal:Fb.test(tb.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Kb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":r.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Ob(Ob(a,r.ajaxSettings),b):Ob(r.ajaxSettings,a)},ajaxPrefilter:Mb(Ib),ajaxTransport:Mb(Jb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var e,f,g,h,i,j,k,l,m,n,o=r.ajaxSetup({},c),p=o.context||o,q=o.context&&(p.nodeType||p.jquery)?r(p):r.event,s=r.Deferred(),t=r.Callbacks("once memory"),u=o.statusCode||{},v={},w={},x="canceled",y={readyState:0,getResponseHeader:function(a){var b;if(k){if(!h){h={};while(b=Eb.exec(g))h[b[1].toLowerCase()]=b[2]}b=h[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return k?g:null},setRequestHeader:function(a,b){return null==k&&(a=w[a.toLowerCase()]=w[a.toLowerCase()]||a,v[a]=b),this},overrideMimeType:function(a){return null==k&&(o.mimeType=a),this},statusCode:function(a){var b;if(a)if(k)y.always(a[y.status]);else for(b in a)u[b]=[u[b],a[b]];return this},abort:function(a){var b=a||x;return e&&e.abort(b),A(0,b),this}};if(s.promise(y),o.url=((b||o.url||tb.href)+"").replace(Hb,tb.protocol+"//"),o.type=c.method||c.type||o.method||o.type,o.dataTypes=(o.dataType||"*").toLowerCase().match(L)||[""],null==o.crossDomain){j=d.createElement("a");try{j.href=o.url,j.href=j.href,o.crossDomain=Lb.protocol+"//"+Lb.host!=j.protocol+"//"+j.host}catch(z){o.crossDomain=!0}}if(o.data&&o.processData&&"string"!=typeof o.data&&(o.data=r.param(o.data,o.traditional)),Nb(Ib,o,c,y),k)return y;l=r.event&&o.global,l&&0===r.active++&&r.event.trigger("ajaxStart"),o.type=o.type.toUpperCase(),o.hasContent=!Gb.test(o.type),f=o.url.replace(Cb,""),o.hasContent?o.data&&o.processData&&0===(o.contentType||"").indexOf("application/x-www-form-urlencoded")&&(o.data=o.data.replace(Bb,"+")):(n=o.url.slice(f.length),o.data&&(f+=(vb.test(f)?"&":"?")+o.data,delete o.data),o.cache===!1&&(f=f.replace(Db,"$1"),n=(vb.test(f)?"&":"?")+"_="+ub++ +n),o.url=f+n),o.ifModified&&(r.lastModified[f]&&y.setRequestHeader("If-Modified-Since",r.lastModified[f]),r.etag[f]&&y.setRequestHeader("If-None-Match",r.etag[f])),(o.data&&o.hasContent&&o.contentType!==!1||c.contentType)&&y.setRequestHeader("Content-Type",o.contentType),y.setRequestHeader("Accept",o.dataTypes[0]&&o.accepts[o.dataTypes[0]]?o.accepts[o.dataTypes[0]]+("*"!==o.dataTypes[0]?", "+Kb+"; q=0.01":""):o.accepts["*"]);for(m in o.headers)y.setRequestHeader(m,o.headers[m]);if(o.beforeSend&&(o.beforeSend.call(p,y,o)===!1||k))return y.abort();if(x="abort",t.add(o.complete),y.done(o.success),y.fail(o.error),e=Nb(Jb,o,c,y)){if(y.readyState=1,l&&q.trigger("ajaxSend",[y,o]),k)return y;o.async&&o.timeout>0&&(i=a.setTimeout(function(){y.abort("timeout")},o.timeout));try{k=!1,e.send(v,A)}catch(z){if(k)throw z;A(-1,z)}}else A(-1,"No Transport");function A(b,c,d,h){var j,m,n,v,w,x=c;k||(k=!0,i&&a.clearTimeout(i),e=void 0,g=h||"",y.readyState=b>0?4:0,j=b>=200&&b<300||304===b,d&&(v=Pb(o,y,d)),v=Qb(o,v,y,j),j?(o.ifModified&&(w=y.getResponseHeader("Last-Modified"),w&&(r.lastModified[f]=w),w=y.getResponseHeader("etag"),w&&(r.etag[f]=w)),204===b||"HEAD"===o.type?x="nocontent":304===b?x="notmodified":(x=v.state,m=v.data,n=v.error,j=!n)):(n=x,!b&&x||(x="error",b<0&&(b=0))),y.status=b,y.statusText=(c||x)+"",j?s.resolveWith(p,[m,x,y]):s.rejectWith(p,[y,x,n]),y.statusCode(u),u=void 0,l&&q.trigger(j?"ajaxSuccess":"ajaxError",[y,o,j?m:n]),t.fireWith(p,[y,x]),l&&(q.trigger("ajaxComplete",[y,o]),--r.active||r.event.trigger("ajaxStop")))}return y},getJSON:function(a,b,c){return r.get(a,b,c,"json")},getScript:function(a,b){return r.get(a,void 0,b,"script")}}),r.each(["get","post"],function(a,b){r[b]=function(a,c,d,e){return r.isFunction(c)&&(e=e||d,d=c,c=void 0),r.ajax(r.extend({url:a,type:b,dataType:e,data:c,success:d},r.isPlainObject(a)&&a))}}),r._evalUrl=function(a){return r.ajax({url:a,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},r.fn.extend({wrapAll:function(a){var b;return this[0]&&(r.isFunction(a)&&(a=a.call(this[0])),b=r(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this},wrapInner:function(a){return r.isFunction(a)?this.each(function(b){r(this).wrapInner(a.call(this,b))}):this.each(function(){var b=r(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=r.isFunction(a);return this.each(function(c){r(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(a){return this.parent(a).not("body").each(function(){r(this).replaceWith(this.childNodes)}),this}}),r.expr.pseudos.hidden=function(a){return!r.expr.pseudos.visible(a)},r.expr.pseudos.visible=function(a){return!!(a.offsetWidth||a.offsetHeight||a.getClientRects().length)},r.ajaxSettings.xhr=function(){try{return new a.XMLHttpRequest}catch(b){}};var Rb={0:200,1223:204},Sb=r.ajaxSettings.xhr();o.cors=!!Sb&&"withCredentials"in Sb,o.ajax=Sb=!!Sb,r.ajaxTransport(function(b){var c,d;if(o.cors||Sb&&!b.crossDomain)return{send:function(e,f){var g,h=b.xhr();if(h.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(g in b.xhrFields)h[g]=b.xhrFields[g];b.mimeType&&h.overrideMimeType&&h.overrideMimeType(b.mimeType),b.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest");for(g in e)h.setRequestHeader(g,e[g]);c=function(a){return function(){c&&(c=d=h.onload=h.onerror=h.onabort=h.onreadystatechange=null,"abort"===a?h.abort():"error"===a?"number"!=typeof h.status?f(0,"error"):f(h.status,h.statusText):f(Rb[h.status]||h.status,h.statusText,"text"!==(h.responseType||"text")||"string"!=typeof h.responseText?{binary:h.response}:{text:h.responseText},h.getAllResponseHeaders()))}},h.onload=c(),d=h.onerror=c("error"),void 0!==h.onabort?h.onabort=d:h.onreadystatechange=function(){4===h.readyState&&a.setTimeout(function(){c&&d()})},c=c("abort");try{h.send(b.hasContent&&b.data||null)}catch(i){if(c)throw i}},abort:function(){c&&c()}}}),r.ajaxPrefilter(function(a){a.crossDomain&&(a.contents.script=!1)}),r.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return r.globalEval(a),a}}}),r.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),r.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(e,f){b=r("<script>").prop({charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&f("error"===a.type?404:200,a.type)}),d.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Tb=[],Ub=/(=)\?(?=&|$)|\?\?/;r.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Tb.pop()||r.expando+"_"+ub++;return this[a]=!0,a}}),r.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Ub.test(b.url)?"url":"string"==typeof b.data&&0===(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ub.test(b.data)&&"data");if(h||"jsonp"===b.dataTypes[0])return e=b.jsonpCallback=r.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Ub,"$1"+e):b.jsonp!==!1&&(b.url+=(vb.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||r.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){void 0===f?r(a).removeProp(e):a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Tb.push(e)),g&&r.isFunction(f)&&f(g[0]),g=f=void 0}),"script"}),o.createHTMLDocument=function(){var a=d.implementation.createHTMLDocument("").body;return a.innerHTML="<form></form><form></form>",2===a.childNodes.length}(),r.parseHTML=function(a,b,c){if("string"!=typeof a)return[];"boolean"==typeof b&&(c=b,b=!1);var e,f,g;return b||(o.createHTMLDocument?(b=d.implementation.createHTMLDocument(""),e=b.createElement("base"),e.href=d.location.href,b.head.appendChild(e)):b=d),f=C.exec(a),g=!c&&[],f?[b.createElement(f[1])]:(f=qa([a],b,g),g&&g.length&&r(g).remove(),r.merge([],f.childNodes))},r.fn.load=function(a,b,c){var d,e,f,g=this,h=a.indexOf(" ");return h>-1&&(d=pb(a.slice(h)),a=a.slice(0,h)),r.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&r.ajax({url:a,type:e||"GET",dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?r("<div>").append(r.parseHTML(a)).find(d):a)}).always(c&&function(a,b){g.each(function(){c.apply(this,f||[a.responseText,b,a])})}),this},r.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){r.fn[b]=function(a){return this.on(b,a)}}),r.expr.pseudos.animated=function(a){return r.grep(r.timers,function(b){return a===b.elem}).length},r.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=r.css(a,"position"),l=r(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=r.css(a,"top"),i=r.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),r.isFunction(b)&&(b=b.call(a,c,r.extend({},h))),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},r.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){r.offset.setOffset(this,a,b)});var b,c,d,e,f=this[0];if(f)return f.getClientRects().length?(d=f.getBoundingClientRect(),b=f.ownerDocument,c=b.documentElement,e=b.defaultView,{top:d.top+e.pageYOffset-c.clientTop,left:d.left+e.pageXOffset-c.clientLeft}):{top:0,left:0}},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===r.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),B(a[0],"html")||(d=a.offset()),d={top:d.top+r.css(a[0],"borderTopWidth",!0),left:d.left+r.css(a[0],"borderLeftWidth",!0)}),{top:b.top-d.top-r.css(c,"marginTop",!0),left:b.left-d.left-r.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent;while(a&&"static"===r.css(a,"position"))a=a.offsetParent;return a||ra})}}),r.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c="pageYOffset"===b;r.fn[a]=function(d){return T(this,function(a,d,e){var f;return r.isWindow(a)?f=a:9===a.nodeType&&(f=a.defaultView),void 0===e?f?f[b]:a[d]:void(f?f.scrollTo(c?f.pageXOffset:e,c?e:f.pageYOffset):a[d]=e)},a,d,arguments.length)}}),r.each(["top","left"],function(a,b){r.cssHooks[b]=Pa(o.pixelPosition,function(a,c){if(c)return c=Oa(a,b),Ma.test(c)?r(a).position()[b]+"px":c})}),r.each({Height:"height",Width:"width"},function(a,b){r.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){r.fn[d]=function(e,f){var g=arguments.length&&(c||"boolean"!=typeof e),h=c||(e===!0||f===!0?"margin":"border");return T(this,function(b,c,e){var f;return r.isWindow(b)?0===d.indexOf("outer")?b["inner"+a]:b.document.documentElement["client"+a]:9===b.nodeType?(f=b.documentElement,Math.max(b.body["scroll"+a],f["scroll"+a],b.body["offset"+a],f["offset"+a],f["client"+a])):void 0===e?r.css(b,c,h):r.style(b,c,e,h)},b,g?e:void 0,g)}})}),r.fn.extend({bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}}),r.holdReady=function(a){a?r.readyWait++:r.ready(!0)},r.isArray=Array.isArray,r.parseJSON=JSON.parse,r.nodeName=B,"function"==typeof define&&define.amd&&define("jquery",[],function(){return r});var Vb=a.jQuery,Wb=a.$;return r.noConflict=function(b){return a.$===r&&(a.$=Wb),b&&a.jQuery===r&&(a.jQuery=Vb),r},b||(a.jQuery=a.$=r),r});
diff --git a/career/lang/en/block_career.php b/career/lang/en/block_career.php
new file mode 100644
index 0000000..cb34858
--- /dev/null
+++ b/career/lang/en/block_career.php
@@ -0,0 +1,18 @@
+<?php
+	$string['date_release'] = '{$a->month}.{$a->date}.{$a->year}';
+	$string['career'] = 'Moodle Version';
+	$string['career:addinstance'] = 'Ajouter un block Parcours';
+	$string['career:myaddinstance'] = 'Ajouter un block Parcours sur ma page';
+    $string['pluginname'] = 'Path block';
+	$string['release'] = 'Release: ';
+	$string['title_plugin'] = 'Path';
+	$string['titleadd_plugin'] = 'New Path';
+	$string['titleaddname_plugin'] = 'Name';
+	$string['titleadddesc_plugin'] = 'Description';
+	$string['titleaddimg_plugin'] = 'Course picture';
+	$string['titleaddelem_plugin'] = 'Course elements';
+	$string['titleaddelemdesc_plugin'] = 'Drag and drop the elements of the course you want to add to this course';
+	$string['heading_plugin'] = 'The path allow you to group some course resources in a particular sequence.';
+	$string['add_path'] = 'Add a path';
+    $string['any_carrer'] = 'No Path in this course';
+?>
\ No newline at end of file
diff --git a/career/lang/fr/block_career.php b/career/lang/fr/block_career.php
new file mode 100644
index 0000000..dc95db7
--- /dev/null
+++ b/career/lang/fr/block_career.php
@@ -0,0 +1,17 @@
+<?php
+	$string['date_release'] = '{$a->month}.{$a->date}.{$a->year}';
+	$string['career'] = 'Version Moodle';
+	$string['career:addinstance'] = 'Ajouter un block Parcours';
+	$string['career:myaddinstance'] = 'Ajouter un block Parcours sur ma page';
+	$string['pluginname'] = 'Bloc Parcours';
+	$string['title_plugin'] = 'Parcours';
+	$string['titleadd_plugin'] = 'Ajouter un parcours';
+	$string['titleaddname_plugin'] = 'Nom';
+	$string['titleadddesc_plugin'] = 'Description';
+	$string['titleaddimg_plugin'] = 'Image du parcours';
+	$string['titleaddelem_plugin'] = 'Elements du parcours';
+	$string['titleaddelemdesc_plugin'] = 'Glissez-déposez les élements du cours que vous souhaitez ajouter à ce parcours';
+	$string['heading_plugin'] = 'Les parcours permettent de regrouper certaines ressources du cours dans un enchaînement particulier.';
+	$string['add_path'] = 'Ajouter un parcours';
+	$string['any_carrer'] = 'Pas de parcours';
+?>
\ No newline at end of file
diff --git a/career/styles.css b/career/styles.css
new file mode 100644
index 0000000..aa8ed19
--- /dev/null
+++ b/career/styles.css
@@ -0,0 +1,260 @@
+.btn-career-block {
+    width: 100%;
+}
+
+/*.left {
+    float: left;
+}*/
+
+/*.img_moodle_course {
+    max-width: 100%;
+    -webkit-border-radius: 50%;
+    -moz-border-radius: 50%;
+    border-radius: 50%;
+    display: block;
+    margin: -1px;
+    min-height: 64px;
+    min-width: 64px;
+}*/
+
+/*.padding_column {
+    padding: 2rem;
+}*/
+
+/*.align_center {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+}*/
+
+/*.button {
+    box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
+}*/
+
+/*.img_center {
+    top: 1rem;
+    left: 1rem;
+}*/
+
+/*.img_moodle_list {
+    max-width: 100%;
+    -webkit-border-radius: 50%;
+    -moz-border-radius: 50%;
+    border-radius: 50%;
+    display: block;
+    margin: -1px;
+    height: 32px;
+    width: 32px;
+
+}*/
+
+.left_course_elements, .right_course_elements {
+    width: 33%;
+    float: left;
+    padding: 1%;
+    color: white;
+    text-align: center;
+    -webkit-box-shadow: 0 1px 3px 0 #d4d4d5, 0 0 0 1px #d4d4d5;
+    box-shadow: 0 1px 3px 0 #d4d4d5, 0 0 0 1px #d4d4d5;
+}
+
+.left_course_elements {
+    background: #2d2d2d;
+}
+
+.right_course_elements {
+    background: #009186;
+
+}
+
+/*.title {
+    font-size: 1.5rem;
+    color: white;
+    padding-bottom: 0.5rem
+}*/
+
+.middle_elements {
+    text-align: center;
+    width: 11%;
+    float: left;
+    padding: 1%;
+}
+
+/*#outer-dropzone {
+    height: 140px;
+}*/
+
+/*#inner-dropzone {
+    height: 80px;
+}*/
+
+/*.dropzone {
+    background-color: #ccc;
+    border: dashed 4px transparent;
+    border-radius: 4px;
+    margin: 10px auto 30px;
+    padding: 10px;
+    width: 80%;
+    transition: background-color 0.3s;
+}*/
+
+/*.drop-active {
+    border-color: #aaa;
+}*/
+
+/*.drop-target {
+    background-color: #29e;
+    border-color: #fff;
+    border-style: solid;
+}*/
+
+/*.drag-drop {
+    display: inline-block;
+    min-width: 40px;
+    padding: 2em 0.5em;
+
+    color: #fff;
+    background-color: #29e;
+    border: solid 2px #fff;
+
+    -webkit-transform: translate(0px, 0px);
+    transform: translate(0px, 0px);
+
+    transition: background-color 0.3s;
+}*/
+
+/*.drag-drop.can-drop {
+    color: #000;
+    background-color: #4e4;
+}*/
+
+/*.textarea:not([rows]) {
+    max-height: 600px;
+    min-height: 120px;
+}*/
+
+/*.textarea {
+    display: block;
+    max-width: 99%;
+    min-width: 99%;
+    padding: 0.625em;
+    resize: vertical;
+}*/
+
+/*.input, .textarea {
+    -moz-appearance: none;
+    -webkit-appearance: none;
+    -webkit-box-align: center;
+    -ms-flex-align: center;
+    align-items: center;
+    border: 1px solid transparent;
+    border-top-color: transparent;
+    border-right-color: transparent;
+    border-bottom-color: transparent;
+    border-left-color: transparent;
+    border-radius: 3px;
+    -webkit-box-shadow: none;
+    box-shadow: none;
+    display: -webkit-inline-box;
+    display: -ms-inline-flexbox;
+    display: inline-flex;
+    font-size: 1rem;
+    height: 2.25em;
+    -webkit-box-pack: start;
+    -ms-flex-pack: start;
+    justify-content: flex-start;
+    line-height: 1.5;
+    padding-bottom: calc(0.375em - 1px);
+    padding-left: calc(0.625em - 1px);
+    padding-right: calc(0.625em - 1px);
+    padding-top: calc(0.375em - 1px);
+    position: relative;
+    vertical-align: top;
+    background-color: white;
+    border-color: #dbdbdb;
+    color: #363636;
+    -webkit-box-shadow: inset 0 1px 2px rgba(10, 10, 10, 0.1);
+    box-shadow: inset 0 1px 2px rgba(10, 10, 10, 0.1);
+    margin: 0.5rem;
+    width: auto;
+    max-width: 90%;
+
+}*/
+
+/*input[type='file'] {
+    margin-bottom: 1rem;
+    padding: 0rem;
+    background: none;
+    border: 0px;
+    box-shadow: none;
+}*/
+
+.subject-info-box-1,
+.subject-info-box-2 {
+    float: left;
+    width: 100%;
+}
+
+.subject-info-box-1 select,
+.subject-info-box-2 select {
+    height: 200px;
+    padding: 0;
+}
+
+.subject-info-box-1 select option,
+.subject-info-box-2 select option {
+    padding: 4px 10px 4px 10px;
+}
+
+.subject-info-box-1 select option:hover,
+.subject-info-box-2 select option:hover {
+    background: #EEEEEE;
+}
+
+/*.subject-info-arrows {
+    float: left;
+    width: 50%;
+    margin-left: 25%;
+}*/
+
+/*.subject-info-arrows input {
+    width: 70%;
+    margin-bottom: 5px;
+}*/
+
+.path-list-edit-link {
+    position: absolute;
+    top: 0;
+    right: 0;
+}
+
+.iena-btn-career-arrow {
+    padding: 0.5rem;
+}
+
+/*.iena-career-description {
+    background: #EEE;
+    color: #323232;
+    padding: 1rem;
+    clear: both;
+    margin-bottom: 0, 5rem;
+}*/
+
+/*.iena-carrer-path-descr {
+    border: 1px solid #1587bc;
+    border-radius: 0.15rem;
+    background-color: white;
+    color: #333;
+    padding: 1rem;
+} */
+
+/*.iena-carrer-path-descr a {
+    color: #1587bc;
+    margin-top: 1rem;
+    display: block;
+}*/
+
+/*.iena-career-description p,
+.iena-carrer-path-descr p {
+    font-size: initial !important;
+}*/
diff --git a/career/version.php b/career/version.php
new file mode 100644
index 0000000..c932b00
--- /dev/null
+++ b/career/version.php
@@ -0,0 +1,35 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+	
+	/**
+	 * Version details
+	 *
+	 * The block career plugin add career in moodle it is a different
+	 * way to screen modules
+	 *
+	 * @package    block_career
+	 * @category   block
+	 * @copyright  2018 Softia/Université lorraine
+	 * @author     Vrignaud Camille / Kridagh Faouzi
+	 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+	 */
+	defined('MOODLE_INTERNAL') || die();
+	
+	$plugin->version = 2018082901;
+	$plugin->requires = 2014051200;
+	$plugin->component = 'block_career';
+	$plugin->release = 'v1.1';
+	$plugin->maturity = MATURITY_STABLE;
\ No newline at end of file
diff --git a/career/view/view_career_list.php b/career/view/view_career_list.php
new file mode 100644
index 0000000..1e04a0c
--- /dev/null
+++ b/career/view/view_career_list.php
@@ -0,0 +1,55 @@
+<?php
+	
+	
+	class view_career_list
+	{
+		
+		/**
+		 * @return string
+		 */
+		public function get_content()
+		{
+			global $DB, $CFG;
+			
+			$content = "<h2>" . get_string('title_plugin', 'block_career') . "</h2>";
+			$content .= "<div class='alert alert-info'>" . get_string('heading_plugin', 'block_career') . "</div>";
+			
+			$request = $DB->get_records_sql('SELECT * FROM {block_career} WHERE course = ?', array($_GET["course"]));
+			
+			// $image = "";
+			
+			foreach ($request as $value) {
+				
+				// if (file_get_contents($value->image) != null) {
+				// 	$image = "<img src='$value->image' class='img_moodle_course'/>";
+				// }
+				
+				$content .= "<div class='card card-block mb-3'>
+				<div class='card-body'>
+				<h2 class='card-title'>$value->name</h2>
+				<p class='card-text'>$value->description</p>
+				<a href='$CFG->wwwroot/blocks/career/career_setting.php?course=" . $_GET["course"] . "&id=$value->id' class='btn btn-primary btn-sm path-list-edit-link'>Modifier</a>
+				</div>
+                </div>";
+
+                // $content .= "<div class='card card_block'>
+                //     <div class='row'>
+                //         <div class='col-lg-1 col-md-1 padding_column align_center img_center' >$image</div>
+                //         <div class='col-lg-10 col-md-10 padding_column'><h3>$value->name</h3>$value->description</div>
+                //         <div class='col-lg-1 col-md-1 padding_column'><a style='color:black' href='$CFG->wwwroot/blocks/career/career_setting.php?course=" . $_GET["course"] . "&id=$value->id'><i class=\"fa fa-cog fa-2x\"></a></i></div>
+                //    </div>
+                // </div>";
+			}
+			
+			if (empty($request)) {
+				$content .= "<p>" . get_string('any_carrer', 'block_career') . "</p>";
+			}
+			// Button for adding course to the list
+			$content .= "<a href='$CFG->wwwroot/blocks/career/career_setting.php?course=" . $_GET["course"] . "' class='btn btn-primary'>" . get_string('add_path', 'block_career') . "</a>";
+			
+			
+			return $content;
+			
+		}
+		
+	}
\ No newline at end of file
diff --git a/career/view/view_career_setting.php b/career/view/view_career_setting.php
new file mode 100644
index 0000000..26d06de
--- /dev/null
+++ b/career/view/view_career_setting.php
@@ -0,0 +1,196 @@
+<?php
+
+/**
+ * block_career
+ *
+ *
+ * @package    block_career
+ * @category   block
+ * @copyright  2018 Softia/Université lorraine
+ * @author     vrignaud camille/ faouzi / Thomas Fradet
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class view_career_setting extends moodleform
+{
+    public function definition()
+    {
+        // TODO: Implement definition() method.
+        global $CFG;
+
+        $mform = $this->_form; // Don't forget the underscore!
+
+              //Default value
+    }
+
+    public function get_content()
+    {
+        global $DB, $CFG;
+
+        $mform = $this->_form;
+        $careerId = optional_param('id', NULL, PARAM_INT);
+        $course = required_param('course', PARAM_INT);
+
+        $name = "";
+        $description = "";
+        $ressourcesId = "";
+        $contentButton = "Ajouter un parcours";
+        // $imagePath = "";
+
+        if (isset($careerId) && !empty($careerId))
+        {
+            $requete = $DB->get_record_sql('SELECT * FROM {block_career} WHERE id = ?', array($careerId));
+            $name = $requete->name;
+            $description = $requete->description;
+            $ressourcesId = explode(",", $requete->ressources);
+            $contentButton = "Modifier le parcours";
+            // $imagePath = $requete->image;
+
+        }
+
+
+        $mform->addElement('text','careerName',get_string('titleaddname_plugin', 'block_career'));
+        $mform->addRule('careerName', get_string('error'), 'required', null, null, false, false);
+        $mform->setDefault('careerName',$name);
+
+        $mform->addElement('editor', 'descriptionName', get_string('titleadddesc_plugin', 'block_career'));
+        $mform->setType('descriptionName', PARAM_RAW);
+        $mform->addRule('descriptionName', get_string('error'), 'required', null, null, false, false);
+        $mform->setDefault('descriptionName',array('text'=>$description));
+
+        //FilePicker IMAGE
+        //$mform->addElement('filepicker', 'imageName', get_string('titleaddimg_plugin', 'block_career'), null);
+
+
+        // $content = "<h1>" . get_string('title_plugin', 'block_career') . "</h1>";
+        $content .= "<div class='alert alert-info'>" . get_string('heading_plugin', 'block_career') . "</div>";
+
+        $temp = $mform->toHtml();
+
+
+        $temp = substr($temp,(strpos($temp,'>')+1));
+        $temp = substr($temp,0, -7);
+        $content .= '<div class="row"><form class="col-12" action="career_setting.php?course=' . $course . '" method="post" enctype="multipart/form-data">';
+
+        $content .= $temp;
+
+        // $content .= ' <section class="section"><h3>' . get_string('titleaddimg_plugin', 'block_career') . '</h3>
+        // <input type="file" class="input" name="imageName" accept="image/*" /></section>';
+
+
+        $content .= ' <section class="section row"><div class="col-12"><h2>' . get_string('titleaddelem_plugin', 'block_career') . '</h2>
+        <div class="alert alert-info">' . get_string('titleaddelemdesc_plugin', 'block_career') . '</div>
+        <div class="left_course_elements">
+        <div class="title">Cours</div>
+        <div class="subject-info-box-1">
+        <select multiple="multiple" id="lstBox1" class="form-control">';
+
+        $sections = block_career_section::get_sections_by_id_course($course);
+
+        // var_dump($sections);
+
+        foreach ($sections as $section)
+        {
+            $section->ressources = block_career_ressource::get_ressources_by_id_section($section->id);
+        }
+
+        foreach ($sections as $section)
+        {
+            $content .= '<optgroup label="'.$section->name.'" value="'.$section->id.'">';
+
+            foreach ($section->ressources as $ressource)
+            {
+                $content .= '<option label="'.$ressource->name.'" value ="'.$ressource->id.'" name="'.$ressource->id.'">'.$ressource->name.'</option>';
+            }
+            $content .= '</optgroup>';
+        }
+
+        $content .='</select></div></div>';
+
+        $content .= '<div class="middle_elements">
+        <div class="title">Actions</div>
+        <div class="subject-info-arrows text-center">
+        <input type="button" id="btnAllRight" value=">>" class="btn btn-default iena-btn-career-arrow" /><br />
+        <input type="button" id="btnRight" value=">" class="btn btn-default iena-btn-career-arrow" /><br />
+        <input type="button" id="btnLeft" value="<" class="btn btn-default iena-btn-career-arrow" /><br />
+        <input type="button" id="btnAllLeft" value="<<" class="btn btn-default iena-btn-career-arrow" />
+        </div>
+        </div>';
+
+        $content .= '<div class="right_course_elements">
+        <div class="title">Parcours</div>
+        <div class="subject-info-box-2">
+        <select multiple="multiple" id="lstBox2" name="ressource[]" class="form-control" required>';
+
+
+        foreach ($ressourcesId as $value)
+        {
+            $res = new block_career_ressource();
+            $res->get_ressource_by_id($value);
+
+            if ($careerId != 0)
+                $content .= '<option label="'.$res->name.'" value ="'.$res->id.'">';
+        }
+
+        
+        $content .=  '</select>
+        </div>
+        <div class="clearfix"></div>
+        </div>
+        </div>
+        </section>';
+
+        $content .= '<script>
+        function selectAll(e)
+        {
+            // e.preventDefault();
+            selectBox = document.getElementById("lstBox2");
+
+            var checkValue = 0;
+
+            for (var i = 0; i < selectBox.options.length; i++)
+            { 
+                selectBox.options[i].selected = true;
+            }
+
+            $("#lstBox2 :selected").map(function(i, el) {
+
+                if (checkValue == $(el).val())
+                $(el).remove();
+
+                checkValue = $(el).val();
+                });
+            }
+            // console.log()
+            </script>';
+
+            if ($careerId != 0) {
+                $content .= '<input type="hidden" name="imagePath" value="'.$imagePath.'">';
+            }
+
+            $content .= '
+            <div class="row mt-3">  
+            <div class="col">
+            <input type="hidden" name="careerId" value="'.$careerId.'">
+            <a href=' . $CFG->wwwroot . "/blocks/career/career_list.php?course=" . $course . ' class="btn btn-secondary">Annuler</a> ';
+
+
+
+            if ($careerId != 0) {
+                $content .= "<a href='$CFG->wwwroot/blocks/career/career_setting.php?course=$course&delete=1&id=$careerId' class='btn btn-danger'>Supprimer</a> ";
+            }
+
+            $content .= '
+            <button type="submit" onclick="selectAll(event);" class="btn btn-primary">'.$contentButton.'</button>
+            </div>
+            </div>
+            ';
+
+
+            $content .= '</div></form>';
+
+
+            return $content;
+        }
+
+    }
\ No newline at end of file
diff --git a/career/view/view_career_unit.php b/career/view/view_career_unit.php
new file mode 100644
index 0000000..a67f079
--- /dev/null
+++ b/career/view/view_career_unit.php
@@ -0,0 +1,106 @@
+<?php
+
+$careerId = required_param("career", PARAM_INT);
+global $DB;
+$requete = $DB->get_record_sql('SELECT * FROM {block_career} WHERE id = ?', array($careerId));
+
+$percent = 70;
+$nb_pers = 5;
+$titre = $requete->name;
+$presence = "En présence";
+$date = "24 nov";
+$intro = $requete->description;
+$img = '';
+$titre_module = "Introduction";
+
+$elements = $requete->ressources;
+$elements = explode(',', $elements);
+$sections = array();
+$ressources = array();
+$i = 0;
+foreach ($elements as $value) {
+    $ressource = new block_career_ressource();
+    $ressource->get_ressource_by_id($value);
+    $sections[$i] = $ressource->section;
+    $ressources[$i] = $ressource;
+    $i++;
+}
+//var_dump($sections);
+//Supprime les doublons
+for($i = 0; $i < count($sections);$i++)
+{
+    $temp = $i;
+    $temp++;
+
+    if ($temp != count($sections))
+    {
+        if ($sections[$i]->id == $sections[$temp]->id)
+        {
+            unset($sections[$i]);
+        }
+    }
+}
+
+//Met dans l'orde
+$keys = array();
+$i = 0;
+foreach ($sections as $value){
+    $keys[$i] = $value->orde;
+    $i++;
+}
+$sections = array_combine($keys,$sections);
+ksort($sections);
+
+
+?>
+
+
+<section class="section">
+    <h2 class="display-3"><?=$titre;?></h2>
+    <div class="iena-carrer-path-descr wrapper">
+        <div class="small">
+            <?= $intro ;?>
+        </div>
+        <a href="#">Voir la description complète</a>
+    </div>
+    <?php foreach ($sections as $section) : ?>
+        <div style="margin-bottom: 0rem; margin-top: 1rem;">
+            <div class="card card_block">
+                <div class="heading-iena set_height" style="background-color: #009186 !important;">
+                    <div class="titre_section set_height">
+                        <h3><?php echo $section->name; ?></h3>
+                    </div>
+                </div>
+            </div>
+            <div class="iena-career-description wrapper">
+                <div class="small">
+                    <p><?= $section->intro ;?></p>
+                </div>
+                <a href="#">Voir la description complète</a>
+
+            </div>
+            <div class="elements">
+                <div class="list-group">
+                    <?php foreach ($ressources as $value) : ?>
+                        <?php if($value->section->id == $section->id) : ?>
+                            <div class="row" style="padding-bottom: 0.5rem;">
+                                <div class="col-md-12 col-sm-12 col-lg-12">
+                                    <a href="<?php echo "$value->link&career=$careerId" ?>" class="list-group-item list-group-item-action flex-column align-items-start">
+                                        <div class="d-flex w-100 justify-content-between">
+                                            <h5 class="mb-1"><img class="" alt="" src="<?php echo $CFG->wwwroot ?>/theme/image.php/boost/<?php echo $value->type ?>/1/icon>">
+                                               <?php echo $value->name;?></h5></div>
+
+                                               <!--<div style="max-height:100px;overflow-y:auto;"><p class="mb-1"><?php echo $value->descrition;?></p></div>--></a>
+                                           </div>
+                                       </div>
+                                   <?php endif;?>
+                               <?php endforeach;?>
+                           </div>
+                       </div></div>
+                   <?php endforeach;?>
+                   <!-- </ul> -->
+                   <!--  </div> -->
+
+
+
+               </section>
diff --git a/classes 14.04.12/external.php b/classes 14.04.12/external.php
new file mode 100644
index 0000000..95de3b8
--- /dev/null
+++ b/classes 14.04.12/external.php	
@@ -0,0 +1,137 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Blocks external API
+ *
+ * @package    core_block
+ * @category   external
+ * @copyright  2017 Juan Leyva <juan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since      Moodle 3.3
+ */
+
+defined('MOODLE_INTERNAL') || die;
+
+require_once("$CFG->libdir/externallib.php");
+
+/**
+ * Blocks external functions
+ *
+ * @package    core_block
+ * @category   external
+ * @copyright  2015 Juan Leyva <juan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since      Moodle 3.3
+ */
+class core_block_external extends external_api {
+
+    /**
+     * Returns description of get_course_blocks parameters.
+     *
+     * @return external_function_parameters
+     * @since Moodle 3.3
+     */
+    public static function get_course_blocks_parameters() {
+        return new external_function_parameters(
+            array(
+                'courseid'  => new external_value(PARAM_INT, 'course id')
+            )
+        );
+    }
+
+    /**
+     * Returns blocks information for a course.
+     *
+     * @param int $courseid The course id
+     * @return array Blocks list and possible warnings
+     * @throws moodle_exception
+     * @since Moodle 3.3
+     */
+    public static function get_course_blocks($courseid) {
+        global $OUTPUT, $PAGE;
+
+        $warnings = array();
+        $params = self::validate_parameters(self::get_course_blocks_parameters(), ['courseid' => $courseid]);
+
+        $course = get_course($params['courseid']);
+        $context = context_course::instance($course->id);
+        self::validate_context($context);
+
+        // Specific layout for frontpage course.
+        if ($course->id == SITEID) {
+            $PAGE->set_pagelayout('frontpage');
+            $PAGE->set_pagetype('site-index');
+        } else {
+            $PAGE->set_pagelayout('course');
+            // Ensure course format is set (view course/view.php).
+            $course->format = course_get_format($course)->get_format();
+            $PAGE->set_pagetype('course-view-' . $course->format);
+        }
+
+        // Load the block instances for all the regions.
+        $PAGE->blocks->load_blocks();
+        $PAGE->blocks->create_all_block_instances();
+
+        $finalblocks = array();
+        $blocks = $PAGE->blocks->get_content_for_all_regions($OUTPUT);
+        foreach ($blocks as $region => $regionblocks) {
+            foreach ($regionblocks as $bc) {
+                $finalblocks[] = [
+                    'instanceid' => $bc->blockinstanceid,
+                    'name' => $bc->attributes['data-block'],
+                    'region' => $region,
+                    'positionid' => $bc->blockpositionid,
+                    'collapsible' => (bool) $bc->collapsible,
+                    'dockable' => (bool) $bc->dockable,
+                ];
+            }
+        }
+
+        return array(
+            'blocks' => $finalblocks,
+            'warnings' => $warnings
+        );
+    }
+
+    /**
+     * Returns description of get_course_blocks result values.
+     *
+     * @return external_single_structure
+     * @since Moodle 3.3
+     */
+    public static function get_course_blocks_returns() {
+
+        return new external_single_structure(
+            array(
+                'blocks' => new external_multiple_structure(
+                    new external_single_structure(
+                        array(
+                            'instanceid'    => new external_value(PARAM_INT, 'Block instance id.'),
+                            'name'          => new external_value(PARAM_PLUGIN, 'Block name.'),
+                            'region'        => new external_value(PARAM_ALPHANUMEXT, 'Block region.'),
+                            'positionid'    => new external_value(PARAM_INT, 'Position id.'),
+                            'collapsible'   => new external_value(PARAM_BOOL, 'Whether the block is collapsible.'),
+                            'dockable'      => new external_value(PARAM_BOOL, 'hether the block is  dockable.'),
+                        ), 'Block information.'
+                    ), 'List of blocks in the course.'
+                ),
+                'warnings'  => new external_warnings(),
+            )
+        );
+    }
+
+}
diff --git a/classes 14.04.12/privacy/provider.php b/classes 14.04.12/privacy/provider.php
new file mode 100644
index 0000000..cbee644
--- /dev/null
+++ b/classes 14.04.12/privacy/provider.php	
@@ -0,0 +1,227 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Data provider.
+ *
+ * @package    core_block
+ * @copyright  2018 Frédéric Massart
+ * @author     Frédéric Massart <fred@branchup.tech>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core_block\privacy;
+defined('MOODLE_INTERNAL') || die();
+
+use context;
+use context_block;
+use core_privacy\local\metadata\collection;
+use core_privacy\local\request\approved_contextlist;
+use core_privacy\local\request\transform;
+use core_privacy\local\request\writer;
+
+/**
+ * Data provider class.
+ *
+ * @package    core_block
+ * @copyright  2018 Frédéric Massart
+ * @author     Frédéric Massart <fred@branchup.tech>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements
+    \core_privacy\local\metadata\provider,
+    \core_privacy\local\request\subsystem\provider,
+    \core_privacy\local\request\user_preference_provider {
+
+    /**
+     * Returns metadata.
+     *
+     * @param collection $collection The initialised collection to add items to.
+     * @return collection A listing of user data stored through this system.
+     */
+    public static function get_metadata(collection $collection) : collection {
+        $collection->add_user_preference('blockIDhidden', 'privacy:metadata:userpref:hiddenblock');
+        $collection->add_user_preference('docked_block_instance_ID', 'privacy:metadata:userpref:dockedinstance');
+        return $collection;
+    }
+
+    /**
+     * Get the list of contexts that contain user information for the specified user.
+     *
+     * @param int $userid The user to search.
+     * @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
+     */
+    public static function get_contexts_for_userid(int $userid) : \core_privacy\local\request\contextlist {
+        global $DB;
+        $contextlist = new \core_privacy\local\request\contextlist();
+
+        // Fetch the block instance IDs.
+        $likehidden = $DB->sql_like('name', ':hidden', false, false);
+        $likedocked = $DB->sql_like('name', ':docked', false, false);
+        $sql = "userid = :userid AND ($likehidden OR $likedocked)";
+        $params = [
+            'userid' => $userid,
+            'hidden' => 'block%hidden',
+            'docked' => 'docked_block_instance_%',
+        ];
+        $prefs = $DB->get_fieldset_select('user_preferences', 'name', $sql, $params);
+
+        $instanceids = array_unique(array_map(function($prefname) {
+            if (preg_match('/^block(\d+)hidden$/', $prefname, $matches)) {
+                return $matches[1];
+            } else if (preg_match('/^docked_block_instance_(\d+)$/', $prefname, $matches)) {
+                return $matches[1];
+            }
+            return 0;
+        }, $prefs));
+
+        // Find the context of the instances.
+        if (!empty($instanceids)) {
+            list($insql, $inparams) = $DB->get_in_or_equal($instanceids, SQL_PARAMS_NAMED);
+            $sql = "
+                SELECT ctx.id
+                  FROM {context} ctx
+                 WHERE ctx.instanceid $insql
+                   AND ctx.contextlevel = :blocklevel";
+            $params = array_merge($inparams, ['blocklevel' => CONTEXT_BLOCK]);
+            $contextlist->add_from_sql($sql, $params);
+        }
+
+        return $contextlist;
+    }
+
+    /**
+     * Export all user data for the specified user, in the specified contexts.
+     *
+     * @param approved_contextlist $contextlist The approved contexts to export information for.
+     */
+    public static function export_user_data(approved_contextlist $contextlist) {
+        global $DB;
+        $userid = $contextlist->get_user()->id;
+
+        // Extract the block instance IDs.
+        $instanceids = array_reduce($contextlist->get_contexts(), function($carry, $context) {
+            if ($context->contextlevel == CONTEXT_BLOCK) {
+                $carry[] = $context->instanceid;
+            }
+            return $carry;
+        }, []);
+        if (empty($instanceids)) {
+            return;
+        }
+
+        // Query the blocks and their preferences.
+        list($insql, $inparams) = $DB->get_in_or_equal($instanceids, SQL_PARAMS_NAMED);
+        $hiddenkey = $DB->sql_concat("'block'", 'bi.id', "'hidden'");
+        $dockedkey = $DB->sql_concat("'docked_block_instance_'", 'bi.id');
+        $sql = "
+            SELECT bi.id, h.value AS prefhidden, d.value AS prefdocked
+              FROM {block_instances} bi
+         LEFT JOIN {user_preferences} h
+                ON h.userid = :userid1
+               AND h.name = $hiddenkey
+         LEFT JOIN {user_preferences} d
+                ON d.userid = :userid2
+               AND d.name = $dockedkey
+             WHERE bi.id $insql
+               AND (h.id IS NOT NULL
+                OR d.id IS NOT NULL)";
+        $params = array_merge($inparams, [
+            'userid1' => $userid,
+            'userid2' => $userid,
+        ]);
+
+        // Export all the things.
+        $dockedstr = get_string('privacy:request:blockisdocked', 'core_block');
+        $hiddenstr = get_string('privacy:request:blockishidden', 'core_block');
+        $recordset = $DB->get_recordset_sql($sql, $params);
+        foreach ($recordset as $record) {
+            $context = context_block::instance($record->id);
+            if ($record->prefdocked !== null) {
+                writer::with_context($context)->export_user_preference(
+                    'core_block',
+                    'block_is_docked',
+                    transform::yesno($record->prefdocked),
+                    $dockedstr
+                );
+            }
+            if ($record->prefhidden !== null) {
+                writer::with_context($context)->export_user_preference(
+                    'core_block',
+                    'block_is_hidden',
+                    transform::yesno($record->prefhidden),
+                    $hiddenstr
+                );
+            }
+        }
+        $recordset->close();
+    }
+
+    /**
+     * Export all user preferences for the plugin.
+     *
+     * @param int $userid The userid of the user whose data is to be exported.
+     */
+    public static function export_user_preferences(int $userid) {
+      // Our preferences aren't site-wide so they are exported in export_user_data.
+    }
+
+    /**
+     * Delete all data for all users in the specified context.
+     *
+     * @param context $context The specific context to delete data for.
+     */
+    public static function delete_data_for_all_users_in_context(context $context) {
+        global $DB;
+        if ($context->contextlevel != CONTEXT_BLOCK) {
+            return;
+        }
+
+        // Delete the user preferences.
+        $instanceid = $context->instanceid;
+        $DB->delete_records_list('user_preferences', 'name', [
+            "block{$instanceid}hidden",
+            "docked_block_instance_{$instanceid}"
+        ]);
+    }
+
+    /**
+     * Delete all user data for the specified user, in the specified contexts.
+     *
+     * @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
+     */
+    public static function delete_data_for_user(approved_contextlist $contextlist) {
+        global $DB;
+        $userid = $contextlist->get_user()->id;
+        $prefnames = array_reduce($contextlist->get_contexts(), function($carry, $context) {
+            if ($context->contextlevel == CONTEXT_BLOCK) {
+                $carry[] = "block{$context->instanceid}hidden";
+                $carry[] = "docked_block_instance_{$context->instanceid}";
+            }
+            return $carry;
+        }, []);
+
+        if (empty($prefnames)) {
+            return;
+        }
+
+        list($insql, $inparams) = $DB->get_in_or_equal($prefnames, SQL_PARAMS_NAMED);
+        $sql = "userid = :userid AND name $insql";
+        $params = array_merge($inparams, ['userid' => $userid]);
+        $DB->delete_records_select('user_preferences', $sql, $params);
+    }
+
+}
diff --git a/comments/block_comments.php b/comments/block_comments.php
new file mode 100644
index 0000000..b36facc
--- /dev/null
+++ b/comments/block_comments.php
@@ -0,0 +1,88 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * The comments block
+ *
+ * @package    block_comments
+ * @copyright 2009 Dongsheng Cai <dongsheng@moodle.com>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+// Obviously required
+require_once($CFG->dirroot . '/comment/lib.php');
+
+class block_comments extends block_base {
+
+    function init() {
+        $this->title = get_string('pluginname', 'block_comments');
+    }
+
+    function specialization() {
+        // require js for commenting
+        comment::init();
+    }
+    function applicable_formats() {
+        return array('all' => true);
+    }
+
+    function instance_allow_multiple() {
+        return false;
+    }
+
+    function get_content() {
+        global $CFG, $PAGE;
+        if ($this->content !== NULL) {
+            return $this->content;
+        }
+        if (!$CFG->usecomments) {
+            $this->content = new stdClass();
+            $this->content->text = '';
+            if ($this->page->user_is_editing()) {
+                $this->content->text = get_string('disabledcomments');
+            }
+            return $this->content;
+        }
+        $this->content = new stdClass();
+        $this->content->footer = '';
+        $this->content->text = '';
+        if (empty($this->instance)) {
+            return $this->content;
+        }
+        list($context, $course, $cm) = get_context_info_array($PAGE->context->id);
+
+        $args = new stdClass;
+        $args->context   = $PAGE->context;
+        $args->course    = $course;
+        $args->area      = 'page_comments';
+        $args->itemid    = 0;
+        $args->component = 'block_comments';
+        $args->linktext  = get_string('showcomments');
+        $args->notoggle  = true;
+        $args->autostart = true;
+        $args->displaycancel = false;
+        $comment = new comment($args);
+        $comment->set_view_permission(true);
+        $comment->set_fullwidth();
+
+        $this->content = new stdClass();
+        $this->content->text = $comment->output(true);
+        $this->content->footer = '';
+        return $this->content;
+    }
+}
diff --git a/comments/classes/event/comment_created.php b/comments/classes/event/comment_created.php
new file mode 100644
index 0000000..5864f83
--- /dev/null
+++ b/comments/classes/event/comment_created.php
@@ -0,0 +1,38 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * block_comments comment created event.
+ *
+ * @package    block_comments
+ * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_comments\event;
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * block_comments comment created event.
+ *
+ * @package    block_comments
+ * @since      Moodle 2.7
+ * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class comment_created extends \core\event\comment_created {
+    // No need to override any method.
+}
diff --git a/comments/classes/event/comment_deleted.php b/comments/classes/event/comment_deleted.php
new file mode 100644
index 0000000..6e1214d
--- /dev/null
+++ b/comments/classes/event/comment_deleted.php
@@ -0,0 +1,38 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * block_comments comment deleted event.
+ *
+ * @package    block_comments
+ * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_comments\event;
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * block_comments comment deleted event.
+ *
+ * @package    block_comments
+ * @since      Moodle 2.7
+ * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class comment_deleted extends \core\event\comment_deleted {
+    // No need to override any method.
+}
diff --git a/comments/classes/privacy/provider.php b/comments/classes/privacy/provider.php
new file mode 100644
index 0000000..d758293
--- /dev/null
+++ b/comments/classes/privacy/provider.php
@@ -0,0 +1,115 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_comments.
+ *
+ * @package    block_comments
+ * @category   privacy
+ * @copyright  2018 Shamim Rezaie <shamim@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_comments\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+use core_privacy\local\metadata\collection;
+use core_privacy\local\request\approved_contextlist;
+use core_privacy\local\request\contextlist;
+
+/**
+ * Privacy Subsystem implementation for block_comments.
+ *
+ * @copyright  2018 Shamim Rezaie <shamim@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements
+        // The block_comments block stores user provided data.
+        \core_privacy\local\metadata\provider,
+
+        // The block_comments block provides data directly to core.
+        \core_privacy\local\request\plugin\provider {
+
+    /**
+     * Returns meta data about this system.
+     *
+     * @param collection $collection
+     * @return collection
+     */
+    public static function get_metadata(collection $collection) : collection {
+        return $collection->add_subsystem_link('core_comment', [], 'privacy:metadata:core_comment');
+    }
+
+    /**
+     * Get the list of contexts that contain user information for the specified user.
+     *
+     * @param int $userid
+     * @return contextlist
+     */
+    public static function get_contexts_for_userid(int $userid) : contextlist {
+        $contextlist = new contextlist();
+
+        $sql = "SELECT contextid
+                  FROM {comments}
+                 WHERE component = :component
+                   AND userid = :userid";
+        $params = [
+            'component' => 'block_comments',
+            'userid' => $userid
+        ];
+
+        $contextlist->add_from_sql($sql, $params);
+
+        return $contextlist;
+    }
+
+    /**
+     * Export all user data for the specified user, in the specified contexts.
+     *
+     * @param approved_contextlist $contextlist
+     */
+    public static function export_user_data(approved_contextlist $contextlist) {
+        $contexts = $contextlist->get_contexts();
+        foreach ($contexts as $context) {
+            \core_comment\privacy\provider::export_comments(
+                    $context,
+                    'block_comments',
+                    'page_comments',
+                    0,
+                    []
+            );
+        }
+    }
+
+    /**
+     * Delete all data for all users in the specified context.
+     *
+     * @param \context $context
+     */
+    public static function delete_data_for_all_users_in_context(\context $context) {
+        \core_comment\privacy\provider::delete_comments_for_all_users($context, 'block_comments');
+    }
+
+    /**
+     * Delete all user data for the specified user, in the specified contexts.
+     *
+     * @param approved_contextlist $contextlist
+     */
+    public static function delete_data_for_user(approved_contextlist $contextlist) {
+        \core_comment\privacy\provider::delete_comments_for_user($contextlist, 'block_comments');
+    }
+}
diff --git a/comments/db/access.php b/comments/db/access.php
new file mode 100644
index 0000000..1122993
--- /dev/null
+++ b/comments/db/access.php
@@ -0,0 +1,51 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Comments block caps.
+ *
+ * @package    block_comments
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/comments:myaddinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/my:manageblocks'
+    ),
+
+    'block/comments:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/comments/lang/en/block_comments.php b/comments/lang/en/block_comments.php
new file mode 100644
index 0000000..116f10e
--- /dev/null
+++ b/comments/lang/en/block_comments.php
@@ -0,0 +1,29 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_comments', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_comments
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['comments:myaddinstance'] = 'Add a new comments block to Dashboard';
+$string['comments:addinstance'] = 'Add a new comments block';
+$string['pluginname'] = 'Comments';
+$string['privacy:metadata:core_comment'] = 'A record of comments added.';
diff --git a/comments/lib.php b/comments/lib.php
new file mode 100644
index 0000000..454d1cd
--- /dev/null
+++ b/comments/lib.php
@@ -0,0 +1,83 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * The comments block helper functions and callbacks
+ *
+ * @package   block_comments
+ * @copyright 2011 Dongsheng Cai <dongsheng@moodle.com>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Validate comment parameter before perform other comments actions
+ *
+ * @package  block_comments
+ * @category comment
+ *
+ * @param stdClass $comment_param {
+ *              context  => context the context object
+ *              courseid => int course id
+ *              cm       => stdClass course module object
+ *              commentarea => string comment area
+ *              itemid      => int itemid
+ * }
+ * @return boolean
+ */
+function block_comments_comment_validate($comment_param) {
+    if ($comment_param->commentarea != 'page_comments') {
+        throw new comment_exception('invalidcommentarea');
+    }
+    if ($comment_param->itemid != 0) {
+        throw new comment_exception('invalidcommentitemid');
+    }
+    return true;
+}
+
+/**
+ * Running addtional permission check on plugins
+ *
+ * @package  block_comments
+ * @category comment
+ *
+ * @param stdClass $args
+ * @return array
+ */
+function block_comments_comment_permissions($args) {
+    return array('post'=>true, 'view'=>true);
+}
+
+/**
+ * Validate comment data before displaying comments
+ *
+ * @package  block_comments
+ * @category comment
+ *
+ * @param stdClass $comment
+ * @param stdClass $args
+ * @return boolean
+ */
+function block_comments_comment_display($comments, $args) {
+    if ($args->commentarea != 'page_comments') {
+        throw new comment_exception('invalidcommentarea');
+    }
+    if ($args->itemid != 0) {
+        throw new comment_exception('invalidcommentitemid');
+    }
+    return $comments;
+}
diff --git a/comments/tests/behat/add_comment.feature b/comments/tests/behat/add_comment.feature
new file mode 100644
index 0000000..02f73f4
--- /dev/null
+++ b/comments/tests/behat/add_comment.feature
@@ -0,0 +1,98 @@
+@block @block_comments
+Feature: Add a comment to the comments block
+  In order to comment on a conversation or a topic
+  As a user
+  In need to add comments to courses
+
+  Background:
+    Given the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "users" exist:
+      | username | firstname | lastname | email |
+      | teacher1 | Teacher | Frist | teacher1@example.com |
+      | student1 | Student | First | student1@example.com |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Comments" block
+    And I log out
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+
+  @javascript
+  Scenario: Add a comment with Javascript enabled
+    When I add "I'm a comment from student1" comment to comments block
+    Then I should see "I'm a comment from student1"
+
+  Scenario: Add a comment with Javascript disabled
+    When I follow "Show comments"
+    And I add "I'm a comment from student1" comment to comments block
+    Then I should see "I'm a comment from student1"
+
+  @javascript
+  Scenario: Test comment block pagination
+    When I add "Super test comment 01" comment to comments block
+    And I add "Super test comment 02" comment to comments block
+    And I add "Super test comment 03" comment to comments block
+    And I add "Super test comment 04" comment to comments block
+    And I add "Super test comment 05" comment to comments block
+    And I add "Super test comment 06" comment to comments block
+    And I add "Super test comment 07" comment to comments block
+    And I add "Super test comment 08" comment to comments block
+    And I add "Super test comment 09" comment to comments block
+    And I add "Super test comment 10" comment to comments block
+    And I add "Super test comment 11" comment to comments block
+    And I add "Super test comment 12" comment to comments block
+    And I add "Super test comment 13" comment to comments block
+    And I add "Super test comment 14" comment to comments block
+    And I add "Super test comment 15" comment to comments block
+    And I add "Super test comment 16" comment to comments block
+    And I add "Super test comment 17" comment to comments block
+    And I add "Super test comment 18" comment to comments block
+    And I add "Super test comment 19" comment to comments block
+    And I add "Super test comment 20" comment to comments block
+    And I add "Super test comment 21" comment to comments block
+    And I add "Super test comment 22" comment to comments block
+    And I add "Super test comment 23" comment to comments block
+    And I add "Super test comment 24" comment to comments block
+    And I add "Super test comment 25" comment to comments block
+    And I add "Super test comment 26" comment to comments block
+    And I add "Super test comment 27" comment to comments block
+    And I add "Super test comment 28" comment to comments block
+    And I add "Super test comment 29" comment to comments block
+    And I add "Super test comment 30" comment to comments block
+    And I add "Super test comment 31" comment to comments block
+    Then I should see "Super test comment 01"
+    And I should see "Super test comment 31"
+    And I am on "Course 1" course homepage
+    And I should not see "Super test comment 01"
+    And I should not see "Super test comment 02"
+    And I should not see "Super test comment 16"
+    And I should see "Super test comment 17"
+    And I should see "Super test comment 31"
+    And I should see "1" in the ".block_comments .comment-paging" "css_element"
+    And I should see "2" in the ".block_comments .comment-paging" "css_element"
+    And I should see "3" in the ".block_comments .comment-paging" "css_element"
+    And I should not see "4" in the ".block_comments .comment-paging" "css_element"
+    And I click on "2" "link" in the ".block_comments .comment-paging" "css_element"
+    And I should not see "Super test comment 01"
+    And I should see "Super test comment 02"
+    And I should see "Super test comment 16"
+    And I should not see "Super test comment 17"
+    And I should not see "Super test comment 31"
+    And I click on "3" "link" in the ".block_comments .comment-paging" "css_element"
+    And I should see "Super test comment 01"
+    And I should not see "Super test comment 02"
+    And I should not see "Super test comment 16"
+    And I should not see "Super test comment 17"
+    And I should not see "Super test comment 31"
+    And I click on "1" "link" in the ".block_comments .comment-paging" "css_element"
+    And I should not see "Super test comment 01"
+    And I should not see "Super test comment 02"
+    And I should not see "Super test comment 16"
+    And I should see "Super test comment 17"
+    And I should see "Super test comment 31"
diff --git a/comments/tests/behat/behat_block_comments.php b/comments/tests/behat/behat_block_comments.php
new file mode 100644
index 0000000..26f7495
--- /dev/null
+++ b/comments/tests/behat/behat_block_comments.php
@@ -0,0 +1,110 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Commenting system steps definitions.
+ *
+ * @package    block_comments
+ * @category   test
+ * @copyright  2013 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
+
+require_once(__DIR__ . '/../../../../lib/behat/behat_base.php');
+
+use Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException,
+    Behat\Mink\Exception\ExpectationException as ExpectationException;
+
+/**
+ * Steps definitions to deal with the commenting system
+ *
+ * @package    block_comments
+ * @category   test
+ * @copyright  2013 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class behat_block_comments extends behat_base {
+
+    /**
+     * Adds the specified option to the comments block of the current page.
+     *
+     * This method can be adapted in future to add other comments considering
+     * that there could be more than one comment textarea per page.
+     *
+     * Only 1 comments block instance is allowed per page, if this changes this
+     * steps definitions should be adapted.
+     *
+     * @Given /^I add "(?P<comment_text_string>(?:[^"]|\\")*)" comment to comments block$/
+     * @throws ElementNotFoundException
+     * @param string $comment
+     */
+    public function i_add_comment_to_comments_block($comment) {
+
+        // Getting the textarea and setting the provided value.
+        $exception = new ElementNotFoundException($this->getSession(), 'Comments block ');
+
+        // The whole DOM structure changes depending on JS enabled/disabled.
+        if ($this->running_javascript()) {
+            $commentstextarea = $this->find('css', '.comment-area textarea', $exception);
+            $commentstextarea->setValue($comment);
+
+            $this->find_link(get_string('savecomment'))->click();
+            // Delay after clicking so that additional comments will have unique time stamps.
+            // We delay 1 second which is all we need.
+            $this->getSession()->wait(1000);
+
+        } else {
+
+            $commentstextarea = $this->find('css', '.block_comments form textarea', $exception);
+            $commentstextarea->setValue($comment);
+
+            // Comments submit button
+            $submit = $this->find('css', '.block_comments form input[type=submit]');
+            $submit->press();
+        }
+    }
+
+    /**
+     * Deletes the specified comment from the current page's comments block.
+     *
+     * @Given /^I delete "(?P<comment_text_string>(?:[^"]|\\")*)" comment from comments block$/
+     * @throws ElementNotFoundException
+     * @throws ExpectationException
+     * @param string $comment
+     */
+    public function i_delete_comment_from_comments_block($comment) {
+
+        $exception = new ElementNotFoundException($this->getSession(), '"' . $comment . '" comment ');
+
+        // Using xpath liternal to avoid possible problems with comments containing quotes.
+        $commentliteral = behat_context_helper::escape($comment);
+
+        $commentxpath = "//*[contains(concat(' ', normalize-space(@class), ' '), ' block_comments ')]" .
+            "/descendant::div[@class='comment-message'][contains(., $commentliteral)]";
+        $commentnode = $this->find('xpath', $commentxpath, $exception);
+
+        // Click on delete icon.
+        $this->execute('behat_general::i_click_on_in_the',
+            array("Delete comment posted by", "icon", $this->escape($commentxpath), "xpath_element")
+        );
+
+        // Wait for the animation to finish, in theory is just 1 sec, adding 4 just in case.
+        $this->getSession()->wait(4 * 1000);
+    }
+
+}
diff --git a/comments/tests/behat/block_comment_activity.feature b/comments/tests/behat/block_comment_activity.feature
new file mode 100644
index 0000000..4aa94bd
--- /dev/null
+++ b/comments/tests/behat/block_comment_activity.feature
@@ -0,0 +1,33 @@
+@block @block_comments
+Feature: Enable Block comments on an activity page and view comments
+  In order to enable the comments block on an activity page
+  As a teacher
+  I can add the comments block to an activity page
+
+  Scenario: Add the comments block on an activity page and add comments
+    Given the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "users" exist:
+      | username | firstname | lastname | email |
+      | teacher1 | Teacher | Frist | teacher1@example.com |
+      | student1 | Student | First | student1@example.com |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+    And the following "activities" exist:
+      | activity | course | idnumber | name           | intro                 |
+      | page    | C1      | page1    | Test page name | Test page description |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I follow "Test page name"
+    And I add the "Comments" block
+    And I follow "Show comments"
+    And I add "I'm a comment from the teacher" comment to comments block
+    And I log out
+    When I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I follow "Test page name"
+    And I follow "Show comments"
+    Then I should see "I'm a comment from the teacher"
diff --git a/comments/tests/behat/block_comment_course.feature b/comments/tests/behat/block_comment_course.feature
new file mode 100644
index 0000000..3589da4
--- /dev/null
+++ b/comments/tests/behat/block_comment_course.feature
@@ -0,0 +1,28 @@
+@block @block_comments
+Feature: Enable Block comments on a course page and view comments
+  In order to enable the comments block on a course page
+  As a teacher
+  I can add the comments block to the course page
+
+  Scenario: Add the comments block on the course page and add comments
+    Given the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "users" exist:
+      | username | firstname | lastname | email |
+      | teacher1 | Teacher | Frist | teacher1@example.com |
+      | student1 | Student | First | student1@example.com |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Comments" block
+    And I follow "Show comments"
+    And I add "I'm a comment from the teacher" comment to comments block
+    And I log out
+    When I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I follow "Show comments"
+    Then I should see "I'm a comment from the teacher"
diff --git a/comments/tests/behat/block_comment_dashboard.feature b/comments/tests/behat/block_comment_dashboard.feature
new file mode 100644
index 0000000..66e49c6
--- /dev/null
+++ b/comments/tests/behat/block_comment_dashboard.feature
@@ -0,0 +1,29 @@
+@block @block_comments
+Feature: Enable Block comments on the dashboard and view comments
+  In order to enable the comments block on a the dashboard
+  As a teacher
+  I can add the comments block to my dashboard
+
+  Background:
+    Given the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "users" exist:
+      | username | firstname | lastname | email |
+      | teacher1 | Teacher | Frist | teacher1@example.com |
+
+  Scenario: Add the comments block on the dashboard and add comments with Javascript disabled
+    When I log in as "teacher1"
+    And I press "Customise this page"
+    And I add the "Comments" block
+    And I follow "Show comments"
+    And I add "I'm a comment from the teacher" comment to comments block
+    Then I should see "I'm a comment from the teacher"
+
+  @javascript
+  Scenario: Add the comments block on the dashboard and add comments with Javascript enabled
+    When I log in as "teacher1"
+    And I press "Customise this page"
+    And I add the "Comments" block
+    And I add "I'm a comment from the teacher" comment to comments block
+    Then I should see "I'm a comment from the teacher"
diff --git a/comments/tests/behat/block_comment_frontpage.feature b/comments/tests/behat/block_comment_frontpage.feature
new file mode 100644
index 0000000..5d949ab
--- /dev/null
+++ b/comments/tests/behat/block_comment_frontpage.feature
@@ -0,0 +1,21 @@
+@block @block_comments
+Feature: Enable Block comments on the frontpage and view comments
+  In order to enable the comments block on the frontpage
+  As a admin
+  I can add the comments block to the frontpage
+
+  Scenario: Add the comments block on the frontpage and add comments
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+    And I log in as "admin"
+    And I am on site homepage
+    And I navigate to "Turn editing on" node in "Front page settings"
+    And I add the "Comments" block
+    And I follow "Show comments"
+    And I add "I'm a comment from admin" comment to comments block
+    And I log out
+    When I log in as "teacher1"
+    And I am on site homepage
+    And I follow "Show comments"
+    Then I should see "I'm a comment from admin"
diff --git a/comments/tests/behat/delete_comment.feature b/comments/tests/behat/delete_comment.feature
new file mode 100644
index 0000000..f8939f4
--- /dev/null
+++ b/comments/tests/behat/delete_comment.feature
@@ -0,0 +1,34 @@
+@block @block_comments
+Feature: Delete comment block messages
+  In order to refine comment block's contents
+  As a teacher
+  In need to delete comments from courses
+
+  @javascript
+  Scenario: Delete comments with Javascript enabled
+    Given the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "users" exist:
+      | username | firstname | lastname | email |
+      | teacher1 | Teacher | First | teacher1@example.com |
+      | student1 | Student | First | student1@example.com |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Comments" block
+    And I log out
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I add "Comment from student1" comment to comments block
+    And I log out
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage
+    And I add "Comment from teacher1" comment to comments block
+    When I delete "Comment from student1" comment from comments block
+    Then I should not see "Comment from student1"
+    And I delete "Comment from teacher1" comment from comments block
+    And I should not see "Comment from teacher1"
diff --git a/comments/tests/events_test.php b/comments/tests/events_test.php
new file mode 100644
index 0000000..1e7aae4
--- /dev/null
+++ b/comments/tests/events_test.php
@@ -0,0 +1,184 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Events tests.
+ *
+ * @package    block_comments
+ * @category   test
+ * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Events tests class.
+ *
+ * @package    block_comments
+ * @category   test
+ * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_comments_events_testcase extends advanced_testcase {
+    /** @var stdClass Keeps course object */
+    private $course;
+
+    /** @var stdClass Keeps wiki object */
+    private $wiki;
+
+    /**
+     * Setup test data.
+     */
+    public function setUp() {
+        $this->resetAfterTest();
+        $this->setAdminUser();
+
+        // Create course and wiki.
+        $this->course = $this->getDataGenerator()->create_course();
+        $this->wiki = $this->getDataGenerator()->create_module('wiki', array('course' => $this->course->id));
+    }
+
+    /**
+     * Test comment_created event.
+     */
+    public function test_comment_created() {
+        global $CFG;
+
+        require_once($CFG->dirroot . '/comment/lib.php');
+
+        // Comment on course page.
+        $context = context_course::instance($this->course->id);
+        $args = new stdClass;
+        $args->context = $context;
+        $args->course = $this->course;
+        $args->area = 'page_comments';
+        $args->itemid = 0;
+        $args->component = 'block_comments';
+        $args->linktext = get_string('showcomments');
+        $args->notoggle = true;
+        $args->autostart = true;
+        $args->displaycancel = false;
+        $comment = new comment($args);
+
+        // Triggering and capturing the event.
+        $sink = $this->redirectEvents();
+        $comment->add('New comment');
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Checking that the event contains the expected values.
+        $this->assertInstanceOf('\block_comments\event\comment_created', $event);
+        $this->assertEquals($context, $event->get_context());
+        $url = new moodle_url('/course/view.php', array('id' => $this->course->id));
+        $this->assertEquals($url, $event->get_url());
+
+        // Comments when block is on module (wiki) page.
+        $context = context_module::instance($this->wiki->cmid);
+        $args = new stdClass;
+        $args->context   = $context;
+        $args->course    = $this->course;
+        $args->area      = 'page_comments';
+        $args->itemid    = 0;
+        $args->component = 'block_comments';
+        $args->linktext  = get_string('showcomments');
+        $args->notoggle  = true;
+        $args->autostart = true;
+        $args->displaycancel = false;
+        $comment = new comment($args);
+
+        // Triggering and capturing the event.
+        $sink = $this->redirectEvents();
+        $comment->add('New comment 1');
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Checking that the event contains the expected values.
+        $this->assertInstanceOf('\block_comments\event\comment_created', $event);
+        $this->assertEquals($context, $event->get_context());
+        $url = new moodle_url('/mod/wiki/view.php', array('id' => $this->wiki->cmid));
+        $this->assertEquals($url, $event->get_url());
+        $this->assertEventContextNotUsed($event);
+    }
+
+    /**
+     * Test comment_deleted event.
+     */
+    public function test_comment_deleted() {
+        global $CFG;
+
+        require_once($CFG->dirroot . '/comment/lib.php');
+
+        // Comment on course page.
+        $context = context_course::instance($this->course->id);
+        $args = new stdClass;
+        $args->context   = $context;
+        $args->course    = $this->course;
+        $args->area      = 'page_comments';
+        $args->itemid    = 0;
+        $args->component = 'block_comments';
+        $args->linktext  = get_string('showcomments');
+        $args->notoggle  = true;
+        $args->autostart = true;
+        $args->displaycancel = false;
+        $comment = new comment($args);
+        $newcomment = $comment->add('New comment');
+
+        // Triggering and capturing the event.
+        $sink = $this->redirectEvents();
+        $comment->delete($newcomment->id);
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Checking that the event contains the expected values.
+        $this->assertInstanceOf('\block_comments\event\comment_deleted', $event);
+        $this->assertEquals($context, $event->get_context());
+        $url = new moodle_url('/course/view.php', array('id' => $this->course->id));
+        $this->assertEquals($url, $event->get_url());
+
+        // Comments when block is on module (wiki) page.
+        $context = context_module::instance($this->wiki->cmid);
+        $args = new stdClass;
+        $args->context   = $context;
+        $args->course    = $this->course;
+        $args->area      = 'page_comments';
+        $args->itemid    = 0;
+        $args->component = 'block_comments';
+        $args->linktext  = get_string('showcomments');
+        $args->notoggle  = true;
+        $args->autostart = true;
+        $args->displaycancel = false;
+        $comment = new comment($args);
+        $newcomment = $comment->add('New comment 1');
+
+        // Triggering and capturing the event.
+        $sink = $this->redirectEvents();
+        $comment->delete($newcomment->id);
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Checking that the event contains the expected values.
+        $this->assertInstanceOf('\block_comments\event\comment_deleted', $event);
+        $this->assertEquals($context, $event->get_context());
+        $url = new moodle_url('/mod/wiki/view.php', array('id' => $this->wiki->cmid));
+        $this->assertEquals($url, $event->get_url());
+        $this->assertEventContextNotUsed($event);
+    }
+}
diff --git a/comments/tests/privacy_provider_test.php b/comments/tests/privacy_provider_test.php
new file mode 100644
index 0000000..9cc028b
--- /dev/null
+++ b/comments/tests/privacy_provider_test.php
@@ -0,0 +1,468 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy provider tests.
+ *
+ * @package    block_comments
+ * @copyright  2018 Shamim Rezaie <shamim@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+use core_privacy\local\metadata\collection;
+use block_comments\privacy\provider;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Class block_comments_privacy_provider_testcase.
+ *
+ * @copyright  2018 Shamim Rezaie <shamim@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_comments_privacy_provider_testcase extends \core_privacy\tests\provider_testcase {
+
+    /** @var stdClass A student who is only enrolled in course1. */
+    protected $student1;
+
+    /** @var stdClass A student who is only enrolled in course2. */
+    protected $student2;
+
+    /** @var stdClass A student who is enrolled in both course1 and course2. */
+    protected $student12;
+
+    /** @var stdClass A test course. */
+    protected $course1;
+
+    /** @var stdClass A test course. */
+    protected $course2;
+
+    protected function setUp() {
+        global $DB;
+
+        $this->resetAfterTest();
+        $this->setAdminUser();
+
+        // Create courses.
+        $generator = $this->getDataGenerator();
+        $this->course1 = $generator->create_course();
+        $this->course2 = $generator->create_course();
+
+        // Create and enrol students.
+        $this->student1 = $generator->create_user();
+        $this->student2 = $generator->create_user();
+        $this->student12 = $generator->create_user();
+
+        $studentrole = $DB->get_record('role', ['shortname' => 'student']);
+        $generator->enrol_user($this->student1->id,  $this->course1->id, $studentrole->id);
+        $generator->enrol_user($this->student2->id,  $this->course2->id, $studentrole->id);
+        $generator->enrol_user($this->student12->id,  $this->course1->id, $studentrole->id);
+        $generator->enrol_user($this->student12->id,  $this->course2->id, $studentrole->id);
+
+        // Comment block on course pages.
+        $block = $this->add_comments_block_in_context(context_course::instance($this->course1->id));
+        $block = $this->add_comments_block_in_context(context_course::instance($this->course2->id));
+    }
+
+    /**
+     * Posts a comment on a given context.
+     *
+     * @param string $text The comment's text.
+     * @param context $context The context on which we want to put the comment.
+     */
+    protected function add_comment($text, context $context) {
+        $args = new stdClass;
+        $args->context = $context;
+        $args->area = 'page_comments';
+        $args->itemid = 0;
+        $args->component = 'block_comments';
+        $args->linktext = get_string('showcomments');
+        $args->notoggle = true;
+        $args->autostart = true;
+        $args->displaycancel = false;
+        $comment = new comment($args);
+
+        $comment->add($text);
+    }
+
+    /**
+     * Creates a comments block on a context.
+     *
+     * @param context $context The context on which we want to put the block.
+     * @return block_base The created block instance.
+     * @throws coding_exception
+     */
+    protected function add_comments_block_in_context(context $context) {
+        global $DB;
+
+        $course = null;
+
+        $page = new \moodle_page();
+        $page->set_context($context);
+
+        switch ($context->contextlevel) {
+            case CONTEXT_SYSTEM:
+                $page->set_pagelayout('frontpage');
+                $page->set_pagetype('site-index');
+                break;
+            case CONTEXT_COURSE:
+                $page->set_pagelayout('standard');
+                $page->set_pagetype('course-view');
+                $course = $DB->get_record('course', ['id' => $context->instanceid]);
+                $page->set_course($course);
+                break;
+            case CONTEXT_MODULE:
+                $page->set_pagelayout('standard');
+                $mod = $DB->get_field_sql("SELECT m.name
+                                             FROM {modules} m
+                                             JOIN {course_modules} cm on cm.module = m.id
+                                            WHERE cm.id = ?", [$context->instanceid]);
+                $page->set_pagetype("mod-$mod-view");
+                break;
+            case CONTEXT_USER:
+                $page->set_pagelayout('mydashboard');
+                $page->set_pagetype('my-index');
+                break;
+            default:
+                throw new coding_exception('Unsupported context for test');
+        }
+
+        $page->blocks->load_blocks();
+
+        $page->blocks->add_block_at_end_of_default_region('comments');
+
+        // We need to use another page object as load_blocks() only loads the blocks once.
+        $page2 = new \moodle_page();
+        $page2->set_context($page->context);
+        $page2->set_pagelayout($page->pagelayout);
+        $page2->set_pagetype($page->pagetype);
+        if ($course) {
+            $page2->set_course($course);
+        }
+
+        $page->blocks->load_blocks();
+        $page2->blocks->load_blocks();
+        $blocks = $page2->blocks->get_blocks_for_region($page2->blocks->get_default_region());
+        $block = end($blocks);
+
+        $block = block_instance('comments', $block->instance);
+
+        return $block;
+    }
+
+    /**
+     * Test for provider::get_metadata().
+     */
+    public function test_get_metadata() {
+        $collection = new collection('block_comments');
+        $newcollection = provider::get_metadata($collection);
+        $itemcollection = $newcollection->get_collection();
+        $this->assertCount(1, $itemcollection);
+
+        $link = reset($itemcollection);
+
+        $this->assertEquals('core_comment', $link->get_name());
+        $this->assertEmpty($link->get_privacy_fields());
+        $this->assertEquals('privacy:metadata:core_comment', $link->get_summary());
+    }
+
+    /**
+     * Test for provider::get_contexts_for_userid() when user had not posted any comments..
+     */
+    public function test_get_contexts_for_userid_no_comment() {
+        $this->setUser($this->student1);
+        $coursecontext1 = context_course::instance($this->course1->id);
+        $this->add_comment('New comment', $coursecontext1);
+
+        $this->setUser($this->student2);
+        $contextlist = provider::get_contexts_for_userid($this->student2->id);
+        $this->assertCount(0, $contextlist);
+    }
+
+    /**
+     * Test for provider::get_contexts_for_userid().
+     */
+    public function test_get_contexts_for_userid() {
+        $coursecontext1 = context_course::instance($this->course1->id);
+        $coursecontext2 = context_course::instance($this->course2->id);
+
+        $this->setUser($this->student12);
+        $this->add_comment('New comment', $coursecontext1);
+        $this->add_comment('New comment', $coursecontext1);
+        $this->add_comment('New comment', $coursecontext2);
+
+        $contextlist = provider::get_contexts_for_userid($this->student12->id);
+        $this->assertCount(2, $contextlist);
+
+        $contextids = $contextlist->get_contextids();
+        $this->assertEquals([$coursecontext1->id, $coursecontext2->id], $contextids, '', 0.0, 10, true);
+    }
+
+    /**
+     * Test for provider::export_user_data() when the user has not posted any comments.
+     */
+    public function test_export_for_context_no_comment() {
+        $coursecontext1 = context_course::instance($this->course1->id);
+        $coursecontext2 = context_course::instance($this->course2->id);
+
+        $this->setUser($this->student1);
+        $this->add_comment('New comment', $coursecontext1);
+
+        $this->setUser($this->student2);
+
+        $this->setUser($this->student2);
+        $this->export_context_data_for_user($this->student2->id, $coursecontext2, 'block_comments');
+        $writer = \core_privacy\local\request\writer::with_context($coursecontext2);
+        $this->assertFalse($writer->has_any_data());
+
+    }
+
+    /**
+     * Test for provider::export_user_data().
+     */
+    public function test_export_for_context() {
+        $coursecontext1 = context_course::instance($this->course1->id);
+        $coursecontext2 = context_course::instance($this->course2->id);
+
+        $this->setUser($this->student12);
+        $this->add_comment('New comment', $coursecontext1);
+        $this->add_comment('New comment', $coursecontext1);
+        $this->add_comment('New comment', $coursecontext2);
+
+        // Export all of the data for the context.
+        $this->export_context_data_for_user($this->student12->id, $coursecontext1, 'block_comments');
+        $writer = \core_privacy\local\request\writer::with_context($coursecontext1);
+        $this->assertTrue($writer->has_any_data());
+    }
+
+    /**
+     * Test for provider::delete_data_for_all_users_in_context().
+     */
+    public function test_delete_data_for_all_users_in_context() {
+        global $DB;
+
+        $coursecontext1 = context_course::instance($this->course1->id);
+        $coursecontext2 = context_course::instance($this->course2->id);
+
+        $this->setUser($this->student1);
+        $this->add_comment('New comment', $coursecontext1);
+
+        $this->setUser($this->student2);
+        $this->add_comment('New comment', $coursecontext2);
+
+        $this->setUser($this->student12);
+        $this->add_comment('New comment', $coursecontext1);
+        $this->add_comment('New comment', $coursecontext1);
+        $this->add_comment('New comment', $coursecontext2);
+
+        // Before deletion, we should have 3 comments in $coursecontext1 and 2 comments in $coursecontext2.
+        $this->assertEquals(
+                3,
+                $DB->count_records('comments', ['component' => 'block_comments', 'contextid' => $coursecontext1->id])
+        );
+        $this->assertEquals(
+                2,
+                $DB->count_records('comments', ['component' => 'block_comments', 'contextid' => $coursecontext2->id])
+        );
+
+        // Delete data based on context.
+        provider::delete_data_for_all_users_in_context($coursecontext1);
+
+        // After deletion, the comments for $coursecontext1 should have been deleted.
+        $this->assertEquals(
+                0,
+                $DB->count_records('comments', ['component' => 'block_comments', 'contextid' => $coursecontext1->id])
+        );
+        $this->assertEquals(
+                2,
+                $DB->count_records('comments', ['component' => 'block_comments', 'contextid' => $coursecontext2->id])
+        );
+    }
+
+    /**
+     * Test for provider::delete_data_for_all_users_in_context() when there are also comments from other plugins.
+     */
+    public function test_delete_data_for_all_users_in_context_with_comments_from_other_plugins() {
+        global $DB;
+
+        $assigngenerator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
+        $instance = $assigngenerator->create_instance(['course' => $this->course1]);
+        $cm = get_coursemodule_from_instance('assign', $instance->id);
+        $assigncontext = \context_module::instance($cm->id);
+        $assign = new \assign($assigncontext, $cm, $this->course1);
+
+        // Add a comments block in the assignment page.
+        $this->add_comments_block_in_context($assigncontext);
+
+        $submission = $assign->get_user_submission($this->student1->id, true);
+
+        $options = new stdClass();
+        $options->area = 'submission_comments';
+        $options->course = $assign->get_course();
+        $options->context = $assigncontext;
+        $options->itemid = $submission->id;
+        $options->component = 'assignsubmission_comments';
+        $options->showcount = true;
+        $options->displaycancel = true;
+
+        $comment = new comment($options);
+        $comment->set_post_permission(true);
+
+        $this->setUser($this->student1);
+        $comment->add('Comment from student 1');
+
+        $this->add_comment('New comment', $assigncontext);
+
+        $this->setUser($this->student2);
+        $this->add_comment('New comment', $assigncontext);
+
+        // Before deletion, we should have 3 comments in $assigncontext.
+        // One comment is for the assignment submission and 2 are for the comments block.
+        $this->assertEquals(
+                3,
+                $DB->count_records('comments', ['contextid' => $assigncontext->id])
+        );
+        $this->assertEquals(
+                2,
+                $DB->count_records('comments', ['component' => 'block_comments', 'contextid' => $assigncontext->id])
+        );
+
+        provider::delete_data_for_all_users_in_context($assigncontext);
+
+        // After deletion, the comments for $assigncontext in the comment block should have been deleted,
+        // but the assignment submission comment should be left.
+        $this->assertEquals(
+                1,
+                $DB->count_records('comments', ['contextid' => $assigncontext->id])
+        );
+        $this->assertEquals(
+                0,
+                $DB->count_records('comments', ['component' => 'block_comments', 'contextid' => $assigncontext->id])
+        );
+    }
+
+    /**
+     * Test for provider::delete_data_for_user().
+     */
+    public function test_delete_data_for_user() {
+        global $DB;
+
+        $coursecontext1 = context_course::instance($this->course1->id);
+        $coursecontext2 = context_course::instance($this->course2->id);
+
+        $this->setUser($this->student1);
+        $this->add_comment('New comment', $coursecontext1);
+
+        $this->setUser($this->student2);
+        $this->add_comment('New comment', $coursecontext2);
+
+        $this->setUser($this->student12);
+        $this->add_comment('New comment', $coursecontext1);
+        $this->add_comment('New comment', $coursecontext1);
+        $this->add_comment('New comment', $coursecontext2);
+
+        // Before deletion, we should have 3 comments in $coursecontext1 and 2 comments in $coursecontext2,
+        // and 3 comments by student12 in $coursecontext1 and $coursecontext2 combined.
+        $this->assertEquals(
+                3,
+                $DB->count_records('comments', ['component' => 'block_comments', 'contextid' => $coursecontext1->id])
+        );
+        $this->assertEquals(
+                2,
+                $DB->count_records('comments', ['component' => 'block_comments', 'contextid' => $coursecontext2->id])
+        );
+        $this->assertEquals(
+                3,
+                $DB->count_records('comments', ['component' => 'block_comments', 'userid' => $this->student12->id])
+        );
+
+        $contextlist = new \core_privacy\local\request\approved_contextlist($this->student12, 'block_comments',
+                [$coursecontext1->id, $coursecontext2->id]);
+        provider::delete_data_for_user($contextlist);
+
+        // After deletion, the comments for the student12 should have been deleted.
+        $this->assertEquals(
+                1,
+                $DB->count_records('comments', ['component' => 'block_comments', 'contextid' => $coursecontext1->id])
+        );
+        $this->assertEquals(
+                1,
+                $DB->count_records('comments', ['component' => 'block_comments', 'contextid' => $coursecontext2->id])
+        );
+        $this->assertEquals(
+                0,
+                $DB->count_records('comments', ['component' => 'block_comments', 'userid' => $this->student12->id])
+        );
+    }
+
+    /**
+     * Test for provider::delete_data_for_user() when there are also comments from other plugins.
+     */
+    public function test_delete_data_for_user_with_comments_from_other_plugins() {
+        global $DB;
+
+        $assigngenerator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
+        $instance = $assigngenerator->create_instance(['course' => $this->course1]);
+        $cm = get_coursemodule_from_instance('assign', $instance->id);
+        $assigncontext = \context_module::instance($cm->id);
+        $assign = new \assign($assigncontext, $cm, $this->course1);
+
+        // Add a comments block in the assignment page.
+        $this->add_comments_block_in_context($assigncontext);
+
+        $submission = $assign->get_user_submission($this->student1->id, true);
+
+        $options = new stdClass();
+        $options->area = 'submission_comments';
+        $options->course = $assign->get_course();
+        $options->context = $assigncontext;
+        $options->itemid = $submission->id;
+        $options->component = 'assignsubmission_comments';
+        $options->showcount = true;
+        $options->displaycancel = true;
+
+        $comment = new comment($options);
+        $comment->set_post_permission(true);
+
+        $this->setUser($this->student1);
+        $comment->add('Comment from student 1');
+
+        $this->add_comment('New comment', $assigncontext);
+        $this->add_comment('New comment', $assigncontext);
+
+        // Before deletion, we should have 3 comments in $assigncontext.
+        // one comment is for the assignment submission and 2 are for the comments block.
+        $this->assertEquals(
+                3,
+                $DB->count_records('comments', ['contextid' => $assigncontext->id])
+        );
+
+        $contextlist = new \core_privacy\local\request\approved_contextlist($this->student1, 'block_comments',
+                [$assigncontext->id]);
+        provider::delete_data_for_user($contextlist);
+
+        // After deletion, the comments for the student1 in the comment block should have been deleted,
+        // but the assignment submission comment should be left.
+        $this->assertEquals(
+                1,
+                $DB->count_records('comments', ['contextid' => $assigncontext->id])
+        );
+        $this->assertEquals(
+                0,
+                $DB->count_records('comments', ['component' => 'block_comments', 'userid' => $this->student1->id])
+        );
+    }
+}
diff --git a/comments/version.php b/comments/version.php
new file mode 100644
index 0000000..9982f0e
--- /dev/null
+++ b/comments/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_comments
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_comments'; // Full name of the plugin (used for diagnostics)
diff --git a/community/block_community.php b/community/block_community.php
new file mode 100644
index 0000000..fc345ca
--- /dev/null
+++ b/community/block_community.php
@@ -0,0 +1,104 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * @package block_community
+ * @author     Jerome Mouneyrac <jerome@mouneyrac.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL
+ * @copyright  (C) 1999 onwards Martin Dougiamas  http://dougiamas.com
+ *
+ * The community block
+ */
+
+class block_community extends block_list {
+
+    function init() {
+        $this->title = get_string('pluginname', 'block_community');
+    }
+
+    function user_can_addto($page) {
+        // Don't allow people to add the block if they can't even use it
+        if (!has_capability('moodle/community:add', $page->context)) {
+            return false;
+        }
+
+        return parent::user_can_addto($page);
+    }
+
+    function user_can_edit() {
+        // Don't allow people to edit the block if they can't even use it
+        if (!has_capability('moodle/community:add',
+                        context::instance_by_id($this->instance->parentcontextid))) {
+            return false;
+        }
+        return parent::user_can_edit();
+    }
+
+    function get_content() {
+        global $CFG, $OUTPUT, $USER;
+
+        $coursecontext = context::instance_by_id($this->instance->parentcontextid);
+
+        if (!has_capability('moodle/community:add', $coursecontext)
+                or $this->content !== NULL) {
+            return $this->content;
+        }
+
+        $this->content = new stdClass();
+        $this->content->items = array();
+        $this->content->icons = array();
+        $this->content->footer = '';
+
+        if (!isloggedin()) {
+            return $this->content;
+        }
+
+        $icon = $OUTPUT->pix_icon('i/group', get_string('group'));
+        $addcourseurl = new moodle_url('/blocks/community/communitycourse.php',
+                        array('add' => true, 'courseid' => $this->page->course->id));
+        $searchlink = html_writer::tag('a', $icon . get_string('addcourse', 'block_community'),
+                        array('href' => $addcourseurl->out(false)));
+        $this->content->items[] = $searchlink;
+
+        require_once($CFG->dirroot . '/blocks/community/locallib.php');
+        $communitymanager = new block_community_manager();
+        $courses = $communitymanager->block_community_get_courses($USER->id);
+        if ($courses) {
+            $this->content->items[] = html_writer::empty_tag('hr');
+            $this->content->icons[] = '';
+            $this->content->items[] = get_string('mycommunities', 'block_community');
+            $this->content->icons[] = '';
+            foreach ($courses as $course) {
+                //delete link
+                $deleteicon = $OUTPUT->pix_icon('t/delete', get_string('removecommunitycourse', 'block_community'));
+                $deleteurl = new moodle_url('/blocks/community/communitycourse.php',
+                                array('remove' => true,
+                                    'courseid' => $this->page->course->id,
+                                    'communityid' => $course->id, 'sesskey' => sesskey()));
+                $deleteatag = html_writer::tag('a', $deleteicon, array('href' => $deleteurl));
+
+                $courselink = html_writer::tag('a', $course->coursename,
+                                array('href' => $course->courseurl));
+                $this->content->items[] = $courselink . ' ' . $deleteatag;
+                $this->content->icons[] = '';
+            }
+        }
+
+        return $this->content;
+    }
+
+}
+
diff --git a/community/classes/privacy/provider.php b/community/classes/privacy/provider.php
new file mode 100644
index 0000000..5699066
--- /dev/null
+++ b/community/classes/privacy/provider.php
@@ -0,0 +1,181 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_community.
+ *
+ * @package    block_community
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_community\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+use \core_privacy\local\request\approved_contextlist;
+use \core_privacy\local\request\contextlist;
+use \core_privacy\local\request\writer;
+use \core_privacy\local\request\deletion_criteria;
+use \core_privacy\local\metadata\collection;
+
+/**
+ * Privacy Subsystem implementation for block_community.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\provider, \core_privacy\local\request\plugin\provider {
+
+    /**
+     * Returns information about how block_community stores its data.
+     *
+     * @param   collection     $collection The initialised collection to add items to.
+     * @return  collection     A listing of user data stored through this system.
+     */
+    public static function get_metadata(collection $collection) : collection {
+        $collection->add_database_table(
+            'block_community',
+            [
+                'coursename' => 'privacy:metadata:block_community:coursename',
+                'coursedescription' => 'privacy:metadata:block_community:coursedescription',
+                'courseurl' => 'privacy:metadata:block_community:courseurl',
+                'imageurl' => 'privacy:metadata:block_community:imageurl',
+                'userid' => 'privacy:metadata:block_community:userid',
+            ],
+            'privacy:metadata:block_community'
+        );
+
+        return $collection;
+    }
+
+    /**
+     * Get the list of contexts that contain user information for the specified user.
+     *
+     * @param   int         $userid     The user to search.
+     * @return  contextlist   $contextlist  The contextlist containing the list of contexts used in this plugin.
+     */
+    public static function get_contexts_for_userid(int $userid) : contextlist {
+        $contextlist = new \core_privacy\local\request\contextlist();
+
+        // The block_community data is associated at the user context level, so retrieve the user's context id.
+        $sql = "SELECT c.id
+                  FROM {block_community} bc
+                  JOIN {context} c ON c.instanceid = bc.userid AND c.contextlevel = :contextuser
+                 WHERE bc.userid = :userid
+              GROUP BY c.id";
+
+        $params = [
+            'contextuser'   => CONTEXT_USER,
+            'userid'        => $userid
+        ];
+
+        $contextlist->add_from_sql($sql, $params);
+
+        return $contextlist;
+    }
+
+    /**
+     * Export all user data for the specified user using the User context level.
+     *
+     * @param   approved_contextlist    $contextlist    The approved contexts to export information for.
+     */
+    public static function export_user_data(approved_contextlist $contextlist) {
+        global $DB;
+
+        // If the user has block_community data, then only the User context should be present so get the first context.
+        $contexts = $contextlist->get_contexts();
+        if (count($contexts) == 0) {
+            return;
+        }
+        $context = reset($contexts);
+
+        // Sanity check that context is at the User context level, then get the userid.
+        if ($context->contextlevel !== CONTEXT_USER) {
+            return;
+        }
+        $userid = $context->instanceid;
+
+        // The block_community data export is organised in: {User Context}/Community Finder/My communities/data.json.
+        $subcontext = [
+            get_string('pluginname', 'block_community'),
+            get_string('mycommunities', 'block_community')
+        ];
+
+        $sql = "SELECT bc.id as id,
+                       bc.coursename as name,
+                       bc.coursedescription as description,
+                       bc.courseurl as url,
+                       bc.imageurl as imageurl
+                  FROM {block_community} bc
+                 WHERE bc.userid = :userid
+              ORDER BY bc.coursename";
+
+        $params = [
+            'userid' => $userid
+        ];
+
+        $communities = $DB->get_records_sql($sql, $params);
+
+        $data = (object) [
+            'communities' => $communities
+        ];
+
+        writer::with_context($context)->export_data($subcontext, $data);
+    }
+
+    /**
+     * Delete all data for all users in the specified context.
+     *
+     * @param   context $context   The specific context to delete data for.
+     */
+    public static function delete_data_for_all_users_in_context(\context $context) {
+        global $DB;
+
+        // Sanity check that context is at the User context level, then get the userid.
+        if ($context->contextlevel !== CONTEXT_USER) {
+            return;
+        }
+        $userid = $context->instanceid;
+
+        $DB->delete_records('block_community', ['userid' => $userid]);
+    }
+
+    /**
+     * Delete all user data for the specified user.
+     *
+     * @param   approved_contextlist $contextlist  The approved contexts and user information to delete information for.
+     */
+    public static function delete_data_for_user(approved_contextlist $contextlist) {
+        global $DB;
+
+        // If the user has block_community data, then only the User context should be present so get the first context.
+        $contexts = $contextlist->get_contexts();
+        if (count($contexts) == 0) {
+            return;
+        }
+        $context = reset($contexts);
+
+        // Sanity check that context is at the User context level, then get the userid.
+        if ($context->contextlevel !== CONTEXT_USER) {
+            return;
+        }
+        $userid = $context->instanceid;
+
+        $DB->delete_records('block_community', ['userid' => $userid]);
+    }
+
+}
diff --git a/community/communitycourse.php b/community/communitycourse.php
new file mode 100644
index 0000000..67f024b
--- /dev/null
+++ b/community/communitycourse.php
@@ -0,0 +1,208 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Controller for various actions of the block.
+ *
+ * This page display the community course search form.
+ * It also handles adding a course to the community block.
+ * It also handles downloading a course template.
+ *
+ * @package    block_community
+ * @author     Jerome Mouneyrac <jerome@mouneyrac.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL
+ * @copyright  (C) 1999 onwards Martin Dougiamas  http://dougiamas.com
+ */
+
+require('../../config.php');
+require_once($CFG->dirroot . '/blocks/community/locallib.php');
+require_once($CFG->dirroot . '/blocks/community/forms.php');
+
+require_login();
+$courseid = required_param('courseid', PARAM_INT); //if no courseid is given
+$parentcourse = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
+
+$context = context_course::instance($courseid);
+$PAGE->set_course($parentcourse);
+$PAGE->set_url('/blocks/community/communitycourse.php');
+$PAGE->set_heading($SITE->fullname);
+$PAGE->set_pagelayout('incourse');
+$PAGE->set_title(get_string('searchcourse', 'block_community'));
+$PAGE->navbar->add(get_string('searchcourse', 'block_community'));
+
+$search = optional_param('search', null, PARAM_TEXT);
+
+//if no capability to search course, display an error message
+require_capability('moodle/community:add', $context);
+$usercandownload = has_capability('moodle/community:download', $context);
+
+$communitymanager = new block_community_manager();
+$renderer = $PAGE->get_renderer('block_community');
+
+/// Check if the page has been called with trust argument
+$add = optional_param('add', -1, PARAM_INT);
+$confirm = optional_param('confirmed', false, PARAM_INT);
+if ($add != -1 and $confirm and confirm_sesskey()) {
+    $course = new stdClass();
+    $course->name = optional_param('coursefullname', '', PARAM_TEXT);
+    $course->description = optional_param('coursedescription', '', PARAM_TEXT);
+    $course->url = optional_param('courseurl', '', PARAM_URL);
+    $course->imageurl = optional_param('courseimageurl', '', PARAM_URL);
+    $communitymanager->block_community_add_course($course, $USER->id);
+    echo $OUTPUT->header();
+    echo $renderer->save_link_success(
+            new moodle_url('/course/view.php', array('id' => $courseid)));
+    echo $OUTPUT->footer();
+    die();
+}
+
+/// Delete temp file when cancel restore
+$cancelrestore = optional_param('cancelrestore', false, PARAM_INT);
+if ($usercandownload and $cancelrestore and confirm_sesskey()) {
+    $filename = optional_param('filename', '', PARAM_ALPHANUMEXT);
+    //delete temp file
+    $backuptempdir = make_backup_temp_directory('');
+    unlink($backuptempdir . '/' . $filename . ".mbz");
+}
+
+/// Download
+$download = optional_param('download', -1, PARAM_INT);
+$downloadcourseid = optional_param('downloadcourseid', '', PARAM_INT);
+$coursefullname = optional_param('coursefullname', '', PARAM_ALPHANUMEXT);
+$backupsize = optional_param('backupsize', 0, PARAM_INT);
+if ($usercandownload and $download != -1 and !empty($downloadcourseid) and confirm_sesskey()) {
+    //OUTPUT: display restore choice page
+    echo $OUTPUT->header();
+    echo $OUTPUT->heading(get_string('downloadingcourse', 'block_community'), 3, 'main');
+    $sizeinfo = new stdClass();
+    $sizeinfo->total = number_format($backupsize / 1000000, 2);
+    echo html_writer::tag('div', get_string('downloadingsize', 'block_community', $sizeinfo),
+            array('class' => 'textinfo'));
+    if (ob_get_level()) {
+        ob_flush();
+    }
+    flush();
+    list($privatefilename, $tmpfilename) = \core\hub\publication::download_course_backup($downloadcourseid, $coursefullname);
+    echo html_writer::tag('div', get_string('downloaded', 'block_community'),
+            array('class' => 'textinfo'));
+    echo $OUTPUT->notification(get_string('downloadconfirmed', 'block_community',
+                    $privatefilename), 'notifysuccess');
+    echo $renderer->restore_confirmation_box($tmpfilename, $context);
+    echo $OUTPUT->footer();
+    die();
+}
+
+/// Remove community
+$remove = optional_param('remove', '', PARAM_INT);
+$communityid = optional_param('communityid', '', PARAM_INT);
+if ($remove != -1 and !empty($communityid) and confirm_sesskey()) {
+    $communitymanager->block_community_remove_course($communityid, $USER->id);
+    echo $OUTPUT->header();
+    echo $renderer->remove_success(new moodle_url('/course/view.php', array('id' => $courseid)));
+    echo $OUTPUT->footer();
+    die();
+}
+
+//Get form default/current values
+$fromformdata['coverage'] = optional_param('coverage', 'all', PARAM_TEXT);
+$fromformdata['licence'] = optional_param('licence', 'all', PARAM_ALPHANUMEXT);
+$fromformdata['subject'] = optional_param('subject', 'all', PARAM_ALPHANUMEXT);
+$fromformdata['audience'] = optional_param('audience', 'all', PARAM_ALPHANUMEXT);
+$fromformdata['language'] = optional_param('language', current_language(), PARAM_ALPHANUMEXT);
+$fromformdata['educationallevel'] = optional_param('educationallevel', 'all', PARAM_ALPHANUMEXT);
+$fromformdata['downloadable'] = optional_param('downloadable', $usercandownload, PARAM_ALPHANUM);
+$fromformdata['orderby'] = optional_param('orderby', 'newest', PARAM_ALPHA);
+$fromformdata['search'] = $search;
+$fromformdata['courseid'] = $courseid;
+$hubselectorform = new community_hub_search_form('', $fromformdata);
+$hubselectorform->set_data($fromformdata);
+
+//Retrieve courses by web service
+$courses = null;
+if (optional_param('executesearch', 0, PARAM_INT) and confirm_sesskey()) {
+    $downloadable = optional_param('downloadable', false, PARAM_INT);
+
+    $options = new stdClass();
+    if (!empty($fromformdata['coverage'])) {
+        $options->coverage = $fromformdata['coverage'];
+    }
+    if ($fromformdata['licence'] != 'all') {
+        $options->licenceshortname = $fromformdata['licence'];
+    }
+    if ($fromformdata['subject'] != 'all') {
+        $options->subject = $fromformdata['subject'];
+    }
+    if ($fromformdata['audience'] != 'all') {
+        $options->audience = $fromformdata['audience'];
+    }
+    if ($fromformdata['educationallevel'] != 'all') {
+        $options->educationallevel = $fromformdata['educationallevel'];
+    }
+    if ($fromformdata['language'] != 'all') {
+        $options->language = $fromformdata['language'];
+    }
+
+    $options->orderby = $fromformdata['orderby'];
+
+    //the range of course requested
+    $options->givememore = optional_param('givememore', 0, PARAM_INT);
+
+    list($courses, $coursetotal) = \core\hub\publication::search($search, $downloadable, $options);
+}
+
+// OUTPUT
+echo $OUTPUT->header();
+echo $OUTPUT->heading(get_string('searchcommunitycourse', 'block_community'), 3, 'main');
+echo $renderer->moodlenet_info();
+
+$hubselectorform->display();
+if (!empty($errormessage)) {
+    echo $errormessage;
+}
+
+//load javascript
+$commentedcourseids = array(); //result courses with comments only
+$courseids = array(); //all result courses
+$courseimagenumbers = array(); //number of screenshots of all courses (must be exact same order than $courseids)
+if (!empty($courses)) {
+    foreach ($courses as $course) {
+        if (!empty($course['comments'])) {
+            $commentedcourseids[] = $course['id'];
+        }
+        $courseids[] = $course['id'];
+        $courseimagenumbers[] = $course['screenshots'];
+    }
+}
+$PAGE->requires->yui_module('moodle-block_community-comments', 'M.blocks_community.init_comments',
+        array(array('commentids' => $commentedcourseids, 'closeButtonTitle' => get_string('close', 'editor'))));
+$PAGE->requires->yui_module('moodle-block_community-imagegallery', 'M.blocks_community.init_imagegallery',
+        array(array('imageids' => $courseids, 'imagenumbers' => $courseimagenumbers,
+                'huburl' => HUB_MOODLEORGHUBURL, 'closeButtonTitle' => get_string('close', 'editor'))));
+
+echo highlight($search, $renderer->course_list($courses, null, $courseid));
+
+//display givememore/Next link if more course can be displayed
+if (!empty($courses)) {
+    if (($options->givememore + count($courses)) < $coursetotal) {
+        $fromformdata['givememore'] = count($courses) + $options->givememore;
+        $fromformdata['executesearch'] = true;
+        $fromformdata['sesskey'] = sesskey();
+        echo $renderer->next_button($fromformdata);
+    }
+}
+
+echo $OUTPUT->footer();
diff --git a/community/db/access.php b/community/db/access.php
new file mode 100644
index 0000000..1ec36ed
--- /dev/null
+++ b/community/db/access.php
@@ -0,0 +1,51 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Community block caps.
+ *
+ * @package    block_community
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/community:myaddinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/my:manageblocks'
+    ),
+
+    'block/community:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/community/db/install.xml b/community/db/install.xml
new file mode 100644
index 0000000..58705d7
--- /dev/null
+++ b/community/db/install.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<XMLDB PATH="blocks/community/db" VERSION="20120122" COMMENT="XMLDB file for Moodle blocks/community"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
+>
+  <TABLES>
+    <TABLE NAME="block_community" COMMENT="Community block">
+      <FIELDS>
+        <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
+        <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
+        <FIELD NAME="coursename" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
+        <FIELD NAME="coursedescription" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false"/>
+        <FIELD NAME="courseurl" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
+        <FIELD NAME="imageurl" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
+      </FIELDS>
+      <KEYS>
+        <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
+      </KEYS>
+    </TABLE>
+  </TABLES>
+</XMLDB>
\ No newline at end of file
diff --git a/community/db/upgrade.php b/community/db/upgrade.php
new file mode 100644
index 0000000..d01face
--- /dev/null
+++ b/community/db/upgrade.php
@@ -0,0 +1,59 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file keeps track of upgrades to the community block
+ *
+ * Sometimes, changes between versions involve alterations to database structures
+ * and other major things that may break installations.
+ *
+ * The upgrade function in this file will attempt to perform all the necessary
+ * actions to upgrade your older installation to the current version.
+ *
+ * If there's something it cannot do itself, it will tell you what you need to do.
+ *
+ * The commands in here will all be database-neutral, using the methods of
+ * database_manager class
+ *
+ * Please do not forget to use upgrade_set_timeout()
+ * before any action that may take longer time to finish.
+ *
+ * @since Moodle 2.0
+ * @package block_community
+ * @copyright 2010 Jerome Mouneyrac
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ *
+ * @param int $oldversion
+ */
+function xmldb_block_community_upgrade($oldversion) {
+    global $CFG;
+
+    // Automatically generated Moodle v3.2.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.3.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.4.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    return true;
+}
diff --git a/community/forms.php b/community/forms.php
new file mode 100644
index 0000000..8142b5c
--- /dev/null
+++ b/community/forms.php
@@ -0,0 +1,173 @@
+<?php
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// This file is part of Moodle - http://moodle.org/                      //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//                                                                       //
+// Moodle is free software: you can redistribute it and/or modify        //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation, either version 3 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// Moodle is distributed in the hope that it will be useful,             //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details.                          //
+//                                                                       //
+// You should have received a copy of the GNU General Public License     //
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.       //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+/**
+ * Form for community search
+ *
+ * @package    block_community
+ * @author     Jerome Mouneyrac <jerome@mouneyrac.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL
+ * @copyright  (C) 1999 onwards Martin Dougiamas  http://dougiamas.com
+ */
+
+require_once($CFG->libdir . '/formslib.php');
+
+class community_hub_search_form extends moodleform {
+
+    public function definition() {
+        global $CFG;
+        $mform = & $this->_form;
+
+        //set default value
+        $search = $this->_customdata['search'];
+        if (isset($this->_customdata['coverage'])) {
+            $coverage = $this->_customdata['coverage'];
+        } else {
+            $coverage = 'all';
+        }
+        if (isset($this->_customdata['licence'])) {
+            $licence = $this->_customdata['licence'];
+        } else {
+            $licence = 'all';
+        }
+        if (isset($this->_customdata['subject'])) {
+            $subject = $this->_customdata['subject'];
+        } else {
+            $subject = 'all';
+        }
+        if (isset($this->_customdata['audience'])) {
+            $audience = $this->_customdata['audience'];
+        } else {
+            $audience = 'all';
+        }
+        if (isset($this->_customdata['language'])) {
+            $language = $this->_customdata['language'];
+        } else {
+            $language = current_language();
+        }
+        if (isset($this->_customdata['educationallevel'])) {
+            $educationallevel = $this->_customdata['educationallevel'];
+        } else {
+            $educationallevel = 'all';
+        }
+        if (isset($this->_customdata['downloadable'])) {
+            $downloadable = $this->_customdata['downloadable'];
+        } else {
+            $downloadable = 1;
+        }
+        if (isset($this->_customdata['orderby'])) {
+            $orderby = $this->_customdata['orderby'];
+        } else {
+            $orderby = 'newest';
+        }
+
+        $mform->addElement('header', 'site', get_string('search', 'block_community'));
+
+        //add the course id (of the context)
+        $mform->addElement('hidden', 'courseid', $this->_customdata['courseid']);
+        $mform->setType('courseid', PARAM_INT);
+        $mform->addElement('hidden', 'executesearch', 1);
+        $mform->setType('executesearch', PARAM_INT);
+
+        // Display enrol/download select box if the USER has the download capability on the course.
+        if (has_capability('moodle/community:download',
+                        context_course::instance($this->_customdata['courseid']))) {
+            $options = array(0 => get_string('enrollable', 'block_community'),
+                1 => get_string('downloadable', 'block_community'));
+            $mform->addElement('select', 'downloadable', get_string('enroldownload', 'block_community'),
+                    $options);
+            $mform->addHelpButton('downloadable', 'enroldownload', 'block_community');
+
+            $mform->setDefault('downloadable', $downloadable);
+        } else {
+            $mform->addElement('hidden', 'downloadable', 0);
+        }
+        $mform->setType('downloadable', PARAM_INT);
+
+        $options = \core\hub\publication::audience_options(true);
+        $mform->addElement('select', 'audience', get_string('audience', 'block_community'), $options);
+        $mform->setDefault('audience', $audience);
+        unset($options);
+        $mform->addHelpButton('audience', 'audience', 'block_community');
+
+        $options = \core\hub\publication::educational_level_options(true);
+        $mform->addElement('select', 'educationallevel',
+                get_string('educationallevel', 'block_community'), $options);
+        $mform->setDefault('educationallevel', $educationallevel);
+        unset($options);
+        $mform->addHelpButton('educationallevel', 'educationallevel', 'block_community');
+
+        $options = \core\hub\publication::get_sorted_subjects();
+        $mform->addElement('searchableselector', 'subject', get_string('subject', 'block_community'),
+                $options, array('id' => 'communitysubject'));
+        $mform->setDefault('subject', $subject);
+        unset($options);
+        $mform->addHelpButton('subject', 'subject', 'block_community');
+
+        require_once($CFG->libdir . "/licenselib.php");
+        $licensemanager = new license_manager();
+        $licences = $licensemanager->get_licenses();
+        $options = array();
+        $options['all'] = get_string('any');
+        foreach ($licences as $license) {
+            $options[$license->shortname] = get_string($license->shortname, 'license');
+        }
+        $mform->addElement('select', 'licence', get_string('licence', 'block_community'), $options);
+        unset($options);
+        $mform->addHelpButton('licence', 'licence', 'block_community');
+        $mform->setDefault('licence', $licence);
+
+        $languages = get_string_manager()->get_list_of_languages();
+        core_collator::asort($languages);
+        $languages = array_merge(array('all' => get_string('any')), $languages);
+        $mform->addElement('select', 'language', get_string('language'), $languages);
+
+        $mform->setDefault('language', $language);
+        $mform->addHelpButton('language', 'language', 'block_community');
+
+        $mform->addElement('select', 'orderby', get_string('orderby', 'block_community'),
+            array('newest' => get_string('orderbynewest', 'block_community'),
+                'eldest' => get_string('orderbyeldest', 'block_community'),
+                'fullname' => get_string('orderbyname', 'block_community'),
+                'publisher' => get_string('orderbypublisher', 'block_community'),
+                'ratingaverage' => get_string('orderbyratingaverage', 'block_community')));
+
+        $mform->setDefault('orderby', $orderby);
+        $mform->addHelpButton('orderby', 'orderby', 'block_community');
+        $mform->setType('orderby', PARAM_ALPHA);
+
+        $mform->setAdvanced('audience');
+        $mform->setAdvanced('educationallevel');
+        $mform->setAdvanced('subject');
+        $mform->setAdvanced('licence');
+        $mform->setAdvanced('language');
+        $mform->setAdvanced('orderby');
+
+        $mform->addElement('text', 'search', get_string('keywords', 'block_community'),
+            array('size' => 30));
+        $mform->addHelpButton('search', 'keywords', 'block_community');
+        $mform->setType('search', PARAM_NOTAGS);
+
+        $mform->addElement('submit', 'submitbutton', get_string('search', 'block_community'));
+
+    }
+
+}
diff --git a/community/lang/en/block_community.php b/community/lang/en/block_community.php
new file mode 100644
index 0000000..73e65d4
--- /dev/null
+++ b/community/lang/en/block_community.php
@@ -0,0 +1,121 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_community', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_community
+ * @author    Jerome Mouneyrac <jerome@mouneyrac.com>
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['activities'] = 'Activities';
+$string['add'] = 'Add';
+$string['addedtoblock'] = 'A link to this course has been added in your community finder block';
+$string['addtocommunityblock'] = 'Save a link to this course';
+$string['addcommunitycourse'] = 'Add community course';
+$string['additionalcoursedesc'] = '{$a->lang} Creator: {$a->creatorname} - Publisher: {$a->publishername} - Subject: {$a->subject}
+    - Audience: {$a->audience} - Educational level: {$a->educationallevel} - License: {$a->license}';
+$string['addcourse'] = 'Search';
+$string['audience'] = 'Designed for';
+$string['audience_help'] = 'What kind of course are you looking for?  As well as traditional courses intended for students, you might search for communities of Educators or Moodle Administrators';
+$string['blocks'] = 'Blocks';
+$string['cannotselecttopsubject'] = 'Cannot select a top subject level';
+$string['comments'] = 'Comments ({$a})';
+$string['community:addinstance'] = 'Add a new community finder block';
+$string['community:myaddinstance'] = 'Add a new community finder block to Dashboard';
+$string['contentinfo'] = 'Subject: {$a->subject} - Audience: {$a->audience} - Educational level: {$a->educationallevel}';
+$string['continue'] = 'Continue';
+$string['contributors'] = ' - Contributors: {$a}';
+$string['coursedesc'] = 'Description';
+$string['courselang'] = 'Language';
+$string['coursename'] = 'Name';
+$string['courses'] = 'Courses';
+$string['coverage'] = 'Tags: {$a}';
+$string['donotrestore'] = 'No';
+$string['dorestore'] = 'Yes';
+$string['download'] = 'Download';
+$string['downloadable'] = 'courses I can download';
+$string['downloadablecourses'] = 'Downloadable courses';
+$string['downloadconfirmed'] = 'The backup has been saved in your private files {$a}';
+$string['downloaded'] = '...finished.';
+$string['downloadingcourse'] = 'Downloading course';
+$string['downloadingsize'] = 'Please wait the course file is downloading ({$a->total}Mb)...';
+$string['downloadtemplate'] = 'Create course from template';
+$string['educationallevel'] = 'Educational level';
+$string['educationallevel_help'] = 'What educational level are you searching for?  In the case of communities of educators, this level describes the level they are teaching.';
+$string['enroldownload'] = 'Find';
+$string['enroldownload_help'] = 'Some courses listed in the selected hub are being advertised so that people can come and participate in them on the original site.
+
+Others are course templates provided for you to download and use on your own Moodle site.';
+$string['enrollable'] = 'courses I can enrol in';
+$string['enrollablecourses'] = 'Enrollable courses';
+$string['errorcourselisting'] = 'An error occurred when retrieving the course listing from the selected hub, please try again later. ({$a})';
+$string['errorhublisting'] = 'An error occurred when retrieving the hub listing from Moodle.org, please try again later. ({$a})';
+$string['fileinfo'] = 'Language: {$a->lang} - License: {$a->license} -  Time updated: {$a->timeupdated}';
+$string['hideall'] = 'Hide hubs';
+$string['hub'] = 'hub';
+$string['hubnottrusted'] = 'Not trusted';
+$string['hubtrusted'] = 'This hub is trusted by Moodle.org';
+$string['install'] = 'Install';
+$string['keywords'] = 'Keywords';
+$string['keywords_help'] = 'You can search for courses containing specific text in the name, description and other fields of the database.';
+$string['langdesc'] = 'Language: {$a} - ';
+$string['language'] = 'Language';
+$string['language_help'] = 'You can search for courses written in a specific language.';
+$string['licence'] = 'License';
+$string['licence_help'] = 'You can search for courses that are licensed in a particular way.';
+$string['moredetails'] = 'More details';
+$string['mycommunities'] = 'My communities:';
+$string['next'] = 'Next >>>';
+$string['nocomments'] = 'No comments';
+$string['nocourse'] = 'No courses found';
+$string['noratings'] = 'No ratings';
+$string['operation'] = 'Operation';
+$string['orderby'] = 'Sort by';
+$string['orderby_help'] = 'The order the search results are displayed.';
+$string['orderbynewest'] = 'Newest';
+$string['orderbyeldest'] = 'Oldest';
+$string['orderbyname'] = 'Name';
+$string['orderbypublisher'] = 'Publisher';
+$string['orderbyratingaverage'] = 'Rating';
+$string['outcomes'] = 'Outcomes: {$a}';
+$string['pluginname'] = 'Community finder';
+$string['privacy:metadata:block_community'] = 'The Community block stores links to shared community courses users can enrol in.';
+$string['privacy:metadata:block_community:coursename'] = 'The name of the linked community course.';
+$string['privacy:metadata:block_community:coursedescription'] = 'The description of the linked community course.';
+$string['privacy:metadata:block_community:courseurl'] = 'The course URL of the linked community course.';
+$string['privacy:metadata:block_community:imageurl'] = 'The image URL of the linked community course.';
+$string['privacy:metadata:block_community:userid'] = 'The ID of the user who created the linked community course.';
+$string['rateandcomment'] = 'Rate and comment';
+$string['rating'] = 'Rating';
+$string['removecommunitycourse'] = 'Remove community course';
+$string['restorecourse'] = 'Restore course';
+$string['restorecourseinfo'] = 'Restore the course?';
+$string['screenshots'] = 'Screenshots';
+$string['search'] = 'Search';
+$string['searchcommunitycourse'] = 'Search for community course';
+$string['searchcourse'] = 'Search for community course';
+$string['selecthub'] = 'Select hub';
+$string['selecthub_help'] = 'Select hub where to search the courses.';
+$string['sites'] = 'Sites';
+$string['showall'] = 'Show all hubs';
+$string['subject'] = 'Subject';
+$string['subject_help'] = 'To narrow your search to courses about a particular subject, choose one from this list.';
+$string['userinfo'] = 'Creator: {$a->creatorname} - Publisher: {$a->publishername}';
+$string['visitdemo'] = 'Visit demo';
+$string['visitsite'] = 'Visit site';
diff --git a/community/locallib.php b/community/locallib.php
new file mode 100644
index 0000000..d975078
--- /dev/null
+++ b/community/locallib.php
@@ -0,0 +1,88 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Community library
+ *
+ * @package    block_community
+ * @author     Jerome Mouneyrac <jerome@mouneyrac.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL
+ * @copyright  (C) 1999 onwards Martin Dougiamas  http://dougiamas.com
+ *
+ *
+ */
+
+class block_community_manager {
+
+    /**
+     * Add a community course
+     * @param object $course
+     * @param integer $userid
+     * @return id of course or false if already added
+     */
+    public function block_community_add_course($course, $userid) {
+        global $DB;
+
+        $community = $this->block_community_get_course($course->url, $userid);
+
+        if (empty($community)) {
+            $community = new stdClass();
+            $community->userid = $userid;
+            $community->coursename = $course->name;
+            $community->coursedescription = $course->description;
+            $community->courseurl = $course->url;
+            $community->imageurl = $course->imageurl;
+            return $DB->insert_record('block_community', $community);
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Return all community courses of a user
+     * @param integer $userid
+     * @return array of course
+     */
+    public function block_community_get_courses($userid) {
+        global $DB;
+        return $DB->get_records('block_community', array('userid' => $userid), 'coursename');
+    }
+
+    /**
+     * Return a community courses of a user
+     * @param integer $userid
+     * @param integer $userid
+     * @return array of course
+     */
+    public function block_community_get_course($courseurl, $userid) {
+        global $DB;
+        return $DB->get_record('block_community',
+                array('courseurl' => $courseurl, 'userid' => $userid));
+    }
+
+    /**
+     * Delete a community course
+     * @param integer $communityid
+     * @param integer $userid
+     * @return bool true
+     */
+    public function block_community_remove_course($communityid, $userid) {
+        global $DB, $USER;
+        return $DB->delete_records('block_community',
+                array('userid' => $userid, 'id' => $communityid));
+    }
+
+}
diff --git a/community/renderer.php b/community/renderer.php
new file mode 100644
index 0000000..f415204
--- /dev/null
+++ b/community/renderer.php
@@ -0,0 +1,400 @@
+<?php
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// This file is part of Moodle - http://moodle.org/                      //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//                                                                       //
+// Moodle is free software: you can redistribute it and/or modify        //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation, either version 3 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// Moodle is distributed in the hope that it will be useful,             //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details.                          //
+//                                                                       //
+// You should have received a copy of the GNU General Public License     //
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.       //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+/**
+ * Block community renderer.
+ * @package   block_community
+ * @copyright 2010 Moodle Pty Ltd (http://moodle.com)
+ * @author    Jerome Mouneyrac
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_community_renderer extends plugin_renderer_base {
+
+    public function restore_confirmation_box($filename, $context) {
+        $restoreurl = new moodle_url('/backup/restore.php',
+                        array('filename' => $filename . ".mbz", 'contextid' => $context->id));
+        $searchurl = new moodle_url('/blocks/community/communitycourse.php',
+                        array('add' => 1, 'courseid' => $context->instanceid,
+                            'cancelrestore' => 1, 'sesskey' => sesskey(),
+                            'filename' => $filename));
+        $formrestore = new single_button($restoreurl,
+                        get_string('dorestore', 'block_community'));
+        $formsearch = new single_button($searchurl,
+                        get_string('donotrestore', 'block_community'));
+        return $this->output->confirm(get_string('restorecourseinfo', 'block_community'),
+                $formrestore, $formsearch);
+    }
+
+    /**
+     * Display remove community success message and a button to be redirected to te referer page
+     * @param moodle_url $url the page to be redirected to
+     * @return string html
+     */
+    public function remove_success(moodle_url $url) {
+        $html = $this->output->notification(get_string('communityremoved', 'hub'),
+                    'notifysuccess');
+        $continuebutton = new single_button($url,
+                        get_string('continue', 'block_community'));
+        $html .= html_writer::tag('div', $this->output->render($continuebutton),
+                array('class' => 'continuebutton'));
+        return $html;
+    }
+
+    /**
+     * Display add community course success message and a button to be redirected to te referer page
+     * @param moodle_url $url the page to be redirected to
+     * @return string html
+     */
+    public function save_link_success(moodle_url $url) {
+        $html = $this->output->notification(get_string('addedtoblock', 'block_community'),
+                    'notifysuccess');
+        $continuebutton = new single_button($url,
+                        get_string('continue', 'block_community'));
+        $html .= html_writer::tag('div', $this->output->render($continuebutton),
+                array('class' => 'continuebutton'));
+        return $html;
+    }
+
+    /**
+     * The 'Next'/'more course result' link for a courses search
+     * @param array $data - the form parameter to execute the search on more result
+     * @return string html code
+     */
+    public function next_button($data) {
+        $nextlink = html_writer::tag('a', get_string('next', 'block_community'),
+                array('href' => new moodle_url('', $data)));
+        return html_writer::tag('div', $nextlink, array( 'class' => 'nextlink'));
+    }
+
+    /**
+     * Displays information about moodle.net above course search form
+     *
+     * @return string
+     */
+    public function moodlenet_info() {
+        if (!$info = \core\hub\registration::get_moodlenet_info()) {
+            return '';
+        }
+
+        $image = html_writer::div(html_writer::img($info['imgurl'], $info['name']), 'hubimage');
+
+        $namelink = html_writer::link($info['url'], html_writer::tag('h2', $info['name']), array('class' => 'hubtitlelink'));
+        $description = clean_param($info['description'], PARAM_TEXT);
+        $descriptiontext = html_writer::div(format_text($description, FORMAT_PLAIN), 'hubdescription');
+
+        $additionaldesc = get_string('enrollablecourses', 'block_community') . ': ' . $info['enrollablecourses'] . ' - ' .
+            get_string('downloadablecourses', 'block_community') . ': ' . $info['downloadablecourses'];
+        $stats = html_writer::div(html_writer::tag('div', $additionaldesc), 'hubstats');
+
+        $text = html_writer::div($descriptiontext . $stats, 'hubtext');
+
+        $imgandtext = html_writer::div($image . $text, 'hubimgandtext');
+
+        $fulldesc = html_writer::div($namelink . $imgandtext, 'hubmainhmtl clearfix');
+
+        return html_writer::div($fulldesc, 'formlisting');
+    }
+
+    /**
+     * Display a list of courses
+     * @param array $courses
+     * @param mixed $unused parameter is not used
+     * @param int $contextcourseid context course id
+     * @return string
+     */
+    public function course_list($courses, $unused, $contextcourseid) {
+        global $CFG;
+
+        $renderedhtml = '';
+
+        if (empty($courses)) {
+            if (isset($courses)) {
+                $renderedhtml .= get_string('nocourse', 'block_community');
+            }
+        } else {
+            $courseiteration = 0;
+            foreach ($courses as $course) {
+                $course = (object) $course;
+                $courseiteration = $courseiteration + 1;
+
+                //create visit link html
+                if (!empty($course->courseurl)) {
+                    $courseurl = new moodle_url($course->courseurl);
+                    $linktext = get_string('visitsite', 'block_community');
+                } else {
+                    $courseurl = new moodle_url($course->demourl);
+                    $linktext = get_string('visitdemo', 'block_community');
+                }
+
+                $visitlinkhtml = html_writer::tag('a', $linktext,
+                                array('href' => $courseurl, 'class' => 'hubcoursedownload',
+                                    'onclick' => 'this.target="_blank"'));
+
+                //create title html
+                $coursename = html_writer::tag('h3', $course->fullname,
+                                array('class' => 'hubcoursetitle'));
+                $coursenamehtml = html_writer::tag('div', $coursename,
+                        array('class' => 'hubcoursetitlepanel'));
+
+                // create screenshots html
+                $screenshothtml = '';
+                if (!empty($course->screenshotbaseurl)) {
+                    $screenshothtml = html_writer::empty_tag('img',
+                        array('src' => $course->screenshotbaseurl, 'alt' => $course->fullname));
+                }
+                $coursescreenshot = html_writer::tag('div', $screenshothtml,
+                                array('class' => 'coursescreenshot',
+                                    'id' => 'image-' . $course->id));
+
+                //create description html
+                $deschtml = html_writer::tag('div', $course->description,
+                                array('class' => 'hubcoursedescription'));
+
+                //create users related information html
+                $courseuserinfo = get_string('userinfo', 'block_community', $course);
+                if ($course->contributornames) {
+                    $courseuserinfo .= ' - ' . get_string('contributors', 'block_community',
+                                    $course->contributornames);
+                }
+                $courseuserinfohtml = html_writer::tag('div', $courseuserinfo,
+                                array('class' => 'hubcourseuserinfo'));
+
+                //create course content related information html
+                $course->subject = (get_string_manager()->string_exists($course->subject, 'edufields')) ?
+                        get_string($course->subject, 'edufields') : get_string('none');
+                $course->audience = get_string('audience' . $course->audience, 'hub');
+                $course->educationallevel = get_string('edulevel' . $course->educationallevel, 'hub');
+                $coursecontentinfo = '';
+                if (empty($course->coverage)) {
+                    $course->coverage = '';
+                } else {
+                    $coursecontentinfo .= get_string('coverage', 'block_community', $course->coverage);
+                    $coursecontentinfo .= ' - ';
+                }
+                $coursecontentinfo .= get_string('contentinfo', 'block_community', $course);
+                $coursecontentinfohtml = html_writer::tag('div', $coursecontentinfo,
+                                array('class' => 'hubcoursecontentinfo'));
+
+                ///create course file related information html
+                //language
+                if (!empty($course->language)) {
+                    $languages = get_string_manager()->get_list_of_languages();
+                    $course->lang = $languages[$course->language];
+                } else {
+                    $course->lang = '';
+                }
+                //licence
+                require_once($CFG->libdir . "/licenselib.php");
+                $licensemanager = new license_manager();
+                $licenses = $licensemanager->get_licenses();
+                foreach ($licenses as $license) {
+                    if ($license->shortname == $course->licenceshortname) {
+                        $course->license = $license->fullname;
+                    }
+                }
+                $course->timeupdated = userdate($course->timemodified);
+                $coursefileinfo = get_string('fileinfo', 'block_community', $course);
+                $coursefileinfohtml = html_writer::tag('div', $coursefileinfo,
+                                array('class' => 'hubcoursefileinfo'));
+
+
+
+                //Create course content html
+                $blocks = core_component::get_plugin_list('block');
+                $activities = core_component::get_plugin_list('mod');
+                if (!empty($course->contents)) {
+                    $activitieshtml = '';
+                    $blockhtml = '';
+                    foreach ($course->contents as $content) {
+                        $content = (object) $content;
+                        if ($content->moduletype == 'block') {
+                            if (!empty($blockhtml)) {
+                                $blockhtml .= ' - ';
+                            }
+                            if (array_key_exists($content->modulename, $blocks)) {
+                                $blockname = get_string('pluginname', 'block_' . $content->modulename);
+                            } else {
+                                $blockname = $content->modulename;
+                            }
+                            $blockhtml .= $blockname . " (" . $content->contentcount . ")";
+                        } else {
+                            if (!empty($activitieshtml)) {
+                                $activitieshtml .= ' - ';
+                            }
+                            if (array_key_exists($content->modulename, $activities)) {
+                                $activityname = get_string('modulename', $content->modulename);
+                            } else {
+                                $activityname = $content->modulename;
+                            }
+                            $activitieshtml .= $activityname . " (" . $content->contentcount . ")";
+                        }
+                    }
+
+                    $blocksandactivities = html_writer::tag('div',
+                                    get_string('activities', 'block_community') . " : " . $activitieshtml);
+
+                    //Uncomment following lines to display blocks information
+//                    $blocksandactivities .= html_writer::tag('span',
+//                                    get_string('blocks', 'block_community') . " : " . $blockhtml);
+                }
+
+                //Create outcomes html
+                $outcomes= '';
+                if (!empty($course->outcomes)) {
+                    foreach ($course->outcomes as $outcome) {
+                        if (!empty($outcomes)) {
+                            $outcomes .= ', ';
+                        }
+                        $outcomes .= $outcome['fullname'];
+                    }
+                    $outcomes = get_string('outcomes', 'block_community',
+                            $outcomes);
+                }
+                $outcomeshtml = html_writer::tag('div', $outcomes, array('class' => 'hubcourseoutcomes'));
+
+                //create additional information html
+                $additionaldesc = $courseuserinfohtml . $coursecontentinfohtml
+                        . $coursefileinfohtml . $blocksandactivities . $outcomeshtml;
+                $additionaldeschtml = html_writer::tag('div', $additionaldesc,
+                                array('class' => 'additionaldesc'));
+
+                //Create add button html
+                $addbuttonhtml = "";
+                if ($course->enrollable) {
+                    $params = array('sesskey' => sesskey(), 'add' => 1, 'confirmed' => 1,
+                        'coursefullname' => $course->fullname, 'courseurl' => $courseurl,
+                        'coursedescription' => $course->description,
+                        'courseid' => $contextcourseid);
+                    $addurl = new moodle_url("/blocks/community/communitycourse.php", $params);
+                    $addbuttonhtml = html_writer::tag('a',
+                                    get_string('addtocommunityblock', 'block_community'),
+                                    array('href' => $addurl, 'class' => 'centeredbutton, hubcoursedownload'));
+                }
+
+                //create download button html
+                $downloadbuttonhtml = "";
+                if (!$course->enrollable) {
+                    $params = array('sesskey' => sesskey(), 'download' => 1, 'confirmed' => 1,
+                        'remotemoodleurl' => $CFG->wwwroot, 'courseid' => $contextcourseid,
+                        'downloadcourseid' => $course->id,
+                        'coursefullname' => $course->fullname, 'backupsize' => $course->backupsize);
+                    $downloadurl = new moodle_url("/blocks/community/communitycourse.php", $params);
+                    $downloadbuttonhtml = html_writer::tag('a', get_string('install', 'block_community'),
+                                    array('href' => $downloadurl, 'class' => 'centeredbutton, hubcoursedownload'));
+                }
+
+                //Create rating html
+                $rating = html_writer::tag('div', get_string('noratings', 'block_community'),
+                                array('class' => 'norating'));
+                if (!empty($course->rating)) {
+                    $course->rating = (object) $course->rating;
+                    if ($course->rating->count > 0) {
+
+                        //calculate size of the rating star
+                        $starimagesize = 20; //in px
+                        $numberofstars = 5;
+                        $size = ($course->rating->aggregate / $course->rating->scaleid)
+                                * $numberofstars * $starimagesize;
+                        $rating = html_writer::tag('li', '',
+                                        array('class' => 'current-rating',
+                                            'style' => 'width:' . $size . 'px;'));
+
+                        $rating = html_writer::tag('ul', $rating,
+                                        array('class' => 'star-rating clearfix'));
+                        $rating .= html_writer::tag('div', ' (' . $course->rating->count . ')',
+                                        array('class' => 'ratingcount clearfix'));
+                    }
+                }
+
+
+                //Create comments html
+                $coursecomments = html_writer::tag('div', get_string('nocomments', 'block_community'),
+                                array('class' => 'nocomments'));
+                $commentcount = 0;
+                if (!empty($course->comments)) {
+                    //display only if there is some comment if there is some comment
+                    $commentcount = count($course->comments);
+                    $coursecomments = html_writer::tag('div',
+                                    get_string('comments', 'block_community', $commentcount),
+                                    array('class' => 'commenttitle'));
+
+                    foreach ($course->comments as $comment) {
+                        $commentator = html_writer::tag('div',
+                                        $comment['commentator'],
+                                        array('class' => 'hubcommentator'));
+                        $commentdate = html_writer::tag('div',
+                                        ' - ' . userdate($comment['date'], '%e/%m/%y'),
+                                        array('class' => 'hubcommentdate clearfix'));
+
+                        $commenttext = html_writer::tag('div',
+                                        $comment['comment'],
+                                        array('class' => 'hubcommenttext'));
+
+                        $coursecomments .= html_writer::tag('div',
+                                        $commentator . $commentdate . $commenttext,
+                                        array('class' => 'hubcomment'));
+                    }
+                    $coursecommenticon = html_writer::tag('div',
+                                    get_string('comments', 'block_community', $commentcount),
+                                    array('class' => 'hubcoursecomments',
+                                        'id' => 'comments-' . $course->id));
+                    $coursecomments = $coursecommenticon . html_writer::tag('div',
+                                    $coursecomments,
+                                    array('class' => 'yui3-overlay-loading',
+                                        'id' => 'commentoverlay-' . $course->id));
+                }
+
+                //link rate and comment
+                $rateandcomment = html_writer::tag('div',
+                                html_writer::link($course->commenturl, get_string('rateandcomment', 'block_community'),
+                                            ['onclick' => 'this.target="_blank"']),
+                                array('class' => 'hubrateandcomment'));
+
+                //the main DIV tags
+                $buttonsdiv = html_writer::tag('div',
+                                $addbuttonhtml . $downloadbuttonhtml . $visitlinkhtml,
+                                array('class' => 'courseoperations'));
+                $screenshotbuttonsdiv = html_writer::tag('div',
+                                $coursescreenshot . $buttonsdiv,
+                                array('class' => 'courselinks'));
+
+                $coursedescdiv = html_writer::tag('div',
+                                $deschtml . $additionaldeschtml
+                                . $rating . $coursecomments . $rateandcomment,
+                                array('class' => 'coursedescription'));
+                $coursehtml =
+                        $coursenamehtml . html_writer::tag('div',
+                                $coursedescdiv . $screenshotbuttonsdiv,
+                                array('class' => 'hubcourseinfo clearfix'));
+
+                $renderedhtml .=html_writer::tag('div', $coursehtml,
+                                array('class' => 'fullhubcourse clearfix'));
+            }
+
+            $renderedhtml = html_writer::tag('div', $renderedhtml,
+                            array('class' => 'hubcourseresult'));
+        }
+
+        return $renderedhtml;
+    }
+
+}
diff --git a/community/styles.css b/community/styles.css
new file mode 100644
index 0000000..f9ecac8
--- /dev/null
+++ b/community/styles.css
@@ -0,0 +1,355 @@
+/** General display rules **/
+
+/* HUB SELECTOR */
+#page-blocks-community-communitycourse .hubscreenshot {
+    float: left;
+}
+
+#page-blocks-community-communitycourse .hubtitlelink {
+    color: #999;
+}
+
+#page-blocks-community-communitycourse .hubsmalllogo {
+    padding-left: 3px;
+    padding-right: 7px;
+    float: left;
+}
+
+#page-blocks-community-communitycourse .hubtext {
+    display: block;
+    width: 68%;
+    padding-left: 165px;
+}
+
+#page-blocks-community-communitycourse .hubimage {
+    float: left;
+    display: block;
+    width: 100px;
+}
+
+#page-blocks-community-communitycourse .hubstats {
+    padding-top: 10px;
+}
+
+#page-blocks-community-communitycourse .hubstats .iconhelp {
+    float: left;
+    padding-right: 3px;
+}
+
+#page-blocks-community-communitycourse .hubadditionaldesc {
+    color: #666;
+    font-size: 90%;
+    display: block;
+}
+
+#page-blocks-community-communitycourse .hubscreenshot {
+    margin-right: 10px;
+}
+
+#page-blocks-community-communitycourse .hubtrusted {
+    display: inline;
+}
+
+#page-blocks-community-communitycourse .trustedtr {
+    background-color: #ffe1c3;
+}
+
+#page-blocks-community-communitycourse .prioritisetr {
+    background-color: #ffd4ff;
+}
+
+#page-blocks-community-communitycourse .blockdescription {
+    font-size: 80%;
+    color: #555;
+}
+
+#page-blocks-community-communitycourse .trusted {
+    font-size: 90%;
+    color: #063;
+    font-weight: normal;
+    font-style: italic;
+}
+
+/* COURSES RESULT */
+#page-blocks-community-communitycourse .additionaldesc {
+    font-size: 80%;
+    color: #8b8989;
+}
+
+#page-blocks-community-communitycourse .comment-link {
+    font-size: 80%;
+    color: #555;
+}
+
+#page-blocks-community-communitycourse .coursescreenshot {
+    text-align: center;
+    cursor: pointer;
+}
+
+#page-blocks-community-communitycourse .hubcourseinfo {
+    margin-left: 15px;
+}
+
+#page-blocks-community-communitycourse .pagingbar {
+    text-align: center;
+}
+
+#page-blocks-community-communitycourse .coursecomment {
+    float: right;
+}
+
+#page-blocks-community-communitycourse .courseoperations {
+    margin-top: 9px;
+    text-align: center;
+}
+
+#page-blocks-community-communitycourse .hubcoursedownload:hover {
+    background-color: #cdc9c9;
+}
+
+#page-blocks-community-communitycourse .courselinks {
+    float: right;
+    width: 180px;
+}
+
+#page-blocks-community-communitycourse .ratingaggregate {
+    float: left;
+    padding-right: 4px;
+}
+
+#page-blocks-community-communitycourse .hubcourserating {
+    padding-top: 3px;
+    font-size: 80%;
+    color: #555;
+}
+
+#page-blocks-community-communitycourse .coursedescription {
+    width: 70%;
+    float: left;
+}
+
+#page-blocks-community-communitycourse .fullhubcourse {
+    margin-bottom: 20px;
+}
+
+#page-blocks-community-communitycourse .hubcoursetitlepanel {
+    margin-bottom: 6px;
+}
+
+#page-blocks-community-communitycourse .hubcourseresult {
+    background: none repeat scroll 0 0 #fff;
+    clear: both;
+    margin: 30px auto 0;
+    z-index: 90;
+    width: 95%;
+    padding: 10px 10px 10px 10px;
+    border-style: solid;
+    border-width: 1px;
+}
+
+#page-blocks-community-communitycourse .hubcoursetitle {
+    -webkit-box-shadow: rgba(0, 0, 0, 0.546875) 0 0 4px;
+    -moz-box-shadow: rgba(0, 0, 0, 0.546875) 0 0 4px;
+    background: #8b8989;
+    left: -15px;
+    position: relative;
+    z-index: 0;
+    border: 0;
+    margin: 0;
+    outline: 0;
+    padding: 0;
+    vertical-align: baseline;
+    color: #fff;
+    padding-top: 6px;
+    padding-bottom: 6px;
+    text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
+    text-align: left;
+    font-style: italic;
+    font-weight: normal;
+    line-height: 1.2em;
+    font-size: 140%;
+    width: 102%;
+    text-indent: 15px;
+}
+
+#page-blocks-community-communitycourse .hubcoursedownload {
+    display: inline-block;
+    padding: 5px 8px 6px;
+    color: black;
+    text-decoration: none;
+    -moz-border-radius: 6px;
+    -webkit-border-radius: 6px;
+    -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
+    -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
+    border-bottom: 1px solid rgba(0, 0, 0, 0.25);
+    position: relative;
+    cursor: pointer;
+    background-color: #eee9e9;
+    margin-left: 6px;
+    font-size: 95%;
+    margin-bottom: 9px;
+}
+
+/*  STAR RATING  */
+#page-blocks-community-communitycourse .ratingcount {
+    color: #8b8989;
+    font-size: 80%;
+    vertical-align: top;
+}
+
+#page-blocks-community-communitycourse .norating {
+    font-weight: bold;
+    color: #8b8989;
+    font-size: 80%;
+}
+
+#page-blocks-community-communitycourse .star-rating {
+    list-style: none;
+    margin: 4px 0 4px;
+    padding: 0;
+    width: 100px;
+    height: 20px;
+    position: relative;
+    background: url([[pix:i/star-rating]]) top left repeat-x;
+    float: left;
+}
+
+#page-blocks-community-communitycourse .star-rating li {
+    padding: 0;
+    margin: 0;
+    height: 20px;
+    width: 20px;
+    float: left;
+}
+
+#page-blocks-community-communitycourse .star-rating li.current-rating {
+    background: url([[pix:i/star-rating]]) left bottom;
+    position: absolute;
+    height: 20px;
+    display: block;
+    text-indent: -9000px;
+    z-index: 1;
+}
+
+/* COMMENTS */
+#page-blocks-community-communitycourse .nocomments {
+    font-weight: bold;
+    color: #8b8989;
+    font-size: 80%;
+}
+
+#page-blocks-community-communitycourse .hubcommentator {
+    float: left;
+    font-weight: bold;
+}
+
+#page-blocks-community-communitycourse .hubcommentdate {
+    font-weight: bold;
+}
+
+#page-blocks-community-communitycourse .hubcommenttext {
+    margin-bottom: 10px;
+}
+
+#page-blocks-community-communitycourse .hubnoscriptcoursecomments {
+    margin-left: 5px;
+}
+
+#page-blocks-community-communitycourse .yui3-overlay-loading {
+    /* Hide overlay markup while loading, if js is enabled */
+    top: -1000em;
+    left: -1000em;
+    position: absolute;
+    z-index: 1000;
+}
+
+#page-blocks-community-communitycourse .hubcoursecomments {
+    /* comment button */
+    display: inline-block;
+    padding: 3px 3px 3px 3px;
+    color: white;
+    text-decoration: none;
+    -moz-border-radius: 6px;
+    -webkit-border-radius: 6px;
+    position: relative;
+    cursor: pointer;
+    background-color: #8b8989;
+    margin-left: 0;
+    font-size: 80%;
+    margin-top: 15px;
+}
+
+#page-blocks-community-communitycourse .hubrateandcomment {
+    font-size: 80%;
+}
+
+#page-blocks-community-communitycourse .nextlink {
+    text-align: center;
+    margin-top: 6px;
+}
+
+#page-blocks-community-communitycourse .textinfo {
+    text-align: center;
+}
+
+#ss-mask {
+    z-index: 10;
+    position: fixed;
+    top: 0;
+    left: 0;
+    bottom: 0;
+    right: 0;
+    opacity: 0.35;
+    filter: alpha(opacity=35);
+    background: #000;
+}
+
+.hiddenoverlay {
+    display: none;
+    text-align: center;
+}
+
+.imagearrow {
+    font-size: 120%;
+    display: inline;
+    cursor: pointer;
+}
+
+.imagetitle {
+    display: inline;
+    cursor: pointer;
+}
+
+#page-blocks-community-communitycourse .moodle-dialogue-base .moodle-dialogue {
+    -moz-border-radius: 12px 12px 12px 12px;
+    -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
+    -webkit-border-radius: 12px 12px 12px 12px;
+    -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
+    border-width: 0 0 0 0;
+}
+
+#page-blocks-community-communitycourse .moodle-dialogue-base .moodle-dialogue-wrap {
+    -moz-border-radius: 12px 12px 0 0;
+    -webkit-border-radius: 12px 12px 0 0;
+    background-color: #fff;
+    border: 1px solid #555;
+}
+
+#page-blocks-community-communitycourse .moodle-dialogue-base .moodle-dialogue-hd {
+    -moz-border-radius: 12px 12px 0 0;
+    -webkit-border-radius: 12px 12px 0 0;
+    background-color: #f6f6f6;
+    border: 1px solid #ccc;
+    overflow: auto;
+    padding: 7px 6px;
+}
+
+#page-blocks-community-communitycourse .moodle-dialogue-base .moodle-dialogue-bd {
+    padding: 0;
+    margin-bottom: -5px;
+}
+
+#page-blocks-community-communitycourse .moodle-dialogue-base .closebutton {
+    margin-top: 4px;
+    margin-right: 4px;
+}
diff --git a/community/tests/privacy_test.php b/community/tests/privacy_test.php
new file mode 100644
index 0000000..48f672f
--- /dev/null
+++ b/community/tests/privacy_test.php
@@ -0,0 +1,267 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Unit tests for the block_community implementation of the privacy API.
+ *
+ * @package    block_community
+ * @category   test
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+use \core_privacy\local\metadata\collection;
+use \core_privacy\local\request\writer;
+use \core_privacy\local\request\approved_contextlist;
+use \block_community\privacy\provider;
+
+/**
+ * Unit tests for the block_community implementation of the privacy API.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_community_privacy_testcase extends \core_privacy\tests\provider_testcase {
+
+    /**
+     * Overriding setUp() function to always reset after tests.
+     */
+    public function setUp() {
+        $this->resetAfterTest(true);
+    }
+
+    /**
+     * Test for provider::get_metadata().
+     */
+    public function test_get_metadata() {
+        $collection = new collection('block_community');
+        $newcollection = provider::get_metadata($collection);
+        $itemcollection = $newcollection->get_collection();
+        $this->assertCount(1, $itemcollection);
+
+        $table = reset($itemcollection);
+        $this->assertEquals('block_community', $table->get_name());
+
+        $privacyfields = $table->get_privacy_fields();
+        $this->assertArrayHasKey('userid', $privacyfields);
+        $this->assertArrayHasKey('coursename', $privacyfields);
+        $this->assertArrayHasKey('coursedescription', $privacyfields);
+        $this->assertArrayHasKey('courseurl', $privacyfields);
+        $this->assertArrayHasKey('imageurl', $privacyfields);
+
+        $this->assertEquals('privacy:metadata:block_community', $table->get_summary());
+    }
+
+    /**
+     * Test for provider::get_contexts_for_userid().
+     */
+    public function test_get_contexts_for_userid() {
+        global $DB;
+
+        // Test setup.
+        $teacher = $this->getDataGenerator()->create_user();
+        $this->setUser($teacher);
+
+        // Add two community links for the User.
+        $community = (object)[
+            'userid' => $teacher->id,
+            'coursename' => 'Dummy Community Course Name - 1',
+            'coursedescription' => 'Dummy Community Course Description - 1',
+            'courseurl' => 'https://moodle.org/community_courses/Dummy_Community_Course-1',
+            'imageurl' => ''
+        ];
+        $DB->insert_record('block_community', $community);
+
+        $community = (object)[
+            'userid' => $teacher->id,
+            'coursename' => 'Dummy Community Course Name - 2',
+            'coursedescription' => 'Dummy Community Course Description - 2',
+            'courseurl' => 'https://moodle.org/community_courses/Dummy_Community_Course-2',
+            'imageurl' => ''
+        ];
+        $DB->insert_record('block_community', $community);
+
+        // Test the User's retrieved contextlist contains only one context.
+        $contextlist = provider::get_contexts_for_userid($teacher->id);
+        $contexts = $contextlist->get_contexts();
+        $this->assertCount(1, $contexts);
+
+        // Test the User's contexts equal the User's own context.
+        $context = reset($contexts);
+        $this->assertEquals(CONTEXT_USER, $context->contextlevel);
+        $this->assertEquals($teacher->id, $context->instanceid);
+    }
+
+    /**
+     * Test for provider::export_user_data().
+     */
+    public function test_export_user_data() {
+        global $DB;
+
+        // Test setup.
+        $teacher = $this->getDataGenerator()->create_user();
+        $this->setUser($teacher);
+
+        // Add 3 community links for the User.
+        $nocommunities = 3;
+        for ($c = 0; $c < $nocommunities; $c++) {
+            $community = (object)[
+                'userid' => $teacher->id,
+                'coursename' => 'Dummy Community Course Name - ' . $c,
+                'coursedescription' => 'Dummy Community Course Description - ' . $c,
+                'courseurl' => 'https://moodle.org/community_courses/Dummy_Community_Course-' . $c,
+                'imageurl' => ''
+            ];
+            $DB->insert_record('block_community', $community);
+        }
+
+        // Test the created block_community records matches the test number of communities specified.
+        $communities = $DB->get_records('block_community', ['userid' => $teacher->id]);
+        $this->assertCount($nocommunities, $communities);
+
+        // Test the User's retrieved contextlist contains only one context.
+        $contextlist = provider::get_contexts_for_userid($teacher->id);
+        $contexts = $contextlist->get_contexts();
+        $this->assertCount(1, $contexts);
+
+        // Test the User's contexts equal the User's own context.
+        $context = reset($contexts);
+        $this->assertEquals(CONTEXT_USER, $context->contextlevel);
+        $this->assertEquals($teacher->id, $context->instanceid);
+
+        $approvedcontextlist = new approved_contextlist($teacher, 'block_community', $contextlist->get_contextids());
+
+        // Retrieve Calendar Event and Subscriptions data only for this user.
+        provider::export_user_data($approvedcontextlist);
+
+        // Test the block_community data is exported at the User context level.
+        $user = $approvedcontextlist->get_user();
+        $contextuser = context_user::instance($user->id);
+        $writer = writer::with_context($contextuser);
+        $this->assertTrue($writer->has_any_data());
+    }
+
+    /**
+     * Test for provider::delete_data_for_all_users_in_context().
+     */
+    public function test_delete_data_for_all_users_in_context() {
+        global $DB;
+
+        // Test setup.
+        $teacher = $this->getDataGenerator()->create_user();
+        $this->setUser($teacher);
+
+        // Add a community link for the User.
+        $community = (object)[
+            'userid' => $teacher->id,
+            'coursename' => 'Dummy Community Course Name',
+            'coursedescription' => 'Dummy Community Course Description',
+            'courseurl' => 'https://moodle.org/community_courses/Dummy_Community_Course',
+            'imageurl' => ''
+        ];
+        $DB->insert_record('block_community', $community);
+
+        // Test the User's retrieved contextlist contains only one context.
+        $contextlist = provider::get_contexts_for_userid($teacher->id);
+        $contexts = $contextlist->get_contexts();
+        $this->assertCount(1, $contexts);
+
+        // Test the User's contexts equal the User's own context.
+        $context = reset($contexts);
+        $this->assertEquals(CONTEXT_USER, $context->contextlevel);
+        $this->assertEquals($teacher->id, $context->instanceid);
+
+        // Test delete all users content by context.
+        provider::delete_data_for_all_users_in_context($context);
+        $blockcommunity = $DB->get_records('block_community', ['userid' => $teacher->id]);
+        $this->assertCount(0, $blockcommunity);
+    }
+
+    /**
+     * Test for provider::delete_data_for_user().
+     */
+    public function test_delete_data_for_user() {
+        global $DB;
+
+        // Test setup.
+        $teacher1 = $this->getDataGenerator()->create_user();
+        $teacher2 = $this->getDataGenerator()->create_user();
+        $this->setUser($teacher1);
+
+        // Add 3 community links for Teacher 1.
+        $nocommunities = 3;
+        for ($c = 0; $c < $nocommunities; $c++) {
+            $community = (object)[
+                'userid' => $teacher1->id,
+                'coursename' => 'Dummy Community Course Name - ' . $c,
+                'coursedescription' => 'Dummy Community Course Description - ' . $c,
+                'courseurl' => 'https://moodle.org/community_courses/Dummy_Community_Course-' . $c,
+                'imageurl' => ''
+            ];
+            $DB->insert_record('block_community', $community);
+        }
+
+        // Add 1 community link for Teacher 2.
+        $community = (object)[
+            'userid' => $teacher2->id,
+            'coursename' => 'Dummy Community Course Name - Blah',
+            'coursedescription' => 'Dummy Community Course Description - Blah',
+            'courseurl' => 'https://moodle.org/community_courses/Dummy_Community_Course-Blah',
+            'imageurl' => ''
+        ];
+        $DB->insert_record('block_community', $community);
+
+        // Test the created block_community records for Teacher 1 equals test number of communities specified.
+        $communities = $DB->get_records('block_community', ['userid' => $teacher1->id]);
+        $this->assertCount($nocommunities, $communities);
+
+        // Test the created block_community records for Teacher 2 equals 1.
+        $communities = $DB->get_records('block_community', ['userid' => $teacher2->id]);
+        $this->assertCount(1, $communities);
+
+        // Test the deletion of block_community records for Teacher 1 results in zero records.
+        $contextlist = provider::get_contexts_for_userid($teacher1->id);
+        $contexts = $contextlist->get_contexts();
+        $this->assertCount(1, $contexts);
+
+        // Test the User's contexts equal the User's own context.
+        $context = reset($contexts);
+        $this->assertEquals(CONTEXT_USER, $context->contextlevel);
+        $this->assertEquals($teacher1->id, $context->instanceid);
+
+        $approvedcontextlist = new approved_contextlist($teacher1, 'block_community', $contextlist->get_contextids());
+        provider::delete_data_for_user($approvedcontextlist);
+        $communities = $DB->get_records('block_community', ['userid' => $teacher1->id]);
+        $this->assertCount(0, $communities);
+
+
+        // Test that Teacher 2's single block_community record still exists.
+        $contextlist = provider::get_contexts_for_userid($teacher2->id);
+        $contexts = $contextlist->get_contexts();
+        $this->assertCount(1, $contexts);
+
+        // Test the User's contexts equal the User's own context.
+        $context = reset($contexts);
+        $this->assertEquals(CONTEXT_USER, $context->contextlevel);
+        $this->assertEquals($teacher2->id, $context->instanceid);
+
+        $communities = $DB->get_records('block_community', ['userid' => $teacher2->id]);
+        $this->assertCount(1, $communities);
+    }
+
+}
diff --git a/community/version.php b/community/version.php
new file mode 100644
index 0000000..9bc9957
--- /dev/null
+++ b/community/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_community
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_community'; // Full name of the plugin (used for diagnostics)
diff --git a/community/yui/comments/comments.js b/community/yui/comments/comments.js
new file mode 100644
index 0000000..e720c18
--- /dev/null
+++ b/community/yui/comments/comments.js
@@ -0,0 +1,97 @@
+YUI.add('moodle-block_community-comments', function(Y) {
+
+    var COMMENTSNAME = 'blocks_community_comments';
+
+    var COMMENTS = function() {
+        COMMENTS.superclass.constructor.apply(this, arguments);
+    };
+
+    Y.extend(COMMENTS, Y.Base, {
+
+        event:null,
+        panelevent: null,
+        panels: [], //all the comment boxes
+
+        initializer : function(params) {
+
+            //attach a show event on the div with id = comments
+            for (var i=0;i<this.get('commentids').length;i++)
+            {
+                var commentid = this.get('commentids')[i];
+                this.panels[commentid] = new M.core.dialogue({
+                    headerContent:Y.Node.create('<h1>')
+                        .append(Y.one('#commentoverlay-'+commentid+' .commenttitle').get('innerHTML')),
+                    bodyContent:Y.one('#commentoverlay-'+commentid).get('innerHTML'),
+                    visible: false, //by default it is not displayed
+                    modal: false,
+                    zIndex:100,
+                    closeButtonTitle: this.get('closeButtonTitle')
+                });
+
+                this.panels[commentid].get('contentBox').one('.commenttitle').remove();
+                this.panels[commentid].render();
+                this.panels[commentid].hide();
+
+                Y.one('#comments-'+commentid).on('click', this.show, this, commentid);
+            }
+
+        },
+
+        show : function (e, commentid) {
+
+            // Hide all panels.
+            for (var i=0;i<this.get('commentids').length;i++)
+            {
+                this.hide(e, this.get('commentids')[i]);
+            }
+
+            this.panels[commentid].show(); //show the panel
+
+            e.halt(); // we are going to attach a new 'hide panel' event to the body,
+            // because javascript always propagate event to parent tag,
+            // we need to tell Yahoo to stop to call the event on parent tag
+            // otherwise the hide event will be call right away.
+
+            // We add a new event on the body in order to hide the panel for the next click.
+            this.event = Y.one(document.body).on('click', this.hide, this, commentid);
+            // We add a new event on the panel in order to hide the panel for the next click (touch device).
+            this.panelevent = Y.one("#commentoverlay-"+commentid).on('click', this.hide, this, commentid);
+
+            // Focus on the close button
+            this.panels[commentid].get('buttons').header[0].focus();
+        },
+
+        hide : function (e, commentid) {
+            this.panels[commentid].hide(); //hide the panel
+            if (this.event != null) {
+                this.event.detach(); //we need to detach the body hide event
+            //Note: it would work without but create js warning everytime
+            //we click on the body
+            }
+            if (this.panelevent != null) {
+                this.panelevent.detach(); //we need to detach the panel hide event
+            //Note: it would work without but create js warning everytime
+            //we click on the body
+            }
+
+        }
+
+    }, {
+        NAME : COMMENTSNAME,
+        ATTRS : {
+            commentids: {},
+            closeButtonTitle : {
+                validator : Y.Lang.isString,
+                value : 'Close'
+            }
+        }
+    });
+
+    M.blocks_community = M.blocks_community || {};
+    M.blocks_community.init_comments = function(params) {
+        return new COMMENTS(params);
+    }
+
+}, '@VERSION@', {
+    requires:['base', 'moodle-core-notification']
+});
diff --git a/community/yui/imagegallery/imagegallery.js b/community/yui/imagegallery/imagegallery.js
new file mode 100644
index 0000000..b48a204
--- /dev/null
+++ b/community/yui/imagegallery/imagegallery.js
@@ -0,0 +1,206 @@
+YUI.add('moodle-block_community-imagegallery', function(Y) {
+
+    var IMAGEGALLERYNAME = 'blocks_community_imagegallery';
+
+    var IMAGEGALLERY = function() {
+        IMAGEGALLERY.superclass.constructor.apply(this, arguments);
+    };
+
+    Y.extend(IMAGEGALLERY, Y.Base, {
+
+        event:null,
+        previousevent:null,
+        nextevent:null,
+        panelevent:null,
+        panel:null, //all the images boxes
+        imageidnumbers: [],
+        imageloadingevent: null,
+        loadingimage: null,
+
+        initializer : function(params) {
+
+            //create the loading image
+            var objBody = Y.one(document.body);
+            this.loadingimage = Y.Node.create('<div id="hubloadingimage" class="hiddenoverlay">'
+                +'<img src=\'' + M.cfg.wwwroot +'/pix/i/loading.gif\'>'
+                +'</div>');
+            objBody.append(this.loadingimage);
+
+            // Create the div for panel.
+            var objBody = Y.one(document.body);
+            var paneltitle = Y.Node.create('<div id="imagetitleoverlay" class="hiddenoverlay"></div>');
+            objBody.append(paneltitle);
+            var panel = Y.Node.create('<div id="imageoverlay" class="hiddenoverlay"></div>');
+            objBody.append(panel);
+
+            /// Create the panel.
+            this.panel = new M.core.dialogue({
+                headerContent:Y.one('#imagetitleoverlay').get('innerHTML'),
+                bodyContent:Y.one('#imageoverlay').get('innerHTML'),
+                visible: false, //by default it is not displayed
+                modal: false,
+                zIndex:100
+            });
+
+            this.panel.render();
+            this.panel.hide();
+
+            //attach a show event on the image divs (<tag id='image-X'>)
+            for (var i=0;i<this.get('imageids').length;i++)
+            {
+                var imageid = this.get('imageids')[i];
+                this.imageidnumbers[imageid] = this.get('imagenumbers')[i];
+                Y.one('#image-'+imageid).on('click', this.show, this, imageid, 1);
+            }
+
+        },
+
+        show : function (e, imageid, screennumber) {
+
+            if (this.imageloadingevent != null) {
+                this.imageloadingevent.detach();
+            }
+
+            var url = this.get('huburl') + "/local/hub/webservice/download.php?courseid="
+            + imageid + "&filetype=screenshot&imagewidth=original&screenshotnumber=" + screennumber;
+
+            /// set the mask
+            if (this.get('maskNode')) {
+                this.get('maskNode').remove();
+            }
+            var objBody = Y.one(document.body);
+            var mask = Y.Node.create('<div id="ss-mask"><!-- --></div>');
+            objBody.prepend(mask);
+            this.set('maskNode', Y.one('#ss-mask'));
+
+            //display loading image
+            Y.one('#hubloadingimage').setStyle('display', 'block');
+            Y.one('#hubloadingimage').setStyle("position", 'fixed');
+            Y.one('#hubloadingimage').setStyle("top", '50%');
+            Y.one('#hubloadingimage').setStyle("left", '50%');
+
+            var windowheight = e.target.get('winHeight');
+            var windowwidth = e.target.get('winWidth');
+
+            var maxheight = windowheight - 150;
+
+            //load the title + link to next image
+            var paneltitle = Y.one('#imagetitleoverlay');
+            var previousimagelink = "<div id=\"previousarrow\" class=\"imagearrow\">←</div>";
+            var nextimagelink = "<div id=\"nextarrow\" class=\"imagearrow\">→</div>";
+
+            // Need to load the images in the panel.
+            var panel = Y.one('#imageoverlay');
+            panel.setContent('');
+
+            panel.append(Y.Node.create('<div style="text-align:center"><img id=\"imagetodisplay\" src="' + url
+                + '" style="max-height:' + maxheight + 'px;"></div>'));
+            this.panel.destroy();
+            this.panel = new M.core.dialogue({
+                headerContent:previousimagelink + '<div id=\"imagenumber\" class=\"imagetitle\"><h1> Image '
+                + screennumber + ' / ' + this.imageidnumbers[imageid] + ' </h1></div>' + nextimagelink,
+                bodyContent:Y.one('#imageoverlay').get('innerHTML'),
+                visible: false, //by default it is not displayed
+                modal: false,
+                zIndex:100,
+                closeButtonTitle: this.get('closeButtonTitle')
+            });
+            this.panel.render();
+            this.panel.hide(); //show the panel
+            this.panel.set("centered", true);
+
+            e.halt(); // we are going to attach a new 'hide panel' event to the body,
+            // because javascript always propagate event to parent tag,
+            // we need to tell Yahoo to stop to call the event on parent tag
+            // otherwise the hide event will be call right away.
+
+            //once the image is loaded, update display
+            this.imageloadingevent = Y.one('#imagetodisplay').on('load', function(e, url){
+                //hide the loading image
+                Y.one('#hubloadingimage').setStyle('display', 'none');
+
+                //display the screenshot
+                var screenshot = new Image();
+                screenshot.src = url;
+
+                var panelwidth = windowwidth - 100;
+                if(panelwidth > screenshot.width) {
+                    panelwidth = screenshot.width;
+                }
+
+                this.panel.set('width', panelwidth);
+                this.panel.set("centered", true);
+                this.panel.show();
+
+                // Focus on the close button
+                this.panel.get('buttons').header[0].focus();
+
+            }, this, url);
+
+            var previousnumber = screennumber - 1;
+            var nextnumber = screennumber + 1;
+            if (previousnumber == 0) {
+                previousnumber = this.imageidnumbers[imageid];
+            }
+            if (nextnumber > this.imageidnumbers[imageid]) {
+                nextnumber = 1;
+            }
+
+            Y.one('#previousarrow').on('click', this.show, this, imageid, previousnumber);
+            Y.one('#nextarrow').on('click', this.show, this, imageid, nextnumber);
+            Y.one('#imagenumber').on('click', this.show, this, imageid, nextnumber);
+
+            // We add a new event on the body in order to hide the panel for the next click.
+            this.event = Y.one(document.body).on('click', this.hide, this);
+            // We add a new event on the panel in order to hide the panel for the next click (touch device).
+            this.panelevent = Y.one("#imageoverlay").on('click', this.hide, this);
+
+            this.panel.on('visibleChange',function(e){
+                if(e.newVal == 0){
+                    this.get('maskNode').remove()
+                }
+            }, this);
+        },
+
+        hide : function (e) {
+
+            // remove the mask
+            this.get('maskNode').remove();
+
+            //hide the loading image
+            Y.one('#hubloadingimage').setStyle('display', 'none');
+
+            this.panel.hide(); //hide the panel
+            if (this.event != null) {
+                this.event.detach(); //we need to detach the body hide event
+            //Note: it would work without but create js warning everytime
+            //we click on the body
+            }
+            if (this.panelevent != null) {
+                this.panelevent.detach(); //we need to detach the panel hide event
+            //Note: it would work without but create js warning everytime
+            //we click on the body
+            }
+        }
+
+    }, {
+        NAME : IMAGEGALLERYNAME,
+        ATTRS : {
+            imageids: {},
+            imagenumbers: {},
+            huburl: {},
+            closeButtonTitle : {
+                validator : Y.Lang.isString,
+                value : 'Close'
+            }
+        }
+    });
+
+    M.blocks_community = M.blocks_community || {};
+    M.blocks_community.init_imagegallery = function(params) {
+        return new IMAGEGALLERY(params);
+    }
+
+}, '@VERSION@', {
+    requires:['base','node', 'moodle-core-notification']
+});
diff --git a/completionstatus/block_completionstatus.php b/completionstatus/block_completionstatus.php
new file mode 100644
index 0000000..b8627d9
--- /dev/null
+++ b/completionstatus/block_completionstatus.php
@@ -0,0 +1,256 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Block for displayed logged in user's course completion status
+ *
+ * @package    block_completionstatus
+ * @copyright  2009-2012 Catalyst IT Ltd
+ * @author     Aaron Barnes <aaronb@catalyst.net.nz>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once("{$CFG->libdir}/completionlib.php");
+
+/**
+ * Course completion status.
+ * Displays overall, and individual criteria status for logged in user.
+ */
+class block_completionstatus extends block_base {
+
+    public function init() {
+        $this->title = get_string('pluginname', 'block_completionstatus');
+    }
+
+    public function applicable_formats() {
+        return array('course' => true);
+    }
+
+    public function get_content() {
+        global $USER;
+
+        $rows = array();
+        $srows = array();
+        $prows = array();
+        // If content is cached.
+        if ($this->content !== null) {
+            return $this->content;
+        }
+
+        $course = $this->page->course;
+        $context = context_course::instance($course->id);
+
+        // Create empty content.
+        $this->content = new stdClass();
+        $this->content->text = '';
+        $this->content->footer = '';
+
+        // Can edit settings?
+        $can_edit = has_capability('moodle/course:update', $context);
+
+        // Get course completion data.
+        $info = new completion_info($course);
+
+        // Don't display if completion isn't enabled!
+        if (!completion_info::is_enabled_for_site()) {
+            if ($can_edit) {
+                $this->content->text .= get_string('completionnotenabledforsite', 'completion');
+            }
+            return $this->content;
+
+        } else if (!$info->is_enabled()) {
+            if ($can_edit) {
+                $this->content->text .= get_string('completionnotenabledforcourse', 'completion');
+            }
+            return $this->content;
+        }
+
+        // Load criteria to display.
+        $completions = $info->get_completions($USER->id);
+
+        // Check if this course has any criteria.
+        if (empty($completions)) {
+            if ($can_edit) {
+                $this->content->text .= get_string('nocriteriaset', 'completion');
+            }
+            return $this->content;
+        }
+
+        // Check this user is enroled.
+        if ($info->is_tracked_user($USER->id)) {
+
+            // Generate markup for criteria statuses.
+            $data = '';
+
+            // For aggregating activity completion.
+            $activities = array();
+            $activities_complete = 0;
+
+            // For aggregating course prerequisites.
+            $prerequisites = array();
+            $prerequisites_complete = 0;
+
+            // Flag to set if current completion data is inconsistent with what is stored in the database.
+            $pending_update = false;
+
+            // Loop through course criteria.
+            foreach ($completions as $completion) {
+                $criteria = $completion->get_criteria();
+                $complete = $completion->is_complete();
+
+                if (!$pending_update && $criteria->is_pending($completion)) {
+                    $pending_update = true;
+                }
+
+                // Activities are a special case, so cache them and leave them till last.
+                if ($criteria->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) {
+                    $activities[$criteria->moduleinstance] = $complete;
+
+                    if ($complete) {
+                        $activities_complete++;
+                    }
+
+                    continue;
+                }
+
+                // Prerequisites are also a special case, so cache them and leave them till last.
+                if ($criteria->criteriatype == COMPLETION_CRITERIA_TYPE_COURSE) {
+                    $prerequisites[$criteria->courseinstance] = $complete;
+
+                    if ($complete) {
+                        $prerequisites_complete++;
+                    }
+
+                    continue;
+                }
+                $row = new html_table_row();
+                $row->cells[0] = new html_table_cell($criteria->get_title());
+                $row->cells[1] = new html_table_cell($completion->get_status());
+                $row->cells[1]->style = 'text-align: right;';
+                $srows[] = $row;
+            }
+
+            // Aggregate activities.
+            if (!empty($activities)) {
+                $a = new stdClass();
+                $a->first = $activities_complete;
+                $a->second = count($activities);
+
+                $row = new html_table_row();
+                $row->cells[0] = new html_table_cell(get_string('activitiescompleted', 'completion'));
+                $row->cells[1] = new html_table_cell(get_string('firstofsecond', 'block_completionstatus', $a));
+                $row->cells[1]->style = 'text-align: right;';
+                $srows[] = $row;
+            }
+
+            // Aggregate prerequisites.
+            if (!empty($prerequisites)) {
+                $a = new stdClass();
+                $a->first = $prerequisites_complete;
+                $a->second = count($prerequisites);
+
+                $row = new html_table_row();
+                $row->cells[0] = new html_table_cell(get_string('dependenciescompleted', 'completion'));
+                $row->cells[1] = new html_table_cell(get_string('firstofsecond', 'block_completionstatus', $a));
+                $row->cells[1]->style = 'text-align: right;';
+                $prows[] = $row;
+
+                $srows = array_merge($prows, $srows);
+            }
+
+            // Display completion status.
+            $table = new html_table();
+            $table->width = '100%';
+            $table->attributes = array('style'=>'font-size: 90%;', 'class'=>'');
+
+            $row = new html_table_row();
+            $content = html_writer::tag('b', get_string('status').': ');
+
+            // Is course complete?
+            $coursecomplete = $info->is_course_complete($USER->id);
+
+            // Load course completion.
+            $params = array(
+                'userid' => $USER->id,
+                'course' => $course->id
+            );
+            $ccompletion = new completion_completion($params);
+
+            // Has this user completed any criteria?
+            $criteriacomplete = $info->count_course_user_data($USER->id);
+
+            if ($pending_update) {
+                $content .= html_writer::tag('i', get_string('pending', 'completion'));
+            } else if ($coursecomplete) {
+                $content .= get_string('complete');
+            } else if (!$criteriacomplete && !$ccompletion->timestarted) {
+                $content .= html_writer::tag('i', get_string('notyetstarted', 'completion'));
+            } else {
+                $content .= html_writer::tag('i', get_string('inprogress', 'completion'));
+            }
+
+            $row->cells[0] = new html_table_cell($content);
+            $row->cells[0]->colspan = '2';
+
+            $rows[] = $row;
+            $row = new html_table_row();
+            $content = "";
+            // Get overall aggregation method.
+            $overall = $info->get_aggregation_method();
+            if ($overall == COMPLETION_AGGREGATION_ALL) {
+                $content .= get_string('criteriarequiredall', 'completion');
+            } else {
+                $content .= get_string('criteriarequiredany', 'completion');
+            }
+            $content .= ':';
+            $row->cells[0] = new html_table_cell($content);
+            $row->cells[0]->colspan = '2';
+            $rows[] = $row;
+
+            $row = new html_table_row();
+            $row->cells[0] = new html_table_cell(html_writer::tag('b', get_string('requiredcriteria', 'completion')));
+            $row->cells[1] = new html_table_cell(html_writer::tag('b', get_string('status')));
+            $row->cells[1]->style = 'text-align: right;';
+            $rows[] = $row;
+
+            // Array merge $rows and $data here.
+            $rows = array_merge($rows, $srows);
+
+            $table->data = $rows;
+            $this->content->text .= html_writer::table($table);
+
+            // Display link to detailed view.
+            $details = new moodle_url('/blocks/completionstatus/details.php', array('course' => $course->id));
+            $this->content->footer .= html_writer::link($details, get_string('moredetails', 'completion'));
+        } else {
+            // If user is not enrolled, show error.
+            $this->content->text = get_string('nottracked', 'completion');
+        }
+
+        if (has_capability('report/completion:view', $context)) {
+            $report = new moodle_url('/report/completion/index.php', array('course' => $course->id));
+            if (empty($this->content->footer)) {
+                $this->content->footer = '';
+            }
+            $this->content->footer .= html_writer::empty_tag('br');
+            $this->content->footer .= html_writer::link($report, get_string('viewcoursereport', 'completion'));
+        }
+
+        return $this->content;
+    }
+}
diff --git a/completionstatus/classes/privacy/provider.php b/completionstatus/classes/privacy/provider.php
new file mode 100644
index 0000000..97fd398
--- /dev/null
+++ b/completionstatus/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_completionstatus.
+ *
+ * @package    block_completionstatus
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_completionstatus\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_completionstatus implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/completionstatus/db/access.php b/completionstatus/db/access.php
new file mode 100644
index 0000000..8d38ec8
--- /dev/null
+++ b/completionstatus/db/access.php
@@ -0,0 +1,41 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Completion status block caps.
+ *
+ * @package    block_completionstatus
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/completionstatus:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/completionstatus/db/upgrade.php b/completionstatus/db/upgrade.php
new file mode 100644
index 0000000..f0837fc
--- /dev/null
+++ b/completionstatus/db/upgrade.php
@@ -0,0 +1,61 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file keeps track of upgrades to the completion status block
+ *
+ * Sometimes, changes between versions involve alterations to database structures
+ * and other major things that may break installations.
+ *
+ * The upgrade function in this file will attempt to perform all the necessary
+ * actions to upgrade your older installation to the current version.
+ *
+ * If there's something it cannot do itself, it will tell you what you need to do.
+ *
+ * The commands in here will all be database-neutral, using the methods of
+ * database_manager class
+ *
+ * Please do not forget to use upgrade_set_timeout()
+ * before any action that may take longer time to finish.
+ *
+ * @since Moodle 2.0
+ * @package block_completionstatus
+ * @copyright 2012 Mark Nelson <markn@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Handles upgrading instances of this block.
+ *
+ * @param int $oldversion
+ * @param object $block
+ */
+function xmldb_block_completionstatus_upgrade($oldversion, $block) {
+    global $CFG;
+
+    // Automatically generated Moodle v3.2.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.3.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.4.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    return true;
+}
diff --git a/completionstatus/details.php b/completionstatus/details.php
new file mode 100644
index 0000000..33bbe77
--- /dev/null
+++ b/completionstatus/details.php
@@ -0,0 +1,263 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Block for displaying logged in user's course completion status
+ *
+ * @package    block_completionstatus
+ * @copyright  2009-2012 Catalyst IT Ltd
+ * @author     Aaron Barnes <aaronb@catalyst.net.nz>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once(__DIR__.'/../../config.php');
+require_once("{$CFG->libdir}/completionlib.php");
+
+// Load data.
+$id = required_param('course', PARAM_INT);
+$userid = optional_param('user', 0, PARAM_INT);
+
+// Load course.
+$course = $DB->get_record('course', array('id' => $id), '*', MUST_EXIST);
+
+// Load user.
+if ($userid) {
+    $user = $DB->get_record('user', array('id' => $userid), '*', MUST_EXIST);
+} else {
+    $user = $USER;
+}
+
+// Check permissions.
+require_login();
+
+if (!completion_can_view_data($user->id, $course)) {
+    print_error('cannotviewreport');
+}
+
+// Load completion data.
+$info = new completion_info($course);
+
+$returnurl = new moodle_url('/course/view.php', array('id' => $id));
+
+// Don't display if completion isn't enabled.
+if (!$info->is_enabled()) {
+    print_error('completionnotenabled', 'completion', $returnurl);
+}
+
+// Check this user is enroled.
+if (!$info->is_tracked_user($user->id)) {
+    if ($USER->id == $user->id) {
+        print_error('notenroled', 'completion', $returnurl);
+    } else {
+        print_error('usernotenroled', 'completion', $returnurl);
+    }
+}
+
+// Display page.
+
+$PAGE->set_context(context_course::instance($course->id));
+
+// Print header.
+$page = get_string('completionprogressdetails', 'block_completionstatus');
+$title = format_string($course->fullname) . ': ' . $page;
+
+$PAGE->navbar->add($page);
+$PAGE->set_pagelayout('report');
+$PAGE->set_url('/blocks/completionstatus/details.php', array('course' => $course->id, 'user' => $user->id));
+$PAGE->set_title(get_string('course') . ': ' . $course->fullname);
+$PAGE->set_heading($title);
+echo $OUTPUT->header();
+
+
+// Display completion status.
+echo html_writer::start_tag('table', array('class' => 'generalbox boxaligncenter'));
+echo html_writer::start_tag('tbody');
+
+// If not display logged in user, show user name.
+if ($USER->id != $user->id) {
+    echo html_writer::start_tag('tr');
+    echo html_writer::start_tag('td', array('colspan' => '2'));
+    echo html_writer::tag('b', get_string('showinguser', 'completion') . ' ');
+    $url = new moodle_url('/user/view.php', array('id' => $user->id, 'course' => $course->id));
+    echo html_writer::link($url, fullname($user));
+    echo html_writer::end_tag('td');
+    echo html_writer::end_tag('tr');
+}
+
+echo html_writer::start_tag('tr');
+echo html_writer::start_tag('td', array('colspan' => '2'));
+echo html_writer::tag('b', get_string('status') . ' ');
+
+// Is course complete?
+$coursecomplete = $info->is_course_complete($user->id);
+
+// Has this user completed any criteria?
+$criteriacomplete = $info->count_course_user_data($user->id);
+
+// Load course completion.
+$params = array(
+    'userid' => $user->id,
+    'course' => $course->id,
+);
+$ccompletion = new completion_completion($params);
+
+if ($coursecomplete) {
+    echo get_string('complete');
+} else if (!$criteriacomplete && !$ccompletion->timestarted) {
+    echo html_writer::tag('i', get_string('notyetstarted', 'completion'));
+} else {
+    echo html_writer::tag('i', get_string('inprogress', 'completion'));
+}
+
+echo html_writer::end_tag('td');
+echo html_writer::end_tag('tr');
+
+// Load criteria to display.
+$completions = $info->get_completions($user->id);
+
+// Check if this course has any criteria.
+if (empty($completions)) {
+    echo html_writer::start_tag('tr');
+    echo html_writer::start_tag('td', array('colspan' => '2'));
+    echo html_writer::start_tag('br');
+    echo $OUTPUT->box(get_string('nocriteriaset', 'completion'), 'noticebox');
+    echo html_writer::end_tag('td');
+    echo html_writer::end_tag('tr');
+    echo html_writer::end_tag('tbody');
+    echo html_writer::end_tag('table');
+} else {
+    echo html_writer::start_tag('tr');
+    echo html_writer::start_tag('td', array('colspan' => '2'));
+    echo html_writer::tag('b', get_string('required') . ' ');
+
+    // Get overall aggregation method.
+    $overall = $info->get_aggregation_method();
+
+    if ($overall == COMPLETION_AGGREGATION_ALL) {
+        echo get_string('criteriarequiredall', 'completion');
+    } else {
+        echo get_string('criteriarequiredany', 'completion');
+    }
+
+    echo html_writer::end_tag('td');
+    echo html_writer::end_tag('tr');
+    echo html_writer::end_tag('tbody');
+    echo html_writer::end_tag('table');
+
+    // Generate markup for criteria statuses.
+    echo html_writer::start_tag('table',
+            array('class' => 'generalbox logtable boxaligncenter', 'id' => 'criteriastatus', 'width' => '100%'));
+    echo html_writer::start_tag('tbody');
+    echo html_writer::start_tag('tr', array('class' => 'ccheader'));
+    echo html_writer::tag('th', get_string('criteriagroup', 'block_completionstatus'), array('class' => 'c0 header', 'scope' => 'col'));
+    echo html_writer::tag('th', get_string('criteria', 'completion'), array('class' => 'c1 header', 'scope' => 'col'));
+    echo html_writer::tag('th', get_string('requirement', 'block_completionstatus'), array('class' => 'c2 header', 'scope' => 'col'));
+    echo html_writer::tag('th', get_string('status'), array('class' => 'c3 header', 'scope' => 'col'));
+    echo html_writer::tag('th', get_string('complete'), array('class' => 'c4 header', 'scope' => 'col'));
+    echo html_writer::tag('th', get_string('completiondate', 'report_completion'), array('class' => 'c5 header', 'scope' => 'col'));
+    echo html_writer::end_tag('tr');
+
+    // Save row data.
+    $rows = array();
+
+    // Loop through course criteria.
+    foreach ($completions as $completion) {
+        $criteria = $completion->get_criteria();
+
+        $row = array();
+        $row['type'] = $criteria->criteriatype;
+        $row['title'] = $criteria->get_title();
+        $row['status'] = $completion->get_status();
+        $row['complete'] = $completion->is_complete();
+        $row['timecompleted'] = $completion->timecompleted;
+        $row['details'] = $criteria->get_details($completion);
+        $rows[] = $row;
+    }
+
+    // Print table.
+    $last_type = '';
+    $agg_type = false;
+    $oddeven = 0;
+
+    foreach ($rows as $row) {
+
+        echo html_writer::start_tag('tr', array('class' => 'r' . $oddeven));
+        // Criteria group.
+        echo html_writer::start_tag('td', array('class' => 'cell c0'));
+        if ($last_type !== $row['details']['type']) {
+            $last_type = $row['details']['type'];
+            echo $last_type;
+
+            // Reset agg type.
+            $agg_type = true;
+        } else {
+            // Display aggregation type.
+            if ($agg_type) {
+                $agg = $info->get_aggregation_method($row['type']);
+                echo '('. html_writer::start_tag('i');
+                if ($agg == COMPLETION_AGGREGATION_ALL) {
+                    echo core_text::strtolower(get_string('all', 'completion'));
+                } else {
+                    echo core_text::strtolower(get_string('any', 'completion'));
+                }
+
+                echo ' ' . html_writer::end_tag('i') .core_text::strtolower(get_string('required')).')';
+                $agg_type = false;
+            }
+        }
+        echo html_writer::end_tag('td');
+
+        // Criteria title.
+        echo html_writer::start_tag('td', array('class' => 'cell c1'));
+        echo $row['details']['criteria'];
+        echo html_writer::end_tag('td');
+
+        // Requirement.
+        echo html_writer::start_tag('td', array('class' => 'cell c2'));
+        echo $row['details']['requirement'];
+        echo html_writer::end_tag('td');
+
+        // Status.
+        echo html_writer::start_tag('td', array('class' => 'cell c3'));
+        echo $row['details']['status'];
+        echo html_writer::end_tag('td');
+
+        // Is complete.
+        echo html_writer::start_tag('td', array('class' => 'cell c4'));
+        echo $row['complete'] ? get_string('yes') : get_string('no');
+        echo html_writer::end_tag('td');
+
+        // Completion data.
+        echo html_writer::start_tag('td', array('class' => 'cell c5'));
+        if ($row['timecompleted']) {
+            echo userdate($row['timecompleted'], get_string('strftimedate', 'langconfig'));
+        } else {
+            echo '-';
+        }
+        echo html_writer::end_tag('td');
+        echo html_writer::end_tag('tr');
+        // For row striping.
+        $oddeven = $oddeven ? 0 : 1;
+    }
+
+    echo html_writer::end_tag('tbody');
+    echo html_writer::end_tag('table');
+}
+$courseurl = new moodle_url("/course/view.php", array('id' => $course->id));
+echo html_writer::start_tag('div', array('class' => 'buttons'));
+echo $OUTPUT->single_button($courseurl, get_string('returntocourse', 'block_completionstatus'), 'get');
+echo html_writer::end_tag('div');
+echo $OUTPUT->footer();
diff --git a/completionstatus/lang/en/block_completionstatus.php b/completionstatus/lang/en/block_completionstatus.php
new file mode 100644
index 0000000..dc93b6f
--- /dev/null
+++ b/completionstatus/lang/en/block_completionstatus.php
@@ -0,0 +1,32 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_completionstatus', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_completionstatus
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['completionprogressdetails'] = 'Completion progress details';
+$string['completionstatus:addinstance'] = 'Add a new course completion status block';
+$string['criteriagroup'] = 'Criteria group';
+$string['firstofsecond'] = '{$a->first} of {$a->second}';
+$string['pluginname'] = 'Course completion status';
+$string['requirement'] = 'Requirement';
+$string['returntocourse'] = 'Return to course';
+$string['privacy:metadata'] = 'The Course completion status block only shows information about course completion and does not store any data of its own.';
diff --git a/completionstatus/tests/behat/block_completionstatus.feature b/completionstatus/tests/behat/block_completionstatus.feature
new file mode 100644
index 0000000..f5e24a1
--- /dev/null
+++ b/completionstatus/tests/behat/block_completionstatus.feature
@@ -0,0 +1,54 @@
+@block @block_completionstatus
+Feature: Enable Block Completion in a course
+  In order to view the completion block in a course
+  As a teacher
+  I can add completion block to a course
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+      | student1 | Student | 1 | student1@example.com | S1 |
+    And the following "courses" exist:
+      | fullname | shortname | category | enablecompletion |
+      | Course 1 | C1        | 0        | 1                |
+    And the following "course enrolments" exist:
+      | user     | course | role           |
+      | teacher1 | C1     | editingteacher |
+      | student1 | C1     | student        |
+
+  Scenario: Add the block to a the course where completion is disabled
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I navigate to "Edit settings" node in "Course administration"
+    And I set the following fields to these values:
+      | Enable completion tracking | No |
+    And I press "Save and display"
+    When I add the "Course completion status" block
+    Then I should see "Completion is not enabled for this course" in the "Course completion status" "block"
+
+  Scenario: Add the block to a the course where completion is not set
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    When I add the "Course completion status" block
+    Then I should see "No completion criteria set for this course" in the "Course completion status" "block"
+
+  Scenario: Add the block to a course with criteria and view as an untracked role.
+    Given the following "activities" exist:
+      | activity | course | idnumber | name           | intro                 |
+      | page     | C1     | page1    | Test page name | Test page description |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I follow "Test page name"
+    And I navigate to "Edit settings" in current page administration
+    And I set the following fields to these values:
+      | Completion tracking | Show activity as complete when conditions are met |
+      | Require view | 1 |
+    And I press "Save and return to course"
+    When I add the "Course completion status" block
+    And I navigate to "Course completion" node in "Course administration"
+    And I expand all fieldsets
+    And I set the following fields to these values:
+      | Test page name | 1 |
+    And I press "Save changes"
+    Then I should see "You are currently not being tracked by completion in this course" in the "Course completion status" "block"
diff --git a/completionstatus/tests/behat/block_completionstatus_activity_completion.feature b/completionstatus/tests/behat/block_completionstatus_activity_completion.feature
new file mode 100644
index 0000000..d41fe98
--- /dev/null
+++ b/completionstatus/tests/behat/block_completionstatus_activity_completion.feature
@@ -0,0 +1,70 @@
+@block @block_completionstatus
+Feature: Enable Block Completion in a course using activity completion
+  In order to view the completion block in a course
+  As a teacher
+  I can add completion block to a course and set up activity completion
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+      | student1 | Student | 1 | student1@example.com | S1 |
+    And the following "courses" exist:
+      | fullname | shortname | category | enablecompletion |
+      | Course 1 | C1        | 0        | 1                |
+    And the following "course enrolments" exist:
+      | user     | course | role           |
+      | teacher1 | C1     | editingteacher |
+      | student1 | C1     | student        |
+    And the following "activities" exist:
+      | activity | course | idnumber | name           | intro                 |
+      | page     | C1     | page1    | Test page name | Test page description |
+
+  Scenario: Add the block to a the course and add course completion items
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I follow "Test page name"
+    And I navigate to "Edit settings" in current page administration
+    And I set the following fields to these values:
+      | Completion tracking | Show activity as complete when conditions are met |
+      | Require view | 1 |
+    And I press "Save and return to course"
+    And I add the "Course completion status" block
+    And I navigate to "Course completion" node in "Course administration"
+    And I expand all fieldsets
+    And I set the following fields to these values:
+      | Test page name | 1 |
+    And I press "Save changes"
+    And I log out
+    When I log in as "student1"
+    And I am on "Course 1" course homepage
+    Then I should see "Status: Not yet started" in the "Course completion status" "block"
+    And I should see "0 of 1" in the "Activity completion" "table_row"
+
+  Scenario: Add the block to a the course and add course completion items
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I follow "Test page name"
+    And I navigate to "Edit settings" in current page administration
+    And I set the following fields to these values:
+      | Completion tracking | Show activity as complete when conditions are met |
+      | Require view | 1 |
+    And I press "Save and return to course"
+    And I add the "Course completion status" block
+    And I navigate to "Course completion" node in "Course administration"
+    And I expand all fieldsets
+    And I set the following fields to these values:
+      | Test page name | 1 |
+    And I press "Save changes"
+    And I log out
+    When I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I follow "Test page name"
+    And I am on "Course 1" course homepage
+    Then I should see "Status: Pending" in the "Course completion status" "block"
+    And I should see "0 of 1" in the "Activity completion" "table_row"
+    And I trigger cron
+    And I am on "Course 1" course homepage
+    And I should see "1 of 1" in the "Activity completion" "table_row"
+    And I follow "More details"
+    And I should see "Yes" in the "Activity completion" "table_row"
diff --git a/completionstatus/tests/behat/block_completionstatus_manual_other.feature b/completionstatus/tests/behat/block_completionstatus_manual_other.feature
new file mode 100644
index 0000000..c021914
--- /dev/null
+++ b/completionstatus/tests/behat/block_completionstatus_manual_other.feature
@@ -0,0 +1,103 @@
+@block @block_completionstatus
+Feature: Enable Block Completion in a course using manual completion by others
+  In order to view the completion block in a course
+  As a teacher
+  I can add completion block to a course and set up manual completion by others
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+      | teacher2 | Teacher | 2 | teacher1@example.com | T2 |
+      | student1 | Student | 1 | student1@example.com | S1 |
+    And the following "courses" exist:
+      | fullname | shortname | category | enablecompletion |
+      | Course 1 | C1        | 0        | 1                |
+    And the following "course enrolments" exist:
+      | user     | course | role           |
+      | teacher1 | C1     | editingteacher |
+      | teacher2 | C1     | teacher        |
+      | student1 | C1     | student        |
+
+  Scenario: Add the block to a the course and mark a student complete.
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Course completion status" block
+    And I navigate to "Course completion" node in "Course administration"
+    And I expand all fieldsets
+    And I set the following fields to these values:
+      | Teacher | 1 |
+    And I press "Save changes"
+    And I log out
+    When I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "Status: Not yet started" in the "Course completion status" "block"
+    And I should see "No" in the "Teacher" "table_row"
+    And I log out
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage
+    And I navigate to "Course completion" node in "Course administration > Reports"
+    And I follow "Click to mark user complete"
+    # Running completion task just after clicking sometimes fail, as record
+    # should be created before the task runs.
+    And I wait "1" seconds
+    And I run the scheduled task "core\task\completion_regular_task"
+    And I am on site homepage
+    And I log out
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    Then I should see "Status: Complete" in the "Course completion status" "block"
+    And I should see "Yes" in the "Teacher" "table_row"
+    And I follow "More details"
+    And I should see "Yes" in the "Marked complete by Teacher" "table_row"
+
+  Scenario: Add the block to a the course and require multiple roles to mark a student complete.
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Course completion status" block
+    And I navigate to "Course completion" node in "Course administration"
+    And I expand all fieldsets
+    And I set the following fields to these values:
+      | Teacher             | 1 |
+      | Non-editing teacher | 1 |
+      | id_role_aggregation | ALL selected roles to mark when the condition is met |
+    And I press "Save changes"
+    And I log out
+    When I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "Status: Not yet started" in the "Course completion status" "block"
+    And I should see "No" in the "Teacher" "table_row"
+    And I should see "No" in the "Non-editing teacher" "table_row"
+    And I log out
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage
+    And I navigate to "Course completion" node in "Course administration > Reports"
+    And I follow "Click to mark user complete"
+    And I log out
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "Status: In progress" in the "Course completion status" "block"
+    And I should see "Yes" in the "Teacher" "table_row"
+    And I should see "No" in the "Non-editing teacher" "table_row"
+    And I follow "More details"
+    And I should see "Yes" in the "Marked complete by Teacher" "table_row"
+    And I should see "No" in the "Marked complete by Non-editing teacher" "table_row"
+    And I log out
+    And I log in as "teacher2"
+    And I am on "Course 1" course homepage
+    And I navigate to "Course completion" node in "Course administration > Reports"
+    And I follow "Click to mark user complete"
+    # Running completion task just after clicking sometimes fail, as record
+    # should be created before the task runs.
+    And I wait "1" seconds
+    And I run the scheduled task "core\task\completion_regular_task"
+    And I am on site homepage
+    And I log out
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    Then I should see "Status: Complete" in the "Course completion status" "block"
+    And I should see "Yes" in the "Teacher" "table_row"
+    And I should see "Yes" in the "Non-editing teacher" "table_row"
+    And I follow "More details"
+    And I should see "Yes" in the "Marked complete by Teacher" "table_row"
+    And I should see "Yes" in the "Marked complete by Non-editing teacher" "table_row"
diff --git a/completionstatus/tests/behat/block_completionstatus_manual_self.feature b/completionstatus/tests/behat/block_completionstatus_manual_self.feature
new file mode 100644
index 0000000..d9b73c5
--- /dev/null
+++ b/completionstatus/tests/behat/block_completionstatus_manual_self.feature
@@ -0,0 +1,45 @@
+@block @block_completionstatus @block_selfcompletion
+Feature: Enable Block Completion in a course using manual self completion
+  In order to view the completion block in a course
+  As a teacher
+  I can add completion block to a course and set up manual self completion
+
+  Scenario: Add the block to a the course and manually complete the course
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+      | student1 | Student | 1 | student1@example.com | S1 |
+    And the following "courses" exist:
+      | fullname | shortname | category | enablecompletion |
+      | Course 1 | C1        | 0        | 1                |
+    And the following "course enrolments" exist:
+      | user     | course | role           |
+      | teacher1 | C1     | editingteacher |
+      | student1 | C1     | student        |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Course completion status" block
+    And I add the "Self completion" block
+    And I navigate to "Course completion" node in "Course administration"
+    And I expand all fieldsets
+    And I set the following fields to these values:
+      | id_criteria_self | 1 |
+    And I press "Save changes"
+    And I log out
+    When I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "Status: Not yet started" in the "Course completion status" "block"
+    And I should see "No" in the "Self completion" "table_row"
+    And I follow "Complete course"
+    And I should see "Confirm self completion"
+    And I press "Yes"
+    And I should see "Status: In progress" in the "Course completion status" "block"
+    # Running completion task just after clicking sometimes fail, as record
+    # should be created before the task runs.
+    And I wait "1" seconds
+    And I run the scheduled task "core\task\completion_regular_task"
+    And I am on "Course 1" course homepage
+    Then I should see "Status: Complete" in the "Course completion status" "block"
+    And I should see "Yes" in the "Self completion" "table_row"
+    And I follow "More details"
+    And I should see "Yes" in the "Self completion" "table_row"
diff --git a/completionstatus/version.php b/completionstatus/version.php
new file mode 100644
index 0000000..1009943
--- /dev/null
+++ b/completionstatus/version.php
@@ -0,0 +1,31 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version info
+ *
+ * @package    block_completionstatus
+ * @copyright  2009 Catalyst IT Ltd
+ * @author     Aaron Barnes <aaronb@catalyst.net.nz>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version      = 2018051400; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires     = 2018050800; // Requires this Moodle version.
+$plugin->component    = 'block_completionstatus';
+$plugin->dependencies = array('report_completion' => 2018050800);
diff --git a/course_list/block_course_list.php b/course_list/block_course_list.php
new file mode 100644
index 0000000..10cbf23
--- /dev/null
+++ b/course_list/block_course_list.php
@@ -0,0 +1,177 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Course list block.
+ *
+ * @package    block_course_list
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+include_once($CFG->dirroot . '/course/lib.php');
+include_once($CFG->libdir . '/coursecatlib.php');
+
+class block_course_list extends block_list {
+    function init() {
+        $this->title = get_string('pluginname', 'block_course_list');
+    }
+
+    function has_config() {
+        return true;
+    }
+
+    function get_content() {
+        global $CFG, $USER, $DB, $OUTPUT;
+
+        if($this->content !== NULL) {
+            return $this->content;
+        }
+
+        $this->content = new stdClass;
+        $this->content->items = array();
+        $this->content->icons = array();
+        $this->content->footer = '';
+
+        $icon = $OUTPUT->pix_icon('i/course', get_string('course'));
+
+        $adminseesall = true;
+        if (isset($CFG->block_course_list_adminview)) {
+           if ( $CFG->block_course_list_adminview == 'own'){
+               $adminseesall = false;
+           }
+        }
+
+        if (empty($CFG->disablemycourses) and isloggedin() and !isguestuser() and
+          !(has_capability('moodle/course:update', context_system::instance()) and $adminseesall)) {    // Just print My Courses
+            if ($courses = enrol_get_my_courses()) {
+                foreach ($courses as $course) {
+                    $coursecontext = context_course::instance($course->id);
+                    $linkcss = $course->visible ? "" : " class=\"dimmed\" ";
+                    $this->content->items[]="<a $linkcss title=\"" . format_string($course->shortname, true, array('context' => $coursecontext)) . "\" ".
+                               "href=\"$CFG->wwwroot/course/view.php?id=$course->id\">".$icon.format_string(get_course_display_name_for_list($course)). "</a>";
+                }
+                $this->title = get_string('mycourses');
+            /// If we can update any course of the view all isn't hidden, show the view all courses link
+                if (has_capability('moodle/course:update', context_system::instance()) || empty($CFG->block_course_list_hideallcourseslink)) {
+                    $this->content->footer = "<a href=\"$CFG->wwwroot/course/index.php\">".get_string("fulllistofcourses")."</a> ...";
+                }
+            }
+            $this->get_remote_courses();
+            if ($this->content->items) { // make sure we don't return an empty list
+                return $this->content;
+            }
+        }
+
+        $categories = coursecat::get(0)->get_children();  // Parent = 0   ie top-level categories only
+        if ($categories) {   //Check we have categories
+            if (count($categories) > 1 || (count($categories) == 1 && $DB->count_records('course') > 200)) {     // Just print top level category links
+                foreach ($categories as $category) {
+                    $categoryname = $category->get_formatted_name();
+                    $linkcss = $category->visible ? "" : " class=\"dimmed\" ";
+                    $this->content->items[]="<a $linkcss href=\"$CFG->wwwroot/course/index.php?categoryid=$category->id\">".$icon . $categoryname . "</a>";
+                }
+            /// If we can update any course of the view all isn't hidden, show the view all courses link
+                if (has_capability('moodle/course:update', context_system::instance()) || empty($CFG->block_course_list_hideallcourseslink)) {
+                    $this->content->footer .= "<a href=\"$CFG->wwwroot/course/index.php\">".get_string('fulllistofcourses').'</a> ...';
+                }
+                $this->title = get_string('categories');
+            } else {                          // Just print course names of single category
+                $category = array_shift($categories);
+                $courses = get_courses($category->id);
+
+                if ($courses) {
+                    foreach ($courses as $course) {
+                        $coursecontext = context_course::instance($course->id);
+                        $linkcss = $course->visible ? "" : " class=\"dimmed\" ";
+
+                        $this->content->items[]="<a $linkcss title=\""
+                                   . format_string($course->shortname, true, array('context' => $coursecontext))."\" ".
+                                   "href=\"$CFG->wwwroot/course/view.php?id=$course->id\">"
+                                   .$icon. format_string(get_course_display_name_for_list($course), true, array('context' => context_course::instance($course->id))) . "</a>";
+                    }
+                /// If we can update any course of the view all isn't hidden, show the view all courses link
+                    if (has_capability('moodle/course:update', context_system::instance()) || empty($CFG->block_course_list_hideallcourseslink)) {
+                        $this->content->footer .= "<a href=\"$CFG->wwwroot/course/index.php\">".get_string('fulllistofcourses').'</a> ...';
+                    }
+                    $this->get_remote_courses();
+                } else {
+
+                    $this->content->icons[] = '';
+                    $this->content->items[] = get_string('nocoursesyet');
+                    if (has_capability('moodle/course:create', context_coursecat::instance($category->id))) {
+                        $this->content->footer = '<a href="'.$CFG->wwwroot.'/course/edit.php?category='.$category->id.'">'.get_string("addnewcourse").'</a> ...';
+                    }
+                    $this->get_remote_courses();
+                }
+                $this->title = get_string('courses');
+            }
+        }
+
+        return $this->content;
+    }
+
+    function get_remote_courses() {
+        global $CFG, $USER, $OUTPUT;
+
+        if (!is_enabled_auth('mnet')) {
+            // no need to query anything remote related
+            return;
+        }
+
+        $icon = $OUTPUT->pix_icon('i/mnethost', get_string('host', 'mnet'));
+
+        // shortcut - the rest is only for logged in users!
+        if (!isloggedin() || isguestuser()) {
+            return false;
+        }
+
+        if ($courses = get_my_remotecourses()) {
+            $this->content->items[] = get_string('remotecourses','mnet');
+            $this->content->icons[] = '';
+            foreach ($courses as $course) {
+                $this->content->items[]="<a title=\"" . format_string($course->shortname, true) . "\" ".
+                    "href=\"{$CFG->wwwroot}/auth/mnet/jump.php?hostid={$course->hostid}&amp;wantsurl=/course/view.php?id={$course->remoteid}\">"
+                    .$icon. format_string(get_course_display_name_for_list($course)) . "</a>";
+            }
+            // if we listed courses, we are done
+            return true;
+        }
+
+        if ($hosts = get_my_remotehosts()) {
+            $this->content->items[] = get_string('remotehosts', 'mnet');
+            $this->content->icons[] = '';
+            foreach($USER->mnet_foreign_host_array as $somehost) {
+                $this->content->items[] = $somehost['count'].get_string('courseson','mnet').'<a title="'.$somehost['name'].'" href="'.$somehost['url'].'">'.$icon.$somehost['name'].'</a>';
+            }
+            // if we listed hosts, done
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns the role that best describes the course list block.
+     *
+     * @return string
+     */
+    public function get_aria_role() {
+        return 'navigation';
+    }
+}
+
+
diff --git a/course_list/classes/privacy/provider.php b/course_list/classes/privacy/provider.php
new file mode 100644
index 0000000..37066fd
--- /dev/null
+++ b/course_list/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_course_list.
+ *
+ * @package    block_course_list
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_course_list\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_course_list implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/course_list/db/access.php b/course_list/db/access.php
new file mode 100644
index 0000000..5d594fe
--- /dev/null
+++ b/course_list/db/access.php
@@ -0,0 +1,51 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Course list block caps.
+ *
+ * @package    block_course_list
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/course_list:myaddinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/my:manageblocks'
+    ),
+
+    'block/course_list:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/course_list/lang/en/block_course_list.php b/course_list/lang/en/block_course_list.php
new file mode 100644
index 0000000..1cd9244
--- /dev/null
+++ b/course_list/lang/en/block_course_list.php
@@ -0,0 +1,34 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_course_list', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_course_list
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['adminview'] = 'Admin view';
+$string['allcourses'] = 'Admin user sees all courses';
+$string['configadminview'] = 'What should the admin see in the course list block?';
+$string['confighideallcourseslink'] = 'Remove the \'All courses\' link under the list of courses. (This setting does not affect the admin view.)';
+$string['course_list:addinstance'] = 'Add a new courses block';
+$string['course_list:myaddinstance'] = 'Add a new courses block to Dashboard';
+$string['hideallcourseslink'] = 'Hide \'All courses\' link';
+$string['owncourses'] = 'Admin user sees own courses';
+$string['pluginname'] = 'Courses';
+$string['privacy:metadata'] = 'The Courses block only shows data about courses and does not store any data itself.';
diff --git a/course_list/settings.php b/course_list/settings.php
new file mode 100644
index 0000000..0d8a9ef
--- /dev/null
+++ b/course_list/settings.php
@@ -0,0 +1,37 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Course list block settings
+ *
+ * @package    block_course_list
+ * @copyright  2007 Petr Skoda
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die;
+
+if ($ADMIN->fulltree) {
+    $options = array('all'=>get_string('allcourses', 'block_course_list'), 'own'=>get_string('owncourses', 'block_course_list'));
+
+    $settings->add(new admin_setting_configselect('block_course_list_adminview', get_string('adminview', 'block_course_list'),
+                       get_string('configadminview', 'block_course_list'), 'all', $options));
+
+    $settings->add(new admin_setting_configcheckbox('block_course_list_hideallcourseslink', get_string('hideallcourseslink', 'block_course_list'),
+                       get_string('confighideallcourseslink', 'block_course_list'), 0));
+}
+
+
diff --git a/course_list/styles.css b/course_list/styles.css
new file mode 100644
index 0000000..b94fe89
--- /dev/null
+++ b/course_list/styles.css
@@ -0,0 +1,7 @@
+.block_course_list .footer {
+    margin-top: 5px;
+}
+
+.block_course_list .content li {
+    margin-bottom: .3em;
+}
diff --git a/course_list/tests/behat/block_course_list_category.feature b/course_list/tests/behat/block_course_list_category.feature
new file mode 100644
index 0000000..3c03721
--- /dev/null
+++ b/course_list/tests/behat/block_course_list_category.feature
@@ -0,0 +1,78 @@
+@block @block_course_list
+Feature: Enable the course_list block on a category page and view it's contents
+  In order to enable the course list block on a category page
+  As an admin
+  I can add the course list block to a category page
+
+  Background:
+    Given the following "categories" exist:
+      | name        | category | idnumber |
+      | Category 1  | 0        | CAT1     |
+      | Category 2  | 0        | CAT2     |
+      | Category 3  | CAT2     | CAT3     |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1        | 0        |
+      | Course 2 | C2        | CAT1     |
+      | Course 3 | C3        | CAT2     |
+      | Course 4 | C4        | CAT3     |
+    And the following "users" exist:
+      | username | firstname | lastname | email                |
+      | teacher1 | Teacher   | First    | teacher1@example.com |
+    And the following "course enrolments" exist:
+      | user | course | role           |
+      | teacher1 | C1 | editingteacher |
+      | teacher1 | C2 | editingteacher |
+      | teacher1 | C3 | editingteacher |
+
+  Scenario: Add the course list block on category page and navigate to the course listing
+    Given I log in as "admin"
+    And I am on site homepage
+    And I turn editing mode on
+    And I am on course index
+    And I follow "Miscellaneous"
+    And I add the "Courses" block
+    And I log out
+    When I log in as "teacher1"
+    And I am on course index
+    And I follow "Miscellaneous"
+    Then I should see "Course 1" in the "My courses" "block"
+    And I should see "Course 2" in the "My courses" "block"
+    And I should see "Course 3" in the "My courses" "block"
+    And I should not see "Course 4" in the "My courses" "block"
+    And I follow "All courses"
+    And I should see "Miscellaneous"
+
+  Scenario: Add the course list block on category page and navigate to another course
+    Given I log in as "admin"
+    And I am on site homepage
+    And I turn editing mode on
+    And I am on course index
+    And I follow "Miscellaneous"
+    And I add the "Courses" block
+    And I log out
+    When I log in as "teacher1"
+    And I am on course index
+    And I follow "Miscellaneous"
+    Then I should see "Course 1" in the "My courses" "block"
+    And I should see "Course 2" in the "My courses" "block"
+    And I should see "Course 3" in the "My courses" "block"
+    And I should not see "Course 4" in the "My courses" "block"
+    And I am on "Course 3" course homepage
+    And I should see "Course 3"
+
+  Scenario: Add the course list block on category page and view as an admin
+    Given I log in as "admin"
+    And I am on site homepage
+    And I turn editing mode on
+    And I am on course index
+    And I follow "Miscellaneous"
+    When I add the "Courses" block
+    Then I should see "Miscellaneous" in the "Course categories" "block"
+    And I should see "Category 1" in the "Course categories" "block"
+    And I should see "Category 2" in the "Course categories" "block"
+    And I should not see "Category 3" in the "Course categories" "block"
+    And I should not see "Course 1" in the "Course categories" "block"
+    And I should not see "Course 2" in the "Course categories" "block"
+    And I follow "All courses"
+    And I should see "Miscellaneous"
diff --git a/course_list/tests/behat/block_course_list_course.feature b/course_list/tests/behat/block_course_list_course.feature
new file mode 100644
index 0000000..8a14d9e
--- /dev/null
+++ b/course_list/tests/behat/block_course_list_course.feature
@@ -0,0 +1,87 @@
+@block @block_course_list
+Feature: Enable the course_list block on a course page and view it's contents
+  In order to enable the course list block on an course page
+  As a teacher
+  I can add the course list block to a course page
+
+  Background:
+    Given the following "categories" exist:
+      | name        | category | idnumber |
+      | Category 1  | 0        | CAT1     |
+      | Category 2  | 0        | CAT2     |
+      | Category 3  | CAT2     | CAT3     |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1        | 0        |
+      | Course 2 | C2        | CAT1     |
+      | Course 3 | C3        | CAT2     |
+      | Course 4 | C4        | CAT3     |
+    And the following "users" exist:
+      | username | firstname | lastname | email                |
+      | teacher1 | Teacher   | First    | teacher1@example.com |
+    And the following "course enrolments" exist:
+      | user | course | role           |
+      | teacher1 | C1 | editingteacher |
+      | teacher1 | C2 | editingteacher |
+      | teacher1 | C3 | editingteacher |
+
+  Scenario: Add the course list block on course page and navigate to the course listing
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    When I add the "Courses" block
+    Then I should see "Course 1" in the "My courses" "block"
+    And I should see "Course 2" in the "My courses" "block"
+    And I should see "Course 3" in the "My courses" "block"
+    And I should not see "Course 4" in the "My courses" "block"
+    And I follow "All courses"
+    And I should see "Miscellaneous"
+
+  Scenario: Add the course list block on course page and navigate to another course
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    When I add the "Courses" block
+    Then I should see "Course 1" in the "My courses" "block"
+    And I should see "Course 2" in the "My courses" "block"
+    And I should see "Course 3" in the "My courses" "block"
+    And I should not see "Course 4" in the "My courses" "block"
+    And I am on "Course 3" course homepage
+    And I should see "Course 3"
+
+  Scenario: Add the course list block on course page and view as an admin
+    Given I log in as "admin"
+    And I am on "Course 1" course homepage with editing mode on
+    When I add the "Courses" block
+    Then I should see "Miscellaneous" in the "Course categories" "block"
+    And I should see "Category 1" in the "Course categories" "block"
+    And I should see "Category 2" in the "Course categories" "block"
+    And I should not see "Category 3" in the "Course categories" "block"
+    And I should not see "Course 1" in the "Course categories" "block"
+    And I should not see "Course 2" in the "Course categories" "block"
+    And I follow "All courses"
+    And I should see "Miscellaneous"
+
+  Scenario: View the course list block on course page with hide all courses link enabled
+    Given the following config values are set as admin:
+      | block_course_list_hideallcourseslink | 1 |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    When I add the "Courses" block
+    Then I should not see "All courses" in the "My courses" "block"
+
+  Scenario: View the course list block on course page with admin sees own course enabled
+    Given the following config values are set as admin:
+      | block_course_list_adminview | own |
+    And the following "course enrolments" exist:
+      | user | course | role           |
+      | admin | C1 | editingteacher |
+    And I log in as "admin"
+    And I am on "Course 1" course homepage with editing mode on
+    When I add the "Courses" block
+    Then I should not see "Miscellaneous" in the "My courses" "block"
+    And I should not see "Category 1" in the "My courses" "block"
+    And I should not see "Category 2" in the "My courses" "block"
+    And I should not see "Category 3" in the "My courses" "block"
+    And I should see "Course 1" in the "My courses" "block"
+    And I should not see "Course 2" in the "My courses" "block"
+    And I follow "All courses"
+    And I should see "Miscellaneous"
diff --git a/course_list/tests/behat/block_course_list_dashboard.feature b/course_list/tests/behat/block_course_list_dashboard.feature
new file mode 100644
index 0000000..f31ae94
--- /dev/null
+++ b/course_list/tests/behat/block_course_list_dashboard.feature
@@ -0,0 +1,61 @@
+@block @block_course_list
+Feature: Enable the course_list block on the dashboard and view it's contents
+  In order to enable the course list block on the dashboard
+  As a user
+  I can add the course list block to the dashboard
+
+  Background:
+    Given the following "categories" exist:
+      | name        | category | idnumber |
+      | Category 1  | 0        | CAT1     |
+      | Category 2  | 0        | CAT2     |
+      | Category 3  | CAT2     | CAT3     |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1        | 0        |
+      | Course 2 | C2        | CAT1     |
+      | Course 3 | C3        | CAT2     |
+      | Course 4 | C4        | CAT3     |
+    And the following "users" exist:
+      | username | firstname | lastname | email                |
+      | teacher1 | Teacher   | First    | teacher1@example.com |
+    And the following "course enrolments" exist:
+      | user | course | role           |
+      | teacher1 | C1 | editingteacher |
+      | teacher1 | C2 | editingteacher |
+      | teacher1 | C3 | editingteacher |
+
+  Scenario: Add the course list block on the dashboard and navigate to the course listing
+    Given I log in as "teacher1"
+    And I press "Customise this page"
+    When I add the "Courses" block
+    Then I should see "Course 1" in the "My courses" "block"
+    And I should see "Course 2" in the "My courses" "block"
+    And I should see "Course 3" in the "My courses" "block"
+    And I should not see "Course 4" in the "My courses" "block"
+    And I follow "All courses"
+    And I should see "Miscellaneous"
+
+  Scenario: Add the course list block on the dashboard and navigate to another course
+    Given I log in as "teacher1"
+    And I press "Customise this page"
+    When I add the "Courses" block
+    Then I should see "Course 1" in the "My courses" "block"
+    And I should see "Course 2" in the "My courses" "block"
+    And I should see "Course 3" in the "My courses" "block"
+    And I should not see "Course 4" in the "My courses" "block"
+    And I am on "Course 3" course homepage
+    And I should see "Course 3"
+
+  Scenario: Add the course list block on the dashboard and view as an admin
+    Given I log in as "admin"
+    And I press "Customise this page"
+    When I add the "Courses" block
+    Then I should see "Miscellaneous" in the "Course categories" "block"
+    And I should see "Category 1" in the "Course categories" "block"
+    And I should see "Category 2" in the "Course categories" "block"
+    And I should not see "Category 3" in the "Course categories" "block"
+    And I should not see "Course 1" in the "Course categories" "block"
+    And I should not see "Course 2" in the "Course categories" "block"
+    And I follow "All courses"
+    And I should see "Miscellaneous"
diff --git a/course_list/tests/behat/block_course_list_frontpage.feature b/course_list/tests/behat/block_course_list_frontpage.feature
new file mode 100644
index 0000000..b10cf27
--- /dev/null
+++ b/course_list/tests/behat/block_course_list_frontpage.feature
@@ -0,0 +1,86 @@
+@block @block_course_list
+Feature: Enable the course_list block on the frontpage and view it's contents
+  In order to enable the course list block on the frontpage
+  As an admin
+  I can add the course list block to the frontpage
+
+  Background:
+    Given the following "categories" exist:
+      | name        | category | idnumber |
+      | Category 1  | 0        | CAT1     |
+      | Category 2  | 0        | CAT2     |
+      | Category 3  | CAT2     | CAT3     |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1        | 0        |
+      | Course 2 | C2        | CAT1     |
+      | Course 3 | C3        | CAT2     |
+      | Course 4 | C4        | CAT3     |
+    And the following "users" exist:
+      | username | firstname | lastname | email                |
+      | teacher1 | Teacher   | First    | teacher1@example.com |
+    And the following "course enrolments" exist:
+      | user | course | role           |
+      | teacher1 | C1 | editingteacher |
+      | teacher1 | C2 | editingteacher |
+      | teacher1 | C3 | editingteacher |
+
+  Scenario: Add the course list block on the frontpage and navigate to the course listing
+    Given I log in as "admin"
+    And I am on site homepage
+    And I navigate to "Turn editing on" node in "Front page settings"
+    And I add the "Courses" block
+    And I log out
+    When I log in as "teacher1"
+    And I am on site homepage
+    Then I should see "Course 1" in the "My courses" "block"
+    And I should see "Course 2" in the "My courses" "block"
+    And I should see "Course 3" in the "My courses" "block"
+    And I should not see "Course 4" in the "My courses" "block"
+    And I follow "All courses"
+    And I should see "Miscellaneous"
+
+  Scenario: Add the course list block on the frontpage page and navigate to another course
+    Given I log in as "admin"
+    And I am on site homepage
+    And I navigate to "Turn editing on" node in "Front page settings"
+    And I add the "Courses" block
+    And I log out
+    When I log in as "teacher1"
+    And I am on site homepage
+    Then I should see "Course 1" in the "My courses" "block"
+    And I should see "Course 2" in the "My courses" "block"
+    And I should see "Course 3" in the "My courses" "block"
+    And I should not see "Course 4" in the "My courses" "block"
+    And I am on "Course 3" course homepage
+    And I should see "Course 3"
+
+  Scenario: Add the course list block on the frontpage page and view as an admin
+    Given I log in as "admin"
+    And I am on site homepage
+    And I navigate to "Turn editing on" node in "Front page settings"
+    When I add the "Courses" block
+    Then I should see "Miscellaneous" in the "Course categories" "block"
+    And I should see "Category 1" in the "Course categories" "block"
+    And I should see "Category 2" in the "Course categories" "block"
+    And I should not see "Category 3" in the "Course categories" "block"
+    And I should not see "Course 1" in the "Course categories" "block"
+    And I should not see "Course 2" in the "Course categories" "block"
+    And I follow "All courses"
+    And I should see "Miscellaneous"
+
+  Scenario: Add the course list block on the frontpage page and view as a guest
+    Given I log in as "admin"
+    And I am on site homepage
+    And I navigate to "Turn editing on" node in "Front page settings"
+    And I add the "Courses" block
+    And I log out
+    When I log in as "guest"
+    Then I should see "Miscellaneous" in the "Course categories" "block"
+    And I should see "Category 1" in the "Course categories" "block"
+    And I should see "Category 2" in the "Course categories" "block"
+    And I should not see "Category 3" in the "Course categories" "block"
+    And I should not see "Course 1" in the "Course categories" "block"
+    And I should not see "Course 2" in the "Course categories" "block"
+    And I follow "All courses"
+    And I should see "Miscellaneous"
diff --git a/course_list/version.php b/course_list/version.php
new file mode 100644
index 0000000..35e5580
--- /dev/null
+++ b/course_list/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_course_list
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_course_list'; // Full name of the plugin (used for diagnostics)
diff --git a/course_summary/block_course_summary.php b/course_summary/block_course_summary.php
new file mode 100644
index 0000000..516c360
--- /dev/null
+++ b/course_summary/block_course_summary.php
@@ -0,0 +1,79 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Course summary block
+ *
+ * @package    block_course_summary
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class block_course_summary extends block_base {
+
+    /**
+     * @var bool Flag to indicate whether the header should be hidden or not.
+     */
+    private $headerhidden = true;
+
+    function init() {
+        $this->title = get_string('pluginname', 'block_course_summary');
+    }
+
+    function applicable_formats() {
+        return array('all' => true, 'mod' => false, 'tag' => false, 'my' => false);
+    }
+
+    function specialization() {
+        // Page type starts with 'course-view' and the page's course ID is not equal to the site ID.
+        if (strpos($this->page->pagetype, PAGE_COURSE_VIEW) === 0 && $this->page->course->id != SITEID) {
+            $this->title = get_string('coursesummary', 'block_course_summary');
+            $this->headerhidden = false;
+        }
+    }
+
+    function get_content() {
+        global $CFG, $OUTPUT;
+
+        require_once($CFG->libdir . '/filelib.php');
+
+        if($this->content !== NULL) {
+            return $this->content;
+        }
+
+        if (empty($this->instance)) {
+            return '';
+        }
+
+        $this->content = new stdClass();
+        $options = new stdClass();
+        $options->noclean = true;    // Don't clean Javascripts etc
+        $options->overflowdiv = true;
+        $context = context_course::instance($this->page->course->id);
+        $this->page->course->summary = file_rewrite_pluginfile_urls($this->page->course->summary, 'pluginfile.php', $context->id, 'course', 'summary', NULL);
+        $this->content->text = format_text($this->page->course->summary, $this->page->course->summaryformat, $options);
+        $this->content->footer = '';
+
+        return $this->content;
+    }
+
+    function hide_header() {
+        return $this->headerhidden;
+    }
+
+}
+
+
diff --git a/course_summary/classes/privacy/provider.php b/course_summary/classes/privacy/provider.php
new file mode 100644
index 0000000..4023e49
--- /dev/null
+++ b/course_summary/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_course_summary.
+ *
+ * @package    block_course_summary
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_course_summary\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_course_summary implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/course_summary/db/access.php b/course_summary/db/access.php
new file mode 100644
index 0000000..a1e4265
--- /dev/null
+++ b/course_summary/db/access.php
@@ -0,0 +1,41 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Course summary block caps.
+ *
+ * @package    block_course_summary
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/course_summary:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/course_summary/db/upgrade.php b/course_summary/db/upgrade.php
new file mode 100644
index 0000000..763a538
--- /dev/null
+++ b/course_summary/db/upgrade.php
@@ -0,0 +1,61 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file keeps track of upgrades to the course summary block
+ *
+ * Sometimes, changes between versions involve alterations to database structures
+ * and other major things that may break installations.
+ *
+ * The upgrade function in this file will attempt to perform all the necessary
+ * actions to upgrade your older installation to the current version.
+ *
+ * If there's something it cannot do itself, it will tell you what you need to do.
+ *
+ * The commands in here will all be database-neutral, using the methods of
+ * database_manager class
+ *
+ * Please do not forget to use upgrade_set_timeout()
+ * before any action that may take longer time to finish.
+ *
+ * @since Moodle 2.0
+ * @package block_course_summary
+ * @copyright 2012 Mark Nelson <markn@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Handles upgrading instances of this block.
+ *
+ * @param int $oldversion
+ * @param object $block
+ */
+function xmldb_block_course_summary_upgrade($oldversion, $block) {
+    global $CFG;
+
+    // Automatically generated Moodle v3.2.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.3.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.4.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    return true;
+}
diff --git a/course_summary/lang/en/block_course_summary.php b/course_summary/lang/en/block_course_summary.php
new file mode 100644
index 0000000..902dd5f
--- /dev/null
+++ b/course_summary/lang/en/block_course_summary.php
@@ -0,0 +1,29 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_course_summary', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_course_summary
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['coursesummary'] = 'Course summary';
+$string['course_summary:addinstance'] = 'Add a new course/site summary block';
+$string['pluginname'] = 'Course/site summary';
+$string['privacy:metadata'] = 'The Course/site summary block only shows information about courses and does not store data itself.';
diff --git a/course_summary/styles.css b/course_summary/styles.css
new file mode 100644
index 0000000..5d37beb
--- /dev/null
+++ b/course_summary/styles.css
@@ -0,0 +1,7 @@
+.block_course_summary .content {
+    padding: 10px;
+}
+
+.block_course_summary .editbutton {
+    text-align: right;
+}
\ No newline at end of file
diff --git a/course_summary/tests/behat/block_course_summary_course.feature b/course_summary/tests/behat/block_course_summary_course.feature
new file mode 100644
index 0000000..3b4b32c
--- /dev/null
+++ b/course_summary/tests/behat/block_course_summary_course.feature
@@ -0,0 +1,36 @@
+@block @block_course_summary
+Feature: Course summary block used in a course
+  In order to help particpants know the summary of a course
+  As a teacher
+  I can add the course summary block to a course page
+
+  Background:
+    Given the following "courses" exist:
+      | fullname | shortname | summary | category |
+      | Course 1 | C101      | Proved the course summary block works! |0        |
+    And the following "users" exist:
+      | username    | firstname | lastname | email            |
+      | student1    | Sam       | Student  | student1@example.com |
+      | teacher1    | Teacher   | One      | teacher1@example.com |
+    And the following "course enrolments" exist:
+      | user        | course | role    |
+      | student1    | C101   | student |
+      | teacher1    | C101   | editingteacher |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Course/site summary" block
+    And I log out
+
+  Scenario: Student can view course summary
+    When I log in as "student1"
+    And I am on "Course 1" course homepage
+    Then "Course summary" "block" should exist
+    And I should see "Course summary" in the "Course summary" "block"
+    And I should see "Proved the course summary block works!" in the "Course summary" "block"
+
+  Scenario: Teacher can not see edit icon when edit mode is off
+    When I log in as "teacher1"
+    And I am on "Course 1" course homepage
+    Then I should see "Proved the course summary block works!" in the "Course summary" "block"
+    And I should see "Course summary" in the "Course summary" "block"
+    And "Edit" "link" should not exist in the "Course summary" "block"
diff --git a/course_summary/tests/behat/block_course_summary_frontpage.feature b/course_summary/tests/behat/block_course_summary_frontpage.feature
new file mode 100644
index 0000000..a48fb70
--- /dev/null
+++ b/course_summary/tests/behat/block_course_summary_frontpage.feature
@@ -0,0 +1,30 @@
+@block @block_course_summary
+Feature: Course summary block used on the frontpage
+  In order to help particpants know the summary of a site
+  As admin
+  I can use the course summary block on the frontpage
+
+  Background:
+    Given I log in as "admin"
+    And I am on site homepage
+    And I turn editing mode on
+    And I add the "Course/site summary" block
+    And I navigate to "Edit settings" node in "Front page settings"
+    And I set the following fields to these values:
+      | summary | Proved the summary block works! |
+    And I press "Save changes"
+    And I log out
+    # The course summary block a default front page block, so no need to add it.
+
+  Scenario: Guest can view site summary
+    When I am on site homepage
+    Then "Course/site summary" "block" should exist
+    And I should not see "Course summary" in the "Course/site summary" "block"
+    And I should see "Proved the summary block works!" in the "Course/site summary" "block"
+
+  Scenario: Admin can not see edit icon when edit mode is off
+    When I log in as "admin"
+    And I am on site homepage
+    Then I should see "Proved the summary block works!" in the "Course/site summary" "block"
+    And I should not see "Course summary" in the "Course/site summary" "block"
+    And "Edit" "link" should not exist in the "Course/site summary" "block"
diff --git a/course_summary/version.php b/course_summary/version.php
new file mode 100644
index 0000000..62f27c5
--- /dev/null
+++ b/course_summary/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_course_summary
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_course_summary'; // Full name of the plugin (used for diagnostics)
diff --git a/edit_form 14.04.12.php b/edit_form 14.04.12.php
new file mode 100644
index 0000000..fac55d4
--- /dev/null
+++ b/edit_form 14.04.12.php	
@@ -0,0 +1,313 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Defines the base class form used by blocks/edit.php to edit block instance configuration.
+ *
+ * It works with the {@link block_edit_form} class, or rather the particular
+ * subclass defined by this block, to do the editing.
+ *
+ * @package    core_block
+ * @copyright  2009 Tim Hunt
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+if (!defined('MOODLE_INTERNAL')) {
+    die('Direct access to this script is forbidden.');    ///  It must be included from a Moodle page
+}
+
+require_once($CFG->libdir . '/formslib.php');
+require_once($CFG->libdir . '/blocklib.php');
+
+/**
+ * The base class form used by blocks/edit.php to edit block instance configuration.
+ *
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_edit_form extends moodleform {
+    /**
+     * The block instance we are editing.
+     * @var block_base
+     */
+    public $block;
+    /**
+     * The page we are editing this block in association with.
+     * @var moodle_page
+     */
+    public $page;
+
+    /**
+     * Defaults set in set_data() that need to be returned in get_data() if form elements were not created
+     * @var array
+     */
+    protected $defaults = [];
+
+    function __construct($actionurl, $block, $page) {
+        global $CFG;
+        $this->block = $block;
+        $this->page = $page;
+        parent::__construct($actionurl);
+    }
+
+    function definition() {
+        $mform =& $this->_form;
+
+        // First show fields specific to this type of block.
+        $this->specific_definition($mform);
+
+        // Then show the fields about where this block appears.
+        $mform->addElement('header', 'whereheader', get_string('wherethisblockappears', 'block'));
+
+        // If the current weight of the block is out-of-range, add that option in.
+        $blockweight = $this->block->instance->weight;
+        $weightoptions = array();
+        if ($blockweight < -block_manager::MAX_WEIGHT) {
+            $weightoptions[$blockweight] = $blockweight;
+        }
+        for ($i = -block_manager::MAX_WEIGHT; $i <= block_manager::MAX_WEIGHT; $i++) {
+            $weightoptions[$i] = $i;
+        }
+        if ($blockweight > block_manager::MAX_WEIGHT) {
+            $weightoptions[$blockweight] = $blockweight;
+        }
+        $first = reset($weightoptions);
+        $weightoptions[$first] = get_string('bracketfirst', 'block', $first);
+        $last = end($weightoptions);
+        $weightoptions[$last] = get_string('bracketlast', 'block', $last);
+
+        $regionoptions = $this->page->theme->get_all_block_regions();
+        foreach ($this->page->blocks->get_regions() as $region) {
+            // Make sure to add all custom regions of this particular page too.
+            if (!isset($regionoptions[$region])) {
+                $regionoptions[$region] = $region;
+            }
+        }
+
+        $parentcontext = context::instance_by_id($this->block->instance->parentcontextid);
+        $mform->addElement('static', 'bui_homecontext', get_string('createdat', 'block'), $parentcontext->get_context_name());
+        $mform->addHelpButton('bui_homecontext', 'createdat', 'block');
+
+        // For pre-calculated (fixed) pagetype lists
+        $pagetypelist = array();
+
+        // parse pagetype patterns
+        $bits = explode('-', $this->page->pagetype);
+
+        // First of all, check if we are editing blocks @ front-page or no and
+        // make some dark magic if so (MDL-30340) because each page context
+        // implies one (and only one) harcoded page-type that will be set later
+        // when processing the form data at {@link block_manager::process_url_edit()}
+
+        // Front page, show the page-contexts element and set $pagetypelist to 'any page' (*)
+        // as unique option. Processign the form will do any change if needed
+        if ($this->is_editing_the_frontpage()) {
+            $contextoptions = array();
+            $contextoptions[BUI_CONTEXTS_FRONTPAGE_ONLY] = get_string('showonfrontpageonly', 'block');
+            $contextoptions[BUI_CONTEXTS_FRONTPAGE_SUBS] = get_string('showonfrontpageandsubs', 'block');
+            $contextoptions[BUI_CONTEXTS_ENTIRE_SITE]    = get_string('showonentiresite', 'block');
+            $mform->addElement('select', 'bui_contexts', get_string('contexts', 'block'), $contextoptions);
+            $mform->addHelpButton('bui_contexts', 'contexts', 'block');
+            $pagetypelist['*'] = '*'; // This is not going to be shown ever, it's an unique option
+
+        // Any other system context block, hide the page-contexts element,
+        // it's always system-wide BUI_CONTEXTS_ENTIRE_SITE
+        } else if ($parentcontext->contextlevel == CONTEXT_SYSTEM) {
+
+        } else if ($parentcontext->contextlevel == CONTEXT_COURSE) {
+            // 0 means display on current context only, not child contexts
+            // but if course managers select mod-* as pagetype patterns, block system will overwrite this option
+            // to 1 (display on current context and child contexts)
+        } else if ($parentcontext->contextlevel == CONTEXT_MODULE or $parentcontext->contextlevel == CONTEXT_USER) {
+            // module context doesn't have child contexts, so display in current context only
+        } else {
+            $parentcontextname = $parentcontext->get_context_name();
+            $contextoptions[BUI_CONTEXTS_CURRENT]      = get_string('showoncontextonly', 'block', $parentcontextname);
+            $contextoptions[BUI_CONTEXTS_CURRENT_SUBS] = get_string('showoncontextandsubs', 'block', $parentcontextname);
+            $mform->addElement('select', 'bui_contexts', get_string('contexts', 'block'), $contextoptions);
+        }
+        $mform->setType('bui_contexts', PARAM_INT);
+
+        // Generate pagetype patterns by callbacks if necessary (has not been set specifically)
+        if (empty($pagetypelist)) {
+            $pagetypelist = generate_page_type_patterns($this->page->pagetype, $parentcontext, $this->page->context);
+            $displaypagetypewarning = false;
+            if (!array_key_exists($this->block->instance->pagetypepattern, $pagetypelist)) {
+                // Pushing block's existing page type pattern
+                $pagetypestringname = 'page-'.str_replace('*', 'x', $this->block->instance->pagetypepattern);
+                if (get_string_manager()->string_exists($pagetypestringname, 'pagetype')) {
+                    $pagetypelist[$this->block->instance->pagetypepattern] = get_string($pagetypestringname, 'pagetype');
+                } else {
+                    //as a last resort we could put the page type pattern in the select box
+                    //however this causes mod-data-view to be added if the only option available is mod-data-*
+                    // so we are just showing a warning to users about their prev setting being reset
+                    $displaypagetypewarning = true;
+                }
+            }
+        }
+
+        // hide page type pattern select box if there is only one choice
+        if (count($pagetypelist) > 1) {
+            if ($displaypagetypewarning) {
+                $mform->addElement('static', 'pagetypewarning', '', get_string('pagetypewarning','block'));
+            }
+
+            $mform->addElement('select', 'bui_pagetypepattern', get_string('restrictpagetypes', 'block'), $pagetypelist);
+        } else {
+            $values = array_keys($pagetypelist);
+            $value = array_pop($values);
+            // Now we are really hiding a lot (both page-contexts and page-type-patterns),
+            // specially in some systemcontext pages having only one option (my/user...)
+            // so, until it's decided if we are going to add the 'bring-back' pattern to
+            // all those pages or no (see MDL-30574), we are going to show the unique
+            // element statically
+            // TODO: Revisit this once MDL-30574 has been decided and implemented, although
+            // perhaps it's not bad to always show this statically when only one pattern is
+            // available.
+            if (!$this->is_editing_the_frontpage()) {
+                // Try to beautify it
+                $strvalue = $value;
+                $strkey = 'page-'.str_replace('*', 'x', $strvalue);
+                if (get_string_manager()->string_exists($strkey, 'pagetype')) {
+                    $strvalue = get_string($strkey, 'pagetype');
+                }
+                // Show as static (hidden has been set already)
+                $mform->addElement('static', 'bui_staticpagetypepattern',
+                    get_string('restrictpagetypes','block'), $strvalue);
+            }
+        }
+
+        if ($this->page->subpage) {
+            if ($parentcontext->contextlevel != CONTEXT_USER) {
+                $subpageoptions = array(
+                    '%@NULL@%' => get_string('anypagematchingtheabove', 'block'),
+                    $this->page->subpage => get_string('thisspecificpage', 'block', $this->page->subpage),
+                );
+                $mform->addElement('select', 'bui_subpagepattern', get_string('subpages', 'block'), $subpageoptions);
+            }
+        }
+
+        $defaultregionoptions = $regionoptions;
+        $defaultregion = $this->block->instance->defaultregion;
+        if (!array_key_exists($defaultregion, $defaultregionoptions)) {
+            $defaultregionoptions[$defaultregion] = $defaultregion;
+        }
+        $mform->addElement('select', 'bui_defaultregion', get_string('defaultregion', 'block'), $defaultregionoptions);
+        $mform->addHelpButton('bui_defaultregion', 'defaultregion', 'block');
+
+        $mform->addElement('select', 'bui_defaultweight', get_string('defaultweight', 'block'), $weightoptions);
+        $mform->addHelpButton('bui_defaultweight', 'defaultweight', 'block');
+
+        // Where this block is positioned on this page.
+        $mform->addElement('header', 'onthispage', get_string('onthispage', 'block'));
+
+        $mform->addElement('selectyesno', 'bui_visible', get_string('visible', 'block'));
+
+        $blockregion = $this->block->instance->region;
+        if (!array_key_exists($blockregion, $regionoptions)) {
+            $regionoptions[$blockregion] = $blockregion;
+        }
+        $mform->addElement('select', 'bui_region', get_string('region', 'block'), $regionoptions);
+
+        $mform->addElement('select', 'bui_weight', get_string('weight', 'block'), $weightoptions);
+
+        $pagefields = array('bui_visible', 'bui_region', 'bui_weight');
+        if (!$this->block->user_can_edit()) {
+            $mform->hardFreezeAllVisibleExcept($pagefields);
+        }
+        if (!$this->page->user_can_edit_blocks()) {
+            $mform->hardFreeze($pagefields);
+        }
+
+        $this->add_action_buttons();
+    }
+
+    /**
+     * Returns true if the user is editing a frontpage.
+     * @return bool
+     */
+    public function is_editing_the_frontpage() {
+        // There are some conditions to check related to contexts.
+        $ctxconditions = $this->page->context->contextlevel == CONTEXT_COURSE &&
+            $this->page->context->instanceid == get_site()->id;
+        $issiteindex = (strpos($this->page->pagetype, 'site-index') === 0);
+        // So now we can be 100% sure if edition is happening at frontpage.
+        return ($ctxconditions && $issiteindex);
+    }
+
+    function set_data($defaults) {
+        // Prefix bui_ on all the core field names.
+        $blockfields = array('showinsubcontexts', 'pagetypepattern', 'subpagepattern', 'parentcontextid',
+                'defaultregion', 'defaultweight', 'visible', 'region', 'weight');
+        foreach ($blockfields as $field) {
+            $newname = 'bui_' . $field;
+            $defaults->$newname = $defaults->$field;
+        }
+
+        // Copy block config into config_ fields.
+        if (!empty($this->block->config)) {
+            foreach ($this->block->config as $field => $value) {
+                $configfield = 'config_' . $field;
+                $defaults->$configfield = $value;
+            }
+        }
+
+        // Munge ->subpagepattern becuase HTML selects don't play nicely with NULLs.
+        if (empty($defaults->bui_subpagepattern)) {
+            $defaults->bui_subpagepattern = '%@NULL@%';
+        }
+
+        $systemcontext = context_system::instance();
+        if ($defaults->parentcontextid == $systemcontext->id) {
+            $defaults->bui_contexts = BUI_CONTEXTS_ENTIRE_SITE; // System-wide and sticky
+        } else {
+            $defaults->bui_contexts = $defaults->bui_showinsubcontexts;
+        }
+
+        // Some fields may not be editable, remember the values here so we can return them in get_data().
+        $this->defaults = [
+            'bui_parentcontextid' => $defaults->bui_parentcontextid,
+            'bui_contexts' => $defaults->bui_contexts,
+            'bui_pagetypepattern' => $defaults->bui_pagetypepattern,
+            'bui_subpagepattern' => $defaults->bui_subpagepattern,
+        ];
+        parent::set_data($defaults);
+    }
+
+    /**
+     * Override this to create any form fields specific to this type of block.
+     * @param object $mform the form being built.
+     */
+    protected function specific_definition($mform) {
+        // By default, do nothing.
+    }
+
+    /**
+     * Return submitted data if properly submitted or returns NULL if validation fails or
+     * if there is no submitted data.
+     *
+     * @return object submitted data; NULL if not valid or not submitted or cancelled
+     */
+    public function get_data() {
+        if ($data = parent::get_data()) {
+            // Blocklib expects 'bui_editingatfrontpage' property to be returned from this form.
+            $data->bui_editingatfrontpage = $this->is_editing_the_frontpage();
+            // Some fields are non-editable and we need to populate them with the values from set_data().
+            return (object)((array)$data + $this->defaults);
+        }
+        return $data;
+    }
+}
diff --git a/feedback/block_feedback.php b/feedback/block_feedback.php
new file mode 100644
index 0000000..b10163a
--- /dev/null
+++ b/feedback/block_feedback.php
@@ -0,0 +1,73 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Feedback block.
+ *
+ * @package    block_feedback
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once($CFG->dirroot . '/mod/feedback/lib.php');
+
+class block_feedback extends block_list {
+
+    function init() {
+        $this->title = get_string('feedback', 'block_feedback');
+    }
+
+    function applicable_formats() {
+        return array('site' => true, 'course' => true);
+    }
+
+    function get_content() {
+        global $CFG, $OUTPUT;
+
+        if ($this->content !== NULL) {
+            return $this->content;
+        }
+
+        $this->content = new stdClass;
+        $this->content->items = array();
+        $this->content->icons = array();
+        $this->content->footer = '';
+
+        $courseid = $this->page->course->id;
+        if ($courseid <= 0) {
+            $courseid = SITEID;
+        }
+
+        $icon = $OUTPUT->image_icon('icon', get_string('pluginname', 'mod_feedback'), 'mod_feedback');
+
+        if (empty($this->instance->pageid)) {
+            $this->instance->pageid = SITEID;
+        }
+
+        if ($feedbacks = feedback_get_feedbacks_from_sitecourse_map($courseid)) {
+            $baseurl = new moodle_url('/mod/feedback/view.php');
+            foreach ($feedbacks as $feedback) {
+                $url = new moodle_url($baseurl);
+                $url->params(array('id'=>$feedback->cmid, 'courseid'=>$courseid));
+                $this->content->items[] = '<a href="'.$url->out().'">'.$icon.$feedback->name.'</a>';
+            }
+        }
+
+        return $this->content;
+    }
+}
diff --git a/feedback/classes/privacy/provider.php b/feedback/classes/privacy/provider.php
new file mode 100644
index 0000000..157e25e
--- /dev/null
+++ b/feedback/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_feedback.
+ *
+ * @package    block_feedback
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_feedback\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_feedback implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/feedback/db/access.php b/feedback/db/access.php
new file mode 100644
index 0000000..3dd660b
--- /dev/null
+++ b/feedback/db/access.php
@@ -0,0 +1,41 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Feedback block caps.
+ *
+ * @package    block_feedback
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/feedback:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/feedback/db/install.php b/feedback/db/install.php
new file mode 100644
index 0000000..737c9e3
--- /dev/null
+++ b/feedback/db/install.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Feedback block installation.
+ *
+ * @package    block_feedback
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+function xmldb_block_feedback_install() {
+    global $DB;
+
+}
+
diff --git a/feedback/lang/en/block_feedback.php b/feedback/lang/en/block_feedback.php
new file mode 100644
index 0000000..e9163f9
--- /dev/null
+++ b/feedback/lang/en/block_feedback.php
@@ -0,0 +1,28 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_feedback', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_feedback
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['feedback'] = 'Feedback';
+$string['feedback:addinstance'] = 'Add a new feedback block';
+$string['pluginname'] = 'Feedback';
+$string['privacy:metadata'] = 'The Feedback block only shows data stored in other locations.';
diff --git a/feedback/version.php b/feedback/version.php
new file mode 100644
index 0000000..5043285
--- /dev/null
+++ b/feedback/version.php
@@ -0,0 +1,31 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_feedback
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_feedback';  // Full name of the plugin (used for diagnostics)
+
+$plugin->dependencies = array('mod_feedback' => 2018050800);
diff --git a/globalsearch/block_globalsearch.php b/globalsearch/block_globalsearch.php
new file mode 100644
index 0000000..d3d96b2
--- /dev/null
+++ b/globalsearch/block_globalsearch.php
@@ -0,0 +1,96 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Global search block.
+ *
+ * @package    block_globalsearch
+ * @copyright  Prateek Sachan {@link http://prateeksachan.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Global search block.
+ *
+ * @package    block_globalsearch
+ * @copyright  Prateek Sachan {@link http://prateeksachan.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_globalsearch extends block_base {
+
+    /**
+     * Initialises the block.
+     *
+     * @return void
+     */
+    public function init() {
+        $this->title = get_string('pluginname', 'block_globalsearch');
+    }
+
+    /**
+     * Gets the block contents.
+     *
+     * If we can avoid it better not check the server status here as connecting
+     * to the server will slow down the whole page load.
+     *
+     * @return string The block HTML.
+     */
+    public function get_content() {
+        global $OUTPUT;
+        if ($this->content !== null) {
+            return $this->content;
+        }
+
+        $this->content = new stdClass();
+        $this->content->footer = '';
+
+        if (\core_search\manager::is_global_search_enabled() === false) {
+            $this->content->text = get_string('globalsearchdisabled', 'search');
+            return $this->content;
+        }
+
+        $url = new moodle_url('/search/index.php');
+        $this->content->footer .= html_writer::link($url, get_string('advancedsearch', 'search'));
+
+        $this->content->text  = html_writer::start_tag('div', array('class' => 'searchform'));
+        $this->content->text .= html_writer::start_tag('form', array('action' => $url->out()));
+        $this->content->text .= html_writer::start_tag('fieldset', array('action' => 'invisiblefieldset'));
+
+        // Input.
+        $this->content->text .= html_writer::tag('label', get_string('search', 'search'),
+            array('for' => 'searchform_search', 'class' => 'accesshide'));
+        $inputoptions = array('id' => 'searchform_search', 'name' => 'q', 'class' => 'form-control',
+            'type' => 'text', 'size' => '15');
+        $this->content->text .= html_writer::empty_tag('input', $inputoptions);
+
+        // Context id.
+        if ($this->page->context && $this->page->context->contextlevel !== CONTEXT_SYSTEM) {
+            $this->content->text .= html_writer::empty_tag('input', ['type' => 'hidden',
+                    'name' => 'context', 'value' => $this->page->context->id]);
+        }
+
+        // Search button.
+        $this->content->text .= html_writer::tag('button', get_string('search', 'search'),
+            array('id' => 'searchform_button', 'type' => 'submit', 'title' => 'globalsearch', 'class' => 'btn btn-secondary'));
+        $this->content->text .= html_writer::end_tag('fieldset');
+        $this->content->text .= html_writer::end_tag('form');
+        $this->content->text .= html_writer::end_tag('div');
+
+        return $this->content;
+    }
+}
diff --git a/globalsearch/classes/privacy/provider.php b/globalsearch/classes/privacy/provider.php
new file mode 100644
index 0000000..0c57f73
--- /dev/null
+++ b/globalsearch/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_globalsearch.
+ *
+ * @package    block_globalsearch
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_globalsearch\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_globalsearch implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/globalsearch/db/access.php b/globalsearch/db/access.php
new file mode 100644
index 0000000..ad9f49d
--- /dev/null
+++ b/globalsearch/db/access.php
@@ -0,0 +1,48 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Global search Block caps.
+ *
+ * @package    block_globalsearch
+ * @copyright  Prateek Sachan {@link http://prateeksachan.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/globalsearch:myaddinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/my:manageblocks'
+    ),
+
+    'block/globalsearch:addinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/globalsearch/lang/en/block_globalsearch.php b/globalsearch/lang/en/block_globalsearch.php
new file mode 100644
index 0000000..6fd2131
--- /dev/null
+++ b/globalsearch/lang/en/block_globalsearch.php
@@ -0,0 +1,28 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_globalsearch'.
+ *
+ * @package    block_globalsearch
+ * @copyright  Prateek Sachan {@link http://prateeksachan.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['globalsearch:addinstance'] = 'Add a new global search block';
+$string['globalsearch:myaddinstance'] = 'Add a new global search block to Dashboard';
+$string['pluginname'] = 'Global search';
+$string['privacy:metadata'] = 'The Global search block only shows data stored in other locations.';
diff --git a/globalsearch/styles.css b/globalsearch/styles.css
new file mode 100644
index 0000000..6b94c4d
--- /dev/null
+++ b/globalsearch/styles.css
@@ -0,0 +1,7 @@
+.block_globalsearch .searchform {
+    text-align: center;
+}
+
+.block_globalsearch .footer {
+    text-align: center;
+}
diff --git a/globalsearch/version.php b/globalsearch/version.php
new file mode 100644
index 0000000..332dce1
--- /dev/null
+++ b/globalsearch/version.php
@@ -0,0 +1,30 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Global Search version details.
+ *
+ * @package    block_globalsearch
+ * @copyright  Prateek Sachan {@link http://prateeksachan.com}
+ * @copyright  Daniel Neis
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die;
+
+$plugin->version = 2018051400;
+$plugin->requires  = 2018050800;
+$plugin->component = 'block_globalsearch';
diff --git a/glossary_random/backup/moodle2/restore_glossary_random_block_task.class.php b/glossary_random/backup/moodle2/restore_glossary_random_block_task.class.php
new file mode 100644
index 0000000..236351c
--- /dev/null
+++ b/glossary_random/backup/moodle2/restore_glossary_random_block_task.class.php
@@ -0,0 +1,95 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * @package block_glossary_random
+ * @subpackage backup-moodle2
+ * @copyright 2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Specialised restore task for the glossary_random block
+ * (using execute_after_tasks for recoding of glossaryid)
+ *
+ * TODO: Finish phpdocs
+ */
+class restore_glossary_random_block_task extends restore_block_task {
+
+    protected function define_my_settings() {
+    }
+
+    protected function define_my_steps() {
+    }
+
+    public function get_fileareas() {
+        return array(); // No associated fileareas
+    }
+
+    public function get_configdata_encoded_attributes() {
+        return array(); // No special handling of configdata
+    }
+
+    /**
+     * This function, executed after all the tasks in the plan
+     * have been executed, will perform the recode of the
+     * target glossary for the block. This must be done here
+     * and not in normal execution steps because the glossary
+     * may be restored after the block.
+     */
+    public function after_restore() {
+        global $DB;
+
+        // Get the blockid
+        $blockid = $this->get_blockid();
+
+        // Extract block configdata and update it to point to the new glossary
+        if ($configdata = $DB->get_field('block_instances', 'configdata', array('id' => $blockid))) {
+            $config = unserialize(base64_decode($configdata));
+            if (!empty($config->glossary)) {
+                if ($glossarymap = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'glossary', $config->glossary)) {
+                    // Get glossary mapping and replace it in config
+                    $config->glossary = $glossarymap->newitemid;
+                } else if ($this->is_samesite()) {
+                    // We are restoring on the same site, check if glossary can be used in the block in this course.
+                    $glossaryid = $DB->get_field_sql("SELECT id FROM {glossary} " .
+                        "WHERE id = ? AND (course = ? OR globalglossary = 1)",
+                        [$config->glossary, $this->get_courseid()]);
+                    if (!$glossaryid) {
+                        unset($config->glossary);
+                    }
+                } else {
+                    // The block refers to a glossary not present in the backup file.
+                    unset($config->glossary);
+                }
+                // Unset config variables that are no longer used.
+                unset($config->globalglossary);
+                unset($config->courseid);
+                // Save updated config.
+                $configdata = base64_encode(serialize($config));
+                $DB->set_field('block_instances', 'configdata', $configdata, array('id' => $blockid));
+            }
+        }
+    }
+
+    static public function define_decode_contents() {
+        return array();
+    }
+
+    static public function define_decode_rules() {
+        return array();
+    }
+}
diff --git a/glossary_random/block_glossary_random.php b/glossary_random/block_glossary_random.php
new file mode 100644
index 0000000..5f15e8e
--- /dev/null
+++ b/glossary_random/block_glossary_random.php
@@ -0,0 +1,258 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Glossary Random block.
+ *
+ * @package   block_glossary_random
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+define('BGR_RANDOMLY',     '0');
+define('BGR_LASTMODIFIED', '1');
+define('BGR_NEXTONE',      '2');
+define('BGR_NEXTALPHA',    '3');
+
+class block_glossary_random extends block_base {
+
+    /**
+     * @var cm_info|stdClass has properties 'id' (course module id) and 'uservisible'
+     *     (whether the glossary is visible to the current user)
+     */
+    protected $glossarycm = null;
+
+    function init() {
+        $this->title = get_string('pluginname','block_glossary_random');
+    }
+
+    function specialization() {
+        global $CFG, $DB;
+
+        require_once($CFG->libdir . '/filelib.php');
+
+        $this->course = $this->page->course;
+
+        // load userdefined title and make sure it's never empty
+        if (empty($this->config->title)) {
+            $this->title = get_string('pluginname','block_glossary_random');
+        } else {
+            $this->title = format_string($this->config->title, true, ['context' => $this->context]);
+        }
+
+        if (empty($this->config->glossary)) {
+            return false;
+        }
+
+        if (!isset($this->config->nexttime)) {
+            $this->config->nexttime = 0;
+        }
+
+        //check if it's time to put a new entry in cache
+        if (time() > $this->config->nexttime) {
+
+            if (!($cm = $this->get_glossary_cm()) || !$cm->uservisible) {
+                // Skip generating of the cache if we can't display anything to the current user.
+                return false;
+            }
+
+            // place glossary concept and definition in $pref->cache
+            if (!$numberofentries = $DB->count_records('glossary_entries',
+                                                       array('glossaryid'=>$this->config->glossary, 'approved'=>1))) {
+                $this->config->cache = get_string('noentriesyet','block_glossary_random');
+                $this->instance_config_commit();
+            }
+
+            $glossaryctx = context_module::instance($cm->id);
+
+            $limitfrom = 0;
+            $limitnum = 1;
+
+            $orderby = 'timemodified ASC';
+
+            switch ($this->config->type) {
+
+                case BGR_RANDOMLY:
+                    $i = ($numberofentries > 1) ? rand(1, $numberofentries) : 1;
+                    $limitfrom = $i-1;
+                    break;
+
+                case BGR_NEXTONE:
+                    if (isset($this->config->previous)) {
+                        $i = $this->config->previous + 1;
+                    } else {
+                        $i = 1;
+                    }
+                    if ($i > $numberofentries) {  // Loop back to beginning
+                        $i = 1;
+                    }
+                    $limitfrom = $i-1;
+                    break;
+
+                case BGR_NEXTALPHA:
+                    $orderby = 'concept ASC';
+                    if (isset($this->config->previous)) {
+                        $i = $this->config->previous + 1;
+                    } else {
+                        $i = 1;
+                    }
+                    if ($i > $numberofentries) {  // Loop back to beginning
+                        $i = 1;
+                    }
+                    $limitfrom = $i-1;
+                    break;
+
+                default:  // BGR_LASTMODIFIED
+                    $i = $numberofentries;
+                    $limitfrom = 0;
+                    $orderby = 'timemodified DESC, id DESC';
+                    break;
+            }
+
+            if ($entry = $DB->get_records_sql("SELECT id, concept, definition, definitionformat, definitiontrust
+                                                 FROM {glossary_entries}
+                                                WHERE glossaryid = ? AND approved = 1
+                                             ORDER BY $orderby", array($this->config->glossary), $limitfrom, $limitnum)) {
+
+                $entry = reset($entry);
+
+                if (empty($this->config->showconcept)) {
+                    $text = '';
+                } else {
+                    $text = "<h3>".format_string($entry->concept,true)."</h3>";
+                }
+
+                $options = new stdClass();
+                $options->trusted = $entry->definitiontrust;
+                $options->overflowdiv = true;
+                $entry->definition = file_rewrite_pluginfile_urls($entry->definition, 'pluginfile.php', $glossaryctx->id, 'mod_glossary', 'entry', $entry->id);
+                $text .= format_text($entry->definition, $entry->definitionformat, $options);
+
+                $this->config->nexttime = usergetmidnight(time()) + DAYSECS * $this->config->refresh;
+                $this->config->previous = $i;
+
+            } else {
+                $text = get_string('noentriesyet','block_glossary_random');
+            }
+            // store the text
+            $this->config->cache = $text;
+            $this->instance_config_commit();
+        }
+    }
+
+    /**
+     * Replace the instance's configuration data with those currently in $this->config;
+     */
+    function instance_config_commit($nolongerused = false) {
+        // Unset config variables that are no longer used.
+        unset($this->config->globalglossary);
+        unset($this->config->courseid);
+        parent::instance_config_commit($nolongerused);
+    }
+
+    /**
+     * Checks if glossary is available - it should be either located in the same course or be global
+     *
+     * @return null|cm_info|stdClass object with properties 'id' (course module id) and 'uservisible'
+     */
+    protected function get_glossary_cm() {
+        global $DB;
+        if (empty($this->config->glossary)) {
+            // No glossary is configured.
+            return null;
+        }
+
+        if (!empty($this->glossarycm)) {
+            return $this->glossarycm;
+        }
+
+        if (!empty($this->page->course->id)) {
+            // First check if glossary belongs to the current course (we don't need to make any DB queries to find it).
+            $modinfo = get_fast_modinfo($this->page->course);
+            if (isset($modinfo->instances['glossary'][$this->config->glossary])) {
+                $this->glossarycm = $modinfo->instances['glossary'][$this->config->glossary];
+                if ($this->glossarycm->uservisible) {
+                    // The glossary is in the same course and is already visible to the current user,
+                    // no need to check if it is global, save on DB query.
+                    return $this->glossarycm;
+                }
+            }
+        }
+
+        // Find course module id for the given glossary, only if it is global.
+        $cm = $DB->get_record_sql("SELECT cm.id, cm.visible AS uservisible
+              FROM {course_modules} cm
+                   JOIN {modules} md ON md.id = cm.module
+                   JOIN {glossary} g ON g.id = cm.instance
+             WHERE g.id = :instance AND md.name = :modulename AND g.globalglossary = 1",
+            ['instance' => $this->config->glossary, 'modulename' => 'glossary']);
+
+        if ($cm) {
+            // This is a global glossary, create an object with properties 'id' and 'uservisible'. We don't need any
+            // other information so why bother retrieving it. Full access check is skipped for global glossaries for
+            // performance reasons.
+            $this->glossarycm = $cm;
+        } else if (empty($this->glossarycm)) {
+            // Glossary does not exist. Remove it in the config so we don't repeat this check again later.
+            $this->config->glossary = 0;
+            $this->instance_config_commit();
+        }
+
+        return $this->glossarycm;
+    }
+
+    function instance_allow_multiple() {
+    // Are you going to allow multiple instances of each block?
+    // If yes, then it is assumed that the block WILL USE per-instance configuration
+        return true;
+    }
+
+    function get_content() {
+        if ($this->content !== null) {
+            return $this->content;
+        }
+        $this->content = (object)['text' => '', 'footer' => ''];
+
+        if (!$cm = $this->get_glossary_cm()) {
+            if ($this->user_can_edit()) {
+                $this->content->text = get_string('notyetconfigured', 'block_glossary_random');
+            }
+            return $this->content;
+        }
+
+        if (empty($this->config->cache)) {
+            $this->config->cache = '';
+        }
+
+        if ($cm->uservisible) {
+            // Show glossary if visible and place links in footer.
+            $this->content->text = $this->config->cache;
+            if (has_capability('mod/glossary:write', context_module::instance($cm->id))) {
+                $this->content->footer = html_writer::link(new moodle_url('/mod/glossary/edit.php', ['cmid' => $cm->id]),
+                    format_string($this->config->addentry)) . '<br/>';
+            }
+
+            $this->content->footer .= html_writer::link(new moodle_url('/mod/glossary/view.php', ['id' => $cm->id]),
+                format_string($this->config->viewglossary));
+        } else {
+            // Otherwise just place some text, no link.
+            $this->content->footer = format_string($this->config->invisible);
+        }
+
+        return $this->content;
+    }
+}
+
diff --git a/glossary_random/classes/privacy/provider.php b/glossary_random/classes/privacy/provider.php
new file mode 100644
index 0000000..d1c64d4
--- /dev/null
+++ b/glossary_random/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_glossary_random.
+ *
+ * @package    block_glossary_random
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_glossary_random\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_glossary_random implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/glossary_random/db/access.php b/glossary_random/db/access.php
new file mode 100644
index 0000000..0c1acd6
--- /dev/null
+++ b/glossary_random/db/access.php
@@ -0,0 +1,51 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Glossary random block caps.
+ *
+ * @package    block_glossary_random
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/glossary_random:myaddinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/my:manageblocks'
+    ),
+
+    'block/glossary_random:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/glossary_random/edit_form.php b/glossary_random/edit_form.php
new file mode 100644
index 0000000..ef1cf34
--- /dev/null
+++ b/glossary_random/edit_form.php
@@ -0,0 +1,79 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Form for editing HTML block instances.
+ *
+ * @package   block_glossary_random
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Form for editing Random glossary entry block instances.
+ *
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_glossary_random_edit_form extends block_edit_form {
+    protected function specific_definition($mform) {
+        global $DB;
+
+        // Fields for editing HTML block title and contents.
+        $mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
+
+        $mform->addElement('text', 'config_title', get_string('title', 'block_glossary_random'));
+        $mform->setDefault('config_title', get_string('pluginname','block_glossary_random'));
+        $mform->setType('config_title', PARAM_TEXT);
+
+        // Select glossaries to put in dropdown box ...
+        $glossaries = $DB->get_records_select_menu('glossary', 'course = ? OR globalglossary = ?', array($this->block->course->id, 1), 'name', 'id,name');
+        foreach($glossaries as $key => $value) {
+            $glossaries[$key] = strip_tags(format_string($value, true));
+        }
+        $mform->addElement('select', 'config_glossary', get_string('select_glossary', 'block_glossary_random'), $glossaries);
+
+        $mform->addElement('text', 'config_refresh', get_string('refresh', 'block_glossary_random'), array('size' => 5));
+        $mform->setDefault('config_refresh', 0);
+        $mform->setType('config_refresh', PARAM_INT);
+
+        // and select quotetypes to put in dropdown box
+        $types = array(
+            0 => get_string('random','block_glossary_random'),
+            1 => get_string('lastmodified','block_glossary_random'),
+            2 => get_string('nextone','block_glossary_random'),
+            3 => get_string('nextalpha','block_glossary_random')
+        );
+        $mform->addElement('select', 'config_type', get_string('type', 'block_glossary_random'), $types);
+
+        $mform->addElement('selectyesno', 'config_showconcept', get_string('showconcept', 'block_glossary_random'));
+        $mform->setDefault('config_showconcept', 1);
+
+        $mform->addElement('static', 'footerdescription', '', get_string('whichfooter', 'block_glossary_random'));
+
+        $mform->addElement('text', 'config_addentry', get_string('askaddentry', 'block_glossary_random'));
+        $mform->setDefault('config_addentry', get_string('addentry', 'block_glossary_random'));
+        $mform->setType('config_addentry', PARAM_NOTAGS);
+
+        $mform->addElement('text', 'config_viewglossary', get_string('askviewglossary', 'block_glossary_random'));
+        $mform->setDefault('config_viewglossary', get_string('viewglossary', 'block_glossary_random'));
+        $mform->setType('config_viewglossary', PARAM_NOTAGS);
+
+        $mform->addElement('text', 'config_invisible', get_string('askinvisible', 'block_glossary_random'));
+        $mform->setDefault('config_invisible', get_string('invisible', 'block_glossary_random'));
+        $mform->setType('config_invisible', PARAM_NOTAGS);
+    }
+}
diff --git a/glossary_random/lang/en/block_glossary_random.php b/glossary_random/lang/en/block_glossary_random.php
new file mode 100644
index 0000000..1c58f6f
--- /dev/null
+++ b/glossary_random/lang/en/block_glossary_random.php
@@ -0,0 +1,48 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_glossary_random', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_glossary_random
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['addentry'] = 'Add a new entry';
+$string['askaddentry'] = 'When users can add entries to the glossary, show a link with this text';
+$string['askinvisible'] = 'When users cannot edit or view the glossary, show this text (without link)';
+$string['askviewglossary'] = 'When users can view the glossary but not add entries, show a link with this text';
+$string['glossary_random:addinstance'] = 'Add a new random glossary entry block';
+$string['glossary_random:myaddinstance'] = 'Add a new random glossary entry block to Dashboard';
+$string['intro'] = 'Make sure you have at least one glossary with at least one entry added to this course. Then you can adjust the following settings';
+$string['invisible'] = '(to be continued)';
+$string['lastmodified'] = 'Last modified entry';
+$string['nextalpha'] = 'Alphabetical order';
+$string['nextone'] = 'Next entry';
+$string['noentriesyet'] = 'There are no entries yet in the chosen glossary.';
+$string['notyetconfigured'] = 'Please configure this block using the edit icon.';
+$string['notyetglossary'] = 'You need to have at least one glossary to choose.';
+$string['pluginname'] = 'Random glossary entry';
+$string['random'] = 'Random entry';
+$string['refresh'] = 'Days before a new entry is chosen';
+$string['select_glossary'] = 'Take entries from this glossary';
+$string['showconcept'] = 'Show concept (heading) for each entry';
+$string['title'] = 'Title';
+$string['type'] = 'How a new entry is chosen';
+$string['viewglossary'] = 'View all entries';
+$string['whichfooter'] = 'You can display links to actions of the glossary this block is associated with. The block will only display links to actions which are enabled for that glossary.';
+$string['privacy:metadata'] = 'The Random glossary entry block only shows data stored in other locations.';
diff --git a/glossary_random/tests/behat/glossary_random.feature b/glossary_random/tests/behat/glossary_random.feature
new file mode 100644
index 0000000..423c195
--- /dev/null
+++ b/glossary_random/tests/behat/glossary_random.feature
@@ -0,0 +1,108 @@
+@block @block_glossary_random
+Feature: Random glossary entry block is used in a course
+  In order to show the entries from glossary
+  As a teacher
+  I can add the random glossary entry to a course page
+
+  Background:
+    Given the following "courses" exist:
+      | fullname | shortname |
+      | Course 1 | C1        |
+    And the following "users" exist:
+      | username | firstname | lastname | email             |
+      | student1 | Sam1      | Student1 | student1@example.com |
+      | teacher1 | Terry1    | Teacher1 | teacher1@example.com |
+    And the following "course enrolments" exist:
+      | user     | course | role           |
+      | student1 | C1     | student        |
+      | teacher1 | C1     | editingteacher |
+
+  Scenario: Student can not see the block if it is not configured
+    When I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Random glossary entry" block
+    Then I should see "Please configure this block using the edit icon" in the "block_glossary_random" "block"
+    And I log out
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And "block_glossary_random" "block" should not exist
+    And I log out
+
+  Scenario: View random (last) entry in the glossary with auto approval
+    Given the following "activities" exist:
+      | activity | name         | intro                     | course | idnumber  | defaultapproval |
+      | glossary | GlossaryAuto | Test glossary description | C1     | glossary1 | 1               |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Random glossary entry" block
+    And I configure the "block_glossary_random" block
+    And I set the following fields to these values:
+      | Title                           | AutoGlossaryblock   |
+      | Take entries from this glossary | GlossaryAuto        |
+      | How a new entry is chosen       | Last modified entry |
+    And I press "Save changes"
+    And I log out
+    When I log in as "student1"
+    And I am on "Course 1" course homepage
+    Then I should see "There are no entries yet in the chosen glossary" in the "AutoGlossaryblock" "block"
+    And I click on "Add a new entry" "link" in the "AutoGlossaryblock" "block"
+    And I set the following fields to these values:
+      | Concept    | Concept1    |
+      | Definition | Definition1 |
+    And I press "Save changes"
+    And I am on "Course 1" course homepage
+    And I should see "Concept1" in the "AutoGlossaryblock" "block"
+    And I should see "Definition1" in the "AutoGlossaryblock" "block"
+    And I should not see "There are no entries yet in the chosen glossary" in the "AutoGlossaryblock" "block"
+    And I click on "Add a new entry" "link" in the "AutoGlossaryblock" "block"
+    And I set the following fields to these values:
+      | Concept    | Concept2    |
+      | Definition | Definition2 |
+    And I press "Save changes"
+    And I am on "Course 1" course homepage
+    # Only the last entry appears in the block
+    And I should not see "Concept1" in the "AutoGlossaryblock" "block"
+    And I should not see "Definition1" in the "AutoGlossaryblock" "block"
+    And I should see "Concept2" in the "AutoGlossaryblock" "block"
+    And I should see "Definition2" in the "AutoGlossaryblock" "block"
+    And I click on "View all entries" "link" in the "AutoGlossaryblock" "block"
+    And I should see "GlossaryAuto" in the "#page-navbar" "css_element"
+    And I should see "Concept1" in the "#page-content" "css_element"
+    And I should see "Concept2" in the "#page-content" "css_element"
+    And I log out
+
+  Scenario: View random (last) entry in the glossary with manual approval
+    Given the following "activities" exist:
+      | activity | name           | intro                     | course | idnumber  | defaultapproval |
+      | glossary | GlossaryManual | Test glossary description | C1     | glossary2 | 0               |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Random glossary entry" block
+    And I configure the "block_glossary_random" block
+    And I set the following fields to these values:
+      | Title                           | ManualGlossaryblock |
+      | Take entries from this glossary | GlossaryManual      |
+      | How a new entry is chosen       | Last modified entry |
+    And I press "Save changes"
+    And I log out
+    When I log in as "student1"
+    And I am on "Course 1" course homepage
+    Then I should see "There are no entries yet in the chosen glossary" in the "ManualGlossaryblock" "block"
+    And I click on "Add a new entry" "link" in the "ManualGlossaryblock" "block"
+    And I set the following fields to these values:
+      | Concept    | Concept1    |
+      | Definition | Definition1 |
+    And I press "Save changes"
+    And I am on "Course 1" course homepage
+    And I should see "There are no entries yet in the chosen glossary" in the "ManualGlossaryblock" "block"
+    And I log out
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage
+    And I should see "There are no entries yet in the chosen glossary" in the "ManualGlossaryblock" "block"
+    And I follow "GlossaryManual"
+    And I follow "Waiting approval"
+    And I follow "Approve"
+    And I click on "Course 1" "link" in the "#page-navbar" "css_element"
+    And I should see "Concept1" in the "ManualGlossaryblock" "block"
+    And I should see "Definition1" in the "ManualGlossaryblock" "block"
+    And I log out
diff --git a/glossary_random/tests/behat/glossary_random_frontpage.feature b/glossary_random/tests/behat/glossary_random_frontpage.feature
new file mode 100644
index 0000000..db31b91
--- /dev/null
+++ b/glossary_random/tests/behat/glossary_random_frontpage.feature
@@ -0,0 +1,27 @@
+@block @block_glossary_random
+Feature: Random glossary entry block can be added to the frontpage
+  In order to show the entries from glossary on the frontpage
+  As a teacher
+  I can add the random glossary entry to the frontpage
+
+  Scenario: Admin can add random glossary block to the frontpage
+    Given the following "activities" exist:
+      | activity   | name             | intro                          | course               | idnumber  |
+      | glossary   | Tips and Tricks  | Frontpage glossary description | Acceptance test site | glossary0 |
+    And I log in as "admin"
+    And I am on site homepage
+    And I turn editing mode on
+    And I add the "Random glossary entry" block
+    And I configure the "block_glossary_random" block
+    And I set the following fields to these values:
+      | Title                           | Tip of the day  |
+      | Take entries from this glossary | Tips and Tricks |
+    And I press "Save changes"
+    And I click on "Add a new entry" "link" in the "Tip of the day" "block"
+    And I set the following fields to these values:
+      | Concept    | Never come late               |
+      | Definition | Come in time for your classes |
+    And I press "Save changes"
+    When I log out
+    Then I should see "Never come late" in the "Tip of the day" "block"
+    And I should see "Come in time for your classes" in the "Tip of the day" "block"
diff --git a/glossary_random/tests/behat/glossary_random_global.feature b/glossary_random/tests/behat/glossary_random_global.feature
new file mode 100644
index 0000000..3329702
--- /dev/null
+++ b/glossary_random/tests/behat/glossary_random_global.feature
@@ -0,0 +1,79 @@
+@block @block_glossary_random
+Feature: Random glossary entry block linking to global glossary
+  In order to show the entries from glossary
+  As a teacher
+  I can add the random glossary entry to a course page
+
+  Background:
+    Given the following "courses" exist:
+      | fullname | shortname |
+      | Course 1 | C1        |
+      | Course 2 | C2        |
+    And the following "activities" exist:
+      | activity   | name             | intro                          | course               | idnumber  | globalglossary | defaultapproval |
+      | glossary   | Tips and Tricks  | Frontpage glossary description | C2 | glossary0 | 1              | 1               |
+    And the following "users" exist:
+      | username | firstname | lastname | email             |
+      | student1 | Sam1      | Student1 | student1@example.com |
+      | teacher1 | Terry1    | Teacher1 | teacher1@example.com |
+    And the following "course enrolments" exist:
+      | user     | course | role           |
+      | student1 | C1     | student        |
+      | teacher1 | C1     | editingteacher |
+
+  Scenario: View random (last) entry in the global glossary
+    When I log in as "admin"
+    And I am on "Course 2" course homepage
+    And I follow "Tips and Tricks"
+    And I press "Add a new entry"
+    And I set the following fields to these values:
+      | Concept    | Never come late               |
+      | Definition | Come in time for your classes |
+    And I press "Save changes"
+    And I log out
+    # As a teacher add a block to the course page linking to the global glossary.
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Random glossary entry" block
+    And I configure the "block_glossary_random" block
+    And I set the following fields to these values:
+      | Title                           | Tip of the day      |
+      | Take entries from this glossary | Tips and Tricks     |
+      | How a new entry is chosen       | Last modified entry |
+    And I press "Save changes"
+    Then I should see "Never come late" in the "Tip of the day" "block"
+    And I should not see "Add a new entry" in the "Tip of the day" "block"
+    And I should see "View all entries" in the "Tip of the day" "block"
+    And I log out
+    # Student who can't see the module is still able to view entries in this block (because the glossary was marked as global)
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "Never come late" in the "Tip of the day" "block"
+    And I should not see "Add a new entry" in the "Tip of the day" "block"
+    And I should see "View all entries" in the "Tip of the day" "block"
+    And I log out
+
+  Scenario: Removing the global glossary that is used in random glossary block
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Random glossary entry" block
+    And I configure the "block_glossary_random" block
+    And I set the following fields to these values:
+      | Title                           | Tip of the day      |
+      | Take entries from this glossary | Tips and Tricks     |
+      | How a new entry is chosen       | Last modified entry |
+    And I press "Save changes"
+    And I log out
+    And I log in as "admin"
+    And I am on "Course 2" course homepage
+    And I follow "Tips and Tricks"
+    And I follow "Edit settings"
+    And I set the field "globalglossary" to "0"
+    And I press "Save and return to course"
+    And I am on "Course 1" course homepage
+    Then I should see "Please configure this block using the edit icon." in the "Tip of the day" "block"
+    And I log out
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And "Tip of the day" "block" should not exist
+    And I log out
diff --git a/glossary_random/version.php b/glossary_random/version.php
new file mode 100644
index 0000000..2a36e21
--- /dev/null
+++ b/glossary_random/version.php
@@ -0,0 +1,31 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_glossary_random
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_glossary_random'; // Full name of the plugin (used for diagnostics)
+
+$plugin->dependencies = array('mod_glossary' => 2018050800);
diff --git a/html/backup/moodle1/lib.php b/html/backup/moodle1/lib.php
new file mode 100644
index 0000000..da215c2
--- /dev/null
+++ b/html/backup/moodle1/lib.php
@@ -0,0 +1,64 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Provides support for the conversion of moodle1 backup to the moodle2 format
+ *
+ * @package    block_html
+ * @copyright  2012 Paul Nicholls
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Block conversion handler for html
+ */
+class moodle1_block_html_handler extends moodle1_block_handler {
+    private $fileman = null;
+    protected function convert_configdata(array $olddata) {
+        global $CFG;
+        require_once($CFG->libdir . '/db/upgradelib.php');
+        $instanceid = $olddata['id'];
+        $contextid  = $this->converter->get_contextid(CONTEXT_BLOCK, $olddata['id']);
+        $decodeddata = base64_decode($olddata['configdata']);
+        list($updated, $configdata) = upgrade_fix_serialized_objects($decodeddata);
+        $configdata = unserialize($configdata);
+
+        // get a fresh new file manager for this instance
+        $this->fileman = $this->converter->get_file_manager($contextid, 'block_html');
+
+        // convert course files embedded in the block content
+        $this->fileman->filearea = 'content';
+        $this->fileman->itemid   = 0;
+        $configdata->text = moodle1_converter::migrate_referenced_files($configdata->text, $this->fileman);
+        $configdata->format = FORMAT_HTML;
+
+        return base64_encode(serialize($configdata));
+    }
+
+    protected function write_inforef_xml($newdata, $data) {
+        $this->open_xml_writer("course/blocks/{$data['name']}_{$data['id']}/inforef.xml");
+        $this->xmlwriter->begin_tag('inforef');
+        $this->xmlwriter->begin_tag('fileref');
+        foreach ($this->fileman->get_fileids() as $fileid) {
+            $this->write_xml('file', array('id' => $fileid));
+        }
+        $this->xmlwriter->end_tag('fileref');
+        $this->xmlwriter->end_tag('inforef');
+        $this->close_xml_writer();
+    }
+}
diff --git a/html/backup/moodle2/backup_html_block_task.class.php b/html/backup/moodle2/backup_html_block_task.class.php
new file mode 100644
index 0000000..7e1bccc
--- /dev/null
+++ b/html/backup/moodle2/backup_html_block_task.class.php
@@ -0,0 +1,50 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * @package    block_html
+ * @subpackage backup-moodle2
+ * @copyright  2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Specialised backup task for the html block
+ * (requires encode_content_links in some configdata attrs)
+ *
+ * TODO: Finish phpdocs
+ */
+class backup_html_block_task extends backup_block_task {
+
+    protected function define_my_settings() {
+    }
+
+    protected function define_my_steps() {
+    }
+
+    public function get_fileareas() {
+        return array('content');
+    }
+
+    public function get_configdata_encoded_attributes() {
+        return array('text'); // We need to encode some attrs in configdata
+    }
+
+    static public function encode_content_links($content) {
+        return $content; // No special encoding of links
+    }
+}
+
diff --git a/html/backup/moodle2/restore_html_block_task.class.php b/html/backup/moodle2/restore_html_block_task.class.php
new file mode 100644
index 0000000..c3ce29b
--- /dev/null
+++ b/html/backup/moodle2/restore_html_block_task.class.php
@@ -0,0 +1,93 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * @package   block_html
+ * @subpackage backup-moodle2
+ * @copyright 2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Specialised restore task for the html block
+ * (requires encode_content_links in some configdata attrs)
+ *
+ * TODO: Finish phpdocs
+ */
+class restore_html_block_task extends restore_block_task {
+
+    protected function define_my_settings() {
+    }
+
+    protected function define_my_steps() {
+    }
+
+    public function get_fileareas() {
+        return array('content');
+    }
+
+    public function get_configdata_encoded_attributes() {
+        return array('text'); // We need to encode some attrs in configdata
+    }
+
+    static public function define_decode_contents() {
+
+        $contents = array();
+
+        $contents[] = new restore_html_block_decode_content('block_instances', 'configdata', 'block_instance');
+
+        return $contents;
+    }
+
+    static public function define_decode_rules() {
+        return array();
+    }
+}
+
+/**
+ * Specialised restore_decode_content provider that unserializes the configdata
+ * field, to serve the configdata->text content to the restore_decode_processor
+ * packaging it back to its serialized form after process
+ */
+class restore_html_block_decode_content extends restore_decode_content {
+
+    protected $configdata; // Temp storage for unserialized configdata
+
+    protected function get_iterator() {
+        global $DB;
+
+        // Build the SQL dynamically here
+        $fieldslist = 't.' . implode(', t.', $this->fields);
+        $sql = "SELECT t.id, $fieldslist
+                  FROM {" . $this->tablename . "} t
+                  JOIN {backup_ids_temp} b ON b.newitemid = t.id
+                 WHERE b.backupid = ?
+                   AND b.itemname = ?
+                   AND t.blockname = 'html'";
+        $params = array($this->restoreid, $this->mapping);
+        return ($DB->get_recordset_sql($sql, $params));
+    }
+
+    protected function preprocess_field($field) {
+        $this->configdata = unserialize(base64_decode($field));
+        return isset($this->configdata->text) ? $this->configdata->text : '';
+    }
+
+    protected function postprocess_field($field) {
+        $this->configdata->text = $field;
+        return base64_encode(serialize($this->configdata));
+    }
+}
diff --git a/html/block_html.php b/html/block_html.php
new file mode 100644
index 0000000..505ff27
--- /dev/null
+++ b/html/block_html.php
@@ -0,0 +1,177 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Form for editing HTML block instances.
+ *
+ * @package   block_html
+ * @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class block_html extends block_base {
+
+    function init() {
+        $this->title = get_string('pluginname', 'block_html');
+    }
+
+    function has_config() {
+        return true;
+    }
+
+    function applicable_formats() {
+        return array('all' => true);
+    }
+
+    function specialization() {
+        if (isset($this->config->title)) {
+            $this->title = $this->title = format_string($this->config->title, true, ['context' => $this->context]);
+        } else {
+            $this->title = get_string('newhtmlblock', 'block_html');
+        }
+    }
+
+    function instance_allow_multiple() {
+        return true;
+    }
+
+    function get_content() {
+        global $CFG;
+
+        require_once($CFG->libdir . '/filelib.php');
+
+        if ($this->content !== NULL) {
+            return $this->content;
+        }
+
+        $filteropt = new stdClass;
+        $filteropt->overflowdiv = true;
+        if ($this->content_is_trusted()) {
+            // fancy html allowed only on course, category and system blocks.
+            $filteropt->noclean = true;
+        }
+
+        $this->content = new stdClass;
+        $this->content->footer = '';
+        if (isset($this->config->text)) {
+            // rewrite url
+            $this->config->text = file_rewrite_pluginfile_urls($this->config->text, 'pluginfile.php', $this->context->id, 'block_html', 'content', NULL);
+            // Default to FORMAT_HTML which is what will have been used before the
+            // editor was properly implemented for the block.
+            $format = FORMAT_HTML;
+            // Check to see if the format has been properly set on the config
+            if (isset($this->config->format)) {
+                $format = $this->config->format;
+            }
+            $this->content->text = format_text($this->config->text, $format, $filteropt);
+        } else {
+            $this->content->text = '';
+        }
+
+        unset($filteropt); // memory footprint
+
+        return $this->content;
+    }
+
+
+    /**
+     * Serialize and store config data
+     */
+    function instance_config_save($data, $nolongerused = false) {
+        global $DB;
+
+        $config = clone($data);
+        // Move embedded files into a proper filearea and adjust HTML links to match
+        $config->text = file_save_draft_area_files($data->text['itemid'], $this->context->id, 'block_html', 'content', 0, array('subdirs'=>true), $data->text['text']);
+        $config->format = $data->text['format'];
+
+        parent::instance_config_save($config, $nolongerused);
+    }
+
+    function instance_delete() {
+        global $DB;
+        $fs = get_file_storage();
+        $fs->delete_area_files($this->context->id, 'block_html');
+        return true;
+    }
+
+    /**
+     * Copy any block-specific data when copying to a new block instance.
+     * @param int $fromid the id number of the block instance to copy from
+     * @return boolean
+     */
+    public function instance_copy($fromid) {
+        $fromcontext = context_block::instance($fromid);
+        $fs = get_file_storage();
+        // This extra check if file area is empty adds one query if it is not empty but saves several if it is.
+        if (!$fs->is_area_empty($fromcontext->id, 'block_html', 'content', 0, false)) {
+            $draftitemid = 0;
+            file_prepare_draft_area($draftitemid, $fromcontext->id, 'block_html', 'content', 0, array('subdirs' => true));
+            file_save_draft_area_files($draftitemid, $this->context->id, 'block_html', 'content', 0, array('subdirs' => true));
+        }
+        return true;
+    }
+
+    function content_is_trusted() {
+        global $SCRIPT;
+
+        if (!$context = context::instance_by_id($this->instance->parentcontextid, IGNORE_MISSING)) {
+            return false;
+        }
+        //find out if this block is on the profile page
+        if ($context->contextlevel == CONTEXT_USER) {
+            if ($SCRIPT === '/my/index.php') {
+                // this is exception - page is completely private, nobody else may see content there
+                // that is why we allow JS here
+                return true;
+            } else {
+                // no JS on public personal pages, it would be a big security issue
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * The block should only be dockable when the title of the block is not empty
+     * and when parent allows docking.
+     *
+     * @return bool
+     */
+    public function instance_can_be_docked() {
+        return (!empty($this->config->title) && parent::instance_can_be_docked());
+    }
+
+    /*
+     * Add custom html attributes to aid with theming and styling
+     *
+     * @return array
+     */
+    function html_attributes() {
+        global $CFG;
+
+        $attributes = parent::html_attributes();
+
+        if (!empty($CFG->block_html_allowcssclasses)) {
+            if (!empty($this->config->classes)) {
+                $attributes['class'] .= ' '.$this->config->classes;
+            }
+        }
+
+        return $attributes;
+    }
+}
diff --git a/html/classes/privacy/provider.php b/html/classes/privacy/provider.php
new file mode 100644
index 0000000..21131fe
--- /dev/null
+++ b/html/classes/privacy/provider.php
@@ -0,0 +1,196 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_html.
+ *
+ * @package    block_html
+ * @copyright  2018 Andrew Nicols <andrew@nicols.co.uk>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_html\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+use \core_privacy\local\request\approved_contextlist;
+use \core_privacy\local\request\writer;
+use \core_privacy\local\request\helper;
+use \core_privacy\local\request\deletion_criteria;
+use \core_privacy\local\metadata\collection;
+
+/**
+ * Privacy Subsystem implementation for block_html.
+ *
+ * @copyright  2018 Andrew Nicols <andrew@nicols.co.uk>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements
+        // The block_html block stores user provided data.
+        \core_privacy\local\metadata\provider,
+
+        // The block_html block provides data directly to core.
+        \core_privacy\local\request\plugin\provider {
+
+    /**
+     * Returns information about how block_html stores its data.
+     *
+     * @param   collection     $collection The initialised collection to add items to.
+     * @return  collection     A listing of user data stored through this system.
+     */
+    public static function get_metadata(collection $collection) : collection {
+        $collection->link_subsystem('block', 'privacy:metadata:block');
+
+        return $collection;
+    }
+
+    /**
+     * Get the list of contexts that contain user information for the specified user.
+     *
+     * @param   int         $userid     The user to search.
+     * @return  contextlist   $contextlist  The contextlist containing the list of contexts used in this plugin.
+     */
+    public static function get_contexts_for_userid(int $userid) : \core_privacy\local\request\contextlist {
+        // This block doesn't know who information is stored against unless it
+        // is at the user context.
+        $contextlist = new \core_privacy\local\request\contextlist();
+
+        $sql = "SELECT c.id
+                  FROM {block_instances} b
+            INNER JOIN {context} c ON c.instanceid = b.id AND c.contextlevel = :contextblock
+            INNER JOIN {context} bpc ON bpc.id = b.parentcontextid
+                 WHERE b.blockname = 'html'
+                   AND bpc.contextlevel = :contextuser
+                   AND bpc.instanceid = :userid";
+
+        $params = [
+            'contextblock' => CONTEXT_BLOCK,
+            'contextuser' => CONTEXT_USER,
+            'userid' => $userid,
+        ];
+
+        $contextlist->add_from_sql($sql, $params);
+
+        return $contextlist;
+    }
+
+    /**
+     * Export all user data for the specified user, in the specified contexts.
+     *
+     * @param   approved_contextlist    $contextlist    The approved contexts to export information for.
+     */
+    public static function export_user_data(approved_contextlist $contextlist) {
+        global $DB;
+
+        $user = $contextlist->get_user();
+
+        list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
+
+        $sql = "SELECT
+                    c.id AS contextid,
+                    bi.*
+                  FROM {context} c
+            INNER JOIN {block_instances} bi ON bi.id = c.instanceid AND c.contextlevel = :contextlevel
+                 WHERE bi.blockname = 'html'
+                   AND(
+                    c.id {$contextsql}
+                )
+        ";
+
+        $params = [
+            'contextlevel' => CONTEXT_BLOCK,
+        ];
+        $params += $contextparams;
+
+        $instances = $DB->get_recordset_sql($sql, $params);
+        foreach ($instances as $instance) {
+            $context = \context_block::instance($instance->id);
+            $block = block_instance('html', $instance);
+            if (empty($block->config)) {
+                // Skip this block. It has not been configured.
+                continue;
+            }
+
+            $html = writer::with_context($context)
+                ->rewrite_pluginfile_urls([], 'block_html', 'content', null, $block->config->text);
+
+            // Default to FORMAT_HTML which is what will have been used before the
+            // editor was properly implemented for the block.
+            $format = isset($block->config->format) ? $block->config->format : FORMAT_HTML;
+
+            $filteropt = (object) [
+                'overflowdiv' => true,
+                'noclean' => true,
+            ];
+            $html = format_text($html, $format, $filteropt);
+
+            $data = helper::get_context_data($context, $user);
+            helper::export_context_files($context, $user);
+            $data->title = $block->config->title;
+            $data->content = $html;
+
+            writer::with_context($context)->export_data([], $data);
+        }
+        $instances->close();
+    }
+
+    /**
+     * Delete all data for all users in the specified context.
+     *
+     * @param   context                 $context   The specific context to delete data for.
+     */
+    public static function delete_data_for_all_users_in_context(\context $context) {
+
+        if (!$context instanceof \context_block) {
+            return;
+        }
+
+        // The only way to delete data for the html block is to delete the block instance itself.
+        if ($blockinstance = static::get_instance_from_context($context)) {
+            blocks_delete_instance($blockinstance);
+        }
+    }
+
+    /**
+     * Delete all user data for the specified user, in the specified contexts.
+     *
+     * @param   approved_contextlist    $contextlist    The approved contexts and user information to delete information for.
+     */
+    public static function delete_data_for_user(approved_contextlist $contextlist) {
+        // The only way to delete data for the html block is to delete the block instance itself.
+        foreach ($contextlist as $context) {
+
+            if (!$context instanceof \context_block) {
+                continue;
+            }
+            if ($blockinstance = static::get_instance_from_context($context)) {
+                blocks_delete_instance($blockinstance);
+            }
+        }
+    }
+
+    /**
+     * Get the block instance record for the specified context.
+     *
+     * @param   \context_block $context The context to fetch
+     * @return  \stdClass
+     */
+    protected static function get_instance_from_context(\context_block $context) {
+        global $DB;
+
+        return $DB->get_record('block_instances', ['id' => $context->instanceid, 'blockname' => 'html']);
+    }
+}
diff --git a/html/classes/search/content.php b/html/classes/search/content.php
new file mode 100644
index 0000000..32b20b9
--- /dev/null
+++ b/html/classes/search/content.php
@@ -0,0 +1,91 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Search area for block_html blocks
+ *
+ * @package block_html
+ * @copyright 2017 The Open University
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_html\search;
+
+use core_search\moodle_recordset;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Search area for block_html blocks
+ *
+ * @package block_html
+ * @copyright 2017 The Open University
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class content extends \core_search\base_block {
+
+    public function get_document($record, $options = array()) {
+        // Create empty document.
+        $doc = \core_search\document_factory::instance($record->id,
+                $this->componentname, $this->areaname);
+
+        // Get stdclass object with data from DB.
+        $data = unserialize(base64_decode($record->configdata));
+
+        // Get content.
+        $content = content_to_text($data->text, $data->format);
+        $doc->set('content', $content);
+
+        if (isset($data->title)) {
+            // If there is a title, use it as title.
+            $doc->set('title', content_to_text($data->title, false));
+        } else {
+            // If there is no title, use the content text again.
+            $doc->set('title', shorten_text($content));
+        }
+
+        // Set standard fields.
+        $doc->set('contextid', $record->contextid);
+        $doc->set('type', \core_search\manager::TYPE_TEXT);
+        $doc->set('courseid', $record->courseid);
+        $doc->set('modified', $record->timemodified);
+        $doc->set('owneruserid', \core_search\manager::NO_OWNER_ID);
+
+        // Mark document new if appropriate.
+        if (isset($options['lastindexedtime']) &&
+                ($options['lastindexedtime'] < $record->timecreated)) {
+            // If the document was created after the last index time, it must be new.
+            $doc->set_is_new(true);
+        }
+
+        return $doc;
+    }
+
+    public function uses_file_indexing() {
+        return true;
+    }
+
+    public function attach_files($document) {
+        $fs = get_file_storage();
+
+        $context = \context::instance_by_id($document->get('contextid'));
+
+        $files = $fs->get_area_files($context->id, 'block_html', 'content');
+        foreach ($files as $file) {
+            $document->add_stored_file($file);
+        }
+    }
+}
diff --git a/html/db/access.php b/html/db/access.php
new file mode 100644
index 0000000..84c5836
--- /dev/null
+++ b/html/db/access.php
@@ -0,0 +1,51 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * HTML block caps.
+ *
+ * @package    block_html
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/html:myaddinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/my:manageblocks'
+    ),
+
+    'block/html:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/html/db/upgrade.php b/html/db/upgrade.php
new file mode 100644
index 0000000..5ad7f22
--- /dev/null
+++ b/html/db/upgrade.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file keeps track of upgrades to the html block
+ *
+ * @since Moodle 2.0
+ * @package block_html
+ * @copyright 2010 Dongsheng Cai
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Upgrade code for the HTML block.
+ *
+ * @param int $oldversion
+ */
+function xmldb_block_html_upgrade($oldversion) {
+    global $CFG;
+
+    // Automatically generated Moodle v3.2.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.3.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.4.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    return true;
+}
diff --git a/html/edit_form.php b/html/edit_form.php
new file mode 100644
index 0000000..1f04ea7
--- /dev/null
+++ b/html/edit_form.php
@@ -0,0 +1,91 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Form for editing HTML block instances.
+ *
+ * @package   block_html
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Form for editing HTML block instances.
+ *
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_html_edit_form extends block_edit_form {
+    protected function specific_definition($mform) {
+        global $CFG;
+
+        // Fields for editing HTML block title and contents.
+        $mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
+
+        $mform->addElement('text', 'config_title', get_string('configtitle', 'block_html'));
+        $mform->setType('config_title', PARAM_TEXT);
+
+        $editoroptions = array('maxfiles' => EDITOR_UNLIMITED_FILES, 'noclean'=>true, 'context'=>$this->block->context);
+        $mform->addElement('editor', 'config_text', get_string('configcontent', 'block_html'), null, $editoroptions);
+        $mform->addRule('config_text', null, 'required', null, 'client');
+        $mform->setType('config_text', PARAM_RAW); // XSS is prevented when printing the block contents and serving files
+
+        if (!empty($CFG->block_html_allowcssclasses)) {
+            $mform->addElement('text', 'config_classes', get_string('configclasses', 'block_html'));
+            $mform->setType('config_classes', PARAM_TEXT);
+            $mform->addHelpButton('config_classes', 'configclasses', 'block_html');
+        }
+    }
+
+    function set_data($defaults) {
+        if (!empty($this->block->config) && is_object($this->block->config)) {
+            $text = $this->block->config->text;
+            $draftid_editor = file_get_submitted_draft_itemid('config_text');
+            if (empty($text)) {
+                $currenttext = '';
+            } else {
+                $currenttext = $text;
+            }
+            $defaults->config_text['text'] = file_prepare_draft_area($draftid_editor, $this->block->context->id, 'block_html', 'content', 0, array('subdirs'=>true), $currenttext);
+            $defaults->config_text['itemid'] = $draftid_editor;
+            $defaults->config_text['format'] = $this->block->config->format;
+        } else {
+            $text = '';
+        }
+
+        if (!$this->block->user_can_edit() && !empty($this->block->config->title)) {
+            // If a title has been set but the user cannot edit it format it nicely
+            $title = $this->block->config->title;
+            $defaults->config_title = format_string($title, true, $this->page->context);
+            // Remove the title from the config so that parent::set_data doesn't set it.
+            unset($this->block->config->title);
+        }
+
+        // have to delete text here, otherwise parent::set_data will empty content
+        // of editor
+        unset($this->block->config->text);
+        parent::set_data($defaults);
+        // restore $text
+        if (!isset($this->block->config)) {
+            $this->block->config = new stdClass();
+        }
+        $this->block->config->text = $text;
+        if (isset($title)) {
+            // Reset the preserved title
+            $this->block->config->title = $title;
+        }
+    }
+}
diff --git a/html/lang/en/block_html.php b/html/lang/en/block_html.php
new file mode 100644
index 0000000..6688816
--- /dev/null
+++ b/html/lang/en/block_html.php
@@ -0,0 +1,36 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_html', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_html
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['allowadditionalcssclasses'] = 'Allow additional CSS classes';
+$string['configallowadditionalcssclasses'] = 'Adds a configuration option to HTML block instances allowing additional CSS classes to be set.';
+$string['configclasses'] = 'Additional CSS classes';
+$string['configclasses_help'] = 'The purpose of this configuration is to aid with theming by helping distinguish HTML blocks from each other. Any CSS classes entered here (space delimited) will be appended to the block\'s default classes.';
+$string['configcontent'] = 'Content';
+$string['configtitle'] = 'HTML block title';
+$string['html:addinstance'] = 'Add a new HTML block';
+$string['html:myaddinstance'] = 'Add a new HTML block to Dashboard';
+$string['newhtmlblock'] = '(new HTML block)';
+$string['pluginname'] = 'HTML';
+$string['search:content'] = 'HTML block content';
+$string['privacy:metadata:block'] = 'The HTML block stores all of its data within the block subsystem.';
diff --git a/html/lib.php b/html/lib.php
new file mode 100644
index 0000000..a86b827
--- /dev/null
+++ b/html/lib.php
@@ -0,0 +1,112 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Form for editing HTML block instances.
+ *
+ * @copyright 2010 Petr Skoda (http://skodak.org)
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @package   block_html
+ * @category  files
+ * @param stdClass $course course object
+ * @param stdClass $birecord_or_cm block instance record
+ * @param stdClass $context context object
+ * @param string $filearea file area
+ * @param array $args extra arguments
+ * @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
+ * @return bool
+ * @todo MDL-36050 improve capability check on stick blocks, so we can check user capability before sending images.
+ */
+function block_html_pluginfile($course, $birecord_or_cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
+    global $DB, $CFG, $USER;
+
+    if ($context->contextlevel != CONTEXT_BLOCK) {
+        send_file_not_found();
+    }
+
+    // If block is in course context, then check if user has capability to access course.
+    if ($context->get_course_context(false)) {
+        require_course_login($course);
+    } else if ($CFG->forcelogin) {
+        require_login();
+    } else {
+        // Get parent context and see if user have proper permission.
+        $parentcontext = $context->get_parent_context();
+        if ($parentcontext->contextlevel === CONTEXT_COURSECAT) {
+            // Check if category is visible and user can view this category.
+            $category = $DB->get_record('course_categories', array('id' => $parentcontext->instanceid), '*', MUST_EXIST);
+            if (!$category->visible) {
+                require_capability('moodle/category:viewhiddencategories', $parentcontext);
+            }
+        } else if ($parentcontext->contextlevel === CONTEXT_USER && $parentcontext->instanceid != $USER->id) {
+            // The block is in the context of a user, it is only visible to the user who it belongs to.
+            send_file_not_found();
+        }
+        // At this point there is no way to check SYSTEM context, so ignoring it.
+    }
+
+    if ($filearea !== 'content') {
+        send_file_not_found();
+    }
+
+    $fs = get_file_storage();
+
+    $filename = array_pop($args);
+    $filepath = $args ? '/'.implode('/', $args).'/' : '/';
+
+    if (!$file = $fs->get_file($context->id, 'block_html', 'content', 0, $filepath, $filename) or $file->is_directory()) {
+        send_file_not_found();
+    }
+
+    if ($parentcontext = context::instance_by_id($birecord_or_cm->parentcontextid, IGNORE_MISSING)) {
+        if ($parentcontext->contextlevel == CONTEXT_USER) {
+            // force download on all personal pages including /my/
+            //because we do not have reliable way to find out from where this is used
+            $forcedownload = true;
+        }
+    } else {
+        // weird, there should be parent context, better force dowload then
+        $forcedownload = true;
+    }
+
+    // NOTE: it woudl be nice to have file revisions here, for now rely on standard file lifetime,
+    //       do not lower it because the files are dispalyed very often.
+    \core\session\manager::write_close();
+    send_stored_file($file, null, 0, $forcedownload, $options);
+}
+
+/**
+ * Perform global search replace such as when migrating site to new URL.
+ * @param  $search
+ * @param  $replace
+ * @return void
+ */
+function block_html_global_db_replace($search, $replace) {
+    global $DB;
+
+    $instances = $DB->get_recordset('block_instances', array('blockname' => 'html'));
+    foreach ($instances as $instance) {
+        // TODO: intentionally hardcoded until MDL-26800 is fixed
+        $config = unserialize(base64_decode($instance->configdata));
+        if (isset($config->text) and is_string($config->text)) {
+            $config->text = str_replace($search, $replace, $config->text);
+            $DB->update_record('block_instances', ['id' => $instance->id,
+                    'configdata' => base64_encode(serialize($config)), 'timemodified' => time()]);
+        }
+    }
+    $instances->close();
+}
diff --git a/html/settings.php b/html/settings.php
new file mode 100644
index 0000000..11c3a6e
--- /dev/null
+++ b/html/settings.php
@@ -0,0 +1,32 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Settings for the HTML block
+ *
+ * @copyright 2012 Aaron Barnes
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @package   block_html
+ */
+
+defined('MOODLE_INTERNAL') || die;
+
+if ($ADMIN->fulltree) {
+    $settings->add(new admin_setting_configcheckbox('block_html_allowcssclasses', get_string('allowadditionalcssclasses', 'block_html'),
+                       get_string('configallowadditionalcssclasses', 'block_html'), 0));
+}
+
+
diff --git a/html/tests/behat/configuring_html_block.feature b/html/tests/behat/configuring_html_block.feature
new file mode 100644
index 0000000..05a00d9
--- /dev/null
+++ b/html/tests/behat/configuring_html_block.feature
@@ -0,0 +1,41 @@
+@block @block_html @core_block
+Feature: Adding and configuring HTML blocks
+  In order to have custom blocks on a page
+  As admin
+  I need to be able to create, configure and change HTML blocks
+
+  @javascript
+  Scenario: Configuring the HTML block with Javascript on
+    Given I log in as "admin"
+    And I am on site homepage
+    When I turn editing mode on
+    And I add the "HTML" block
+    And I configure the "(new HTML block)" block
+    And I set the field "Content" to "Static text without a header"
+    Then I should see "HTML block title"
+    And I press "Save changes"
+    Then I should not see "(new HTML block)"
+    And I configure the "block_html" block
+    And I set the field "HTML block title" to "The HTML block header"
+    And I set the field "Content" to "Static text with a header"
+    And I press "Save changes"
+    And "block_html" "block" should exist
+    And "The HTML block header" "block" should exist
+    And I should see "Static text with a header" in the "The HTML block header" "block"
+
+  Scenario: Configuring the HTML block with Javascript off
+    Given I log in as "admin"
+    And I am on site homepage
+    When I turn editing mode on
+    And I add the "HTML" block
+    And I configure the "(new HTML block)" block
+    And I set the field "Content" to "Static text without a header"
+    And I press "Save changes"
+    Then I should not see "(new HTML block)"
+    And I configure the "block_html" block
+    And I set the field "HTML block title" to "The HTML block header"
+    And I set the field "Content" to "Static text with a header"
+    And I press "Save changes"
+    And "block_html" "block" should exist
+    And "The HTML block header" "block" should exist
+    And I should see "Static text with a header" in the "The HTML block header" "block"
diff --git a/html/tests/behat/course_block.feature b/html/tests/behat/course_block.feature
new file mode 100644
index 0000000..3341177
--- /dev/null
+++ b/html/tests/behat/course_block.feature
@@ -0,0 +1,35 @@
+@block @block_html
+Feature: HTML blocks in a course
+  In order to have one or multiple HTML blocks in a course
+  As a teacher
+  I need to be able to create and change such blocks
+
+  Scenario: Adding HTML block in a course
+    Given the following "users" exist:
+      | username | firstname | lastname | email            |
+      | teacher1 | Terry1    | Teacher1 | teacher@example.com  |
+      | student1 | Sam1      | Student1 | student1@example.com |
+    And the following "courses" exist:
+      | fullname | shortname |
+      | Course 1 | C1        |
+    And the following "course enrolments" exist:
+      | user     | course | role           |
+      | teacher1 | C1     | editingteacher |
+      | student1 | C1     | student        |
+    When I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "HTML" block
+    And I configure the "(new HTML block)" block
+    And I set the field "Content" to "First block content"
+    And I set the field "HTML block title" to "First block header"
+    And I press "Save changes"
+    And I add the "HTML" block
+    And I configure the "(new HTML block)" block
+    And I set the field "Content" to "Second block content"
+    And I set the field "HTML block title" to "Second block header"
+    And I press "Save changes"
+    And I log out
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "First block content" in the "First block header" "block"
+    And I should see "Second block content" in the "Second block header" "block"
diff --git a/html/tests/behat/multiple_instances.feature b/html/tests/behat/multiple_instances.feature
new file mode 100644
index 0000000..3ed187b
--- /dev/null
+++ b/html/tests/behat/multiple_instances.feature
@@ -0,0 +1,42 @@
+@block @block_html
+Feature: Adding and configuring multiple HTML blocks
+  In order to have one or multiple HTML blocks on a page
+  As admin
+  I need to be able to create, configure and change HTML blocks
+
+  Background:
+    Given I log in as "admin"
+    And I am on site homepage
+    When I turn editing mode on
+    And I add the "HTML" block
+
+  Scenario: Other users can not see HTML block that has not been configured
+    Then "(new HTML block)" "block" should exist
+    And I log out
+    And "(new HTML block)" "block" should not exist
+    And "block_html" "block" should not exist
+
+  Scenario: Other users can see HTML block that has been configured even when it has no header
+    And I configure the "(new HTML block)" block
+    And I set the field "Content" to "Static text without a header"
+    And I press "Save changes"
+    Then I should not see "(new HTML block)"
+    And I log out
+    And I am on homepage
+    And "block_html" "block" should exist
+    And I should see "Static text without a header" in the "block_html" "block"
+    And I should not see "(new HTML block)"
+
+  Scenario: Adding multiple instances of HTML block on a page
+    And I configure the "block_html" block
+    And I set the field "HTML block title" to "The HTML block header"
+    And I set the field "Content" to "Static text with a header"
+    And I press "Save changes"
+    And I add the "HTML" block
+    And I configure the "(new HTML block)" block
+    And I set the field "HTML block title" to "The second HTML block header"
+    And I set the field "Content" to "Second block contents"
+    And I press "Save changes"
+    And I log out
+    Then I should see "Static text with a header" in the "The HTML block header" "block"
+    And I should see "Second block contents" in the "The second HTML block header" "block"
diff --git a/html/tests/privacy_provider_test.php b/html/tests/privacy_provider_test.php
new file mode 100644
index 0000000..94d38ca
--- /dev/null
+++ b/html/tests/privacy_provider_test.php
@@ -0,0 +1,344 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Unit tests for the block_html implementation of the privacy API.
+ *
+ * @package    block_html
+ * @category   test
+ * @copyright  2018 Andrew Nicols <andrew@nicols.co.uk>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+use \core_privacy\local\request\writer;
+use \core_privacy\local\request\approved_contextlist;
+use \block_html\privacy\provider;
+
+/**
+ * Unit tests for the block_html implementation of the privacy API.
+ *
+ * @copyright  2018 Andrew Nicols <andrew@nicols.co.uk>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_html_privacy_testcase extends \core_privacy\tests\provider_testcase {
+    /**
+     * Get the list of standard format options for comparison.
+     *
+     * @return \stdClass
+     */
+    protected function get_format_options() {
+        return (object) [
+            'overflowdiv' => true,
+            'noclean' => true,
+        ];
+    }
+
+    /**
+     * Creates an HTML block on a user.
+     *
+     * @param   string  $title
+     * @param   string  $body
+     * @param   string  $format
+     * @return  \block_instance
+     */
+    protected function create_user_block($title, $body, $format) {
+        global $USER;
+
+        $configdata = (object) [
+            'title' => $title,
+            'text' => [
+                'itemid' => 19,
+                'text' => $body,
+                'format' => $format,
+            ],
+        ];
+
+        $this->create_block($this->construct_user_page($USER));
+        $block = $this->get_last_block_on_page($this->construct_user_page($USER));
+        $block = block_instance('html', $block->instance);
+        $block->instance_config_save((object) $configdata);
+
+        return $block;
+    }
+
+    /**
+     * Creates an HTML block on a course.
+     *
+     * @param   \stdClass $course
+     * @param   string  $title
+     * @param   string  $body
+     * @param   string  $format
+     * @return  \block_instance
+     */
+    protected function create_course_block($course, $title, $body, $format) {
+        global $USER;
+
+        $configdata = (object) [
+            'title' => $title,
+            'text' => [
+                'itemid' => 19,
+                'text' => $body,
+                'format' => $format,
+            ],
+        ];
+
+        $this->create_block($this->construct_course_page($course));
+        $block = $this->get_last_block_on_page($this->construct_course_page($course));
+        $block = block_instance('html', $block->instance);
+        $block->instance_config_save((object) $configdata);
+
+        return $block;
+    }
+
+    /**
+     * Creates an HTML block on a page.
+     *
+     * @param \page $page Page
+     */
+    protected function create_block($page) {
+        $page->blocks->add_block_at_end_of_default_region('html');
+    }
+
+    /**
+     * Get the last block on the page.
+     *
+     * @param \page $page Page
+     * @return \block_html Block instance object
+     */
+    protected function get_last_block_on_page($page) {
+        $blocks = $page->blocks->get_blocks_for_region($page->blocks->get_default_region());
+        $block = end($blocks);
+
+        return $block;
+    }
+
+    /**
+     * Constructs a Page object for the User Dashboard.
+     *
+     * @param   \stdClass       $user User to create Dashboard for.
+     * @return  \moodle_page
+     */
+    protected function construct_user_page(\stdClass $user) {
+        $page = new \moodle_page();
+        $page->set_context(\context_user::instance($user->id));
+        $page->set_pagelayout('mydashboard');
+        $page->set_pagetype('my-index');
+        $page->blocks->load_blocks();
+        return $page;
+    }
+
+    /**
+     * Constructs a Page object for the User Dashboard.
+     *
+     * @param   \stdClass       $course Course to create Dashboard for.
+     * @return  \moodle_page
+     */
+    protected function construct_course_page(\stdClass $course) {
+        $page = new \moodle_page();
+        $page->set_context(\context_course::instance($course->id));
+        $page->set_pagelayout('standard');
+        $page->set_pagetype('course-view');
+        $page->set_course($course);
+        $page->blocks->load_blocks();
+        return $page;
+    }
+
+    /**
+     * Test that a block on the dashboard is exported.
+     */
+    public function test_user_block() {
+        $this->resetAfterTest();
+
+        $title = 'Example title';
+        $content = 'Example content';
+        $format = FORMAT_PLAIN;
+
+        // Test setup.
+        $user = $this->getDataGenerator()->create_user();
+        $this->setUser($user);
+        $block = $this->create_user_block($title, $content, $format);
+        $context = \context_block::instance($block->instance->id);
+
+        // Get the contexts.
+        $contextlist = provider::get_contexts_for_userid($user->id);
+
+        // Only the user context should be returned.
+        $this->assertCount(1, $contextlist);
+        $this->assertEquals($context, $contextlist->current());
+
+        // Export the data.
+        $this->export_context_data_for_user($user->id, $context, 'block_html');
+        $writer = \core_privacy\local\request\writer::with_context($context);
+        $this->assertTrue($writer->has_any_data());
+
+        // Check the data.
+        $data = $writer->get_data([]);
+        $this->assertInstanceOf('stdClass', $data);
+        $this->assertEquals($title, $data->title);
+        $this->assertEquals(format_text($content, $format, $this->get_format_options()), $data->content);
+
+        // Delete the context.
+        provider::delete_data_for_all_users_in_context($context);
+
+        // Re-fetch the contexts - it should no longer be returned.
+        $contextlist = provider::get_contexts_for_userid($user->id);
+        $this->assertCount(0, $contextlist);
+    }
+
+    /**
+     * Test that a block on the dashboard which is not configured is _not_ exported.
+     */
+    public function test_user_block_unconfigured() {
+        global $DB;
+
+        $this->resetAfterTest();
+
+        $title = 'Example title';
+        $content = 'Example content';
+        $format = FORMAT_PLAIN;
+
+        // Test setup.
+        $user = $this->getDataGenerator()->create_user();
+        $this->setUser($user);
+        $block = $this->create_user_block($title, $content, $format);
+        $block->instance->configdata = '';
+        $DB->update_record('block_instances', $block->instance);
+        $block = block_instance('html', $block->instance);
+
+        $context = \context_block::instance($block->instance->id);
+
+        // Get the contexts.
+        $contextlist = provider::get_contexts_for_userid($user->id);
+
+        // Only the user context should be returned.
+        $this->assertCount(1, $contextlist);
+        $this->assertEquals($context, $contextlist->current());
+
+        // Export the data.
+        $this->export_context_data_for_user($user->id, $context, 'block_html');
+        $writer = \core_privacy\local\request\writer::with_context($context);
+        $this->assertFalse($writer->has_any_data());
+    }
+
+    /**
+     * Test that a block on the dashboard is exported.
+     */
+    public function test_user_multiple_blocks_exported() {
+        $this->resetAfterTest();
+
+        $title = 'Example title';
+        $content = 'Example content';
+        $format = FORMAT_PLAIN;
+
+        // Test setup.
+        $blocks = [];
+        $contexts = [];
+        $user = $this->getDataGenerator()->create_user();
+        $this->setUser($user);
+
+        $block = $this->create_user_block($title, $content, $format);
+        $context = \context_block::instance($block->instance->id);
+        $contexts[$context->id] = $context;
+
+        $block = $this->create_user_block($title, $content, $format);
+        $context = \context_block::instance($block->instance->id);
+        $contexts[$context->id] = $context;
+
+        // Get the contexts.
+        $contextlist = provider::get_contexts_for_userid($user->id);
+
+        // There are now two blocks on the user context.
+        $this->assertCount(2, $contextlist);
+        foreach ($contextlist as $context) {
+            $this->assertTrue(isset($contexts[$context->id]));
+        }
+
+        // Turn them into an approved_contextlist.
+        $approvedlist = new approved_contextlist($user, 'block_html', $contextlist->get_contextids());
+
+        // Delete using delete_data_for_user.
+        provider::delete_data_for_user($approvedlist);
+
+        // Re-fetch the contexts - it should no longer be returned.
+        $contextlist = provider::get_contexts_for_userid($user->id);
+        $this->assertCount(0, $contextlist);
+    }
+
+    /**
+     * Test that a block on the dashboard is not exported.
+     */
+    public function test_course_blocks_not_exported() {
+        $this->resetAfterTest();
+
+        $title = 'Example title';
+        $content = 'Example content';
+        $format = FORMAT_PLAIN;
+
+        // Test setup.
+        $user = $this->getDataGenerator()->create_user();
+        $course = $this->getDataGenerator()->create_course();
+        $this->setUser($user);
+
+        $block = $this->create_course_block($course, $title, $content, $format);
+        $context = \context_block::instance($block->instance->id);
+
+        // Get the contexts.
+        $contextlist = provider::get_contexts_for_userid($user->id);
+
+        // No blocks should be returned.
+        $this->assertCount(0, $contextlist);
+    }
+
+    /**
+     * Test that a block on the dashboard is exported.
+     */
+    public function test_mixed_multiple_blocks_exported() {
+        $this->resetAfterTest();
+
+        $title = 'Example title';
+        $content = 'Example content';
+        $format = FORMAT_PLAIN;
+
+        // Test setup.
+        $contexts = [];
+
+        $user = $this->getDataGenerator()->create_user();
+        $course = $this->getDataGenerator()->create_course();
+        $this->setUser($user);
+
+        $block = $this->create_course_block($course, $title, $content, $format);
+        $context = \context_block::instance($block->instance->id);
+
+        $block = $this->create_user_block($title, $content, $format);
+        $context = \context_block::instance($block->instance->id);
+        $contexts[$context->id] = $context;
+
+        $block = $this->create_user_block($title, $content, $format);
+        $context = \context_block::instance($block->instance->id);
+        $contexts[$context->id] = $context;
+
+        // Get the contexts.
+        $contextlist = provider::get_contexts_for_userid($user->id);
+
+        // There are now two blocks on the user context.
+        $this->assertCount(2, $contextlist);
+        foreach ($contextlist as $context) {
+            $this->assertTrue(isset($contexts[$context->id]));
+        }
+    }
+}
diff --git a/html/tests/search_content_test.php b/html/tests/search_content_test.php
new file mode 100644
index 0000000..5afb8cd
--- /dev/null
+++ b/html/tests/search_content_test.php
@@ -0,0 +1,191 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Unit test for search indexing.
+ *
+ * @package block_html
+ * @copyright 2017 The Open University
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_html;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Unit test for search indexing.
+ *
+ * @package block_html
+ * @copyright 2017 The Open University
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class search_content_testcase extends \advanced_testcase {
+
+    /**
+     * Creates an HTML block on a course.
+     *
+     * @param \stdClass $course Course object
+     * @return \block_html Block instance object
+     */
+    protected function create_block($course) {
+        $page = self::construct_page($course);
+        $page->blocks->add_block_at_end_of_default_region('html');
+
+        // Load the block.
+        $page = self::construct_page($course);
+        $page->blocks->load_blocks();
+        $blocks = $page->blocks->get_blocks_for_region($page->blocks->get_default_region());
+        $block = end($blocks);
+        return $block;
+    }
+
+    /**
+     * Constructs a page object for the test course.
+     *
+     * @param \stdClass $course Moodle course object
+     * @return \moodle_page Page object representing course view
+     */
+    protected static function construct_page($course) {
+        $context = \context_course::instance($course->id);
+        $page = new \moodle_page();
+        $page->set_context($context);
+        $page->set_course($course);
+        $page->set_pagelayout('standard');
+        $page->set_pagetype('course-view');
+        $page->blocks->load_blocks();
+        return $page;
+    }
+
+    /**
+     * Tests all functionality in the search area.
+     */
+    public function test_search_area() {
+        global $CFG, $USER, $DB;
+        require_once($CFG->dirroot . '/search/tests/fixtures/testable_core_search.php');
+
+        $this->resetAfterTest();
+        $this->setAdminUser();
+
+        // Create course and add HTML block.
+        $generator = $this->getDataGenerator();
+        $course = $generator->create_course();
+        $before = time();
+        $block = $this->create_block($course);
+
+        // Change block settings to add some text and a file.
+        $itemid = file_get_unused_draft_itemid();
+        $fs = get_file_storage();
+        $usercontext = \context_user::instance($USER->id);
+        $fs->create_file_from_string(['component' => 'user', 'filearea' => 'draft',
+                'contextid' => $usercontext->id, 'itemid' => $itemid, 'filepath' => '/',
+                'filename' => 'file.txt'], 'File content');
+        $data = (object)['title' => 'Block title', 'text' => ['text' => 'Block text',
+                'itemid' => $itemid, 'format' => FORMAT_HTML]];
+        $block->instance_config_save($data);
+        $after = time();
+
+        // Set up fake search engine so we can create documents.
+        \testable_core_search::instance();
+
+        // Do indexing query.
+        $area = new \block_html\search\content();
+        $this->assertEquals('html', $area->get_block_name());
+        $rs = $area->get_recordset_by_timestamp();
+        $count = 0;
+        foreach ($rs as $record) {
+            $count++;
+
+            $this->assertEquals($course->id, $record->courseid);
+
+            // Check context is correct.
+            $blockcontext = \context::instance_by_id($record->contextid);
+            $this->assertInstanceOf('\context_block', $blockcontext);
+            $coursecontext = $blockcontext->get_parent_context();
+            $this->assertEquals($course->id, $coursecontext->instanceid);
+
+            // Check created and modified times are correct.
+            $this->assertTrue($record->timecreated >= $before && $record->timecreated <= $after);
+            $this->assertTrue($record->timemodified >= $before && $record->timemodified <= $after);
+
+            // Get config data.
+            $data = unserialize(base64_decode($record->configdata));
+            $this->assertEquals('Block title', $data->title);
+            $this->assertEquals('Block text', $data->text);
+            $this->assertEquals(FORMAT_HTML, $data->format);
+
+            // Check the get_document function 'new' flag.
+            $doc = $area->get_document($record, ['lastindexedtime' => 1]);
+            $this->assertTrue($doc->get_is_new());
+            $doc = $area->get_document($record, ['lastindexedtime' => time() + 1]);
+            $this->assertFalse($doc->get_is_new());
+
+            // Check the attach_files function results in correct list of associated files.
+            $this->assertCount(0, $doc->get_files());
+            $area->attach_files($doc);
+            $files = $doc->get_files();
+            $this->assertCount(2, $files);
+            foreach ($files as $file) {
+                if ($file->is_directory()) {
+                    continue;
+                }
+                $this->assertEquals('file.txt', $file->get_filename());
+                $this->assertEquals('File content', $file->get_content());
+            }
+
+            // Check the document fields are all as expected.
+            $this->assertEquals('Block title', $doc->get('title'));
+            $this->assertEquals('Block text', $doc->get('content'));
+            $this->assertEquals($blockcontext->id, $doc->get('contextid'));
+            $this->assertEquals(\core_search\manager::TYPE_TEXT, $doc->get('type'));
+            $this->assertEquals($course->id, $doc->get('courseid'));
+            $this->assertEquals($record->timemodified, $doc->get('modified'));
+            $this->assertEquals(\core_search\manager::NO_OWNER_ID, $doc->get('owneruserid'));
+
+            // Also check getting the doc url and context url.
+            $url = new \moodle_url('/course/view.php', ['id' => $course->id], 'inst' . $record->id);
+            $this->assertTrue($url->compare($area->get_doc_url($doc)));
+            $this->assertTrue($url->compare($area->get_context_url($doc)));
+        }
+        $rs->close();
+
+        // Should only be one HTML block systemwide.
+        $this->assertEquals(1, $count);
+
+        // If we run the query starting from 1 second after now, there should be no results.
+        $rs = $area->get_recordset_by_timestamp($after + 1);
+        $count = 0;
+        foreach ($rs as $record) {
+            $count++;
+        }
+        $rs->close();
+        $this->assertEquals(0, $count);
+
+        // Create another block, but this time leave it empty (no data set). Hack the time though.
+        $block = $this->create_block($course);
+        $DB->set_field('block_instances', 'timemodified',
+                $after + 10, ['id' => $block->instance->id]);
+        $rs = $area->get_recordset_by_timestamp($after + 10);
+        $count = 0;
+        foreach ($rs as $record) {
+            // Because there is no configdata we don't index it.
+            $count++;
+        }
+        $rs->close();
+        $this->assertEquals(0, $count);
+    }
+}
+
diff --git a/html/version.php b/html/version.php
new file mode 100644
index 0000000..07c49bd
--- /dev/null
+++ b/html/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_html
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_html';      // Full name of the plugin (used for diagnostics)
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/index.html
@@ -0,0 +1 @@
+
diff --git a/login/block_login.php b/login/block_login.php
new file mode 100644
index 0000000..e17aea1
--- /dev/null
+++ b/login/block_login.php
@@ -0,0 +1,126 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Login block
+ *
+ * @package   block_login
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class block_login extends block_base {
+    function init() {
+        $this->title = get_string('pluginname', 'block_login');
+    }
+
+    function applicable_formats() {
+        return array('site' => true);
+    }
+
+    function get_content () {
+        global $USER, $CFG, $SESSION, $OUTPUT;
+        require_once($CFG->libdir . '/authlib.php');
+
+        $wwwroot = '';
+        $signup = '';
+
+        if ($this->content !== NULL) {
+            return $this->content;
+        }
+
+        $wwwroot = $CFG->wwwroot;
+
+        if (signup_is_enabled()) {
+            $signup = $wwwroot . '/login/signup.php';
+        }
+        // TODO: now that we have multiauth it is hard to find out if there is a way to change password
+        $forgot = $wwwroot . '/login/forgot_password.php';
+
+
+        $username = get_moodle_cookie();
+
+        $this->content = new stdClass();
+        $this->content->footer = '';
+        $this->content->text = '';
+
+        if (!isloggedin() or isguestuser()) {   // Show the block
+            if (empty($CFG->authloginviaemail)) {
+                $strusername = get_string('username');
+            } else {
+                $strusername = get_string('usernameemail');
+            }
+
+            $this->content->text .= "\n".'<form class="loginform" id="login" method="post" action="'.get_login_url().'">';
+
+            $this->content->text .= '<div class="form-group"><label for="login_username">'.$strusername.'</label>';
+            $this->content->text .= '<input type="text" name="username" id="login_username" class="form-control" value="'.s($username).'" /></div>';
+
+            $this->content->text .= '<div class="form-group"><label for="login_password">'.get_string('password').'</label>';
+
+            $this->content->text .= '<input type="password" name="password" id="login_password" class="form-control" value="" /></div>';
+
+            if (isset($CFG->rememberusername) and $CFG->rememberusername == 2) {
+                $checked = $username ? 'checked="checked"' : '';
+                $this->content->text .= '<div class="form-check">';
+                $this->content->text .= '<label class="form-check-label">';
+                $this->content->text .= '<input type="checkbox" name="rememberusername" id="rememberusername"
+                        class="form-check-input" value="1" '.$checked.'/> ';
+                $this->content->text .= get_string('rememberusername', 'admin').'</label>';
+                $this->content->text .= '</div>';
+            }
+
+            $this->content->text .= '<div class="form-group">';
+            $this->content->text .= '<input type="submit" class="btn btn-primary btn-block" value="'.get_string('login').'" />';
+            $this->content->text .= '</div>';
+
+            $this->content->text .= "</form>\n";
+
+            if (!empty($signup)) {
+                $this->content->text .= '<div><a href="'.$signup.'">'.get_string('startsignup').'</a></div>';
+            }
+            if (!empty($forgot)) {
+                $this->content->text .= '<div><a href="'.$forgot.'">'.get_string('forgotaccount').'</a></div>';
+            }
+
+            $authsequence = get_enabled_auth_plugins(true); // Get all auths, in sequence.
+            $potentialidps = array();
+            foreach ($authsequence as $authname) {
+                $authplugin = get_auth_plugin($authname);
+                $potentialidps = array_merge($potentialidps, $authplugin->loginpage_idp_list($this->page->url->out(false)));
+            }
+
+            if (!empty($potentialidps)) {
+                $this->content->text .= '<div class="potentialidps">';
+                $this->content->text .= '<h6>' . get_string('potentialidps', 'auth') . '</h6>';
+                $this->content->text .= '<div class="potentialidplist">';
+                foreach ($potentialidps as $idp) {
+                    $this->content->text .= '<div class="potentialidp">';
+                    $this->content->text .= '<a class="btn btn-default btn-block" ';
+                    $this->content->text .= 'href="' . $idp['url']->out() . '" title="' . s($idp['name']) . '">';
+                    if (!empty($idp['iconurl'])) {
+                        $this->content->text .= '<img src="' . s($idp['iconurl']) . '" width="24" height="24" class="m-r-1"/>';
+                    }
+                    $this->content->text .= s($idp['name']) . '</a></div>';
+                }
+                $this->content->text .= '</div>';
+                $this->content->text .= '</div>';
+            }
+        }
+
+        return $this->content;
+    }
+}
diff --git a/login/classes/privacy/provider.php b/login/classes/privacy/provider.php
new file mode 100644
index 0000000..3978b4f
--- /dev/null
+++ b/login/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_login.
+ *
+ * @package    block_login
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_login\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_login implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/login/db/access.php b/login/db/access.php
new file mode 100644
index 0000000..51bc829
--- /dev/null
+++ b/login/db/access.php
@@ -0,0 +1,41 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Login block caps.
+ *
+ * @package    block_login
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/login:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/login/lang/en/block_login.php b/login/lang/en/block_login.php
new file mode 100644
index 0000000..29b53ad
--- /dev/null
+++ b/login/lang/en/block_login.php
@@ -0,0 +1,27 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_login', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_login
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['login:addinstance'] = 'Add a new login block';
+$string['pluginname'] = 'Login';
+$string['privacy:metadata'] = 'The Login block only provides a way to log in and does not store any data itself.';
diff --git a/login/tests/behat/login_block.feature b/login/tests/behat/login_block.feature
new file mode 100644
index 0000000..caaa06b
--- /dev/null
+++ b/login/tests/behat/login_block.feature
@@ -0,0 +1,28 @@
+@block @block_login
+Feature: Login from a block
+    In order to make it easier to login
+    As an user
+    In need to login through a block
+
+  Background:
+    Given the following "users" exist:
+      | username | password | firstname | lastname | email |
+      | testuser | testpass | Test      | User     | student1@example.com |
+    And I log in as "admin"
+    And I am on site homepage
+    And I navigate to "Turn editing on" node in "Front page settings"
+    And I add the "Login" block
+
+  Scenario: Login block visible to non-logged in users
+    Given I log out
+    When I am on homepage
+    Then "Login" "block" should exist
+
+  Scenario: Login as student through login block
+    Given I log out
+    And I am on homepage
+    When I set the field "Username" to "testuser"
+    And I set the field "Password" to "testpass"
+    And I click on "Log in" "button" in the "Login" "block"
+    Then I should see "You are logged in as Test User"
+    And "Login" "block" should not exist
diff --git a/login/version.php b/login/version.php
new file mode 100644
index 0000000..b4caa4f
--- /dev/null
+++ b/login/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_login
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_login';     // Full name of the plugin (used for diagnostics)
diff --git a/lp/block_lp.php b/lp/block_lp.php
new file mode 100644
index 0000000..53fede6
--- /dev/null
+++ b/lp/block_lp.php
@@ -0,0 +1,84 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Block LP main file.
+ *
+ * @package    block_lp
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Block LP class.
+ *
+ * @package    block_lp
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_lp extends block_base {
+
+    /**
+     * Applicable formats.
+     *
+     * @return array
+     */
+    public function applicable_formats() {
+        return array('site' => true, 'course' => true, 'my' => true);
+    }
+
+    /**
+     * Init.
+     *
+     * @return void
+     */
+    public function init() {
+        $this->title = get_string('pluginname', 'block_lp');
+    }
+
+    /**
+     * Get content.
+     *
+     * @return stdClass
+     */
+    public function get_content() {
+        if (isset($this->content)) {
+            return $this->content;
+        }
+        $this->content = new stdClass();
+
+        if (!get_config('core_competency', 'enabled')) {
+            return $this->content;
+        }
+
+        // Block needs a valid, non-guest user to be logged-in in order to display the user's learning plans.
+        if (isloggedin() && !isguestuser()) {
+            $summary = new \block_lp\output\summary();
+            if (!$summary->has_content()) {
+                return $this->content;
+            }
+
+            $renderer = $this->page->get_renderer('block_lp');
+            $this->content->text = $renderer->render($summary);
+            $this->content->footer = '';
+        }
+
+        return $this->content;
+    }
+
+}
diff --git a/lp/classes/output/competencies_to_review_page.php b/lp/classes/output/competencies_to_review_page.php
new file mode 100644
index 0000000..ce15862
--- /dev/null
+++ b/lp/classes/output/competencies_to_review_page.php
@@ -0,0 +1,87 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Competencies to review renderable.
+ *
+ * @package    block_lp
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+namespace block_lp\output;
+defined('MOODLE_INTERNAL') || die();
+
+use renderable;
+use templatable;
+use renderer_base;
+use stdClass;
+use moodle_url;
+use core_competency\api;
+use core_competency\external\competency_exporter;
+use core_competency\external\user_competency_exporter;
+use core_user\external\user_summary_exporter;
+
+/**
+ * Competencies to review renderable class.
+ *
+ * @package    block_lp
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class competencies_to_review_page implements renderable, templatable {
+
+    /** @var array Competencies to review. */
+    protected $compstoreview;
+
+    /**
+     * Constructor.
+     */
+    public function __construct() {
+        $this->compstoreview = api::list_user_competencies_to_review(0, 1000);
+    }
+
+    /**
+     * Export the data.
+     *
+     * @param renderer_base $output
+     * @return stdClass
+     */
+    public function export_for_template(renderer_base $output) {
+        $data = new stdClass();
+
+        $compstoreview = array();
+        foreach ($this->compstoreview['competencies'] as $compdata) {
+            $ucexporter = new user_competency_exporter($compdata->usercompetency,
+                array('scale' => $compdata->competency->get_scale()));
+            $compexporter = new competency_exporter($compdata->competency,
+                array('context' => $compdata->competency->get_context()));
+            $userexporter = new user_summary_exporter($compdata->user);
+            $compstoreview[] = array(
+                'usercompetency' => $ucexporter->export($output),
+                'competency' => $compexporter->export($output),
+                'user' => $userexporter->export($output),
+            );
+        }
+
+        $data = array(
+            'competencies' => $compstoreview,
+            'pluginbaseurl' => (new moodle_url('/blocks/lp'))->out(false),
+        );
+
+        return $data;
+    }
+
+}
diff --git a/lp/classes/output/plans_to_review_page.php b/lp/classes/output/plans_to_review_page.php
new file mode 100644
index 0000000..ddf0624
--- /dev/null
+++ b/lp/classes/output/plans_to_review_page.php
@@ -0,0 +1,82 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Plans to review renderable.
+ *
+ * @package    block_lp
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+namespace block_lp\output;
+defined('MOODLE_INTERNAL') || die();
+
+use renderable;
+use templatable;
+use renderer_base;
+use stdClass;
+use moodle_url;
+use core_competency\api;
+use core_competency\external\plan_exporter;
+use core_user\external\user_summary_exporter;
+
+/**
+ * Plans to review renderable class.
+ *
+ * @package    block_lp
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class plans_to_review_page implements renderable, templatable {
+
+    /** @var array Plans to review. */
+    protected $planstoreview;
+
+    /**
+     * Constructor.
+     */
+    public function __construct() {
+        $this->planstoreview = api::list_plans_to_review(0, 1000);
+    }
+
+    /**
+     * Export the data.
+     *
+     * @param renderer_base $output
+     * @return stdClass
+     */
+    public function export_for_template(renderer_base $output) {
+        $data = new stdClass();
+
+        $planstoreview = array();
+        foreach ($this->planstoreview['plans'] as $plandata) {
+            $planexporter = new plan_exporter($plandata->plan, array('template' => $plandata->template));
+            $userexporter = new user_summary_exporter($plandata->owner);
+            $planstoreview[] = array(
+                'plan' => $planexporter->export($output),
+                'user' => $userexporter->export($output),
+            );
+        }
+
+        $data = array(
+            'plans' => $planstoreview,
+            'pluginbaseurl' => (new moodle_url('/blocks/lp'))->out(false),
+        );
+
+        return $data;
+    }
+
+}
diff --git a/lp/classes/output/renderer.php b/lp/classes/output/renderer.php
new file mode 100644
index 0000000..14e7783
--- /dev/null
+++ b/lp/classes/output/renderer.php
@@ -0,0 +1,70 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Block LP renderer.
+ *
+ * @package    block_lp
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_lp\output;
+defined('MOODLE_INTERNAL') || die();
+
+use plugin_renderer_base;
+use renderable;
+
+/**
+ * Block LP renderer class.
+ *
+ * @package    block_lp
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class renderer extends plugin_renderer_base {
+
+    /**
+     * Defer to template.
+     * @param renderable $page
+     * @return string
+     */
+    public function render_competencies_to_review_page(renderable $page) {
+        $data = $page->export_for_template($this);
+        return parent::render_from_template('block_lp/competencies_to_review_page', $data);
+    }
+
+    /**
+     * Defer to template.
+     * @param renderable $page
+     * @return string
+     */
+    public function render_plans_to_review_page(renderable $page) {
+        $data = $page->export_for_template($this);
+        return parent::render_from_template('block_lp/plans_to_review_page', $data);
+    }
+
+    /**
+     * Defer to template.
+     * @param renderable $summary
+     * @return string
+     */
+    public function render_summary(renderable $summary) {
+        $data = $summary->export_for_template($this);
+        return parent::render_from_template('block_lp/summary', $data);
+    }
+
+}
diff --git a/lp/classes/output/summary.php b/lp/classes/output/summary.php
new file mode 100644
index 0000000..995f6d4
--- /dev/null
+++ b/lp/classes/output/summary.php
@@ -0,0 +1,156 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Summary renderable.
+ *
+ * @package    block_lp
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_lp\output;
+defined('MOODLE_INTERNAL') || die();
+
+use core_competency\api;
+use core_competency\external\competency_exporter;
+use core_competency\external\plan_exporter;
+use core_competency\external\user_competency_exporter;
+use core_user\external\user_summary_exporter;
+use core_competency\plan;
+use core_competency\url;
+use renderable;
+use renderer_base;
+use templatable;
+use required_capability_exception;
+
+/**
+ * Summary renderable class.
+ *
+ * @package    block_lp
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class summary implements renderable, templatable {
+
+    /** @var array Active plans. */
+    protected $activeplans = array();
+    /** @var array Competencies to review. */
+    protected $compstoreview = array();
+    /** @var array Plans to review. */
+    protected $planstoreview = array();
+    /** @var array Plans. */
+    protected $plans = array();
+    /** @var stdClass The user. */
+    protected $user;
+
+    /**
+     * Constructor.
+     * @param stdClass $user The user.
+     */
+    public function __construct($user = null) {
+        global $USER;
+        if (!$user) {
+            $user = $USER;
+        }
+        $this->user = $user;
+
+        // Get the plans.
+        try {
+            $this->plans = api::list_user_plans($this->user->id);
+        } catch (required_capability_exception $e) {
+            $this->plans = [];
+        }
+
+        // Get the competencies to review.
+        $this->compstoreview = api::list_user_competencies_to_review(0, 3);
+
+        // Get the plans to review.
+        $this->planstoreview = api::list_plans_to_review(0, 3);
+    }
+
+    public function export_for_template(renderer_base $output) {
+        $plans = array();
+        foreach ($this->plans as $plan) {
+            if (count($plans) >= 3) {
+                break;
+            }
+            if ($plan->get('status') == plan::STATUS_ACTIVE) {
+                $plans[] = $plan;
+            }
+        }
+        $activeplans = array();
+        foreach ($plans as $plan) {
+            $planexporter = new plan_exporter($plan, array('template' => $plan->get_template()));
+            $activeplans[] = $planexporter->export($output);
+        }
+
+        $compstoreview = array();
+        foreach ($this->compstoreview['competencies'] as $compdata) {
+            $ucexporter = new user_competency_exporter($compdata->usercompetency,
+                array('scale' => $compdata->competency->get_scale()));
+            $compexporter = new competency_exporter($compdata->competency,
+                array('context' => $compdata->competency->get_context()));
+            $userexporter = new user_summary_exporter($compdata->user);
+            $compstoreview[] = array(
+                'usercompetency' => $ucexporter->export($output),
+                'competency' => $compexporter->export($output),
+                'user' => $userexporter->export($output),
+            );
+        }
+
+        $planstoreview = array();
+        foreach ($this->planstoreview['plans'] as $plandata) {
+            $planexporter = new plan_exporter($plandata->plan, array('template' => $plandata->template));
+            $userexporter = new user_summary_exporter($plandata->owner);
+            $planstoreview[] = array(
+                'plan' => $planexporter->export($output),
+                'user' => $userexporter->export($output),
+            );
+        }
+
+        $data = array(
+            'hasplans' => !empty($this->plans),
+            'hasactiveplans' => !empty($activeplans),
+            'hasmoreplans' => count($this->plans) > count($activeplans),
+            'activeplans' => $activeplans,
+
+            'compstoreview' => $compstoreview,
+            'hascompstoreview' => $this->compstoreview['count'] > 0,
+            'hasmorecompstoreview' => $this->compstoreview['count'] > 3,
+
+            'planstoreview' => $planstoreview,
+            'hasplanstoreview' => $this->planstoreview['count'] > 0,
+            'hasmoreplanstoreview' => $this->planstoreview['count'] > 3,
+
+            'plansurl' => url::plans($this->user->id)->out(false),
+            'pluginbaseurl' => (new \moodle_url('/blocks/lp'))->out(false),
+            'userid' => $this->user->id,
+        );
+
+        return $data;
+    }
+
+    /**
+     * Returns whether there is content in the summary.
+     *
+     * @return boolean
+     */
+    public function has_content() {
+        return !empty($this->plans) || $this->planstoreview['count'] > 0 || $this->compstoreview['count'] > 0;
+    }
+
+}
diff --git a/lp/classes/privacy/provider.php b/lp/classes/privacy/provider.php
new file mode 100644
index 0000000..602af6f
--- /dev/null
+++ b/lp/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_lp.
+ *
+ * @package    block_lp
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_lp\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_lp implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/lp/competencies_to_review.php b/lp/competencies_to_review.php
new file mode 100644
index 0000000..817620c
--- /dev/null
+++ b/lp/competencies_to_review.php
@@ -0,0 +1,48 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Competencies to review page.
+ *
+ * @package    block_lp
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once(__DIR__ . '/../../config.php');
+
+require_login(null, false);
+if (isguestuser()) {
+    throw new require_login_exception('Guests are not allowed here.');
+}
+
+$toreviewstr = get_string('competenciestoreview', 'block_lp');
+
+$url = new moodle_url('/blocks/lp/competencies_to_review.php');
+$PAGE->set_context(context_user::instance($USER->id));
+$PAGE->set_url($url);
+$PAGE->set_title($toreviewstr);
+$PAGE->set_pagelayout('standard');
+$PAGE->navbar->add($toreviewstr, $url);
+
+$output = $PAGE->get_renderer('block_lp');
+echo $output->header();
+echo $output->heading($toreviewstr);
+
+$page = new \block_lp\output\competencies_to_review_page();
+echo $output->render($page);
+
+echo $output->footer();
diff --git a/lp/db/access.php b/lp/db/access.php
new file mode 100644
index 0000000..73da9c9
--- /dev/null
+++ b/lp/db/access.php
@@ -0,0 +1,57 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Block LP capabilities.
+ *
+ * @package    block_lp
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    // Whether or not the user can add the block.
+    'block/lp:addinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'manager' => CAP_ALLOW
+        ),
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+
+    // Whether or not the user can add the block on their dashboard.
+    'block/lp:myaddinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        )
+    ),
+
+    // Whether or not a user can see the block.
+    'block/lp:view' => array(
+        'captype' => 'read',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        ),
+    ),
+
+);
diff --git a/lp/lang/en/block_lp.php b/lp/lang/en/block_lp.php
new file mode 100644
index 0000000..520f710
--- /dev/null
+++ b/lp/lang/en/block_lp.php
@@ -0,0 +1,37 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Block LP language strings.
+ *
+ * @package    block_lp
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['competenciestoreview'] = 'Competencies to review';
+$string['lp:addinstance'] = 'Add a new learning plans block';
+$string['lp:myaddinstance'] = 'Add a new learning plans block to Dashboard';
+$string['lp:view'] = 'View learning plans block';
+$string['myplans'] = 'My plans';
+$string['noactiveplans'] = 'No active plans at the moment.';
+$string['planstoreview'] = 'Plans to review';
+$string['pluginname'] = 'Learning plans';
+$string['viewmore'] = 'View more...';
+$string['viewotherplans'] = 'View other plans...';
+$string['privacy:metadata'] = 'The Learning plans block only shows data stored in other locations.';
diff --git a/lp/plans_to_review.php b/lp/plans_to_review.php
new file mode 100644
index 0000000..8643bcf
--- /dev/null
+++ b/lp/plans_to_review.php
@@ -0,0 +1,48 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Competencies to review page.
+ *
+ * @package    block_lp
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once(__DIR__ . '/../../config.php');
+
+require_login(null, false);
+if (isguestuser()) {
+    throw new require_login_exception('Guests are not allowed here.');
+}
+
+$toreviewstr = get_string('planstoreview', 'block_lp');
+
+$url = new moodle_url('/blocks/lp/plans_to_review.php');
+$PAGE->set_context(context_user::instance($USER->id));
+$PAGE->set_url($url);
+$PAGE->set_title($toreviewstr);
+$PAGE->set_pagelayout('standard');
+$PAGE->navbar->add($toreviewstr, $url);
+
+$output = $PAGE->get_renderer('block_lp');
+echo $output->header();
+echo $output->heading($toreviewstr);
+
+$page = new \block_lp\output\plans_to_review_page();
+echo $output->render($page);
+
+echo $output->footer();
diff --git a/lp/styles.css b/lp/styles.css
new file mode 100644
index 0000000..2f06516
--- /dev/null
+++ b/lp/styles.css
@@ -0,0 +1,17 @@
+.block_lp.block .content h3 {
+    padding: 0;
+    text-transform: none;
+}
+
+.block_lp .sub-content {
+    padding: 0 15px;
+}
+
+.block_lp ul {
+    list-style: none;
+    margin: 0;
+}
+
+.block_lp ul .more {
+    padding-top: 10px;
+}
diff --git a/lp/templates/competencies_to_review_page.mustache b/lp/templates/competencies_to_review_page.mustache
new file mode 100644
index 0000000..9038d47
--- /dev/null
+++ b/lp/templates/competencies_to_review_page.mustache
@@ -0,0 +1,49 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    Competencies to review.
+
+    Classes required for JS:
+    * -
+
+    Data attributes required for JS:
+    * -
+
+    Context variables required for this template:
+    * competencies
+}}
+
+<div data-region="competencies-to-review">
+<table class="generaltable fullwidth">
+    <thead>
+        <tr>
+            <th scope="col">{{#str}}shortname, tool_lp{{/str}}</th>
+            <th scope="col">{{#str}}user{{/str}}</th>
+            <th scope="col">{{#str}}reviewstatus, tool_lp{{/str}}</th>
+        </tr>
+    </thead>
+    <tbody>
+        {{#competencies}}
+        <tr>
+            <td><a href="{{usercompetency.url}}">{{{competency.shortname}}}</a></td>
+            <td>{{user.fullname}}</td>
+            <td>{{usercompetency.statusname}}</td>
+        </tr>
+        {{/competencies}}
+    </tbody>
+</table>
+</div>
diff --git a/lp/templates/plans_to_review_page.mustache b/lp/templates/plans_to_review_page.mustache
new file mode 100644
index 0000000..124dcd3
--- /dev/null
+++ b/lp/templates/plans_to_review_page.mustache
@@ -0,0 +1,49 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    Plans to review.
+
+    Classes required for JS:
+    * -
+
+    Data attributes required for JS:
+    * -
+
+    Context variables required for this template:
+    * plans
+}}
+
+<div data-region="plans-to-review">
+<table class="generaltable fullwidth">
+    <thead>
+        <tr>
+            <th scope="col">{{#str}}planname, tool_lp{{/str}}</th>
+            <th scope="col">{{#str}}user{{/str}}</th>
+            <th scope="col">{{#str}}reviewstatus, tool_lp{{/str}}</th>
+        </tr>
+    </thead>
+    <tbody>
+        {{#plans}}
+        <tr>
+            <td><a href="{{plan.url}}">{{{plan.name}}}</a></td>
+            <td>{{user.fullname}}</td>
+            <td>{{plan.statusname}}</td>
+        </tr>
+        {{/plans}}
+    </tbody>
+</table>
+</div>
diff --git a/lp/templates/summary.mustache b/lp/templates/summary.mustache
new file mode 100644
index 0000000..dc0943f
--- /dev/null
+++ b/lp/templates/summary.mustache
@@ -0,0 +1,87 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    Summary.
+
+    Classes required for JS:
+    * None
+
+    Data attibutes required for JS:
+    * None
+
+    Context variables required for this template:
+    * hasplans
+    * hasactiveplans
+    * activeplans
+    * hasmoreplans
+    * hascompstoreview
+    * compstoreview
+    * hasmorecompstoreview
+    * hasplanstoreview
+    * planstoreview
+    * hasmoreplanstoreview
+}}
+<div>
+    {{#hasplans}}
+        <h3>{{#str}}myplans, block_lp{{/str}}</h3>
+        <div class="sub-content">
+            {{#hasactiveplans}}
+                <ul>
+                    {{#activeplans}}
+                        <li><a href="{{url}}">{{{name}}}</a></li>
+                    {{/activeplans}}
+                    {{#hasmoreplans}}
+                        <li class="more"><a href="{{plansurl}}">{{#str}}viewmore, block_lp{{/str}}</a></li>
+                    {{/hasmoreplans}}
+                </ul>
+            {{/hasactiveplans}}
+            {{^hasactiveplans}}
+                <p>{{#str}}noactiveplans, block_lp{{/str}} <a href="{{plansurl}}">{{#str}}viewotherplans, block_lp{{/str}}</a></p>
+            {{/hasactiveplans}}
+        </div>
+    {{/hasplans}}
+    {{#hascompstoreview}}
+        <h3>{{#str}}competenciestoreview, block_lp{{/str}}</h3>
+        <div class="sub-content">
+            <ul>
+                {{#compstoreview}}
+                    <li>
+                        <a href="{{usercompetency.url}}">{{{competency.shortname}}}</a> ({{user.fullname}}) - {{usercompetency.statusname}}
+                    </li>
+                {{/compstoreview}}
+                {{#hasmorecompstoreview}}
+                    <li class="more"><a href="{{pluginbaseurl}}/competencies_to_review.php">{{#str}}viewmore, block_lp{{/str}}</a></li>
+                {{/hasmorecompstoreview}}
+            </ul>
+        </div>
+    {{/hascompstoreview}}
+    {{#hasplanstoreview}}
+        <h3>{{#str}}planstoreview, block_lp{{/str}}</h3>
+        <div class="sub-content">
+            <ul>
+                {{#planstoreview}}
+                    <li>
+                        <a href="{{plan.url}}">{{{plan.name}}}</a> ({{user.fullname}}) - {{plan.statusname}}
+                    </li>
+                {{/planstoreview}}
+                {{#hasmoreplanstoreview}}
+                    <li class="more"><a href="{{pluginbaseurl}}/plans_to_review.php">{{#str}}viewmore, block_lp{{/str}}</a></li>
+                {{/hasmoreplanstoreview}}
+            </ul>
+        </div>
+    {{/hasplanstoreview}}
+</div>
diff --git a/lp/version.php b/lp/version.php
new file mode 100644
index 0000000..8d99fe3
--- /dev/null
+++ b/lp/version.php
@@ -0,0 +1,32 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Block LP version file.
+ *
+ * @package    block_lp
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;
+$plugin->requires  = 2018050800;
+$plugin->component = 'block_lp';
+$plugin->dependencies = array(
+    'tool_lp' => ANY_VERSION
+);
diff --git a/mahara_iena b/mahara_iena
new file mode 160000
index 0000000..fa37238
--- /dev/null
+++ b/mahara_iena
@@ -0,0 +1 @@
+Subproject commit fa37238b9f08eeee40d97b3dbedb8666d6fa13c2
diff --git a/mentees/block_mentees.php b/mentees/block_mentees.php
new file mode 100644
index 0000000..0c2ff91
--- /dev/null
+++ b/mentees/block_mentees.php
@@ -0,0 +1,82 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Mentees block.
+ *
+ * @package    block_mentees
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class block_mentees extends block_base {
+
+    function init() {
+        $this->title = get_string('pluginname', 'block_mentees');
+    }
+
+    function applicable_formats() {
+        return array('all' => true, 'tag' => false);
+    }
+
+    function specialization() {
+        $this->title = isset($this->config->title) ? $this->config->title : get_string('newmenteesblock', 'block_mentees');
+    }
+
+    function instance_allow_multiple() {
+        return true;
+    }
+
+    function get_content() {
+        global $CFG, $USER, $DB;
+
+        if ($this->content !== NULL) {
+            return $this->content;
+        }
+
+        $this->content = new stdClass();
+
+        // get all the mentees, i.e. users you have a direct assignment to
+        $allusernames = get_all_user_name_fields(true, 'u');
+        if ($usercontexts = $DB->get_records_sql("SELECT c.instanceid, c.instanceid, $allusernames
+                                                    FROM {role_assignments} ra, {context} c, {user} u
+                                                   WHERE ra.userid = ?
+                                                         AND ra.contextid = c.id
+                                                         AND c.instanceid = u.id
+                                                         AND c.contextlevel = ".CONTEXT_USER, array($USER->id))) {
+
+            $this->content->text = '<ul>';
+            foreach ($usercontexts as $usercontext) {
+                $this->content->text .= '<li><a href="'.$CFG->wwwroot.'/user/view.php?id='.$usercontext->instanceid.'&amp;course='.SITEID.'">'.fullname($usercontext).'</a></li>';
+            }
+            $this->content->text .= '</ul>';
+        }
+
+        $this->content->footer = '';
+
+        return $this->content;
+    }
+
+    /**
+     * Returns true if the block can be docked.
+     * The mentees block can only be docked if it has a non-empty title.
+     * @return bool
+     */
+    public function instance_can_be_docked() {
+        return parent::instance_can_be_docked() && isset($this->config->title) && !empty($this->config->title);
+    }
+}
+
diff --git a/mentees/classes/privacy/provider.php b/mentees/classes/privacy/provider.php
new file mode 100644
index 0000000..ca86561
--- /dev/null
+++ b/mentees/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_mentees.
+ *
+ * @package    block_mentees
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_mentees\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_mentees implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/mentees/db/access.php b/mentees/db/access.php
new file mode 100644
index 0000000..ba14b07
--- /dev/null
+++ b/mentees/db/access.php
@@ -0,0 +1,51 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Mentees block caps.
+ *
+ * @package    block_mentees
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/mentees:myaddinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/my:manageblocks'
+    ),
+
+    'block/mentees:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/mentees/edit_form.php b/mentees/edit_form.php
new file mode 100644
index 0000000..333497d
--- /dev/null
+++ b/mentees/edit_form.php
@@ -0,0 +1,39 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Form for editing Mentees block instances.
+ *
+ * @package   block_mentees
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Form for editing Mentees block instances.
+ *
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_mentees_edit_form extends block_edit_form {
+    protected function specific_definition($mform) {
+        // Fields for editing HTML block title and contents.
+        $mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
+
+        $mform->addElement('text', 'config_title', get_string('configtitleblankhides', 'block_mentees'));
+        $mform->setType('config_title', PARAM_TEXT);
+    }
+}
\ No newline at end of file
diff --git a/mentees/lang/en/block_mentees.php b/mentees/lang/en/block_mentees.php
new file mode 100644
index 0000000..df160cd
--- /dev/null
+++ b/mentees/lang/en/block_mentees.php
@@ -0,0 +1,32 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_mentees', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_mentees
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['configtitle'] = 'Mentees block title';
+$string['configtitleblankhides'] = 'Mentees block title (no title if blank)';
+$string['mentees:addinstance'] = 'Add a new mentees block';
+$string['mentees:myaddinstance'] = 'Add a new mentees block to Dashboard';
+$string['newmenteesblock'] = '(new Mentees block)';
+$string['pluginname'] = 'Mentees';
+$string['privacy:metadata'] = 'The Mentees block only shows data stored in other locations.';
diff --git a/mentees/tests/behat/configuring_mentees_block.feature b/mentees/tests/behat/configuring_mentees_block.feature
new file mode 100644
index 0000000..3b6df26
--- /dev/null
+++ b/mentees/tests/behat/configuring_mentees_block.feature
@@ -0,0 +1,18 @@
+@block @block_mentees @core_block
+Feature: Adding and configuring Mentees blocks
+  In order to have a Mentees blocks on a page
+  As admin
+  I need to be able to insert and configure a Mentees blocks
+
+  @javascript
+  Scenario: Configuring the Mentees block with Javascript on
+    Given I log in as "admin"
+    And I am on site homepage
+    When I turn editing mode on
+    And I add the "Mentees" block
+    And I configure the "(new Mentees block)" block
+    Then I should see "Mentees block title (no title if blank)"
+    And I set the field "Mentees block title (no title if blank)" to "The Mentees block header"
+    And I press "Save changes"
+    And "block_mentees" "block" should exist
+    Then "The Mentees block header" "block" should exist
diff --git a/mentees/version.php b/mentees/version.php
new file mode 100644
index 0000000..6c47867
--- /dev/null
+++ b/mentees/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_mentees
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_mentees';   // Full name of the plugin (used for diagnostics)
diff --git a/mnet_hosts/block_mnet_hosts.php b/mnet_hosts/block_mnet_hosts.php
new file mode 100644
index 0000000..9e0715c
--- /dev/null
+++ b/mnet_hosts/block_mnet_hosts.php
@@ -0,0 +1,156 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * MNet hosts block.
+ *
+ * @package    block_mnet_hosts
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class block_mnet_hosts extends block_list {
+    function init() {
+        $this->title = get_string('pluginname','block_mnet_hosts') ;
+    }
+
+    function has_config() {
+        return false;
+    }
+
+    function applicable_formats() {
+        if (has_capability('moodle/site:mnetlogintoremote', context_system::instance(), NULL, false)) {
+            return array('all' => true, 'mod' => false, 'tag' => false);
+        } else {
+            return array('site' => true);
+        }
+    }
+
+    function get_content() {
+        global $CFG, $USER, $DB, $OUTPUT;
+
+        // shortcut -  only for logged in users!
+        if (!isloggedin() || isguestuser()) {
+            return false;
+        }
+
+        if (\core\session\manager::is_loggedinas()) {
+            $this->content = new stdClass();
+            $this->content->footer = html_writer::tag('span',
+                get_string('notpermittedtojumpas', 'mnet'));
+            return $this->content;
+        }
+
+        // according to start_jump_session,
+        // remote users can't on-jump
+        // so don't show this block to them
+        if (is_mnet_remote_user($USER)) {
+            if (debugging() and !empty($CFG->debugdisplay)) {
+                $this->content = new stdClass();
+                $this->content->footer = html_writer::tag('span',
+                    get_string('error_localusersonly', 'block_mnet_hosts'),
+                    array('class' => 'error'));
+                return $this->content;
+            } else {
+                return '';
+            }
+        }
+
+        if (!is_enabled_auth('mnet')) {
+            if (debugging() and !empty($CFG->debugdisplay)) {
+                $this->content = new stdClass();
+                $this->content->footer = html_writer::tag('span',
+                    get_string('error_authmnetneeded', 'block_mnet_hosts'),
+                    array('class' => 'error'));
+                return $this->content;
+            } else {
+                return '';
+            }
+        }
+
+        if (!has_capability('moodle/site:mnetlogintoremote', context_system::instance(), NULL, false)) {
+            if (debugging() and !empty($CFG->debugdisplay)) {
+                $this->content = new stdClass();
+                $this->content->footer = html_writer::tag('span',
+                    get_string('error_roamcapabilityneeded', 'block_mnet_hosts'),
+                    array('class' => 'error'));
+                return $this->content;
+            } else {
+                return '';
+            }
+        }
+
+        if ($this->content !== NULL) {
+            return $this->content;
+        }
+
+        // TODO: Test this query - it's appropriate? It works?
+        // get the hosts and whether we are doing SSO with them
+        $sql = "
+             SELECT DISTINCT
+                 h.id,
+                 h.name,
+                 h.wwwroot,
+                 a.name as application,
+                 a.display_name
+             FROM
+                 {mnet_host} h,
+                 {mnet_application} a,
+                 {mnet_host2service} h2s_IDP,
+                 {mnet_service} s_IDP,
+                 {mnet_host2service} h2s_SP,
+                 {mnet_service} s_SP
+             WHERE
+                 h.id <> ? AND
+                 h.id <> ? AND
+                 h.id = h2s_IDP.hostid AND
+                 h.deleted = 0 AND
+                 h.applicationid = a.id AND
+                 h2s_IDP.serviceid = s_IDP.id AND
+                 s_IDP.name = 'sso_idp' AND
+                 h2s_IDP.publish = '1' AND
+                 h.id = h2s_SP.hostid AND
+                 h2s_SP.serviceid = s_SP.id AND
+                 s_SP.name = 'sso_idp' AND
+                 h2s_SP.publish = '1'
+             ORDER BY
+                 a.display_name,
+                 h.name";
+
+        $hosts = $DB->get_records_sql($sql, array($CFG->mnet_localhost_id, $CFG->mnet_all_hosts_id));
+
+        $this->content = new stdClass();
+        $this->content->items = array();
+        $this->content->icons = array();
+        $this->content->footer = '';
+
+        if ($hosts) {
+            foreach ($hosts as $host) {
+                if ($host->id == $USER->mnethostid) {
+                    $url = new \moodle_url($host->wwwroot);
+                } else {
+                    $url = new \moodle_url('/auth/mnet/jump.php', array('hostid' => $host->id));
+                }
+                $this->content->items[] = html_writer::tag('a',
+                    $OUTPUT->pix_icon("i/{$host->application}_host", get_string('server', 'block_mnet_hosts')) . s($host->name),
+                    array('href' => $url->out(), 'title' => s($host->name))
+                );
+            }
+        }
+
+        return $this->content;
+    }
+}
diff --git a/mnet_hosts/classes/privacy/provider.php b/mnet_hosts/classes/privacy/provider.php
new file mode 100644
index 0000000..e70f864
--- /dev/null
+++ b/mnet_hosts/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_mnet_hosts.
+ *
+ * @package    block_mnet_hosts
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_mnet_hosts\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_mnet_hosts implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/mnet_hosts/db/access.php b/mnet_hosts/db/access.php
new file mode 100644
index 0000000..43e2c32
--- /dev/null
+++ b/mnet_hosts/db/access.php
@@ -0,0 +1,51 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Mnet hosts block caps.
+ *
+ * @package    block_mnet_hosts
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/mnet_hosts:myaddinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/my:manageblocks'
+    ),
+
+    'block/mnet_hosts:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/mnet_hosts/lang/en/block_mnet_hosts.php b/mnet_hosts/lang/en/block_mnet_hosts.php
new file mode 100644
index 0000000..4275b75
--- /dev/null
+++ b/mnet_hosts/lang/en/block_mnet_hosts.php
@@ -0,0 +1,32 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_mnet_hosts', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_mnet_hosts
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['error_authmnetneeded'] = 'MNet authentication plugin must be enabled to see the list of MNet network servers';
+$string['error_localusersonly'] = 'Remote users can not jump to other MNet network servers from this host';
+$string['error_roamcapabilityneeded'] = 'Users need the capability \'Roam to a remote application via MNet\' to see the list of MNet network servers';
+$string['mnet_hosts:addinstance'] = 'Add a new network servers block';
+$string['mnet_hosts:myaddinstance'] = 'Add a new network servers block to Dashboard';
+$string['pluginname'] = 'Network servers';
+$string['server'] = 'Server';
+$string['privacy:metadata'] = 'The Network servers block only allows interaction with Network servers and neither stores or exports data itself.';
diff --git a/mnet_hosts/version.php b/mnet_hosts/version.php
new file mode 100644
index 0000000..87c8b62
--- /dev/null
+++ b/mnet_hosts/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_mnet_hosts
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_mnet_hosts'; // Full name of the plugin (used for diagnostics)
diff --git a/moodleblock.class.php b/moodleblock.class.php
new file mode 100644
index 0000000..a81f7ac
--- /dev/null
+++ b/moodleblock.class.php
@@ -0,0 +1,778 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file contains the parent class for moodle blocks, block_base.
+ *
+ * @package    core_block
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU Public License
+ */
+
+/// Constants
+
+/**
+ * Block type of list. Contents of block should be set as an associative array in the content object as items ($this->content->items). Optionally include footer text in $this->content->footer.
+ */
+define('BLOCK_TYPE_LIST',    1);
+
+/**
+ * Block type of text. Contents of block should be set to standard html text in the content object as items ($this->content->text). Optionally include footer text in $this->content->footer.
+ */
+define('BLOCK_TYPE_TEXT',    2);
+/**
+ * Block type of tree. $this->content->items is a list of tree_item objects and $this->content->footer is a string.
+ */
+define('BLOCK_TYPE_TREE',    3);
+
+/**
+ * Class for describing a moodle block, all Moodle blocks derive from this class
+ *
+ * @author Jon Papaioannou
+ * @package core_block
+ */
+class block_base {
+
+    /**
+     * Internal var for storing/caching translated strings
+     * @var string $str
+     */
+    var $str;
+
+    /**
+     * The title of the block to be displayed in the block title area.
+     * @var string $title
+     */
+    var $title         = NULL;
+
+    /**
+     * The name of the block to be displayed in the block title area if the title is empty.
+     * @var string arialabel
+     */
+    var $arialabel         = NULL;
+
+    /**
+     * The type of content that this block creates. Currently support options - BLOCK_TYPE_LIST, BLOCK_TYPE_TEXT
+     * @var int $content_type
+     */
+    var $content_type  = BLOCK_TYPE_TEXT;
+
+    /**
+     * An object to contain the information to be displayed in the block.
+     * @var stdObject $content
+     */
+    var $content       = NULL;
+
+    /**
+     * The initialized instance of this block object.
+     * @var block $instance
+     */
+    var $instance      = NULL;
+
+    /**
+     * The page that this block is appearing on.
+     * @var moodle_page
+     */
+    public $page       = NULL;
+
+    /**
+     * This blocks's context.
+     * @var stdClass
+     */
+    public $context    = NULL;
+
+    /**
+     * An object containing the instance configuration information for the current instance of this block.
+     * @var stdObject $config
+     */
+    var $config        = NULL;
+
+    /**
+     * How often the cronjob should run, 0 if not at all.
+     * @var int $cron
+     */
+
+    var $cron          = NULL;
+
+/// Class Functions
+
+    /**
+     * Fake constructor to keep PHP5 happy
+     *
+     */
+    function __construct() {
+        $this->init();
+    }
+
+    /**
+     * Function that can be overridden to do extra cleanup before
+     * the database tables are deleted. (Called once per block, not per instance!)
+     */
+    function before_delete() {
+    }
+
+    /**
+     * Returns the block name, as present in the class name,
+     * the database, the block directory, etc etc.
+     *
+     * @return string
+     */
+    function name() {
+        // Returns the block name, as present in the class name,
+        // the database, the block directory, etc etc.
+        static $myname;
+        if ($myname === NULL) {
+            $myname = strtolower(get_class($this));
+            $myname = substr($myname, strpos($myname, '_') + 1);
+        }
+        return $myname;
+    }
+
+    /**
+     * Parent class version of this function simply returns NULL
+     * This should be implemented by the derived class to return
+     * the content object.
+     *
+     * @return stdObject
+     */
+    function get_content() {
+        // This should be implemented by the derived class.
+        return NULL;
+    }
+
+    /**
+     * Returns the class $title var value.
+     *
+     * Intentionally doesn't check if a title is set.
+     * This is already done in {@link _self_test()}
+     *
+     * @return string $this->title
+     */
+    function get_title() {
+        // Intentionally doesn't check if a title is set. This is already done in _self_test()
+        return $this->title;
+    }
+
+    /**
+     * Returns the class $content_type var value.
+     *
+     * Intentionally doesn't check if content_type is set.
+     * This is already done in {@link _self_test()}
+     *
+     * @return string $this->content_type
+     */
+    function get_content_type() {
+        // Intentionally doesn't check if a content_type is set. This is already done in _self_test()
+        return $this->content_type;
+    }
+
+    /**
+     * Returns true or false, depending on whether this block has any content to display
+     * and whether the user has permission to view the block
+     *
+     * @return boolean
+     */
+    function is_empty() {
+        if ( !has_capability('moodle/block:view', $this->context) ) {
+            return true;
+        }
+
+        $this->get_content();
+        return(empty($this->content->text) && empty($this->content->footer));
+    }
+
+    /**
+     * First sets the current value of $this->content to NULL
+     * then calls the block's {@link get_content()} function
+     * to set its value back.
+     *
+     * @return stdObject
+     */
+    function refresh_content() {
+        // Nothing special here, depends on content()
+        $this->content = NULL;
+        return $this->get_content();
+    }
+
+    /**
+     * Return a block_contents object representing the full contents of this block.
+     *
+     * This internally calls ->get_content(), and then adds the editing controls etc.
+     *
+     * You probably should not override this method, but instead override
+     * {@link html_attributes()}, {@link formatted_contents()} or {@link get_content()},
+     * {@link hide_header()}, {@link (get_edit_controls)}, etc.
+     *
+     * @return block_contents a representation of the block, for rendering.
+     * @since Moodle 2.0.
+     */
+    public function get_content_for_output($output) {
+        global $CFG;
+
+        $bc = new block_contents($this->html_attributes());
+        $bc->attributes['data-block'] = $this->name();
+        $bc->blockinstanceid = $this->instance->id;
+        $bc->blockpositionid = $this->instance->blockpositionid;
+
+        if ($this->instance->visible) {
+            $bc->content = $this->formatted_contents($output);
+            if (!empty($this->content->footer)) {
+                $bc->footer = $this->content->footer;
+            }
+        } else {
+            $bc->add_class('invisible');
+        }
+
+        if (!$this->hide_header()) {
+            $bc->title = $this->title;
+        }
+
+        if (empty($bc->title)) {
+            $bc->arialabel = new lang_string('pluginname', get_class($this));
+            $this->arialabel = $bc->arialabel;
+        }
+
+        if ($this->page->user_is_editing()) {
+            $bc->controls = $this->page->blocks->edit_controls($this);
+        } else {
+            // we must not use is_empty on hidden blocks
+            if ($this->is_empty() && !$bc->controls) {
+                return null;
+            }
+        }
+
+        if (empty($CFG->allowuserblockhiding)
+                || (empty($bc->content) && empty($bc->footer))
+                || !$this->instance_can_be_collapsed()) {
+            $bc->collapsible = block_contents::NOT_HIDEABLE;
+        } else if (get_user_preferences('block' . $bc->blockinstanceid . 'hidden', false)) {
+            $bc->collapsible = block_contents::HIDDEN;
+        } else {
+            $bc->collapsible = block_contents::VISIBLE;
+        }
+
+        if ($this->instance_can_be_docked() && !$this->hide_header()) {
+            $bc->dockable = true;
+        }
+
+        $bc->annotation = ''; // TODO MDL-19398 need to work out what to say here.
+
+        return $bc;
+    }
+
+    /**
+     * Convert the contents of the block to HTML.
+     *
+     * This is used by block base classes like block_list to convert the structured
+     * $this->content->list and $this->content->icons arrays to HTML. So, in most
+     * blocks, you probaby want to override the {@link get_contents()} method,
+     * which generates that structured representation of the contents.
+     *
+     * @param $output The core_renderer to use when generating the output.
+     * @return string the HTML that should appearn in the body of the block.
+     * @since Moodle 2.0.
+     */
+    protected function formatted_contents($output) {
+        $this->get_content();
+        $this->get_required_javascript();
+        if (!empty($this->content->text)) {
+            return $this->content->text;
+        } else {
+            return '';
+        }
+    }
+
+    /**
+     * Tests if this block has been implemented correctly.
+     * Also, $errors isn't used right now
+     *
+     * @return boolean
+     */
+
+    function _self_test() {
+        // Tests if this block has been implemented correctly.
+        // Also, $errors isn't used right now
+        $errors = array();
+
+        $correct = true;
+        if ($this->get_title() === NULL) {
+            $errors[] = 'title_not_set';
+            $correct = false;
+        }
+        if (!in_array($this->get_content_type(), array(BLOCK_TYPE_LIST, BLOCK_TYPE_TEXT, BLOCK_TYPE_TREE))) {
+            $errors[] = 'invalid_content_type';
+            $correct = false;
+        }
+        //following selftest was not working when roles&capabilities were used from block
+/*        if ($this->get_content() === NULL) {
+            $errors[] = 'content_not_set';
+            $correct = false;
+        }*/
+        $formats = $this->applicable_formats();
+        if (empty($formats) || array_sum($formats) === 0) {
+            $errors[] = 'no_formats';
+            $correct = false;
+        }
+
+        return $correct;
+    }
+
+    /**
+     * Subclasses should override this and return true if the
+     * subclass block has a settings.php file.
+     *
+     * @return boolean
+     */
+    function has_config() {
+        return false;
+    }
+
+    /**
+     * Default behavior: save all variables as $CFG properties
+     * You don't need to override this if you 're satisfied with the above
+     *
+     * @deprecated since Moodle 2.9 MDL-49385 - Please use Admin Settings functionality to save block configuration.
+     */
+    function config_save($data) {
+        throw new coding_exception('config_save() can not be used any more, use Admin Settings functionality to save block configuration.');
+    }
+
+    /**
+     * Which page types this block may appear on.
+     *
+     * The information returned here is processed by the
+     * {@link blocks_name_allowed_in_format()} function. Look there if you need
+     * to know exactly how this works.
+     *
+     * Default case: everything except mod and tag.
+     *
+     * @return array page-type prefix => true/false.
+     */
+    function applicable_formats() {
+        // Default case: the block can be used in courses and site index, but not in activities
+        return array('all' => true, 'mod' => false, 'tag' => false);
+    }
+
+
+    /**
+     * Default return is false - header will be shown
+     * @return boolean
+     */
+    function hide_header() {
+        return false;
+    }
+
+    /**
+     * Return any HTML attributes that you want added to the outer <div> that
+     * of the block when it is output.
+     *
+     * Because of the way certain JS events are wired it is a good idea to ensure
+     * that the default values here still get set.
+     * I found the easiest way to do this and still set anything you want is to
+     * override it within your block in the following way
+     *
+     * <code php>
+     * function html_attributes() {
+     *    $attributes = parent::html_attributes();
+     *    $attributes['class'] .= ' mynewclass';
+     *    return $attributes;
+     * }
+     * </code>
+     *
+     * @return array attribute name => value.
+     */
+    function html_attributes() {
+        $attributes = array(
+            'id' => 'inst' . $this->instance->id,
+            'class' => 'block_' . $this->name(). '  block',
+            'role' => $this->get_aria_role()
+        );
+        if ($this->hide_header()) {
+            $attributes['class'] .= ' no-header';
+        }
+        if ($this->instance_can_be_docked() && get_user_preferences('docked_block_instance_'.$this->instance->id, 0)) {
+            $attributes['class'] .= ' dock_on_load';
+        }
+        return $attributes;
+    }
+
+    /**
+     * Set up a particular instance of this class given data from the block_insances
+     * table and the current page. (See {@link block_manager::load_blocks()}.)
+     *
+     * @param stdClass $instance data from block_insances, block_positions, etc.
+     * @param moodle_page $the page this block is on.
+     */
+    function _load_instance($instance, $page) {
+        if (!empty($instance->configdata)) {
+            $this->config = unserialize(base64_decode($instance->configdata));
+        }
+        $this->instance = $instance;
+        $this->context = context_block::instance($instance->id);
+        $this->page = $page;
+        $this->specialization();
+    }
+
+    /**
+     * Allows the block to load any JS it requires into the page.
+     *
+     * By default this function simply permits the user to dock the block if it is dockable.
+     */
+    function get_required_javascript() {
+        if ($this->instance_can_be_docked() && !$this->hide_header()) {
+            user_preference_allow_ajax_update('docked_block_instance_'.$this->instance->id, PARAM_INT);
+        }
+    }
+
+    /**
+     * This function is called on your subclass right after an instance is loaded
+     * Use this function to act on instance data just after it's loaded and before anything else is done
+     * For instance: if your block will have different title's depending on location (site, course, blog, etc)
+     */
+    function specialization() {
+        // Just to make sure that this method exists.
+    }
+
+    /**
+     * Is each block of this type going to have instance-specific configuration?
+     * Normally, this setting is controlled by {@link instance_allow_multiple()}: if multiple
+     * instances are allowed, then each will surely need its own configuration. However, in some
+     * cases it may be necessary to provide instance configuration to blocks that do not want to
+     * allow multiple instances. In that case, make this function return true.
+     * I stress again that this makes a difference ONLY if {@link instance_allow_multiple()} returns false.
+     * @return boolean
+     */
+    function instance_allow_config() {
+        return false;
+    }
+
+    /**
+     * Are you going to allow multiple instances of each block?
+     * If yes, then it is assumed that the block WILL USE per-instance configuration
+     * @return boolean
+     */
+    function instance_allow_multiple() {
+        // Are you going to allow multiple instances of each block?
+        // If yes, then it is assumed that the block WILL USE per-instance configuration
+        return false;
+    }
+
+    /**
+     * Serialize and store config data
+     */
+    function instance_config_save($data, $nolongerused = false) {
+        global $DB;
+        $DB->update_record('block_instances', ['id' => $this->instance->id,
+                'configdata' => base64_encode(serialize($data)), 'timemodified' => time()]);
+    }
+
+    /**
+     * Replace the instance's configuration data with those currently in $this->config;
+     */
+    function instance_config_commit($nolongerused = false) {
+        global $DB;
+        $this->instance_config_save($this->config);
+    }
+
+    /**
+     * Do any additional initialization you may need at the time a new block instance is created
+     * @return boolean
+     */
+    function instance_create() {
+        return true;
+    }
+
+    /**
+     * Copy any block-specific data when copying to a new block instance.
+     * @param int $fromid the id number of the block instance to copy from
+     * @return boolean
+     */
+    public function instance_copy($fromid) {
+        return true;
+    }
+
+    /**
+     * Delete everything related to this instance if you have been using persistent storage other than the configdata field.
+     * @return boolean
+     */
+    function instance_delete() {
+        return true;
+    }
+
+    /**
+     * Allows the block class to have a say in the user's ability to edit (i.e., configure) blocks of this type.
+     * The framework has first say in whether this will be allowed (e.g., no editing allowed unless in edit mode)
+     * but if the framework does allow it, the block can still decide to refuse.
+     * @return boolean
+     */
+    function user_can_edit() {
+        global $USER;
+
+        if (has_capability('moodle/block:edit', $this->context)) {
+            return true;
+        }
+
+        // The blocks in My Moodle are a special case.  We want them to inherit from the user context.
+        if (!empty($USER->id)
+            && $this->instance->parentcontextid == $this->page->context->id   // Block belongs to this page
+            && $this->page->context->contextlevel == CONTEXT_USER             // Page belongs to a user
+            && $this->page->context->instanceid == $USER->id) {               // Page belongs to this user
+            return has_capability('moodle/my:manageblocks', $this->page->context);
+        }
+
+        return false;
+    }
+
+    /**
+     * Allows the block class to have a say in the user's ability to create new instances of this block.
+     * The framework has first say in whether this will be allowed (e.g., no adding allowed unless in edit mode)
+     * but if the framework does allow it, the block can still decide to refuse.
+     * This function has access to the complete page object, the creation related to which is being determined.
+     *
+     * @param moodle_page $page
+     * @return boolean
+     */
+    function user_can_addto($page) {
+        global $USER;
+
+        // The blocks in My Moodle are a special case and use a different capability.
+        if (!empty($USER->id)
+            && $page->context->contextlevel == CONTEXT_USER // Page belongs to a user
+            && $page->context->instanceid == $USER->id // Page belongs to this user
+            && $page->pagetype == 'my-index') { // Ensure we are on the My Moodle page
+
+            // If the block cannot be displayed on /my it is ok if the myaddinstance capability is not defined.
+            $formats = $this->applicable_formats();
+            // Is 'my' explicitly forbidden?
+            // If 'all' has not been allowed, has 'my' been explicitly allowed?
+            if ((isset($formats['my']) && $formats['my'] == false)
+                || (empty($formats['all']) && empty($formats['my']))) {
+
+                // Block cannot be added to /my regardless of capabilities.
+                return false;
+            } else {
+                $capability = 'block/' . $this->name() . ':myaddinstance';
+                return $this->has_add_block_capability($page, $capability)
+                       && has_capability('moodle/my:manageblocks', $page->context);
+            }
+        }
+
+        $capability = 'block/' . $this->name() . ':addinstance';
+        if ($this->has_add_block_capability($page, $capability)
+                && has_capability('moodle/block:edit', $page->context)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns true if the user can add a block to a page.
+     *
+     * @param moodle_page $page
+     * @param string $capability the capability to check
+     * @return boolean true if user can add a block, false otherwise.
+     */
+    private function has_add_block_capability($page, $capability) {
+        // Check if the capability exists.
+        if (!get_capability_info($capability)) {
+            // Debug warning that the capability does not exist, but no more than once per page.
+            static $warned = array();
+            if (!isset($warned[$this->name()])) {
+                debugging('The block ' .$this->name() . ' does not define the standard capability ' .
+                        $capability , DEBUG_DEVELOPER);
+                $warned[$this->name()] = 1;
+            }
+            // If the capability does not exist, the block can always be added.
+            return true;
+        } else {
+            return has_capability($capability, $page->context);
+        }
+    }
+
+    static function get_extra_capabilities() {
+        return array('moodle/block:view', 'moodle/block:edit');
+    }
+
+    /**
+     * Can be overridden by the block to prevent the block from being dockable.
+     *
+     * @return bool
+     */
+    public function instance_can_be_docked() {
+        global $CFG;
+        return (!empty($CFG->allowblockstodock) && $this->page->theme->enable_dock);
+    }
+
+    /**
+     * If overridden and set to false by the block it will not be hidable when
+     * editing is turned on.
+     *
+     * @return bool
+     */
+    public function instance_can_be_hidden() {
+        return true;
+    }
+
+    /**
+     * If overridden and set to false by the block it will not be collapsible.
+     *
+     * @return bool
+     */
+    public function instance_can_be_collapsed() {
+        return true;
+    }
+
+    /** @callback callback functions for comments api */
+    public static function comment_template($options) {
+        $ret = <<<EOD
+<div class="comment-userpicture">___picture___</div>
+<div class="comment-content">
+    ___name___ - <span>___time___</span>
+    <div>___content___</div>
+</div>
+EOD;
+        return $ret;
+    }
+    public static function comment_permissions($options) {
+        return array('view'=>true, 'post'=>true);
+    }
+    public static function comment_url($options) {
+        return null;
+    }
+    public static function comment_display($comments, $options) {
+        return $comments;
+    }
+    public static function comment_add(&$comments, $options) {
+        return true;
+    }
+
+    /**
+     * Returns the aria role attribute that best describes this block.
+     *
+     * Region is the default, but this should be overridden by a block is there is a region child, or even better
+     * a landmark child.
+     *
+     * Options are as follows:
+     *    - landmark
+     *      - application
+     *      - banner
+     *      - complementary
+     *      - contentinfo
+     *      - form
+     *      - main
+     *      - navigation
+     *      - search
+     *
+     * @return string
+     */
+    public function get_aria_role() {
+        return 'complementary';
+    }
+}
+
+/**
+ * Specialized class for displaying a block with a list of icons/text labels
+ *
+ * The get_content method should set $this->content->items and (optionally)
+ * $this->content->icons, instead of $this->content->text.
+ *
+ * @author Jon Papaioannou
+ * @package core_block
+ */
+
+class block_list extends block_base {
+    var $content_type  = BLOCK_TYPE_LIST;
+
+    function is_empty() {
+        if ( !has_capability('moodle/block:view', $this->context) ) {
+            return true;
+        }
+
+        $this->get_content();
+        return (empty($this->content->items) && empty($this->content->footer));
+    }
+
+    protected function formatted_contents($output) {
+        $this->get_content();
+        $this->get_required_javascript();
+        if (!empty($this->content->items)) {
+            return $output->list_block_contents($this->content->icons, $this->content->items);
+        } else {
+            return '';
+        }
+    }
+
+    function html_attributes() {
+        $attributes = parent::html_attributes();
+        $attributes['class'] .= ' list_block';
+        return $attributes;
+    }
+
+}
+
+/**
+ * Specialized class for displaying a tree menu.
+ *
+ * The {@link get_content()} method involves setting the content of
+ * <code>$this->content->items</code> with an array of {@link tree_item}
+ * objects (these are the top-level nodes). The {@link tree_item::children}
+ * property may contain more tree_item objects, and so on. The tree_item class
+ * itself is abstract and not intended for use, use one of it's subclasses.
+ *
+ * Unlike {@link block_list}, the icons are specified as part of the items,
+ * not in a separate array.
+ *
+ * @author Alan Trick
+ * @package core_block
+ * @internal this extends block_list so we get is_empty() for free
+ */
+class block_tree extends block_list {
+
+    /**
+     * @var int specifies the manner in which contents should be added to this
+     * block type. In this case <code>$this->content->items</code> is used with
+     * {@link tree_item}s.
+     */
+    public $content_type = BLOCK_TYPE_TREE;
+
+    /**
+     * Make the formatted HTML ouput.
+     *
+     * Also adds the required javascript call to the page output.
+     *
+     * @param core_renderer $output
+     * @return string HTML
+     */
+    protected function formatted_contents($output) {
+        // based of code in admin_tree
+        global $PAGE; // TODO change this when there is a proper way for blocks to get stuff into head.
+        static $eventattached;
+        if ($eventattached===null) {
+            $eventattached = true;
+        }
+        if (!$this->content) {
+            $this->content = new stdClass;
+            $this->content->items = array();
+        }
+        $this->get_required_javascript();
+        $this->get_content();
+        $content = $output->tree_block_contents($this->content->items,array('class'=>'block_tree list'));
+        if (isset($this->id) && !is_numeric($this->id)) {
+            $content = $output->box($content, 'block_tree_box', $this->id);
+        }
+        return $content;
+    }
+}
diff --git a/myoverview/amd/build/calendar_events_repository.min.js b/myoverview/amd/build/calendar_events_repository.min.js
new file mode 100644
index 0000000..5c6e35a
--- /dev/null
+++ b/myoverview/amd/build/calendar_events_repository.min.js
@@ -0,0 +1 @@
+define(["jquery","core/ajax","core/notification"],function(a,b,c){var d=20,e=function(a){a.hasOwnProperty("limit")||(a.limit=d),a.limitnum=a.limit,delete a.limit,a.hasOwnProperty("starttime")&&(a.timesortfrom=a.starttime,delete a.starttime),a.hasOwnProperty("endtime")&&(a.timesortto=a.endtime,delete a.endtime);var e={methodname:"core_calendar_get_action_events_by_course",args:a},f=b.call([e])[0];return f.fail(c.exception),f},f=function(a){a.hasOwnProperty("limit")||(a.limit=10),a.limitnum=a.limit,delete a.limit,a.hasOwnProperty("starttime")&&(a.timesortfrom=a.starttime,delete a.starttime),a.hasOwnProperty("endtime")&&(a.timesortto=a.endtime,delete a.endtime);var d={methodname:"core_calendar_get_action_events_by_courses",args:a},e=b.call([d])[0];return e.fail(c.exception),e},g=function(a){a.hasOwnProperty("limit")||(a.limit=d),a.limitnum=a.limit,delete a.limit,a.hasOwnProperty("starttime")&&(a.timesortfrom=a.starttime,delete a.starttime),a.hasOwnProperty("endtime")&&(a.timesortto=a.endtime,delete a.endtime);var e={methodname:"core_calendar_get_action_events_by_timesort",args:a},f=b.call([e])[0];return f.fail(c.exception),f};return{queryByTime:g,queryByCourse:e,queryByCourses:f}});
\ No newline at end of file
diff --git a/myoverview/amd/build/event_list.min.js b/myoverview/amd/build/event_list.min.js
new file mode 100644
index 0000000..0d04b59
--- /dev/null
+++ b/myoverview/amd/build/event_list.min.js
@@ -0,0 +1 @@
+define(["jquery","core/notification","core/templates","core/custom_interaction_events","block_myoverview/calendar_events_repository"],function(a,b,c,d,e){var f=86400,g={EMPTY_MESSAGE:'[data-region="empty-message"]',ROOT:'[data-region="event-list-container"]',EVENT_LIST:'[data-region="event-list"]',EVENT_LIST_CONTENT:'[data-region="event-list-content"]',EVENT_LIST_GROUP_CONTAINER:'[data-region="event-list-group-container"]',LOADING_ICON_CONTAINER:'[data-region="loading-icon-container"]',VIEW_MORE_BUTTON:'[data-action="view-more"]'},h={EVENT_LIST_ITEMS:"block_myoverview/event-list-items",COURSE_EVENT_LIST_ITEMS:"block_myoverview/course-event-list-items"},i=function(a){a.attr("data-loaded-all",!0)},j=function(a){return!!a.attr("data-loaded-all")},k=function(a){var b=a.find(g.LOADING_ICON_CONTAINER),c=a.find(g.VIEW_MORE_BUTTON);a.addClass("loading"),b.removeClass("hidden"),c.prop("disabled",!0)},l=function(a){var b=a.find(g.LOADING_ICON_CONTAINER),c=a.find(g.VIEW_MORE_BUTTON);a.removeClass("loading"),b.addClass("hidden"),j(a)||c.prop("disabled",!1)},m=function(a){return a.hasClass("loading")},n=function(a){a.attr("data-has-events",!0)},o=function(a){return!!a.attr("data-has-events")},p=function(a,b){b?n(a):o(a)||q(a)},q=function(a){a.find(g.EVENT_LIST_CONTENT).addClass("hidden"),a.find(g.EMPTY_MESSAGE).removeClass("hidden")},r=function(a,b,d){return a.removeClass("hidden"),c.render(d,{events:b}).done(function(b,d){c.appendNodeContents(a.find(g.EVENT_LIST),b,d)})},s=function(a,b){var c=b.timesort||0;return c-a},t=function(a,b,c){var d=a.attr("data-midnight"),e=+c.attr("data-start-day")*f,g=+c.attr("data-end-day")*f,h=s(d,b);return""===c.attr("data-end-day")?e<=h:e<=h&&h<g},u=function(b,c){return function(d){return t(b,d,a(c))}},v=function(b,c){var d=0,e=h.EVENT_LIST_ITEMS;return b.attr("data-course-id")&&(e=h.COURSE_EVENT_LIST_ITEMS),a.when.apply(a,a.map(b.find(g.EVENT_LIST_GROUP_CONTAINER),function(f){var g=c.filter(u(b,f));return g.length?(d+=g.length,r(a(f),g,e)):null})).then(function(){return d})},w=function(c,d){c=a(c);var g=+c.attr("data-limit"),h=+c.attr("data-course-id"),j=c.attr("data-last-id"),n=c.attr("data-midnight"),o=n-14*f;if(m(c))return a.Deferred().resolve();if(k(c),"undefined"==typeof d){var q={starttime:o,limit:g};j&&(q.aftereventid=j),h?(q.courseid=h,d=e.queryByCourse(q)):d=e.queryByTime(q)}return d.then(function(a){if(!a.events.length)return i(c),0;var b=a.events;return c.attr("data-last-id",b[b.length-1].id),b.length<g&&i(c),v(c,b).then(function(a){return a<b.length&&i(c),b.length})}).then(function(a){return p(c,a)}).fail(b.exception).always(function(){l(c)})},x=function(a){d.define(a,[d.events.activate]),a.on(d.events.activate,g.VIEW_MORE_BUTTON,function(){w(a)})};return{init:function(b){b=a(b),w(b),x(b)},registerEventListeners:x,load:w,rootSelector:g.ROOT}});
\ No newline at end of file
diff --git a/myoverview/amd/build/event_list_by_course.min.js b/myoverview/amd/build/event_list_by_course.min.js
new file mode 100644
index 0000000..055a8b3
--- /dev/null
+++ b/myoverview/amd/build/event_list_by_course.min.js
@@ -0,0 +1 @@
+define(["jquery","block_myoverview/event_list","block_myoverview/calendar_events_repository"],function(a,b,c){var d=86400,e={EVENTS_BY_COURSE_CONTAINER:'[data-region="course-events-container"]',EVENT_LIST_CONTAINER:'[data-region="event-list-container"]'},f=function(f){var g=f.find(e.EVENTS_BY_COURSE_CONTAINER);if(g.length){var h=g.find(e.EVENT_LIST_CONTAINER).first(),i=h.attr("data-midnight"),j=i-14*d,k=h.attr("data-limit"),l=g.map(function(){return a(this).attr("data-course-id")}).get(),m=c.queryByCourses({courseids:l,starttime:j,limit:k});g.each(function(c,d){d=a(d);var e=d.attr("data-course-id"),f=d.find(b.rootSelector),g=a.Deferred();m.done(function(a){var b=[],c=a.groupedbycourse.filter(function(a){return a.courseid==e});c.length&&(b=c[0].events),g.resolve({events:b})}).fail(function(a){g.reject(a)}),b.load(f,g)})}};return{init:function(b){b=a(b),f(b)}}});
\ No newline at end of file
diff --git a/myoverview/amd/build/paging_bar.min.js b/myoverview/amd/build/paging_bar.min.js
new file mode 100644
index 0000000..40e8b6d
--- /dev/null
+++ b/myoverview/amd/build/paging_bar.min.js
@@ -0,0 +1 @@
+define(["jquery","core/custom_interaction_events"],function(a,b){var c={ROOT:'[data-region="paging-bar"]',PAGE_ITEM:'[data-region="page-item"]',ACTIVE_PAGE_ITEM:'[data-region="page-item"].active'},d={PAGE_SELECTED:"block_myoverview-paging-bar-page-selected"},e=function(a,b){return a.find(c.PAGE_ITEM+'[data-page-number="'+b+'"]')},f=function(a,b){var c=b.attr("data-page-number");return"first"==c?c=1:"last"==c&&(c=a.attr("data-page-count")),c},g=function(g){g=a(g),b.define(g,[b.events.activate]),g.on(b.events.activate,c.PAGE_ITEM,function(b,h){var i=a(b.target).closest(c.PAGE_ITEM),j=g.find(c.ACTIVE_PAGE_ITEM),k=f(g,i),l=k==f(g,j);l||(g.find(c.PAGE_ITEM).removeClass("active"),e(g,k).addClass("active")),g.trigger(d.PAGE_SELECTED,[{pageNumber:k,isSamePage:l}]),h.originalEvent.preventDefault()})};return{registerEventListeners:g,events:d,rootSelector:c.ROOT}});
\ No newline at end of file
diff --git a/myoverview/amd/build/paging_content.min.js b/myoverview/amd/build/paging_content.min.js
new file mode 100644
index 0000000..97da2ca
--- /dev/null
+++ b/myoverview/amd/build/paging_content.min.js
@@ -0,0 +1 @@
+define(["jquery","core/templates","block_myoverview/paging_bar"],function(a,b,c){var d={ROOT:'[data-region="paging-content"]',PAGE_REGION:'[data-region="paging-content-item"]'},e=function(b,c){this.root=a(b),this.pagingBar=a(c)};return e.rootSelector=d.ROOT,e.prototype.createPage=function(a){return this.loadContent(a).then(function(a,c){b.appendNodeContents(this.root,a,c)}.bind(this)).then(function(){return this.findPage(a)}.bind(this))},e.prototype.findPage=function(a){return this.root.find('[data-page="'+a+'"]')},e.prototype.showPage=function(a){var b=this.findPage(a);this.root.find(d.PAGE_REGION).addClass("hidden"),b.length?b.removeClass("hidden"):this.createPage(a).done(function(a){a.removeClass("hidden")})},e.prototype.registerEventListeners=function(){this.pagingBar.on(c.events.PAGE_SELECTED,function(a,b){b.isSamePage||this.showPage(b.pageNumber)}.bind(this))},e});
\ No newline at end of file
diff --git a/myoverview/amd/build/tab_preferences.min.js b/myoverview/amd/build/tab_preferences.min.js
new file mode 100644
index 0000000..da5bd97
--- /dev/null
+++ b/myoverview/amd/build/tab_preferences.min.js
@@ -0,0 +1 @@
+define(["jquery","core/ajax","core/custom_interaction_events","core/notification"],function(a,b,c,d){var e=function(e){c.define(e,[c.events.activate]),e.on(c.events.activate,"[data-toggle='tab']",function(c){var e=a(c.currentTarget).data("tabname");"function"==typeof window.history.pushState&&window.history.pushState(null,null,"?myoverviewtab="+e);var f={methodname:"core_user_update_user_preferences",args:{preferences:[{type:"block_myoverview_last_tab",value:e}]}};b.call([f])[0].fail(d.exception)})};return{registerEventListeners:e}});
\ No newline at end of file
diff --git a/myoverview/amd/src/calendar_events_repository.js b/myoverview/amd/src/calendar_events_repository.js
new file mode 100644
index 0000000..64c06e0
--- /dev/null
+++ b/myoverview/amd/src/calendar_events_repository.js
@@ -0,0 +1,168 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * A javascript module to retrieve calendar events from the server.
+ *
+ * @module     block_myoverview/calendar_events_repository
+ * @class      repository
+ * @package    block_myoverview
+ * @copyright  2016 Ryan Wyllie <ryan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+define(['jquery', 'core/ajax', 'core/notification'], function($, Ajax, Notification) {
+
+    var DEFAULT_LIMIT = 20;
+
+    /**
+     * Retrieve a list of calendar events for the logged in user for the
+     * given course.
+     *
+     * Valid args are:
+     * int courseid     Only get events for this course
+     * int starttime    Only get events after this time
+     * int endtime      Only get events before this time
+     * int limit        Limit the number of results returned
+     * int aftereventid Offset the result set from the given id
+     *
+     * @method queryByCourse
+     * @param {object} args The request arguments
+     * @return {promise} Resolved with an array of the calendar events
+     */
+    var queryByCourse = function(args) {
+        if (!args.hasOwnProperty('limit')) {
+            args.limit = DEFAULT_LIMIT;
+        }
+
+        args.limitnum = args.limit;
+        delete args.limit;
+
+        if (args.hasOwnProperty('starttime')) {
+            args.timesortfrom = args.starttime;
+            delete args.starttime;
+        }
+
+        if (args.hasOwnProperty('endtime')) {
+            args.timesortto = args.endtime;
+            delete args.endtime;
+        }
+
+        var request = {
+            methodname: 'core_calendar_get_action_events_by_course',
+            args: args
+        };
+
+        var promise = Ajax.call([request])[0];
+
+        promise.fail(Notification.exception);
+
+        return promise;
+    };
+
+    /**
+     * Retrieve a list of calendar events for the given courses for the
+     * logged in user.
+     *
+     * Valid args are:
+     * array courseids    Get events for these courses
+     * int   starttime    Only get events after this time
+     * int   endtime      Only get events before this time
+     * int   limit        Limit the number of results returned
+     *
+     * @method queryByCourses
+     * @param {object} args The request arguments
+     * @return {promise} Resolved with an array of the calendar events
+     */
+    var queryByCourses = function(args) {
+        if (!args.hasOwnProperty('limit')) {
+            // This is intentionally smaller than the default limit.
+            args.limit = 10;
+        }
+
+        args.limitnum = args.limit;
+        delete args.limit;
+
+        if (args.hasOwnProperty('starttime')) {
+            args.timesortfrom = args.starttime;
+            delete args.starttime;
+        }
+
+        if (args.hasOwnProperty('endtime')) {
+            args.timesortto = args.endtime;
+            delete args.endtime;
+        }
+
+        var request = {
+            methodname: 'core_calendar_get_action_events_by_courses',
+            args: args
+        };
+
+        var promise = Ajax.call([request])[0];
+
+        promise.fail(Notification.exception);
+
+        return promise;
+    };
+
+    /**
+     * Retrieve a list of calendar events for the logged in user after the given
+     * time.
+     *
+     * Valid args are:
+     * int starttime    Only get events after this time
+     * int endtime      Only get events before this time
+     * int limit        Limit the number of results returned
+     * int aftereventid Offset the result set from the given id
+     *
+     * @method queryByTime
+     * @param {object} args The request arguments
+     * @return {promise} Resolved with an array of the calendar events
+     */
+    var queryByTime = function(args) {
+        if (!args.hasOwnProperty('limit')) {
+            args.limit = DEFAULT_LIMIT;
+        }
+
+        args.limitnum = args.limit;
+        delete args.limit;
+
+        if (args.hasOwnProperty('starttime')) {
+            args.timesortfrom = args.starttime;
+            delete args.starttime;
+        }
+
+        if (args.hasOwnProperty('endtime')) {
+            args.timesortto = args.endtime;
+            delete args.endtime;
+        }
+
+        var request = {
+            methodname: 'core_calendar_get_action_events_by_timesort',
+            args: args
+        };
+
+        var promise = Ajax.call([request])[0];
+
+        promise.fail(Notification.exception);
+
+        return promise;
+    };
+
+    return {
+        queryByTime: queryByTime,
+        queryByCourse: queryByCourse,
+        queryByCourses: queryByCourses,
+    };
+});
diff --git a/myoverview/amd/src/event_list.js b/myoverview/amd/src/event_list.js
new file mode 100644
index 0000000..9d96fc5
--- /dev/null
+++ b/myoverview/amd/src/event_list.js
@@ -0,0 +1,414 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Javascript to load and render the list of calendar events for a
+ * given day range.
+ *
+ * @module     block_myoverview/event_list
+ * @package    block_myoverview
+ * @copyright  2016 Ryan Wyllie <ryan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+define(['jquery', 'core/notification', 'core/templates',
+        'core/custom_interaction_events',
+        'block_myoverview/calendar_events_repository'],
+        function($, Notification, Templates, CustomEvents, CalendarEventsRepository) {
+
+    var SECONDS_IN_DAY = 60 * 60 * 24;
+
+    var SELECTORS = {
+        EMPTY_MESSAGE: '[data-region="empty-message"]',
+        ROOT: '[data-region="event-list-container"]',
+        EVENT_LIST: '[data-region="event-list"]',
+        EVENT_LIST_CONTENT: '[data-region="event-list-content"]',
+        EVENT_LIST_GROUP_CONTAINER: '[data-region="event-list-group-container"]',
+        LOADING_ICON_CONTAINER: '[data-region="loading-icon-container"]',
+        VIEW_MORE_BUTTON: '[data-action="view-more"]'
+    };
+
+    var TEMPLATES = {
+        EVENT_LIST_ITEMS: 'block_myoverview/event-list-items',
+        COURSE_EVENT_LIST_ITEMS: 'block_myoverview/course-event-list-items'
+    };
+
+    /**
+     * Set a flag on the element to indicate that it has completed
+     * loading all event data.
+     *
+     * @method setLoadedAll
+     * @private
+     * @param {object} root The container element
+     */
+    var setLoadedAll = function(root) {
+        root.attr('data-loaded-all', true);
+    };
+
+    /**
+     * Check if all event data has finished loading.
+     *
+     * @method hasLoadedAll
+     * @private
+     * @param {object} root The container element
+     * @return {bool} if the element has completed all loading
+     */
+    var hasLoadedAll = function(root) {
+        return !!root.attr('data-loaded-all');
+    };
+
+    /**
+     * Set the element state to loading.
+     *
+     * @method startLoading
+     * @private
+     * @param {object} root The container element
+     */
+    var startLoading = function(root) {
+        var loadingIcon = root.find(SELECTORS.LOADING_ICON_CONTAINER),
+            viewMoreButton = root.find(SELECTORS.VIEW_MORE_BUTTON);
+
+        root.addClass('loading');
+        loadingIcon.removeClass('hidden');
+        viewMoreButton.prop('disabled', true);
+    };
+
+    /**
+     * Remove the loading state from the element.
+     *
+     * @method stopLoading
+     * @private
+     * @param {object} root The container element
+     */
+    var stopLoading = function(root) {
+        var loadingIcon = root.find(SELECTORS.LOADING_ICON_CONTAINER),
+            viewMoreButton = root.find(SELECTORS.VIEW_MORE_BUTTON);
+
+        root.removeClass('loading');
+        loadingIcon.addClass('hidden');
+
+        if (!hasLoadedAll(root)) {
+            // Only enable the button if we've got more events to load.
+            viewMoreButton.prop('disabled', false);
+        }
+    };
+
+    /**
+     * Check if the element is currently loading some event data.
+     *
+     * @method isLoading
+     * @private
+     * @param {object} root The container element
+     * @returns {Boolean}
+     */
+    var isLoading = function(root) {
+        return root.hasClass('loading');
+    };
+
+    /**
+     * Flag the root element to remember that it contains events.
+     *
+     * @method setHasContent
+     * @private
+     * @param {object} root The container element
+     */
+    var setHasContent = function(root) {
+        root.attr('data-has-events', true);
+    };
+
+    /**
+     * Check if the root element has had events loaded.
+     *
+     * @method hasContent
+     * @private
+     * @param {object} root The container element
+     * @return {bool}
+     */
+    var hasContent = function(root) {
+        return root.attr('data-has-events') ? true : false;
+    };
+
+    /**
+     * Update the visibility of the content area. The content area
+     * is hidden if we have no events.
+     *
+     * @method updateContentVisibility
+     * @private
+     * @param {object} root The container element
+     * @param {int} eventCount A count of the events we just received.
+     */
+    var updateContentVisibility = function(root, eventCount) {
+        if (eventCount) {
+            // We've rendered some events, let's remember that.
+            setHasContent(root);
+        } else {
+            // If this is the first time trying to load events and
+            // we don't have any then there isn't any so let's show
+            // the empty message.
+            if (!hasContent(root)) {
+                hideContent(root);
+            }
+        }
+    };
+
+    /**
+     * Hide the content area and display the empty content message.
+     *
+     * @method hideContent
+     * @private
+     * @param {object} root The container element
+     */
+    var hideContent = function(root) {
+        root.find(SELECTORS.EVENT_LIST_CONTENT).addClass('hidden');
+        root.find(SELECTORS.EMPTY_MESSAGE).removeClass('hidden');
+    };
+
+    /**
+     * Render a group of calendar events and add them to the event
+     * list.
+     *
+     * @method renderGroup
+     * @private
+     * @param {object}  group           The group container element
+     * @param {array}   calendarEvents  The list of calendar events
+     * @param {string}  templateName    The template name
+     * @return {promise} Resolved when the elements are attached to the DOM
+     */
+    var renderGroup = function(group, calendarEvents, templateName) {
+
+        group.removeClass('hidden');
+
+        return Templates.render(
+            templateName,
+            {events: calendarEvents}
+        ).done(function(html, js) {
+            Templates.appendNodeContents(group.find(SELECTORS.EVENT_LIST), html, js);
+        });
+    };
+
+    /**
+     * Determine the time (in seconds) from the given timestamp until the calendar
+     * event will need actioning.
+     *
+     * @method timeUntilEvent
+     * @private
+     * @param {int}     timestamp   The time to compare with
+     * @param {object}  event       The calendar event
+     * @return {int}
+     */
+    var timeUntilEvent = function(timestamp, event) {
+        var orderTime = event.timesort || 0;
+        return orderTime - timestamp;
+    };
+
+    /**
+     * Check if the given calendar event should be added to the given event
+     * list group container. The event list group container will specify a
+     * day range for the time boundary it is interested in.
+     *
+     * If only a start day is specified for the container then it will be treated
+     * as an open catchment for all events that begin after that time.
+     *
+     * @method eventBelongsInContainer
+     * @private
+     * @param {object} root         The root element
+     * @param {object} event        The calendar event
+     * @param {object} container    The group event list container
+     * @return {bool}
+     */
+    var eventBelongsInContainer = function(root, event, container) {
+        var todayTime = root.attr('data-midnight'),
+            timeUntilContainerStart = +container.attr('data-start-day') * SECONDS_IN_DAY,
+            timeUntilContainerEnd = +container.attr('data-end-day') * SECONDS_IN_DAY,
+            timeUntilEventNeedsAction = timeUntilEvent(todayTime, event);
+
+        if (container.attr('data-end-day') === '') {
+            return timeUntilContainerStart <= timeUntilEventNeedsAction;
+        } else {
+            return timeUntilContainerStart <= timeUntilEventNeedsAction &&
+                   timeUntilEventNeedsAction < timeUntilContainerEnd;
+        }
+    };
+
+    /**
+     * Return a function that can be used to filter a list of events based on the day
+     * range specified on the given event list group container.
+     *
+     * @method getFilterCallbackForContainer
+     * @private
+     * @param {object} root      The root element
+     * @param {object} container Event list group container
+     * @return {function}
+     */
+    var getFilterCallbackForContainer = function(root, container) {
+        return function(event) {
+            return eventBelongsInContainer(root, event, $(container));
+        };
+    };
+
+    /**
+     * Render the given calendar events in the container element. The container
+     * elements must have a day range defined using data attributes that will be
+     * used to group the calendar events according to their order time.
+     *
+     * @method render
+     * @private
+     * @param {object}  root            The container element
+     * @param {array}   calendarEvents  A list of calendar events
+     * @return {promise} Resolved with a count of the number of rendered events
+     */
+    var render = function(root, calendarEvents) {
+        var renderCount = 0;
+        var templateName = TEMPLATES.EVENT_LIST_ITEMS;
+
+        if (root.attr('data-course-id')) {
+            templateName = TEMPLATES.COURSE_EVENT_LIST_ITEMS;
+        }
+
+        // Loop over each of the element list groups and find the set of calendar events
+        // that belong to that group (as defined by the group's day range). The matching
+        // list of calendar events are rendered and added to the DOM within that group.
+        return $.when.apply($, $.map(root.find(SELECTORS.EVENT_LIST_GROUP_CONTAINER), function(container) {
+            var events = calendarEvents.filter(getFilterCallbackForContainer(root, container));
+
+            if (events.length) {
+                renderCount += events.length;
+                return renderGroup($(container), events, templateName);
+            } else {
+                return null;
+            }
+        })).then(function() {
+            return renderCount;
+        });
+    };
+
+    /**
+     * Retrieve a list of calendar events, render and append them to the end of the
+     * existing list. The events will be loaded based on the set of data attributes
+     * on the root element.
+     *
+     * This function can be provided with a jQuery promise. If it is then it won't
+     * attempt to load data by itself, instead it will use the given promise.
+     *
+     * The provided promise must resolve with an an object that has an events key
+     * and value is an array of calendar events.
+     * E.g.
+     * { events: ['event 1', 'event 2'] }
+     *
+     * @method load
+     * @param {object} root The root element of the event list
+     * @param {object} promise A jQuery promise resolved with events
+     * @return {promise} A jquery promise
+     */
+    var load = function(root, promise) {
+        root = $(root);
+        var limit = +root.attr('data-limit'),
+            courseId = +root.attr('data-course-id'),
+            lastId = root.attr('data-last-id'),
+            midnight = root.attr('data-midnight'),
+            startTime = midnight - (14 * SECONDS_IN_DAY);
+
+        // Don't load twice.
+        if (isLoading(root)) {
+            return $.Deferred().resolve();
+        }
+
+        startLoading(root);
+
+        // If we haven't been provided a promise to resolve the
+        // data then we will load our own.
+        if (typeof promise == 'undefined') {
+            var args = {
+                starttime: startTime,
+                limit: limit,
+            };
+
+            if (lastId) {
+                args.aftereventid = lastId;
+            }
+
+            // If we have a course id then we only want events from that course.
+            if (courseId) {
+                args.courseid = courseId;
+                promise = CalendarEventsRepository.queryByCourse(args);
+            } else {
+                // Otherwise we want events from any course.
+                promise = CalendarEventsRepository.queryByTime(args);
+            }
+        }
+
+        // Request data from the server.
+        return promise.then(function(result) {
+            if (!result.events.length) {
+                // No events, nothing to do.
+                setLoadedAll(root);
+                return 0;
+            }
+
+            var calendarEvents = result.events;
+
+            // Remember the last id we've seen.
+            root.attr('data-last-id', calendarEvents[calendarEvents.length - 1].id);
+
+            if (calendarEvents.length < limit) {
+                // No more events to load, disable loading button.
+                setLoadedAll(root);
+            }
+
+            // Render the events.
+            return render(root, calendarEvents).then(function(renderCount) {
+                if (renderCount < calendarEvents.length) {
+                    // If the number of events that was rendered is less than
+                    // the number we sent for rendering we can assume that there
+                    // are no groups to add them in. Since the ordering of the
+                    // events is guaranteed it means that any future requests will
+                    // also yield events that can't be rendered, so let's not bother
+                    // sending any more requests.
+                    setLoadedAll(root);
+                }
+                return calendarEvents.length;
+            });
+        }).then(function(eventCount) {
+            return updateContentVisibility(root, eventCount);
+        }).fail(
+            Notification.exception
+        ).always(function() {
+            stopLoading(root);
+        });
+    };
+
+    /**
+     * Register the event listeners for the container element.
+     *
+     * @method registerEventListeners
+     * @param {object} root The root element of the event list
+     */
+    var registerEventListeners = function(root) {
+        CustomEvents.define(root, [CustomEvents.events.activate]);
+        root.on(CustomEvents.events.activate, SELECTORS.VIEW_MORE_BUTTON, function() {
+            load(root);
+        });
+    };
+
+    return {
+        init: function(root) {
+            root = $(root);
+            load(root);
+            registerEventListeners(root);
+        },
+        registerEventListeners: registerEventListeners,
+        load: load,
+        rootSelector: SELECTORS.ROOT,
+    };
+});
diff --git a/myoverview/amd/src/event_list_by_course.js b/myoverview/amd/src/event_list_by_course.js
new file mode 100644
index 0000000..32d52cc
--- /dev/null
+++ b/myoverview/amd/src/event_list_by_course.js
@@ -0,0 +1,108 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Javascript to load and render the list of calendar events grouping by course.
+ *
+ * @module     block_myoverview/events_by_course_list
+ * @package    block_myoverview
+ * @copyright  2016 Simey Lameze <simey@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+define(
+[
+    'jquery',
+    'block_myoverview/event_list',
+    'block_myoverview/calendar_events_repository'
+],
+function($, EventList, EventsRepository) {
+
+    var SECONDS_IN_DAY = 60 * 60 * 24;
+
+    var SELECTORS = {
+        EVENTS_BY_COURSE_CONTAINER: '[data-region="course-events-container"]',
+        EVENT_LIST_CONTAINER: '[data-region="event-list-container"]',
+    };
+
+    /**
+     * Loop through course events containers and load calendar events for that course.
+     *
+     * @method load
+     * @param {Object} root The root element of sort by course list.
+     */
+    var load = function(root) {
+        var courseBlocks = root.find(SELECTORS.EVENTS_BY_COURSE_CONTAINER);
+
+        if (!courseBlocks.length) {
+            return;
+        }
+
+        var eventList = courseBlocks.find(SELECTORS.EVENT_LIST_CONTAINER).first();
+        var midnight = eventList.attr('data-midnight');
+        var startTime = midnight - (14 * SECONDS_IN_DAY);
+        var limit = eventList.attr('data-limit');
+        var courseIds = courseBlocks.map(function() {
+            return $(this).attr('data-course-id');
+        }).get();
+
+        // Load the first set of events for each course in a single request.
+        // We want to avoid sending an individual request for each course because
+        // there could be lots of them.
+        var coursesPromise = EventsRepository.queryByCourses({
+            courseids: courseIds,
+            starttime: startTime,
+            limit: limit
+        });
+
+        // Load the events into each course block.
+        courseBlocks.each(function(index, container) {
+            container = $(container);
+            var courseId = container.attr('data-course-id');
+            var eventListContainer = container.find(EventList.rootSelector);
+            var promise = $.Deferred();
+
+            // Once all of the course events have been loaded then we need
+            // to extract just the ones relevant to this course block and
+            // hand them to the event list to render.
+            coursesPromise.done(function(result) {
+                var events = [];
+                // Get this course block's events from the collection returned
+                // from the server.
+                var courseGroup = result.groupedbycourse.filter(function(group) {
+                    return group.courseid == courseId;
+                });
+
+                if (courseGroup.length) {
+                    events = courseGroup[0].events;
+                }
+
+                promise.resolve({events: events});
+            }).fail(function(e) {
+                promise.reject(e);
+            });
+
+            // Provide the event list with a promise that will be resolved
+            // when we have received the events from the server.
+            EventList.load(eventListContainer, promise);
+        });
+    };
+
+    return {
+        init: function(root) {
+            root = $(root);
+            load(root);
+        }
+    };
+});
diff --git a/myoverview/amd/src/paging_bar.js b/myoverview/amd/src/paging_bar.js
new file mode 100644
index 0000000..e153e2d
--- /dev/null
+++ b/myoverview/amd/src/paging_bar.js
@@ -0,0 +1,102 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Javascript to load and render the paging bar.
+ *
+ * @module     block_myoverview/paging_bar
+ * @package    block_myoverview
+ * @copyright  2016 Ryan Wyllie <ryan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+define(['jquery', 'core/custom_interaction_events'],
+        function($, CustomEvents) {
+
+    var SELECTORS = {
+        ROOT: '[data-region="paging-bar"]',
+        PAGE_ITEM: '[data-region="page-item"]',
+        ACTIVE_PAGE_ITEM: '[data-region="page-item"].active'
+    };
+
+    var EVENTS = {
+        PAGE_SELECTED: 'block_myoverview-paging-bar-page-selected',
+    };
+
+    /**
+     * Get the page element by number.
+     *
+     * @param {object} root The root element.
+     * @param {Number} pageNumber The page number.
+     * @returns {*}
+     */
+    var getPageByNumber = function(root, pageNumber) {
+        return root.find(SELECTORS.PAGE_ITEM + '[data-page-number="' + pageNumber + '"]');
+    };
+
+    /**
+     * Get the page number.
+     *
+     * @param {object} root The root element.
+     * @param {object} page The page.
+     * @returns {*} the page number
+     */
+    var getPageNumber = function(root, page) {
+        var pageNumber = page.attr('data-page-number');
+
+        if (pageNumber == 'first') {
+            pageNumber = 1;
+        } else if (pageNumber == 'last') {
+            pageNumber = root.attr('data-page-count');
+        }
+
+        return pageNumber;
+    };
+
+    /**
+     * Register event listeners for the module.
+     * @param {object} root The root element.
+     */
+    var registerEventListeners = function(root) {
+        root = $(root);
+        CustomEvents.define(root, [
+            CustomEvents.events.activate
+        ]);
+
+        root.on(CustomEvents.events.activate, SELECTORS.PAGE_ITEM, function(e, data) {
+            var page = $(e.target).closest(SELECTORS.PAGE_ITEM);
+            var activePage = root.find(SELECTORS.ACTIVE_PAGE_ITEM);
+            var pageNumber = getPageNumber(root, page);
+            var isSamePage = pageNumber == getPageNumber(root, activePage);
+
+            if (!isSamePage) {
+                root.find(SELECTORS.PAGE_ITEM).removeClass('active');
+                getPageByNumber(root, pageNumber).addClass('active');
+            }
+
+            root.trigger(EVENTS.PAGE_SELECTED, [{
+                pageNumber: pageNumber,
+                isSamePage: isSamePage,
+            }]);
+
+            data.originalEvent.preventDefault();
+        });
+    };
+
+    return {
+        registerEventListeners: registerEventListeners,
+        events: EVENTS,
+        rootSelector: SELECTORS.ROOT,
+    };
+});
diff --git a/myoverview/amd/src/paging_content.js b/myoverview/amd/src/paging_content.js
new file mode 100644
index 0000000..1e33dae
--- /dev/null
+++ b/myoverview/amd/src/paging_content.js
@@ -0,0 +1,105 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Paging content module.
+ *
+ * @module     block_myoverview/paging_content
+ * @package    block_myoverview
+ * @copyright  2016 Ryan Wyllie <ryan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+define(['jquery', 'core/templates', 'block_myoverview/paging_bar'],
+        function($, Templates, PagingBar) {
+
+    var SELECTORS = {
+        ROOT: '[data-region="paging-content"]',
+        PAGE_REGION: '[data-region="paging-content-item"]'
+    };
+
+    /**
+     * Constructor of the paging content module.
+     *
+     * @param {object} root
+     * @param {object} pagingBarElement
+     * @constructor
+     */
+    var PagingContent = function(root, pagingBarElement) {
+        this.root = $(root);
+        this.pagingBar = $(pagingBarElement);
+
+    };
+
+    PagingContent.rootSelector = SELECTORS.ROOT;
+
+    /**
+     * Load content and create page.
+     *
+     * @param {Number} pageNumber
+     * @returns {*|Promise}
+     */
+    PagingContent.prototype.createPage = function(pageNumber) {
+
+        return this.loadContent(pageNumber).then(function(html, js) {
+            Templates.appendNodeContents(this.root, html, js);
+        }.bind(this)).then(function() {
+                return this.findPage(pageNumber);
+            }.bind(this)
+        );
+    };
+
+    /**
+     * Find a page by the number.
+     *
+     * @param {Number} pageNumber The number of the page to be found.
+     * @returns {*} Page root
+     */
+    PagingContent.prototype.findPage = function(pageNumber) {
+        return this.root.find('[data-page="' + pageNumber + '"]');
+    };
+
+    /**
+     * Make a page visible.
+     *
+     * @param {Number} pageNumber The number of the page to be visible.
+     */
+    PagingContent.prototype.showPage = function(pageNumber) {
+
+        var existingPage = this.findPage(pageNumber);
+        this.root.find(SELECTORS.PAGE_REGION).addClass('hidden');
+
+        if (existingPage.length) {
+            existingPage.removeClass('hidden');
+        } else {
+            this.createPage(pageNumber).done(function(newPage) {
+                newPage.removeClass('hidden');
+            });
+        }
+    };
+
+    /**
+     * Event listeners.
+     */
+    PagingContent.prototype.registerEventListeners = function() {
+
+        this.pagingBar.on(PagingBar.events.PAGE_SELECTED, function(e, data) {
+            if (!data.isSamePage) {
+                this.showPage(data.pageNumber);
+            }
+        }.bind(this));
+    };
+
+    return PagingContent;
+});
diff --git a/myoverview/amd/src/tab_preferences.js b/myoverview/amd/src/tab_preferences.js
new file mode 100644
index 0000000..25ac2ee
--- /dev/null
+++ b/myoverview/amd/src/tab_preferences.js
@@ -0,0 +1,61 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Javascript used to save the user's tab preference.
+ *
+ * @package    block_myoverview
+ * @copyright  2017 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+define(['jquery', 'core/ajax', 'core/custom_interaction_events',
+    'core/notification'], function($, Ajax, CustomEvents, Notification) {
+
+    /**
+     * Registers an event that saves the user's tab preference when switching between them.
+     *
+     * @param {object} root The container element
+     */
+    var registerEventListeners = function(root) {
+        CustomEvents.define(root, [CustomEvents.events.activate]);
+        root.on(CustomEvents.events.activate, "[data-toggle='tab']", function(e) {
+            var tabname = $(e.currentTarget).data('tabname');
+            // Bootstrap does not change the URL when using BS tabs, so need to do this here.
+            // Also check to make sure the browser supports the history API.
+            if (typeof window.history.pushState === "function") {
+                window.history.pushState(null, null, '?myoverviewtab=' + tabname);
+            }
+            var request = {
+                methodname: 'core_user_update_user_preferences',
+                args: {
+                    preferences: [
+                        {
+                            type: 'block_myoverview_last_tab',
+                            value: tabname
+                        }
+                    ]
+                }
+            };
+
+            Ajax.call([request])[0]
+                .fail(Notification.exception);
+        });
+    };
+
+    return {
+        registerEventListeners: registerEventListeners
+    };
+});
diff --git a/myoverview/block_myoverview.php b/myoverview/block_myoverview.php
new file mode 100644
index 0000000..8afd4a1
--- /dev/null
+++ b/myoverview/block_myoverview.php
@@ -0,0 +1,89 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Contains the class for the My overview block.
+ *
+ * @package    block_myoverview
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * My overview block class.
+ *
+ * @package    block_myoverview
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_myoverview extends block_base {
+
+    /**
+     * Init.
+     */
+    public function init() {
+        $this->title = get_string('pluginname', 'block_myoverview');
+    }
+
+    /**
+     * Returns the contents.
+     *
+     * @return stdClass contents of block
+     */
+    public function get_content() {
+        if (isset($this->content)) {
+            return $this->content;
+        }
+
+        // Check if the tab to select wasn't passed in the URL, if so see if the user has any preference.
+        if (!$tab = optional_param('myoverviewtab', null, PARAM_ALPHA)) {
+            // Check if the user has no preference, if so get the site setting.
+            if (!$tab = get_user_preferences('block_myoverview_last_tab')) {
+                $config = get_config('block_myoverview');
+                $tab = $config->defaulttab;
+            }
+        }
+
+        $renderable = new \block_myoverview\output\main($tab);
+        $renderer = $this->page->get_renderer('block_myoverview');
+
+        $this->content = new stdClass();
+        $this->content->text = $renderer->render($renderable);
+        $this->content->footer = '';
+
+        return $this->content;
+    }
+
+    /**
+     * Locations where block can be displayed.
+     *
+     * @return array
+     */
+    public function applicable_formats() {
+        return array('my' => true);
+    }
+
+    /**
+     * This block does contain a configuration settings.
+     *
+     * @return boolean
+     */
+    public function has_config() {
+        return true;
+    }
+}
diff --git a/myoverview/classes/output/courses_view.php b/myoverview/classes/output/courses_view.php
new file mode 100644
index 0000000..b00741d
--- /dev/null
+++ b/myoverview/classes/output/courses_view.php
@@ -0,0 +1,190 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Class containing data for courses view in the myoverview block.
+ *
+ * @package    block_myoverview
+ * @copyright  2017 Ryan Wyllie <ryan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+namespace block_myoverview\output;
+defined('MOODLE_INTERNAL') || die();
+
+use renderable;
+use renderer_base;
+use templatable;
+use core_course\external\course_summary_exporter;
+
+/**
+ * Class containing data for courses view in the myoverview block.
+ *
+ * @copyright  2017 Simey Lameze <simey@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class courses_view implements renderable, templatable {
+    /** Quantity of courses per page. */
+    const COURSES_PER_PAGE = 6;
+
+    /** @var array $courses List of courses the user is enrolled in. */
+    protected $courses = [];
+
+    /** @var array $coursesprogress List of progress percentage for each course. */
+    protected $coursesprogress = [];
+
+    /**
+     * The courses_view constructor.
+     *
+     * @param array $courses list of courses.
+     * @param array $coursesprogress list of courses progress.
+     */
+    public function __construct($courses, $coursesprogress) {
+        $this->courses = $courses;
+        $this->coursesprogress = $coursesprogress;
+    }
+
+    /**
+     * Export this data so it can be used as the context for a mustache template.
+     *
+     * @param \renderer_base $output
+     * @return array
+     */
+    public function export_for_template(renderer_base $output) {
+        global $CFG;
+        require_once($CFG->dirroot.'/course/lib.php');
+        require_once($CFG->dirroot.'/lib/coursecatlib.php');
+
+        // Build courses view data structure.
+        $coursesview = [
+            'hascourses' => !empty($this->courses)
+        ];
+
+        // How many courses we have per status?
+        $coursesbystatus = ['past' => 0, 'inprogress' => 0, 'future' => 0];
+        foreach ($this->courses as $course) {
+            $courseid = $course->id;
+            $context = \context_course::instance($courseid);
+            $exporter = new course_summary_exporter($course, [
+                'context' => $context
+            ]);
+            $exportedcourse = $exporter->export($output);
+            // Convert summary to plain text.
+            $exportedcourse->summary = content_to_text($exportedcourse->summary, $exportedcourse->summaryformat);
+
+            $course = new \course_in_list($course);
+            foreach ($course->get_course_overviewfiles() as $file) {
+                $isimage = $file->is_valid_image();
+                if ($isimage) {
+                    $url = file_encode_url("$CFG->wwwroot/pluginfile.php",
+                        '/'. $file->get_contextid(). '/'. $file->get_component(). '/'.
+                        $file->get_filearea(). $file->get_filepath(). $file->get_filename(), !$isimage);
+                    $exportedcourse->courseimage = $url;
+                    $exportedcourse->classes = 'courseimage';
+                    break;
+                }
+            }
+
+            $exportedcourse->color = $this->coursecolor($course->id);
+
+            if (!isset($exportedcourse->courseimage)) {
+                $pattern = new \core_geopattern();
+                $pattern->setColor($exportedcourse->color);
+                $pattern->patternbyid($courseid);
+                $exportedcourse->classes = 'coursepattern';
+                $exportedcourse->courseimage = $pattern->datauri();
+            }
+
+            // Include course visibility.
+            $exportedcourse->visible = (bool)$course->visible;
+
+            $courseprogress = null;
+
+            $classified = course_classify_for_timeline($course);
+
+            if (isset($this->coursesprogress[$courseid])) {
+                $courseprogress = $this->coursesprogress[$courseid]['progress'];
+                $exportedcourse->hasprogress = !is_null($courseprogress);
+                $exportedcourse->progress = $courseprogress;
+            }
+
+            if ($classified == COURSE_TIMELINE_PAST) {
+                // Courses that have already ended.
+                $pastpages = floor($coursesbystatus['past'] / $this::COURSES_PER_PAGE);
+
+                $coursesview['past']['pages'][$pastpages]['courses'][] = $exportedcourse;
+                $coursesview['past']['pages'][$pastpages]['active'] = ($pastpages == 0 ? true : false);
+                $coursesview['past']['pages'][$pastpages]['page'] = $pastpages + 1;
+                $coursesview['past']['haspages'] = true;
+                $coursesbystatus['past']++;
+            } else if ($classified == COURSE_TIMELINE_FUTURE) {
+                // Courses that have not started yet.
+                $futurepages = floor($coursesbystatus['future'] / $this::COURSES_PER_PAGE);
+
+                $coursesview['future']['pages'][$futurepages]['courses'][] = $exportedcourse;
+                $coursesview['future']['pages'][$futurepages]['active'] = ($futurepages == 0 ? true : false);
+                $coursesview['future']['pages'][$futurepages]['page'] = $futurepages + 1;
+                $coursesview['future']['haspages'] = true;
+                $coursesbystatus['future']++;
+            } else {
+                // Courses still in progress. Either their end date is not set, or the end date is not yet past the current date.
+                $inprogresspages = floor($coursesbystatus['inprogress'] / $this::COURSES_PER_PAGE);
+
+                $coursesview['inprogress']['pages'][$inprogresspages]['courses'][] = $exportedcourse;
+                $coursesview['inprogress']['pages'][$inprogresspages]['active'] = ($inprogresspages == 0 ? true : false);
+                $coursesview['inprogress']['pages'][$inprogresspages]['page'] = $inprogresspages + 1;
+                $coursesview['inprogress']['haspages'] = true;
+                $coursesbystatus['inprogress']++;
+            }
+        }
+
+        // Build courses view paging bar structure.
+        foreach ($coursesbystatus as $status => $total) {
+            $quantpages = ceil($total / $this::COURSES_PER_PAGE);
+
+            if ($quantpages) {
+                $coursesview[$status]['pagingbar']['disabled'] = ($quantpages <= 1);
+                $coursesview[$status]['pagingbar']['pagecount'] = $quantpages;
+                $coursesview[$status]['pagingbar']['first'] = ['page' => '&laquo;', 'url' => '#'];
+                $coursesview[$status]['pagingbar']['last'] = ['page' => '&raquo;', 'url' => '#'];
+                for ($page = 0; $page < $quantpages; $page++) {
+                    $coursesview[$status]['pagingbar']['pages'][$page] = [
+                        'number' => $page + 1,
+                        'page' => $page + 1,
+                        'url' => '#',
+                        'active' => ($page == 0 ? true : false)
+                    ];
+                }
+            }
+        }
+
+        return $coursesview;
+    }
+
+    /**
+     * Generate a semi-random color based on the courseid number (so it will always return
+     * the same color for a course)
+     *
+     * @param int $courseid
+     * @return string $color, hexvalue color code.
+     */
+    protected function coursecolor($courseid) {
+        // The colour palette is hardcoded for now. It would make sense to combine it with theme settings.
+        $basecolors = ['#81ecec', '#74b9ff', '#a29bfe', '#dfe6e9', '#00b894', '#0984e3', '#b2bec3', '#fdcb6e', '#fd79a8', '#6c5ce7'];
+
+        $color = $basecolors[$courseid % 10];
+        return $color;
+    }
+}
diff --git a/myoverview/classes/output/main.php b/myoverview/classes/output/main.php
new file mode 100644
index 0000000..2850637
--- /dev/null
+++ b/myoverview/classes/output/main.php
@@ -0,0 +1,111 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Class containing data for my overview block.
+ *
+ * @package    block_myoverview
+ * @copyright  2017 Ryan Wyllie <ryan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+namespace block_myoverview\output;
+defined('MOODLE_INTERNAL') || die();
+
+use renderable;
+use renderer_base;
+use templatable;
+use core_completion\progress;
+
+require_once($CFG->dirroot . '/blocks/myoverview/lib.php');
+require_once($CFG->libdir . '/completionlib.php');
+
+/**
+ * Class containing data for my overview block.
+ *
+ * @copyright  2017 Simey Lameze <simey@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class main implements renderable, templatable {
+
+    /**
+     * @var string The tab to display.
+     */
+    public $tab;
+
+    /**
+     * Constructor.
+     *
+     * @param string $tab The tab to display.
+     */
+    public function __construct($tab) {
+        $this->tab = $tab;
+    }
+
+    /**
+     * Export this data so it can be used as the context for a mustache template.
+     *
+     * @param \renderer_base $output
+     * @return stdClass
+     */
+    public function export_for_template(renderer_base $output) {
+        global $USER;
+
+        $courses = enrol_get_my_courses('*');
+        $coursesprogress = [];
+
+        foreach ($courses as $course) {
+
+            $completion = new \completion_info($course);
+
+            // First, let's make sure completion is enabled.
+            if (!$completion->is_enabled()) {
+                continue;
+            }
+
+            $percentage = progress::get_course_progress_percentage($course);
+            if (!is_null($percentage)) {
+                $percentage = floor($percentage);
+            }
+
+            $coursesprogress[$course->id]['completed'] = $completion->is_course_complete($USER->id);
+            $coursesprogress[$course->id]['progress'] = $percentage;
+        }
+
+        $coursesview = new courses_view($courses, $coursesprogress);
+        $nocoursesurl = $output->image_url('courses', 'block_myoverview')->out();
+        $noeventsurl = $output->image_url('activities', 'block_myoverview')->out();
+
+        // Now, set the tab we are going to be viewing.
+        $viewingtimeline = false;
+        $viewingcourses = false;
+        if ($this->tab == BLOCK_MYOVERVIEW_TIMELINE_VIEW) {
+            $viewingtimeline = true;
+        } else {
+            $viewingcourses = true;
+        }
+
+        return [
+            'midnight' => usergetmidnight(time()),
+            'coursesview' => $coursesview->export_for_template($output),
+            'urls' => [
+                'nocourses' => $nocoursesurl,
+                'noevents' => $noeventsurl
+            ],
+            'viewingtimeline' => $viewingtimeline,
+            'viewingcourses' => $viewingcourses
+        ];
+    }
+}
diff --git a/myoverview/classes/output/renderer.php b/myoverview/classes/output/renderer.php
new file mode 100644
index 0000000..606dd3b
--- /dev/null
+++ b/myoverview/classes/output/renderer.php
@@ -0,0 +1,48 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * myoverview block rendrer
+ *
+ * @package    block_myoverview
+ * @copyright  2016 Ryan Wyllie <ryan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+namespace block_myoverview\output;
+defined('MOODLE_INTERNAL') || die;
+
+use plugin_renderer_base;
+use renderable;
+
+/**
+ * myoverview block renderer
+ *
+ * @package    block_myoverview
+ * @copyright  2016 Ryan Wyllie <ryan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class renderer extends plugin_renderer_base {
+
+    /**
+     * Return the main content for the block overview.
+     *
+     * @param main $main The main renderable
+     * @return string HTML string
+     */
+    public function render_main(main $main) {
+        return $this->render_from_template('block_myoverview/main', $main->export_for_template($this));
+    }
+}
diff --git a/myoverview/classes/privacy/provider.php b/myoverview/classes/privacy/provider.php
new file mode 100644
index 0000000..d0ee9e8
--- /dev/null
+++ b/myoverview/classes/privacy/provider.php
@@ -0,0 +1,61 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_myoverview.
+ *
+ * @package    block_myoverview
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_myoverview\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_myoverview.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\provider, \core_privacy\local\request\user_preference_provider {
+
+    /**
+     * Returns meta-data information about the myoverview block.
+     *
+     * @param  \core_privacy\local\metadata\collection $collection A collection of meta-data.
+     * @return \core_privacy\local\metadata\collection Return the collection of meta-data.
+     */
+    public static function get_metadata(\core_privacy\local\metadata\collection $collection) :
+            \core_privacy\local\metadata\collection {
+        $collection->add_user_preference('block_myoverview_last_tab', 'privacy:metadata:overviewlasttab');
+        return $collection;
+    }
+
+    /**
+     * Export all user preferences for the myoverview block
+     *
+     * @param int $userid The userid of the user whose data is to be exported.
+     */
+    public static function export_user_preferences(int $userid) {
+        $preference = get_user_preferences('block_myoverview_last_tab', null, $userid);
+        if (isset($preference)) {
+            \core_privacy\local\request\writer::export_user_preference('block_myoverview', 'block_myoverview_last_tab',
+                    $preference, get_string('privacy:metadata:overviewlasttab', 'block_myoverview'));
+        }
+    }
+}
diff --git a/myoverview/db/access.php b/myoverview/db/access.php
new file mode 100644
index 0000000..d05b432
--- /dev/null
+++ b/myoverview/db/access.php
@@ -0,0 +1,50 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Capabilities for the My overview block.
+ *
+ * @package    block_myoverview
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/myoverview:myaddinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/my:manageblocks'
+    ),
+
+    'block/myoverview:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    )
+);
diff --git a/myoverview/lang/en/block_myoverview.php b/myoverview/lang/en/block_myoverview.php
new file mode 100644
index 0000000..a3ca64e
--- /dev/null
+++ b/myoverview/lang/en/block_myoverview.php
@@ -0,0 +1,47 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Lang strings for the My overview block.
+ *
+ * @package    block_myoverview
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['defaulttab'] = 'Default tab';
+$string['defaulttab_desc'] = 'The tab that will be displayed when a user first views their course overview. When returning to their course overview, the user\'s active tab is remembered.';
+$string['future'] = 'Future';
+$string['inprogress'] = 'In progress';
+$string['morecourses'] = 'More courses';
+$string['myoverview:addinstance'] = 'Add a new course overview block';
+$string['myoverview:myaddinstance'] = 'Add a new course overview block to Dashboard';
+$string['nocourses'] = 'No courses';
+$string['nocoursesinprogress'] = 'No in progress courses';
+$string['nocoursesfuture'] = 'No future courses';
+$string['nocoursespast'] = 'No past courses';
+$string['noevents'] = 'No upcoming activities due';
+$string['next30days'] = 'Next 30 days';
+$string['next7days'] = 'Next 7 days';
+$string['past'] = 'Past';
+$string['pluginname'] = 'Course overview';
+$string['recentlyoverdue'] = 'Recently overdue';
+$string['sortbycourses'] = 'Sort by courses';
+$string['sortbydates'] = 'Sort by dates';
+$string['timeline'] = 'Timeline';
+$string['viewcourse'] = 'View course';
+$string['viewcoursename'] = 'View course {$a}';
+$string['privacy:metadata:overviewlasttab'] = 'This stores the last tab selected by the user on the overview block.';
diff --git a/myoverview/lib.php b/myoverview/lib.php
new file mode 100644
index 0000000..a73db25
--- /dev/null
+++ b/myoverview/lib.php
@@ -0,0 +1,52 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Contains functions called by core.
+ *
+ * @package    block_myoverview
+ * @copyright  2017 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The timeline view.
+ */
+define('BLOCK_MYOVERVIEW_TIMELINE_VIEW', 'timeline');
+
+/**
+ * The courses view.
+ */
+define('BLOCK_MYOVERVIEW_COURSES_VIEW', 'courses');
+
+/**
+ * Returns the name of the user preferences as well as the details this plugin uses.
+ *
+ * @return array
+ */
+function block_myoverview_user_preferences() {
+    $preferences = array();
+    $preferences['block_myoverview_last_tab'] = array(
+        'type' => PARAM_ALPHA,
+        'null' => NULL_NOT_ALLOWED,
+        'default' => BLOCK_MYOVERVIEW_TIMELINE_VIEW,
+        'choices' => array(BLOCK_MYOVERVIEW_TIMELINE_VIEW, BLOCK_MYOVERVIEW_COURSES_VIEW)
+    );
+
+    return $preferences;
+}
diff --git a/myoverview/pix/activities.svg b/myoverview/pix/activities.svg
new file mode 100644
index 0000000..ed7546a
--- /dev/null
+++ b/myoverview/pix/activities.svg
@@ -0,0 +1,41 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="157 -1509 148 125" preserveAspectRatio="xMinYMid meet">
+  <defs>
+    <style>
+      .cls-1 {
+        clip-path: url(#clip-Activities);
+      }
+
+      .cls-2 {
+        fill: #eee;
+      }
+
+      .cls-3 {
+        fill: #c4c8cc;
+      }
+
+      .cls-4 {
+        fill: #fff;
+      }
+    </style>
+    <clipPath id="clip-Activities">
+      <rect x="157" y="-1509" width="148" height="125"/>
+    </clipPath>
+  </defs>
+  <g id="Activities" class="cls-1">
+    <g id="Group_42" data-name="Group 42" transform="translate(-268 -1985)">
+      <ellipse id="Ellipse_37" data-name="Ellipse 37" class="cls-2" cx="74" cy="14.785" rx="74" ry="14.785" transform="translate(425 571.43)"/>
+      <rect id="Rectangle_80" data-name="Rectangle 80" class="cls-3" width="94.182" height="110.215" transform="translate(451.909 476)"/>
+      <g id="Group_41" data-name="Group 41" transform="translate(467.043 493)">
+        <rect id="Rectangle_81" data-name="Rectangle 81" class="cls-4" width="44.456" height="5.625" transform="translate(21.16 0.549)"/>
+        <rect id="Rectangle_82" data-name="Rectangle 82" class="cls-4" width="33.342" height="5.625" transform="translate(21.16 11.652)"/>
+        <rect id="Rectangle_83" data-name="Rectangle 83" class="cls-4" width="44.456" height="5.625" transform="translate(21.16 30.772)"/>
+        <rect id="Rectangle_84" data-name="Rectangle 84" class="cls-4" width="33.342" height="5.625" transform="translate(21.16 41.875)"/>
+        <rect id="Rectangle_85" data-name="Rectangle 85" class="cls-4" width="44.456" height="5.625" transform="translate(21.16 61.291)"/>
+        <rect id="Rectangle_86" data-name="Rectangle 86" class="cls-4" width="33.342" height="5.625" transform="translate(21.16 72.393)"/>
+        <ellipse id="Ellipse_38" data-name="Ellipse 38" class="cls-4" cx="7.007" cy="7" rx="7.007" ry="7" transform="translate(0 0)"/>
+        <ellipse id="Ellipse_39" data-name="Ellipse 39" class="cls-4" cx="7.007" cy="7" rx="7.007" ry="7" transform="translate(0 31)"/>
+        <ellipse id="Ellipse_40" data-name="Ellipse 40" class="cls-4" cx="7.007" cy="7" rx="7.007" ry="7" transform="translate(0 61)"/>
+      </g>
+    </g>
+  </g>
+</svg>
diff --git a/myoverview/pix/courses.svg b/myoverview/pix/courses.svg
new file mode 100644
index 0000000..75e59fc
--- /dev/null
+++ b/myoverview/pix/courses.svg
@@ -0,0 +1,52 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="157 -1305 148 125" preserveAspectRatio="xMinYMid meet">
+  <defs>
+    <style>
+      .cls-1 {
+        clip-path: url(#clip-Courses);
+      }
+
+      .cls-2 {
+        fill: #eee;
+      }
+
+      .cls-3 {
+        fill: #c4c8cc;
+      }
+
+      .cls-4 {
+        fill: #fff;
+      }
+    </style>
+    <clipPath id="clip-Courses">
+      <rect x="157" y="-1305" width="148" height="125"/>
+    </clipPath>
+  </defs>
+  <g id="Courses" class="cls-1">
+    <g id="Group_44" data-name="Group 44" transform="translate(-268 -1781)">
+      <ellipse id="Ellipse_41" data-name="Ellipse 41" class="cls-2" cx="74" cy="14.785" rx="74" ry="14.785" transform="translate(425 571.43)"/>
+      <rect id="Rectangle_87" data-name="Rectangle 87" class="cls-3" width="95.097" height="110.215" transform="translate(451.909 476)"/>
+      <g id="Group_43" data-name="Group 43" transform="translate(464.04 494)">
+        <rect id="Rectangle_88" data-name="Rectangle 88" class="cls-4" width="31.043" height="34" transform="translate(0)"/>
+        <rect id="Rectangle_89" data-name="Rectangle 89" class="cls-4" width="31.043" height="34" transform="translate(0 42)"/>
+        <rect id="Rectangle_90" data-name="Rectangle 90" class="cls-4" width="31.067" height="34" transform="translate(39.005)"/>
+        <rect id="Rectangle_91" data-name="Rectangle 91" class="cls-4" width="31.067" height="34" transform="translate(39.005 42)"/>
+        <rect id="Rectangle_92" data-name="Rectangle 92" class="cls-3" width="23.023" height="3.18" transform="translate(3.081 16.549)"/>
+        <rect id="Rectangle_93" data-name="Rectangle 93" class="cls-3" width="23.023" height="3.18" transform="translate(3.081 58.549)"/>
+        <rect id="Rectangle_94" data-name="Rectangle 94" class="cls-3" width="23.023" height="3.18" transform="translate(43.122 16.549)"/>
+        <rect id="Rectangle_95" data-name="Rectangle 95" class="cls-3" width="23.023" height="3.18" transform="translate(43.122 58.549)"/>
+        <rect id="Rectangle_96" data-name="Rectangle 96" class="cls-3" width="14.014" height="3.18" transform="translate(3.081 21.825)"/>
+        <rect id="Rectangle_97" data-name="Rectangle 97" class="cls-3" width="18.845" height="3.18" transform="translate(3.081 26.825)"/>
+        <rect id="Rectangle_98" data-name="Rectangle 98" class="cls-3" width="14.014" height="3.18" transform="translate(3.081 63.825)"/>
+        <rect id="Rectangle_99" data-name="Rectangle 99" class="cls-3" width="18.845" height="3.18" transform="translate(3.081 68.825)"/>
+        <rect id="Rectangle_100" data-name="Rectangle 100" class="cls-3" width="14.014" height="3.18" transform="translate(43.122 21.825)"/>
+        <rect id="Rectangle_101" data-name="Rectangle 101" class="cls-3" width="18.845" height="3.18" transform="translate(43.122 26.825)"/>
+        <rect id="Rectangle_102" data-name="Rectangle 102" class="cls-3" width="14.014" height="3.18" transform="translate(43.122 63.825)"/>
+        <rect id="Rectangle_103" data-name="Rectangle 103" class="cls-3" width="18.845" height="3.18" transform="translate(43.122 68.825)"/>
+        <ellipse id="Ellipse_42" data-name="Ellipse 42" class="cls-3" cx="5.658" cy="5.652" rx="5.658" ry="5.652" transform="translate(3.003 3.55)"/>
+        <ellipse id="Ellipse_43" data-name="Ellipse 43" class="cls-3" cx="5.658" cy="5.652" rx="5.658" ry="5.652" transform="translate(3.003 45.55)"/>
+        <ellipse id="Ellipse_44" data-name="Ellipse 44" class="cls-3" cx="5.658" cy="5.652" rx="5.658" ry="5.652" transform="translate(43.044 3.55)"/>
+        <ellipse id="Ellipse_45" data-name="Ellipse 45" class="cls-3" cx="5.658" cy="5.652" rx="5.658" ry="5.652" transform="translate(43.044 45.55)"/>
+      </g>
+    </g>
+  </g>
+</svg>
diff --git a/myoverview/settings.php b/myoverview/settings.php
new file mode 100644
index 0000000..10f084d
--- /dev/null
+++ b/myoverview/settings.php
@@ -0,0 +1,39 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Settings for the overview block.
+ *
+ * @package    block_myoverview
+ * @copyright  2017 Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die;
+
+require_once($CFG->dirroot . '/blocks/myoverview/lib.php');
+
+if ($ADMIN->fulltree) {
+
+    $options = [
+        BLOCK_MYOVERVIEW_TIMELINE_VIEW => get_string('timeline', 'block_myoverview'),
+        BLOCK_MYOVERVIEW_COURSES_VIEW => get_string('courses')
+    ];
+
+    $settings->add(new admin_setting_configselect('block_myoverview/defaulttab',
+        get_string('defaulttab', 'block_myoverview'),
+        get_string('defaulttab_desc', 'block_myoverview'), 'timeline', $options));
+}
diff --git a/myoverview/templates/course-event-list-item.mustache b/myoverview/templates/course-event-list-item.mustache
new file mode 100644
index 0000000..55c0e46
--- /dev/null
+++ b/myoverview/templates/course-event-list-item.mustache
@@ -0,0 +1,69 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_myoverview/course-event-list-item
+
+    This template renders an event list item for the myoverview block
+    in the courses view.
+
+    Example context (json):
+    {
+        "name": "Assignment due 1",
+        "url": "https://www.google.com",
+        "timesort": 1490320388,
+        "action": {
+            "name": "Submit assignment",
+            "url": "https://www.google.com",
+            "itemcount": 1,
+            "showitemcount": true,
+            "actionable": true
+        },
+        "icon": {
+            "key": "icon",
+            "component": "mod_assign",
+            "alttext": "Assignment icon"
+        }
+    }
+}}
+<li class="list-group-item event-list-item" data-region="event-list-item">
+    <div class="row">
+        <div class="col-lg-7 col-xl-8">
+            <div class="d-inline-block icon-large event-icon">
+                {{#icon}}{{#pix}} {{key}}, {{component}}, {{alttext}} {{/pix}}{{/icon}}
+            </div>
+            <div class="d-inline-block event-name-container">
+                <a class="event-name text-truncate" href="{{{url}}}">{{{name}}}</a>
+                <p class="small text-muted text-truncate m-b-0">
+                    {{#userdate}} {{timesort}}, {{#str}} strftimerecent {{/str}} {{/userdate}}
+                </p>
+            </div>
+        </div>
+        <div class="hidden-md-down d-none d-md-block col-lg-5 col-xl-4 text-truncate">
+            {{#action.actionable}}
+                <a href="{{{action.url}}}">{{action.name}}</a>
+                {{#action.itemcount}}
+                    {{#action.showitemcount}}
+                        <span class="tag tag-pill tag-default">{{.}}</span>
+                    {{/action.showitemcount}}
+                {{/action.itemcount}}
+            {{/action.actionable}}
+            {{^action.actionable}}
+                <div class="text-muted">{{action.name}}</div>
+            {{/action.actionable}}
+        </div>
+    </div>
+</li>
diff --git a/myoverview/templates/course-event-list-items.mustache b/myoverview/templates/course-event-list-items.mustache
new file mode 100644
index 0000000..10a1c43
--- /dev/null
+++ b/myoverview/templates/course-event-list-items.mustache
@@ -0,0 +1,63 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_myoverview/course-event-list-items
+
+    This template renders a group of event list items for the myoverview block
+    sort by courses view.
+
+    Example context (json):
+    {
+        "events": [
+            {
+                "name": "Assignment due 1",
+                "url": "https://www.google.com",
+                "timesort": 1490320388,
+                "action": {
+                    "name": "Submit assignment",
+                    "url": "https://www.google.com",
+                    "itemcount": 1,
+                    "actionable": true
+                },
+                "icon": {
+                    "key": "icon",
+                    "component": "mod_assign",
+                    "alttext": "Assignment icon"
+                }
+            },
+            {
+                "name": "Assignment due 2",
+                "url": "https://www.google.com",
+                "timesort": 1490320388,
+                "action": {
+                    "name": "Submit assignment",
+                    "url": "https://www.google.com",
+                    "itemcount": 1,
+                    "actionable": true
+                },
+                "icon": {
+                    "key": "icon",
+                    "component": "mod_assign",
+                    "alttext": "Assignment icon"
+                }
+            }
+        ]
+    }
+}}
+{{#events}}
+    {{> block_myoverview/course-event-list-item }}
+{{/events}}
diff --git a/myoverview/templates/course-event-list.mustache b/myoverview/templates/course-event-list.mustache
new file mode 100644
index 0000000..d7f9fb2
--- /dev/null
+++ b/myoverview/templates/course-event-list.mustache
@@ -0,0 +1,110 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_myoverview/course-event-list
+
+    This template renders a list of events for the myoverview block
+    sort by courses view.
+
+    Example context (json):
+    {
+        "urls": {
+            "noevents": "#"
+        }
+    }
+}}
+<div data-region="event-list-container"
+     data-limit="{{$limit}}20{{/limit}}"
+     data-course-id="{{$courseid}}{{/courseid}}"
+     data-last-id="{{$lastid}}{{/lastid}}"
+     data-midnight="{{midnight}}"
+     id="event-list-container-{{$courseid}}{{/courseid}}">
+
+    <div data-region="event-list-content">
+        {{< block_myoverview/event-list-group }}
+            {{$title}}{{#str}} recentlyoverdue, block_myoverview {{/str}}{{/title}}
+            {{$extratitleclasses}}text-danger{{/extratitleclasses}}
+            {{$startday}}-14{{/startday}}
+            {{$endday}}0{{/endday}}
+            {{$eventlistitems}}
+                {{> block_myoverview/course-event-list-items }}
+            {{/eventlistitems}}
+        {{/ block_myoverview/event-list-group }}
+        {{< block_myoverview/event-list-group }}
+            {{$title}}{{#str}} today {{/str}}{{/title}}
+            {{$extratitleclasses}}{{/extratitleclasses}}
+            {{$startday}}0{{/startday}}
+            {{$endday}}1{{/endday}}
+            {{$eventlistitems}}
+                {{> block_myoverview/course-event-list-items }}
+            {{/eventlistitems}}
+        {{/ block_myoverview/event-list-group }}
+        {{< block_myoverview/event-list-group }}
+            {{$title}}{{#str}} next7days, block_myoverview {{/str}}{{/title}}
+            {{$extratitleclasses}}{{/extratitleclasses}}
+            {{$startday}}1{{/startday}}
+            {{$endday}}7{{/endday}}
+            {{$eventlistitems}}
+                {{> block_myoverview/course-event-list-items }}
+            {{/eventlistitems}}
+        {{/ block_myoverview/event-list-group }}
+        {{< block_myoverview/event-list-group }}
+            {{$title}}{{#str}} next30days, block_myoverview {{/str}}{{/title}}
+            {{$extratitleclasses}}{{/extratitleclasses}}
+            {{$startday}}7{{/startday}}
+            {{$endday}}30{{/endday}}
+            {{$eventlistitems}}
+                {{> block_myoverview/course-event-list-items }}
+            {{/eventlistitems}}
+        {{/ block_myoverview/event-list-group }}
+        {{< block_myoverview/event-list-group }}
+            {{$title}}{{#str}} future, block_myoverview {{/str}}{{/title}}
+            {{$extratitleclasses}}{{/extratitleclasses}}
+            {{$startday}}30{{/startday}}
+            {{$endday}}{{/endday}}
+            {{$eventlistitems}}
+                {{> block_myoverview/course-event-list-items }}
+            {{/eventlistitems}}
+        {{/ block_myoverview/event-list-group }}
+
+        <div class="text-xs-center text-center m-y-2">
+            <button type="button" class="btn btn-secondary" data-action="view-more">
+                {{#str}} viewmore {{/str}}
+                <span class="hidden" data-region="loading-icon-container">
+                    {{> core/loading }}
+                </span>
+            </button>
+        </div>
+    </div>
+    <div class="hidden text-xs-center text-center m-y-3" data-region="empty-message">
+        <img class="empty-placeholder-image-sm"
+             src="{{urls.noevents}}"
+             alt="{{#str}} noevents, block_myoverview {{/str}}"
+             role="presentation">
+        <p class="text-muted m-t-1">{{#str}} noevents, block_myoverview {{/str}}</p>
+        <a href="{{viewurl}}" class="btn btn-secondary {{#visible}}text-primary{{/visible}}"
+           aria-label="{{#str}} viewcoursename, block_myoverview, {{{fullnamedisplay}}} {{/str}}">
+            {{#str}} viewcourse, block_myoverview {{/str}}
+        </a>
+    </div>
+</div>
+{{#js}}
+require(['jquery', 'block_myoverview/event_list'], function($, EventList) {
+    var root = $("#event-list-container-{{$courseid}}{{/courseid}}");
+    EventList.registerEventListeners(root);
+});
+{{/js}}
diff --git a/myoverview/templates/course-item.mustache b/myoverview/templates/course-item.mustache
new file mode 100644
index 0000000..c7ce9d8
--- /dev/null
+++ b/myoverview/templates/course-item.mustache
@@ -0,0 +1,44 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_myoverview/course-item
+
+    This template renders the each course block containing a summary and calendar events.
+
+    Example context (json):
+    {
+        "shortname": "course 3",
+        "viewurl": "https://www.google.com",
+        "summary": "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout."
+    }
+}}
+<li class="list-group-item m-y-1">
+<div data-region="course-events-container" id="course-events-container-{{id}}" data-course-id="{{id}}">
+    <div class="row">
+        <div class="col-lg-3">
+            {{> block_myoverview/course-summary }}
+        </div>
+        <div class="col-lg-9">
+            {{< block_myoverview/course-event-list }}
+                {{$limit}}10{{/limit}}
+                {{$offset}}0{{/offset}}
+                {{$courseid}}{{id}}{{/courseid}}
+            {{/ block_myoverview/course-event-list }}
+        </div>
+    </div>
+</div>
+</li>
diff --git a/myoverview/templates/course-paging-content-item.mustache b/myoverview/templates/course-paging-content-item.mustache
new file mode 100644
index 0000000..bbaa637
--- /dev/null
+++ b/myoverview/templates/course-paging-content-item.mustache
@@ -0,0 +1,47 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_myoverview/course-paging-content-item
+
+    This template renders each course block.
+
+    Example context (json):
+    {
+        "page": 1,
+        "active": true,
+        "courses": [
+            {
+                "fullnamedisplay": "course 1",
+                "viewurl": "https://www.google.com",
+                "summary": "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout."
+            },
+            {
+                "fullnamedisplay": "course 2",
+                "viewurl": "https://www.google.com",
+                "summary": "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout."
+            }
+        ]
+    }
+}}
+{{< block_myoverview/paging-content-item }}
+    {{$classes}}row card-deck{{/classes}}
+    {{$content}}
+        {{#courses}}
+            {{> block_myoverview/courses-view-course-item }}
+        {{/courses}}
+    {{/content}}
+{{/ block_myoverview/paging-content-item }}
diff --git a/myoverview/templates/course-paging-content.mustache b/myoverview/templates/course-paging-content.mustache
new file mode 100644
index 0000000..85ee437
--- /dev/null
+++ b/myoverview/templates/course-paging-content.mustache
@@ -0,0 +1,48 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_myoverview/course-paging-content
+
+    This template renders the each course block containing a summary and calendar events.
+
+    Example context (json):
+    {
+        "pages": [
+            {
+                "page": 1,
+                "active": true,
+                "courses": [
+                    {
+                        "fullnamedisplay": "course 1",
+                        "viewurl": "https://www.google.com",
+                        "summary": "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout."
+                    },
+                    {
+                        "fullnamedisplay": "course 2",
+                        "viewurl": "https://www.google.com",
+                        "summary": "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout."
+                    }
+                ]
+            }
+        ]
+    }
+}}
+{{< block_myoverview/paging-content }}
+    {{$paging-content-item}}
+        {{> block_myoverview/course-paging-content-item }}
+    {{/paging-content-item}}
+{{/ block_myoverview/paging-content }}
diff --git a/myoverview/templates/course-summary.mustache b/myoverview/templates/course-summary.mustache
new file mode 100644
index 0000000..53f40a0
--- /dev/null
+++ b/myoverview/templates/course-summary.mustache
@@ -0,0 +1,49 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_myoverview/course-summary
+
+    This template renders the course summary (view by courses) for the myoverview block.
+
+    Example context (json):
+    {
+        "fullnamedisplay": "course 3",
+        "viewurl": "https://www.google.com",
+        "summary": "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout."
+    }
+}}
+<div class="course-info-container" id="course-info-container-{{id}}">
+    <div class="d-sm-none d-lg-block">
+        {{> block_myoverview/progress-chart}}
+        <h4 class="h5"><a href="{{viewurl}}" class="{{^visible}}dimmed{{/visible}}">{{{fullnamedisplay}}}</a></h4>
+    </div>
+    <div class="d-none d-sm-block d-lg-none visible-tablet">
+        <div class="media">
+            <div class="media-left pr-3">
+                <div class="media-object">
+                    {{> block_myoverview/progress-chart}}
+                </div>
+            </div>
+            <div class="media-body">
+                <h4 class="h5"><a href="{{viewurl}}" class="{{^visible}}dimmed{{/visible}}">{{{fullnamedisplay}}}</a></h4>
+            </div>
+        </div>
+    </div>
+    <p class="text-muted">
+        {{#shortentext}} 140, {{{summary}}}{{/shortentext}}
+    </p>
+</div>
diff --git a/myoverview/templates/courses-view-by-status.mustache b/myoverview/templates/courses-view-by-status.mustache
new file mode 100644
index 0000000..3360d55
--- /dev/null
+++ b/myoverview/templates/courses-view-by-status.mustache
@@ -0,0 +1,45 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_myoverview/courses-view-by-status
+
+    This template renders the courses view for the myoverview block.
+
+    Example context (json):
+    {}
+}}
+<div id="{{$id}}courses-view-status-{{uniqid}}{{/id}}"
+     data-status="{{$status}}{{/status}}">
+
+    {{> block_myoverview/course-paging-content }}
+
+    <div class="text-xs-center text-center">
+        {{> block_myoverview/paging-bar }}
+    </div>
+</div>
+{{#js}}
+require(['jquery', 'block_myoverview/paging_bar', 'block_myoverview/paging_content'],
+    function($, PagingBar, PagingContent) {
+
+    var root = $('#{{$id}}courses-view-status-{{uniqid}}{{/id}}');
+    var pagingBarElement = root.find(PagingBar.rootSelector);
+    var pagingContentElement = root.find(PagingContent.rootSelector);
+
+    var content = new PagingContent(pagingContentElement, pagingBarElement);
+    content.registerEventListeners();
+});
+{{/js}}
diff --git a/myoverview/templates/courses-view-course-item.mustache b/myoverview/templates/courses-view-course-item.mustache
new file mode 100644
index 0000000..db2034d
--- /dev/null
+++ b/myoverview/templates/courses-view-course-item.mustache
@@ -0,0 +1,49 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_myoverview/courses-view-course-item
+
+    This template renders the course summary (view by courses) for the myoverview block.
+
+    Example context (json):
+    {
+        "fullnamedisplay": "course 3",
+        "viewurl": "https://www.google.com",
+        "summary": "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout."
+    }
+}}
+<div class="card mb-3 courses-view-course-item">
+    <a href="{{viewurl}}">
+        <div class="card-img-top myoverviewimg {{classes}}" style='background-image: url("{{{courseimage}}}");'>
+        </div>
+    </a>
+    <div class="card-body course-info-container" id="course-info-container-{{id}}">
+
+        <div class="media">
+            <div class="mr-2">
+                {{> block_myoverview/progress-chart}}
+            </div>
+            <div class="media-body">
+                <h4 class="h5"><a href="{{viewurl}}" class="{{^visible}}dimmed{{/visible}}">{{{fullnamedisplay}}}</a></h4>
+            </div>
+        </div>
+
+        <p class="text-muted">
+            {{#shortentext}} 140, {{summary}}{{/shortentext}}
+        </p>
+    </div>
+</div>
\ No newline at end of file
diff --git a/myoverview/templates/courses-view.mustache b/myoverview/templates/courses-view.mustache
new file mode 100644
index 0000000..14ffa49
--- /dev/null
+++ b/myoverview/templates/courses-view.mustache
@@ -0,0 +1,115 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_myoverview/courses-view
+
+    This template renders the courses view for the myoverview block.
+
+    Example context (json):
+    {}
+}}
+<div id="courses-view-{{uniqid}}" data-region="courses-view">
+    {{#hascourses}}
+    <div class="d-flex justify-content-center">
+        <ul class="nav nav-pills my-5">
+            <li class="nav-item">
+                <a class="nav-link active" href="#myoverview_courses_view_in_progress" data-toggle="tab">
+                    {{#str}} inprogress, block_myoverview {{/str}}
+                </a>
+            </li>
+            <li class="nav-item">
+                <a class="nav-link" href="#myoverview_courses_view_future" data-toggle="tab">
+                    {{#str}} future, block_myoverview {{/str}}
+                </a>
+            </li>
+            <li class="nav-item">
+                <a class="nav-link" href="#myoverview_courses_view_past" data-toggle="tab">
+                    {{#str}} past, block_myoverview {{/str}}
+                </a>
+            </li>
+        </ul>
+    </div>
+    <div class="tab-content">
+        <div class="tab-pane active fade show" id="myoverview_courses_view_in_progress">
+            {{#inprogress}}
+                {{< block_myoverview/courses-view-by-status }}
+                    {{$id}}courses-view-in-progress{{/id}}
+                    {{$status}}1{{/status}}
+                    {{$pagingbarid}}pb-for-in-progress{{/pagingbarid}}
+                    {{$pagingcontentid}}pc-for-in-progress{{/pagingcontentid}}
+                {{/ block_myoverview/courses-view-by-status }}
+            {{/inprogress}}
+            {{^inprogress}}
+                <div class="justify-content-center text-center mt-5">
+                    <img class="empty-placeholder-image-lg"
+                         src="{{urls.nocourses}}"
+                         alt="{{#str}} nocoursesinprogress, block_myoverview {{/str}}"
+                         role="presentation">
+                    <p class="text-muted mt-3">{{#str}} nocoursesinprogress, block_myoverview {{/str}}</p>
+                </div>
+            {{/inprogress}}
+        </div>
+        <div class="tab-pane fade" id="myoverview_courses_view_future">
+            {{#future}}
+                {{< block_myoverview/courses-view-by-status }}
+                    {{$id}}courses-view-future{{/id}}
+                    {{$status}}2{{/status}}
+                    {{$pagingbarid}}pb-for-future{{/pagingbarid}}
+                    {{$pagingcontentid}}pc-for-in-progress{{/pagingcontentid}}
+                {{/ block_myoverview/courses-view-by-status }}
+            {{/future}}
+            {{^future}}
+                <div class="justify-content-center text-center mt-5">
+                    <img class="empty-placeholder-image-lg"
+                         src="{{urls.nocourses}}"
+                         alt="{{#str}} nocoursesfuture, block_myoverview {{/str}}"
+                         role="presentation">
+                    <p class="text-muted mt-3">{{#str}} nocoursesfuture, block_myoverview {{/str}}</p>
+                </div>
+            {{/future}}
+        </div>
+        <div class="tab-pane fade" id="myoverview_courses_view_past">
+            {{#past}}
+                {{< block_myoverview/courses-view-by-status }}
+                    {{$id}}courses-view-past{{/id}}
+                    {{$status}}0{{/status}}
+                    {{$pagingbarid}}pb-for-past{{/pagingbarid}}
+                    {{$pagingcontentid}}pc-for-in-progress{{/pagingcontentid}}
+                {{/ block_myoverview/courses-view-by-status }}
+            {{/past}}
+            {{^past}}
+                <div class="justify-content-center text-center mt-5">
+                    <img class="empty-placeholder-image-lg"
+                         src="{{urls.nocourses}}"
+                         alt="{{#str}} nocoursespast, block_myoverview {{/str}}"
+                         role="presentation">
+                    <p class="text-muted mt-3">{{#str}} nocoursespast, block_myoverview {{/str}}</p>
+                </div>
+            {{/past}}
+        </div>
+    </div>
+    {{/hascourses}}
+    {{^hascourses}}
+    <div class="justify-content-center text-center mt-5">
+        <img class="empty-placeholder-image-lg"
+             src="{{urls.nocourses}}"
+             alt="{{#str}} nocourses, block_myoverview {{/str}}"
+             role="presentation">
+        <p class="text-muted mt-3">{{#str}} nocourses, block_myoverview {{/str}}</p>
+    </div>
+    {{/hascourses}}
+</div>
\ No newline at end of file
diff --git a/myoverview/templates/event-list-group.mustache b/myoverview/templates/event-list-group.mustache
new file mode 100644
index 0000000..340fdcb
--- /dev/null
+++ b/myoverview/templates/event-list-group.mustache
@@ -0,0 +1,75 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_myoverview/event-list-group
+
+    This template renders a list of events for the myoverview block.
+
+    Example context (json):
+    {
+        "events": [
+            {
+                "enddate": "Nov 4th, 10am",
+                "name": "Assignment due 1",
+                "url": "https://www.google.com",
+                "course": {
+                    "fullname": "Course 1"
+                },
+                "action": {
+                    "name": "Submit assignment",
+                    "url": "https://www.google.com",
+                    "itemcount": 1
+                },
+                "icon": {
+                    "key": "icon",
+                    "component": "mod_assign",
+                    "alttext": "Assignment icon"
+                }
+            },
+            {
+                "enddate": "Nov 4th, 10am",
+                "name": "Assignment due 2",
+                "url": "https://www.google.com",
+                "course": {
+                    "fullname": "Course 1"
+                },
+                "action": {
+                    "name": "Submit assignment",
+                    "url": "https://www.google.com",
+                    "itemcount": 1
+                },
+                "icon": {
+                    "key": "icon",
+                    "component": "mod_assign",
+                    "alttext": "Assignment icon"
+                }
+            }
+        ]
+    }
+}}
+<div data-region="event-list-group-container"
+     data-start-day="{{$startday}}0{{/startday}}"
+     data-end-day="{{$endday}}{{/endday}}"
+     class="hidden">
+
+    <h5 class="h6 m-t-1 {{$extratitleclasses}}{{/extratitleclasses}}" id="event-list-title-{{uniqid}}"><strong>{{$title}}{{/title}}</strong></h5>
+    <ul class="list-group unstyled" data-region="event-list" aria-describedby="event-list-title-{{uniqid}}">
+        {{$eventlistitems}}
+            {{> block_myoverview/event-list-items }}
+        {{/eventlistitems}}
+    </ul>
+</div>
diff --git a/myoverview/templates/event-list-item.mustache b/myoverview/templates/event-list-item.mustache
new file mode 100644
index 0000000..a269b5c
--- /dev/null
+++ b/myoverview/templates/event-list-item.mustache
@@ -0,0 +1,76 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_myoverview/event-list-item
+
+    This template renders an event list item for the myoverview block.
+
+    Example context (json):
+    {
+        "name": "Assignment due 1",
+        "url": "https://www.google.com",
+        "timesort": 1490320388,
+        "course": {
+            "fullnamedisplay": "Course 1"
+        },
+        "action": {
+            "name": "Submit assignment",
+            "url": "https://www.google.com",
+            "itemcount": 1,
+            "showitemcount": true,
+            "actionable": true
+        },
+        "icon": {
+            "key": "icon",
+            "component": "mod_assign",
+            "alttext": "Assignment icon"
+        }
+    }
+}}
+<li class="list-group-item event-list-item" data-region="event-list-item">
+    <div class="row">
+        <div class="col-sm-8 col-lg-6 col-xl-7">
+            <div class="d-inline-block icon-large event-icon">
+                {{#icon}}{{#pix}} {{key}}, {{component}}, {{alttext}} {{/pix}}{{/icon}}
+            </div>
+            <div class="d-inline-block event-name-container">
+                <a class="event-name text-truncate" href="{{{url}}}">{{{name}}}</a>
+                <p class="small text-muted text-truncate m-b-0">{{{course.fullnamedisplay}}}</p>
+            </div>
+        </div>
+        <div class="col-sm-4 col-lg-6 col-xl-5">
+            <div class="row">
+                <div class="col-lg-5 text-xs-right text-lg-left text-truncate">
+                    {{#userdate}} {{timesort}}, {{#str}} strftimerecent {{/str}} {{/userdate}}
+                </div>
+                <div class="hidden-md-down d-none d-md-block col-lg-7 text-truncate">
+                    {{#action.actionable}}
+                        <a href="{{{action.url}}}">{{action.name}}</a>
+                        {{#action.itemcount}}
+                            {{#action.showitemcount}}
+                                <span class="tag tag-pill tag-default">{{.}}</span>
+                            {{/action.showitemcount}}
+                        {{/action.itemcount}}
+                    {{/action.actionable}}
+                    {{^action.actionable}}
+                        <div class="text-muted">{{action.name}}</div>
+                    {{/action.actionable}}
+                </div>
+            </div>
+        </div>
+    </div>
+</li>
diff --git a/myoverview/templates/event-list-items.mustache b/myoverview/templates/event-list-items.mustache
new file mode 100644
index 0000000..2dc770b
--- /dev/null
+++ b/myoverview/templates/event-list-items.mustache
@@ -0,0 +1,68 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_myoverview/event-list-items
+
+    This template renders a group of event list items for the myoverview block.
+
+    Example context (json):
+    {
+        "events": [
+            {
+                "name": "Assignment due 1",
+                "url": "https://www.google.com",
+                "timesort": 1490320388,
+                "course": {
+                    "fullnamedisplay": "Course 1"
+                },
+                "action": {
+                    "name": "Submit assignment",
+                    "url": "https://www.google.com",
+                    "itemcount": 1,
+                    "actionable": true
+                },
+                "icon": {
+                    "key": "icon",
+                    "component": "mod_assign",
+                    "alttext": "Assignment icon"
+                }
+            },
+            {
+                "name": "Assignment due 2",
+                "url": "https://www.google.com",
+                "timesort": 1490320388,
+                "course": {
+                    "fullnamedisplay": "Course 1"
+                },
+                "action": {
+                    "name": "Submit assignment",
+                    "url": "https://www.google.com",
+                    "itemcount": 1,
+                    "actionable": true
+                },
+                "icon": {
+                    "key": "icon",
+                    "component": "mod_assign",
+                    "alttext": "Assignment icon"
+                }
+            }
+        ]
+    }
+}}
+{{#events}}
+    {{> block_myoverview/event-list-item }}
+{{/events}}
diff --git a/myoverview/templates/event-list.mustache b/myoverview/templates/event-list.mustache
new file mode 100644
index 0000000..dbe3d25
--- /dev/null
+++ b/myoverview/templates/event-list.mustache
@@ -0,0 +1,87 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_myoverview/event-list
+
+    This template renders a list of events for the myoverview block.
+
+    Example context (json):
+    {
+    }
+}}
+<div data-region="event-list-container"
+     data-limit="{{$limit}}20{{/limit}}"
+     data-course-id="{{$courseid}}{{/courseid}}"
+     data-last-id="{{$lastid}}{{/lastid}}"
+     data-midnight="{{midnight}}"
+     id="event-list-container-{{$courseid}}{{/courseid}}">
+
+    <div data-region="event-list-content">
+        {{< block_myoverview/event-list-group }}
+            {{$title}}{{#str}} recentlyoverdue, block_myoverview {{/str}}{{/title}}
+            {{$extratitleclasses}}text-danger{{/extratitleclasses}}
+            {{$startday}}-14{{/startday}}
+            {{$endday}}0{{/endday}}
+        {{/ block_myoverview/event-list-group }}
+        {{< block_myoverview/event-list-group }}
+            {{$title}}{{#str}} today {{/str}}{{/title}}
+            {{$extratitleclasses}}{{/extratitleclasses}}
+            {{$startday}}0{{/startday}}
+            {{$endday}}1{{/endday}}
+        {{/ block_myoverview/event-list-group }}
+        {{< block_myoverview/event-list-group }}
+            {{$title}}{{#str}} next7days, block_myoverview {{/str}}{{/title}}
+            {{$extratitleclasses}}{{/extratitleclasses}}
+            {{$startday}}1{{/startday}}
+            {{$endday}}7{{/endday}}
+        {{/ block_myoverview/event-list-group }}
+        {{< block_myoverview/event-list-group }}
+            {{$title}}{{#str}} next30days, block_myoverview {{/str}}{{/title}}
+            {{$extratitleclasses}}{{/extratitleclasses}}
+            {{$startday}}7{{/startday}}
+            {{$endday}}30{{/endday}}
+        {{/ block_myoverview/event-list-group }}
+        {{< block_myoverview/event-list-group }}
+            {{$title}}{{#str}} future, block_myoverview {{/str}}{{/title}}
+            {{$extratitleclasses}}{{/extratitleclasses}}
+            {{$startday}}30{{/startday}}
+            {{$endday}}{{/endday}}
+        {{/ block_myoverview/event-list-group }}
+
+        <div class="text-xs-center text-center m-y-2">
+            <button type="button" class="btn btn-secondary" data-action="view-more">
+                {{#str}} viewmore {{/str}}
+                <span class="hidden" data-region="loading-icon-container">
+                    {{> core/loading }}
+                </span>
+            </button>
+        </div>
+    </div>
+    <div class="hidden text-xs-center text-center m-t-3" data-region="empty-message">
+        <img class="empty-placeholder-image-lg"
+             src="{{urls.noevents}}"
+             alt="{{#str}} noevents, block_myoverview {{/str}}"
+             role="presentation">
+        <p class="text-muted m-t-1">{{#str}} noevents, block_myoverview {{/str}}</p>
+    </div>
+</div>
+{{#js}}
+require(['jquery', 'block_myoverview/event_list'], function($, EventList) {
+    var root = $("#event-list-container-{{$courseid}}{{/courseid}}");
+    EventList.registerEventListeners(root);
+});
+{{/js}}
diff --git a/myoverview/templates/main.mustache b/myoverview/templates/main.mustache
new file mode 100644
index 0000000..e9b21bd
--- /dev/null
+++ b/myoverview/templates/main.mustache
@@ -0,0 +1,55 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_myoverview/main
+
+    This template renders the main content area for the myoverview block.
+
+    Example context (json):
+    {}
+}}
+
+<div id="block-myoverview-{{uniqid}}" class="block-myoverview" data-region="myoverview">
+    <ul id="block-myoverview-view-choices-{{uniqid}}" class="nav nav-tabs" role="tablist">
+        <li class="nav-item">
+            <a class="nav-link {{#viewingtimeline}}active{{/viewingtimeline}}" href="#myoverview_timeline_view" role="tab" data-toggle="tab" data-tabname="timeline">
+                {{#str}} timeline, block_myoverview {{/str}}
+            </a>
+        </li>
+        <li class="nav-item">
+            <a class="nav-link {{#viewingcourses}}active{{/viewingcourses}}" href="#myoverview_courses_view" role="tab" data-toggle="tab" data-tabname="courses">
+                {{#str}} courses {{/str}}
+            </a>
+        </li>
+    </ul>
+    <div class="tab-content content-centred">
+        <div role="tabpanel" class="tab-pane fade {{#viewingtimeline}}in active{{/viewingtimeline}}" id="myoverview_timeline_view">
+            {{> block_myoverview/timeline-view }}
+        </div>
+        <div role="tabpanel" class="tab-pane fade {{#viewingcourses}}in active{{/viewingcourses}}" id="myoverview_courses_view">
+            {{#coursesview}}
+                {{> block_myoverview/courses-view }}
+            {{/coursesview}}
+        </div>
+    </div>
+</div>
+{{#js}}
+require(['jquery', 'block_myoverview/tab_preferences'], function($, TabPreferences) {
+    var root = $('#block-myoverview-view-choices-{{uniqid}}');
+    TabPreferences.registerEventListeners(root);
+});
+{{/js}}
diff --git a/myoverview/templates/paging-bar-item.mustache b/myoverview/templates/paging-bar-item.mustache
new file mode 100644
index 0000000..955ff02
--- /dev/null
+++ b/myoverview/templates/paging-bar-item.mustache
@@ -0,0 +1,41 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_myoverview/paging-bar-item
+
+    This template renders a single item in the paging bar.
+
+    Example context (json):
+    {
+        "url": "#",
+        "number": 1,
+        "page": "1",
+        "active": true
+    }
+}}
+<li class="page-item {{#active}}active{{/active}} {{#disabled}}disabled{{/disabled}}"
+    data-region="page-item"
+    data-page-number="{{$pagenumber}}{{number}}{{/pagenumber}}">
+
+    <a href="{{url}}"
+       class="page-link"
+       data-region="page-link">
+        {{$item-content}}
+            {{{page}}}
+        {{/item-content}}
+    </a>
+</li>
diff --git a/myoverview/templates/paging-bar.mustache b/myoverview/templates/paging-bar.mustache
new file mode 100644
index 0000000..71ffecf
--- /dev/null
+++ b/myoverview/templates/paging-bar.mustache
@@ -0,0 +1,96 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_myoverview/paging-bar
+
+    This template renders the bootstrap style paging bar.
+
+    Example context (json):
+    {
+        "pagingbar": {
+            "pagecount": 2,
+            "previous": {},
+            "next": {},
+            "first": {
+                "url": "#",
+                "page": "first"
+            },
+            "last": {
+                "url": "#",
+                "page": "last"
+            },
+            "pages": [
+                {
+                    "url": "#",
+                    "number": 1,
+                    "page": "1",
+                    "active": true
+                },
+                {
+                    "url": "#",
+                    "number": 2,
+                    "page": "2"
+                }
+            ]
+        }
+    }
+}}
+{{#pagingbar}}
+<nav aria-label="{{label}}"
+     id="{{$pagingbarid}}paging-bar-{{uniqid}}{{/pagingbarid}}"
+     data-region="paging-bar"
+     data-page-count="{{pagecount}}">
+
+    <ul class="pagination">
+        {{#previous}}
+            {{< block_myoverview/paging-bar-item }}
+                {{$item-content}}
+                    <span aria-hidden="true">&laquo;</span>
+                    <span class="sr-only">{{#str}}previous{{/str}}</span>
+                {{/item-content}}
+            {{/ block_myoverview/paging-bar-item }}
+        {{/previous}}
+        {{#first}}
+            {{< block_myoverview/paging-bar-item }}
+                {{$pagenumber}}first{{/pagenumber}}
+            {{/ block_myoverview/paging-bar-item }}
+        {{/first}}
+        {{#pages}}
+            {{> block_myoverview/paging-bar-item }}
+        {{/pages}}
+        {{#last}}
+            {{< block_myoverview/paging-bar-item }}
+                {{$pagenumber}}last{{/pagenumber}}
+            {{/ block_myoverview/paging-bar-item }}
+        {{/last}}
+        {{#next}}
+            {{< block_myoverview/paging-bar-item }}
+                {{$item-content}}
+                    <span aria-hidden="true">&raquo;</span>
+                    <span class="sr-only">{{#str}}next{{/str}}</span>
+                {{/item-content}}
+            {{/ block_myoverview/paging-bar-item }}
+        {{/next}}
+    </ul>
+</nav>
+{{#js}}
+require(['jquery', 'block_myoverview/paging_bar'], function($, PagingBar) {
+    var root = $('#{{$pagingbarid}}paging-bar-{{uniqid}}{{/pagingbarid}}');
+    PagingBar.registerEventListeners(root);
+});
+{{/js}}
+{{/pagingbar}}
diff --git a/myoverview/templates/paging-content-item.mustache b/myoverview/templates/paging-content-item.mustache
new file mode 100644
index 0000000..82e73e1
--- /dev/null
+++ b/myoverview/templates/paging-content-item.mustache
@@ -0,0 +1,36 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_myoverview/paging-content-item
+
+    This template renders the content of a page. It is to be used with
+    the paging bar to toggle visibility of the content items.
+
+    Example context (json):
+    {
+        "active": true,
+        "page": 1,
+        "content": "<p>Some page content</p>"
+    }
+}}
+<div data-region="paging-content-item"
+     data-page="{{page}}"
+     class="{{^active}}hidden{{/active}} {{$classes}}{{/classes}}">
+    {{$content}}
+        {{{content}}}
+    {{/content}}
+</div>
diff --git a/myoverview/templates/paging-content.mustache b/myoverview/templates/paging-content.mustache
new file mode 100644
index 0000000..83a9cdd
--- /dev/null
+++ b/myoverview/templates/paging-content.mustache
@@ -0,0 +1,44 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_myoverview/paging-content
+
+    This template renders each of the content regions for a paginated
+    content section.
+
+    Example context (json):
+    {
+        "pages": [
+            {
+                "active": true,
+                "page": 1,
+                "content": "<p>Some page content</p>"
+            },
+            {
+                "page": 2,
+                "content": "<p>Some page content</p>"
+            }
+        ]
+    }
+}}
+<div id="{{$pagingcontentid}}paging-content-{{uniqid}}{{/pagingcontentid}}" data-region="paging-content">
+    {{#pages}}
+        {{$paging-content-item}}
+            {{> block_myoverview/paging-content-item }}
+        {{/paging-content-item}}
+    {{/pages}}
+</div>
diff --git a/myoverview/templates/progress-chart.mustache b/myoverview/templates/progress-chart.mustache
new file mode 100644
index 0000000..18ff2a4
--- /dev/null
+++ b/myoverview/templates/progress-chart.mustache
@@ -0,0 +1,50 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_myoverview/progress-chart
+
+    This template renders a doughnut chart to show course progress.
+
+    Example context (json):
+    {
+        "hasprogress": true,
+        "progress": "60"
+    }
+}}
+<div class="progress-chart-container m-b-1">
+    {{#hasprogress}}
+    <div class="progress-doughnut">
+        <div class="progress-text {{#progress}}has-percent{{/progress}}">{{progress}}&#37;</div>
+        <div class="progress-indicator">
+            <svg xmlns="http://www.w3.org/2000/svg">
+                <g>
+                    <title aria-hidden="true">{{progress}}&#37;</title>
+                    <circle class="circle percent-{{progress}}"
+                            r="27.5"
+                            cx="35"
+                            cy="35"/>
+                </g>
+            </svg>
+        </div>
+    </div>
+    {{/hasprogress}}
+    {{^hasprogress}}
+    <div class="no-progress">
+        {{#pix}} i/course {{/pix}}
+    </div>
+    {{/hasprogress}}
+</div>
diff --git a/myoverview/templates/timeline-view-courses.mustache b/myoverview/templates/timeline-view-courses.mustache
new file mode 100644
index 0000000..a569405
--- /dev/null
+++ b/myoverview/templates/timeline-view-courses.mustache
@@ -0,0 +1,121 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_myoverview/timeline-view-courses
+
+    This template renders the timeline view by courses for the myoverview block.
+
+    Example context (json):
+    {}
+}}
+<div id="sort-by-courses-view-{{uniqid}}">
+    {{#coursesview}}
+        {{#inprogress}}
+            {{#haspages}}
+                {{#pages}}
+                    <ul class="list-group unstyled hidden" data-region="course-block">
+                        {{#courses}} {{> block_myoverview/course-item }} {{/courses}}
+                    </ul>
+                {{/pages}}
+                <div class="text-xs-center text-center m-t-1">
+                    <button type="button" class="btn btn-secondary" data-action="more-courses">
+                        {{#str}} morecourses, block_myoverview {{/str}}
+                        <span class="hidden" data-region="loading-icon-container">
+                            {{> core/loading }}
+                        </span>
+                    </button>
+                </div>
+            {{/haspages}}
+            {{^haspages}}
+                <div class="text-xs-center text-center m-t-3">
+                    <img class="empty-placeholder-image-lg"
+                         src="{{urls.noevents}}"
+                         alt="{{#str}} nocoursesinprogress, block_myoverview {{/str}}"
+                         role="presentation">
+                    <p class="text-muted m-t-1">{{#str}} nocoursesinprogress, block_myoverview {{/str}}</p>
+                </div>
+            {{/haspages}}
+        {{/inprogress}}
+        {{^inprogress}}
+            <div class="text-xs-center text-center m-t-3">
+                <img class="empty-placeholder-image-lg"
+                     src="{{urls.noevents}}"
+                     alt="{{#str}} nocoursesinprogress, block_myoverview {{/str}}"
+                     role="presentation">
+                <p class="text-muted m-t-1">{{#str}} nocoursesinprogress, block_myoverview {{/str}}</p>
+            </div>
+        {{/inprogress}}
+    {{/coursesview}}
+</div>
+{{#js}}
+    require(['jquery', 'core/custom_interaction_events', 'block_myoverview/event_list_by_course'],
+        function($, CustomEvents, EventListByCourse) {
+
+        var root = $("#sort-by-courses-view-{{uniqid}}");
+        // This flag is used so that we can delay the loading of the events until the tab
+        // is toggled by the user.
+        var seen = false;
+
+        CustomEvents.define(root, [CustomEvents.events.activate]);
+        // Show more courses and load their events when the user clicks the "more courses"
+        // button.
+        root.on(CustomEvents.events.activate, '[data-action="more-courses"]', function(e, data) {
+            var button = $(e.target);
+            var blocks = root.find('[data-region="course-block"].hidden');
+
+            if (blocks && blocks.length) {
+                var block = blocks.first();
+                EventListByCourse.init(block);
+                block.removeClass('hidden');
+            }
+
+            // If there was only one hidden block then we have no more to show now
+            // so we can disable the button.
+            if (blocks && blocks.length == 1) {
+                button.prop('disabled', true);
+            }
+
+            if (data) {
+                data.originalEvent.preventDefault();
+                data.originalEvent.stopPropagation();
+            }
+            e.stopPropagation();
+        });
+
+        // Listen for when the user changes tab so that we can show the first set of courses
+        // and load their events when they request the sort by courses view for the first time.
+        root.closest('[data-region="timeline-view"]').on('shown shown.bs.tab', function(e) {
+            if (seen) {
+                return;
+            }
+
+            var tab = $(e.target);
+            var tabTarget = $(tab.attr('href'));
+
+            if (!tabTarget || !tabTarget.length) {
+                return;
+            }
+
+            var viewCourses = tabTarget.find('#sort-by-courses-view-{{uniqid}}');
+
+            if (viewCourses && viewCourses.length && !seen) {
+                seen = true;
+                viewCourses.find('[data-action="more-courses"]').trigger(CustomEvents.events.activate);
+            }
+        });
+    });
+{{/js}}
diff --git a/myoverview/templates/timeline-view-dates.mustache b/myoverview/templates/timeline-view-dates.mustache
new file mode 100644
index 0000000..66cb8ea
--- /dev/null
+++ b/myoverview/templates/timeline-view-dates.mustache
@@ -0,0 +1,35 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_myoverview/timeline-view-dates
+
+    This template renders the timeline view by dates for the myoverview block.
+
+    Example context (json):
+    {}
+}}
+<div data-region="timeline-view-dates" id="timeline-view-dates-{{uniqid}}">
+    {{< block_myoverview/event-list }}
+        {{$limit}}20{{/limit}}
+    {{/ block_myoverview/event-list }}
+</div>
+{{#js}}
+    require(['jquery', 'block_myoverview/event_list'], function($, EventList) {
+    var root = $("#timeline-view-dates-{{uniqid}}").find('[data-region="event-list-container"]');
+    EventList.load(root);
+    });
+{{/js}}
diff --git a/myoverview/templates/timeline-view.mustache b/myoverview/templates/timeline-view.mustache
new file mode 100644
index 0000000..9d57cd2
--- /dev/null
+++ b/myoverview/templates/timeline-view.mustache
@@ -0,0 +1,49 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_myoverview/timeline-view
+
+    This template renders the timeline view for the myoverview block.
+
+    Example context (json):
+    {}
+}}
+<div id="timeline-view-{{uniqid}}" data-region="timeline-view">
+    <div class="d-flex justify-content-center">
+        <ul class="nav nav-pills my-5">
+            <li class="nav-item">
+            <a class="nav-link active" href="#myoverview_timeline_dates" data-toggle="tab">
+                {{#str}} sortbydates, block_myoverview {{/str}}
+            </a>
+            </li>
+            <li class="nav-item">
+            <a class="nav-link" href="#myoverview_timeline_courses" data-toggle="tab">
+                {{#str}} sortbycourses, block_myoverview {{/str}}
+            </a>
+            </li>
+        </ul>
+    </div>
+
+    <div class="tab-content">
+        <div class="tab-pane active fade show" id="myoverview_timeline_dates">
+            {{> block_myoverview/timeline-view-dates }}
+        </div>
+        <div class="tab-pane fade" id="myoverview_timeline_courses">
+            {{> block_myoverview/timeline-view-courses }}
+        </div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/myoverview/tests/behat/block_myoverview_dashboard.feature b/myoverview/tests/behat/block_myoverview_dashboard.feature
new file mode 100644
index 0000000..bf6f356
--- /dev/null
+++ b/myoverview/tests/behat/block_myoverview_dashboard.feature
@@ -0,0 +1,72 @@
+@block @block_myoverview @javascript
+Feature: The my overview block allows users to easily access their courses and see upcoming activities
+  In order to enable the my overview block in a course
+  As a student
+  I can add the my overview block to my dashboard
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email                | idnumber |
+      | student1 | Student   | 1        | student1@example.com | S1       |
+      | student2 | Student   | 2        | student2@example.com | S2       |
+    And the following "courses" exist:
+      | fullname | shortname | category | startdate                   | enddate         |
+      | Course 1 | C1        | 0        | ##1 month ago##             | ##15 days ago## |
+      | Course 2 | C2        | 0        | ##yesterday##               | ##tomorrow## |
+      | Course 3 | C3        | 0        | ##first day of next month## | ##last day of next month## |
+    And the following "activities" exist:
+      | activity | course | idnumber  | name            | intro                   | timeopen      | timeclose     |
+      | choice   | C2     | choice1   | Test choice 1   | Test choice description | ##yesterday## | ##tomorrow##  |
+      | choice   | C1     | choice2   | Test choice 2   | Test choice description | ##1 month ago## | ##15 days ago##  |
+      | choice   | C3     | choice3   | Test choice 3   | Test choice description | ##first day of +5 months## | ##last day of +5 months##  |
+      | feedback | C2     | feedback1 | Test feedback 1 | Test feedback description | ##yesterday## | ##tomorrow##  |
+      | feedback | C3     | feedback3 | Test feedback 3 | Test feedback description | ##first day of +5 months## | ##last day of +5 months## |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | student1 | C1 | student |
+      | student1 | C2 | student |
+      | student1 | C3 | student |
+
+  Scenario: View courses and upcoming activities on timeline view
+    Given I log in as "student1"
+    And I click on "Timeline" "link" in the "Course overview" "block"
+    When I click on "Sort by dates" "link" in the "Course overview" "block"
+    Then I should see "Next 7 days" in the "Course overview" "block"
+    And I should see "Test choice 1 closes" in the "Course overview" "block"
+    And I should see "View choices" in the "Course overview" "block"
+    And I should see "Test feedback 1 closes" in the "Course overview" "block"
+    And I should see "Answer the questions" in the "Course overview" "block"
+    And I should see "Future" in the "Course overview" "block"
+    And I should see "Test choice 3 closes" in the "Course overview" "block"
+    And I should see "Test feedback 3 closes" in the "Course overview" "block"
+    And I log out
+
+  Scenario: Past activities should not be displayed on the timeline view
+    Given I log in as "student1"
+    And I click on "Timeline" "link" in the "Course overview" "block"
+    When I click on "Sort by dates" "link" in the "Course overview" "block"
+    And I should not see "Test choice 2 closes" in the "Course overview" "block"
+    And I log out
+
+  Scenario: See the courses I am enrolled by their status on courses view
+    Given I log in as "student1"
+    And I click on "Courses" "link" in the "Course overview" "block"
+    And I click on "In progress" "link" in the "Course overview" "block"
+    And I should see "Course 2" in the "Course overview" "block"
+    And I should not see "Course 1" in the "Course overview" "block"
+    And I click on "Future" "link" in the "Course overview" "block"
+    And I should see "Course 3" in the "Course overview" "block"
+    And I should not see "Course 1" in the "Course overview" "block"
+    When I click on "Past" "link" in the "Course overview" "block"
+    Then I should see "Course 1" in the "Course overview" "block"
+    And I should not see "Course 2" in the "Course overview" "block"
+    And I should not see "Course 3" in the "Course overview" "block"
+    And I log out
+
+  Scenario: No activities should be displayed if the user is not enrolled
+    Given I log in as "student2"
+    And I click on "Timeline" "link" in the "Course overview" "block"
+    And I should see "No upcoming activities" in the "Course overview" "block"
+    When I click on "Courses" "link" in the "Course overview" "block"
+    Then I should see "No courses" in the "Course overview" "block"
+    And I log out
diff --git a/myoverview/tests/behat/block_myoverview_progress.feature b/myoverview/tests/behat/block_myoverview_progress.feature
new file mode 100644
index 0000000..44cd539
--- /dev/null
+++ b/myoverview/tests/behat/block_myoverview_progress.feature
@@ -0,0 +1,63 @@
+@block @block_myoverview @javascript
+Feature: Course overview block show users their progress on courses
+  In order to enable the my overview block in a course
+  As a student
+  I can see the progress percentage of the courses I am enrolled in
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+      | student1 | Student | 1 | student1@example.com | S1 |
+    And the following "courses" exist:
+      | fullname | shortname | category | enablecompletion | startdate     | enddate       |
+      | Course 1 | C1        | 0        | 1                | ##yesterday## | ##tomorrow##  |
+    And the following "activities" exist:
+      | activity | course | idnumber | name          | intro                   | timeopen      | timeclose     |
+      | choice   | C1     | choice1  | Test choice 1 | Test choice description | ##yesterday## | ##tomorrow##  |
+    And the following "course enrolments" exist:
+      | user | course | role            |
+      | teacher1 | C1 | editingteacher  |
+      | student1 | C1 | student         |
+
+  Scenario: Course progress percentage should not be displayed if completion is not enabled
+    Given I log in as "student1"
+    And I click on "Timeline" "link" in the "Course overview" "block"
+    When I click on "Sort by courses" "link" in the "Course overview" "block"
+    Then I should see "Test choice 1 closes" in the "#myoverview_timeline_courses" "css_element"
+    And I should not see "0%" in the "Course overview" "block"
+    And I click on "Courses" "link" in the "Course overview" "block"
+    And I click on "In progress" "link" in the "Course overview" "block"
+    And I should see "Course 1" in the "Course overview" "block"
+    And I should not see "0%" in the "Course overview" "block"
+    And I log out
+
+  Scenario: User complete activity and verify his progress
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I follow "Test choice 1"
+    And I navigate to "Edit settings" in current page administration
+    And I set the following fields to these values:
+      | Completion tracking | Show activity as complete when conditions are met |
+      | id_completionview   | 1                                                 |
+    And I press "Save and return to course"
+    And I log out
+    And I log in as "student1"
+    And I click on "Sort by courses" "link" in the "Course overview" "block"
+    And I should see "Test choice 1 closes" in the "#myoverview_timeline_courses" "css_element"
+    And I should see "0%" in the "Course overview" "block"
+    And I click on "Courses" "link" in the "Course overview" "block"
+    When I click on "In progress" "link" in the "Course overview" "block"
+    Then I should see "Course 1" in the "Course overview" "block"
+    And I should see "0%" in the "Course overview" "block"
+    And I am on "Course 1" course homepage
+    And I follow "Test choice 1"
+    And I follow "Dashboard" in the user menu
+    And I click on "Timeline" "link" in the "Course overview" "block"
+    And I click on "Sort by courses" "link" in the "Course overview" "block"
+    And I should see "100%" in the "Course overview" "block"
+    And I click on "Courses" "link" in the "Course overview" "block"
+    And I click on "In progress" "link" in the "Course overview" "block"
+    And I should see "Course 1" in the "Course overview" "block"
+    And I should see "100%" in the "Course overview" "block"
+    And I log out
diff --git a/myoverview/tests/privacy_test.php b/myoverview/tests/privacy_test.php
new file mode 100644
index 0000000..875dd03
--- /dev/null
+++ b/myoverview/tests/privacy_test.php
@@ -0,0 +1,80 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Unit tests for the block_myoverview implementation of the privacy API.
+ *
+ * @package    block_myoverview
+ * @category   test
+ * @copyright  2018 Adrian Greeve <adriangreeve.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+use \core_privacy\local\request\writer;
+use \block_myoverview\privacy\provider;
+
+/**
+ * Unit tests for the block_myoverview implementation of the privacy API.
+ *
+ * @copyright  2018 Adrian Greeve <adriangreeve.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_myoverview_privacy_testcase extends \core_privacy\tests\provider_testcase {
+
+    /**
+     * Ensure that export_user_preferences returns no data if the user has not visited the myoverview block.
+     */
+    public function test_export_user_preferences_no_pref() {
+        $this->resetAfterTest();
+
+        $user = $this->getDataGenerator()->create_user();
+        provider::export_user_preferences($user->id);
+        $writer = writer::with_context(\context_system::instance());
+        $this->assertFalse($writer->has_any_data());
+    }
+
+    /**
+     * Test that the preference courses is exported properly.
+     */
+    public function test_export_user_preferences_course_preference() {
+        $this->resetAfterTest();
+
+        $user = $this->getDataGenerator()->create_user();
+        set_user_preference('block_myoverview_last_tab', 'courses', $user);
+
+        provider::export_user_preferences($user->id);
+        $writer = writer::with_context(\context_system::instance());
+        $blockpreferences = $writer->get_user_preferences('block_myoverview');
+        $this->assertEquals('courses', $blockpreferences->block_myoverview_last_tab->value);
+    }
+
+    /**
+     * Test that the preference timeline is exported properly.
+     */
+    public function test_export_user_preferences_timeline_preference() {
+        $this->resetAfterTest();
+
+        $user = $this->getDataGenerator()->create_user();
+        set_user_preference('block_myoverview_last_tab', 'timeline', $user);
+
+        provider::export_user_preferences($user->id);
+        $writer = writer::with_context(\context_system::instance());
+        $blockpreferences = $writer->get_user_preferences('block_myoverview');
+        $this->assertEquals('timeline', $blockpreferences->block_myoverview_last_tab->value);
+    }
+}
diff --git a/myoverview/version.php b/myoverview/version.php
new file mode 100644
index 0000000..26ccc6d
--- /dev/null
+++ b/myoverview/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details for the My overview block.
+ *
+ * @package    block_myoverview
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;         // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800;         // Requires this Moodle version.
+$plugin->component = 'block_myoverview'; // Full name of the plugin (used for diagnostics).
diff --git a/myprofile/block_myprofile.php b/myprofile/block_myprofile.php
new file mode 100644
index 0000000..b596f15
--- /dev/null
+++ b/myprofile/block_myprofile.php
@@ -0,0 +1,238 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Block displaying information about current logged-in user.
+ *
+ * This block can be used as anti cheating measure, you
+ * can easily check the logged-in user matches the person
+ * operating the computer.
+ *
+ * @package    block_myprofile
+ * @copyright  2010 Remote-Learner.net
+ * @author     Olav Jordan <olav.jordan@remote-learner.ca>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Displays the current user's profile information.
+ *
+ * @copyright  2010 Remote-Learner.net
+ * @author     Olav Jordan <olav.jordan@remote-learner.ca>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_myprofile extends block_base {
+    /**
+     * block initializations
+     */
+    public function init() {
+        $this->title   = get_string('pluginname', 'block_myprofile');
+    }
+
+    /**
+     * block contents
+     *
+     * @return object
+     */
+    public function get_content() {
+        global $CFG, $USER, $DB, $OUTPUT, $PAGE;
+
+        if ($this->content !== NULL) {
+            return $this->content;
+        }
+
+        if (!isloggedin() or isguestuser()) {
+            return '';      // Never useful unless you are logged in as real users
+        }
+
+        $this->content = new stdClass;
+        $this->content->text = '';
+        $this->content->footer = '';
+
+        $course = $this->page->course;
+
+        if (!isset($this->config->display_picture) || $this->config->display_picture == 1) {
+            $this->content->text .= '<div class="myprofileitem picture">';
+            $this->content->text .= $OUTPUT->user_picture($USER, array('courseid'=>$course->id, 'size'=>'100', 'class'=>'profilepicture'));  // The new class makes CSS easier
+            $this->content->text .= '</div>';
+        }
+
+        $this->content->text .= '<div class="myprofileitem fullname">'.fullname($USER).'</div>';
+
+        if(!isset($this->config->display_country) || $this->config->display_country == 1) {
+            $countries = get_string_manager()->get_list_of_countries(true);
+            if (isset($countries[$USER->country])) {
+                $this->content->text .= '<div class="myprofileitem country">';
+                $this->content->text .= get_string('country') . ': ' . $countries[$USER->country];
+                $this->content->text .= '</div>';
+            }
+        }
+
+        if(!isset($this->config->display_city) || $this->config->display_city == 1) {
+            $this->content->text .= '<div class="myprofileitem city">';
+            $this->content->text .= get_string('city') . ': ' . format_string($USER->city);
+            $this->content->text .= '</div>';
+        }
+
+        if(!isset($this->config->display_email) || $this->config->display_email == 1) {
+            $this->content->text .= '<div class="myprofileitem email">';
+            $this->content->text .= obfuscate_mailto($USER->email, '');
+            $this->content->text .= '</div>';
+        }
+
+        if(!empty($this->config->display_icq) && !empty($USER->icq)) {
+            $this->content->text .= '<div class="myprofileitem icq">';
+            $this->content->text .= 'ICQ: ' . s($USER->icq);
+            $this->content->text .= '</div>';
+        }
+
+        if(!empty($this->config->display_skype) && !empty($USER->skype)) {
+            $this->content->text .= '<div class="myprofileitem skype">';
+            $this->content->text .= 'Skype: ' . s($USER->skype);
+            $this->content->text .= '</div>';
+        }
+
+        if(!empty($this->config->display_yahoo) && !empty($USER->yahoo)) {
+            $this->content->text .= '<div class="myprofileitem yahoo">';
+            $this->content->text .= 'Yahoo: ' . s($USER->yahoo);
+            $this->content->text .= '</div>';
+        }
+
+        if(!empty($this->config->display_aim) && !empty($USER->aim)) {
+            $this->content->text .= '<div class="myprofileitem aim">';
+            $this->content->text .= 'AIM: ' . s($USER->aim);
+            $this->content->text .= '</div>';
+        }
+
+        if(!empty($this->config->display_msn) && !empty($USER->msn)) {
+            $this->content->text .= '<div class="myprofileitem msn">';
+            $this->content->text .= 'MSN: ' . s($USER->msn);
+            $this->content->text .= '</div>';
+        }
+
+        if(!empty($this->config->display_phone1) && !empty($USER->phone1)) {
+            $this->content->text .= '<div class="myprofileitem phone1">';
+            $this->content->text .= get_string('phone1').': ' . s($USER->phone1);
+            $this->content->text .= '</div>';
+        }
+
+        if(!empty($this->config->display_phone2) && !empty($USER->phone2)) {
+            $this->content->text .= '<div class="myprofileitem phone2">';
+            $this->content->text .= get_string('phone2').': ' . s($USER->phone2);
+            $this->content->text .= '</div>';
+        }
+
+        if(!empty($this->config->display_institution) && !empty($USER->institution)) {
+            $this->content->text .= '<div class="myprofileitem institution">';
+            $this->content->text .= format_string($USER->institution);
+            $this->content->text .= '</div>';
+        }
+
+        if(!empty($this->config->display_address) && !empty($USER->address)) {
+            $this->content->text .= '<div class="myprofileitem address">';
+            $this->content->text .= format_string($USER->address);
+            $this->content->text .= '</div>';
+        }
+
+        if(!empty($this->config->display_firstaccess) && !empty($USER->firstaccess)) {
+            $this->content->text .= '<div class="myprofileitem firstaccess">';
+            $this->content->text .= get_string('firstaccess').': ' . userdate($USER->firstaccess);
+            $this->content->text .= '</div>';
+        }
+
+        if(!empty($this->config->display_lastaccess) && !empty($USER->lastaccess)) {
+            $this->content->text .= '<div class="myprofileitem lastaccess">';
+            $this->content->text .= get_string('lastaccess').': ' . userdate($USER->lastaccess);
+            $this->content->text .= '</div>';
+        }
+
+        if(!empty($this->config->display_currentlogin) && !empty($USER->currentlogin)) {
+            $this->content->text .= '<div class="myprofileitem currentlogin">';
+            $this->content->text .= get_string('login').': ' . userdate($USER->currentlogin);
+            $this->content->text .= '</div>';
+        }
+
+        if(!empty($this->config->display_lastip) && !empty($USER->lastip)) {
+            $this->content->text .= '<div class="myprofileitem lastip">';
+            $this->content->text .= 'IP: ' . $USER->lastip;
+            $this->content->text .= '</div>';
+        }
+
+        return $this->content;
+    }
+
+    /**
+     * allow the block to have a configuration page
+     *
+     * @return boolean
+     */
+    public function has_config() {
+        return false;
+    }
+
+    /**
+     * allow more than one instance of the block on a page
+     *
+     * @return boolean
+     */
+    public function instance_allow_multiple() {
+        //allow more than one instance on a page
+        return false;
+    }
+
+    /**
+     * allow instances to have their own configuration
+     *
+     * @return boolean
+     */
+    function instance_allow_config() {
+        //allow instances to have their own configuration
+        return false;
+    }
+
+    /**
+     * instance specialisations (must have instance allow config true)
+     *
+     */
+    public function specialization() {
+    }
+
+    /**
+     * locations where block can be displayed
+     *
+     * @return array
+     */
+    public function applicable_formats() {
+        return array('all'=>true);
+    }
+
+    /**
+     * post install configurations
+     *
+     */
+    public function after_install() {
+    }
+
+    /**
+     * post delete configurations
+     *
+     */
+    public function before_delete() {
+    }
+
+}
diff --git a/myprofile/classes/privacy/provider.php b/myprofile/classes/privacy/provider.php
new file mode 100644
index 0000000..160c186
--- /dev/null
+++ b/myprofile/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_myprofile.
+ *
+ * @package    block_myprofile
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_myprofile\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_myprofile implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/myprofile/db/access.php b/myprofile/db/access.php
new file mode 100644
index 0000000..328a6f0
--- /dev/null
+++ b/myprofile/db/access.php
@@ -0,0 +1,51 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * My profile block caps.
+ *
+ * @package    block_myprofile
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/myprofile:myaddinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/my:manageblocks'
+    ),
+
+    'block/myprofile:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/myprofile/edit_form.php b/myprofile/edit_form.php
new file mode 100644
index 0000000..0302647
--- /dev/null
+++ b/myprofile/edit_form.php
@@ -0,0 +1,151 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Form for editing profile block settings
+ *
+ * @package    block_myprofile
+ * @copyright  2010 Remote-Learner.net
+ * @author     Olav Jordan <olav.jordan@remote-learner.ca>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_myprofile_edit_form extends block_edit_form {
+    protected function specific_definition($mform) {
+        global $CFG;
+        $mform->addElement('header', 'configheader', get_string('myprofile_settings', 'block_myprofile'));
+
+        $mform->addElement('selectyesno', 'config_display_picture', get_string('display_picture', 'block_myprofile'));
+        if (isset($this->block->config->display_picture)) {
+            $mform->setDefault('config_display_picture', $this->block->config->display_picture);
+        } else {
+            $mform->setDefault('config_display_picture', '1');
+        }
+
+        $mform->addElement('selectyesno', 'config_display_country', get_string('display_country', 'block_myprofile'));
+        if (isset($this->block->config->display_country)) {
+            $mform->setDefault('config_display_country', $this->block->config->display_country);
+        } else {
+            $mform->setDefault('config_display_country', '1');
+        }
+
+        $mform->addElement('selectyesno', 'config_display_city', get_string('display_city', 'block_myprofile'));
+        if (isset($this->block->config->display_city)) {
+            $mform->setDefault('config_display_city', $this->block->config->display_city);
+        } else {
+            $mform->setDefault('config_display_city', '1');
+        }
+
+        $mform->addElement('selectyesno', 'config_display_email', get_string('display_email', 'block_myprofile'));
+        if (isset($this->block->config->display_email)) {
+            $mform->setDefault('config_display_email', $this->block->config->display_email);
+        } else {
+            $mform->setDefault('config_display_email', '1');
+        }
+
+        $mform->addElement('selectyesno', 'config_display_icq', get_string('display_icq', 'block_myprofile'));
+        if (isset($this->block->config->display_icq)) {
+            $mform->setDefault('config_display_icq', $this->block->config->display_icq);
+        } else {
+            $mform->setDefault('config_display_icq', '0');
+        }
+
+        $mform->addElement('selectyesno', 'config_display_skype', get_string('display_skype', 'block_myprofile'));
+        if (isset($this->block->config->display_skype)) {
+            $mform->setDefault('config_display_skype', $this->block->config->display_skype);
+        } else {
+            $mform->setDefault('config_display_skype', '0');
+        }
+
+        $mform->addElement('selectyesno', 'config_display_yahoo', get_string('display_yahoo', 'block_myprofile'));
+        if (isset($this->block->config->display_yahoo)) {
+            $mform->setDefault('config_display_yahoo', $this->block->config->display_yahoo);
+        } else {
+            $mform->setDefault('config_display_yahoo', '0');
+        }
+
+        $mform->addElement('selectyesno', 'config_display_aim', get_string('display_aim', 'block_myprofile'));
+        if (isset($this->block->config->display_aim)) {
+            $mform->setDefault('config_display_aim', $this->block->config->display_aim);
+        } else {
+            $mform->setDefault('config_display_aim', '0');
+        }
+
+        $mform->addElement('selectyesno', 'config_display_msn', get_string('display_msn', 'block_myprofile'));
+        if (isset($this->block->config->display_msn)) {
+            $mform->setDefault('config_display_msn', $this->block->config->display_msn);
+        } else {
+            $mform->setDefault('config_display_msn', '0');
+        }
+
+        $mform->addElement('selectyesno', 'config_display_phone1', get_string('display_phone1', 'block_myprofile'));
+        if (isset($this->block->config->display_phone1)) {
+            $mform->setDefault('config_display_phone1', $this->block->config->display_phone1);
+        } else {
+            $mform->setDefault('config_display_phone1', '0');
+        }
+
+        $mform->addElement('selectyesno', 'config_display_phone2', get_string('display_phone2', 'block_myprofile'));
+        if (isset($this->block->config->display_phone2)) {
+            $mform->setDefault('config_display_phone2', $this->block->config->display_phone2);
+        } else {
+            $mform->setDefault('config_display_phone2', '0');
+        }
+
+        $mform->addElement('selectyesno', 'config_display_institution', get_string('display_institution', 'block_myprofile'));
+        if (isset($this->block->config->display_institution)) {
+            $mform->setDefault('config_display_institution', $this->block->config->display_institution);
+        } else {
+            $mform->setDefault('config_display_institution', '0');
+        }
+
+        $mform->addElement('selectyesno', 'config_display_address', get_string('display_address', 'block_myprofile'));
+        if (isset($this->block->config->display_address)) {
+            $mform->setDefault('config_display_address', $this->block->config->display_address);
+        } else {
+            $mform->setDefault('config_display_address', '0');
+        }
+
+        $mform->addElement('selectyesno', 'config_display_firstaccess', get_string('display_firstaccess', 'block_myprofile'));
+        if (isset($this->block->config->display_firstaccess)) {
+            $mform->setDefault('config_display_firstaccess', $this->block->config->display_firstaccess);
+        } else {
+            $mform->setDefault('config_display_firstaccess', '0');
+        }
+
+        $mform->addElement('selectyesno', 'config_display_lastaccess', get_string('display_lastaccess', 'block_myprofile'));
+        if (isset($this->block->config->display_lastaccess)) {
+            $mform->setDefault('config_display_lastaccess', $this->block->config->display_lastaccess);
+        } else {
+            $mform->setDefault('config_display_lastaccess', '0');
+        }
+
+        $mform->addElement('selectyesno', 'config_display_currentlogin', get_string('display_currentlogin', 'block_myprofile'));
+        if (isset($this->block->config->display_currentlogin)) {
+            $mform->setDefault('config_display_currentlogin', $this->block->config->display_currentlogin);
+        } else {
+            $mform->setDefault('config_display_currentlogin', '0');
+        }
+
+        $mform->addElement('selectyesno', 'config_display_lastip', get_string('display_lastip', 'block_myprofile'));
+        if (isset($this->block->config->display_lastip)) {
+            $mform->setDefault('config_display_lastip', $this->block->config->display_lastip);
+        } else {
+            $mform->setDefault('config_display_lastip', '0');
+        }
+    }
+}
\ No newline at end of file
diff --git a/myprofile/lang/en/block_myprofile.php b/myprofile/lang/en/block_myprofile.php
new file mode 100644
index 0000000..b7de027
--- /dev/null
+++ b/myprofile/lang/en/block_myprofile.php
@@ -0,0 +1,51 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_myprofile', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package    block_myprofile
+ * @copyright  2010 Remote-Learner.net
+ * @author     Olav Jordan <olav.jordan@remote-learner.ca>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['contentsettings'] = 'Display settings for content region';
+$string['display_picture'] = 'Display picture';
+$string['display_country'] = 'Display country';
+$string['display_city'] = 'Display city';
+$string['display_email'] = 'Display email';
+$string['display_icq'] = 'Display ICQ';
+$string['display_skype'] = 'Display Skype';
+$string['display_yahoo'] = 'Display Yahoo';
+$string['display_aim'] = 'Display AIM';
+$string['display_msn'] = 'Display MSN';
+$string['display_phone1'] = 'Display phone';
+$string['display_phone2'] = 'Display mobile phone';
+$string['display_institution'] = 'Display institution';
+$string['display_address'] = 'Display address';
+$string['display_firstaccess'] = 'Display first access';
+$string['display_lastaccess'] = 'Display last access';
+$string['display_currentlogin'] = 'Display current login';
+$string['display_lastip'] = 'Display last IP';
+$string['myprofile:addinstance'] = 'Add a new logged in user block';
+$string['myprofile:myaddinstance'] = 'Add a new logged in user block to Dashboard';
+$string['myprofile_settings'] = 'Visible user information';
+$string['pluginname'] = 'Logged in user';
+$string['privacy:metadata'] = 'The Logged in user block only shows information about the logged in user and does not store data itself.';
+
+// Deprecated since Moodle 3.2.
+$string['display_un'] = 'Display name';
diff --git a/myprofile/lang/en/deprecated.txt b/myprofile/lang/en/deprecated.txt
new file mode 100644
index 0000000..e79d781
--- /dev/null
+++ b/myprofile/lang/en/deprecated.txt
@@ -0,0 +1 @@
+display_un,block_myprofile
diff --git a/myprofile/styles.css b/myprofile/styles.css
new file mode 100644
index 0000000..ee3944e
--- /dev/null
+++ b/myprofile/styles.css
@@ -0,0 +1,14 @@
+.block_myprofile img.profilepicture {
+    height: 100px;
+    width: 100px;
+}
+
+.block_myprofile .myprofileitem.fullname {
+    font-size: 1.5em;
+    font-weight: bold;
+}
+
+.block_myprofile .myprofileitem.edit {
+    text-align: right;
+}
+
diff --git a/myprofile/tests/behat/block_myprofile.feature b/myprofile/tests/behat/block_myprofile.feature
new file mode 100644
index 0000000..8bd076c
--- /dev/null
+++ b/myprofile/tests/behat/block_myprofile.feature
@@ -0,0 +1,309 @@
+@block @block_myprofile
+Feature: The logged in user block allows users to view their profile information
+  In order to enable the logged in user block
+  As a user
+  I can add the logged in user block and configure it to show my information
+
+  Scenario: Configure the logged in user block to show / hide the users country
+    Given the following "users" exist:
+      | username | firstname | lastname | email                | country   |
+      | teacher1 | Teacher   | One      | teacher1@example.com | AU        |
+    And I log in as "teacher1"
+    And I press "Customise this page"
+    When I add the "Logged in user" block
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display country       | No |
+    And I press "Save changes"
+    Then I should see "Teacher One" in the "Logged in user" "block"
+    And I should not see "Australia" in the "Logged in user" "block"
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display country | Yes |
+    And I press "Save changes"
+    And I should see "Australia" in the "Logged in user" "block"
+
+  Scenario: Configure the logged in user block to show / hide the users city
+    Given the following "users" exist:
+      | username | firstname | lastname | email                | city  |
+      | teacher1 | Teacher   | One      | teacher1@example.com | Perth |
+    And I log in as "teacher1"
+    And I press "Customise this page"
+    When I add the "Logged in user" block
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display city          | No |
+    And I press "Save changes"
+    Then I should see "Teacher One" in the "Logged in user" "block"
+    And I should not see "Perth" in the "Logged in user" "block"
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display city | Yes |
+    And I press "Save changes"
+    And I should see "Perth" in the "Logged in user" "block"
+
+  Scenario: Configure the logged in user block to show / hide the users email
+    Given the following "users" exist:
+      | username | firstname | lastname | email                |
+      | teacher1 | Teacher   | One      | teacher1@example.com |
+    And I log in as "teacher1"
+    And I press "Customise this page"
+    When I add the "Logged in user" block
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display email         | No |
+    And I press "Save changes"
+    Then I should see "Teacher One" in the "Logged in user" "block"
+    And I should not see "teacher1@example.com" in the "Logged in user" "block"
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display email | Yes |
+    And I press "Save changes"
+    And I should see "teacher1@example.com" in the "Logged in user" "block"
+
+  Scenario: Configure the logged in user block to show / hide the users ICQ
+    Given the following "users" exist:
+      | username | firstname | lastname | email                | icq   |
+      | teacher1 | Teacher   | One      | teacher1@example.com | myicq |
+    And I log in as "teacher1"
+    And I press "Customise this page"
+    When I add the "Logged in user" block
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display ICQ           | No |
+    And I press "Save changes"
+    Then I should see "Teacher One" in the "Logged in user" "block"
+    And I should not see "myicq" in the "Logged in user" "block"
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display ICQ | Yes |
+    And I press "Save changes"
+    And I should see "myicq" in the "Logged in user" "block"
+
+  Scenario: Configure the logged in user block to show / hide the users Skype
+    Given the following "users" exist:
+      | username | firstname | lastname | email                | skype   |
+      | teacher1 | Teacher   | One      | teacher1@example.com | myskype |
+    And I log in as "teacher1"
+    And I press "Customise this page"
+    When I add the "Logged in user" block
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display Skype         | No |
+    And I press "Save changes"
+    Then I should see "Teacher One" in the "Logged in user" "block"
+    And I should not see "myskype" in the "Logged in user" "block"
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display Skype | Yes |
+    And I press "Save changes"
+    And I should see "myskype" in the "Logged in user" "block"
+
+  Scenario: Configure the logged in user block to show / hide the users Yahoo
+    Given the following "users" exist:
+      | username | firstname | lastname | email                | yahoo   |
+      | teacher1 | Teacher   | One      | teacher1@example.com | myyahoo |
+    And I log in as "teacher1"
+    And I press "Customise this page"
+    When I add the "Logged in user" block
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display Yahoo         | No |
+    And I press "Save changes"
+    Then I should see "Teacher One" in the "Logged in user" "block"
+    And I should not see "myyahoo" in the "Logged in user" "block"
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display Yahoo | Yes |
+    And I press "Save changes"
+    And I should see "myyahoo" in the "Logged in user" "block"
+
+  Scenario: Configure the logged in user block to show / hide the users AIM
+    Given the following "users" exist:
+      | username | firstname | lastname | email                | aim   |
+      | teacher1 | Teacher   | One      | teacher1@example.com | myaim |
+    And I log in as "teacher1"
+    And I press "Customise this page"
+    When I add the "Logged in user" block
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display AIM           | No |
+    And I press "Save changes"
+    Then I should see "Teacher One" in the "Logged in user" "block"
+    And I should not see "myaim" in the "Logged in user" "block"
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display AIM | Yes |
+    And I press "Save changes"
+    And I should see "myaim" in the "Logged in user" "block"
+
+  Scenario: Configure the logged in user block to show / hide the users MSN
+    Given the following "users" exist:
+      | username | firstname | lastname | email                | msn   |
+      | teacher1 | Teacher   | One      | teacher1@example.com | mymsn |
+    And I log in as "teacher1"
+    And I press "Customise this page"
+    When I add the "Logged in user" block
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display MSN           | No |
+    And I press "Save changes"
+    Then I should see "Teacher One" in the "Logged in user" "block"
+    And I should not see "mymsn" in the "Logged in user" "block"
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display MSN | Yes |
+    And I press "Save changes"
+    And I should see "mymsn" in the "Logged in user" "block"
+
+  Scenario: Configure the logged in user block to show / hide the users phone
+    Given the following "users" exist:
+      | username | firstname | lastname | email                | phone1   |
+      | teacher1 | Teacher   | One      | teacher1@example.com | 555-5555 |
+    And I log in as "teacher1"
+    And I press "Customise this page"
+    When I add the "Logged in user" block
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display phone         | No |
+    And I press "Save changes"
+    Then I should see "Teacher One" in the "Logged in user" "block"
+    And I should not see "555-5555" in the "Logged in user" "block"
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display phone | Yes |
+    And I press "Save changes"
+    And I should see "555-5555" in the "Logged in user" "block"
+
+  Scenario: Configure the logged in user block to show / hide the users mobile phone
+    Given the following "users" exist:
+      | username | firstname | lastname | email                | phone2   |
+      | teacher1 | Teacher   | One      | teacher1@example.com | 555-5555 |
+    And I log in as "teacher1"
+    And I press "Customise this page"
+    When I add the "Logged in user" block
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display mobile phone | No |
+    And I press "Save changes"
+    Then I should see "Teacher One" in the "Logged in user" "block"
+    And I should not see "555-5555" in the "Logged in user" "block"
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display mobile phone | Yes |
+    And I press "Save changes"
+    And I should see "555-5555" in the "Logged in user" "block"
+
+  Scenario: Configure the logged in user block to show / hide the users Institution
+    Given the following "users" exist:
+      | username | firstname | lastname | email                | institution   |
+      | teacher1 | Teacher   | One      | teacher1@example.com | myinstitution |
+    And I log in as "teacher1"
+    And I press "Customise this page"
+    When I add the "Logged in user" block
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display institution | No |
+    And I press "Save changes"
+    Then I should see "Teacher One" in the "Logged in user" "block"
+    And I should not see "myinstitution" in the "Logged in user" "block"
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display institution | Yes |
+    And I press "Save changes"
+    And I should see "myinstitution" in the "Logged in user" "block"
+
+  Scenario: Configure the logged in user block to show / hide the users address
+    Given the following "users" exist:
+      | username | firstname | lastname | email                | address   |
+      | teacher1 | Teacher   | One      | teacher1@example.com | myaddress |
+    And I log in as "teacher1"
+    And I press "Customise this page"
+    When I add the "Logged in user" block
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display address | No |
+    And I press "Save changes"
+    Then I should see "Teacher One" in the "Logged in user" "block"
+    And I should not see "myaddress" in the "Logged in user" "block"
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display address | Yes |
+    And I press "Save changes"
+    And I should see "myaddress" in the "Logged in user" "block"
+
+  Scenario: Configure the logged in user block to show / hide the users first access
+    Given the following "users" exist:
+      | username | firstname | lastname | email                |
+      | teacher1 | Teacher   | One      | teacher1@example.com |
+    And I log in as "teacher1"
+    And I press "Customise this page"
+    When I add the "Logged in user" block
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display first access | No |
+    And I press "Save changes"
+    Then I should see "Teacher One" in the "Logged in user" "block"
+    And I should not see "First access:" in the "Logged in user" "block"
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display first access | Yes |
+    And I press "Save changes"
+    And I should see "First access:" in the "Logged in user" "block"
+
+  Scenario: Configure the logged in user block to show / hide the users last access
+    Given the following "users" exist:
+      | username | firstname | lastname | email                |
+      | teacher1 | Teacher   | One      | teacher1@example.com |
+    And I log in as "teacher1"
+    And I press "Customise this page"
+    When I add the "Logged in user" block
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display last access | No |
+    And I press "Save changes"
+    Then I should see "Teacher One" in the "Logged in user" "block"
+    And I should not see "Last access:" in the "Logged in user" "block"
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display last access | Yes |
+    And I press "Save changes"
+    And I should see "Last access:" in the "Logged in user" "block"
+
+  Scenario: Configure the logged in user block to show / hide the users current login
+    Given the following "users" exist:
+      | username | firstname | lastname | email                |
+      | teacher1 | Teacher   | One      | teacher1@example.com |
+    And I log in as "teacher1"
+    And I press "Customise this page"
+    When I add the "Logged in user" block
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display current login | No |
+    And I press "Save changes"
+    Then I should see "Teacher One" in the "Logged in user" "block"
+    And I should not see "Log in:" in the "Logged in user" "block"
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display current login | Yes |
+    And I press "Save changes"
+    And I should see "Log in:" in the "Logged in user" "block"
+
+  Scenario: Configure the logged in user block to show / hide the users last ip
+    Given the following "users" exist:
+      | username | firstname | lastname | email                |
+      | teacher1 | Teacher   | One      | teacher1@example.com |
+    And I log in as "teacher1"
+    And I press "Customise this page"
+    When I add the "Logged in user" block
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display last IP | No |
+    And I press "Save changes"
+    Then I should see "Teacher One" in the "Logged in user" "block"
+    And I should not see "IP:" in the "Logged in user" "block"
+    And I configure the "Logged in user" block
+    And I set the following fields to these values:
+      | Display last IP | Yes |
+    And I press "Save changes"
+    And I should see "IP:" in the "Logged in user" "block"
diff --git a/myprofile/tests/behat/block_myprofile_activity.feature b/myprofile/tests/behat/block_myprofile_activity.feature
new file mode 100644
index 0000000..bc0f704
--- /dev/null
+++ b/myprofile/tests/behat/block_myprofile_activity.feature
@@ -0,0 +1,24 @@
+@block @block_myprofile
+Feature: The logged in user block allows users to view their profile information in an activity
+  In order to enable the logged in user block in an activity
+  As a teacher
+  I can add the logged in user block to an activity and view my information
+
+  Scenario: View the logged in user block by a user in an activity
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | One | teacher1@example.com | T1 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+    And the following "activities" exist:
+      | activity | course | idnumber | name           | intro                 |
+      | page     | C1     | page1    | Test page name | Test page description |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I follow "Test page name"
+    When I add the "Logged in user" block
+    Then I should see "Teacher One" in the "Logged in user" "block"
diff --git a/myprofile/tests/behat/block_myprofile_course.feature b/myprofile/tests/behat/block_myprofile_course.feature
new file mode 100644
index 0000000..c0aa2db
--- /dev/null
+++ b/myprofile/tests/behat/block_myprofile_course.feature
@@ -0,0 +1,20 @@
+@block @block_myprofile
+Feature: The logged in user block allows users to view their profile information in a course
+  In order to enable the logged in user block in a course
+  As a teacher
+  I can add the logged in user block to a course and view my information
+
+  Scenario: View the logged in user block by a user in a course
+    Given the following "users" exist:
+      | username | firstname | lastname | email                | idnumber |
+      | teacher1 | Teacher   | One      | teacher1@example.com | T1       |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+    When I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Logged in user" block
+    Then I should see "Teacher One" in the "Logged in user" "block"
diff --git a/myprofile/tests/behat/block_myprofile_dashboard.feature b/myprofile/tests/behat/block_myprofile_dashboard.feature
new file mode 100644
index 0000000..e130522
--- /dev/null
+++ b/myprofile/tests/behat/block_myprofile_dashboard.feature
@@ -0,0 +1,14 @@
+@block @block_myprofile
+Feature: The logged in user block allows users to view their profile information in on the dashboard
+  In order to enable the logged in user block on the dashboard
+  As a user
+  I can add the logged in user block to a the dashboard and view my information
+
+  Scenario: View the logged in user block by a user on the dashboard
+    Given the following "users" exist:
+      | username | firstname | lastname | email                |
+      | teacher1 | Teacher   | One      | teacher1@example.com |
+    And I log in as "teacher1"
+    And I press "Customise this page"
+    When I add the "Logged in user" block
+    Then I should see "Teacher One" in the "Logged in user" "block"
diff --git a/myprofile/tests/behat/block_myprofile_frontpage.feature b/myprofile/tests/behat/block_myprofile_frontpage.feature
new file mode 100644
index 0000000..5b14df3
--- /dev/null
+++ b/myprofile/tests/behat/block_myprofile_frontpage.feature
@@ -0,0 +1,25 @@
+@block @block_myprofile
+Feature: The logged in user block allows users to view their profile information on the front page
+  In order to enable the logged in user block on the frontpage
+  As an admin
+  I can add the logged in user block to the frontpage and view my information
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email                | idnumber |
+      | teacher1 | Teacher   | One      | teacher1@example.com | T1       |
+    And I log in as "admin"
+    And I am on site homepage
+    And I navigate to "Turn editing on" node in "Front page settings"
+    And I add the "Logged in user" block
+    And I log out
+
+  Scenario: Try to view the logged in user block as a guest
+    Given I log in as "guest"
+    When I am on site homepage
+    Then I should not see "Logged in user"
+
+  Scenario: View the logged in user block by a logged in user
+    Given I log in as "teacher1"
+    When I am on site homepage
+    Then I should see "Teacher One" in the "Logged in user" "block"
diff --git a/myprofile/version.php b/myprofile/version.php
new file mode 100644
index 0000000..09d06a2
--- /dev/null
+++ b/myprofile/version.php
@@ -0,0 +1,30 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Current user info block.
+ *
+ * @package    block_myprofile
+ * @copyright  2010 Remote-Learner.net
+ * @author     Olav Jordan <olav.jordan@remote-learner.ca>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_myprofile'; // Full name of the plugin (used for diagnostics)
diff --git a/navigation/amd/build/ajax_response_renderer.min.js b/navigation/amd/build/ajax_response_renderer.min.js
new file mode 100644
index 0000000..02578ec
--- /dev/null
+++ b/navigation/amd/build/ajax_response_renderer.min.js
@@ -0,0 +1 @@
+define(["jquery","core/templates","core/notification","core/url"],function(a,b,c,d){function e(g,h){var i=a("<ul></ul>");i.attr("role","group"),i.attr("aria-hidden",!0),a.each(h,function(g,h){if("object"==typeof h){var j=a("<li></li>"),k=a("<p></p>"),l=h.id||h.key+"_tree_item",m=null,n=!(!h.expandable&&!h.haschildren);k.addClass("tree_item"),k.attr("id",l),k.attr("role","treeitem"),k.attr("tabindex","-1"),h.requiresajaxloading&&(k.attr("data-requires-ajax",!0),k.attr("data-node-id",h.id),k.attr("data-node-key",h.key),k.attr("data-node-type",h.type)),n&&(j.addClass("collapsed contains_branch"),k.attr("aria-expanded",!1),k.addClass("branch"));var o=null;if(h.link){var p=a('<a title="'+h.title+'" href="'+h.link+'"></a>');o=p,p.append('<span class="item-content-wrap">'+h.name+"</span>"),h.hidden&&p.addClass("dimmed"),k.append(p)}else{var q=a("<span></span>");o=q,q.append('<span class="item-content-wrap">'+h.name+"</span>"),h.hidden&&q.addClass("dimmed"),k.append(q)}!h.icon||n&&h.type!==f.ACTIVITY&&h.type!==f.RESOURCE||(j.addClass("item_with_icon"),k.addClass("hasicon"),h.type===f.ACTIVITY||h.type===f.RESOURCE?(m=a("<img/>"),m.attr("alt",h.icon.alt),m.attr("title",h.icon.title),m.attr("src",d.imageUrl(h.icon.pix,h.icon.component)),a.each(h.icon.classes,function(a,b){m.addClass(b)}),o.prepend(m)):("moodle"==h.icon.component&&(h.icon.component="core"),b.renderPix(h.icon.pix,h.icon.component,h.icon.title).then(function(a){o.prepend(a)})["catch"](c.exception))),j.append(k),i.append(j),h.children&&h.children.length?e(k,h.children):n&&!h.requiresajaxloading&&(j.removeClass("contains_branch"),k.addClass("emptybranch"))}}),g.parent().append(i);var j=g.attr("id")+"_group";i.attr("id",j),g.attr("aria-owns",j),g.attr("role","treeitem")}var f={ACTIVITY:40,RESOURCE:50};return{render:function(a,b){if(b.children&&b.children.length){e(a,b.children);var c=a.children("[role='treeitem']").first(),d=a.find("#"+c.attr("aria-owns"));c.attr("aria-expanded",!0),d.attr("aria-hidden",!1)}else a.parent().hasClass("contains_branch")&&(a.parent().removeClass("contains_branch"),a.addClass("emptybranch"))}}});
\ No newline at end of file
diff --git a/navigation/amd/build/nav_loader.min.js b/navigation/amd/build/nav_loader.min.js
new file mode 100644
index 0000000..183a19f
--- /dev/null
+++ b/navigation/amd/build/nav_loader.min.js
@@ -0,0 +1 @@
+define(["jquery","core/ajax","core/config","block_navigation/ajax_response_renderer"],function(a,b,c,d){function e(a){return a.closest("[data-block]").attr("data-instanceid")}var f=c.wwwroot+"/lib/ajax/getnavbranch.php";return{load:function(b){b=a(b);var g=a.Deferred(),h={elementid:b.attr("data-node-id"),id:b.attr("data-node-key"),type:b.attr("data-node-type"),sesskey:c.sesskey,instance:e(b)},i={type:"POST",dataType:"json",data:h};return a.ajax(f,i).done(function(a){d.render(b,a),g.resolve()}),g}}});
\ No newline at end of file
diff --git a/navigation/amd/build/navblock.min.js b/navigation/amd/build/navblock.min.js
new file mode 100644
index 0000000..2025554
--- /dev/null
+++ b/navigation/amd/build/navblock.min.js
@@ -0,0 +1 @@
+define(["jquery","core/tree"],function(a,b){return{init:function(a){var c=new b(".block_navigation .block_tree");c.finishExpandingGroup=function(c){b.prototype.finishExpandingGroup.call(this,c),Y.use("moodle-core-event",function(){Y.Global.fire(M.core.globalEvents.BLOCK_CONTENT_UPDATED,{instanceid:a})})},c.collapseGroup=function(c){b.prototype.collapseGroup.call(this,c),Y.use("moodle-core-event",function(){Y.Global.fire(M.core.globalEvents.BLOCK_CONTENT_UPDATED,{instanceid:a})})}}}});
\ No newline at end of file
diff --git a/navigation/amd/build/site_admin_loader.min.js b/navigation/amd/build/site_admin_loader.min.js
new file mode 100644
index 0000000..9bd76cb
--- /dev/null
+++ b/navigation/amd/build/site_admin_loader.min.js
@@ -0,0 +1 @@
+define(["jquery","core/ajax","core/config","block_navigation/ajax_response_renderer"],function(a,b,c,d){var e=71,f=c.wwwroot+"/lib/ajax/getsiteadminbranch.php";return{load:function(b){b=a(b);var g=a.Deferred(),h={type:e,sesskey:c.sesskey},i={type:"POST",dataType:"json",data:h};return a.ajax(f,i).done(function(a){d.render(b,a),g.resolve()}),g}}});
\ No newline at end of file
diff --git a/navigation/amd/src/ajax_response_renderer.js b/navigation/amd/src/ajax_response_renderer.js
new file mode 100644
index 0000000..99f2e28
--- /dev/null
+++ b/navigation/amd/src/ajax_response_renderer.js
@@ -0,0 +1,165 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Parse the response from the navblock ajax page and render the correct DOM
+ * structure for the tree from it.
+ *
+ * @module     block_navigation/ajax_response_renderer
+ * @package    core
+ * @copyright  2015 John Okely <john@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+define(['jquery', 'core/templates', 'core/notification', 'core/url'], function($, Templates, Notification, Url) {
+
+    // Mappings for the different types of nodes coming from the navigation.
+    // Copied from lib/navigationlib.php navigation_node constants.
+    var NODETYPE = {
+        // @type int Activity (course module) = 40.
+        ACTIVITY: 40,
+        // @type int Resource (course module = 50.
+        RESOURCE: 50,
+    };
+
+    /**
+     * Build DOM.
+     *
+     * @method buildDOM
+     * @param {Object} rootElement the root element of DOM.
+     * @param {object} nodes jquery object representing the nodes to be build.
+     */
+    function buildDOM(rootElement, nodes) {
+        var ul = $('<ul></ul>');
+        ul.attr('role', 'group');
+        ul.attr('aria-hidden', true);
+
+        $.each(nodes, function(index, node) {
+            if (typeof node !== 'object') {
+                return;
+            }
+
+            var li = $('<li></li>');
+            var p = $('<p></p>');
+            var id = node.id || node.key + '_tree_item';
+            var icon = null;
+            var isBranch = (node.expandable || node.haschildren) ? true : false;
+
+            p.addClass('tree_item');
+            p.attr('id', id);
+            p.attr('role', 'treeitem');
+            // Negative tab index to allow it to receive focus.
+            p.attr('tabindex', '-1');
+
+            if (node.requiresajaxloading) {
+                p.attr('data-requires-ajax', true);
+                p.attr('data-node-id', node.id);
+                p.attr('data-node-key', node.key);
+                p.attr('data-node-type', node.type);
+            }
+
+            if (isBranch) {
+                li.addClass('collapsed contains_branch');
+                p.attr('aria-expanded', false);
+                p.addClass('branch');
+            }
+
+            var eleToAddIcon = null;
+            if (node.link) {
+                var link = $('<a title="' + node.title + '" href="' + node.link + '"></a>');
+
+                eleToAddIcon = link;
+                link.append('<span class="item-content-wrap">' + node.name + '</span>');
+
+                if (node.hidden) {
+                    link.addClass('dimmed');
+                }
+
+                p.append(link);
+            } else {
+                var span = $('<span></span>');
+
+                eleToAddIcon = span;
+                span.append('<span class="item-content-wrap">' + node.name + '</span>');
+
+                if (node.hidden) {
+                    span.addClass('dimmed');
+                }
+
+                p.append(span);
+            }
+
+            if (node.icon && (!isBranch || node.type === NODETYPE.ACTIVITY || node.type === NODETYPE.RESOURCE)) {
+                li.addClass('item_with_icon');
+                p.addClass('hasicon');
+
+                if (node.type === NODETYPE.ACTIVITY || node.type === NODETYPE.RESOURCE) {
+                    icon = $('<img/>');
+                    icon.attr('alt', node.icon.alt);
+                    icon.attr('title', node.icon.title);
+                    icon.attr('src', Url.imageUrl(node.icon.pix, node.icon.component));
+                    $.each(node.icon.classes, function(index, className) {
+                        icon.addClass(className);
+                    });
+                    eleToAddIcon.prepend(icon);
+                } else {
+                    if (node.icon.component == 'moodle') {
+                        node.icon.component = 'core';
+                    }
+                    Templates.renderPix(node.icon.pix, node.icon.component, node.icon.title).then(function(html) {
+                        // Prepend.
+                        eleToAddIcon.prepend(html);
+                        return;
+                    }).catch(Notification.exception);
+                }
+            }
+
+            li.append(p);
+            ul.append(li);
+
+            if (node.children && node.children.length) {
+                buildDOM(p, node.children);
+            } else if (isBranch && !node.requiresajaxloading) {
+                li.removeClass('contains_branch');
+                p.addClass('emptybranch');
+            }
+        });
+
+        rootElement.parent().append(ul);
+        var id = rootElement.attr('id') + '_group';
+        ul.attr('id', id);
+        rootElement.attr('aria-owns', id);
+        rootElement.attr('role', 'treeitem');
+    }
+
+    return {
+        render: function(element, nodes) {
+            // The first element of the response is the existing node so we start with processing the children.
+            if (nodes.children && nodes.children.length) {
+                buildDOM(element, nodes.children);
+
+                var item = element.children("[role='treeitem']").first();
+                var group = element.find('#' + item.attr('aria-owns'));
+
+                item.attr('aria-expanded', true);
+                group.attr('aria-hidden', false);
+            } else {
+                if (element.parent().hasClass('contains_branch')) {
+                    element.parent().removeClass('contains_branch');
+                    element.addClass('emptybranch');
+                }
+            }
+        }
+    };
+});
diff --git a/navigation/amd/src/nav_loader.js b/navigation/amd/src/nav_loader.js
new file mode 100644
index 0000000..ce5cb99
--- /dev/null
+++ b/navigation/amd/src/nav_loader.js
@@ -0,0 +1,64 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Load the nav tree items via ajax and render the response.
+ *
+ * @module     block_navigation/nav_loader
+ * @package    core
+ * @copyright  2015 John Okely <john@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+define(['jquery', 'core/ajax', 'core/config', 'block_navigation/ajax_response_renderer'],
+    function($, ajax, config, renderer) {
+        var URL = config.wwwroot + '/lib/ajax/getnavbranch.php';
+
+        /**
+         * Get the block instance id.
+         *
+         * @function getBlockInstanceId
+         * @param {Element} element
+         * @returns {String} the instance id
+         */
+        function getBlockInstanceId(element) {
+            return element.closest('[data-block]').attr('data-instanceid');
+        }
+
+    return {
+        load: function(element) {
+            element = $(element);
+            var promise = $.Deferred();
+            var data = {
+                elementid: element.attr('data-node-id'),
+                id: element.attr('data-node-key'),
+                type: element.attr('data-node-type'),
+                sesskey: config.sesskey,
+                instance: getBlockInstanceId(element)
+            };
+            var settings = {
+                type: 'POST',
+                dataType: 'json',
+                data: data
+            };
+
+            $.ajax(URL, settings).done(function(nodes) {
+                renderer.render(element, nodes);
+                promise.resolve();
+            });
+
+            return promise;
+        }
+    };
+});
diff --git a/navigation/amd/src/navblock.js b/navigation/amd/src/navblock.js
new file mode 100644
index 0000000..40e8678
--- /dev/null
+++ b/navigation/amd/src/navblock.js
@@ -0,0 +1,46 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Load the navigation tree javascript.
+ *
+ * @module     block_navigation/navblock
+ * @package    core
+ * @copyright  2015 John Okely <john@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+define(['jquery', 'core/tree'], function($, Tree) {
+    return {
+        init: function(instanceid) {
+            var navTree = new Tree(".block_navigation .block_tree");
+            navTree.finishExpandingGroup = function(item) {
+                Tree.prototype.finishExpandingGroup.call(this, item);
+                Y.use('moodle-core-event', function() {
+                    Y.Global.fire(M.core.globalEvents.BLOCK_CONTENT_UPDATED, {
+                        instanceid: instanceid
+                    });
+                });
+            };
+            navTree.collapseGroup = function(item) {
+                Tree.prototype.collapseGroup.call(this, item);
+                Y.use('moodle-core-event', function() {
+                    Y.Global.fire(M.core.globalEvents.BLOCK_CONTENT_UPDATED, {
+                        instanceid: instanceid
+                    });
+                });
+            };
+        }
+    };
+});
diff --git a/navigation/amd/src/site_admin_loader.js b/navigation/amd/src/site_admin_loader.js
new file mode 100644
index 0000000..b203aac
--- /dev/null
+++ b/navigation/amd/src/site_admin_loader.js
@@ -0,0 +1,52 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Load the site admin nav tree via ajax and render the response.
+ *
+ * @module     block_navigation/site_admin_loader
+ * @package    core
+ * @copyright  2015 John Okely <john@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+define(['jquery', 'core/ajax', 'core/config', 'block_navigation/ajax_response_renderer'],
+        function($, ajax, config, renderer) {
+
+    var SITE_ADMIN_NODE_TYPE = 71;
+    var URL = config.wwwroot + '/lib/ajax/getsiteadminbranch.php';
+
+    return {
+        load: function(element) {
+            element = $(element);
+            var promise = $.Deferred();
+            var data = {
+                type: SITE_ADMIN_NODE_TYPE,
+                sesskey: config.sesskey
+            };
+            var settings = {
+                type: 'POST',
+                dataType: 'json',
+                data: data
+            };
+
+            $.ajax(URL, settings).done(function(nodes) {
+                renderer.render(element, nodes);
+                promise.resolve();
+            });
+
+            return promise;
+        }
+    };
+});
diff --git a/navigation/block_navigation.php b/navigation/block_navigation.php
new file mode 100644
index 0000000..e7a5c11
--- /dev/null
+++ b/navigation/block_navigation.php
@@ -0,0 +1,336 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file contains classes used to manage the navigation structures in Moodle
+ * and was introduced as part of the changes occuring in Moodle 2.0
+ *
+ * @since     Moodle 2.0
+ * @package   block_navigation
+ * @copyright 2009 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * The global navigation tree block class
+ *
+ * Used to produce the global navigation block new to Moodle 2.0
+ *
+ * @package   block_navigation
+ * @category  navigation
+ * @copyright 2009 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_navigation extends block_base {
+
+    /** @var int This allows for multiple navigation trees */
+    public static $navcount;
+    /** @var string The name of the block */
+    public $blockname = null;
+    /** @var bool A switch to indicate whether content has been generated or not. */
+    protected $contentgenerated = false;
+    /** @var bool|null variable for checking if the block is docked*/
+    protected $docked = null;
+
+    /** @var int Trim characters from the right */
+    const TRIM_RIGHT = 1;
+    /** @var int Trim characters from the left */
+    const TRIM_LEFT = 2;
+    /** @var int Trim characters from the center */
+    const TRIM_CENTER = 3;
+
+    /**
+     * Set the initial properties for the block
+     */
+    function init() {
+        $this->blockname = get_class($this);
+        $this->title = get_string('pluginname', $this->blockname);
+    }
+
+    /**
+     * All multiple instances of this block
+     * @return bool Returns false
+     */
+    function instance_allow_multiple() {
+        return false;
+    }
+
+    /**
+     * Set the applicable formats for this block to all
+     * @return array
+     */
+    function applicable_formats() {
+        return array('all' => true);
+    }
+
+    /**
+     * Allow the user to configure a block instance
+     * @return bool Returns true
+     */
+    function instance_allow_config() {
+        return true;
+    }
+
+    /**
+     * The navigation block cannot be hidden by default as it is integral to
+     * the navigation of Moodle.
+     *
+     * @return false
+     */
+    function  instance_can_be_hidden() {
+        return false;
+    }
+
+    /**
+     * Find out if an instance can be docked.
+     *
+     * @return bool true or false depending on whether the instance can be docked or not.
+     */
+    function instance_can_be_docked() {
+        return (parent::instance_can_be_docked() && (empty($this->config->enabledock) || $this->config->enabledock=='yes'));
+    }
+
+    /**
+     * Gets Javascript that may be required for navigation
+     */
+    function get_required_javascript() {
+        parent::get_required_javascript();
+        $arguments = array(
+            'instanceid' => $this->instance->id
+        );
+        $this->page->requires->string_for_js('viewallcourses', 'moodle');
+        $this->page->requires->js_call_amd('block_navigation/navblock', 'init', $arguments);
+    }
+
+    /**
+     * Gets the content for this block by grabbing it from $this->page
+     *
+     * @return object $this->content
+     */
+    function get_content() {
+        global $CFG;
+        // First check if we have already generated, don't waste cycles
+        if ($this->contentgenerated === true) {
+            return $this->content;
+        }
+        // JS for navigation moved to the standard theme, the code will probably have to depend on the actual page structure
+        // $this->page->requires->js('/lib/javascript-navigation.js');
+        // Navcount is used to allow us to have multiple trees although I dont' know why
+        // you would want two trees the same
+
+        block_navigation::$navcount++;
+
+        // Check if this block has been docked
+        if ($this->docked === null) {
+            $this->docked = get_user_preferences('nav_in_tab_panel_globalnav'.block_navigation::$navcount, 0);
+        }
+
+        // Check if there is a param to change the docked state
+        if ($this->docked && optional_param('undock', null, PARAM_INT)==$this->instance->id) {
+            unset_user_preference('nav_in_tab_panel_globalnav'.block_navigation::$navcount);
+            $url = $this->page->url;
+            $url->remove_params(array('undock'));
+            redirect($url);
+        } else if (!$this->docked && optional_param('dock', null, PARAM_INT)==$this->instance->id) {
+            set_user_preferences(array('nav_in_tab_panel_globalnav'.block_navigation::$navcount=>1));
+            $url = $this->page->url;
+            $url->remove_params(array('dock'));
+            redirect($url);
+        }
+
+        $trimmode = self::TRIM_RIGHT;
+        $trimlength = 50;
+
+        if (!empty($this->config->trimmode)) {
+            $trimmode = (int)$this->config->trimmode;
+        }
+
+        if (!empty($this->config->trimlength)) {
+            $trimlength = (int)$this->config->trimlength;
+        }
+
+        // Get the navigation object or don't display the block if none provided.
+        if (!$navigation = $this->get_navigation()) {
+            return null;
+        }
+        $expansionlimit = null;
+        if (!empty($this->config->expansionlimit)) {
+            $expansionlimit = $this->config->expansionlimit;
+            $navigation->set_expansion_limit($this->config->expansionlimit);
+        }
+        $this->trim($navigation, $trimmode, $trimlength, ceil($trimlength/2));
+
+        // Get the expandable items so we can pass them to JS
+        $expandable = array();
+        $navigation->find_expandable($expandable);
+        if ($expansionlimit) {
+            foreach ($expandable as $key=>$node) {
+                if ($node['type'] > $expansionlimit && !($expansionlimit == navigation_node::TYPE_COURSE && $node['type'] == $expansionlimit && $node['branchid'] == SITEID)) {
+                    unset($expandable[$key]);
+                }
+            }
+        }
+
+        $limit = 20;
+        if (!empty($CFG->navcourselimit)) {
+            $limit = $CFG->navcourselimit;
+        }
+        $expansionlimit = 0;
+        if (!empty($this->config->expansionlimit)) {
+            $expansionlimit = $this->config->expansionlimit;
+        }
+        $arguments = array(
+            'id'             => $this->instance->id,
+            'instance'       => $this->instance->id,
+            'candock'        => $this->instance_can_be_docked(),
+            'courselimit'    => $limit,
+            'expansionlimit' => $expansionlimit
+        );
+
+        $options = array();
+        $options['linkcategories'] = (!empty($this->config->linkcategories) && $this->config->linkcategories == 'yes');
+
+        // Grab the items to display
+        $renderer = $this->page->get_renderer($this->blockname);
+        $this->content = new stdClass();
+        $this->content->text = $renderer->navigation_tree($navigation, $expansionlimit, $options);
+
+        // Set content generated to true so that we know it has been done
+        $this->contentgenerated = true;
+
+        return $this->content;
+    }
+
+    /**
+     * Returns the navigation
+     *
+     * @return navigation_node The navigation object to display
+     */
+    protected function get_navigation() {
+        // Initialise (only actually happens if it hasn't already been done yet)
+        $this->page->navigation->initialise();
+        return clone($this->page->navigation);
+    }
+
+    /**
+     * Returns the attributes to set for this block
+     *
+     * This function returns an array of HTML attributes for this block including
+     * the defaults.
+     * {@link block_tree::html_attributes()} is used to get the default arguments
+     * and then we check whether the user has enabled hover expansion and add the
+     * appropriate hover class if it has.
+     *
+     * @return array An array of HTML attributes
+     */
+    public function html_attributes() {
+        $attributes = parent::html_attributes();
+        if (!empty($this->config->enablehoverexpansion) && $this->config->enablehoverexpansion == 'yes') {
+            $attributes['class'] .= ' block_js_expansion';
+        }
+        return $attributes;
+    }
+
+    /**
+     * Trims the text and shorttext properties of this node and optionally
+     * all of its children.
+     *
+     * @param navigation_node $node
+     * @param int $mode One of navigation_node::TRIM_*
+     * @param int $long The length to trim text to
+     * @param int $short The length to trim shorttext to
+     * @param bool $recurse Recurse all children
+     */
+    public function trim(navigation_node $node, $mode=1, $long=50, $short=25, $recurse=true) {
+        switch ($mode) {
+            case self::TRIM_RIGHT :
+                if (core_text::strlen($node->text)>($long+3)) {
+                    // Truncate the text to $long characters
+                    $node->text = $this->trim_right($node->text, $long);
+                }
+                if (is_string($node->shorttext) && core_text::strlen($node->shorttext)>($short+3)) {
+                    // Truncate the shorttext
+                    $node->shorttext = $this->trim_right($node->shorttext, $short);
+                }
+                break;
+            case self::TRIM_LEFT :
+                if (core_text::strlen($node->text)>($long+3)) {
+                    // Truncate the text to $long characters
+                    $node->text = $this->trim_left($node->text, $long);
+                }
+                if (is_string($node->shorttext) && core_text::strlen($node->shorttext)>($short+3)) {
+                    // Truncate the shorttext
+                    $node->shorttext = $this->trim_left($node->shorttext, $short);
+                }
+                break;
+            case self::TRIM_CENTER :
+                if (core_text::strlen($node->text)>($long+3)) {
+                    // Truncate the text to $long characters
+                    $node->text = $this->trim_center($node->text, $long);
+                }
+                if (is_string($node->shorttext) && core_text::strlen($node->shorttext)>($short+3)) {
+                    // Truncate the shorttext
+                    $node->shorttext = $this->trim_center($node->shorttext, $short);
+                }
+                break;
+        }
+        if ($recurse && $node->children->count()) {
+            foreach ($node->children as &$child) {
+                $this->trim($child, $mode, $long, $short, true);
+            }
+        }
+    }
+    /**
+     * Truncate a string from the left
+     * @param string $string The string to truncate
+     * @param int $length The length to truncate to
+     * @return string The truncated string
+     */
+    protected function trim_left($string, $length) {
+        return '...'.core_text::substr($string, core_text::strlen($string)-$length, $length);
+    }
+    /**
+     * Truncate a string from the right
+     * @param string $string The string to truncate
+     * @param int $length The length to truncate to
+     * @return string The truncated string
+     */
+    protected function trim_right($string, $length) {
+        return core_text::substr($string, 0, $length).'...';
+    }
+    /**
+     * Truncate a string in the center
+     * @param string $string The string to truncate
+     * @param int $length The length to truncate to
+     * @return string The truncated string
+     */
+    protected function trim_center($string, $length) {
+        $trimlength = ceil($length/2);
+        $start = core_text::substr($string, 0, $trimlength);
+        $end = core_text::substr($string, core_text::strlen($string)-$trimlength);
+        $string = $start.'...'.$end;
+        return $string;
+    }
+
+    /**
+     * Returns the role that best describes the navigation block... 'navigation'
+     *
+     * @return string 'navigation'
+     */
+    public function get_aria_role() {
+        return 'navigation';
+    }
+}
diff --git a/navigation/classes/privacy/provider.php b/navigation/classes/privacy/provider.php
new file mode 100644
index 0000000..032a554
--- /dev/null
+++ b/navigation/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_navigation.
+ *
+ * @package    block_navigation
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_navigation\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_navigation implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/navigation/db/access.php b/navigation/db/access.php
new file mode 100644
index 0000000..6754273
--- /dev/null
+++ b/navigation/db/access.php
@@ -0,0 +1,51 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Navigation block caps.
+ *
+ * @package    block_navigation
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/navigation:myaddinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/my:manageblocks'
+    ),
+
+    'block/navigation:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/navigation/db/upgrade.php b/navigation/db/upgrade.php
new file mode 100644
index 0000000..07b4381
--- /dev/null
+++ b/navigation/db/upgrade.php
@@ -0,0 +1,68 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file keeps track of upgrades to the navigation block
+ *
+ * Sometimes, changes between versions involve alterations to database structures
+ * and other major things that may break installations.
+ *
+ * The upgrade function in this file will attempt to perform all the necessary
+ * actions to upgrade your older installation to the current version.
+ *
+ * If there's something it cannot do itself, it will tell you what you need to do.
+ *
+ * The commands in here will all be database-neutral, using the methods of
+ * database_manager class
+ *
+ * Please do not forget to use upgrade_set_timeout()
+ * before any action that may take longer time to finish.
+ *
+ * @since Moodle 2.0
+ * @package block_navigation
+ * @copyright 2009 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * As of the implementation of this block and the general navigation code
+ * in Moodle 2.0 the body of immediate upgrade work for this block and
+ * settings is done in core upgrade {@see lib/db/upgrade.php}
+ *
+ * There were several reasons that they were put there and not here, both becuase
+ * the process for the two blocks was very similar and because the upgrade process
+ * was complex due to us wanting to remvoe the outmoded blocks that this
+ * block was going to replace.
+ *
+ * @param int $oldversion
+ * @param object $block
+ */
+function xmldb_block_navigation_upgrade($oldversion, $block) {
+    global $CFG;
+
+    // Automatically generated Moodle v3.2.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.3.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.4.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    return true;
+}
diff --git a/navigation/edit_form.php b/navigation/edit_form.php
new file mode 100644
index 0000000..9db482a
--- /dev/null
+++ b/navigation/edit_form.php
@@ -0,0 +1,71 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Form for editing global navigation instances.
+ *
+ * @since     Moodle 2.0
+ * @package   block_navigation
+ * @copyright 2009 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Form for editing global navigation instances.
+ *
+ * @package   block_navigation
+ * @category  navigation
+ * @copyright 2009 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_navigation_edit_form extends block_edit_form {
+    /**
+     * @param MoodleQuickForm $mform
+     */
+    protected function specific_definition($mform) {
+        global $CFG;
+        $mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
+
+        $mods = array('enabledock'=>'yes', 'linkcategories'=>'no');
+        $yesnooptions = array('yes'=>get_string('yes'), 'no'=>get_string('no'));
+        foreach ($mods as $modname=>$default) {
+            $mform->addElement('select', 'config_'.$modname, get_string($modname.'desc', $this->block->blockname), $yesnooptions);
+            $mform->setDefault('config_'.$modname, $default);
+        }
+
+        $options = array(
+            block_navigation::TRIM_RIGHT => get_string('trimmoderight', $this->block->blockname),
+            block_navigation::TRIM_LEFT => get_string('trimmodeleft', $this->block->blockname),
+            block_navigation::TRIM_CENTER => get_string('trimmodecenter', $this->block->blockname)
+        );
+        $mform->addElement('select', 'config_trimmode', get_string('trimmode', $this->block->blockname), $options);
+        $mform->setType('config_trimmode', PARAM_INT);
+
+        $mform->addElement('text', 'config_trimlength', get_string('trimlength', $this->block->blockname));
+        $mform->setDefault('config_trimlength', 50);
+        $mform->setType('config_trimlength', PARAM_INT);
+
+        $options = array(
+            0 => get_string('everything', $this->block->blockname),
+            global_navigation::TYPE_COURSE => get_string('courses', $this->block->blockname),
+            global_navigation::TYPE_SECTION => get_string('coursestructures', $this->block->blockname),
+            global_navigation::TYPE_ACTIVITY => get_string('courseactivities', $this->block->blockname)
+        );
+        $mform->addElement('select', 'config_expansionlimit', get_string('expansionlimit', $this->block->blockname), $options);
+        $mform->setType('config_expansionlimit', PARAM_INT);
+
+    }
+}
\ No newline at end of file
diff --git a/navigation/lang/en/block_navigation.php b/navigation/lang/en/block_navigation.php
new file mode 100644
index 0000000..89c95e6
--- /dev/null
+++ b/navigation/lang/en/block_navigation.php
@@ -0,0 +1,42 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file contains language strings used in the global navigation block
+ *
+ * @since Moodle 2.0
+ * @package block_navigation
+ * @copyright 2009 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['everything'] = 'Everything';
+$string['courses'] = 'Categories and courses';
+$string['coursestructures'] = 'Categories, courses, and course structures';
+$string['courseactivities'] = 'Categories, courses, and course Activities';
+$string['enabledockdesc'] = 'Allow the user to dock this block';
+$string['expansionlimit'] = 'Generate navigation for the following';
+$string['linkcategoriesdesc'] = 'Display categories as links';
+$string['navigation:addinstance'] = 'Add a new navigation block';
+$string['navigation:myaddinstance'] = 'Add a new navigation block to Dashboard';
+$string['pluginname'] = 'Navigation';
+$string['trimmode'] = 'Trim mode';
+$string['trimmoderight'] = 'Trim characters from the right';
+$string['trimmodeleft'] = 'Trim characters from the left';
+$string['trimmodecenter'] = 'Trim characters from the center';
+$string['trimlength'] = 'How many characters to trim to';
+$string['privacy:metadata'] = 'The Navigation block only shows data stored in other locations.';
diff --git a/navigation/renderer.php b/navigation/renderer.php
new file mode 100644
index 0000000..c64e55d
--- /dev/null
+++ b/navigation/renderer.php
@@ -0,0 +1,192 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Outputs the navigation tree.
+ *
+ * @since     Moodle 2.0
+ * @package   block_navigation
+ * @copyright 2009 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Renderer for block navigation
+ *
+ * @package   block_navigation
+ * @category  navigation
+ * @copyright 2009 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_navigation_renderer extends plugin_renderer_base {
+
+    /**
+     * Returns the content of the navigation tree.
+     *
+     * @param global_navigation $navigation
+     * @param int $expansionlimit
+     * @param array $options
+     * @return string $content
+     */
+    public function navigation_tree(global_navigation $navigation, $expansionlimit, array $options = array()) {
+        $navigation->add_class('navigation_node');
+        $navigationattrs = array(
+            'class' => 'block_tree list',
+            'role' => 'tree',
+            'data-ajax-loader' => 'block_navigation/nav_loader');
+        $content = $this->navigation_node(array($navigation), $navigationattrs, $expansionlimit, $options);
+        if (isset($navigation->id) && !is_numeric($navigation->id) && !empty($content)) {
+            $content = $this->output->box($content, 'block_tree_box', $navigation->id);
+        }
+        return $content;
+    }
+    /**
+     * Produces a navigation node for the navigation tree
+     *
+     * @param navigation_node[] $items
+     * @param array $attrs
+     * @param int $expansionlimit
+     * @param array $options
+     * @param int $depth
+     * @return string
+     */
+    protected function navigation_node($items, $attrs=array(), $expansionlimit=null, array $options = array(), $depth=1) {
+        // Exit if empty, we don't want an empty ul element.
+        if (count($items) === 0) {
+            return '';
+        }
+
+        // Turn our navigation items into list items.
+        $lis = array();
+        // Set the number to be static for unique id's.
+        static $number = 0;
+        foreach ($items as $item) {
+            $number++;
+            if (!$item->display && !$item->contains_active_node()) {
+                continue;
+            }
+
+            $isexpandable = (empty($expansionlimit) || ($item->type > navigation_node::TYPE_ACTIVITY || $item->type < $expansionlimit) || ($item->contains_active_node() && $item->children->count() > 0));
+
+            // Skip elements which have no content and no action - no point in showing them
+            if (!$isexpandable && empty($item->action)) {
+                continue;
+            }
+
+            $id = $item->id ? $item->id : html_writer::random_id();
+            $content = $item->get_content();
+            $title = $item->get_title();
+            $ulattr = ['id' => $id . '_group', 'role' => 'group'];
+            $liattr = ['class' => [$item->get_css_type(), 'depth_'.$depth]];
+            $pattr = ['class' => ['tree_item'], 'role' => 'treeitem'];
+            $pattr += !empty($item->id) ? ['id' => $item->id] : [];
+            $isbranch = $isexpandable && ($item->children->count() > 0 || ($item->has_children() && (isloggedin() || $item->type <= navigation_node::TYPE_CATEGORY)));
+            $hasicon = ((!$isbranch || $item->type == navigation_node::TYPE_ACTIVITY || $item->type == navigation_node::TYPE_RESOURCE) && $item->icon instanceof renderable);
+            $icon = '';
+
+            if ($hasicon) {
+                $liattr['class'][] = 'item_with_icon';
+                $pattr['class'][] = 'hasicon';
+                $icon = $this->output->render($item->icon);
+                // Because an icon is being used we're going to wrap the actual content in a span.
+                // This will allow designers to create columns for the content, as we've done in styles.css.
+                $content = $icon . html_writer::span($content, 'item-content-wrap');
+            }
+            if ($item->helpbutton !== null) {
+                $content = trim($item->helpbutton).html_writer::tag('span', $content, array('class'=>'clearhelpbutton'));
+            }
+            if (empty($content)) {
+                continue;
+            }
+
+            $nodetextid = 'label_' . $depth . '_' . $number;
+            $attributes = array('tabindex' => '-1', 'id' => $nodetextid);
+            if ($title !== '') {
+                $attributes['title'] = $title;
+            }
+            if ($item->hidden) {
+                $attributes['class'] = 'dimmed_text';
+            }
+            if (is_string($item->action) || empty($item->action) ||
+                    (($item->type === navigation_node::TYPE_CATEGORY || $item->type === navigation_node::TYPE_MY_CATEGORY) &&
+                    empty($options['linkcategories']))) {
+                $content = html_writer::tag('span', $content, $attributes);
+            } else if ($item->action instanceof action_link) {
+                //TODO: to be replaced with something else
+                $link = $item->action;
+                $link->text = $icon.html_writer::span($link->text, 'item-content-wrap');
+                $link->attributes = array_merge($link->attributes, $attributes);
+                $content = $this->output->render($link);
+            } else if ($item->action instanceof moodle_url) {
+                $content = html_writer::link($item->action, $content, $attributes);
+            }
+
+            if ($isbranch) {
+                $pattr['class'][] = 'branch';
+                $liattr['class'][] = 'contains_branch';
+                $pattr += ['aria-expanded' => ($item->has_children() && (!$item->forceopen || $item->collapse)) ? "false" : "true"];
+                if ($item->requiresajaxloading) {
+                    $pattr += [
+                        'data-requires-ajax' => 'true',
+                        'data-loaded' => 'false',
+                        'data-node-id' => $item->id,
+                        'data-node-key' => $item->key,
+                        'data-node-type' => $item->type
+                    ];
+                } else {
+                    $pattr += ['aria-owns' => $id . '_group'];
+                }
+            }
+
+            if ($item->isactive === true) {
+                $liattr['class'][] = 'current_branch';
+            }
+            if (!empty($item->classes) && count($item->classes)>0) {
+                $pattr['class'] = array_merge($pattr['class'], $item->classes);
+            }
+
+            $liattr['class'] = join(' ', $liattr['class']);
+            $pattr['class'] = join(' ', $pattr['class']);
+
+            $pattr += $depth == 1 ? ['data-collapsible' => 'false'] : [];
+            if (isset($pattr['aria-expanded']) && $pattr['aria-expanded'] === 'false') {
+                $ulattr += ['aria-hidden' => 'true'];
+            }
+
+            // Create the structure.
+            $content = html_writer::tag('p', $content, $pattr);
+            if ($isexpandable) {
+                $content .= $this->navigation_node($item->children, $ulattr, $expansionlimit, $options, $depth + 1);
+            }
+            if (!empty($item->preceedwithhr) && $item->preceedwithhr===true) {
+                $content = html_writer::empty_tag('hr') . $content;
+            }
+
+            $liattr['aria-labelledby'] = $nodetextid;
+            $content = html_writer::tag('li', $content, $liattr);
+            $lis[] = $content;
+        }
+
+        if (count($lis) === 0) {
+            // There is still a chance, despite having items, that nothing had content and no list items were created.
+            return '';
+        }
+
+        // We used to separate using new lines, however we don't do that now, instead we'll save a few chars.
+        // The source is complex already anyway.
+        return html_writer::tag('ul', implode('', $lis), $attrs);
+    }
+}
diff --git a/navigation/styles.css b/navigation/styles.css
new file mode 100644
index 0000000..2369c1a
--- /dev/null
+++ b/navigation/styles.css
@@ -0,0 +1,76 @@
+.block_navigation .block_tree .depth_1 > .tree_item.branch {
+    padding-left: 0;
+    background-image: none;
+}
+
+.block_navigation .block_tree .depth_1 > ul {
+    margin: 0;
+}
+
+.block_navigation .block_tree ul {
+    margin-left: 18px;
+}
+
+.block_navigation .block_tree p.hasicon {
+    text-indent: -21px;
+    padding-left: 21px;
+}
+
+.block_navigation .block_tree p.hasicon img {
+    width: 16px;
+    height: 16px;
+    margin-top: 3px;
+    margin-right: 5px;
+    vertical-align: top;
+}
+
+.block_navigation .block_tree p.hasicon.visibleifjs {
+    display: block;
+}
+
+.block_navigation .block_tree .tree_item {
+    cursor: pointer;
+    padding-left: 0;
+    margin: 3px 0;
+    background-position: 0 50%;
+    background-repeat: no-repeat;
+    word-wrap: break-word;
+}
+
+.block_navigation .block_tree .tree_item.branch {
+    padding-left: 21px;
+}
+
+.block_navigation .block_tree .active_tree_node {
+    font-weight: bold;
+}
+
+.block_navigation .block_tree [aria-expanded="true"] {
+    background-image: url('[[pix:t/expanded]]');
+}
+
+.block_navigation .block_tree [aria-expanded="false"] {
+    background-image: url('[[pix:t/collapsed]]');
+}
+
+.block_navigation .block_tree [aria-expanded="true"].emptybranch {
+    background-image: url('[[pix:t/collapsed_empty]]');
+}
+
+.block_navigation .block_tree [aria-expanded="false"].loading {
+    background-image: url('[[pix:i/loading_small]]');
+}
+
+/*rtl:raw:
+.block_navigation .block_tree [aria-expanded="false"] {background-image: url('[[pix:t/collapsed_rtl]]');}
+.block_navigation .block_tree [aria-expanded="true"].emptybranch {background-image: url('[[pix:t/collapsed_empty_rtl]]');}
+.block_navigation .block_tree [aria-expanded="false"].loading {background-image: url('[[pix:i/loading_small]]');}
+*/
+
+.block_navigation .block_tree [aria-hidden="false"] {
+    display: block;
+}
+
+.block_navigation .block_tree [aria-hidden="true"]:not(.icon) {
+    display: none;
+}
diff --git a/navigation/tests/behat/expand_courses_node.feature b/navigation/tests/behat/expand_courses_node.feature
new file mode 100644
index 0000000..683c34a
--- /dev/null
+++ b/navigation/tests/behat/expand_courses_node.feature
@@ -0,0 +1,202 @@
+@block @block_navigation
+Feature: Expand the courses nodes within the navigation block
+  In order to navigate the site
+  As an anonymous user, a guest, a student, and an admin
+  I need to expand the courses node in the navigation block and check the display of courses and categories.
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email |
+      | teacher1 | Teacher | 1 | teacher1@example.com |
+      | student1 | Student | 1 | student1@example.com |
+    And the following "categories" exist:
+      | name   | category | idnumber | visible |
+      | cat1   | 0        | cat1     | 1       |
+      | cat2   | 0        | cat2     | 1       |
+      | cat21  | cat2     | cat21    | 1       |
+      | cat211 | cat21    | cat211   | 1       |
+      | cat3   | 0        | cat3     | 0       |
+    And the following "courses" exist:
+      | fullname  | shortname | category | visible |
+      | Course 1  | c1        | cat1     | 1       |
+      | Course 2  | c2        | cat2     | 1       |
+      | Course 3  | c3        | cat21    | 1       |
+      | Course 4  | c4        | cat211   | 1       |
+      | Course 5  | c5        | cat211   | 0       |
+      | Course 6  | c6        | cat211   | 0       |
+      | Course 7  | c7        | cat3     | 1       |
+      | Course 8  | c8        | cat3     | 0       |
+    And the following "course enrolments" exist:
+      | user     | course | role    |
+      | teacher1 | c1     | teacher |
+      | teacher1 | c3     | teacher |
+      | teacher1 | c5     | teacher |
+      | student1 | c1     | student |
+      | student1 | c2     | student |
+      | student1 | c4     | student |
+    And the following config values are set as admin:
+      | navshowallcourses | 1 |
+    And I log in as "admin"
+    And I am on site homepage
+    And I turn editing mode on
+    And I add the "Navigation" block if not present
+    And I configure the "Navigation" block
+    And I set the following fields to these values:
+      | Page contexts | Display throughout the entire site |
+    And I press "Save changes"
+    And I turn editing mode off
+    And I am on "Course 2" course homepage
+    And I navigate to "Enrolment methods" node in "Course administration > Users"
+    And I click on "Edit" "link" in the "Guest access" "table_row"
+    And I set the following fields to these values:
+      | Allow guest access | Yes |
+    And I press "Save changes"
+    And I log out
+
+  @javascript
+  Scenario: As an anonymous user I expand the courses node to see courses.
+    When I should see "You are not logged in." in the ".logininfo" "css_element"
+    And I should see "Home" in the "Navigation" "block"
+    And I should see "Courses" in the "Navigation" "block"
+    And I expand "Courses" node
+    And I should see "cat1" in the "Navigation" "block"
+    And I should see "cat2" in the "Navigation" "block"
+    And I should not see "cat3" in the "Navigation" "block"
+    And I expand "cat1" node
+    And I expand "cat2" node
+    And I should see "cat21" in the "Navigation" "block"
+    And I expand "cat21" node
+    And I should see "cat211" in the "Navigation" "block"
+    And I expand "cat211" node
+    Then I should see "c1" in the "Navigation" "block"
+    And I should see "c2" in the "Navigation" "block"
+    And I should see "c3" in the "Navigation" "block"
+    And I should see "c4" in the "Navigation" "block"
+    And I should not see "c5" in the "Navigation" "block"
+    And I should not see "c6" in the "Navigation" "block"
+    And navigation node "c1" should not be expandable
+    And navigation node "c2" should not be expandable
+    And navigation node "c3" should not be expandable
+    And navigation node "c4" should not be expandable
+
+  @javascript
+  Scenario: As the admin user I expand the courses and category nodes to see courses.
+    When I log in as "admin"
+    And I am on site homepage
+    And I should see "Site home" in the "Navigation" "block"
+    And I should see "Courses" in the "Navigation" "block"
+    And I expand "Courses" node
+    And I should see "cat1" in the "Navigation" "block"
+    And I should see "cat2" in the "Navigation" "block"
+    And I should see "cat3" in the "Navigation" "block"
+    And I expand "cat1" node
+    And I expand "cat2" node
+    And I expand "cat3" node
+    And I should see "cat21" in the "Navigation" "block"
+    And I expand "cat21" node
+    And I should see "cat211" in the "Navigation" "block"
+    And I expand "cat211" node
+    Then I should see "c1" in the "Navigation" "block"
+    And I should see "c2" in the "Navigation" "block"
+    And I should see "c3" in the "Navigation" "block"
+    And I should see "c4" in the "Navigation" "block"
+    And I should see "c5" in the "Navigation" "block"
+    And I should see "c6" in the "Navigation" "block"
+    And I should see "c7" in the "Navigation" "block"
+    And I should see "c8" in the "Navigation" "block"
+    And navigation node "c1" should be expandable
+    And navigation node "c2" should be expandable
+    And navigation node "c3" should be expandable
+    And navigation node "c4" should be expandable
+    And navigation node "c5" should be expandable
+    And navigation node "c6" should be expandable
+    And navigation node "c7" should be expandable
+    And navigation node "c8" should be expandable
+
+  @javascript
+  Scenario: As teacher1 I expand the courses and category nodes to see courses.
+    When I log in as "teacher1"
+    And I am on site homepage
+    And I should see "Site home" in the "Navigation" "block"
+    And I should see "Courses" in the "Navigation" "block"
+    And I expand "Courses" node
+    And I should see "cat1" in the "Navigation" "block"
+    And I should see "cat2" in the "Navigation" "block"
+    And I should not see "cat3" in the "Navigation" "block"
+    And I expand "cat1" node
+    And I expand "cat2" node
+    And I should see "cat21" in the "Navigation" "block"
+    And I expand "cat21" node
+    And I should see "cat211" in the "Navigation" "block"
+    And I expand "cat211" node
+    Then I should see "c1" in the "Navigation" "block"
+    And I should see "c2" in the "Navigation" "block"
+    And I should see "c3" in the "Navigation" "block"
+    And I should see "c4" in the "Navigation" "block"
+    And I should see "c5" in the "Navigation" "block"
+    And I should not see "c6" in the "Navigation" "block"
+    And I should not see "c7" in the "Navigation" "block"
+    And I should not see "c8" in the "Navigation" "block"
+    And navigation node "c1" should be expandable
+    And navigation node "c2" should be expandable
+    And navigation node "c3" should be expandable
+    And navigation node "c4" should not be expandable
+    And navigation node "c5" should be expandable
+
+  @javascript
+  Scenario: As student1 I expand the courses and category nodes to see courses.
+    When I log in as "student1"
+    And I am on site homepage
+    And I should see "Site home" in the "Navigation" "block"
+    And I should see "Courses" in the "Navigation" "block"
+    And I expand "Courses" node
+    And I should see "cat1" in the "Navigation" "block"
+    And I should see "cat2" in the "Navigation" "block"
+    And I should not see "cat3" in the "Navigation" "block"
+    And I expand "cat1" node
+    And I expand "cat2" node
+    And I should see "cat21" in the "Navigation" "block"
+    And I expand "cat21" node
+    And I should see "cat211" in the "Navigation" "block"
+    And I expand "cat211" node
+    Then I should see "c1" in the "Navigation" "block"
+    And I should see "c2" in the "Navigation" "block"
+    And I should see "c3" in the "Navigation" "block"
+    And I should see "c4" in the "Navigation" "block"
+    And I should not see "c5" in the "Navigation" "block"
+    And I should not see "c6" in the "Navigation" "block"
+    And I should not see "c7" in the "Navigation" "block"
+    And I should not see "c8" in the "Navigation" "block"
+    And navigation node "c1" should be expandable
+    And navigation node "c2" should be expandable
+    And navigation node "c3" should not be expandable
+    And navigation node "c4" should be expandable
+
+  @javascript
+  Scenario: As guest I expand the courses and category nodes to see courses.
+    When I log in as "guest"
+    And I am on site homepage
+    And I should see "Home" in the "Navigation" "block"
+    And I should see "Courses" in the "Navigation" "block"
+    And I expand "Courses" node
+    And I should see "cat1" in the "Navigation" "block"
+    And I should see "cat2" in the "Navigation" "block"
+    And I should not see "cat3" in the "Navigation" "block"
+    And I expand "cat1" node
+    And I expand "cat2" node
+    And I should see "cat21" in the "Navigation" "block"
+    And I expand "cat21" node
+    And I should see "cat211" in the "Navigation" "block"
+    And I expand "cat211" node
+    Then I should see "c1" in the "Navigation" "block"
+    And I should see "c2" in the "Navigation" "block"
+    And I should see "c3" in the "Navigation" "block"
+    And I should see "c4" in the "Navigation" "block"
+    And I should not see "c5" in the "Navigation" "block"
+    And I should not see "c6" in the "Navigation" "block"
+    And I should not see "c7" in the "Navigation" "block"
+    And I should not see "c8" in the "Navigation" "block"
+    And navigation node "c1" should not be expandable
+    And navigation node "c2" should be expandable
+    And navigation node "c3" should not be expandable
+    And navigation node "c4" should not be expandable
diff --git a/navigation/tests/behat/participants_link.feature b/navigation/tests/behat/participants_link.feature
new file mode 100644
index 0000000..76533c9
--- /dev/null
+++ b/navigation/tests/behat/participants_link.feature
@@ -0,0 +1,54 @@
+@block @block_navigation
+Feature: Displaying the link to the Participants page
+  In order to see the course / site participants
+  As a student / admin respectively
+  I need a link to the Participants page be displayed (but only if I can access that page)
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email                |
+      | student1 | Student   | One      | student1@example.com |
+      | student2 | Student   | Two      | student2@example.com |
+    And the following "courses" exist:
+      | fullname | shortname |
+      | Course1  | C1        |
+    And the following "course enrolments" exist:
+      | user     | course | role    |
+      | student1 | C1     | student |
+    And I log in as "admin"
+    And I am on site homepage
+    And I turn editing mode on
+    And I add the "Navigation" block if not present
+    And I configure the "Navigation" block
+    And I set the following fields to these values:
+      | Page contexts | Display throughout the entire site |
+    And I press "Save changes"
+    And I log out
+
+  @javascript
+  Scenario: Course participants link is displayed to enrolled students after expanding the course node
+    When I log in as "student1"
+    And I expand "C1" node
+    Then "Participants" "link" should exist in the "Navigation" "block"
+    And I click on "Participants" "link" in the "Navigation" "block"
+    And I should see "Participants"
+    And "Student One" "link" should exist
+    And "Student Two" "link" should not exist
+
+  Scenario: Site participants link is displayed to admins
+    When I log in as "admin"
+    Then "Participants" "link" should exist in the "Navigation" "block"
+    And I click on "Participants" "link" in the "Navigation" "block"
+    And I should see "Participants"
+    And "Student One" "link" should exist
+    And "Student Two" "link" should exist
+
+  @javascript
+  Scenario: Site participants link is not displayed to students (MDL-55667)
+    Given I log in as "admin"
+    And I set the following administration settings values:
+      | defaultfrontpageroleid | Student (student) |
+    And I log out
+    When I log in as "student2"
+    And I expand "Site pages" node
+    Then "Participants" "link" should not exist in the "Navigation" "block"
diff --git a/navigation/tests/behat/view_my_courses.feature b/navigation/tests/behat/view_my_courses.feature
new file mode 100644
index 0000000..2b086ce
--- /dev/null
+++ b/navigation/tests/behat/view_my_courses.feature
@@ -0,0 +1,104 @@
+@block @block_navigation
+Feature: View my courses in navigation block
+  In order to navigate to my courses
+  As a student
+  I need my courses displayed in the navigation block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email |
+      | student1 | Student | 1 | student1@example.com |
+    And the following "categories" exist:
+      | name  | category | idnumber |
+      | cat1  | 0        | cat1     |
+      | cat2  | 0        | cat2     |
+      | cat3  | 0        | cat3     |
+      | cat31 | cat3     | cat31    |
+      | cat32 | cat3     | cat32    |
+      | cat33 | cat3     | cat33    |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course1  | c1        | cat1     |
+      | Course2  | c2        | cat2     |
+      | Course31 | c31       | cat31    |
+      | Course32 | c32       | cat32    |
+      | Course331| c331      | cat33    |
+      | Course332| c332      | cat33    |
+    And the following "course enrolments" exist:
+      | user     | course | role    |
+      | student1 | c1     | student |
+      | student1 | c31    | student |
+      | student1 | c331   | student |
+    And I log in as "admin"
+    And I am on site homepage
+    And I turn editing mode on
+    And I add the "Navigation" block if not present
+    And I configure the "Navigation" block
+    And I set the following fields to these values:
+      | Page contexts | Display throughout the entire site |
+    And I press "Save changes"
+    And I log out
+
+  @javascript
+  Scenario: The plain list of enrolled courses is shown
+    Given the following config values are set as admin:
+      | navshowmycoursecategories | 0 |
+    And I log in as "student1"
+    When I click on "Dashboard" "link" in the "Navigation" "block"
+    Then I should not see "cat1" in the "Navigation" "block"
+    And I should not see "cat2" in the "Navigation" "block"
+    And I should see "c1" in the "Navigation" "block"
+    And I should see "c31" in the "Navigation" "block"
+    And I should see "c331" in the "Navigation" "block"
+    And I should not see "c2" in the "Navigation" "block"
+    And I should not see "c32" in the "Navigation" "block"
+    And I should not see "c332" in the "Navigation" "block"
+
+  @javascript
+  Scenario: The nested list of enrolled courses is shown
+    Given the following config values are set as admin:
+      | navshowmycoursecategories | 1 |
+    And I log in as "student1"
+    When I click on "Dashboard" "link" in the "Navigation" "block"
+    Then I should see "cat1" in the "Navigation" "block"
+    And I should see "cat3" in the "Navigation" "block"
+    And I should not see "cat2" in the "Navigation" "block"
+    And I expand "cat3" node
+    And I should see "cat31" in the "Navigation" "block"
+    And I should see "cat33" in the "Navigation" "block"
+    And I should not see "cat32" in the "Navigation" "block"
+    And I expand "cat31" node
+    And I should see "c31" in the "Navigation" "block"
+    And I expand "cat33" node
+    And I should see "c331" in the "Navigation" "block"
+    And I should not see "c332" in the "Navigation" "block"
+
+  @javascript
+  Scenario: I can expand categories and courses as guest
+    Given the following config values are set as admin:
+      | navshowmycoursecategories | 1 |
+      | navshowallcourses         | 1 |
+    And I expand "Courses" node
+    And I should see "cat1" in the "Navigation" "block"
+    And I should see "cat2" in the "Navigation" "block"
+    And I should see "cat3" in the "Navigation" "block"
+    And I should not see "cat31" in the "Navigation" "block"
+    And I should not see "cat32" in the "Navigation" "block"
+    And I should not see "cat331" in the "Navigation" "block"
+    And I should not see "c1" in the "Navigation" "block"
+    And I should not see "c2" in the "Navigation" "block"
+    And I should not see "c31" in the "Navigation" "block"
+    And I should not see "c32" in the "Navigation" "block"
+    When I expand "cat3" node
+    And I expand "cat31" node
+    And I expand "cat1" node
+    Then I should see "cat1" in the "Navigation" "block"
+    And I should see "cat2" in the "Navigation" "block"
+    And I should see "cat3" in the "Navigation" "block"
+    And I should see "cat31" in the "Navigation" "block"
+    And I should see "cat32" in the "Navigation" "block"
+    And I should not see "cat331" in the "Navigation" "block"
+    And I should see "c1" in the "Navigation" "block"
+    And I should not see "c2" in the "Navigation" "block"
+    And I should see "c31" in the "Navigation" "block"
+    And I should not see "c32" in the "Navigation" "block"
diff --git a/navigation/version.php b/navigation/version.php
new file mode 100644
index 0000000..2b08391
--- /dev/null
+++ b/navigation/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_navigation
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_navigation'; // Full name of the plugin (used for diagnostics)
diff --git a/news_items/block_news_items.php b/news_items/block_news_items.php
new file mode 100644
index 0000000..9cd9406
--- /dev/null
+++ b/news_items/block_news_items.php
@@ -0,0 +1,156 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file contains the news item block class, based upon block_base.
+ *
+ * @package    block_news_items
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Class block_news_items
+ *
+ * @package    block_news_items
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_news_items extends block_base {
+    function init() {
+        $this->title = get_string('pluginname', 'block_news_items');
+    }
+
+    function get_content() {
+        global $CFG, $USER;
+
+        if ($this->content !== NULL) {
+            return $this->content;
+        }
+
+        $this->content = new stdClass;
+        $this->content->text = '';
+        $this->content->footer = '';
+
+        if (empty($this->instance)) {
+            return $this->content;
+        }
+
+
+        if ($this->page->course->newsitems) {   // Create a nice listing of recent postings
+
+            require_once($CFG->dirroot.'/mod/forum/lib.php');   // We'll need this
+
+            $text = '';
+
+            if (!$forum = forum_get_course_forum($this->page->course->id, 'news')) {
+                return '';
+            }
+
+            $modinfo = get_fast_modinfo($this->page->course);
+            if (empty($modinfo->instances['forum'][$forum->id])) {
+                return '';
+            }
+            $cm = $modinfo->instances['forum'][$forum->id];
+
+            if (!$cm->uservisible) {
+                return '';
+            }
+
+            $context = context_module::instance($cm->id);
+
+        /// User must have perms to view discussions in that forum
+            if (!has_capability('mod/forum:viewdiscussion', $context)) {
+                return '';
+            }
+
+        /// First work out whether we can post to this group and if so, include a link
+            $groupmode    = groups_get_activity_groupmode($cm);
+            $currentgroup = groups_get_activity_group($cm, true);
+
+            if (forum_user_can_post_discussion($forum, $currentgroup, $groupmode, $cm, $context)) {
+                $text .= '<div class="newlink"><a href="'.$CFG->wwwroot.'/mod/forum/post.php?forum='.$forum->id.'">'.
+                          get_string('addanewtopic', 'forum').'</a>...</div>';
+            }
+
+        /// Get all the recent discussions we're allowed to see
+
+            // This block displays the most recent posts in a forum in
+            // descending order. The call to default sort order here will use
+            // that unless the discussion that post is in has a timestart set
+            // in the future.
+            // This sort will ignore pinned posts as we want the most recent.
+            $sort = forum_get_default_sort_order(true, 'p.modified', 'd', false);
+            if (! $discussions = forum_get_discussions($cm, $sort, false,
+                                                        -1, $this->page->course->newsitems,
+                                                        false, -1, 0, FORUM_POSTS_ALL_USER_GROUPS) ) {
+                $text .= '('.get_string('nonews', 'forum').')';
+                $this->content->text = $text;
+                return $this->content;
+            }
+
+        /// Actually create the listing now
+
+            $strftimerecent = get_string('strftimerecent');
+            $strmore = get_string('more', 'forum');
+
+        /// Accessibility: markup as a list.
+            $text .= "\n<ul class='unlist'>\n";
+            foreach ($discussions as $discussion) {
+
+                $discussion->subject = $discussion->name;
+
+                $discussion->subject = format_string($discussion->subject, true, $forum->course);
+
+                $text .= '<li class="post">'.
+                         '<div class="head clearfix">'.
+                         '<div class="date">'.userdate($discussion->modified, $strftimerecent).'</div>'.
+                         '<div class="name">'.fullname($discussion).'</div></div>'.
+                         '<div class="info"><a href="'.$CFG->wwwroot.'/mod/forum/discuss.php?d='.$discussion->discussion.'">'.$discussion->subject.'</a></div>'.
+                         "</li>\n";
+            }
+            $text .= "</ul>\n";
+
+            $this->content->text = $text;
+
+            $this->content->footer = '<a href="'.$CFG->wwwroot.'/mod/forum/view.php?f='.$forum->id.'">'.
+                                      get_string('oldertopics', 'forum').'</a> ...';
+
+        /// If RSS is activated at site and forum level and this forum has rss defined, show link
+            if (isset($CFG->enablerssfeeds) && isset($CFG->forum_enablerssfeeds) &&
+                $CFG->enablerssfeeds && $CFG->forum_enablerssfeeds && $forum->rsstype && $forum->rssarticles) {
+                require_once($CFG->dirroot.'/lib/rsslib.php');   // We'll need this
+                if ($forum->rsstype == 1) {
+                    $tooltiptext = get_string('rsssubscriberssdiscussions','forum');
+                } else {
+                    $tooltiptext = get_string('rsssubscriberssposts','forum');
+                }
+                if (!isloggedin()) {
+                    $userid = $CFG->siteguest;
+                } else {
+                    $userid = $USER->id;
+                }
+
+                $this->content->footer .= '<br />'.rss_get_link($context->id, $userid, 'mod_forum', $forum->id, $tooltiptext);
+            }
+
+        }
+
+        return $this->content;
+    }
+}
+
+
diff --git a/news_items/classes/privacy/provider.php b/news_items/classes/privacy/provider.php
new file mode 100644
index 0000000..d4b883b
--- /dev/null
+++ b/news_items/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_news_items.
+ *
+ * @package    block_news_items
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_news_items\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_news_items implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/news_items/db/access.php b/news_items/db/access.php
new file mode 100644
index 0000000..86bb1b7
--- /dev/null
+++ b/news_items/db/access.php
@@ -0,0 +1,51 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * News items block caps.
+ *
+ * @package    block_news_items
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/news_items:myaddinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/my:manageblocks'
+    ),
+
+    'block/news_items:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/news_items/lang/en/block_news_items.php b/news_items/lang/en/block_news_items.php
new file mode 100644
index 0000000..8287d4f
--- /dev/null
+++ b/news_items/lang/en/block_news_items.php
@@ -0,0 +1,28 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_news_items', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_news_items
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['news_items:addinstance'] = 'Add a new latest announcements block';
+$string['news_items:myaddinstance'] = 'Add a new latest announcements block to Dashboard';
+$string['pluginname'] = 'Latest announcements';
+$string['privacy:metadata'] = 'The Latest announcements block only shows data stored in the forum and does not store data itself.';
diff --git a/news_items/tests/behat/display_news.feature b/news_items/tests/behat/display_news.feature
new file mode 100644
index 0000000..dfc75ee
--- /dev/null
+++ b/news_items/tests/behat/display_news.feature
@@ -0,0 +1,47 @@
+@block @block_news_items
+Feature: Latest announcements block displays the course latest news
+  In order to be aware of the course announcements
+  As a user
+  I need to see the latest announcements block in the main course page
+
+  @javascript
+  Scenario: Latest course announcements are displayed and can be configured
+    Given the following "users" exist:
+      | username | firstname | lastname | email |
+      | teacher1 | Teacher | 1 | teacher1@example.com |
+    And I log in as "admin"
+    And I create a course with:
+      | Course full name | Course 1 |
+      | Course short name | C1 |
+      | Number of announcements | 5 |
+    And I enrol "Teacher 1" user as "Teacher"
+    And I log out
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Latest announcements" block
+    And I turn editing mode off
+    When I add a new topic to "Announcements" forum with:
+      | Subject | Discussion One |
+      | Message | Not important |
+    And I add a new topic to "Announcements" forum with:
+      | Subject | Discussion Two |
+      | Message | Not important |
+    And I add a new topic to "Announcements" forum with:
+      | Subject | Discussion Three |
+      | Message | Not important |
+    And I am on "Course 1" course homepage
+    Then I should see "Discussion One" in the "Latest announcements" "block"
+    And I should see "Discussion Two" in the "Latest announcements" "block"
+    And I should see "Discussion Three" in the "Latest announcements" "block"
+    And I navigate to "Edit settings" in current page administration
+    And I set the following fields to these values:
+      | Number of announcements | 2 |
+    And I press "Save and display"
+    And I should not see "Discussion One" in the "Latest announcements" "block"
+    And I should see "Discussion Two" in the "Latest announcements" "block"
+    And I should see "Discussion Three" in the "Latest announcements" "block"
+    And I navigate to "Edit settings" in current page administration
+    And I set the following fields to these values:
+      | Number of announcements | 0 |
+    And I press "Save and display"
+    And "Latest announcements" "block" should not exist
diff --git a/news_items/version.php b/news_items/version.php
new file mode 100644
index 0000000..6802862
--- /dev/null
+++ b/news_items/version.php
@@ -0,0 +1,30 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_news_items
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;         // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;         // Requires this Moodle version
+$plugin->component = 'block_news_items'; // Full name of the plugin (used for diagnostics)
+$plugin->dependencies = array('mod_forum' => 2018050800);
diff --git a/online_users/block_online_users.php b/online_users/block_online_users.php
new file mode 100644
index 0000000..08521a3
--- /dev/null
+++ b/online_users/block_online_users.php
@@ -0,0 +1,147 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Online users block.
+ *
+ * @package    block_online_users
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+use block_online_users\fetcher;
+
+/**
+ * This block needs to be reworked.
+ * The new roles system does away with the concepts of rigid student and
+ * teacher roles.
+ */
+class block_online_users extends block_base {
+    function init() {
+        $this->title = get_string('pluginname','block_online_users');
+    }
+
+    function has_config() {
+        return true;
+    }
+
+    function get_content() {
+        global $USER, $CFG, $DB, $OUTPUT;
+
+        if ($this->content !== NULL) {
+            return $this->content;
+        }
+
+        $this->content = new stdClass;
+        $this->content->text = '';
+        $this->content->footer = '';
+
+        if (empty($this->instance)) {
+            return $this->content;
+        }
+
+        $timetoshowusers = 300; //Seconds default
+        if (isset($CFG->block_online_users_timetosee)) {
+            $timetoshowusers = $CFG->block_online_users_timetosee * 60;
+        }
+        $now = time();
+
+        //Calculate if we are in separate groups
+        $isseparategroups = ($this->page->course->groupmode == SEPARATEGROUPS
+                             && $this->page->course->groupmodeforce
+                             && !has_capability('moodle/site:accessallgroups', $this->page->context));
+
+        //Get the user current group
+        $currentgroup = $isseparategroups ? groups_get_course_group($this->page->course) : NULL;
+
+        $sitelevel = $this->page->course->id == SITEID || $this->page->context->contextlevel < CONTEXT_COURSE;
+
+        $onlineusers = new fetcher($currentgroup, $now, $timetoshowusers, $this->page->context,
+                $sitelevel, $this->page->course->id);
+
+        //Calculate minutes
+        $minutes  = floor($timetoshowusers/60);
+        $periodminutes = get_string('periodnminutes', 'block_online_users', $minutes);
+
+        // Count users.
+        $usercount = $onlineusers->count_users();
+        if ($usercount === 0) {
+            $usercount = get_string('nouser', 'block_online_users');
+        } else if ($usercount === 1) {
+            $usercount = get_string('numuser', 'block_online_users', $usercount);
+        } else {
+            $usercount = get_string('numusers', 'block_online_users', $usercount);
+        }
+
+        $this->content->text = '<div class="info">'.$usercount.' ('.$periodminutes.')</div>';
+
+        // Verify if we can see the list of users, if not just print number of users
+        if (!has_capability('block/online_users:viewlist', $this->page->context)) {
+            return $this->content;
+        }
+
+        $userlimit = 50; // We'll just take the most recent 50 maximum.
+        if ($users = $onlineusers->get_users($userlimit)) {
+            foreach ($users as $user) {
+                $users[$user->id]->fullname = fullname($user);
+            }
+        } else {
+            $users = array();
+        }
+
+        //Now, we have in users, the list of users to show
+        //Because they are online
+        if (!empty($users)) {
+            //Accessibility: Don't want 'Alt' text for the user picture; DO want it for the envelope/message link (existing lang string).
+            //Accessibility: Converted <div> to <ul>, inherit existing classes & styles.
+            $this->content->text .= "<ul class='list'>\n";
+            if (isloggedin() && has_capability('moodle/site:sendmessage', $this->page->context)
+                           && !empty($CFG->messaging) && !isguestuser()) {
+                $canshowicon = true;
+            } else {
+                $canshowicon = false;
+            }
+            foreach ($users as $user) {
+                $this->content->text .= '<li class="listentry">';
+                $timeago = format_time($now - $user->lastaccess); //bruno to calculate correctly on frontpage
+
+                if (isguestuser($user)) {
+                    $this->content->text .= '<div class="user">'.$OUTPUT->user_picture($user, array('size'=>16, 'alttext'=>false));
+                    $this->content->text .= get_string('guestuser').'</div>';
+
+                } else {
+                    $this->content->text .= '<div class="user">';
+                    $this->content->text .= '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$user->id.'&amp;course='.$this->page->course->id.'" title="'.$timeago.'">';
+                    $this->content->text .= $OUTPUT->user_picture($user, array('size'=>16, 'alttext'=>false, 'link'=>false)) .$user->fullname.'</a></div>';
+                }
+                if ($canshowicon and ($USER->id != $user->id) and !isguestuser($user)) {  // Only when logged in and messaging active etc
+                    $anchortagcontents = $OUTPUT->pix_icon('t/message', get_string('messageselectadd'));
+                    $anchorurl = new moodle_url('/message/index.php', array('id' => $user->id));
+                    $anchortag = html_writer::link($anchorurl, $anchortagcontents,
+                        array('title' => get_string('messageselectadd')));
+
+                    $this->content->text .= '<div class="message">'.$anchortag.'</div>';
+                }
+                $this->content->text .= "</li>\n";
+            }
+            $this->content->text .= '</ul><div class="clearer"><!-- --></div>';
+        }
+
+        return $this->content;
+    }
+}
+
+
diff --git a/online_users/classes/fetcher.php b/online_users/classes/fetcher.php
new file mode 100644
index 0000000..1c6d15a
--- /dev/null
+++ b/online_users/classes/fetcher.php
@@ -0,0 +1,165 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * File containing onlineusers class.
+ *
+ * @package    block_online_users
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_online_users;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Class used to list and count online users
+ *
+ * @package    block_online_users
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class fetcher {
+
+    /** @var string The SQL query for retrieving a list of online users */
+    public $sql;
+    /** @var string The SQL query for counting the number of online users */
+    public $csql;
+    /** @var string The params for the SQL queries */
+    public $params;
+
+    /**
+     * Class constructor
+     *
+     * @param int $currentgroup The group (if any) to filter on
+     * @param int $now Time now
+     * @param int $timetoshowusers Number of seconds to show online users
+     * @param context $context Context object used to generate the sql for users enrolled in a specific course
+     * @param bool $sitelevel Whether to check online users at site level.
+     * @param int $courseid The course id to check
+     */
+    public function __construct($currentgroup, $now, $timetoshowusers, $context, $sitelevel = true, $courseid = null) {
+        $this->set_sql($currentgroup, $now, $timetoshowusers, $context, $sitelevel, $courseid);
+    }
+
+    /**
+     * Store the SQL queries & params for listing online users
+     *
+     * @param int $currentgroup The group (if any) to filter on
+     * @param int $now Time now
+     * @param int $timetoshowusers Number of seconds to show online users
+     * @param context $context Context object used to generate the sql for users enrolled in a specific course
+     * @param bool $sitelevel Whether to check online users at site level.
+     * @param int $courseid The course id to check
+     */
+    protected function set_sql($currentgroup, $now, $timetoshowusers, $context, $sitelevel, $courseid) {
+        $timefrom = 100 * floor(($now - $timetoshowusers) / 100); // Round to nearest 100 seconds for better query cache.
+
+        $groupmembers = "";
+        $groupselect  = "";
+        $groupby       = "";
+        $lastaccess    = ", lastaccess";
+        $timeaccess    = ", ul.timeaccess AS lastaccess";
+        $params = array();
+
+        $userfields = \user_picture::fields('u', array('username'));
+
+        // Add this to the SQL to show only group users.
+        if ($currentgroup !== null) {
+            $groupmembers = ", {groups_members} gm";
+            $groupselect = "AND u.id = gm.userid AND gm.groupid = :currentgroup";
+            $groupby = "GROUP BY $userfields";
+            $lastaccess = ", MAX(u.lastaccess) AS lastaccess";
+            $timeaccess = ", MAX(ul.timeaccess) AS lastaccess";
+            $params['currentgroup'] = $currentgroup;
+        }
+
+        $params['now'] = $now;
+        $params['timefrom'] = $timefrom;
+        if ($sitelevel) {
+            $sql = "SELECT $userfields $lastaccess
+                      FROM {user} u $groupmembers
+                     WHERE u.lastaccess > :timefrom
+                           AND u.lastaccess <= :now
+                           AND u.deleted = 0
+                           $groupselect $groupby
+                  ORDER BY lastaccess DESC ";
+
+            $csql = "SELECT COUNT(u.id)
+                      FROM {user} u $groupmembers
+                     WHERE u.lastaccess > :timefrom
+                           AND u.lastaccess <= :now
+                           AND u.deleted = 0
+                           $groupselect";
+
+        } else {
+            // Course level - show only enrolled users for now.
+            // TODO: add a new capability for viewing of all users (guests+enrolled+viewing).
+            list($esqljoin, $eparams) = get_enrolled_sql($context);
+            $params = array_merge($params, $eparams);
+
+            $sql = "SELECT $userfields $timeaccess
+                      FROM {user_lastaccess} ul $groupmembers, {user} u
+                      JOIN ($esqljoin) euj ON euj.id = u.id
+                     WHERE ul.timeaccess > :timefrom
+                           AND u.id = ul.userid
+                           AND ul.courseid = :courseid
+                           AND ul.timeaccess <= :now
+                           AND u.deleted = 0
+                           $groupselect $groupby
+                  ORDER BY lastaccess DESC";
+
+            $csql = "SELECT COUNT(u.id)
+                      FROM {user_lastaccess} ul $groupmembers, {user} u
+                      JOIN ($esqljoin) euj ON euj.id = u.id
+                     WHERE ul.timeaccess > :timefrom
+                           AND u.id = ul.userid
+                           AND ul.courseid = :courseid
+                           AND ul.timeaccess <= :now
+                           AND u.deleted = 0
+                           $groupselect";
+
+            $params['courseid'] = $courseid;
+        }
+        $this->sql = $sql;
+        $this->csql = $csql;
+        $this->params = $params;
+    }
+
+    /**
+     * Get a list of the most recent online users
+     *
+     * @param int $userlimit The maximum number of users that will be returned (optional, unlimited if not set)
+     * @return array
+     */
+    public function get_users($userlimit = 0) {
+        global $DB;
+        $users = $DB->get_records_sql($this->sql, $this->params, 0, $userlimit);
+        return $users;
+    }
+
+    /**
+     * Count the number of online users
+     *
+     * @return int
+     */
+    public function count_users() {
+        global $DB;
+        return $DB->count_records_sql($this->csql, $this->params);
+    }
+
+}
diff --git a/online_users/classes/privacy/provider.php b/online_users/classes/privacy/provider.php
new file mode 100644
index 0000000..50d0280
--- /dev/null
+++ b/online_users/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_online_users.
+ *
+ * @package    block_online_users
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_online_users\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_online_users implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/online_users/db/access.php b/online_users/db/access.php
new file mode 100644
index 0000000..f238b73
--- /dev/null
+++ b/online_users/db/access.php
@@ -0,0 +1,65 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Online users block caps.
+ *
+ * @package    block_online_users
+ * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/online_users:myaddinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/my:manageblocks'
+    ),
+
+    'block/online_users:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+
+    'block/online_users:viewlist' => array(
+
+        'captype' => 'read',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'user' => CAP_ALLOW,
+            'guest' => CAP_ALLOW,
+            'student' => CAP_ALLOW,
+            'teacher' => CAP_ALLOW,
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        )
+    )
+);
diff --git a/online_users/lang/en/block_online_users.php b/online_users/lang/en/block_online_users.php
new file mode 100644
index 0000000..ff79ce5
--- /dev/null
+++ b/online_users/lang/en/block_online_users.php
@@ -0,0 +1,36 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_online_users', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_online_users
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['configtimetosee'] = 'Number of minutes determining the period of inactivity after which a user is no longer considered to be online.';
+$string['nouser'] = 'No online users';
+$string['numuser'] = '{$a} online user';
+$string['numusers'] = '{$a} online users';
+$string['online_users:addinstance'] = 'Add a new online users block';
+$string['online_users:myaddinstance'] = 'Add a new online users block to Dashboard';
+$string['online_users:viewlist'] = 'View list of online users';
+$string['periodnminutes'] = 'last {$a} minutes';
+$string['pluginname'] = 'Online users';
+$string['timetosee'] = 'Remove after inactivity (minutes)';
+$string['privacy:metadata'] = 'The Online users block only shows data stored in other locations.';
diff --git a/online_users/settings.php b/online_users/settings.php
new file mode 100644
index 0000000..b9d7d81
--- /dev/null
+++ b/online_users/settings.php
@@ -0,0 +1,31 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Online users block settings.
+ *
+ * @package    block_online_users
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die;
+
+if ($ADMIN->fulltree) {
+    $settings->add(new admin_setting_configtext('block_online_users_timetosee', get_string('timetosee', 'block_online_users'),
+                   get_string('configtimetosee', 'block_online_users'), 5, PARAM_INT));
+}
+
diff --git a/online_users/styles.css b/online_users/styles.css
new file mode 100644
index 0000000..90be203
--- /dev/null
+++ b/online_users/styles.css
@@ -0,0 +1,21 @@
+.block_online_users .content .list li.listentry {
+    clear: both;
+}
+
+.block_online_users .content .list li.listentry .user {
+    float: left;
+    position: relative;
+}
+
+.block_online_users .content .list li.listentry .user .userpicture {
+    vertical-align: text-bottom;
+}
+
+.block_online_users .content .list li.listentry .message {
+    float: right;
+    margin-top: 3px;
+}
+
+.block_online_users .content .info {
+    text-align: center;
+}
diff --git a/online_users/tests/behat/block_online_users_course.feature b/online_users/tests/behat/block_online_users_course.feature
new file mode 100644
index 0000000..e86e4d8
--- /dev/null
+++ b/online_users/tests/behat/block_online_users_course.feature
@@ -0,0 +1,41 @@
+@block @block_online_users
+Feature: The online users block allow you to see who is currently online
+  In order to enable the online users block on an course page
+  As a teacher
+  I can add the online users block to a course page
+
+  Background:
+    Given the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1        | 0        |
+    And the following "users" exist:
+      | username | firstname | lastname | email                |
+      | teacher1 | Teacher   | 1        | teacher1@example.com |
+      | student1 | Student   | 1        | student1@example.com |
+      | student2 | Student   | 2        | student2@example.com |
+
+    And the following "course enrolments" exist:
+      | user | course | role           |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student        |
+
+  Scenario: Add the online users on course page and see myself
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    When I add the "Online users" block
+    Then I should see "Teacher 1" in the "Online users" "block"
+    And I should see "1 online user" in the "Online users" "block"
+
+  Scenario: Add the online users on course page and see other logged in users
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Online users" block
+    And I log out
+    And I log in as "student2"
+    And I log out
+    When I log in as "student1"
+    And I am on "Course 1" course homepage
+    Then I should see "Teacher 1" in the "Online users" "block"
+    And I should see "Student 1" in the "Online users" "block"
+    And I should not see "Student 2" in the "Online users" "block"
+    And I should see "2 online users" in the "Online users" "block"
diff --git a/online_users/tests/behat/block_online_users_dashboard.feature b/online_users/tests/behat/block_online_users_dashboard.feature
new file mode 100644
index 0000000..34207c5
--- /dev/null
+++ b/online_users/tests/behat/block_online_users_dashboard.feature
@@ -0,0 +1,28 @@
+@block @block_online_users
+Feature: The online users block allow you to see who is currently online on dashboard
+  In order to use the online users block on the dashboard
+  As a user
+  I can view the online users block on my dashboard
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email                |
+      | teacher1 | Teacher   | 1        | teacher1@example.com |
+      | student1 | Student   | 1        | student1@example.com |
+      | student2 | Student   | 2        | student2@example.com |
+
+  Scenario: View the online users block on the dashboard and see myself
+    Given I log in as "teacher1"
+    Then I should see "Teacher 1" in the "Online users" "block"
+    And I should see "1 online user" in the "Online users" "block"
+
+  Scenario: View the online users block on the dashboard and see other logged in users
+    Given I log in as "student2"
+    And I log out
+    And I log in as "student1"
+    And I log out
+    When  I log in as "teacher1"
+    Then I should see "Teacher 1" in the "Online users" "block"
+    And I should see "Student 1" in the "Online users" "block"
+    And I should see "Student 2" in the "Online users" "block"
+    And I should see "3 online users" in the "Online users" "block"
diff --git a/online_users/tests/behat/block_online_users_frontpage.feature b/online_users/tests/behat/block_online_users_frontpage.feature
new file mode 100644
index 0000000..6237d3d
--- /dev/null
+++ b/online_users/tests/behat/block_online_users_frontpage.feature
@@ -0,0 +1,51 @@
+@block @block_online_users
+Feature: The online users block allow you to see who is currently online on frontpage
+  In order to enable the online users block on the front page page
+  As an admin
+  I can add the online users block to the front page page
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email                |
+      | student1 | Student   | 1        | student1@example.com |
+      | student2 | Student   | 2        | student2@example.com |
+
+  Scenario: View the online users block on the front page and see myself
+    Given I log in as "admin"
+    And I am on site homepage
+    And I navigate to "Turn editing on" node in "Front page settings"
+    When I add the "Online users" block
+    Then I should see "Admin User" in the "Online users" "block"
+    And I should see "1 online user" in the "Online users" "block"
+
+  Scenario: View the online users block on the front page as a logged in user
+    Given I log in as "admin"
+    And I am on site homepage
+    And I navigate to "Turn editing on" node in "Front page settings"
+    And I add the "Online users" block
+    And I log out
+    And I log in as "student2"
+    And I log out
+    When I log in as "student1"
+    And I am on site homepage
+    Then I should see "Admin User" in the "Online users" "block"
+    And I should see "Student 1" in the "Online users" "block"
+    And I should see "Student 2" in the "Online users" "block"
+    And I should see "3 online users" in the "Online users" "block"
+
+  Scenario: View the online users block on the front page as a guest
+    Given I log in as "admin"
+    And I am on site homepage
+    And I navigate to "Turn editing on" node in "Front page settings"
+    And I add the "Online users" block
+    And I log out
+    And I log in as "student2"
+    And I log out
+    And I log in as "student1"
+    And I log out
+    When I log in as "guest"
+    And I am on site homepage
+    Then I should see "Admin User" in the "Online users" "block"
+    And I should see "Student 1" in the "Online users" "block"
+    And I should see "Student 2" in the "Online users" "block"
+    And I should see "3 online users" in the "Online users" "block"
diff --git a/online_users/tests/generator/lib.php b/online_users/tests/generator/lib.php
new file mode 100644
index 0000000..6b721a9
--- /dev/null
+++ b/online_users/tests/generator/lib.php
@@ -0,0 +1,90 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * block_online_users data generator
+ *
+ * @package    block_online_users
+ * @category   test
+ * @copyright  2012 Petr Skoda {@link http://skodak.org}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+
+/**
+ * Online users block data generator class
+ *
+ * @package    block_online_users
+ * @category   test
+ * @copyright  2012 Petr Skoda {@link http://skodak.org}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_online_users_generator extends testing_block_generator {
+
+    /**
+     * Create (simulated) logged in users and add some of them to groups in a course
+     */
+    public function create_logged_in_users() {
+        global $DB;
+
+        $generator = advanced_testcase::getDataGenerator();
+        $data = array();
+
+        // Create 2 courses.
+        $course1 = $generator->create_course();
+        $data['course1'] = $course1;
+        $course2 = $generator->create_course();
+        $data['course2'] = $course2;
+
+        // Create 9 (simulated) logged in users enroled into $course1.
+        for ($i = 1; $i <= 9; $i++) {
+            $user = $generator->create_user();
+            $DB->set_field('user', 'lastaccess', time(), array('id' => $user->id));
+            $generator->enrol_user($user->id, $course1->id);
+            $DB->insert_record('user_lastaccess', array('userid' => $user->id, 'courseid' => $course1->id, 'timeaccess' => time()));
+            $data['user' . $i] = $user;
+        }
+        // Create 3 (simulated) logged in users who are not enroled into $course1.
+        for ($i = 10; $i <= 12; $i++) {
+            $user = $generator->create_user();
+            $DB->set_field('user', 'lastaccess', time(), array('id' => $user->id));
+            $data['user' . $i] = $user;
+        }
+
+        // Create 3 groups in course 1.
+        $group1 = $generator->create_group(array('courseid' => $course1->id));
+        $data['group1'] = $group1;
+        $group2 = $generator->create_group(array('courseid' => $course1->id));
+        $data['group2'] = $group2;
+        $group3 = $generator->create_group(array('courseid' => $course1->id));
+        $data['group3'] = $group3;
+
+        // Add 3 users to course group 1.
+        $generator->create_group_member(array('groupid' => $group1->id, 'userid' => $data['user1']->id));
+        $generator->create_group_member(array('groupid' => $group1->id, 'userid' => $data['user2']->id));
+        $generator->create_group_member(array('groupid' => $group1->id, 'userid' => $data['user3']->id));
+
+        // Add 4 users to course group 2.
+        $generator->create_group_member(array('groupid' => $group2->id, 'userid' => $data['user3']->id));
+        $generator->create_group_member(array('groupid' => $group2->id, 'userid' => $data['user4']->id));
+        $generator->create_group_member(array('groupid' => $group2->id, 'userid' => $data['user5']->id));
+        $generator->create_group_member(array('groupid' => $group2->id, 'userid' => $data['user6']->id));
+
+        return $data; // Return the user, course and group objects.
+    }
+}
diff --git a/online_users/tests/generator_test.php b/online_users/tests/generator_test.php
new file mode 100644
index 0000000..1ffcaba
--- /dev/null
+++ b/online_users/tests/generator_test.php
@@ -0,0 +1,57 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * PHPUnit data generator tests
+ *
+ * @package    block_online_users
+ * @category   phpunit
+ * @copyright  2012 Petr Skoda {@link http://skodak.org}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+
+/**
+ * PHPUnit data generator testcase
+ *
+ * @package    block_online_users
+ * @category   phpunit
+ * @copyright  2012 Petr Skoda {@link http://skodak.org}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_online_users_generator_testcase extends advanced_testcase {
+    public function test_generator() {
+        global $DB;
+
+        $this->resetAfterTest(true);
+
+        $beforeblocks = $DB->count_records('block_instances');
+        $beforecontexts = $DB->count_records('context');
+
+        /** @var block_online_users_generator $generator */
+        $generator = $this->getDataGenerator()->get_plugin_generator('block_online_users');
+        $this->assertInstanceOf('block_online_users_generator', $generator);
+        $this->assertEquals('online_users', $generator->get_blockname());
+
+        $generator->create_instance();
+        $generator->create_instance();
+        $bi = $generator->create_instance();
+        $this->assertEquals($beforeblocks+3, $DB->count_records('block_instances'));
+
+    }
+}
diff --git a/online_users/tests/online_users_test.php b/online_users/tests/online_users_test.php
new file mode 100644
index 0000000..9ff1e3c
--- /dev/null
+++ b/online_users/tests/online_users_test.php
@@ -0,0 +1,151 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Online users tests
+ *
+ * @package    block_online_users
+ * @category   test
+ * @copyright  2015 University of Nottingham <www.nottingham.ac.uk>
+ * @author     Barry Oosthuizen <barry.oosthuizen@nottingham.ac.uk>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+use block_online_users\fetcher;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Online users testcase
+ *
+ * @package    block_online_users
+ * @category   test
+ * @copyright  2015 University of Nottingham <www.nottingham.ac.uk>
+ * @author     Barry Oosthuizen <barry.oosthuizen@nottingham.ac.uk>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_online_users_testcase extends advanced_testcase {
+
+    protected $data;
+
+    /**
+     * Tests initial setup.
+     *
+     * Prepare the site with some courses, groups, users and
+     * simulate various recent accesses.
+     */
+    protected function setUp() {
+
+        // Generate (simulated) recently logged-in users.
+        $generator = $this->getDataGenerator()->get_plugin_generator('block_online_users');
+        $this->data = $generator->create_logged_in_users();
+
+        // Confirm we have modified the site and requires reset.
+        $this->resetAfterTest(true);
+    }
+
+    /**
+     * Check logged in group 1, 2 & 3 members in course 1 (should be 3, 4 and 0).
+     *
+     * @param array $data Array of user, course and group objects
+     * @param int $now Current Unix timestamp
+     * @param int $timetoshowusers The time window (in seconds) to check for the latest logged in users
+     */
+    public function test_fetcher_course1_group_members() {
+        global $CFG;
+
+        $groupid = $this->data['group1']->id;
+        $now = time();
+        $timetoshowusers = $CFG->block_online_users_timetosee * 60;
+        $context = context_course::instance($this->data['course1']->id);
+        $courseid = $this->data['course1']->id;
+        $onlineusers = new fetcher($groupid, $now, $timetoshowusers, $context, false, $courseid);
+
+        $usercount = $onlineusers->count_users();
+        $users = $onlineusers->get_users();
+        $this->assertEquals(3, $usercount, 'There was a problem counting the number of online users in group 1');
+        $this->assertEquals($usercount, count($users), 'There was a problem counting the number of online users in group 1');
+
+        $groupid = $this->data['group2']->id;
+        $onlineusers = new fetcher($groupid, $now, $timetoshowusers, $context, false, $courseid);
+
+        $usercount = $onlineusers->count_users();
+        $users = $onlineusers->get_users();
+        $this->assertEquals($usercount, count($users), 'There was a problem counting the number of online users in group 2');
+        $this->assertEquals(4, $usercount, 'There was a problem counting the number of online users in group 2');
+
+        $groupid = $this->data['group3']->id;
+        $onlineusers = new fetcher($groupid, $now, $timetoshowusers, $context, false, $courseid);
+
+        $usercount = $onlineusers->count_users();
+        $users = $onlineusers->get_users();
+        $this->assertEquals($usercount, count($users), 'There was a problem counting the number of online users in group 3');
+        $this->assertEquals(0, $usercount, 'There was a problem counting the number of online users in group 3');
+    }
+
+    /**
+     * Check logged in users in courses 1 & 2 (should be 9 and 0).
+     *
+     * @param array $data Array of user, course and group objects
+     * @param int $now Current Unix timestamp
+     * @param int $timetoshowusers The time window (in seconds) to check for the latest logged in users
+     */
+    public function test_fetcher_courses() {
+
+        global $CFG;
+
+        $currentgroup = null;
+        $now = time();
+        $timetoshowusers = $CFG->block_online_users_timetosee * 60;
+        $context = context_course::instance($this->data['course1']->id);
+        $courseid = $this->data['course1']->id;
+        $onlineusers = new fetcher($currentgroup, $now, $timetoshowusers, $context, false, $courseid);
+
+        $usercount = $onlineusers->count_users();
+        $users = $onlineusers->get_users();
+        $this->assertEquals($usercount, count($users), 'There was a problem counting the number of online users in course 1');
+        $this->assertEquals(9, $usercount, 'There was a problem counting the number of online users in course 1');
+
+        $courseid = $this->data['course2']->id;
+        $onlineusers = new fetcher($currentgroup, $now, $timetoshowusers, $context, false, $courseid);
+
+        $usercount = $onlineusers->count_users();
+        $users = $onlineusers->get_users();
+        $this->assertEquals($usercount, count($users), 'There was a problem counting the number of online users in course 2');
+        $this->assertEquals(0, $usercount, 'There was a problem counting the number of online users in course 2');
+    }
+
+    /**
+     * Check logged in at the site level (should be 12).
+     *
+     * @param int $now Current Unix timestamp
+     * @param int $timetoshowusers The time window (in seconds) to check for the latest logged in users
+     */
+    public function test_fetcher_sitelevel() {
+        global $CFG;
+
+        $currentgroup = null;
+        $now = time();
+        $timetoshowusers = $CFG->block_online_users_timetosee * 60;
+        $context = context_system::instance();
+        $onlineusers = new fetcher($currentgroup, $now, $timetoshowusers, $context, true);
+
+        $usercount = $onlineusers->count_users();
+        $users = $onlineusers->get_users();
+        $this->assertEquals($usercount, count($users), 'There was a problem counting the number of online users at site level');
+        $this->assertEquals(12, $usercount, 'There was a problem counting the number of online users at site level');
+    }
+}
diff --git a/online_users/version.php b/online_users/version.php
new file mode 100644
index 0000000..6bbce9f
--- /dev/null
+++ b/online_users/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_online_users
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_online_users'; // Full name of the plugin (used for diagnostics)
diff --git a/participants/block_participants.php b/participants/block_participants.php
new file mode 100644
index 0000000..b1b433b
--- /dev/null
+++ b/participants/block_participants.php
@@ -0,0 +1,85 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Participants block
+ *
+ * @package    block_participants
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once($CFG->dirroot . '/course/lib.php');
+
+/**
+ * Participants block
+ *
+ * @package    block_participants
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_participants extends block_list {
+    function init() {
+        $this->title = get_string('pluginname', 'block_participants');
+    }
+
+    function get_content() {
+
+        global $CFG, $OUTPUT;
+
+        if (empty($this->instance)) {
+            $this->content = '';
+            return $this->content;
+        }
+
+        $this->content = new stdClass();
+        $this->content->items = array();
+        $this->content->icons = array();
+        $this->content->footer = '';
+
+        // user/index.php expect course context, so get one if page has module context.
+        $currentcontext = $this->page->context->get_course_context(false);
+
+        if (empty($currentcontext)) {
+            $this->content = '';
+            return $this->content;
+        } else if ($this->page->course->id == SITEID) {
+            if (!course_can_view_participants(context_system::instance())) {
+                $this->content = '';
+                return $this->content;
+            }
+        } else {
+            if (!course_can_view_participants($currentcontext)) {
+                $this->content = '';
+                return $this->content;
+            }
+        }
+
+        $icon = $OUTPUT->pix_icon('i/users', '');
+        $this->content->items[] = '<a title="'.get_string('listofallpeople').'" href="'.
+                                  $CFG->wwwroot.'/user/index.php?contextid='.$currentcontext->id.'">'.$icon.get_string('participants').'</a>';
+
+        return $this->content;
+    }
+
+    // my moodle can only have SITEID and it's redundant here, so take it away
+    function applicable_formats() {
+        return array('all' => true, 'my' => false, 'tag' => false);
+    }
+
+}
diff --git a/participants/classes/privacy/provider.php b/participants/classes/privacy/provider.php
new file mode 100644
index 0000000..efcffd1
--- /dev/null
+++ b/participants/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_participants.
+ *
+ * @package    block_participants
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_participants\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_participants implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/participants/db/access.php b/participants/db/access.php
new file mode 100644
index 0000000..734f8a1
--- /dev/null
+++ b/participants/db/access.php
@@ -0,0 +1,41 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Participants block caps.
+ *
+ * @package    block_participants
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/participants:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/participants/lang/en/block_participants.php b/participants/lang/en/block_participants.php
new file mode 100644
index 0000000..20eb2dd
--- /dev/null
+++ b/participants/lang/en/block_participants.php
@@ -0,0 +1,27 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_participants', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_participants
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['participants:addinstance'] = 'Add a new people block';
+$string['pluginname'] = 'People';
+$string['privacy:metadata'] = 'The People block only shows data stored in other locations.';
diff --git a/participants/tests/behat/block_participants_course.feature b/participants/tests/behat/block_participants_course.feature
new file mode 100644
index 0000000..5fa4a0b
--- /dev/null
+++ b/participants/tests/behat/block_participants_course.feature
@@ -0,0 +1,40 @@
+@block @block_participants
+Feature: People Block used in a course
+  In order to view participants in a course
+  As a teacher
+  I can add the people block to a course
+
+  Background:
+    Given the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C101      | 0        |
+    And the following "users" exist:
+      | username    | firstname | lastname | email            |
+      | student1    | Sam       | Student  | student1@example.com |
+    And the following "course enrolments" exist:
+      | user        | course | role           |
+      | student1    | C101   | student        |
+    And I log in as "admin"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "People" block
+    And I log out
+
+  Scenario: Student can view participants link
+    When I log in as "student1"
+    And I am on "Course 1" course homepage
+    Then "People" "block" should exist
+    And I should see "Participants" in the "People" "block"
+
+  Scenario: Student can follow participants link and be directed to the correct page
+    When I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I click on "Participants" "link" in the "People" "block"
+    Then I should see "Participants" in the "#page-content" "css_element"
+
+  Scenario: Student without permission can not view participants link
+    Given the following "permission overrides" exist:
+         | capability | permission | role | contextlevel | reference |
+         | moodle/course:viewparticipants | Prevent | student | Course | C101 |
+    When I log in as "student1"
+    And I am on "Course 1" course homepage
+    Then "People" "block" should not exist
diff --git a/participants/tests/behat/block_participants_frontpage.feature b/participants/tests/behat/block_participants_frontpage.feature
new file mode 100644
index 0000000..93b6a57
--- /dev/null
+++ b/participants/tests/behat/block_participants_frontpage.feature
@@ -0,0 +1,26 @@
+@block @block_participants
+Feature: People Block used on frontpage
+  In order to view participants in a site
+  As a admin
+  I can add the people block to the front page
+
+  Background:
+    Given the following "users" exist:
+      | username    | firstname | lastname | email            |
+      | student1    | Sam       | Student  | student1@example.com |
+    And I log in as "admin"
+    And I am on site homepage
+    And I navigate to "Turn editing on" node in "Front page settings"
+    And I add the "People" block
+    And I log out
+
+  Scenario: Admin can view site participants link
+    When I log in as "admin"
+    And I am on site homepage
+    Then "People" "block" should exist
+    And I should see "Participants" in the "People" "block"
+
+  Scenario: Student can not follow participants link on frontpage
+    When I log in as "student1"
+    And I am on site homepage
+    Then "People" "block" should not exist
diff --git a/participants/version.php b/participants/version.php
new file mode 100644
index 0000000..d05b247
--- /dev/null
+++ b/participants/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_participants
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_participants'; // Full name of the plugin (used for diagnostics)
diff --git a/private_files/block_private_files.php b/private_files/block_private_files.php
new file mode 100644
index 0000000..fba8113
--- /dev/null
+++ b/private_files/block_private_files.php
@@ -0,0 +1,72 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+
+/**
+ * Manage user private area files
+ *
+ * @package    block_private_files
+ * @copyright  2010 Dongsheng Cai <dongsheng@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class block_private_files extends block_base {
+
+    function init() {
+        $this->title = get_string('pluginname', 'block_private_files');
+    }
+
+    function specialization() {
+    }
+
+    function applicable_formats() {
+        return array('all' => true);
+    }
+
+    function instance_allow_multiple() {
+        return false;
+    }
+
+    function get_content() {
+        global $CFG, $USER, $PAGE, $OUTPUT;
+
+        if ($this->content !== NULL) {
+            return $this->content;
+        }
+        if (empty($this->instance)) {
+            return null;
+        }
+
+        $this->content = new stdClass();
+        $this->content->text = '';
+        $this->content->footer = '';
+        if (isloggedin() && !isguestuser()) {   // Show the block
+            $this->content = new stdClass();
+
+            //TODO: add capability check here!
+
+            $renderer = $this->page->get_renderer('block_private_files');
+            $this->content->text = $renderer->private_files_tree();
+            if (has_capability('moodle/user:manageownfiles', $this->context)) {
+                $this->content->footer = html_writer::link(
+                    new moodle_url('/user/files.php', array('returnurl' => $PAGE->url->out())),
+                    get_string('privatefilesmanage') . '...');
+            }
+
+        }
+        return $this->content;
+    }
+}
diff --git a/private_files/classes/privacy/provider.php b/private_files/classes/privacy/provider.php
new file mode 100644
index 0000000..147ab44
--- /dev/null
+++ b/private_files/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_private_files.
+ *
+ * @package    block_private_files
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_private_files\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_private_files implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/private_files/db/access.php b/private_files/db/access.php
new file mode 100644
index 0000000..707027f
--- /dev/null
+++ b/private_files/db/access.php
@@ -0,0 +1,51 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Private files block caps.
+ *
+ * @package    block_private_files
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/private_files:myaddinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/my:manageblocks'
+    ),
+
+    'block/private_files:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/private_files/edit.php b/private_files/edit.php
new file mode 100644
index 0000000..785349e
--- /dev/null
+++ b/private_files/edit.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Manage files in folder in private area.
+ *
+ * This page is not used and now redirects to the page to manage the private files.
+ *
+ * @package   block_private_files
+ * @copyright 2010 Petr Skoda (http://skodak.org)
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require('../../config.php');
+
+redirect(new moodle_url('/user/files.php'));
diff --git a/private_files/lang/en/block_private_files.php b/private_files/lang/en/block_private_files.php
new file mode 100644
index 0000000..f0791fc
--- /dev/null
+++ b/private_files/lang/en/block_private_files.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_private_files', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_private_files
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['pluginname'] = 'Private files';
+$string['privatefiles'] = 'Private files';
+$string['private_files:addinstance'] = 'Add a new private files block';
+$string['private_files:myaddinstance'] = 'Add a new private files block to Dashboard';
+$string['privacy:metadata'] = 'The Private files block only provides a view of, and a link to, the user\'s private files.';
diff --git a/private_files/module.js b/private_files/module.js
new file mode 100644
index 0000000..42a4026
--- /dev/null
+++ b/private_files/module.js
@@ -0,0 +1,41 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Init private files treeview
+ *
+ * @package    block_private_files
+ * @copyright  2009 Petr Skoda (http://skodak.org)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+M.block_private_files = {};
+
+M.block_private_files.init_tree = function(Y, expand_all, htmlid) {
+    Y.use('yui2-treeview', function(Y) {
+        var tree = new Y.YUI2.widget.TreeView(htmlid);
+
+        tree.subscribe("clickEvent", function(node, event) {
+            // we want normal clicking which redirects to url
+            return false;
+        });
+
+        if (expand_all) {
+            tree.expandAll();
+        }
+
+        tree.render();
+    });
+};
diff --git a/private_files/renderer.php b/private_files/renderer.php
new file mode 100644
index 0000000..d357053
--- /dev/null
+++ b/private_files/renderer.php
@@ -0,0 +1,89 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Print private files tree
+ *
+ * @package    block_private_files
+ * @copyright  2010 Dongsheng Cai <dongsheng@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+class block_private_files_renderer extends plugin_renderer_base {
+
+    /**
+     * Prints private files tree view
+     * @return string
+     */
+    public function private_files_tree() {
+        return $this->render(new private_files_tree);
+    }
+
+    public function render_private_files_tree(private_files_tree $tree) {
+        $module = array('name'=>'block_private_files', 'fullpath'=>'/blocks/private_files/module.js', 'requires'=>array('yui2-treeview'));
+        if (empty($tree->dir['subdirs']) && empty($tree->dir['files'])) {
+            $html = $this->output->box(get_string('nofilesavailable', 'repository'));
+        } else {
+            $htmlid = 'private_files_tree_'.uniqid();
+            $this->page->requires->js_init_call('M.block_private_files.init_tree', array(false, $htmlid));
+            $html = '<div id="'.$htmlid.'">';
+            $html .= $this->htmllize_tree($tree, $tree->dir);
+            $html .= '</div>';
+        }
+
+        return $html;
+    }
+
+    /**
+     * Internal function - creates htmls structure suitable for YUI tree.
+     */
+    protected function htmllize_tree($tree, $dir) {
+        global $CFG;
+        $yuiconfig = array();
+        $yuiconfig['type'] = 'html';
+
+        if (empty($dir['subdirs']) and empty($dir['files'])) {
+            return '';
+        }
+        $result = '<ul>';
+        foreach ($dir['subdirs'] as $subdir) {
+            $image = $this->output->pix_icon(file_folder_icon(), $subdir['dirname'], 'moodle', array('class'=>'icon'));
+            $result .= '<li yuiConfig=\''.json_encode($yuiconfig).'\'><div>'.$image.s($subdir['dirname']).'</div> '.$this->htmllize_tree($tree, $subdir).'</li>';
+        }
+        foreach ($dir['files'] as $file) {
+            $url = file_encode_url("$CFG->wwwroot/pluginfile.php", '/'.$tree->context->id.'/user/private'.$file->get_filepath().$file->get_filename(), true);
+            $filename = $file->get_filename();
+            $image = $this->output->pix_icon(file_file_icon($file), $filename, 'moodle', array('class'=>'icon'));
+            $result .= '<li yuiConfig=\''.json_encode($yuiconfig).'\'><div>'.html_writer::link($url, $image.$filename).'</div></li>';
+        }
+        $result .= '</ul>';
+
+        return $result;
+    }
+}
+
+class private_files_tree implements renderable {
+    public $context;
+    public $dir;
+    public function __construct() {
+        global $USER;
+        $this->context = context_user::instance($USER->id);
+        $fs = get_file_storage();
+        $this->dir = $fs->get_area_tree($this->context->id, 'user', 'private', 0);
+    }
+}
diff --git a/private_files/styles.css b/private_files/styles.css
new file mode 100644
index 0000000..b553b4c
--- /dev/null
+++ b/private_files/styles.css
@@ -0,0 +1,10 @@
+/* Rule so that the table tree view works with word-wrap: break-word. */
+.block_private_files .content table {
+    table-layout: fixed;
+    width: 100%;
+}
+
+.block_private_files .content .footer {
+    padding: 10px 0 0;
+    margin-top: .5em;
+}
diff --git a/private_files/tests/behat/block_private_files_activity.feature b/private_files/tests/behat/block_private_files_activity.feature
new file mode 100644
index 0000000..fb84377
--- /dev/null
+++ b/private_files/tests/behat/block_private_files_activity.feature
@@ -0,0 +1,28 @@
+@block @block_private_files @_file_upload @javascript
+Feature: The private files block allows users to store files privately in moodle on activity page
+  In order to store a private file in moodle
+  As a teacher
+  I can upload the file to my private files area using the private files block in an activity
+
+  Scenario: Upload a file to the private files block in an activity
+    Given the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "users" exist:
+      | username | firstname | lastname | email |
+      | teacher1 | Teacher | 1 | teacher1@example.com |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+    And the following "activities" exist:
+      | activity | course | idnumber | name           | intro                 |
+      | page    | C1      | page1    | Test page name | Test page description |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I follow "Test page name"
+    And I add the "Private files" block
+    And I should see "No files available" in the "Private files" "block"
+    When I follow "Manage private files..."
+    And I upload "blocks/private_files/tests/fixtures/testfile.txt" file to "Files" filemanager
+    And I press "Save changes"
+    Then I should see "testfile.txt" in the "Private files" "block"
diff --git a/private_files/tests/behat/block_private_files_course.feature b/private_files/tests/behat/block_private_files_course.feature
new file mode 100644
index 0000000..35a4e96
--- /dev/null
+++ b/private_files/tests/behat/block_private_files_course.feature
@@ -0,0 +1,24 @@
+@block @block_private_files @_file_upload @javascript
+Feature: The private files block allows users to store files privately in moodle on course page
+  In order to store a private file in moodle
+  As a teacher
+  I can upload the file to my private files area using the private files block in a course
+
+  Scenario: Upload a file to the private files block from a course
+    Given the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "users" exist:
+      | username | firstname | lastname | email |
+      | teacher1 | Teacher | 1 | teacher1@example.com |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Private files" block
+    And I should see "No files available" in the "Private files" "block"
+    When I follow "Manage private files..."
+    And I upload "blocks/private_files/tests/fixtures/testfile.txt" file to "Files" filemanager
+    And I press "Save changes"
+    Then I should see "testfile.txt" in the "Private files" "block"
diff --git a/private_files/tests/behat/block_private_files_dashboard.feature b/private_files/tests/behat/block_private_files_dashboard.feature
new file mode 100644
index 0000000..3b6eb5c
--- /dev/null
+++ b/private_files/tests/behat/block_private_files_dashboard.feature
@@ -0,0 +1,17 @@
+@block @block_private_files @_file_upload @javascript
+Feature: The private files block allows users to store files privately in moodle on dashboard
+  In order to store a private file in moodle
+  As a user
+  I can upload the file to my private files area using the private files block on the dashboard
+
+  Scenario: Upload a file to the private files block from the dashboard
+    Given the following "users" exist:
+      | username | firstname | lastname | email |
+      | teacher1 | Teacher | 1 | teacher1@example.com |
+    And I log in as "teacher1"
+    And "Private files" "block" should exist
+    And I should see "No files available" in the "Private files" "block"
+    When I follow "Manage private files..."
+    And I upload "blocks/private_files/tests/fixtures/testfile.txt" file to "Files" filemanager
+    And I press "Save changes"
+    Then I should see "testfile.txt" in the "Private files" "block"
diff --git a/private_files/tests/behat/block_private_files_frontpage.feature b/private_files/tests/behat/block_private_files_frontpage.feature
new file mode 100644
index 0000000..7816060
--- /dev/null
+++ b/private_files/tests/behat/block_private_files_frontpage.feature
@@ -0,0 +1,34 @@
+@block @block_private_files @_file_upload
+Feature: The private files block allows users to store files privately in moodle on front page.
+  In order to store a private file in moodle
+  As a teacher
+  I can upload the file to my private files area using the private files block from the front page
+
+  Background:
+    Given the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "users" exist:
+      | username | firstname | lastname | email |
+      | teacher1 | Teacher | 1 | teacher1@example.com |
+    And I log in as "admin"
+    And I am on site homepage
+    And I navigate to "Turn editing on" node in "Front page settings"
+    And I add the "Private files" block
+    And I log out
+
+  Scenario: Try to view the private files block as a guest
+    Given I log in as "guest"
+    When I am on site homepage
+    Then "Private files" "block" should not exist
+
+  @javascript
+  Scenario: Upload a file to the private files block from the frontpage
+    Given I log in as "teacher1"
+    And I am on site homepage
+    And "Private files" "block" should exist
+    And I should see "No files available" in the "Private files" "block"
+    When I follow "Manage private files..."
+    And I upload "blocks/private_files/tests/fixtures/testfile.txt" file to "Files" filemanager
+    And I press "Save changes"
+    Then I should see "testfile.txt" in the "Private files" "block"
diff --git a/private_files/tests/fixtures/testfile.txt b/private_files/tests/fixtures/testfile.txt
new file mode 100644
index 0000000..9f4b6d8
--- /dev/null
+++ b/private_files/tests/fixtures/testfile.txt
@@ -0,0 +1 @@
+This is a test file
diff --git a/private_files/version.php b/private_files/version.php
new file mode 100644
index 0000000..3376580
--- /dev/null
+++ b/private_files/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_private_files
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_private_files'; // Full name of the plugin (used for diagnostics)
diff --git a/quiz_results/backup/moodle2/restore_quiz_results_block_task.class.php b/quiz_results/backup/moodle2/restore_quiz_results_block_task.class.php
new file mode 100644
index 0000000..9aff839
--- /dev/null
+++ b/quiz_results/backup/moodle2/restore_quiz_results_block_task.class.php
@@ -0,0 +1,113 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * @package    block_quiz_results
+ * @copyright  2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Specialised restore task for the quiz_results block
+ * (using execute_after_tasks for recoding of target quiz)
+ *
+ * TODO: Finish phpdocs
+ *
+ * @copyright  2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class restore_quiz_results_block_task extends restore_block_task {
+
+    protected function define_my_settings() {
+    }
+
+    protected function define_my_steps() {
+    }
+
+    public function get_fileareas() {
+        return array(); // No associated fileareas
+    }
+
+    public function get_configdata_encoded_attributes() {
+        return array(); // No special handling of configdata
+    }
+
+    /**
+     * This function, executed after all the tasks in the plan
+     * have been executed, will perform the recode of the
+     * target quiz for the block. This must be done here
+     * and not in normal execution steps because the quiz
+     * can be restored after the block.
+     */
+    public function after_restore() {
+        global $DB;
+
+        // Get the blockid.
+        $blockid = $this->get_blockid();
+
+        // Extract block configdata and update it to point to the new quiz.
+        $configdata = $DB->get_field('block_instances', 'configdata', array('id' => $blockid));
+        $newconfigdata = '';
+
+        // The block was configured.
+        if (!empty($configdata)) {
+
+            $config = unserialize(base64_decode($configdata));
+            $config->activityparent = 'quiz';
+            $config->activityparentid = 0;
+            $config->gradeformat = isset($config->gradeformat) ? $config->gradeformat : 1;
+
+            if (!empty($config->quizid)
+                    && $quizmap = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'quiz', $config->quizid)) {
+                $config->activityparentid = $quizmap->newitemid;
+            }
+
+            // Set the decimal valuue as appropriate.
+            if ($config->gradeformat == 1) {
+                // This block is using percentages, do not display any decimal places.
+                $config->decimalpoints = 0;
+            } else {
+                // Get the decimal value from the corresponding quiz.
+                $config->decimalpoints = $DB->get_field('quiz', 'decimalpoints', array('id' => $config->activityparentid));
+            }
+
+            // Get the grade_items record to set the activitygradeitemid.
+            $info = $DB->get_record('grade_items',
+                    array('iteminstance' => $config->activityparentid, 'itemmodule' => $config->activityparent));
+            $config->activitygradeitemid = 0;
+            if ($info) {
+                $config->activitygradeitemid = $info->id;
+            }
+
+            unset($config->quizid);
+            $newconfigdata = base64_encode(serialize($config));
+        }
+
+        // Update the configuration and convert the block.
+        $DB->set_field('block_instances', 'configdata', $newconfigdata, array('id' => $blockid));
+        $DB->set_field('block_instances', 'blockname', 'activity_results', array('id' => $blockid));
+    }
+
+    static public function define_decode_contents() {
+        return array();
+    }
+
+    static public function define_decode_rules() {
+        return array();
+    }
+}
diff --git a/quiz_results/block_quiz_results.php b/quiz_results/block_quiz_results.php
new file mode 100644
index 0000000..bfb259b
--- /dev/null
+++ b/quiz_results/block_quiz_results.php
@@ -0,0 +1,61 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Classes to enforce the various access rules that can apply to a quiz.
+ *
+ * @package    block_quiz_results
+ * @copyright  2009 Tim Hunt
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once($CFG->dirroot . '/mod/quiz/lib.php');
+
+/**
+ * Block quiz_results class definition.
+ *
+ * This block can be added to a course page or a quiz page to display of list of
+ * the best/worst students/groups in a particular quiz.
+ *
+ * @package    block_quiz_results
+ * @copyright  2009 Tim Hunt
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_quiz_results extends block_base {
+    function init() {
+        $this->title = get_string('pluginname', 'block_quiz_results');
+    }
+
+    function applicable_formats() {
+        return array('mod-quiz' => true);
+    }
+
+    function instance_config_save($data, $nolongerused = false) {
+        parent::instance_config_save($data);
+    }
+
+    function get_content() {
+        return $this->content;
+    }
+
+    function instance_allow_multiple() {
+        return true;
+    }
+}
+
+
diff --git a/quiz_results/classes/privacy/provider.php b/quiz_results/classes/privacy/provider.php
new file mode 100644
index 0000000..0994665
--- /dev/null
+++ b/quiz_results/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_quiz_results.
+ *
+ * @package    block_quiz_results
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_quiz_results\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_quiz_results implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/quiz_results/db/access.php b/quiz_results/db/access.php
new file mode 100644
index 0000000..8e3622b
--- /dev/null
+++ b/quiz_results/db/access.php
@@ -0,0 +1,41 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Quiz results block caps.
+ *
+ * @package    block_quiz_results
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/quiz_results:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/quiz_results/db/install.php b/quiz_results/db/install.php
new file mode 100644
index 0000000..255cdba
--- /dev/null
+++ b/quiz_results/db/install.php
@@ -0,0 +1,31 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Quiz results block installation.
+ *
+ * @package    block_quiz_results
+ * @copyright  2015 Dan Poltawski <dan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+function xmldb_block_quiz_results_install() {
+    global $DB;
+
+    // Disable quiz_results on new installs (its now just a stub).
+    $DB->set_field('block', 'visible', 0, array('name' => 'quiz_results'));
+}
+
diff --git a/quiz_results/db/upgrade.php b/quiz_results/db/upgrade.php
new file mode 100644
index 0000000..18ee857
--- /dev/null
+++ b/quiz_results/db/upgrade.php
@@ -0,0 +1,58 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file keeps track of upgrades to the quiz_results block
+ *
+ * Sometimes, changes between versions involve alterations to database structures
+ * and other major things that may break installations.
+ *
+ * The upgrade function in this file will attempt to perform all the necessary
+ * actions to upgrade your older installation to the current version.
+ *
+ * If there's something it cannot do itself, it will tell you what you need to do.
+ *
+ * The commands in here will all be database-neutral, using the methods of
+ * database_manager class
+ *
+ * Please do not forget to use upgrade_set_timeout()
+ * before any action that may take longer time to finish.
+ *
+ * @since Moodle 2.9
+ * @package block_quiz_results
+ * @copyright 2015 Stephen Bourget
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Upgrade the quiz_results block
+ * @param int $oldversion
+ * @param object $block
+ */
+function xmldb_block_quiz_results_upgrade($oldversion, $block) {
+    global $CFG;
+
+    // Automatically generated Moodle v3.2.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.3.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.4.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    return true;
+}
diff --git a/quiz_results/lang/en/block_quiz_results.php b/quiz_results/lang/en/block_quiz_results.php
new file mode 100644
index 0000000..f822a2f
--- /dev/null
+++ b/quiz_results/lang/en/block_quiz_results.php
@@ -0,0 +1,27 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_quiz_results', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package    block_quiz_results
+ * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['pluginname'] = 'Quiz results (disabled)';
+$string['quiz_results:addinstance'] = 'Add a new quiz results block';
+$string['privacy:metadata'] = 'The Quiz results block only shows data stored in other locations.';
diff --git a/quiz_results/lang/en/depreciated.txt b/quiz_results/lang/en/depreciated.txt
new file mode 100644
index 0000000..e69de29
diff --git a/quiz_results/version.php b/quiz_results/version.php
new file mode 100644
index 0000000..b3ae74a
--- /dev/null
+++ b/quiz_results/version.php
@@ -0,0 +1,31 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version information for the block_quiz_results plugin.
+ *
+ * @package    block_quiz_results
+ * @copyright  2011 The Open University
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_quiz_results'; // Full name of the plugin (used for diagnostics)
+
+$plugin->dependencies = array('mod_quiz' => 2018050800);
diff --git a/recent_activity/block_recent_activity.php b/recent_activity/block_recent_activity.php
new file mode 100644
index 0000000..6a46c36
--- /dev/null
+++ b/recent_activity/block_recent_activity.php
@@ -0,0 +1,309 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * class block_recent_activity
+ *
+ * @package    block_recent_activity
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once($CFG->dirroot.'/course/lib.php');
+
+/**
+ * class block_recent_activity
+ *
+ * @package    block_recent_activity
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_recent_activity extends block_base {
+
+    /**
+     * Use {@link block_recent_activity::get_timestart()} to access
+     *
+     * @var int stores the time since when we want to show recent activity
+     */
+    protected $timestart = null;
+
+    /**
+     * Initialises the block
+     */
+    function init() {
+        $this->title = get_string('pluginname', 'block_recent_activity');
+    }
+
+    /**
+     * Returns the content object
+     *
+     * @return stdObject
+     */
+    function get_content() {
+        if ($this->content !== NULL) {
+            return $this->content;
+        }
+
+        if (empty($this->instance)) {
+            $this->content = '';
+            return $this->content;
+        }
+
+        $this->content = new stdClass;
+        $this->content->text = '';
+        $this->content->footer = '';
+
+        $renderer = $this->page->get_renderer('block_recent_activity');
+        $this->content->text = $renderer->recent_activity($this->page->course,
+                $this->get_timestart(),
+                $this->get_recent_enrolments(),
+                $this->get_structural_changes(),
+                $this->get_modules_recent_activity());
+
+        return $this->content;
+    }
+
+    /**
+     * Returns the time since when we want to show recent activity
+     *
+     * For guest users it is 2 days, for registered users it is the time of last access to the course
+     *
+     * @return int
+     */
+    protected function get_timestart() {
+        global $USER;
+        if ($this->timestart === null) {
+            $this->timestart = round(time() - COURSE_MAX_RECENT_PERIOD, -2); // better db caching for guests - 100 seconds
+
+            if (!isguestuser()) {
+                if (!empty($USER->lastcourseaccess[$this->page->course->id])) {
+                    if ($USER->lastcourseaccess[$this->page->course->id] > $this->timestart) {
+                        $this->timestart = $USER->lastcourseaccess[$this->page->course->id];
+                    }
+                }
+            }
+        }
+        return $this->timestart;
+    }
+
+    /**
+     * Returns all recent enrolments.
+     *
+     * This function previously used get_recent_enrolments located in lib/deprecatedlib.php which would
+     * return an empty array which was identified in MDL-36993. The use of this function outside the
+     * deprecated lib was removed in MDL-40649.
+     *
+     * @todo MDL-36993 this function always return empty array
+     * @return array array of entries from {user} table
+     */
+    protected function get_recent_enrolments() {
+        return array();
+    }
+
+    /**
+     * Returns list of recent changes in course structure
+     *
+     * It includes adding, editing or deleting of the resources or activities
+     * Excludes changes on modules without a view link (i.e. labels), and also
+     * if activity was both added and deleted
+     *
+     * @return array array of changes. Each element is an array containing attributes:
+     *    'action' - one of: 'add mod', 'update mod', 'delete mod'
+     *    'module' - instance of cm_info (for 'delete mod' it is an object with attributes modname and modfullname)
+     */
+    protected function get_structural_changes() {
+        global $DB;
+        $course = $this->page->course;
+        $context = context_course::instance($course->id);
+        $canviewdeleted = has_capability('block/recent_activity:viewdeletemodule', $context);
+        $canviewupdated = has_capability('block/recent_activity:viewaddupdatemodule', $context);
+        if (!$canviewdeleted && !$canviewupdated) {
+            return;
+        }
+
+        $timestart = $this->get_timestart();
+        $changelist = array();
+        // The following query will retrieve the latest action for each course module in the specified course.
+        // Also the query filters out the modules that were created and then deleted during the given interval.
+        $sql = "SELECT
+                    cmid, MIN(action) AS minaction, MAX(action) AS maxaction, MAX(modname) AS modname
+                FROM {block_recent_activity}
+                WHERE timecreated > ? AND courseid = ?
+                GROUP BY cmid
+                ORDER BY MAX(timecreated) ASC";
+        $params = array($timestart, $course->id);
+        $logs = $DB->get_records_sql($sql, $params);
+        if (isset($logs[0])) {
+            // If special record for this course and cmid=0 is present, migrate logs.
+            self::migrate_logs($course);
+            $logs = $DB->get_records_sql($sql, $params);
+        }
+        if ($logs) {
+            $modinfo = get_fast_modinfo($course);
+            foreach ($logs as $log) {
+                // We used aggregate functions since constants CM_CREATED, CM_UPDATED and CM_DELETED have ascending order (0,1,2).
+                $wasdeleted = ($log->maxaction == block_recent_activity_observer::CM_DELETED);
+                $wascreated = ($log->minaction == block_recent_activity_observer::CM_CREATED);
+
+                if ($wasdeleted && $wascreated) {
+                    // Activity was created and deleted within this interval. Do not show it.
+                    continue;
+                } else if ($wasdeleted && $canviewdeleted) {
+                    if (plugin_supports('mod', $log->modname, FEATURE_NO_VIEW_LINK, false)) {
+                        // Better to call cm_info::has_view() because it can be dynamic.
+                        // But there is no instance of cm_info now.
+                        continue;
+                    }
+                    // Unfortunately we do not know if the mod was visible.
+                    $modnames = get_module_types_names();
+                    $changelist[$log->cmid] = array('action' => 'delete mod',
+                        'module' => (object)array(
+                            'modname' => $log->modname,
+                            'modfullname' => isset($modnames[$log->modname]) ? $modnames[$log->modname] : $log->modname
+                         ));
+
+                } else if (!$wasdeleted && isset($modinfo->cms[$log->cmid]) && $canviewupdated) {
+                    // Module was either added or updated during this interval and it currently exists.
+                    // If module was both added and updated show only "add" action.
+                    $cm = $modinfo->cms[$log->cmid];
+                    if ($cm->has_view() && $cm->uservisible) {
+                        $changelist[$log->cmid] = array(
+                            'action' => $wascreated ? 'add mod' : 'update mod',
+                            'module' => $cm
+                        );
+                    }
+                }
+            }
+        }
+        return $changelist;
+    }
+
+    /**
+     * Returns list of recent activity within modules
+     *
+     * For each used module type executes callback MODULE_print_recent_activity()
+     *
+     * @return array array of pairs moduletype => content
+     */
+    protected function get_modules_recent_activity() {
+        $context = context_course::instance($this->page->course->id);
+        $viewfullnames = has_capability('moodle/site:viewfullnames', $context);
+        $hascontent = false;
+
+        $modinfo = get_fast_modinfo($this->page->course);
+        $usedmodules = $modinfo->get_used_module_names();
+        $recentactivity = array();
+        foreach ($usedmodules as $modname => $modfullname) {
+            // Each module gets it's own logs and prints them
+            ob_start();
+            $hascontent = component_callback('mod_'. $modname, 'print_recent_activity',
+                    array($this->page->course, $viewfullnames, $this->get_timestart()), false);
+            if ($hascontent) {
+                $recentactivity[$modname] = ob_get_contents();
+            }
+            ob_end_clean();
+        }
+        return $recentactivity;
+    }
+
+    /**
+     * Which page types this block may appear on.
+     *
+     * @return array page-type prefix => true/false.
+     */
+    function applicable_formats() {
+        return array('all' => true, 'my' => false, 'tag' => false);
+    }
+
+    /**
+     * Remove old entries from table block_recent_activity
+     */
+    public function cron() {
+        global $DB;
+        // Those entries will never be displayed as RECENT anyway.
+        $DB->delete_records_select('block_recent_activity', 'timecreated < ?',
+                array(time() - COURSE_MAX_RECENT_PERIOD));
+    }
+
+    /**
+     * Migrates entries from table {log} into {block_recent_activity}
+     *
+     * We only migrate logs for the courses that actually have recent activity
+     * block and that are being viewed within COURSE_MAX_RECENT_PERIOD time
+     * after the upgrade.
+     *
+     * The presence of entry in {block_recent_activity} with the cmid=0 indicates
+     * that the course needs log migration. Those entries were installed in
+     * db/upgrade.php when the table block_recent_activity was created.
+     *
+     * @param stdClass $course
+     */
+    protected static function migrate_logs($course) {
+        global $DB;
+        if (!$logstarted = $DB->get_record('block_recent_activity',
+                array('courseid' => $course->id, 'cmid' => 0),
+                'id, timecreated')) {
+            return;
+        }
+        $DB->delete_records('block_recent_activity', array('id' => $logstarted->id));
+        try {
+            $logs = $DB->get_records_select('log',
+                    "time > ? AND time < ? AND course = ? AND
+                        module = 'course' AND
+                        (action = 'add mod' OR action = 'update mod' OR action = 'delete mod')",
+                    array(time()-COURSE_MAX_RECENT_PERIOD, $logstarted->timecreated, $course->id),
+                    'id ASC', 'id, time, userid, cmid, action, info');
+        } catch (Exception $e) {
+            // Probably table {log} was already removed.
+            return;
+        }
+        if (!$logs) {
+            return;
+        }
+        $modinfo = get_fast_modinfo($course);
+        $entries = array();
+        foreach ($logs as $log) {
+            $info = explode(' ', $log->info);
+            if (count($info) != 2) {
+                continue;
+            }
+            $modname = $info[0];
+            $instanceid = $info[1];
+            $entry = array('courseid' => $course->id, 'userid' => $log->userid,
+                'timecreated' => $log->time, 'modname' => $modname);
+            if ($log->action == 'delete mod') {
+                if (!$log->cmid) {
+                    continue;
+                }
+                $entry['action'] = 2;
+                $entry['cmid'] = $log->cmid;
+            } else {
+                if (!isset($modinfo->instances[$modname][$instanceid])) {
+                    continue;
+                }
+                if ($log->action == 'add mod') {
+                    $entry['action'] = 0;
+                } else {
+                    $entry['action'] = 1;
+                }
+                $entry['cmid'] = $modinfo->instances[$modname][$instanceid]->id;
+            }
+            $entries[] = $entry;
+        }
+        $DB->insert_records('block_recent_activity', $entries);
+    }
+}
+
diff --git a/recent_activity/classes/observer.php b/recent_activity/classes/observer.php
new file mode 100644
index 0000000..ad55559
--- /dev/null
+++ b/recent_activity/classes/observer.php
@@ -0,0 +1,73 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Event observer.
+ *
+ * @package    block_recent_activity
+ * @copyright  2014 Marina Glancy
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Event observer.
+ * Stores all actions about modules create/update/delete in plugin own's table.
+ * This allows the block to avoid expensive queries to the log table.
+ *
+ * @package    block_recent_activity
+ * @copyright  2014 Marina Glancy
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_recent_activity_observer {
+
+    /** @var int indicates that course module was created */
+    const CM_CREATED = 0;
+    /** @var int indicates that course module was udpated */
+    const CM_UPDATED = 1;
+    /** @var int indicates that course module was deleted */
+    const CM_DELETED = 2;
+
+    /**
+     * Store all actions about modules create/update/delete in own table.
+     *
+     * @param \core\event\base $event
+     */
+    public static function store(\core\event\base $event) {
+        global $DB;
+        $eventdata = new \stdClass();
+        switch ($event->eventname) {
+            case '\core\event\course_module_created':
+                $eventdata->action = self::CM_CREATED;
+                break;
+            case '\core\event\course_module_updated':
+                $eventdata->action = self::CM_UPDATED;
+                break;
+            case '\core\event\course_module_deleted':
+                $eventdata->action = self::CM_DELETED;
+                $eventdata->modname = $event->other['modulename'];
+                break;
+            default:
+                return;
+        }
+        $eventdata->timecreated = $event->timecreated;
+        $eventdata->courseid = $event->courseid;
+        $eventdata->cmid = $event->objectid;
+        $eventdata->userid = $event->userid;
+        $DB->insert_record('block_recent_activity', $eventdata);
+    }
+}
diff --git a/recent_activity/classes/privacy/provider.php b/recent_activity/classes/privacy/provider.php
new file mode 100644
index 0000000..b024b5b
--- /dev/null
+++ b/recent_activity/classes/privacy/provider.php
@@ -0,0 +1,97 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy subsystem implementation for block_recent_activity.
+ *
+ * @package    block_recent_activity
+ * @category   privacy
+ * @copyright  2018 Shamim Rezaie <shamim@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_recent_activity\privacy;
+
+use core_privacy\local\metadata\collection;
+use core_privacy\local\request\approved_contextlist;
+use core_privacy\local\request\contextlist;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * The block_recent_activity does not keep any data for more than COURSE_MAX_RECENT_PERIOD.
+ *
+ * @copyright  2018 Shamim Rezaie <shamim@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\provider,
+            \core_privacy\local\request\plugin\provider {
+
+    /**
+     * Returns metadata.
+     *
+     * @param collection $collection The initialised collection to add items to.
+     * @return collection A listing of user data stored through this system.
+     */
+    public static function get_metadata(collection $collection) : collection {
+
+        // This plugin defines a db table but it is not considered personal data and, therefore, not exported or deleted.
+        $collection->add_database_table('block_recent_activity', [
+            'courseid' => 'privacy:metadata:block_recent_activity:courseid',
+            'cmid' => 'privacy:metadata:block_recent_activity:cmid',
+            'timecreated' => 'privacy:metadata:block_recent_activity:timecreated',
+            'userid' => 'privacy:metadata:block_recent_activity:userid',
+            'action' => 'privacy:metadata:block_recent_activity:action',
+            'modname' => 'privacy:metadata:block_recent_activity:modname'
+        ], 'privacy:metadata:block_recent_activity');
+
+        return $collection;
+    }
+
+    /**
+     * Get the list of contexts that contain user information for the specified user.
+     *
+     * @param   int $userid The user to search.
+     * @return  contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
+     */
+    public static function get_contexts_for_userid(int $userid) : contextlist {
+        return new contextlist();
+    }
+
+    /**
+     * Export all user data for the specified user, in the specified contexts.
+     *
+     * @param approved_contextlist $contextlist The approved contexts to export information for.
+     */
+    public static function export_user_data(approved_contextlist $contextlist) {
+    }
+
+    /**
+     * Delete all data for all users in the specified context.
+     *
+     * @param \context $context The specific context to delete data for.
+     */
+    public static function delete_data_for_all_users_in_context(\context $context) {
+    }
+
+    /**
+     * Delete all user data for the specified user, in the specified contexts.
+     *
+     * @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
+     */
+    public static function delete_data_for_user(approved_contextlist $contextlist) {
+    }
+}
diff --git a/recent_activity/db/access.php b/recent_activity/db/access.php
new file mode 100644
index 0000000..80530bc
--- /dev/null
+++ b/recent_activity/db/access.php
@@ -0,0 +1,57 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Recent activity block caps.
+ *
+ * @package    block_recent_activity
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/recent_activity:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+
+    'block/recent_activity:viewaddupdatemodule' => array(
+        'captype' => 'read',
+        'contextlevel' => CONTEXT_COURSE,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        )
+    ),
+
+    'block/recent_activity:viewdeletemodule' => array(
+        'captype' => 'read',
+        'contextlevel' => CONTEXT_COURSE,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        )
+    )
+);
diff --git a/recent_activity/db/events.php b/recent_activity/db/events.php
new file mode 100644
index 0000000..0819cdb
--- /dev/null
+++ b/recent_activity/db/events.php
@@ -0,0 +1,47 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Event observer.
+ *
+ * @package   block_recent_activity
+ * @category  event
+ * @copyright 2014 Marina Glancy
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$observers = array (
+    array (
+        'eventname' => '\core\event\course_module_created',
+        'callback'  => 'block_recent_activity_observer::store',
+        'internal'  => false, // This means that we get events only after transaction commit.
+        'priority'  => 1000,
+    ),
+    array (
+        'eventname' => '\core\event\course_module_updated',
+        'callback'  => 'block_recent_activity_observer::store',
+        'internal'  => false, // This means that we get events only after transaction commit.
+        'priority'  => 1000,
+    ),
+    array (
+        'eventname' => '\core\event\course_module_deleted',
+        'callback'  => 'block_recent_activity_observer::store',
+        'internal'  => false, // This means that we get events only after transaction commit.
+        'priority'  => 1000,
+    ),
+);
diff --git a/recent_activity/db/install.xml b/recent_activity/db/install.xml
new file mode 100644
index 0000000..34fc9ff
--- /dev/null
+++ b/recent_activity/db/install.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<XMLDB PATH="blocks/recent_activity/db" VERSION="20140120" COMMENT="XMLDB file for Moodle blocks/recent_activity"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
+>
+  <TABLES>
+    <TABLE NAME="block_recent_activity" COMMENT="Recent activity block">
+      <FIELDS>
+        <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
+        <FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Course id"/>
+        <FIELD NAME="cmid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Course module id"/>
+        <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
+        <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="User performing the action"/>
+        <FIELD NAME="action" TYPE="int" LENGTH="1" NOTNULL="true" SEQUENCE="false" COMMENT="0 created, 1 updated, 2 deleted"/>
+        <FIELD NAME="modname" TYPE="char" LENGTH="20" NOTNULL="false" SEQUENCE="false" COMMENT="module type name (for delete action)"/>
+      </FIELDS>
+      <KEYS>
+        <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
+      </KEYS>
+      <INDEXES>
+        <INDEX NAME="coursetime" UNIQUE="false" FIELDS="courseid, timecreated"/>
+      </INDEXES>
+    </TABLE>
+  </TABLES>
+</XMLDB>
\ No newline at end of file
diff --git a/recent_activity/db/upgrade.php b/recent_activity/db/upgrade.php
new file mode 100644
index 0000000..d9bf407
--- /dev/null
+++ b/recent_activity/db/upgrade.php
@@ -0,0 +1,60 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file keeps track of upgrades to the recent activity block
+ *
+ * Sometimes, changes between versions involve alterations to database structures
+ * and other major things that may break installations.
+ *
+ * The upgrade function in this file will attempt to perform all the necessary
+ * actions to upgrade your older installation to the current version.
+ *
+ * If there's something it cannot do itself, it will tell you what you need to do.
+ *
+ * The commands in here will all be database-neutral, using the methods of
+ * database_manager class
+ *
+ * Please do not forget to use upgrade_set_timeout()
+ * before any action that may take longer time to finish.
+ *
+ * @package   block_recent_activity
+ * @copyright 2014 Marina Glancy
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Upgrade code for the recent activity block.
+ *
+ * @param int $oldversion
+ * @param object $block
+ */
+function xmldb_block_recent_activity_upgrade($oldversion, $block) {
+    global $CFG;
+
+    // Automatically generated Moodle v3.2.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.3.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.4.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    return true;
+}
diff --git a/recent_activity/lang/en/block_recent_activity.php b/recent_activity/lang/en/block_recent_activity.php
new file mode 100644
index 0000000..a569a7a
--- /dev/null
+++ b/recent_activity/lang/en/block_recent_activity.php
@@ -0,0 +1,37 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_recent_activity', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_recent_activity
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['pluginname'] = 'Recent activity';
+$string['privacy:metadata'] = 'The recent activity block contains a cache of data stored elsewhere in Moodle.';
+$string['privacy:metadata:block_recent_activity'] = 'Temporary log of recent teacher activity. Removed after two days';
+$string['privacy:metadata:block_recent_activity:action'] = 'Action: created, updated or deleted';
+$string['privacy:metadata:block_recent_activity:cmid'] = 'Course module id';
+$string['privacy:metadata:block_recent_activity:courseid'] = 'Course id';
+$string['privacy:metadata:block_recent_activity:modname'] = 'Module type name (for delete action)';
+$string['privacy:metadata:block_recent_activity:timecreated'] = 'Time when action was performed';
+$string['privacy:metadata:block_recent_activity:userid'] = 'User performing the action';
+$string['recent_activity:addinstance'] = 'Add a new recent activity block';
+$string['recent_activity:viewaddupdatemodule'] = 'View added and updated modules in recent activity block';
+$string['recent_activity:viewdeletemodule'] = 'View deleted modules in recent activity block';
diff --git a/recent_activity/renderer.php b/recent_activity/renderer.php
new file mode 100644
index 0000000..2e96eeb
--- /dev/null
+++ b/recent_activity/renderer.php
@@ -0,0 +1,128 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Renderer for block recent_activity
+ *
+ * @package    block_recent_activity
+ * @copyright  2012 Marina Glancy
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die;
+
+/**
+ * recent_activity block rendrer
+ *
+ * @package    block_recent_activity
+ * @copyright  2012 Marina Glancy
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_recent_activity_renderer extends plugin_renderer_base {
+
+    /**
+     * Renders HTML to display recent_activity block
+     *
+     * @param stdClass $course
+     * @param int $timestart
+     * @param array $recentenrolments array of changes in enrolments
+     * @param array $structuralchanges array of changes in course structure
+     * @param array $modulesrecentactivity array of changes in modules (provided by modules)
+     * @return string
+     */
+    public function recent_activity($course, $timestart, $recentenrolments, $structuralchanges,
+            $modulesrecentactivity) {
+
+        $output = html_writer::tag('div',
+                get_string('activitysince', '', userdate($timestart)),
+                array('class' => 'activityhead'));
+
+        $output .= html_writer::tag('div',
+                html_writer::link(new moodle_url('/course/recent.php', array('id' => $course->id)),
+                    get_string('recentactivityreport')),
+                array('class' => 'activityhead'));
+
+        $content = false;
+
+        // Firstly, have there been any new enrolments?
+        if ($recentenrolments) {
+            $content = true;
+            $context = context_course::instance($course->id);
+            $viewfullnames = has_capability('moodle/site:viewfullnames', $context);
+            $output .= html_writer::start_tag('div', array('class' => 'newusers'));
+            $output .= $this->heading(get_string("newusers").':', 3);
+            //Accessibility: new users now appear in an <OL> list.
+            $output .= html_writer::start_tag('ol', array('class' => 'list'));
+            foreach ($recentenrolments as $user) {
+                $output .= html_writer::tag('li',
+                        html_writer::link(new moodle_url('/user/view.php', array('id' => $user->id, 'course' => $course->id)),
+                                fullname($user, $viewfullnames)),
+                        array('class' => 'name'));
+            }
+            $output .= html_writer::end_tag('ol');
+            $output .= html_writer::end_tag('div');
+        }
+
+        // Next, have there been any modifications to the course structure?
+        if (!empty($structuralchanges)) {
+            $content = true;
+            $output .= $this->heading(get_string("courseupdates").':', 3);
+            foreach ($structuralchanges as $changeinfo => $change) {
+                $output .= $this->structural_change($change);
+            }
+        }
+
+        // Now display new things from each module
+        foreach ($modulesrecentactivity as $modname => $moduleactivity) {
+            $content = true;
+            $output .= $moduleactivity;
+        }
+
+        if (! $content) {
+            $output .= html_writer::tag('p', get_string('nothingnew'), array('class' => 'message'));
+        }
+        return $output;
+    }
+
+    /**
+     * Renders HTML for one change in course structure
+     *
+     * @see block_recent_activity::get_structural_changes()
+     * @param array $change array containing attributes
+     *    'action' - one of: 'add mod', 'update mod', 'delete mod'
+     *    'module' - instance of cm_info (for 'delete mod' it is an object with attributes modname and modfullname)
+     * @return string
+     */
+    protected function structural_change($change) {
+        $cm = $change['module'];
+        switch ($change['action']) {
+            case 'delete mod':
+                $text = get_string('deletedactivity', 'moodle', $cm->modfullname);
+                break;
+            case 'add mod':
+                $text = get_string('added', 'moodle', $cm->modfullname). '<br />'.
+                    html_writer::link($cm->url, format_string($cm->name, true));
+                break;
+            case 'update mod':
+                $text = get_string('updated', 'moodle', $cm->modfullname). '<br />'.
+                    html_writer::link($cm->url, format_string($cm->name, true));
+                break;
+            default:
+                return '';
+        }
+        return html_writer::tag('p', $text, array('class' => 'activity'));
+    }
+}
diff --git a/recent_activity/styles.css b/recent_activity/styles.css
new file mode 100644
index 0000000..3d1d9e3
--- /dev/null
+++ b/recent_activity/styles.css
@@ -0,0 +1,12 @@
+.block_recent_activity .activitydate,
+.block_recent_activity .activityhead {
+    text-align: center;
+}
+
+.block_recent_activity .unlist li {
+    margin-bottom: 1em;
+}
+
+.block_recent_activity li .head .date {
+    float: right;
+}
diff --git a/recent_activity/tests/behat/structural_changes.feature b/recent_activity/tests/behat/structural_changes.feature
new file mode 100644
index 0000000..62dc490
--- /dev/null
+++ b/recent_activity/tests/behat/structural_changes.feature
@@ -0,0 +1,215 @@
+@block @block_recent_activity
+Feature: View structural changes in recent activity block
+  In order to know when activities were changed
+  As a user
+  In need to see the structural changes in recent activity block
+
+  Background:
+    Given the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "users" exist:
+      | username    | firstname | lastname | email            |
+      | teacher1    | Terry1    | Teacher1 | teacher1@example.com |
+      | assistant1  | Terry2    | Teacher2 | teacher2@example.com |
+      | student1    | Sam1      | Student1 | student1@example.com |
+      | student2    | Sam2      | Student2 | student2@example.com |
+      | student3    | Sam3      | Student3 | student3@example.com |
+    And the following "course enrolments" exist:
+      | user        | course | role           |
+      | teacher1    | C1     | editingteacher |
+      | assistant1  | C1     | teacher        |
+      | student1    | C1     | student        |
+      | student2    | C1     | student        |
+      | student3    | C1     | student        |
+    And the following "groups" exist:
+      | name | course | idnumber |
+      | Group 1 | C1 | G1 |
+      | Group 2 | C1 | G2 |
+    And the following "groupings" exist:
+      | name        | course | idnumber |
+      | Grouping 1  | C1     | GG1      |
+      | Grouping 2  | C1     | GG2      |
+      | Grouping 3  | C1     | GG3      |
+    And the following "group members" exist:
+      | user        | group |
+      | student1    | G1    |
+      | student2    | G2    |
+      | student3    | G1    |
+      | student3    | G2    |
+      | assistant1  | G1    |
+    And the following "grouping groups" exist:
+      | grouping | group |
+      | GG1      | G1    |
+      | GG2      | G2    |
+      | GG3      | G1    |
+      | GG3      | G2    |
+
+  Scenario: Check that Added module information is displayed respecting view capability
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Recent activity" block
+    When I add a "Forum" to section "1" and I fill the form with:
+      | name        | ForumVisibleGroups |
+      | Description | No description     |
+      | groupmode   | Visible groups     |
+    And I add a "Forum" to section "1" and I fill the form with:
+      | name        | ForumSeparateGroups |
+      | Description | No description      |
+      | groupmode   | Separate groups     |
+    And I add a "Forum" to section "1" and I fill the form with:
+      | name        | ForumHidden    |
+      | Description | No description |
+      | Availability | 0             |
+    And I add a "Forum" to section "1" and I fill the form with:
+      | name        | ForumNoGroups  |
+      | Description | No description |
+      | groupmode   | No groups      |
+    And I add a "Forum" to section "2" and I fill the form with:
+      | name                | ForumVisibleGroupsG1 |
+      | Description         | No description       |
+      | groupmode           | Visible groups       |
+      | Grouping            | Grouping 1           |
+      | Access restrictions | Grouping: Grouping 1 |
+    And I add a "Forum" to section "2" and I fill the form with:
+      | name                | ForumSeparateGroupsG1 |
+      | Description         | No description        |
+      | groupmode           | Separate groups       |
+      | Grouping            | Grouping 1            |
+      | Access restrictions | Grouping: Grouping 1  |
+    And I add a "Forum" to section "3" and I fill the form with:
+      | name                | ForumVisibleGroupsG2 |
+      | Description         | No description       |
+      | groupmode           | Visible groups       |
+      | Grouping            | Grouping 2           |
+      | Access restrictions | Grouping: Grouping 2 |
+    And I add a "Forum" to section "3" and I fill the form with:
+      | name                | ForumSeparateGroupsG2 |
+      | Description         | No description        |
+      | groupmode           | Separate groups       |
+      | Grouping            | Grouping 2            |
+      | Access restrictions | Grouping: Grouping 2  |
+    Then I should see "ForumVisibleGroups" in the "Recent activity" "block"
+    And I should see "ForumSeparateGroups" in the "Recent activity" "block"
+    And I should see "ForumNoGroups" in the "Recent activity" "block"
+    And I should see "ForumHidden" in the "Recent activity" "block"
+    And I should see "ForumVisibleGroupsG1" in the "Recent activity" "block"
+    And I should see "ForumSeparateGroupsG1" in the "Recent activity" "block"
+    And I should see "ForumVisibleGroupsG2" in the "Recent activity" "block"
+    And I should see "ForumSeparateGroupsG2" in the "Recent activity" "block"
+    And I log out
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "ForumVisibleGroups" in the "Recent activity" "block"
+    And I should see "ForumSeparateGroups" in the "Recent activity" "block"
+    And I should see "ForumNoGroups" in the "Recent activity" "block"
+    And I should not see "ForumHidden" in the "Recent activity" "block"
+    And I should see "ForumVisibleGroupsG1" in the "Recent activity" "block"
+    And I should see "ForumSeparateGroupsG1" in the "Recent activity" "block"
+    And I should not see "ForumVisibleGroupsG2" in the "Recent activity" "block"
+    And I should not see "ForumSeparateGroupsG2" in the "Recent activity" "block"
+    And I log out
+    And I log in as "student2"
+    And I am on "Course 1" course homepage
+    And I should see "ForumVisibleGroups" in the "Recent activity" "block"
+    And I should see "ForumSeparateGroups" in the "Recent activity" "block"
+    And I should see "ForumNoGroups" in the "Recent activity" "block"
+    And I should not see "ForumHidden" in the "Recent activity" "block"
+    And I should not see "ForumVisibleGroupsG1" in the "Recent activity" "block"
+    And I should not see "ForumSeparateGroupsG1" in the "Recent activity" "block"
+    And I should see "ForumVisibleGroupsG2" in the "Recent activity" "block"
+    And I should see "ForumSeparateGroupsG2" in the "Recent activity" "block"
+    And I log out
+    And I log in as "student3"
+    And I am on "Course 1" course homepage
+    And I should see "ForumVisibleGroups" in the "Recent activity" "block"
+    And I should see "ForumSeparateGroups" in the "Recent activity" "block"
+    And I should see "ForumNoGroups" in the "Recent activity" "block"
+    And I should not see "ForumHidden" in the "Recent activity" "block"
+    And I should see "ForumVisibleGroupsG1" in the "Recent activity" "block"
+    And I should see "ForumSeparateGroupsG1" in the "Recent activity" "block"
+    And I should see "ForumVisibleGroupsG2" in the "Recent activity" "block"
+    And I should see "ForumSeparateGroupsG2" in the "Recent activity" "block"
+    And I log out
+    # Teachers have capability to see all groups and hidden activities
+    And I log in as "assistant1"
+    And I am on "Course 1" course homepage
+    And I should see "ForumHidden" in the "Recent activity" "block"
+    And I should see "ForumVisibleGroupsG1" in the "Recent activity" "block"
+    And I should see "ForumSeparateGroupsG1" in the "Recent activity" "block"
+    And I should see "ForumVisibleGroupsG2" in the "Recent activity" "block"
+    And I should see "ForumSeparateGroupsG2" in the "Recent activity" "block"
+    And I log out
+
+  Scenario: Updates and deletes in recent activity block
+    When I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Recent activity" block
+    And I add a "Forum" to section "1" and I fill the form with:
+      | name        | ForumNew       |
+      | Description | No description |
+    Then I should see "Added Forum" in the "Recent activity" "block"
+    And I should see "ForumNew" in the "Recent activity" "block"
+    And I log out
+    And I wait "1" seconds
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should see "Added Forum" in the "Recent activity" "block"
+    And I should see "ForumNew" in the "Recent activity" "block"
+    And I log out
+    # Update forum as a teacher after a second to ensure we have a new timestamp for recent activity.
+    And I wait "1" seconds
+    # Update forum as a teacher
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage
+    And I follow "ForumNew"
+    And I navigate to "Edit settings" in current page administration
+    And I set the following fields to these values:
+      | name | ForumUpdated |
+    And I press "Save and return to course"
+    And I log out
+    And I wait "1" seconds
+    # Student 1 already saw that forum was created, now he can see that forum was updated
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should not see "Added Forum" in the "Recent activity" "block"
+    And I should not see "ForumNew" in the "Recent activity" "block"
+    And I should see "Updated Forum" in the "Recent activity" "block"
+    And I should see "ForumUpdated" in the "Recent activity" "block"
+    And I log out
+    And I wait "1" seconds
+    # Student 2 has bigger interval and he can see one entry that forum was created but with the new name
+    And I log in as "student2"
+    And I am on "Course 1" course homepage
+    And I should see "Added Forum" in the "Recent activity" "block"
+    And I should not see "ForumNew" in the "Recent activity" "block"
+    And I should not see "Updated Forum" in the "Recent activity" "block"
+    And I should see "ForumUpdated" in the "Recent activity" "block"
+    And I log out
+    And I wait "1" seconds
+    # Delete forum as a teacher
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I delete "ForumUpdated" activity
+    And I run all adhoc tasks
+    And I log out
+    And I wait "1" seconds
+    # Students 1 and 2 see that forum was deleted
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should not see "Added Forum" in the "Recent activity" "block"
+    And I should not see "ForumNew" in the "Recent activity" "block"
+    And I should not see "Updated Forum" in the "Recent activity" "block"
+    And I should not see "ForumUpdated" in the "Recent activity" "block"
+    And I should see "Deleted Forum" in the "Recent activity" "block"
+    And I log out
+    And I wait "1" seconds
+    # Student 3 never knew that forum was created, so he does not see anything
+    And I log in as "student3"
+    And I am on "Course 1" course homepage
+    And I should not see "Added Forum" in the "Recent activity" "block"
+    And I should not see "ForumNew" in the "Recent activity" "block"
+    And I should not see "Updated Forum" in the "Recent activity" "block"
+    And I should not see "ForumUpdated" in the "Recent activity" "block"
+    And I should not see "Deleted Forum" in the "Recent activity" "block"
+    And I log out
diff --git a/recent_activity/version.php b/recent_activity/version.php
new file mode 100644
index 0000000..1943157
--- /dev/null
+++ b/recent_activity/version.php
@@ -0,0 +1,30 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_recent_activity
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_recent_activity'; // Full name of the plugin (used for diagnostics)
+$plugin->cron      = 24*3600;           // Cron interval 1 day.
\ No newline at end of file
diff --git a/rss_client/backup/moodle1/lib.php b/rss_client/backup/moodle1/lib.php
new file mode 100644
index 0000000..b87e0a3
--- /dev/null
+++ b/rss_client/backup/moodle1/lib.php
@@ -0,0 +1,48 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Provides support for the conversion of moodle1 backup to the moodle2 format
+ *
+ * @package    block_rss_client
+ * @copyright  2012 Paul Nicholls
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Block conversion handler for rss_client
+ */
+class moodle1_block_rss_client_handler extends moodle1_block_handler {
+    public function process_block(array $data) {
+        parent::process_block($data);
+        $instanceid = $data['id'];
+        $contextid = $this->converter->get_contextid(CONTEXT_BLOCK, $data['id']);
+
+        // Moodle 1.9 backups do not include sufficient data to restore feeds, so we need an empty shell rss_client.xml
+        // for the restore process to find
+        $this->open_xml_writer("course/blocks/{$data['name']}_{$instanceid}/rss_client.xml");
+        $this->xmlwriter->begin_tag('block', array('id' => $instanceid, 'contextid' => $contextid, 'blockname' => 'rss_client'));
+        $this->xmlwriter->begin_tag('rss_client', array('id' => $instanceid));
+        $this->xmlwriter->full_tag('feeds', '');
+        $this->xmlwriter->end_tag('rss_client');
+        $this->xmlwriter->end_tag('block');
+        $this->close_xml_writer();
+
+        return $data;
+    }
+}
diff --git a/rss_client/backup/moodle2/backup_rss_client_block_task.class.php b/rss_client/backup/moodle2/backup_rss_client_block_task.class.php
new file mode 100644
index 0000000..f3500c0
--- /dev/null
+++ b/rss_client/backup/moodle2/backup_rss_client_block_task.class.php
@@ -0,0 +1,54 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * @package    block_rss_client
+ * @subpackage backup-moodle2
+ * @copyright 2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once($CFG->dirroot . '/blocks/rss_client/backup/moodle2/backup_rss_client_stepslib.php'); // We have structure steps
+
+/**
+ * Specialised backup task for the rss_client block
+ * (has own DB structures to backup)
+ *
+ * TODO: Finish phpdocs
+ */
+class backup_rss_client_block_task extends backup_block_task {
+
+    protected function define_my_settings() {
+    }
+
+    protected function define_my_steps() {
+        // rss_client has one structure step
+        $this->add_step(new backup_rss_client_block_structure_step('rss_client_structure', 'rss_client.xml'));
+    }
+
+    public function get_fileareas() {
+        return array(); // No associated fileareas
+    }
+
+    public function get_configdata_encoded_attributes() {
+        return array(); // No special handling of configdata
+    }
+
+    static public function encode_content_links($content) {
+        return $content; // No special encoding of links
+    }
+}
+
diff --git a/rss_client/backup/moodle2/backup_rss_client_stepslib.php b/rss_client/backup/moodle2/backup_rss_client_stepslib.php
new file mode 100644
index 0000000..437d708
--- /dev/null
+++ b/rss_client/backup/moodle2/backup_rss_client_stepslib.php
@@ -0,0 +1,83 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * @package    block_rss_client
+ * @subpackage backup-moodle2
+ * @copyright 2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Define all the backup steps that wll be used by the backup_rss_client_block_task
+ */
+
+/**
+ * Define the complete forum structure for backup, with file and id annotations
+ */
+class backup_rss_client_block_structure_step extends backup_block_structure_step {
+
+    protected function define_structure() {
+        global $DB;
+
+        // Get the block
+        $block = $DB->get_record('block_instances', array('id' => $this->task->get_blockid()));
+        // Extract configdata
+        $config = unserialize(base64_decode($block->configdata));
+        // Get array of used rss feeds
+        if (!empty($config->rssid)) {
+            $feedids = $config->rssid;
+            // Get the IN corresponding query
+            list($in_sql, $in_params) = $DB->get_in_or_equal($feedids);
+            // Define all the in_params as sqlparams
+            foreach ($in_params as $key => $value) {
+                $in_params[$key] = backup_helper::is_sqlparam($value);
+            }
+        }
+
+        // Define each element separated
+
+        $rss_client = new backup_nested_element('rss_client', array('id'), null);
+
+        $feeds = new backup_nested_element('feeds');
+
+        $feed = new backup_nested_element('feed', array('id'), array(
+            'title', 'preferredtitle', 'description', 'shared',
+            'url'));
+
+        // Build the tree
+
+        $rss_client->add_child($feeds);
+        $feeds->add_child($feed);
+
+        // Define sources
+
+        $rss_client->set_source_array(array((object)array('id' => $this->task->get_blockid())));
+
+        // Only if there are feeds
+        if (!empty($config->rssid)) {
+            $feed->set_source_sql("
+                SELECT *
+                  FROM {block_rss_client}
+                 WHERE id $in_sql", $in_params);
+        }
+
+        // Annotations (none)
+
+        // Return the root element (rss_client), wrapped into standard block structure
+        return $this->prepare_block_structure($rss_client);
+    }
+}
diff --git a/rss_client/backup/moodle2/restore_rss_client_block_task.class.php b/rss_client/backup/moodle2/restore_rss_client_block_task.class.php
new file mode 100644
index 0000000..cf99891
--- /dev/null
+++ b/rss_client/backup/moodle2/restore_rss_client_block_task.class.php
@@ -0,0 +1,58 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * @package    block_rss_client
+ * @subpackage backup-moodle2
+ * @copyright 2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once($CFG->dirroot . '/blocks/rss_client/backup/moodle2/restore_rss_client_stepslib.php'); // We have structure steps
+
+/**
+ * Specialised restore task for the rss_client block
+ * (has own DB structures to backup)
+ *
+ * TODO: Finish phpdocs
+ */
+class restore_rss_client_block_task extends restore_block_task {
+
+    protected function define_my_settings() {
+    }
+
+    protected function define_my_steps() {
+        // rss_client has one structure step
+        $this->add_step(new restore_rss_client_block_structure_step('rss_client_structure', 'rss_client.xml'));
+    }
+
+    public function get_fileareas() {
+        return array(); // No associated fileareas
+    }
+
+    public function get_configdata_encoded_attributes() {
+        return array(); // No special handling of configdata
+    }
+
+    static public function define_decode_contents() {
+        return array();
+    }
+
+    static public function define_decode_rules() {
+        return array();
+    }
+}
+
diff --git a/rss_client/backup/moodle2/restore_rss_client_stepslib.php b/rss_client/backup/moodle2/restore_rss_client_stepslib.php
new file mode 100644
index 0000000..cdd9783
--- /dev/null
+++ b/rss_client/backup/moodle2/restore_rss_client_stepslib.php
@@ -0,0 +1,90 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * @package    block_rss_client
+ * @subpackage backup-moodle2
+ * @copyright 2003 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Define all the restore steps that wll be used by the restore_rss_client_block_task
+ */
+
+/**
+ * Define the complete rss_client  structure for restore
+ */
+class restore_rss_client_block_structure_step extends restore_structure_step {
+
+    protected function define_structure() {
+
+        $paths = array();
+
+        $paths[] = new restore_path_element('block', '/block', true);
+        $paths[] = new restore_path_element('rss_client', '/block/rss_client');
+        $paths[] = new restore_path_element('feed', '/block/rss_client/feeds/feed');
+
+        return $paths;
+    }
+
+    public function process_block($data) {
+        global $DB;
+
+        $data = (object)$data;
+        $feedsarr = array(); // To accumulate feeds
+
+        // For any reason (non multiple, dupe detected...) block not restored, return
+        if (!$this->task->get_blockid()) {
+            return;
+        }
+
+        // Iterate over all the feed elements, creating them if needed
+        if (isset($data->rss_client['feeds']['feed'])) {
+            foreach ($data->rss_client['feeds']['feed'] as $feed) {
+                $feed = (object)$feed;
+                // Look if the same feed is available by url and (shared or userid)
+                $select = 'url = :url AND (shared = 1 OR userid = :userid)';
+                $params = array('url' => $feed->url, 'userid' => $this->task->get_userid());
+                // The feed already exists, use it
+                if ($feedid = $DB->get_field_select('block_rss_client', 'id', $select, $params, IGNORE_MULTIPLE)) {
+                    $feedsarr[] = $feedid;
+
+                // The feed doesn't exist, create it
+                } else {
+                    $feed->userid = $this->task->get_userid();
+                    $feedid = $DB->insert_record('block_rss_client', $feed);
+                    $feedsarr[] = $feedid;
+                }
+            }
+        }
+
+        // Adjust the serialized configdata->rssid to the created/mapped feeds
+        // Get the configdata
+        $configdata = $DB->get_field('block_instances', 'configdata', array('id' => $this->task->get_blockid()));
+        // Extract configdata
+        $config = unserialize(base64_decode($configdata));
+        if (empty($config)) {
+            $config = new stdClass();
+        }
+        // Set array of used rss feeds
+        $config->rssid = $feedsarr;
+        // Serialize back the configdata
+        $configdata = base64_encode(serialize($config));
+        // Set the configdata back
+        $DB->set_field('block_instances', 'configdata', $configdata, array('id' => $this->task->get_blockid()));
+    }
+}
diff --git a/rss_client/block_rss_client.php b/rss_client/block_rss_client.php
new file mode 100644
index 0000000..bc6d7c5
--- /dev/null
+++ b/rss_client/block_rss_client.php
@@ -0,0 +1,387 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Contains block_rss_client
+ * @package    block_rss_client
+ * @copyright  Daryl Hawes
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL
+ */
+
+/**
+ * A block which displays Remote feeds
+ *
+ * @package   block_rss_client
+ * @copyright  Daryl Hawes
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL
+ */
+
+ class block_rss_client extends block_base {
+    /** The maximum time in seconds that cron will wait between attempts to retry failing RSS feeds. */
+    const CLIENT_MAX_SKIPTIME = 43200; // 60 * 60 * 12 seconds.
+
+    /** @var bool track whether any of the output feeds have recorded failures */
+    private $hasfailedfeeds = false;
+
+    function init() {
+        $this->title = get_string('pluginname', 'block_rss_client');
+    }
+
+    function applicable_formats() {
+        return array('all' => true, 'tag' => false);   // Needs work to make it work on tags MDL-11960
+    }
+
+    function specialization() {
+        // After the block has been loaded we customize the block's title display
+        if (!empty($this->config) && !empty($this->config->title)) {
+            // There is a customized block title, display it
+            $this->title = $this->config->title;
+        } else {
+            // No customized block title, use localized remote news feed string
+            $this->title = get_string('remotenewsfeed', 'block_rss_client');
+        }
+    }
+
+    /**
+     * Gets the footer, which is the channel link of the last feed in our list of feeds
+     *
+     * @param array $feedrecords The feed records from the database.
+     * @return block_rss_client\output\footer|null The renderable footer or null if none should be displayed.
+     */
+    protected function get_footer($feedrecords) {
+        global $PAGE;
+        $footer = null;
+
+        if ($this->config->block_rss_client_show_channel_link) {
+            global $CFG;
+            require_once($CFG->libdir.'/simplepie/moodle_simplepie.php');
+
+            $feedrecord     = array_pop($feedrecords);
+            $feed           = new moodle_simplepie($feedrecord->url);
+            $channellink    = new moodle_url($feed->get_link());
+
+            if (!empty($channellink)) {
+                $footer = new block_rss_client\output\footer($channellink);
+            }
+        }
+
+        if ($this->hasfailedfeeds) {
+            if (has_any_capability(['block/rss_client:manageownfeeds', 'block/rss_client:manageanyfeeds'], $this->context)) {
+                if ($footer === null) {
+                    $footer = new block_rss_client\output\footer();
+                }
+                $manageurl = new moodle_url('/blocks/rss_client/managefeeds.php', ['courseid' => $PAGE->course->id]);
+                $footer->set_failed($manageurl);
+            }
+        }
+
+        return $footer;
+    }
+
+    function get_content() {
+        global $CFG, $DB;
+
+        if ($this->content !== NULL) {
+            return $this->content;
+        }
+
+        // initalise block content object
+        $this->content = new stdClass;
+        $this->content->text   = '';
+        $this->content->footer = '';
+
+        if (empty($this->instance)) {
+            return $this->content;
+        }
+
+        if (!isset($this->config)) {
+            // The block has yet to be configured - just display configure message in
+            // the block if user has permission to configure it
+
+            if (has_capability('block/rss_client:manageanyfeeds', $this->context)) {
+                $this->content->text = get_string('feedsconfigurenewinstance2', 'block_rss_client');
+            }
+
+            return $this->content;
+        }
+
+        // How many feed items should we display?
+        $maxentries = 5;
+        if ( !empty($this->config->shownumentries) ) {
+            $maxentries = intval($this->config->shownumentries);
+        }elseif( isset($CFG->block_rss_client_num_entries) ) {
+            $maxentries = intval($CFG->block_rss_client_num_entries);
+        }
+
+        /* ---------------------------------
+         * Begin Normal Display of Block Content
+         * --------------------------------- */
+
+        $renderer = $this->page->get_renderer('block_rss_client');
+        $block = new \block_rss_client\output\block();
+
+        if (!empty($this->config->rssid)) {
+            list($rssidssql, $params) = $DB->get_in_or_equal($this->config->rssid);
+            $rssfeeds = $DB->get_records_select('block_rss_client', "id $rssidssql", $params);
+
+            if (!empty($rssfeeds)) {
+                $showtitle = false;
+                if (count($rssfeeds) > 1) {
+                    // When many feeds show the title for each feed.
+                    $showtitle = true;
+                }
+
+                foreach ($rssfeeds as $feed) {
+                    if ($renderablefeed = $this->get_feed($feed, $maxentries, $showtitle)) {
+                        $block->add_feed($renderablefeed);
+                    }
+                }
+
+                $footer = $this->get_footer($rssfeeds);
+            }
+        }
+
+        $this->content->text = $renderer->render_block($block);
+        if (isset($footer)) {
+            $this->content->footer = $renderer->render_footer($footer);
+        }
+
+        return $this->content;
+    }
+
+
+    function instance_allow_multiple() {
+        return true;
+    }
+
+    function has_config() {
+        return true;
+    }
+
+    function instance_allow_config() {
+        return true;
+    }
+
+    /**
+     * Returns the html of a feed to be displaed in the block
+     *
+     * @param mixed feedrecord The feed record from the database
+     * @param int maxentries The maximum number of entries to be displayed
+     * @param boolean showtitle Should the feed title be displayed in html
+     * @return block_rss_client\output\feed|null The renderable feed or null of there is an error
+     */
+    public function get_feed($feedrecord, $maxentries, $showtitle) {
+        global $CFG;
+        require_once($CFG->libdir.'/simplepie/moodle_simplepie.php');
+
+        if ($feedrecord->skipuntil) {
+            // Last attempt to gather this feed via cron failed - do not try to fetch it now.
+            $this->hasfailedfeeds = true;
+            return null;
+        }
+
+        $simplepiefeed = new moodle_simplepie($feedrecord->url);
+
+        if(isset($CFG->block_rss_client_timeout)){
+            $simplepiefeed->set_cache_duration($CFG->block_rss_client_timeout * 60);
+        }
+
+        if ($simplepiefeed->error()) {
+            debugging($feedrecord->url .' Failed with code: '.$simplepiefeed->error());
+            return null;
+        }
+
+        if(empty($feedrecord->preferredtitle)){
+            // Simplepie does escape HTML entities.
+            $feedtitle = $this->format_title($simplepiefeed->get_title());
+        }else{
+            // Moodle custom title does not does escape HTML entities.
+            $feedtitle = $this->format_title(s($feedrecord->preferredtitle));
+        }
+
+        if (empty($this->config->title)){
+            //NOTE: this means the 'last feed' displayed wins the block title - but
+            //this is exiting behaviour..
+            $this->title = strip_tags($feedtitle);
+        }
+
+        $feed = new \block_rss_client\output\feed($feedtitle, $showtitle, $this->config->block_rss_client_show_channel_image);
+
+        if ($simplepieitems = $simplepiefeed->get_items(0, $maxentries)) {
+            foreach ($simplepieitems as $simplepieitem) {
+                try {
+                    $item = new \block_rss_client\output\item(
+                        $simplepieitem->get_id(),
+                        new moodle_url($simplepieitem->get_link()),
+                        $simplepieitem->get_title(),
+                        $simplepieitem->get_description(),
+                        new moodle_url($simplepieitem->get_permalink()),
+                        $simplepieitem->get_date('U'),
+                        $this->config->display_description
+                    );
+
+                    $feed->add_item($item);
+                } catch (moodle_exception $e) {
+                    // If there is an error with the RSS item, we don't
+                    // want to crash the page. Specifically, moodle_url can
+                    // throw an exception of the param is an extremely
+                    // malformed url.
+                    debugging($e->getMessage());
+                }
+            }
+        }
+
+        // Feed image.
+        if ($imageurl = $simplepiefeed->get_image_url()) {
+            try {
+                $image = new \block_rss_client\output\channel_image(
+                    new moodle_url($imageurl),
+                    $simplepiefeed->get_image_title(),
+                    new moodle_url($simplepiefeed->get_image_link())
+                );
+
+                $feed->set_image($image);
+            } catch (moodle_exception $e) {
+                // If there is an error with the RSS image, we don'twant to
+                // crash the page. Specifically, moodle_url can throw an
+                // exception if the param is an extremely malformed url.
+                debugging($e->getMessage());
+            }
+        }
+
+        return $feed;
+    }
+
+    /**
+     * Strips a large title to size and adds ... if title too long
+     * This function does not escape HTML entities, so they have to be escaped
+     * before being passed here.
+     *
+     * @param string title to shorten
+     * @param int max character length of title
+     * @return string title shortened if necessary
+     */
+    function format_title($title,$max=64) {
+
+        if (core_text::strlen($title) <= $max) {
+            return $title;
+        } else {
+            return core_text::substr($title, 0, $max - 3) . '...';
+        }
+    }
+
+    /**
+     * cron - goes through all the feeds. If the feed has a skipuntil value
+     * that is less than the current time cron will attempt to retrieve it
+     * with the cache duration set to 0 in order to force the retrieval of
+     * the item and refresh the cache.
+     *
+     * If a feed fails then the skipuntil time of that feed is set to be
+     * later than the next expected cron time. The amount of time will
+     * increase each time the fetch fails until the maximum is reached.
+     *
+     * If a feed that has been failing is successfully retrieved it will
+     * go back to being handled as though it had never failed.
+     *
+     * CRON should therefor process requests for permanently broken RSS
+     * feeds infrequently, and temporarily unavailable feeds will be tried
+     * less often until they become available again.
+     *
+     * @return boolean Always returns true
+     */
+    function cron() {
+        global $CFG, $DB;
+        require_once($CFG->libdir.'/simplepie/moodle_simplepie.php');
+
+        // Get the legacy cron time, strangely the cron property of block_base
+        // does not seem to get set. This means we must retrive it here.
+        $this->cron = $DB->get_field('block', 'cron', array('name' => 'rss_client'));
+
+        // We are going to measure execution times
+        $starttime =  microtime();
+        $starttimesec = time();
+
+        // Fetch all site feeds.
+        $rs = $DB->get_recordset('block_rss_client');
+        $counter = 0;
+        mtrace('');
+        foreach ($rs as $rec) {
+            mtrace('    ' . $rec->url . ' ', '');
+
+            // Skip feed if it failed recently.
+            if ($starttimesec < $rec->skipuntil) {
+                mtrace('skipping until ' . userdate($rec->skipuntil));
+                continue;
+            }
+
+            // Fetch the rss feed, using standard simplepie caching
+            // so feeds will be renewed only if cache has expired
+            core_php_time_limit::raise(60);
+
+            $feed =  new moodle_simplepie();
+            // set timeout for longer than normal to be agressive at
+            // fetching feeds if possible..
+            $feed->set_timeout(40);
+            $feed->set_cache_duration(0);
+            $feed->set_feed_url($rec->url);
+            $feed->init();
+
+            if ($feed->error()) {
+                // Skip this feed (for an ever-increasing time if it keeps failing).
+                $rec->skiptime = $this->calculate_skiptime($rec->skiptime);
+                $rec->skipuntil = time() + $rec->skiptime;
+                $DB->update_record('block_rss_client', $rec);
+                mtrace("Error: could not load/find the RSS feed - skipping for {$rec->skiptime} seconds.");
+            } else {
+                mtrace ('ok');
+                // It worked this time, so reset the skiptime.
+                if ($rec->skiptime > 0) {
+                    $rec->skiptime = 0;
+                    $rec->skipuntil = 0;
+                    $DB->update_record('block_rss_client', $rec);
+                }
+                // Only increase the counter when a feed is sucesfully refreshed.
+                $counter ++;
+            }
+        }
+        $rs->close();
+
+        // Show times
+        mtrace($counter . ' feeds refreshed (took ' . microtime_diff($starttime, microtime()) . ' seconds)');
+
+        return true;
+    }
+
+    /**
+     * Calculates a new skip time for a record based on the current skip time.
+     *
+     * @param int $currentskip The curreent skip time of a record.
+     * @return int A new skip time that should be set.
+     */
+    protected function calculate_skiptime($currentskip) {
+        // The default time to skiptime.
+        $newskiptime = $this->cron * 1.1;
+        if ($currentskip > 0) {
+            // Double the last time.
+            $newskiptime = $currentskip * 2;
+        }
+        if ($newskiptime > self::CLIENT_MAX_SKIPTIME) {
+            // Do not allow the skip time to increase indefinatly.
+            $newskiptime = self::CLIENT_MAX_SKIPTIME;
+        }
+        return $newskiptime;
+    }
+}
diff --git a/rss_client/classes/output/block.php b/rss_client/classes/output/block.php
new file mode 100644
index 0000000..7789f0c
--- /dev/null
+++ b/rss_client/classes/output/block.php
@@ -0,0 +1,104 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Contains class block_rss_client\output\block
+ *
+ * @package   block_rss_client
+ * @copyright 2015 Howard County Public School System
+ * @author    Brendan Anderson <brendan_anderson@hcpss.org>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_rss_client\output;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Class to help display an RSS Feeds block
+ *
+ * @package   block_rss_client
+ * @copyright 2016 Howard County Public School System
+ * @author    Brendan Anderson <brendan_anderson@hcpss.org>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block implements \renderable, \templatable {
+
+    /**
+     * An array of renderable feeds
+     *
+     * @var array
+     */
+    protected $feeds;
+
+    /**
+     * Contruct
+     *
+     * @param array $feeds An array of renderable feeds
+     */
+    public function __construct(array $feeds = array()) {
+        $this->feeds = $feeds;
+    }
+
+    /**
+     * Prepare data for use in a template
+     *
+     * @param \renderer_base $output
+     * @return array
+     */
+    public function export_for_template(\renderer_base $output) {
+        $data = array('feeds' => array());
+
+        foreach ($this->feeds as $feed) {
+            $data['feeds'][] = $feed->export_for_template($output);
+        }
+
+        return $data;
+    }
+
+    /**
+     * Add a feed
+     *
+     * @param \block_rss_client\output\feed $feed
+     * @return \block_rss_client\output\block
+     */
+    public function add_feed(feed $feed) {
+        $this->feeds[] = $feed;
+
+        return $this;
+    }
+
+    /**
+     * Set the feeds
+     *
+     * @param array $feeds
+     * @return \block_rss_client\output\block
+     */
+    public function set_feeds(array $feeds) {
+        $this->feeds = $feeds;
+
+        return $this;
+    }
+
+    /**
+     * Get feeds
+     *
+     * @return array
+     */
+    public function get_feeds() {
+        return $this->feeds;
+    }
+}
diff --git a/rss_client/classes/output/channel_image.php b/rss_client/classes/output/channel_image.php
new file mode 100644
index 0000000..af9e22f
--- /dev/null
+++ b/rss_client/classes/output/channel_image.php
@@ -0,0 +1,151 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Contains class block_rss_client\output\channel_image
+ *
+ * @package   block_rss_client
+ * @copyright 2016 Howard County Public School System
+ * @author    Brendan Anderson <brendan_anderson@hcpss.org>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_rss_client\output;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Class to display RSS channel images
+ *
+ * @package   block_rss_client
+ * @copyright 2016 Howard County Public School System
+ * @author    Brendan Anderson <brendan_anderson@hcpss.org>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class channel_image implements \renderable, \templatable {
+
+    /**
+     * The URL location of the image
+     *
+     * @var string
+     */
+    protected $url;
+
+    /**
+     * The title of the image
+     *
+     * @var string
+     */
+    protected $title;
+
+    /**
+     * The URL of the image link
+     *
+     * @var string
+     */
+    protected $link;
+
+    /**
+     * Contructor
+     *
+     * @param \moodle_url $url The URL location of the image
+     * @param string $title The title of the image
+     * @param \moodle_url $link The URL of the image link
+     */
+    public function __construct(\moodle_url $url, $title, \moodle_url $link = null) {
+        $this->url      = $url;
+        $this->title    = $title;
+        $this->link     = $link;
+    }
+
+    /**
+     * Export this for use in a mustache template context.
+     *
+     * @see templatable::export_for_template()
+     * @param renderer_base $output
+     * @return array The data for the template
+     */
+    public function export_for_template(\renderer_base $output) {
+        return array(
+            'url'   => clean_param($this->url, PARAM_URL),
+            'title' => $this->title,
+            'link'  => clean_param($this->link, PARAM_URL),
+        );
+    }
+
+    /**
+     * Set the URL
+     *
+     * @param \moodle_url $url
+     * @return \block_rss_client\output\channel_image
+     */
+    public function set_url(\moodle_url $url) {
+        $this->url = $url;
+
+        return $this;
+    }
+
+    /**
+     * Get the URL
+     *
+     * @return \moodle_url
+     */
+    public function get_url() {
+        return $this->url;
+    }
+
+    /**
+     * Set the title
+     *
+     * @param string $title
+     * @return \block_rss_client\output\channel_image
+     */
+    public function set_title($title) {
+        $this->title = $title;
+
+        return $this;
+    }
+
+    /**
+     * Get the title
+     *
+     * @return string
+     */
+    public function get_title() {
+        return $this->title;
+    }
+
+    /**
+     * Set the link
+     *
+     * @param \moodle_url $link
+     * @return \block_rss_client\output\channel_image
+     */
+    public function set_link($link) {
+        $this->link = $link;
+
+        return $this;
+    }
+
+    /**
+     * Get the link
+     *
+     * @return \moodle_url
+     */
+    public function get_link() {
+        return $this->link;
+    }
+}
diff --git a/rss_client/classes/output/feed.php b/rss_client/classes/output/feed.php
new file mode 100644
index 0000000..02f7e2d
--- /dev/null
+++ b/rss_client/classes/output/feed.php
@@ -0,0 +1,224 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Contains class block_rss_client\output\feed
+ *
+ * @package   block_rss_client
+ * @copyright 2015 Howard County Public School System
+ * @author    Brendan Anderson <brendan_anderson@hcpss.org>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_rss_client\output;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Class to help display an RSS Feed
+ *
+ * @package   block_rss_client
+ * @copyright 2015 Howard County Public School System
+ * @author    Brendan Anderson <brendan_anderson@hcpss.org>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class feed implements \renderable, \templatable {
+
+    /**
+     * The feed's title
+     *
+     * @var string
+     */
+    protected $title = null;
+
+    /**
+     * An array of renderable feed items
+     *
+     * @var array
+     */
+    protected $items = array();
+
+    /**
+     * The channel image
+     *
+     * @var channel_image
+     */
+    protected $image = null;
+
+    /**
+     * Whether or not to show the title
+     *
+     * @var boolean
+     */
+    protected $showtitle;
+
+    /**
+     * Whether or not to show the channel image
+     *
+     * @var boolean
+     */
+    protected $showimage;
+
+    /**
+     * Contructor
+     *
+     * @param string $title The title of the RSS feed
+     * @param boolean $showtitle Whether to show the title
+     * @param boolean $showimage Whether to show the channel image
+     */
+    public function __construct($title, $showtitle = true, $showimage = true) {
+        $this->title = $title;
+        $this->showtitle = $showtitle;
+        $this->showimage = $showimage;
+    }
+
+    /**
+     * Export this for use in a mustache template context.
+     *
+     * @see templatable::export_for_template()
+     * @param renderer_base $output
+     * @return stdClass
+     */
+    public function export_for_template(\renderer_base $output) {
+        $data = array(
+            'title' => $this->showtitle ? $this->title : null,
+            'image' => null,
+            'items' => array(),
+        );
+
+        if ($this->showimage && $this->image) {
+            $data['image'] = $this->image->export_for_template($output);
+        }
+
+        foreach ($this->items as $item) {
+            $data['items'][] = $item->export_for_template($output);
+        }
+
+        return $data;
+    }
+
+    /**
+     * Set the feed title
+     *
+     * @param string $title
+     * @return \block_rss_client\output\feed
+     */
+    public function set_title($title) {
+        $this->title = $title;
+
+        return $this;
+    }
+
+    /**
+     * Get the feed title
+     *
+     * @return string
+     */
+    public function get_title() {
+        return $this->title;
+    }
+
+    /**
+     * Add an RSS item
+     *
+     * @param \block_rss_client\output\item $item
+     */
+    public function add_item(item $item) {
+        $this->items[] = $item;
+
+        return $this;
+    }
+
+    /**
+     * Set the RSS items
+     *
+     * @param array $items An array of renderable RSS items
+     */
+    public function set_items(array $items) {
+        $this->items = $items;
+
+        return $this;
+    }
+
+    /**
+     * Get the RSS items
+     *
+     * @return array An array of renderable RSS items
+     */
+    public function get_items() {
+        return $this->items;
+    }
+
+    /**
+     * Set the channel image
+     *
+     * @param \block_rss_client\output\channel_image $image
+     */
+    public function set_image(channel_image $image) {
+        $this->image = $image;
+    }
+
+    /**
+     * Get the channel image
+     *
+     * @return channel_image
+     */
+    public function get_image() {
+        return $this->image;
+    }
+
+    /**
+     * Set showtitle
+     *
+     * @param boolean $showtitle
+     * @return \block_rss_client\output\feed
+     */
+    public function set_showtitle($showtitle) {
+        $this->showtitle = boolval($showtitle);
+
+        return $this;
+    }
+
+    /**
+     * Get showtitle
+     *
+     * @return boolean
+     */
+    public function get_showtitle() {
+        return $this->showtitle;
+    }
+
+    /**
+     * Set showimage
+     *
+     * @param boolean $showimage
+     * @return \block_rss_client\output\feed
+     */
+    public function set_showimage($showimage) {
+        $this->showimage = boolval($showimage);
+
+        return $this;
+    }
+
+    /**
+     * Get showimage
+     *
+     * @return boolean
+     */
+    public function get_showimage() {
+        return $this->showimage;
+    }
+}
diff --git a/rss_client/classes/output/footer.php b/rss_client/classes/output/footer.php
new file mode 100644
index 0000000..c864df3
--- /dev/null
+++ b/rss_client/classes/output/footer.php
@@ -0,0 +1,111 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Contains class block_rss_client\output\footer
+ *
+ * @package   block_rss_client
+ * @copyright 2015 Howard County Public School System
+ * @author    Brendan Anderson <brendan_anderson@hcpss.org>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_rss_client\output;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Class to help display an RSS Block footer
+ *
+ * @package   block_rss_client
+ * @copyright 2015 Howard County Public School System
+ * @author    Brendan Anderson <brendan_anderson@hcpss.org>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class footer implements \renderable, \templatable {
+
+    /**
+     * The link provided in the RSS channel
+     *
+     * @var \moodle_url|null
+     */
+    protected $channelurl;
+
+    /**
+     * Link to manage feeds, only provided if a feed has failed.
+     *
+     * @var \moodle_url|null
+     */
+    protected $manageurl = null;
+
+    /**
+     * Constructor
+     *
+     * @param \moodle_url $channelurl (optional) The link provided in the RSS channel
+     */
+    public function __construct($channelurl = null) {
+        $this->channelurl = $channelurl;
+    }
+
+    /**
+     * Set the channel url
+     *
+     * @param \moodle_url $channelurl
+     * @return \block_rss_client\output\footer
+     */
+    public function set_channelurl(\moodle_url $channelurl) {
+        $this->channelurl = $channelurl;
+
+        return $this;
+    }
+
+    /**
+     * Record the fact that there is at least one failed feed (and the URL for viewing
+     * these failed feeds).
+     *
+     * @param \moodle_url $manageurl the URL to link to for more information
+     */
+    public function set_failed(\moodle_url $manageurl) {
+        $this->manageurl = $manageurl;
+    }
+
+    /**
+     * Get the channel url
+     *
+     * @return \moodle_url
+     */
+    public function get_channelurl() {
+        return $this->channelurl;
+    }
+
+    /**
+     * Export context for use in mustache templates
+     *
+     * @see templatable::export_for_template()
+     * @param renderer_base $output
+     * @return stdClass
+     */
+    public function export_for_template(\renderer_base $output) {
+        $data = new \stdClass();
+        $data->channellink = clean_param($this->channelurl, PARAM_URL);
+        if ($this->manageurl) {
+            $data->hasfailedfeeds = true;
+            $data->manageurl = clean_param($this->manageurl, PARAM_URL);
+        }
+
+        return $data;
+    }
+}
diff --git a/rss_client/classes/output/item.php b/rss_client/classes/output/item.php
new file mode 100644
index 0000000..e988304
--- /dev/null
+++ b/rss_client/classes/output/item.php
@@ -0,0 +1,286 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Contains class block_rss_client\output\feed
+ *
+ * @package   block_rss_client
+ * @copyright 2015 Howard County Public School System
+ * @author    Brendan Anderson <brendan_anderson@hcpss.org>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_rss_client\output;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Class to help display an RSS Item
+ *
+ * @package   block_rss_client
+ * @copyright 2015 Howard County Public School System
+ * @author    Brendan Anderson <brendan_anderson@hcpss.org>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class item implements \renderable, \templatable {
+
+    /**
+     * The unique id of the item
+     *
+     * @var string
+     */
+    protected $id;
+
+    /**
+     * The link to the item
+     *
+     * @var \moodle_url
+     */
+    protected $link;
+
+    /**
+     * The title of the item
+     *
+     * @var string
+     */
+    protected $title;
+
+    /**
+     * The description of the item
+     *
+     * @var string
+     */
+    protected $description;
+
+    /**
+     * The item's permalink
+     *
+     * @var \moodle_url
+     */
+    protected $permalink;
+
+    /**
+     * The publish date of the item in Unix timestamp format
+     *
+     * @var int
+     */
+    protected $timestamp;
+
+    /**
+     * Whether or not to show the item's description
+     *
+     * @var string
+     */
+    protected $showdescription;
+
+    /**
+     * Contructor
+     *
+     * @param string $id The id of the RSS item
+     * @param \moodle_url $link The URL of the RSS item
+     * @param string $title The title pf the RSS item
+     * @param string $description The description of the RSS item
+     * @param \moodle_url $permalink The permalink of the RSS item
+     * @param int $timestamp The Unix timestamp that represents the published date
+     * @param boolean $showdescription Whether or not to show the description
+     */
+    public function __construct($id, \moodle_url $link, $title, $description, \moodle_url $permalink, $timestamp,
+            $showdescription = true) {
+        $this->id               = $id;
+        $this->link             = $link;
+        $this->title            = $title;
+        $this->description      = $description;
+        $this->permalink        = $permalink;
+        $this->timestamp        = $timestamp;
+        $this->showdescription  = $showdescription;
+    }
+
+    /**
+     * Export context for use in mustache templates
+     *
+     * @see templatable::export_for_template()
+     * @param renderer_base $output
+     * @return array
+     */
+    public function export_for_template(\renderer_base $output) {
+        $data = array(
+            'id'            => $this->id,
+            'permalink'     => clean_param($this->permalink, PARAM_URL),
+            'datepublished' => $output->format_published_date($this->timestamp),
+            'link'          => clean_param($this->link, PARAM_URL),
+        );
+
+        // If the item does not have a title, create one from the description.
+        $title = $this->title;
+        if (!$title) {
+            $title = strip_tags($this->description);
+            $title = \core_text::substr($title, 0, 20) . '...';
+        }
+
+        // Allow the renderer to format the title and description.
+        $data['title']          = $output->format_title($title);
+        $data['description']    = $this->showdescription ? $output->format_description($this->description) : null;
+
+        return $data;
+    }
+
+    /**
+     * Set id
+     *
+     * @param string $id
+     * @return \block_rss_client\output\item
+     */
+    public function set_id($id) {
+        $this->id = $id;
+
+        return $this;
+    }
+
+    /**
+     * Get id
+     *
+     * @return string
+     */
+    public function get_id() {
+        return $this->id;
+    }
+
+    /**
+     * Set link
+     *
+     * @param \moodle_url $link
+     * @return \block_rss_client\output\item
+     */
+    public function set_link(\moodle_url $link) {
+        $this->link = $link;
+
+        return $this;
+    }
+
+    /**
+     * Get link
+     *
+     * @return \moodle_url
+     */
+    public function get_link() {
+        return $this->link;
+    }
+
+    /**
+     * Set title
+     *
+     * @param string $title
+     * @return \block_rss_client\output\item
+     */
+    public function set_title($title) {
+        $this->title = $title;
+
+        return $this;
+    }
+
+    /**
+     * Get title
+     *
+     * @return string
+     */
+    public function get_title() {
+        return $this->title;
+    }
+
+    /**
+     * Set description
+     *
+     * @param string $description
+     * @return \block_rss_client\output\item
+     */
+    public function set_description($description) {
+        $this->description = $description;
+
+        return $this;
+    }
+
+    /**
+     * Get description
+     *
+     * @return string
+     */
+    public function get_description() {
+        return $this->description;
+    }
+
+    /**
+     * Set permalink
+     *
+     * @param string $permalink
+     * @return \block_rss_client\output\item
+     */
+    public function set_permalink($permalink) {
+        $this->permalink = $permalink;
+
+        return $this;
+    }
+
+    /**
+     * Get permalink
+     *
+     * @return string
+     */
+    public function get_permalink() {
+        return $this->permalink;
+    }
+
+    /**
+     * Set timestamp
+     *
+     * @param int $timestamp
+     * @return \block_rss_client\output\item
+     */
+    public function set_timestamp($timestamp) {
+        $this->timestamp = $timestamp;
+
+        return $this;
+    }
+
+    /**
+     * Get timestamp
+     *
+     * @return string
+     */
+    public function get_timestamp() {
+        return $this->timestamp;
+    }
+
+    /**
+     * Set showdescription
+     *
+     * @param boolean $showdescription
+     * @return \block_rss_client\output\item
+     */
+    public function set_showdescription($showdescription) {
+        $this->showdescription = boolval($showdescription);
+
+        return $this;
+    }
+
+    /**
+     * Get showdescription
+     *
+     * @return boolean
+     */
+    public function get_showdescription() {
+        return $this->showdescription;
+    }
+}
diff --git a/rss_client/classes/output/renderer.php b/rss_client/classes/output/renderer.php
new file mode 100644
index 0000000..7a03280
--- /dev/null
+++ b/rss_client/classes/output/renderer.php
@@ -0,0 +1,121 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Contains class block_rss_client\output\block_renderer_html
+ *
+ * @package   block_rss_client
+ * @copyright 2015 Howard County Public School System
+ * @author    Brendan Anderson <brendan_anderson@hcpss.org>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_rss_client\output;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Renderer for RSS Client block
+ *
+ * @package   block_rss_client
+ * @copyright 2015 Howard County Public School System
+ * @author    Brendan Anderson <brendan_anderson@hcpss.org>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class renderer extends \plugin_renderer_base {
+
+    /**
+     * Render an RSS Item
+     *
+     * @param templatable $item
+     * @return string|boolean
+     */
+    public function render_item(\templatable $item) {
+        $data = $item->export_for_template($this);
+
+        return $this->render_from_template('block_rss_client/item', $data);
+    }
+
+    /**
+     * Render an RSS Feed
+     *
+     * @param templatable $feed
+     * @return string|boolean
+     */
+    public function render_feed(\templatable $feed) {
+        $data = $feed->export_for_template($this);
+
+        return $this->render_from_template('block_rss_client/feed', $data);
+    }
+
+    /**
+     * Render an RSS feeds block
+     *
+     * @param \templatable $block
+     * @return string|boolean
+     */
+    public function render_block(\templatable $block) {
+        $data = $block->export_for_template($this);
+
+        return $this->render_from_template('block_rss_client/block', $data);
+    }
+
+    /**
+     * Render the block footer
+     *
+     * @param templatable $footer
+     * @return string|boolean
+     */
+    public function render_footer(\templatable $footer) {
+        $data = $footer->export_for_template($this);
+
+        return $this->render_from_template('block_rss_client/footer', $data);
+    }
+
+    /**
+     * Format a timestamp to use as a published date
+     *
+     * @param int $timestamp Unix timestamp
+     * @return string
+     */
+    public function format_published_date($timestamp) {
+        return strftime(get_string('strftimerecentfull', 'langconfig'), $timestamp);
+        return date('j F Y, g:i a', $timestamp);
+    }
+
+    /**
+     * Format an RSS item title
+     *
+     * @param string $title
+     * @return string
+     */
+    public function format_title($title) {
+        return break_up_long_words($title, 30);
+    }
+
+    /**
+     * Format an RSS item description
+     *
+     * @param string $description
+     * @return string
+     */
+    public function format_description($description) {
+        $description = format_text($description, FORMAT_HTML, array('para' => false));
+        $description = break_up_long_words($description, 30);
+
+        return $description;
+    }
+}
diff --git a/rss_client/classes/privacy/provider.php b/rss_client/classes/privacy/provider.php
new file mode 100644
index 0000000..c1ea54f
--- /dev/null
+++ b/rss_client/classes/privacy/provider.php
@@ -0,0 +1,152 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+/**
+ * Privacy class for requesting user data.
+ *
+ * @package    block_rss_client
+ * @copyright  2018 Mihail Geshoski <mihail@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_rss_client\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+use \core_privacy\local\metadata\collection;
+use \core_privacy\local\request\contextlist;
+use \core_privacy\local\request\approved_contextlist;
+
+/**
+ * Privacy class for requesting user data.
+ *
+ * @package    block_rss_client
+ * @copyright  2018 Mihail Geshoski <mihail@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\provider, \core_privacy\local\request\plugin\provider {
+
+    /**
+     * Returns meta data about this system.
+     *
+     * @param   collection $collection The initialised collection to add items to.
+     * @return  collection A listing of user data stored through this system.
+     */
+    public static function get_metadata(collection $collection) : collection {
+        $collection->add_database_table('block_rss_client', [
+            'userid' => 'privacy:metadata:block_rss_client:userid',
+            'title' => 'privacy:metadata:block_rss_client:title',
+            'preferredtitle' => 'privacy:metadata:block_rss_client:preferredtitle',
+            'description' => 'privacy:metadata:block_rss_client:description',
+            'shared' => 'privacy:metadata:block_rss_client:shared',
+            'url' => 'privacy:metadata:block_rss_client:url',
+            'skiptime' => 'privacy:metadata:block_rss_client:skiptime',
+            'skipuntil' => 'privacy:metadata:block_rss_client:skipuntil',
+        ], 'privacy:metadata:block_rss_client:tableexplanation');
+        return $collection;
+    }
+
+    /**
+     * Get the list of contexts that contain user information for the specified user.
+     *
+     * @param   int         $userid     The user to search.
+     * @return  contextlist $contextlist  The contextlist containing the list of contexts used in this plugin.
+     */
+    public static function get_contexts_for_userid(int $userid) : contextlist {
+        $sql = "SELECT ctx.id
+                FROM {block_rss_client} brc
+                JOIN {user} u
+                    ON brc.userid = u.id
+                JOIN {context} ctx
+                    ON ctx.instanceid = u.id
+                        AND ctx.contextlevel = :contextlevel
+                WHERE brc.userid = :userid";
+
+        $params = ['userid' => $userid, 'contextlevel' => CONTEXT_USER];
+
+        $contextlist = new contextlist();
+        $contextlist->add_from_sql($sql, $params);
+        return $contextlist;
+    }
+
+    /**
+     * Export all user data for the specified user, in the specified contexts.
+     *
+     * @param approved_contextlist $contextlist The approved contexts to export information for.
+     */
+    public static function export_user_data(approved_contextlist $contextlist) {
+        $rssdata = [];
+        $results = static::get_records($contextlist->get_user()->id);
+        foreach ($results as $result) {
+            $rssdata[] = (object) [
+                'title' => $result->title,
+                'preferredtitle' => $result->preferredtitle,
+                'description' => $result->description,
+                'shared' => \core_privacy\local\request\transform::yesno($result->shared),
+                'url' => $result->url
+            ];
+        }
+        if (!empty($rssdata)) {
+            $data = (object) [
+                'feeds' => $rssdata,
+            ];
+            \core_privacy\local\request\writer::with_context($contextlist->current())->export_data([
+                    get_string('pluginname', 'block_rss_client')], $data);
+        }
+    }
+
+    /**
+     * Delete all use data which matches the specified deletion_criteria.
+     *
+     * @param   context $context A user context.
+     */
+    public static function delete_data_for_all_users_in_context(\context $context) {
+        if ($context instanceof \context_user) {
+            static::delete_data($context->instanceid);
+        }
+    }
+
+    /**
+     * Delete all user data for the specified user, in the specified contexts.
+     *
+     * @param   approved_contextlist    $contextlist    The approved contexts and user information to delete information for.
+     */
+    public static function delete_data_for_user(approved_contextlist $contextlist) {
+        static::delete_data($contextlist->get_user()->id);
+    }
+
+    /**
+     * Delete data related to a userid.
+     *
+     * @param  int $userid The user ID
+     */
+    protected static function delete_data($userid) {
+        global $DB;
+
+        $DB->delete_records('block_rss_client', ['userid' => $userid]);
+    }
+
+    /**
+     * Get records related to this plugin and user.
+     *
+     * @param  int $userid The user ID
+     * @return array An array of records.
+     */
+    protected static function get_records($userid) {
+        global $DB;
+
+        return $DB->get_records('block_rss_client', ['userid' => $userid]);
+    }
+}
diff --git a/rss_client/db/access.php b/rss_client/db/access.php
new file mode 100644
index 0000000..3789a58
--- /dev/null
+++ b/rss_client/db/access.php
@@ -0,0 +1,76 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * RSS client block caps.
+ *
+ * @package    block_rss_client
+ * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/rss_client:myaddinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/my:manageblocks'
+    ),
+
+    'block/rss_client:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+
+    'block/rss_client:manageownfeeds' => array(
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'teacher' => CAP_ALLOW,
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        )
+    ),
+
+    'block/rss_client:manageanyfeeds' => array(
+
+        'riskbitmask' => RISK_SPAM,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'manager' => CAP_ALLOW
+        )
+    )
+
+);
+
+
diff --git a/rss_client/db/install.xml b/rss_client/db/install.xml
new file mode 100644
index 0000000..7a7e9cb
--- /dev/null
+++ b/rss_client/db/install.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<XMLDB PATH="blocks/rss_client/db" VERSION="20150717" COMMENT="XMLDB file for Moodle rss_client block"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
+>
+  <TABLES>
+    <TABLE NAME="block_rss_client" COMMENT="Remote news feed information. Contains the news feed id, the userid of the user who added the feed, the title of the feed itself and a description of the feed contents along with the url used to access the remote feed. Preferredtitle is a field for future use - intended to allow for custom titles rather than those found in the feed">
+      <FIELDS>
+        <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
+        <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
+        <FIELD NAME="title" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
+        <FIELD NAME="preferredtitle" TYPE="char" LENGTH="64" NOTNULL="true" SEQUENCE="false"/>
+        <FIELD NAME="description" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
+        <FIELD NAME="shared" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
+        <FIELD NAME="url" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
+        <FIELD NAME="skiptime" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="How many seconds skip this feed for (increases every time it fails, resets to 0 when it succeeds)"/>
+        <FIELD NAME="skipuntil" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Do not query this RSS feed again until this time"/>
+      </FIELDS>
+      <KEYS>
+        <KEY NAME="primary" TYPE="primary" FIELDS="id" />
+      </KEYS>
+    </TABLE>
+  </TABLES>
+</XMLDB>
diff --git a/rss_client/db/upgrade.php b/rss_client/db/upgrade.php
new file mode 100644
index 0000000..d968dda
--- /dev/null
+++ b/rss_client/db/upgrade.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Database upgrades for the RSS block.
+ *
+ * @package   block_rss_client
+ * @copyright 2014 Davo Smith
+ * @author    Neill Magill <neill.magill@nottingham.ac.uk>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL
+ */
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Upgrade the block_rss_client database.
+ *
+ * @param int $oldversion The version number of the plugin that was installed.
+ * @return boolean
+ */
+function xmldb_block_rss_client_upgrade($oldversion) {
+    global $CFG;
+
+    // Automatically generated Moodle v3.2.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.3.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.4.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    return true;
+}
diff --git a/rss_client/edit_form.php b/rss_client/edit_form.php
new file mode 100644
index 0000000..0c70060
--- /dev/null
+++ b/rss_client/edit_form.php
@@ -0,0 +1,93 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Form for editing RSS client block instances.
+ *
+ * @package   block_rss_client
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Form for editing RSS client block instances.
+ *
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_rss_client_edit_form extends block_edit_form {
+    protected function specific_definition($mform) {
+        global $CFG, $DB, $USER;
+
+        // Fields for editing block contents.
+        $mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
+
+        $mform->addElement('selectyesno', 'config_display_description', get_string('displaydescriptionlabel', 'block_rss_client'));
+        $mform->setDefault('config_display_description', 0);
+
+        $mform->addElement('text', 'config_shownumentries', get_string('shownumentrieslabel', 'block_rss_client'), array('size' => 5));
+        $mform->setType('config_shownumentries', PARAM_INT);
+        $mform->addRule('config_shownumentries', null, 'numeric', null, 'client');
+        if (!empty($CFG->block_rss_client_num_entries)) {
+            $mform->setDefault('config_shownumentries', $CFG->block_rss_client_num_entries);
+        } else {
+            $mform->setDefault('config_shownumentries', 5);
+        }
+
+        $insql = '';
+        $params = array('userid' => $USER->id);
+        $rssconfig = unserialize(base64_decode($this->block->instance->configdata));
+        if ($rssconfig && !empty($rssconfig->rssid)) {
+            list($insql, $inparams) = $DB->get_in_or_equal($rssconfig->rssid, SQL_PARAMS_NAMED);
+            $insql = "OR id $insql ";
+            $params += $inparams;
+        }
+
+        $titlesql = "CASE WHEN {$DB->sql_isempty('block_rss_client','preferredtitle', false, false)}
+                      THEN {$DB->sql_compare_text('title', 64)} ELSE preferredtitle END";
+
+        $rssfeeds = $DB->get_records_sql_menu("
+                SELECT id, $titlesql
+                  FROM {block_rss_client}
+                 WHERE userid = :userid OR shared = 1 $insql
+                 ORDER BY $titlesql",
+                $params);
+
+        if ($rssfeeds) {
+            $select = $mform->addElement('select', 'config_rssid', get_string('choosefeedlabel', 'block_rss_client'), $rssfeeds);
+            $select->setMultiple(true);
+
+        } else {
+            $mform->addElement('static', 'config_rssid_no_feeds', get_string('choosefeedlabel', 'block_rss_client'),
+                    get_string('nofeeds', 'block_rss_client'));
+        }
+
+        if (has_any_capability(array('block/rss_client:manageanyfeeds', 'block/rss_client:manageownfeeds'), $this->block->context)) {
+            $mform->addElement('static', 'nofeedmessage', '',
+                    '<a href="' . $CFG->wwwroot . '/blocks/rss_client/managefeeds.php?courseid=' . $this->page->course->id . '">' .
+                    get_string('feedsaddedit', 'block_rss_client') . '</a>');
+        }
+
+        $mform->addElement('text', 'config_title', get_string('uploadlabel'));
+        $mform->setType('config_title', PARAM_NOTAGS);
+
+        $mform->addElement('selectyesno', 'config_block_rss_client_show_channel_link', get_string('clientshowchannellinklabel', 'block_rss_client'));
+        $mform->setDefault('config_block_rss_client_show_channel_link', 0);
+
+        $mform->addElement('selectyesno', 'config_block_rss_client_show_channel_image', get_string('clientshowimagelabel', 'block_rss_client'));
+        $mform->setDefault('config_block_rss_client_show_channel_image', 0);
+    }
+}
diff --git a/rss_client/editfeed.php b/rss_client/editfeed.php
new file mode 100644
index 0000000..97e1706
--- /dev/null
+++ b/rss_client/editfeed.php
@@ -0,0 +1,232 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Script to let a user edit the properties of a particular RSS feed.
+ *
+ * @package   block_rss_client
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+
+require_once(__DIR__ . '/../../config.php');
+require_once($CFG->libdir . '/formslib.php');
+require_once($CFG->libdir .'/simplepie/moodle_simplepie.php');
+
+class feed_edit_form extends moodleform {
+    protected $isadding;
+    protected $caneditshared;
+    protected $title = '';
+    protected $description = '';
+
+    function __construct($actionurl, $isadding, $caneditshared) {
+        $this->isadding = $isadding;
+        $this->caneditshared = $caneditshared;
+        parent::__construct($actionurl);
+    }
+
+    function definition() {
+        $mform =& $this->_form;
+
+        // Then show the fields about where this block appears.
+        $mform->addElement('header', 'rsseditfeedheader', get_string('feed', 'block_rss_client'));
+
+        $mform->addElement('text', 'url', get_string('feedurl', 'block_rss_client'), array('size' => 60));
+        $mform->setType('url', PARAM_URL);
+        $mform->addRule('url', null, 'required');
+
+        $mform->addElement('checkbox', 'autodiscovery', get_string('enableautodiscovery', 'block_rss_client'));
+        $mform->setDefault('autodiscovery', 1);
+        $mform->setAdvanced('autodiscovery');
+        $mform->addHelpButton('autodiscovery', 'enableautodiscovery', 'block_rss_client');
+
+        $mform->addElement('text', 'preferredtitle', get_string('customtitlelabel', 'block_rss_client'), array('size' => 60));
+        $mform->setType('preferredtitle', PARAM_NOTAGS);
+
+        if ($this->caneditshared) {
+            $mform->addElement('selectyesno', 'shared', get_string('sharedfeed', 'block_rss_client'));
+            $mform->setDefault('shared', 0);
+        }
+
+        $submitlabal = null; // Default
+        if ($this->isadding) {
+            $submitlabal = get_string('addnewfeed', 'block_rss_client');
+        }
+        $this->add_action_buttons(true, $submitlabal);
+    }
+
+    function definition_after_data(){
+        $mform =& $this->_form;
+
+        if($mform->getElementValue('autodiscovery')){
+            $mform->applyFilter('url', 'feed_edit_form::autodiscover_feed_url');
+        }
+    }
+
+    function validation($data, $files) {
+        $errors = parent::validation($data, $files);
+
+        $rss =  new moodle_simplepie();
+        // set timeout for longer than normal to try and grab the feed
+        $rss->set_timeout(10);
+        $rss->set_feed_url($data['url']);
+        $rss->set_autodiscovery_cache_duration(0);
+        $rss->set_autodiscovery_level(SIMPLEPIE_LOCATOR_NONE);
+        $rss->init();
+
+        if ($rss->error()) {
+            $errors['url'] = get_string('couldnotfindloadrssfeed', 'block_rss_client');
+        } else {
+            $this->title = $rss->get_title();
+            $this->description = $rss->get_description();
+        }
+
+        return $errors;
+    }
+
+    function get_data() {
+        $data = parent::get_data();
+        if ($data) {
+            $data->title = '';
+            $data->description = '';
+
+            if($this->title){
+                $data->title = $this->title;
+            }
+
+            if($this->description){
+                $data->description = $this->description;
+            }
+        }
+        return $data;
+    }
+
+    /**
+     * Autodiscovers a feed url from a given url, to be used by the formslibs
+     * filter function
+     *
+     * Uses simplepie with autodiscovery set to maximum level to try and find
+     * a feed to subscribe to.
+     * See: http://simplepie.org/wiki/reference/simplepie/set_autodiscovery_level
+     *
+     * @param string URL to autodiscover a url
+     * @return string URL of feed or original url if none found
+     */
+    public static function autodiscover_feed_url($url){
+            $rss =  new moodle_simplepie();
+            $rss->set_feed_url($url);
+            $rss->set_autodiscovery_level(SIMPLEPIE_LOCATOR_ALL);
+            // When autodiscovering an RSS feed, simplepie will try lots of
+            // rss links on a page, so set the timeout high
+            $rss->set_timeout(20);
+            $rss->init();
+
+            if($rss->error()){
+                return $url;
+            }
+
+            // return URL without quoting..
+            $discoveredurl = new moodle_url($rss->subscribe_url());
+            return $discoveredurl->out(false);
+    }
+}
+
+$returnurl = optional_param('returnurl', '', PARAM_LOCALURL);
+$courseid = optional_param('courseid', 0, PARAM_INT);
+$rssid = optional_param('rssid', 0, PARAM_INT); // 0 mean create new.
+
+if ($courseid == SITEID) {
+    $courseid = 0;
+}
+if ($courseid) {
+    $course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
+    $PAGE->set_course($course);
+    $context = $PAGE->context;
+} else {
+    $context = context_system::instance();
+    $PAGE->set_context($context);
+}
+
+$managesharedfeeds = has_capability('block/rss_client:manageanyfeeds', $context);
+if (!$managesharedfeeds) {
+    require_capability('block/rss_client:manageownfeeds', $context);
+}
+
+$urlparams = array('rssid' => $rssid);
+if ($courseid) {
+    $urlparams['courseid'] = $courseid;
+}
+if ($returnurl) {
+    $urlparams['returnurl'] = $returnurl;
+}
+$managefeeds = new moodle_url('/blocks/rss_client/managefeeds.php', $urlparams);
+
+$PAGE->set_url('/blocks/rss_client/editfeed.php', $urlparams);
+$PAGE->set_pagelayout('admin');
+
+if ($rssid) {
+    $isadding = false;
+    $rssrecord = $DB->get_record('block_rss_client', array('id' => $rssid), '*', MUST_EXIST);
+} else {
+    $isadding = true;
+    $rssrecord = new stdClass;
+}
+
+$mform = new feed_edit_form($PAGE->url, $isadding, $managesharedfeeds);
+$mform->set_data($rssrecord);
+
+if ($mform->is_cancelled()) {
+    redirect($managefeeds);
+
+} else if ($data = $mform->get_data()) {
+    $data->userid = $USER->id;
+    if (!$managesharedfeeds) {
+        $data->shared = 0;
+    }
+
+    if ($isadding) {
+        $DB->insert_record('block_rss_client', $data);
+    } else {
+        $data->id = $rssid;
+        $DB->update_record('block_rss_client', $data);
+    }
+
+    redirect($managefeeds);
+
+} else {
+    if ($isadding) {
+        $strtitle = get_string('addnewfeed', 'block_rss_client');
+    } else {
+        $strtitle = get_string('editafeed', 'block_rss_client');
+    }
+
+    $PAGE->set_title($strtitle);
+    $PAGE->set_heading($strtitle);
+
+    $PAGE->navbar->add(get_string('blocks'));
+    $PAGE->navbar->add(get_string('pluginname', 'block_rss_client'));
+    $PAGE->navbar->add(get_string('managefeeds', 'block_rss_client'), $managefeeds );
+    $PAGE->navbar->add($strtitle);
+
+    echo $OUTPUT->header();
+    echo $OUTPUT->heading($strtitle, 2);
+
+    $mform->display();
+
+    echo $OUTPUT->footer();
+}
+
diff --git a/rss_client/lang/en/block_rss_client.php b/rss_client/lang/en/block_rss_client.php
new file mode 100644
index 0000000..3045074
--- /dev/null
+++ b/rss_client/lang/en/block_rss_client.php
@@ -0,0 +1,90 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_rss_client', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_rss_client
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['addfeed'] = 'Add a news feed URL:';
+$string['addheadlineblock'] = 'Add RSS headline block';
+$string['addnew'] = 'Add new';
+$string['addnewfeed'] = 'Add a new feed';
+$string['cannotmakemodification'] = 'You are not allowed to make modifications to this RSS feed at this time.';
+$string['clientchannellink'] = 'Source site...';
+$string['clientnumentries'] = 'The default number of entries to show per feed.';
+$string['clientshowchannellinklabel'] = 'Should a link to the original site (channel link) be displayed? (Note that if no feed link is supplied in the news feed then no link will be shown) :';
+$string['clientshowimagelabel'] = 'Show channel image if available :';
+$string['configblock'] = 'Configure this block';
+$string['couldnotfindfeed'] = 'Could not find feed with id';
+$string['couldnotfindloadrssfeed'] = 'Could not find or load the RSS feed.';
+$string['customtitlelabel'] = 'Custom title (leave blank to use title supplied by feed):';
+$string['deletefeedconfirm'] = 'Are you sure you want to delete this feed?';
+$string['disabledrssfeeds'] = 'RSS feeds are disabled';
+$string['displaydescriptionlabel'] = 'Display each link\'s description?';
+$string['editafeed'] = 'Edit a feed';
+$string['editfeeds'] = 'Edit, subscribe or unsubscribe from RSS/Atom news feeds';
+$string['editnewsfeeds'] = 'Edit news feeds';
+$string['editrssblock'] = 'Edit RSS headline block';
+$string['enableautodiscovery'] = 'Enable auto-discovery of feeds?';
+$string['enableautodiscovery_help'] = 'If enabled, feeds on web pages are found automatically. For example, if http://docs.moodle.org is entered, then http://docs.moodle.org/en/index.php?title=Special:RecentChanges&feed=rss would be found.';
+$string['failedfeed'] = 'Feed failed to download - will retry after {$a}';
+$string['failedfeeds'] = 'One or more RSS feeds have failed';
+$string['feed'] = 'Feed';
+$string['feedadded'] = 'News feed added';
+$string['feeddeleted'] = 'News feed deleted';
+$string['feeds'] = 'News feeds';
+$string['feedsaddedit'] = 'Add/edit feeds';
+$string['feedsconfigurenewinstance'] = 'Click here to configure this block to display RSS feeds.';
+$string['feedsconfigurenewinstance2'] = 'Click the edit icon above to configure this block to display RSS feeds.';
+$string['feedupdated'] = 'News feed updated';
+$string['feedurl'] = 'Feed URL';
+$string['findmorefeeds'] = 'Find more RSS feeds';
+$string['choosefeedlabel'] = 'Choose the feeds which you would like to make available in this block:';
+$string['managefeeds'] = 'Manage all my feeds';
+$string['nofeeds'] = 'There are no RSS feeds defined for this site.';
+$string['numentries'] = 'Entries per feed';
+$string['pickfeed'] = 'Pick a news feed';
+$string['pluginname'] = 'Remote RSS feeds';
+$string['privacy:metadata:block_rss_client:description'] = 'The description of the RSS feed.';
+$string['privacy:metadata:block_rss_client:preferredtitle'] = 'The preferred (custom) title of the RSS feed.';
+$string['privacy:metadata:block_rss_client:shared'] = 'If the RSS feed is available to all courses.';
+$string['privacy:metadata:block_rss_client:skiptime'] = 'The defined time in seconds that the cron will wait between attempts to retry failing RSS feeds.';
+$string['privacy:metadata:block_rss_client:skipuntil'] = 'The maximum defined time that the cron will attempt to open failing RSS feeds.';
+$string['privacy:metadata:block_rss_client:tableexplanation'] = 'RSS block information is stored here.';
+$string['privacy:metadata:block_rss_client:title'] = 'The title of the RSS feed.';
+$string['privacy:metadata:block_rss_client:url'] = 'The URL of the RSS feed.';
+$string['privacy:metadata:block_rss_client:userid'] = 'The ID of the user that added the RSS feed.';
+$string['remotenewsfeed'] = 'Remote news feed';
+$string['rss_client:addinstance'] = 'Add a new remote RSS feeds block';
+$string['rss_client:createprivatefeeds'] = 'Create private RSS feeds';
+$string['rss_client:createsharedfeeds'] = 'Create shared RSS feeds';
+$string['rss_client:manageanyfeeds'] = 'Manage any RSS feeds';
+$string['rss_client:manageownfeeds'] = 'Manage own RSS feeds';
+$string['rss_client:myaddinstance'] = 'Add a new RSS feeds block to Dashboard';
+$string['seeallfeeds'] = 'See all feeds';
+$string['sharedfeed'] = 'Shared feed';
+$string['shownumentrieslabel'] = 'Max number entries to show per block.';
+$string['submitters'] = 'Who will be allowed to define new RSS feeds? Defined feeds are available for any page on your site.';
+$string['submitters2'] = 'Submitters';
+$string['timeout'] = 'Time in minutes before an RSS feed expires in cache. Note that this time defines the minimum time before expiry; the feed will be refreshed in cache on the next cron execution after expiry. Recommended values are 30 mins or greater.';
+$string['timeoutdesc'] = 'Time in minutes for an RSS feed to live in cache.';
+$string['timeout2'] = 'Timeout';
+$string['updatefeed'] = 'Update a news feed URL:';
+$string['viewfeed'] = 'View feed';
diff --git a/rss_client/managefeeds.php b/rss_client/managefeeds.php
new file mode 100644
index 0000000..d216c3c
--- /dev/null
+++ b/rss_client/managefeeds.php
@@ -0,0 +1,147 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Script to let a user manage their RSS feeds.
+ *
+ * @package   block_rss_client
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once(__DIR__ . '/../../config.php');
+require_once($CFG->libdir . '/tablelib.php');
+
+require_login();
+
+$returnurl = optional_param('returnurl', '', PARAM_LOCALURL);
+$courseid = optional_param('courseid', 0, PARAM_INT);
+$deleterssid = optional_param('deleterssid', 0, PARAM_INT);
+
+if ($courseid == SITEID) {
+    $courseid = 0;
+}
+if ($courseid) {
+    $course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
+    $PAGE->set_course($course);
+    $context = $PAGE->context;
+} else {
+    $context = context_system::instance();
+    $PAGE->set_context($context);
+}
+
+$managesharedfeeds = has_capability('block/rss_client:manageanyfeeds', $context);
+if (!$managesharedfeeds) {
+    require_capability('block/rss_client:manageownfeeds', $context);
+}
+
+$urlparams = array();
+$extraparams = '';
+if ($courseid) {
+    $urlparams['courseid'] = $courseid;
+    $extraparams = '&courseid=' . $courseid;
+}
+if ($returnurl) {
+    $urlparams['returnurl'] = $returnurl;
+    $extraparams = '&returnurl=' . $returnurl;
+}
+$baseurl = new moodle_url('/blocks/rss_client/managefeeds.php', $urlparams);
+$PAGE->set_url($baseurl);
+
+// Process any actions
+if ($deleterssid && confirm_sesskey()) {
+    $DB->delete_records('block_rss_client', array('id'=>$deleterssid));
+
+    redirect($PAGE->url, get_string('feeddeleted', 'block_rss_client'));
+}
+
+// Display the list of feeds.
+if ($managesharedfeeds) {
+    $select = '(userid = ' . $USER->id . ' OR shared = 1)';
+} else {
+    $select = 'userid = ' . $USER->id;
+}
+$feeds = $DB->get_records_select('block_rss_client', $select, null, $DB->sql_order_by_text('title'));
+
+$strmanage = get_string('managefeeds', 'block_rss_client');
+
+$PAGE->set_pagelayout('standard');
+$PAGE->set_title($strmanage);
+$PAGE->set_heading($strmanage);
+
+$managefeeds = new moodle_url('/blocks/rss_client/managefeeds.php', $urlparams);
+$PAGE->navbar->add(get_string('blocks'));
+$PAGE->navbar->add(get_string('pluginname', 'block_rss_client'));
+$PAGE->navbar->add(get_string('managefeeds', 'block_rss_client'), $managefeeds);
+echo $OUTPUT->header();
+
+$table = new flexible_table('rss-display-feeds');
+
+$table->define_columns(array('feed', 'actions'));
+$table->define_headers(array(get_string('feed', 'block_rss_client'), get_string('actions', 'moodle')));
+$table->define_baseurl($baseurl);
+
+$table->set_attribute('cellspacing', '0');
+$table->set_attribute('id', 'rssfeeds');
+$table->set_attribute('class', 'generaltable generalbox');
+$table->column_class('feed', 'feed');
+$table->column_class('actions', 'actions');
+
+$table->setup();
+
+foreach($feeds as $feed) {
+    if (!empty($feed->preferredtitle)) {
+        $feedtitle = s($feed->preferredtitle);
+    } else {
+        $feedtitle = $feed->title;
+    }
+
+    $viewlink = html_writer::link($CFG->wwwroot .'/blocks/rss_client/viewfeed.php?rssid=' . $feed->id . $extraparams, $feedtitle);
+
+    $feedinfo = '<div class="title">' . $viewlink . '</div>' .
+        '<div class="url">' . html_writer::link($feed->url, $feed->url) .'</div>' .
+        '<div class="description">' . $feed->description . '</div>';
+    if ($feed->skipuntil) {
+        $skipuntil = userdate($feed->skipuntil, get_string('strftimedatetime', 'langconfig'));
+        $skipmsg = get_string('failedfeed', 'block_rss_client', $skipuntil);
+        $notification = new \core\output\notification($skipmsg, 'error');
+        $notification->set_show_closebutton(false);
+        $feedinfo .= $OUTPUT->render($notification);
+    }
+
+    $editurl = new moodle_url('/blocks/rss_client/editfeed.php?rssid=' . $feed->id . $extraparams);
+    $editaction = $OUTPUT->action_icon($editurl, new pix_icon('t/edit', get_string('edit')));
+
+    $deleteurl = new moodle_url('/blocks/rss_client/managefeeds.php?deleterssid=' . $feed->id . '&sesskey=' . sesskey() . $extraparams);
+    $deleteicon = new pix_icon('t/delete', get_string('delete'));
+    $deleteaction = $OUTPUT->action_icon($deleteurl, $deleteicon, new confirm_action(get_string('deletefeedconfirm', 'block_rss_client')));
+
+    $feedicons = $editaction . ' ' . $deleteaction;
+
+    $table->add_data(array($feedinfo, $feedicons));
+}
+
+$table->print_html();
+
+$url = $CFG->wwwroot . '/blocks/rss_client/editfeed.php?' . substr($extraparams, 1);
+echo '<div class="actionbuttons">' . $OUTPUT->single_button($url, get_string('addnewfeed', 'block_rss_client'), 'get') . '</div>';
+
+
+if ($returnurl) {
+    echo '<div class="backlink">' . html_writer::link($returnurl, get_string('back')) . '</div>';
+}
+
+echo $OUTPUT->footer();
diff --git a/rss_client/settings.php b/rss_client/settings.php
new file mode 100644
index 0000000..cb98280
--- /dev/null
+++ b/rss_client/settings.php
@@ -0,0 +1,36 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Settings for the RSS client block.
+ *
+ * @package   block_rss_client
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die;
+
+if ($ADMIN->fulltree) {
+    $settings->add(new admin_setting_configtext('block_rss_client_num_entries', get_string('numentries', 'block_rss_client'),
+                       get_string('clientnumentries', 'block_rss_client'), 5, PARAM_INT));
+
+    $settings->add(new admin_setting_configtext('block_rss_client_timeout', get_string('timeout2', 'block_rss_client'),
+                       get_string('timeout', 'block_rss_client'), 30, PARAM_INT));
+
+    $link ='<a href="'.$CFG->wwwroot.'/blocks/rss_client/managefeeds.php">'.get_string('feedsaddedit', 'block_rss_client').'</a>';
+    $settings->add(new admin_setting_heading('block_rss_addheading', '', $link));
+}
\ No newline at end of file
diff --git a/rss_client/styles.css b/rss_client/styles.css
new file mode 100644
index 0000000..b1afcae
--- /dev/null
+++ b/rss_client/styles.css
@@ -0,0 +1,10 @@
+/* RSS Feeds
+-------------------------*/
+.block_rss_client .list li:first-child {
+    border-top-width: 0;
+}
+
+.block_rss_client .list li {
+    border-top: 1px solid;
+    padding: 5px;
+}
\ No newline at end of file
diff --git a/rss_client/templates/block.mustache b/rss_client/templates/block.mustache
new file mode 100644
index 0000000..6cc2c71
--- /dev/null
+++ b/rss_client/templates/block.mustache
@@ -0,0 +1,91 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_rss_client/block
+
+    Template which defines an RSS Feeds block
+
+    Classes required for JS:
+    * none
+
+    Data attributes required for JS:
+    * none
+
+    Context variables required for this template:
+    * feeds - array: An array of RSS feeds.
+
+    Example context (json):
+    {
+        "feeds": [
+            {
+                "title": "News from around my living room",
+                "image": {
+                    "url": "https://www.example.com/feeds/news/poster.jpg",
+                    "title": "Example News Logo",
+                    "link": "https://www.example.com/feeds/news/"
+                },
+                "items": [
+                    {
+                        "id": "https://www.example.com/node/12",
+                        "link": "https://www.example.com/my-turtle-story.html",
+                        "title": "My Turtle Story",
+                        "description": "This is a story about my turtle.",
+                        "permalink": "https://www.example.com/my-turtle-story.html",
+                        "datepublished": "11 January 2016, 7:11 pm"
+                    },
+                    {
+                        "id": "https://www.example.com/node/12",
+                        "link": "https://www.example.com/my-cat-story.html",
+                        "title": "My Story",
+                        "description": "This is a story about my cats.",
+                        "permalink": "https://www.example.com/my-cat-story.html",
+                        "datepublished": "12 January 2016, 9:12 pm"
+                    }
+                ]
+            },
+            {
+                "title": "News from around my kitchen",
+                "image": {
+                    "url": "https://www.example.com/feeds/news/kitchen.jpg",
+                    "title": "Picture of My Kitchen",
+                    "link": "https://www.example.com/feeds/news/kitchen/"
+                },
+                "items": [
+                    {
+                        "id": "https://www.example.com/node/10",
+                        "link": "https://www.example.com/oven-smoke.html",
+                        "title": "Why is the Oven Smoking?",
+                        "description": "There is something smoking in the oven.",
+                        "permalink": "https://www.example.com/oven-smoke.html",
+                        "datepublished": "10 January 2016, 1:13 pm"
+                    },
+                    {
+                        "id": "https://www.example.com/node/13",
+                        "link": "https://www.example.com/coffee-is-good.html",
+                        "title": "Why My Coffee Machine is So Great!",
+                        "description": "Don't be fancy; drips are best.",
+                        "permalink": "https://www.example.com/oven-smoke.html",
+                        "datepublished": "13 January 2016, 8:25 pm"
+                    }
+                ]
+            }
+        ]
+    }
+}}
+{{#feeds}}
+    {{> block_rss_client/feed}}
+{{/feeds}}
diff --git a/rss_client/templates/channel_image.mustache b/rss_client/templates/channel_image.mustache
new file mode 100644
index 0000000..f20166e
--- /dev/null
+++ b/rss_client/templates/channel_image.mustache
@@ -0,0 +1,50 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_rss_client/channel_image
+
+    Template which defines an item in an RSS Feed
+
+    Classes required for JS:
+    * none
+
+    Data attributes required for JS:
+    * none
+
+    Context variables required for this template:
+    * url - string: The escaped URL of the image.
+    * title - string: The title of the image.
+    * link - string: Optionally, a URL to link the image to. Must be escaped.
+
+    Example context (json):
+    {
+        "url": "http://www.example.com/images/catpic.jpg",
+        "title": "A picture of my cat",
+        "link": "http://www.example.com/cat-news/"
+    }
+}}
+<div class="image" title="{{title}}">
+    {{#link}}
+        <a href="{{{link}}}">
+    {{/link}}
+
+    <img src="{{{url}}}" alt="{{title}}" />
+
+    {{#link}}
+        </a>
+    {{/link}}
+</div>
diff --git a/rss_client/templates/feed.mustache b/rss_client/templates/feed.mustache
new file mode 100644
index 0000000..a69f3e8
--- /dev/null
+++ b/rss_client/templates/feed.mustache
@@ -0,0 +1,79 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_rss_client/feed
+
+    Template which defines an item in an RSS Feed
+
+    Classes required for JS:
+    * none
+
+    Data attributes required for JS:
+    * none
+
+    Context variables required for this template:
+    * channel_image - object: URL, title and link for the channel image.
+    * title - string: The title of the feed.
+    * items - array: An array of feed items.
+
+    Example context (json):
+    {
+        "title": "News from around my living room",
+        "image": {
+            "url": "https://www.example.com/feeds/news/poster.jpg",
+            "title": "Example News Logo",
+            "link": "https://www.example.com/feeds/news/"
+        },
+        "feeditems": [
+            {
+                "id": "https://www.example.com/node/12",
+                "link": "https://www.example.com/my-turtle-story.html",
+                "title": "My Turtle Story",
+                "description": "This is a story about my turtle.",
+                "permalink": "https://www.example.com/my-turtle-story.html",
+                "datepublished": "11 January 2016, 7:11 pm"
+            },
+            {
+                "id": "https://www.example.com/node/12",
+                "link": "https://www.example.com/my-cat-story.html",
+                "title": "My Story",
+                "description": "This is a story about my cats.",
+                "permalink": "https://www.example.com/my-cat-story.html",
+                "datepublished": "12 January 2016, 9:12 pm"
+            }
+        ]
+    }
+}}
+{{$image}}
+    {{#image}}
+        {{> block_rss_client/channel_image}}
+    {{/image}}
+{{/image}}
+
+{{$title}}
+    {{#title}}
+        <div class="title">{{title}}</div>
+    {{/title}}
+{{/title}}
+
+{{$items}}
+    <ul class="list no-overflow">
+        {{#items}}
+            {{> block_rss_client/item}}
+        {{/items}}
+    </ul>
+{{/items}}
diff --git a/rss_client/templates/footer.mustache b/rss_client/templates/footer.mustache
new file mode 100644
index 0000000..dd5d0fe
--- /dev/null
+++ b/rss_client/templates/footer.mustache
@@ -0,0 +1,42 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_rss_client/footer
+
+    Template which defines an item in an RSS Feed
+
+    Classes required for JS:
+    * none
+
+    Data attributes required for JS:
+    * none
+
+    Context variables required for this template:
+    * channellink - string: The channel URL. Must be escaped.
+
+    Example context (json):
+    {
+        "channellink": "https://www.example.com/feeds/rss"
+    }
+}}
+{{#channellink}}
+    <a href="{{{channellink}}}">{{#str}} clientchannellink, block_rss_client {{/str}}</a>
+    {{#hasfailedfeeds}}<br>{{/hasfailedfeeds}}
+{{/channellink}}
+{{#hasfailedfeeds}}
+    <a href="{{{manageurl}}}">{{#str}} failedfeeds, block_rss_client {{/str}}</a>
+{{/hasfailedfeeds}}
\ No newline at end of file
diff --git a/rss_client/templates/item.mustache b/rss_client/templates/item.mustache
new file mode 100644
index 0000000..1d700ba
--- /dev/null
+++ b/rss_client/templates/item.mustache
@@ -0,0 +1,63 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template block_rss_client/item
+
+    Template which defines an item in an RSS Feed
+
+    Classes required for JS:
+    * none
+
+    Data attributes required for JS:
+    * none
+
+    Context variables required for this template:
+    * id - string: A unique id for the feed item.
+    * link - string: The URL of the feed item. Must already be escaped.
+    * title - string: The title of the feed item.
+    * description - string: The text description of the feed item.
+    * permalink - string: The permalink of the feed item. Must already be escaped.
+    * datepublished - string: The date the feed item was published.
+
+    Example context (json):
+    {
+        "id": "https://www.example.com/node",
+        "link": "https://www.example.com/my-cat-story.html",
+        "title": "My Story",
+        "description": "This is a story about my cats.",
+        "permalink": "https://www.example.com/my-cat-story.html",
+        "datepublished": "12 January 2016, 9:12 pm"
+    }
+}}
+<li class="p-y-1">
+    {{$title}}
+        <div class="link">
+            <a href="{{{link}}}" onclick='this.target="_blank"'>{{title}}</a>
+        </div>
+    {{/title}}
+
+    {{$content}}
+        {{#description}}
+            <div class="date text-muted muted m-b-1">
+                <small>{{{datepublished}}}</small>
+            </div>
+            <div class="description">
+                {{{description}}}
+            </div>
+        {{/description}}
+    {{/content}}
+</li>
diff --git a/rss_client/tests/cron_test.php b/rss_client/tests/cron_test.php
new file mode 100644
index 0000000..7f99275
--- /dev/null
+++ b/rss_client/tests/cron_test.php
@@ -0,0 +1,149 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * PHPunit tests for rss client cron.
+ *
+ * @package    block_rss_client
+ * @copyright  2015 University of Nottingham
+ * @author     Neill Magill <neill.magill@nottingham.ac.uk>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+defined('MOODLE_INTERNAL') || die();
+require_once(__DIR__ . '/../../moodleblock.class.php');
+require_once(__DIR__ . '/../block_rss_client.php');
+
+/**
+ * Class for the PHPunit tests for rss client cron.
+ *
+ * @package    block_rss_client
+ * @copyright  2015 Universit of Nottingham
+ * @author     Neill Magill <neill.magill@nottingham.ac.uk>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_rss_client_cron_testcase extends advanced_testcase {
+    /**
+     * Test that when a record has a skipuntil time that is greater
+     * than the current time the attempt is skipped.
+     */
+    public function test_skip() {
+        global $DB, $CFG;
+        $this->resetAfterTest();
+        // Create a RSS feed record with a skip until time set to the future.
+        $record = (object) array(
+            'userid' => 1,
+            'title' => 'Skip test feed',
+            'preferredtitle' => '',
+            'description' => 'A feed to test the skip time.',
+            'shared' => 0,
+            'url' => 'http://example.com/rss',
+            'skiptime' => 330,
+            'skipuntil' => time() + 300,
+        );
+        $DB->insert_record('block_rss_client', $record);
+
+        $block = new block_rss_client();
+        ob_start();
+
+        // Silence SimplePie php notices.
+        $errorlevel = error_reporting($CFG->debug & ~E_USER_NOTICE);
+        $block->cron();
+        error_reporting($errorlevel);
+
+        $cronoutput = ob_get_clean();
+        $this->assertContains('skipping until ' . userdate($record->skipuntil), $cronoutput);
+        $this->assertContains('0 feeds refreshed (took ', $cronoutput);
+    }
+
+    /**
+     * Test that when a feed has an error the skip time is increaed correctly.
+     */
+    public function test_error() {
+        global $DB, $CFG;
+        $this->resetAfterTest();
+        $time = time();
+        // A record that has failed before.
+        $record = (object) array(
+            'userid' => 1,
+            'title' => 'Skip test feed',
+            'preferredtitle' => '',
+            'description' => 'A feed to test the skip time.',
+            'shared' => 0,
+            'url' => 'http://example.com/rss',
+            'skiptime' => 330,
+            'skipuntil' => $time - 300,
+        );
+        $record->id = $DB->insert_record('block_rss_client', $record);
+
+        // A record that has not failed before.
+        $record2 = (object) array(
+            'userid' => 1,
+            'title' => 'Skip test feed',
+            'preferredtitle' => '',
+            'description' => 'A feed to test the skip time.',
+            'shared' => 0,
+            'url' => 'http://example.com/rss2',
+            'skiptime' => 0,
+            'skipuntil' => 0,
+        );
+        $record2->id = $DB->insert_record('block_rss_client', $record2);
+
+        // A record that is near the maximum wait time.
+        $record3 = (object) array(
+            'userid' => 1,
+            'title' => 'Skip test feed',
+            'preferredtitle' => '',
+            'description' => 'A feed to test the skip time.',
+            'shared' => 0,
+            'url' => 'http://example.com/rss3',
+            'skiptime' => block_rss_client::CLIENT_MAX_SKIPTIME - 5,
+            'skipuntil' => $time - 1,
+        );
+        $record3->id = $DB->insert_record('block_rss_client', $record3);
+
+        // Run the cron.
+        $block = new block_rss_client();
+        ob_start();
+
+        // Silence SimplePie php notices.
+        $errorlevel = error_reporting($CFG->debug & ~E_USER_NOTICE);
+        $block->cron();
+        error_reporting($errorlevel);
+
+        $cronoutput = ob_get_clean();
+        $skiptime1 = $record->skiptime * 2;
+        $message1 = 'http://example.com/rss Error: could not load/find the RSS feed - skipping for ' . $skiptime1 . ' seconds.';
+        $this->assertContains($message1, $cronoutput);
+        $skiptime2 = 330; // Assumes that the cron time in the version file is 300.
+        $message2 = 'http://example.com/rss2 Error: could not load/find the RSS feed - skipping for ' . $skiptime2 . ' seconds.';
+        $this->assertContains($message2, $cronoutput);
+        $skiptime3 = block_rss_client::CLIENT_MAX_SKIPTIME;
+        $message3 = 'http://example.com/rss3 Error: could not load/find the RSS feed - skipping for ' . $skiptime3 . ' seconds.';
+        $this->assertContains($message3, $cronoutput);
+        $this->assertContains('0 feeds refreshed (took ', $cronoutput);
+
+        // Test that the records have been correctly updated.
+        $newrecord = $DB->get_record('block_rss_client', array('id' => $record->id));
+        $this->assertAttributeEquals($skiptime1, 'skiptime', $newrecord);
+        $this->assertAttributeGreaterThanOrEqual($time + $skiptime1, 'skipuntil', $newrecord);
+        $newrecord2 = $DB->get_record('block_rss_client', array('id' => $record2->id));
+        $this->assertAttributeEquals($skiptime2, 'skiptime', $newrecord2);
+        $this->assertAttributeGreaterThanOrEqual($time + $skiptime2, 'skipuntil', $newrecord2);
+        $newrecord3 = $DB->get_record('block_rss_client', array('id' => $record3->id));
+        $this->assertAttributeEquals($skiptime3, 'skiptime', $newrecord3);
+        $this->assertAttributeGreaterThanOrEqual($time + $skiptime3, 'skipuntil', $newrecord3);
+    }
+}
diff --git a/rss_client/tests/privacy_test.php b/rss_client/tests/privacy_test.php
new file mode 100644
index 0000000..901d198
--- /dev/null
+++ b/rss_client/tests/privacy_test.php
@@ -0,0 +1,148 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+/**
+ * Base class for unit tests for block_rss_client.
+ *
+ * @package    block_rss_client
+ * @copyright  2018 Mihail Geshoski <mihail@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+use \core_privacy\tests\provider_testcase;
+
+/**
+ * Unit tests for blocks\rss_client\classes\privacy\provider.php
+ *
+ * @copyright  2018 Mihail Geshoski <mihail@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_rss_client_testcase extends provider_testcase {
+
+    /**
+     * Basic setup for these tests.
+     */
+    public function setUp() {
+        $this->resetAfterTest(true);
+    }
+
+    /**
+     * Test getting the context for the user ID related to this plugin.
+     */
+    public function test_get_contexts_for_userid() {
+
+        $user = $this->getDataGenerator()->create_user();
+        $context = context_user::instance($user->id);
+
+        $this->add_rss_feed($user);
+
+        $contextlist = \block_rss_client\privacy\provider::get_contexts_for_userid($user->id);
+
+        $this->assertEquals($context, $contextlist->current());
+    }
+
+    /**
+     * Test that data is exported correctly for this plugin.
+     */
+    public function test_export_user_data() {
+
+        $user = $this->getDataGenerator()->create_user();
+        $context = context_user::instance($user->id);
+
+        $this->add_rss_feed($user);
+        $this->add_rss_feed($user);
+
+        $writer = \core_privacy\local\request\writer::with_context($context);
+        $this->assertFalse($writer->has_any_data());
+        $this->export_context_data_for_user($user->id, $context, 'block_rss_client');
+
+        $data = $writer->get_data([get_string('pluginname', 'block_rss_client')]);
+        $this->assertCount(2, $data->feeds);
+        $feed1 = reset($data->feeds);
+        $this->assertEquals('BBC News - World', $feed1->title);
+        $this->assertEquals('World News', $feed1->preferredtitle);
+        $this->assertEquals('Description: BBC News - World', $feed1->description);
+        $this->assertEquals(get_string('no'), $feed1->shared);
+        $this->assertEquals('http://feeds.bbci.co.uk/news/world/rss.xml?edition=uk', $feed1->url);
+    }
+
+    /**
+     * Test that user data is deleted using the context.
+     */
+    public function test_delete_data_for_all_users_in_context() {
+        global $DB;
+
+        $user = $this->getDataGenerator()->create_user();
+        $context = context_user::instance($user->id);
+
+        $this->add_rss_feed($user);
+
+        // Check that we have an entry.
+        $rssfeeds = $DB->get_records('block_rss_client', ['userid' => $user->id]);
+        $this->assertCount(1, $rssfeeds);
+
+        \block_rss_client\privacy\provider::delete_data_for_all_users_in_context($context);
+
+        // Check that it has now been deleted.
+        $rssfeeds = $DB->get_records('block_rss_client', ['userid' => $user->id]);
+        $this->assertCount(0, $rssfeeds);
+    }
+
+    /**
+     * Test that user data is deleted for this user.
+     */
+    public function test_delete_data_for_user() {
+        global $DB;
+
+        $user = $this->getDataGenerator()->create_user();
+        $context = context_user::instance($user->id);
+
+        $this->add_rss_feed($user);
+
+        // Check that we have an entry.
+        $rssfeeds = $DB->get_records('block_rss_client', ['userid' => $user->id]);
+        $this->assertCount(1, $rssfeeds);
+
+        $approvedlist = new \core_privacy\local\request\approved_contextlist($user, 'block_rss_feed',
+                [$context->id]);
+        \block_rss_client\privacy\provider::delete_data_for_user($approvedlist);
+
+        // Check that it has now been deleted.
+        $rssfeeds = $DB->get_records('block_rss_client', ['userid' => $user->id]);
+        $this->assertCount(0, $rssfeeds);
+    }
+
+    /**
+     * Add dummy rss feed.
+     *
+     * @param object $user User object
+     */
+    private function add_rss_feed($user) {
+        global $DB;
+
+        $rssfeeddata = array(
+            'userid' => $user->id,
+            'title' => 'BBC News - World',
+            'preferredtitle' => 'World News',
+            'description' => 'Description: BBC News - World',
+            'shared' => 0,
+            'url' => 'http://feeds.bbci.co.uk/news/world/rss.xml?edition=uk',
+        );
+
+        $DB->insert_record('block_rss_client', $rssfeeddata);
+    }
+}
diff --git a/rss_client/version.php b/rss_client/version.php
new file mode 100644
index 0000000..c0e9e59
--- /dev/null
+++ b/rss_client/version.php
@@ -0,0 +1,30 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_rss_client
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_rss_client'; // Full name of the plugin (used for diagnostics)
+$plugin->cron      = 300;               // Set min time between cron executions to 300 secs (5 mins)
diff --git a/rss_client/viewfeed.php b/rss_client/viewfeed.php
new file mode 100644
index 0000000..c56eb30
--- /dev/null
+++ b/rss_client/viewfeed.php
@@ -0,0 +1,99 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Script to let a user edit the properties of a particular RSS feed.
+ *
+ * @package   block_rss_client
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once(__DIR__ . '/../../config.php');
+require_once($CFG->libdir .'/simplepie/moodle_simplepie.php');
+
+require_login();
+if (isguestuser()) {
+    print_error('guestsarenotallowed');
+}
+
+$returnurl = optional_param('returnurl', '', PARAM_LOCALURL);
+$courseid = optional_param('courseid', 0, PARAM_INT);
+$rssid = required_param('rssid', PARAM_INT);
+
+if ($courseid = SITEID) {
+    $courseid = 0;
+}
+if ($courseid) {
+    $course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
+    $PAGE->set_course($course);
+    $context = $PAGE->context;
+} else {
+    $context = context_system::instance();
+    $PAGE->set_context($context);
+}
+
+$urlparams = array('rssid' => $rssid);
+if ($courseid) {
+    $urlparams['courseid'] = $courseid;
+}
+if ($returnurl) {
+    $urlparams['returnurl'] = $returnurl;
+}
+$PAGE->set_url('/blocks/rss_client/viewfeed.php', $urlparams);
+$PAGE->set_pagelayout('popup');
+
+$rssrecord = $DB->get_record('block_rss_client', array('id' => $rssid), '*', MUST_EXIST);
+
+$rss = new moodle_simplepie($rssrecord->url);
+
+if ($rss->error()) {
+    debugging($rss->error());
+    print_error('errorfetchingrssfeed');
+}
+
+$strviewfeed = get_string('viewfeed', 'block_rss_client');
+
+$PAGE->set_title($strviewfeed);
+$PAGE->set_heading($strviewfeed);
+
+$managefeeds = new moodle_url('/blocks/rss_client/managefeeds.php', $urlparams);
+$PAGE->navbar->add(get_string('blocks'));
+$PAGE->navbar->add(get_string('pluginname', 'block_rss_client'));
+$PAGE->navbar->add(get_string('managefeeds', 'block_rss_client'), $managefeeds);
+$PAGE->navbar->add($strviewfeed);
+echo $OUTPUT->header();
+
+if (!empty($rssrecord->preferredtitle)) {
+    $feedtitle = $rssrecord->preferredtitle;
+} else {
+    $feedtitle =  $rss->get_title();
+}
+echo '<table align="center" width="50%" cellspacing="1">'."\n";
+echo '<tr><td colspan="2"><strong>'. s($feedtitle) .'</strong></td></tr>'."\n";
+foreach ($rss->get_items() as $item) {
+    echo '<tr><td valign="middle">'."\n";
+    echo '<a href="'.$item->get_link().'" target="_blank"><strong>';
+    echo s($item->get_title());
+    echo '</strong></a>'."\n";
+    echo '</td>'."\n";
+    echo '</tr>'."\n";
+    echo '<tr><td colspan="2"><small>';
+    echo format_text($item->get_description(), FORMAT_HTML) .'</small></td></tr>'."\n";
+}
+echo '</table>'."\n";
+
+echo $OUTPUT->footer();
diff --git a/search_forums/block_search_forums.php b/search_forums/block_search_forums.php
new file mode 100644
index 0000000..669d5e8
--- /dev/null
+++ b/search_forums/block_search_forums.php
@@ -0,0 +1,66 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Block to search forum posts.
+ *
+ * @package   block_search_forums
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class block_search_forums extends block_base {
+    function init() {
+        $this->title = get_string('pluginname', 'block_search_forums');
+    }
+
+    function get_content() {
+        global $CFG, $OUTPUT;
+
+        if($this->content !== NULL) {
+            return $this->content;
+        }
+
+        $this->content = new stdClass;
+        $this->content->footer = '';
+
+        if (empty($this->instance)) {
+            $this->content->text   = '';
+            return $this->content;
+        }
+
+        $output = $this->page->get_renderer('block_search_forums');
+        $searchform = new \block_search_forums\output\search_form($this->page->course->id);
+        $this->content->text = $output->render($searchform);
+
+        return $this->content;
+    }
+
+    function applicable_formats() {
+        return array('site' => true, 'course' => true);
+    }
+
+    /**
+     * Returns the role that best describes the forum search block.
+     *
+     * @return string
+     */
+    public function get_aria_role() {
+        return 'search';
+    }
+}
+
+
diff --git a/search_forums/classes/output/renderer.php b/search_forums/classes/output/renderer.php
new file mode 100644
index 0000000..292ce34
--- /dev/null
+++ b/search_forums/classes/output/renderer.php
@@ -0,0 +1,50 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Block search forums renderer.
+ *
+ * @package    block_search_forums
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_search_forums\output;
+defined('MOODLE_INTERNAL') || die();
+
+use plugin_renderer_base;
+use renderable;
+
+/**
+ * Block search forums renderer.
+ *
+ * @package    block_search_forums
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class renderer extends plugin_renderer_base {
+
+    /**
+     * Render search form.
+     *
+     * @param renderable $searchform The search form.
+     * @return string
+     */
+    public function render_search_form(renderable $searchform) {
+        return $this->render_from_template('block_search_forums/search_form', $searchform->export_for_template($this));
+    }
+
+}
diff --git a/search_forums/classes/output/search_form.php b/search_forums/classes/output/search_form.php
new file mode 100644
index 0000000..8213abe
--- /dev/null
+++ b/search_forums/classes/output/search_form.php
@@ -0,0 +1,74 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Search form renderable.
+ *
+ * @package    block_search_forums
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_search_forums\output;
+defined('MOODLE_INTERNAL') || die();
+
+use help_icon;
+use moodle_url;
+use renderable;
+use renderer_base;
+use templatable;
+
+/**
+ * Search form renderable class.
+ *
+ * @package    block_search_forums
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class search_form implements renderable, templatable {
+
+    /** @var int The course ID. */
+    protected $courseid;
+    /** @var moodle_url The form action URL. */
+    protected $actionurl;
+    /** @var moodle_url The advanced search URL. */
+    protected $advancedsearchurl;
+    /** @var help_icon The help icon. */
+    protected $helpicon;
+
+    /**
+     * Constructor.
+     *
+     * @param int $courseid The course ID.
+     */
+    public function __construct($courseid) {
+        $this->courseid = $courseid;
+        $this->actionurl = new moodle_url('/mod/forum/search.php');
+        $this->advancedsearchurl = new moodle_url('/mod/forum/search.php', ['id' => $this->courseid]);
+        $this->helpicon = new help_icon('search', 'core');
+    }
+
+    public function export_for_template(renderer_base $output) {
+        $data = [
+            'actionurl' => $this->actionurl->out(false),
+            'courseid' => $this->courseid,
+            'advancedsearchurl' => $this->advancedsearchurl->out(false),
+            'helpicon' => $this->helpicon->export_for_template($output),
+        ];
+        return $data;
+    }
+
+}
diff --git a/search_forums/classes/privacy/provider.php b/search_forums/classes/privacy/provider.php
new file mode 100644
index 0000000..090f960
--- /dev/null
+++ b/search_forums/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_search_forums.
+ *
+ * @package    block_search_forums
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_search_forums\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_search_forums implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/search_forums/db/access.php b/search_forums/db/access.php
new file mode 100644
index 0000000..04d96db
--- /dev/null
+++ b/search_forums/db/access.php
@@ -0,0 +1,41 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Search forums block caps.
+ *
+ * @package    block_search_forums
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/search_forums:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/search_forums/lang/en/block_search_forums.php b/search_forums/lang/en/block_search_forums.php
new file mode 100644
index 0000000..c87b740
--- /dev/null
+++ b/search_forums/lang/en/block_search_forums.php
@@ -0,0 +1,28 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_search_forums', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_search_forums
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['advancedsearch'] = 'Advanced search';
+$string['pluginname'] = 'Search forums';
+$string['search_forums:addinstance'] = 'Add a new search forums block';
+$string['privacy:metadata'] = 'The Search forums block only shows data stored in other locations.';
diff --git a/search_forums/styles.css b/search_forums/styles.css
new file mode 100644
index 0000000..09217a5
--- /dev/null
+++ b/search_forums/styles.css
@@ -0,0 +1,16 @@
+.block_search_forums .searchform {
+    text-align: center;
+}
+
+.block_search_forums .searchform img {
+    vertical-align: middle;
+}
+
+.block_search_forums .searchform img.resize {
+    width: 1em;
+    height: 1.1em;
+}
+
+.block_search_forums .invisiblefieldset {
+    display: block;
+}
\ No newline at end of file
diff --git a/search_forums/templates/search_form.mustache b/search_forums/templates/search_form.mustache
new file mode 100644
index 0000000..9f0411f
--- /dev/null
+++ b/search_forums/templates/search_form.mustache
@@ -0,0 +1,15 @@
+<div class="searchform">
+    <form action="{{actionurl}}" style="display: inline;">
+        <fieldset class="invisiblefieldset">
+            <legend class="accesshide">{{#str}}search{{/str}}</legend>
+            <input type="hidden" name="id" value="{{courseid}}">
+            <label class="accesshide" for="searchform_search">{{#str}}search{{/str}}</label>
+            <input id="searchform_search" name="search" type="text" size="16">
+            <button id="searchform_button" type="submit" title={{#quote}}{{#str}}search{{/str}}{{/quote}}>{{#str}}go{{/str}}</button><br>
+            <a href="{{advancedsearchurl}}">{{#str}}advancedsearch, block_search_forums{{/str}}</a>
+            {{#helpicon}}
+                {{>core/help_icon}}
+            {{/helpicon}}
+        </fieldset>
+    </form>
+</div>
diff --git a/search_forums/tests/behat/block_search_forums_course.feature b/search_forums/tests/behat/block_search_forums_course.feature
new file mode 100644
index 0000000..e2e37d2
--- /dev/null
+++ b/search_forums/tests/behat/block_search_forums_course.feature
@@ -0,0 +1,71 @@
+@block @block_search_forums @mod_forum
+Feature: The search forums block allows users to search for forum posts on course page
+  In order to search for a forum post
+  As a user
+  I can use the search forums block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
+      | student1 | Student | 1 | student1@example.com | S1 |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage
+    And I navigate to "Edit settings" node in "Course administration"
+    And I set the field "id_newsitems" to "1"
+    And I press "Save and display"
+    And I turn editing mode on
+    And I add the "Latest announcements" block
+    And I add the "Search forums" block
+    And I log out
+
+  Scenario: Use the search forum block in a course without any forum posts
+    Given I log in as "student1"
+    And I am on "Course 1" course homepage
+    When I set the following fields to these values:
+      | searchform_search | Moodle |
+    And I press "Go"
+    Then I should see "No posts"
+
+  Scenario: Use the search forum block in a course with a hidden forum and search for posts
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage
+    And I add a new topic to "Announcements" forum with:
+      | Subject | My subject |
+      | Message | My message |
+    And I am on "Course 1" course homepage with editing mode on
+    And I follow "Announcements"
+    And I navigate to "Edit settings" in current page administration
+    And I expand all fieldsets
+    And I set the field "id_visible" to "0"
+    And I press "Save and return to course"
+    And I log out
+    When I log in as "student1"
+    And I am on "Course 1" course homepage
+    And "Search forums" "block" should exist
+    And I set the following fields to these values:
+      | searchform_search | message |
+    And I press "Go"
+    Then I should see "No posts"
+
+  Scenario: Use the search forum block in a course and search for posts
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage
+    And I add a new topic to "Announcements" forum with:
+      | Subject | My subject |
+      | Message | My message |
+    And I log out
+    When I log in as "student1"
+    And I am on "Course 1" course homepage
+    And "Search forums" "block" should exist
+    And I set the following fields to these values:
+      | searchform_search | message |
+    And I press "Go"
+    Then I should see "My subject"
diff --git a/search_forums/tests/behat/block_search_forums_frontpage.feature b/search_forums/tests/behat/block_search_forums_frontpage.feature
new file mode 100644
index 0000000..1f76d15
--- /dev/null
+++ b/search_forums/tests/behat/block_search_forums_frontpage.feature
@@ -0,0 +1,31 @@
+@block @block_search_forums @mod_forum
+Feature: The search forums block allows users to search for forum posts on frontpage
+  In order to search for a forum post
+  As an administrator
+  I can add the search forums block
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | student1 | Student | 1 | student1@example.com | S1 |
+    And I log in as "admin"
+    And I am on site homepage
+    And I navigate to "Turn editing on" node in "Front page settings"
+    And I add the "Search forums" block
+    And I log out
+
+  Scenario: Use the search forum block on the frontpage and search for posts as a user
+    Given I log in as "student1"
+    And I am on site homepage
+    When I set the following fields to these values:
+      | searchform_search | Moodle |
+    And I press "Go"
+    Then I should see "No posts"
+
+  Scenario: Use the search forum block on the frontpage and search for posts as a guest
+    Given I log in as "guest"
+    And I am on site homepage
+    When I set the following fields to these values:
+      | searchform_search | Moodle |
+    And I press "Go"
+    Then I should see "No posts"
diff --git a/search_forums/version.php b/search_forums/version.php
new file mode 100644
index 0000000..e62c1d8
--- /dev/null
+++ b/search_forums/version.php
@@ -0,0 +1,31 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_search_forums
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_search_forums'; // Full name of the plugin (used for diagnostics)
+
+$plugin->dependencies = array('mod_forum' => 2018050800);
diff --git a/section_links/block_section_links.php b/section_links/block_section_links.php
new file mode 100644
index 0000000..7f12683
--- /dev/null
+++ b/section_links/block_section_links.php
@@ -0,0 +1,159 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file contains the main class for the section links block.
+ *
+ * @package    block_section_links
+ * @copyright  Jason Hardin
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Section links block class.
+ *
+ * @package    block_section_links
+ * @copyright  Jason Hardin
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_section_links extends block_base {
+
+    /**
+     * Initialises the block instance.
+     */
+    public function init() {
+        $this->title = get_string('pluginname', 'block_section_links');
+    }
+
+    /**
+     * Returns an array of formats for which this block can be used.
+     *
+     * @return array
+     */
+    public function applicable_formats() {
+        return array(
+            'course-view-weeks' => true,
+            'course-view-topics' => true
+        );
+    }
+
+    /**
+     * Generates the content of the block and returns it.
+     *
+     * If the content has already been generated then the previously generated content is returned.
+     *
+     * @return stdClass
+     */
+    public function get_content() {
+
+        // The config should be loaded by now.
+        // If its empty then we will use the global config for the section links block.
+        if (isset($this->config)){
+            $config = $this->config;
+        } else{
+            $config = get_config('block_section_links');
+        }
+
+        if ($this->content !== null) {
+            return $this->content;
+        }
+
+        $this->content = new stdClass;
+        $this->content->footer = '';
+        $this->content->text   = '';
+
+        if (empty($this->instance)) {
+            return $this->content;
+        }
+
+        $course = $this->page->course;
+        $courseformat = course_get_format($course);
+        $numsections = $courseformat->get_last_section_number();
+        $context = context_course::instance($course->id);
+
+        // Course format options 'numsections' is required to display the block.
+        if (empty($numsections)) {
+            return $this->content;
+        }
+
+        // Prepare the increment value.
+        if (!empty($config->numsections1) and ($numsections > $config->numsections1)) {
+            $inc = $config->incby1;
+        } else if ($numsections > 22) {
+            $inc = 2;
+        } else {
+            $inc = 1;
+        }
+        if (!empty($config->numsections2) and ($numsections > $config->numsections2)) {
+            $inc = $config->incby2;
+        } else {
+            if ($numsections > 40) {
+                $inc = 5;
+            }
+        }
+
+        // Prepare an array of sections to create links for.
+        $sections = array();
+        $canviewhidden = has_capability('moodle/course:update', $context);
+        $coursesections = $courseformat->get_sections();
+        $coursesectionscount = count($coursesections);
+        $sectiontojumpto = false;
+        for ($i = $inc; $i <= $coursesectionscount; $i += $inc) {
+            if ($i > $numsections || !isset($coursesections[$i])) {
+                continue;
+            }
+            $section = $coursesections[$i];
+            if ($section->section && ($section->visible || $canviewhidden)) {
+                $sections[$i] = (object)array(
+                    'section' => $section->section,
+                    'visible' => $section->visible,
+                    'highlight' => false
+                );
+                if ($courseformat->is_section_current($section)) {
+                    $sections[$i]->highlight = true;
+                    $sectiontojumpto = $section->section;
+                }
+            }
+        }
+
+        if (!empty($sections)) {
+            // Render the sections.
+            $renderer = $this->page->get_renderer('block_section_links');
+            $this->content->text = $renderer->render_section_links($this->page->course, $sections, $sectiontojumpto);
+        }
+
+        return $this->content;
+    }
+    /**
+     * Returns true if this block has instance config.
+     *
+     * @return bool
+     **/
+    public function instance_allow_config() {
+        return true;
+    }
+
+    /**
+     * Returns true if this block has global config.
+     *
+     * @return bool
+     */
+    public function has_config() {
+        return true;
+    }
+}
+
+
diff --git a/section_links/classes/privacy/provider.php b/section_links/classes/privacy/provider.php
new file mode 100644
index 0000000..83bb444
--- /dev/null
+++ b/section_links/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_section_links.
+ *
+ * @package    block_section_links
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_section_links\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_section_links implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/section_links/db/access.php b/section_links/db/access.php
new file mode 100644
index 0000000..7a96c63
--- /dev/null
+++ b/section_links/db/access.php
@@ -0,0 +1,41 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Section links block caps.
+ *
+ * @package    block_section_links
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/section_links:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/section_links/db/upgrade.php b/section_links/db/upgrade.php
new file mode 100644
index 0000000..0200032
--- /dev/null
+++ b/section_links/db/upgrade.php
@@ -0,0 +1,62 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file keeps track of upgrades to the section links block
+ *
+ * Sometimes, changes between versions involve alterations to database structures
+ * and other major things that may break installations.
+ *
+ * The upgrade function in this file will attempt to perform all the necessary
+ * actions to upgrade your older installation to the current version.
+ *
+ * If there's something it cannot do itself, it will tell you what you need to do.
+ *
+ * The commands in here will all be database-neutral, using the methods of
+ * database_manager class
+ *
+ * Please do not forget to use upgrade_set_timeout()
+ * before any action that may take longer time to finish.
+ *
+ * @since Moodle 2.5
+ * @package block_section_links
+ * @copyright 2013 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Upgrade code for the section links block.
+ *
+ * @global moodle_database $DB
+ * @param int $oldversion
+ * @param object $block
+ */
+function xmldb_block_section_links_upgrade($oldversion, $block) {
+    global $CFG;
+
+    // Automatically generated Moodle v3.2.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.3.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.4.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    return true;
+}
diff --git a/section_links/edit_form.php b/section_links/edit_form.php
new file mode 100644
index 0000000..63a3593
--- /dev/null
+++ b/section_links/edit_form.php
@@ -0,0 +1,86 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Instance configuration for the section links block.
+ *
+ * @package   block_section_links
+ * @copyright 2013 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Instance configuration form.
+ *
+ * @package   block_section_links
+ * @copyright 2013 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_section_links_edit_form extends block_edit_form {
+
+    /**
+     * The definition of the fields to use.
+     *
+     * @param MoodleQuickForm $mform
+     */
+    protected function specific_definition($mform) {
+        $mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
+
+        $numberofsections = array();
+        for ($i = 1; $i < 53; $i++){
+            $numberofsections[$i] = $i;
+        }
+
+        $increments = array();
+
+        for ($i = 1; $i < 11; $i++){
+            $increments[$i] = $i;
+        }
+
+        $config = get_config('block_section_links');
+
+        $selected = array(
+            1 => array(22, 2),
+            2 => array(40, 5),
+        );
+        if (!empty($config->numsections1)) {
+            if (empty($config->incby1)) {
+                $config->incby1 = $selected[1][1];
+            }
+            $selected[1] = array($config->numsections1, $config->incby1);
+        }
+
+        if (!empty($config->numsections2)) {
+            if (empty($config->incby1)) {
+                $config->incby1 = $selected[2][1];
+            }
+            $selected[2] = array($config->numsections2, $config->incby2);
+        }
+
+        for ($i = 1; $i < 3; $i++) {
+            $mform->addElement('select', 'config_numsections'.$i, get_string('numsections'.$i, 'block_section_links'), $numberofsections);
+            $mform->setDefault('config_numsections'.$i, $selected[$i][0]);
+            $mform->setType('config_numsections'.$i, PARAM_INT);
+            $mform->addHelpButton('config_numsections'.$i, 'numsections'.$i, 'block_section_links');
+
+            $mform->addElement('select', 'config_incby'.$i, get_string('incby'.$i, 'block_section_links'), $increments);
+            $mform->setDefault('config_incby'.$i, $selected[$i][1]);
+            $mform->setType('config_incby'.$i, PARAM_INT);
+            $mform->addHelpButton('config_incby'.$i, 'incby'.$i, 'block_section_links');
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/section_links/lang/en/block_section_links.php b/section_links/lang/en/block_section_links.php
new file mode 100644
index 0000000..b267898
--- /dev/null
+++ b/section_links/lang/en/block_section_links.php
@@ -0,0 +1,39 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_section_links', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package    block_section_links
+ * @copyright  Jason Hardin
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['incby1'] = 'Increase by';
+$string['incby1_help'] = 'This is the value the section is incremented each time a section link is displayed starting at 1.';
+$string['incby2'] = 'Alternative increase by';
+$string['incby2_help'] = 'This is the value the section is incremented each time a section link is displayed starting at 1.';
+$string['jumptocurrenttopic'] = 'Jump to current topic';
+$string['jumptocurrentweek'] = 'Jump to current week';
+$string['numsections1'] = 'Number of sections';
+$string['numsections1_help'] = 'Once the number of sections in the course reaches this number then the increment by value is used.';
+$string['numsections2'] = 'Alternative number of sections';
+$string['numsections2_help'] = 'Once the number of sections in the course reaches this number then the Alternative increment by value is used.';
+$string['pluginname'] = 'Section links';
+$string['section_links:addinstance'] = 'Add a new section links block';
+$string['topics'] = 'Topics';
+$string['weeks'] = 'Weeks';
+$string['privacy:metadata'] = 'The Section links block only shows data stored in other locations.';
diff --git a/section_links/renderer.php b/section_links/renderer.php
new file mode 100644
index 0000000..338855b
--- /dev/null
+++ b/section_links/renderer.php
@@ -0,0 +1,76 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Renderer for the section links block.
+ *
+ * @since     Moodle 2.5
+ * @package   block_section_links
+ * @copyright 2013 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Renderer for the section links block.
+ *
+ * @package   block_section_links
+ * @copyright 2013 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_section_links_renderer extends plugin_renderer_base {
+
+    /**
+     * Render a series of section links.
+     *
+     * @param stdClass $course The course we are rendering for.
+     * @param array $sections An array of section objects to render.
+     * @param bool|int The section to provide a jump to link for.
+     * @return string The HTML to display.
+     */
+    public function render_section_links(stdClass $course, array $sections, $jumptosection = false) {
+        $html = html_writer::start_tag('ol', array('class' => 'inline-list'));
+        foreach ($sections as $section) {
+            $attributes = array();
+            if (!$section->visible) {
+                $attributes['class'] = 'dimmed';
+            }
+            $html .= html_writer::start_tag('li');
+            $sectiontext = $section->section;
+            if ($section->highlight) {
+                $sectiontext = html_writer::tag('strong', $sectiontext);
+            }
+            $html .= html_writer::link(course_get_url($course, $section->section), $sectiontext, $attributes);
+            $html .= html_writer::end_tag('li').' ';
+        }
+        $html .= html_writer::end_tag('ol');
+        if ($jumptosection && isset($sections[$jumptosection])) {
+
+            if ($course->format == 'weeks') {
+                $linktext = new lang_string('jumptocurrentweek', 'block_section_links');
+            } else if ($course->format == 'topics') {
+                $linktext = new lang_string('jumptocurrenttopic', 'block_section_links');
+            }
+
+            $attributes = array();
+            if (!$sections[$jumptosection]->visible) {
+                $attributes['class'] = 'dimmed';
+            }
+            $html .= html_writer::link(course_get_url($course, $jumptosection), $linktext, $attributes);
+        }
+
+        return $html;
+    }
+}
\ No newline at end of file
diff --git a/section_links/settings.php b/section_links/settings.php
new file mode 100644
index 0000000..2fcb4a4
--- /dev/null
+++ b/section_links/settings.php
@@ -0,0 +1,51 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Section links block
+ *
+ * @package    block_section_links
+ * @copyright  Jason Hardin
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die;
+
+if ($ADMIN->fulltree) {
+    $numberofsections = array();
+
+    for ($i = 1; $i < 53; $i++){
+        $numberofsections[$i] = $i;
+    }
+    $increments = array();
+
+    for ($i = 1; $i < 11; $i++){
+        $increments[$i] = $i;
+    }
+
+    $selected = array(1 => array(22,2),
+                      2 => array(40,5));
+
+    for($i = 1; $i < 3; $i++){
+        $settings->add(new admin_setting_configselect('block_section_links/numsections'.$i, get_string('numsections'.$i, 'block_section_links'),
+                            get_string('numsections'.$i.'_help', 'block_section_links'),
+                            $selected[$i][0], $numberofsections));
+
+        $settings->add(new admin_setting_configselect('block_section_links/incby'.$i, get_string('incby'.$i, 'block_section_links'),
+                            get_string('incby'.$i.'_help', 'block_section_links'),
+                            $selected[$i][1], $increments));
+    }
+}
\ No newline at end of file
diff --git a/section_links/tests/behat/block_section_links_course.feature b/section_links/tests/behat/block_section_links_course.feature
new file mode 100644
index 0000000..5ef506d
--- /dev/null
+++ b/section_links/tests/behat/block_section_links_course.feature
@@ -0,0 +1,57 @@
+@block @block_section_links
+Feature: The section links block allows users to quickly navigate around a moodle course
+  In order to navigate a moodle course
+  As a teacher
+  I can use the section links block
+
+  Background:
+    Given the following "courses" exist:
+      | fullname | shortname | category | numsections | coursedisplay |
+      | Course 1 | C1        | 0        | 20          | 1             |
+    And the following "users" exist:
+      | username | firstname | lastname | email |
+      | teacher1 | Teacher   | 1        | teacher1@example.com |
+    And the following "course enrolments" exist:
+      | user     | course | role |
+      | teacher1 | C1     | editingteacher |
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add a "Assignment" to section "5" and I fill the form with:
+      | Assignment name | Test assignment 1 |
+      | Description | Offline text |
+      | assignsubmission_file_enabled | 0 |
+
+  Scenario: Add the section links block to a course.
+    Given I add the "Section links" block
+    And I turn editing mode off
+    And I should see "5" in the "Section links" "block"
+    When I follow "5"
+    Then I should see "Test assignment 1"
+
+  Scenario: Add the section links block to a course and limit the sections displayed.
+    Given I add the "Section links" block
+    And I configure the "Section links" block
+    And I set the following fields to these values:
+      | id_config_numsections1 | 5 |
+      | id_config_incby1 | 5 |
+      | id_config_numsections2 | 40 |
+      | id_config_incby2 | 10 |
+    And I press "Save changes"
+    And I turn editing mode off
+    And I should see "5" in the "Section links" "block"
+    When I follow "5"
+    Then I should see "Test assignment 1"
+
+  Scenario: Add the section links block to a course and limit the sections displayed using the alternative number of sections.
+    Given I add the "Section links" block
+    And I configure the "Section links" block
+    And I set the following fields to these values:
+      | id_config_numsections1 | 5 |
+      | id_config_incby1 | 1 |
+      | id_config_numsections2 | 10 |
+      | id_config_incby2 | 5 |
+    And I press "Save changes"
+    And I turn editing mode off
+    And I should see "5" in the "Section links" "block"
+    When I follow "5"
+    Then I should see "Test assignment 1"
diff --git a/section_links/version.php b/section_links/version.php
new file mode 100644
index 0000000..8f9aa4f
--- /dev/null
+++ b/section_links/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_section_links
+ * @copyright  Jason Hardin
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_section_links'; // Full name of the plugin (used for diagnostics)
diff --git a/selfcompletion/block_selfcompletion.php b/selfcompletion/block_selfcompletion.php
new file mode 100644
index 0000000..4e4d2d7
--- /dev/null
+++ b/selfcompletion/block_selfcompletion.php
@@ -0,0 +1,112 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Self completion block.
+ *
+ * @package   block_selfcompletion
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once($CFG->libdir.'/completionlib.php');
+
+/**
+ * Self course completion marking
+ * Let's a user manually complete a course
+ *
+ * Will only display if the course has completion enabled,
+ * there is a self completion criteria, and the logged in user is yet
+ * to complete the course.
+ */
+class block_selfcompletion extends block_base {
+
+    public function init() {
+        $this->title = get_string('pluginname', 'block_selfcompletion');
+    }
+
+    function applicable_formats() {
+        return array('course' => true);
+    }
+
+    public function get_content() {
+        global $CFG, $USER;
+
+        // If content is cached
+        if ($this->content !== NULL) {
+          return $this->content;
+        }
+
+        // Create empty content
+        $this->content = new stdClass;
+
+        // Can edit settings?
+        $can_edit = has_capability('moodle/course:update', context_course::instance($this->page->course->id));
+
+        // Get course completion data
+        $info = new completion_info($this->page->course);
+
+        // Don't display if completion isn't enabled!
+        if (!completion_info::is_enabled_for_site()) {
+            if ($can_edit) {
+                $this->content->text = get_string('completionnotenabledforsite', 'completion');
+            }
+            return $this->content;
+
+        } else if (!$info->is_enabled()) {
+            if ($can_edit) {
+                $this->content->text = get_string('completionnotenabledforcourse', 'completion');
+            }
+            return $this->content;
+        }
+
+        // Get this user's data
+        $completion = $info->get_completion($USER->id, COMPLETION_CRITERIA_TYPE_SELF);
+
+        // Check if self completion is one of this course's criteria
+        if (empty($completion)) {
+            if ($can_edit) {
+                $this->content->text = get_string('selfcompletionnotenabled', 'block_selfcompletion');
+            }
+            return $this->content;
+        }
+
+        // Check this user is enroled
+        if (!$info->is_tracked_user($USER->id)) {
+            $this->content->text = get_string('nottracked', 'completion');
+            return $this->content;
+        }
+
+        // Is course complete?
+        if ($info->is_course_complete($USER->id)) {
+            $this->content->text = get_string('coursealreadycompleted', 'completion');
+            return $this->content;
+
+        // Check if the user has already marked themselves as complete
+        } else if ($completion->is_complete()) {
+            $this->content->text = get_string('alreadyselfcompleted', 'block_selfcompletion');
+            return $this->content;
+
+        // If user is not complete, or has not yet self completed
+        } else {
+            $this->content->text = '';
+            $this->content->footer = '<br /><a href="'.$CFG->wwwroot.'/course/togglecompletion.php?course='.$this->page->course->id.'">';
+            $this->content->footer .= get_string('completecourse', 'block_selfcompletion').'</a>...';
+        }
+
+        return $this->content;
+    }
+}
diff --git a/selfcompletion/classes/privacy/provider.php b/selfcompletion/classes/privacy/provider.php
new file mode 100644
index 0000000..c96a187
--- /dev/null
+++ b/selfcompletion/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_selfcompletion.
+ *
+ * @package    block_selfcompletion
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_selfcompletion\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_selfcompletion implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/selfcompletion/db/access.php b/selfcompletion/db/access.php
new file mode 100644
index 0000000..d91d4d4
--- /dev/null
+++ b/selfcompletion/db/access.php
@@ -0,0 +1,41 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Self completion block caps.
+ *
+ * @package    block_selfcompletion
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/selfcompletion:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/selfcompletion/db/upgrade.php b/selfcompletion/db/upgrade.php
new file mode 100644
index 0000000..7e5e56a
--- /dev/null
+++ b/selfcompletion/db/upgrade.php
@@ -0,0 +1,61 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file keeps track of upgrades to the self completion block
+ *
+ * Sometimes, changes between versions involve alterations to database structures
+ * and other major things that may break installations.
+ *
+ * The upgrade function in this file will attempt to perform all the necessary
+ * actions to upgrade your older installation to the current version.
+ *
+ * If there's something it cannot do itself, it will tell you what you need to do.
+ *
+ * The commands in here will all be database-neutral, using the methods of
+ * database_manager class
+ *
+ * Please do not forget to use upgrade_set_timeout()
+ * before any action that may take longer time to finish.
+ *
+ * @since Moodle 2.0
+ * @package    block_selfcompletion
+ * @copyright 2012 Mark Nelson <markn@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Handles upgrading instances of this block.
+ *
+ * @param int $oldversion
+ * @param object $block
+ */
+function xmldb_block_selfcompletion_upgrade($oldversion, $block) {
+    global $CFG;
+
+    // Automatically generated Moodle v3.2.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.3.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.4.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    return true;
+}
diff --git a/selfcompletion/lang/en/block_selfcompletion.php b/selfcompletion/lang/en/block_selfcompletion.php
new file mode 100644
index 0000000..2561b6a
--- /dev/null
+++ b/selfcompletion/lang/en/block_selfcompletion.php
@@ -0,0 +1,30 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_selfcompletion', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_selfcompletion
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['alreadyselfcompleted'] = 'You have already marked yourself as complete in this course';
+$string['completecourse'] = 'Complete course';
+$string['pluginname'] = 'Self completion';
+$string['selfcompletionnotenabled'] = 'The self completion criteria has not been enabled for this course';
+$string['selfcompletion:addinstance'] = 'Add a new self completion block';
+$string['privacy:metadata'] = 'The Self completion block only shows data stored in other locations.';
diff --git a/selfcompletion/version.php b/selfcompletion/version.php
new file mode 100644
index 0000000..07db48d
--- /dev/null
+++ b/selfcompletion/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_selfcompletion
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_selfcompletion'; // Full name of the plugin (used for diagnostics)
diff --git a/settings/amd/build/settingsblock.min.js b/settings/amd/build/settingsblock.min.js
new file mode 100644
index 0000000..1cebc85
--- /dev/null
+++ b/settings/amd/build/settingsblock.min.js
@@ -0,0 +1 @@
+define(["jquery","core/tree"],function(a,b){return{init:function(a,c){var d=new b(".block_settings .block_tree");if(c){var e=d.treeRoot.find("#"+c),f=e.children("a").first();f.replaceWith('<span tabindex="0">'+f.html()+"</span>")}d.finishExpandingGroup=function(c){b.prototype.finishExpandingGroup.call(this,c),Y.use("moodle-core-event",function(){Y.Global.fire(M.core.globalEvents.BLOCK_CONTENT_UPDATED,{instanceid:a})})},d.collapseGroup=function(c){b.prototype.collapseGroup.call(this,c),Y.use("moodle-core-event",function(){Y.Global.fire(M.core.globalEvents.BLOCK_CONTENT_UPDATED,{instanceid:a})})}}}});
\ No newline at end of file
diff --git a/settings/amd/src/settingsblock.js b/settings/amd/src/settingsblock.js
new file mode 100644
index 0000000..f17553f
--- /dev/null
+++ b/settings/amd/src/settingsblock.js
@@ -0,0 +1,51 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Load the settings block tree javscript
+ *
+ * @module     block_settings/settingsblock
+ * @package    core
+ * @copyright  2015 John Okely <john@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+define(['jquery', 'core/tree'], function($, Tree) {
+    return {
+        init: function(instanceid, siteAdminNodeId) {
+            var adminTree = new Tree(".block_settings .block_tree");
+            if (siteAdminNodeId) {
+                var siteAdminNode = adminTree.treeRoot.find('#' + siteAdminNodeId);
+                var siteAdminLink = siteAdminNode.children('a').first();
+                siteAdminLink.replaceWith('<span tabindex="0">' + siteAdminLink.html() + '</span>');
+            }
+            adminTree.finishExpandingGroup = function(item) {
+                Tree.prototype.finishExpandingGroup.call(this, item);
+                Y.use('moodle-core-event', function() {
+                    Y.Global.fire(M.core.globalEvents.BLOCK_CONTENT_UPDATED, {
+                        instanceid: instanceid
+                    });
+                });
+            };
+            adminTree.collapseGroup = function(item) {
+                Tree.prototype.collapseGroup.call(this, item);
+                Y.use('moodle-core-event', function() {
+                    Y.Global.fire(M.core.globalEvents.BLOCK_CONTENT_UPDATED, {
+                        instanceid: instanceid
+                    });
+                });
+            };
+        }
+    };
+});
diff --git a/settings/block_settings.php b/settings/block_settings.php
new file mode 100644
index 0000000..1ed9409
--- /dev/null
+++ b/settings/block_settings.php
@@ -0,0 +1,163 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file contains classes used to manage the navigation structures in Moodle
+ * and was introduced as part of the changes occuring in Moodle 2.0
+ *
+ * @since Moodle 2.0
+ * @package block_settings
+ * @copyright 2009 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * The settings navigation tree block class
+ *
+ * Used to produce the settings navigation block new to Moodle 2.0
+ *
+ * @package block_settings
+ * @copyright 2009 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_settings extends block_base {
+
+    /** @var string */
+    public static $navcount;
+    public $blockname = null;
+    /** @var bool */
+    protected $contentgenerated = false;
+    /** @var bool|null */
+    protected $docked = null;
+
+    /**
+     * Set the initial properties for the block
+     */
+    function init() {
+        $this->blockname = get_class($this);
+        $this->title = get_string('pluginname', $this->blockname);
+    }
+
+    /**
+     * All multiple instances of this block
+     * @return bool Returns true
+     */
+    function instance_allow_multiple() {
+        return false;
+    }
+
+    /**
+     * The settings block cannot be hidden by default as it is integral to
+     * the navigation of Moodle.
+     *
+     * @return false
+     */
+    function  instance_can_be_hidden() {
+        return false;
+    }
+
+    /**
+     * Set the applicable formats for this block to all
+     * @return array
+     */
+    function applicable_formats() {
+        return array('all' => true);
+    }
+
+    /**
+     * Allow the user to configure a block instance
+     * @return bool Returns true
+     */
+    function instance_allow_config() {
+        return true;
+    }
+
+    function instance_can_be_docked() {
+        return (parent::instance_can_be_docked() && (empty($this->config->enabledock) || $this->config->enabledock=='yes'));
+    }
+
+    function get_required_javascript() {
+        global $PAGE;
+        $adminnode = $PAGE->settingsnav->find('siteadministration', navigation_node::TYPE_SITE_ADMIN);
+        parent::get_required_javascript();
+        $arguments = array(
+            'instanceid' => $this->instance->id,
+            'adminnodeid' => $adminnode ? $adminnode->id : null
+        );
+        $this->page->requires->js_call_amd('block_settings/settingsblock', 'init', $arguments);
+    }
+
+    /**
+     * Gets the content for this block by grabbing it from $this->page
+     */
+    function get_content() {
+        global $CFG, $OUTPUT;
+        // First check if we have already generated, don't waste cycles
+        if ($this->contentgenerated === true) {
+            return true;
+        }
+        // JS for navigation moved to the standard theme, the code will probably have to depend on the actual page structure
+        // $this->page->requires->js('/lib/javascript-navigation.js');
+        block_settings::$navcount++;
+
+        // Check if this block has been docked
+        if ($this->docked === null) {
+            $this->docked = get_user_preferences('nav_in_tab_panel_settingsnav'.block_settings::$navcount, 0);
+        }
+
+        // Check if there is a param to change the docked state
+        if ($this->docked && optional_param('undock', null, PARAM_INT)==$this->instance->id) {
+            unset_user_preference('nav_in_tab_panel_settingsnav'.block_settings::$navcount, 0);
+            $url = $this->page->url;
+            $url->remove_params(array('undock'));
+            redirect($url);
+        } else if (!$this->docked && optional_param('dock', null, PARAM_INT)==$this->instance->id) {
+            set_user_preferences(array('nav_in_tab_panel_settingsnav'.block_settings::$navcount=>1));
+            $url = $this->page->url;
+            $url->remove_params(array('dock'));
+            redirect($url);
+        }
+
+        $renderer = $this->page->get_renderer('block_settings');
+        $this->content = new stdClass();
+        $this->content->text = $renderer->settings_tree($this->page->settingsnav);
+
+        // only do search if you have moodle/site:config
+        if (!empty($this->content->text)) {
+            if (has_capability('moodle/site:config',context_system::instance()) ) {
+                $this->content->footer = $renderer->search_form(new moodle_url("$CFG->wwwroot/$CFG->admin/search.php"), optional_param('query', '', PARAM_RAW));
+            } else {
+                $this->content->footer = '';
+            }
+
+            if (!empty($this->config->enabledock) && $this->config->enabledock == 'yes') {
+                user_preference_allow_ajax_update('nav_in_tab_panel_settingsnav'.block_settings::$navcount, PARAM_INT);
+            }
+        }
+
+        $this->contentgenerated = true;
+        return true;
+    }
+
+    /**
+     * Returns the role that best describes the settings block.
+     *
+     * @return string 'navigation'
+     */
+    public function get_aria_role() {
+        return 'navigation';
+    }
+}
diff --git a/settings/classes/privacy/provider.php b/settings/classes/privacy/provider.php
new file mode 100644
index 0000000..808dda4
--- /dev/null
+++ b/settings/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_settings.
+ *
+ * @package    block_settings
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_settings\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_settings implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/settings/db/access.php b/settings/db/access.php
new file mode 100644
index 0000000..7585857
--- /dev/null
+++ b/settings/db/access.php
@@ -0,0 +1,51 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Settings block caps.
+ *
+ * @package    block_settings
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/settings:myaddinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/my:manageblocks'
+    ),
+
+    'block/settings:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/settings/db/upgrade.php b/settings/db/upgrade.php
new file mode 100644
index 0000000..2a9dceb
--- /dev/null
+++ b/settings/db/upgrade.php
@@ -0,0 +1,68 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file keeps track of upgrades to the settings block
+ *
+ * Sometimes, changes between versions involve alterations to database structures
+ * and other major things that may break installations.
+ *
+ * The upgrade function in this file will attempt to perform all the necessary
+ * actions to upgrade your older installation to the current version.
+ *
+ * If there's something it cannot do itself, it will tell you what you need to do.
+ *
+ * The commands in here will all be database-neutral, using the methods of
+ * database_manager class
+ *
+ * Please do not forget to use upgrade_set_timeout()
+ * before any action that may take longer time to finish.
+ *
+ * @since Moodle 2.0
+ * @package block_settings
+ * @copyright 2009 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * As of the implementation of this block and the general navigation code
+ * in Moodle 2.0 the body of immediate upgrade work for this block and
+ * settings is done in core upgrade {@see lib/db/upgrade.php}
+ *
+ * There were several reasons that they were put there and not here, both becuase
+ * the process for the two blocks was very similar and because the upgrade process
+ * was complex due to us wanting to remvoe the outmoded blocks that this
+ * block was going to replace.
+ *
+ * @param int $oldversion
+ * @param object $block
+ */
+function xmldb_block_settings_upgrade($oldversion, $block) {
+    global $CFG;
+
+    // Automatically generated Moodle v3.2.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.3.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    // Automatically generated Moodle v3.4.0 release upgrade line.
+    // Put any upgrade step following this.
+
+    return true;
+}
diff --git a/settings/edit_form.php b/settings/edit_form.php
new file mode 100644
index 0000000..0874ee6
--- /dev/null
+++ b/settings/edit_form.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Form for editing settings navigation instances.
+ *
+ * @since Moodle 2.0
+ * @package block_settings
+ * @copyright 2009 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Form for setting navigation instances.
+ *
+ * @package block_settings
+ * @copyright 2009 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_settings_edit_form extends block_edit_form {
+    protected function specific_definition($mform) {
+        $mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
+
+        $yesnooptions = array('yes'=>get_string('yes'), 'no'=>get_string('no'));
+
+        $mform->addElement('select', 'config_enabledock', get_string('enabledock', $this->block->blockname), $yesnooptions);
+        if (empty($this->block->config->enabledock) || $this->block->config->enabledock=='yes') {
+            $mform->getElement('config_enabledock')->setSelected('yes');
+        } else {
+            $mform->getElement('config_enabledock')->setSelected('no');
+        }
+    }
+}
\ No newline at end of file
diff --git a/settings/lang/en/block_settings.php b/settings/lang/en/block_settings.php
new file mode 100644
index 0000000..80e95b2
--- /dev/null
+++ b/settings/lang/en/block_settings.php
@@ -0,0 +1,31 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file contains language strings used in the settings navigation block
+ *
+ * @since Moodle 2.0
+ * @package block_settings
+ * @copyright 2009 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['enabledock'] = 'Allow the user to dock this block';
+$string['pluginname'] = 'Administration';
+$string['settings:addinstance'] = 'Add a new administration block';
+$string['settings:myaddinstance'] = 'Add a new administration block to Dashboard';
+$string['privacy:metadata'] = 'The Administration block only shows data stored in other locations.';
diff --git a/settings/renderer.php b/settings/renderer.php
new file mode 100644
index 0000000..34e99ef
--- /dev/null
+++ b/settings/renderer.php
@@ -0,0 +1,156 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Settings block
+ *
+ * @package    block_settings
+ * @copyright  2010 Sam Hemelryk
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class block_settings_renderer extends plugin_renderer_base {
+
+    public function settings_tree(settings_navigation $navigation) {
+        $count = 0;
+        foreach ($navigation->children as &$child) {
+            $child->preceedwithhr = ($count!==0);
+            if ($child->display) {
+                $count++;
+            }
+        }
+        $navigationattrs = array(
+            'class' => 'block_tree list',
+            'role' => 'tree',
+            'data-ajax-loader' => 'block_navigation/site_admin_loader');
+        $content = $this->navigation_node($navigation, $navigationattrs);
+        if (isset($navigation->id) && !is_numeric($navigation->id) && !empty($content)) {
+            $content = $this->output->box($content, 'block_tree_box', $navigation->id);
+        }
+        return $content;
+    }
+
+    /**
+     * Build the navigation node.
+     *
+     * @param navigation_node $node the navigation node object.
+     * @param array $attrs list of attributes.
+     * @param int $depth the depth, default to 1.
+     * @return string the navigation node code.
+     */
+    protected function navigation_node(navigation_node $node, $attrs=array(), $depth = 1) {
+        $items = $node->children;
+
+        // exit if empty, we don't want an empty ul element
+        if ($items->count()==0) {
+            return '';
+        }
+
+        // array of nested li elements
+        $lis = array();
+        $number = 0;
+        foreach ($items as $item) {
+            $number++;
+            if (!$item->display) {
+                continue;
+            }
+
+            $isbranch = ($item->children->count()>0  || $item->nodetype==navigation_node::NODETYPE_BRANCH);
+
+            if ($isbranch) {
+                $item->hideicon = true;
+            }
+
+            $content = $this->output->render($item);
+            $id = $item->id ? $item->id : html_writer::random_id();
+            $ulattr = ['id' => $id . '_group', 'role' => 'group'];
+            $liattr = ['class' => [$item->get_css_type(), 'depth_'.$depth], 'tabindex' => '-1'];
+            $pattr = ['class' => ['tree_item'], 'role' => 'treeitem'];
+            $pattr += !empty($item->id) ? ['id' => $item->id] : [];
+            $hasicon = (!$isbranch && $item->icon instanceof renderable);
+
+            if ($isbranch) {
+                $liattr['class'][] = 'contains_branch';
+                if (!$item->forceopen || (!$item->forceopen && $item->collapse) || ($item->children->count() == 0
+                        && $item->nodetype == navigation_node::NODETYPE_BRANCH)) {
+                    $pattr += ['aria-expanded' => 'false'];
+                } else {
+                    $pattr += ['aria-expanded' => 'true'];
+                }
+                if ($item->requiresajaxloading) {
+                    $pattr['data-requires-ajax'] = 'true';
+                    $pattr['data-loaded'] = 'false';
+                } else {
+                    $pattr += ['aria-owns' => $id . '_group'];
+                }
+            } else if ($hasicon) {
+                $liattr['class'][] = 'item_with_icon';
+                $pattr['class'][] = 'hasicon';
+            }
+            if ($item->isactive === true) {
+                $liattr['class'][] = 'current_branch';
+            }
+            if (!empty($item->classes) && count($item->classes) > 0) {
+                $pattr['class'] = array_merge($pattr['class'], $item->classes);
+            }
+            $nodetextid = 'label_' . $depth . '_' . $number;
+
+            // class attribute on the div item which only contains the item content
+            $pattr['class'][] = 'tree_item';
+            if ($isbranch) {
+                $pattr['class'][] = 'branch';
+            } else {
+                $pattr['class'][] = 'leaf';
+            }
+
+            $liattr['class'] = join(' ', $liattr['class']);
+            $pattr['class'] = join(' ', $pattr['class']);
+
+            if (isset($pattr['aria-expanded']) && $pattr['aria-expanded'] === 'false') {
+                $ulattr += ['aria-hidden' => 'true'];
+            }
+
+            $content = html_writer::tag('p', $content, $pattr) . $this->navigation_node($item, $ulattr, $depth + 1);
+            if (!empty($item->preceedwithhr) && $item->preceedwithhr===true) {
+                $content = html_writer::empty_tag('hr') . $content;
+            }
+            $liattr['aria-labelledby'] = $nodetextid;
+            $content = html_writer::tag('li', $content, $liattr);
+            $lis[] = $content;
+        }
+
+        if (count($lis)) {
+            if (empty($attrs['role'])) {
+                $attrs['role'] = 'group';
+            }
+            return html_writer::tag('ul', implode("\n", $lis), $attrs);
+        } else {
+            return '';
+        }
+    }
+
+    public function search_form(moodle_url $formtarget, $searchvalue) {
+        $content = html_writer::start_tag('form', array('class'=>'adminsearchform', 'method'=>'get', 'action'=>$formtarget, 'role' => 'search'));
+        $content .= html_writer::start_tag('div');
+        $content .= html_writer::tag('label', s(get_string('searchinsettings', 'admin')), array('for'=>'adminsearchquery', 'class'=>'accesshide'));
+        $content .= html_writer::empty_tag('input', array('id'=>'adminsearchquery', 'type'=>'text', 'name'=>'query', 'value'=>s($searchvalue)));
+        $content .= html_writer::empty_tag('input', array('type'=>'submit', 'value'=>s(get_string('search'))));
+        $content .= html_writer::end_tag('div');
+        $content .= html_writer::end_tag('form');
+        return $content;
+    }
+
+}
diff --git a/settings/styles.css b/settings/styles.css
new file mode 100644
index 0000000..3d7e1d1
--- /dev/null
+++ b/settings/styles.css
@@ -0,0 +1,65 @@
+.block_settings .block_tree ul {
+    margin-left: 18px;
+}
+
+.block_settings .block_tree p.hasicon {
+    text-indent: -21px;
+    padding-left: 21px;
+}
+
+.block_settings .block_tree p.hasicon img {
+    width: 16px;
+    height: 16px;
+    margin-top: 3px;
+    margin-right: 5px;
+    vertical-align: top;
+}
+
+.block_settings .block_tree p.hasicon.visibleifjs {
+    display: block;
+}
+
+.block_settings .block_tree .tree_item.branch {
+    padding-left: 21px;
+}
+
+.block_settings .block_tree .tree_item {
+    cursor: pointer;
+    margin: 3px 0;
+    background-position: 0 50%;
+    background-repeat: no-repeat;
+}
+
+.block_settings .block_tree .active_tree_node {
+    font-weight: bold;
+}
+
+.block_settings .block_tree [aria-expanded="true"] {
+    background-image: url('[[pix:t/expanded]]');
+}
+
+.block_settings .block_tree [aria-expanded="false"] {
+    background-image: url('[[pix:t/collapsed]]');
+}
+
+.block_settings .block_tree [aria-expanded="true"].emptybranch {
+    background-image: url('[[pix:t/collapsed_empty]]');
+}
+
+.block_settings .block_tree [aria-expanded="false"].loading {
+    background-image: url('[[pix:i/loading_small]]');
+}
+/*rtl:raw:
+.block_settings .block_tree [aria-expanded="false"] {background-image: url('[[pix:t/collapsed_rtl]]');}
+.block_settings .block_tree [aria-expanded="true"].emptybranch {background-image: url('[[pix:t/collapsed_empty_rtl]]');}
+.block_settings .block_tree [aria-expanded="false"].loading {background-image: url('[[pix:i/loading_small]]');}
+*/
+.block_settings .block_tree [aria-hidden="false"] {
+    display: block;
+}
+
+.block_settings .block_tree  [aria-hidden="true"]:not(.icon) {
+    display: none;
+}
+
+
diff --git a/settings/version.php b/settings/version.php
new file mode 100644
index 0000000..9540efc
--- /dev/null
+++ b/settings/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_settings
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_settings';  // Full name of the plugin (used for diagnostics)
diff --git a/site_main_menu/block_site_main_menu.php b/site_main_menu/block_site_main_menu.php
new file mode 100644
index 0000000..c5a692f
--- /dev/null
+++ b/site_main_menu/block_site_main_menu.php
@@ -0,0 +1,163 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Site main menu block.
+ *
+ * @package    block_site_main_menu
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class block_site_main_menu extends block_list {
+    function init() {
+        $this->title = get_string('pluginname', 'block_site_main_menu');
+    }
+
+    function applicable_formats() {
+        return array('site' => true);
+    }
+
+    function get_content() {
+        global $USER, $CFG, $DB, $OUTPUT;
+
+        if ($this->content !== NULL) {
+            return $this->content;
+        }
+
+        $this->content = new stdClass();
+        $this->content->items = array();
+        $this->content->icons = array();
+        $this->content->footer = '';
+
+        if (empty($this->instance)) {
+            return $this->content;
+        }
+
+        $course = get_site();
+        require_once($CFG->dirroot.'/course/lib.php');
+        $context = context_course::instance($course->id);
+        $isediting = $this->page->user_is_editing() && has_capability('moodle/course:manageactivities', $context);
+        $courserenderer = $this->page->get_renderer('core', 'course');
+
+/// extra fast view mode
+        if (!$isediting) {
+            $modinfo = get_fast_modinfo($course);
+            if (!empty($modinfo->sections[0])) {
+                foreach($modinfo->sections[0] as $cmid) {
+                    $cm = $modinfo->cms[$cmid];
+                    if (!$cm->uservisible || !$cm->is_visible_on_course_page()) {
+                        continue;
+                    }
+
+                    if ($cm->indent > 0) {
+                        $indent = '<div class="mod-indent mod-indent-'.$cm->indent.'"></div>';
+                    } else {
+                        $indent = '';
+                    }
+
+                    if (!empty($cm->url)) {
+                        $content = html_writer::div($courserenderer->course_section_cm_name($cm), 'activity');
+                    } else {
+                        $content = $courserenderer->course_section_cm_text($cm);
+                    }
+
+                    $this->content->items[] = $indent . html_writer::div($content, 'main-menu-content');
+                }
+            }
+            return $this->content;
+        }
+
+        // Slow & hacky editing mode.
+        $ismoving = ismoving($course->id);
+        course_create_sections_if_missing($course, 0);
+        $modinfo = get_fast_modinfo($course);
+        $section = $modinfo->get_section_info(0);
+
+        if ($ismoving) {
+            $strmovehere = get_string('movehere');
+            $strmovefull = strip_tags(get_string('movefull', '', "'$USER->activitycopyname'"));
+            $strcancel= get_string('cancel');
+        } else {
+            $strmove = get_string('move');
+        }
+
+        if ($ismoving) {
+            $this->content->icons[] = $OUTPUT->pix_icon('t/move', get_string('move'));
+            $this->content->items[] = $USER->activitycopyname.'&nbsp;(<a href="'.$CFG->wwwroot.'/course/mod.php?cancelcopy=true&amp;sesskey='.sesskey().'">'.$strcancel.'</a>)';
+        }
+
+        if (!empty($modinfo->sections[0])) {
+            foreach ($modinfo->sections[0] as $modnumber) {
+                $mod = $modinfo->cms[$modnumber];
+                if (!$mod->uservisible || !$mod->is_visible_on_course_page()) {
+                    continue;
+                }
+                if (!$ismoving) {
+                    $actions = course_get_cm_edit_actions($mod, $mod->indent);
+
+                    // Prepend list of actions with the 'move' action.
+                    $actions = array('move' => new action_menu_link_primary(
+                        new moodle_url('/course/mod.php', array('sesskey' => sesskey(), 'copy' => $mod->id)),
+                        new pix_icon('t/move', $strmove, 'moodle', array('class' => 'iconsmall', 'title' => '')),
+                        $strmove
+                    )) + $actions;
+
+                    $editbuttons = html_writer::tag('div',
+                        $courserenderer->course_section_cm_edit_actions($actions, $mod, array('donotenhance' => true)),
+                        array('class' => 'buttons')
+                    );
+                } else {
+                    $editbuttons = '';
+                }
+                if ($mod->visible || has_capability('moodle/course:viewhiddenactivities', $mod->context)) {
+                    if ($ismoving) {
+                        if ($mod->id == $USER->activitycopy) {
+                            continue;
+                        }
+                        $this->content->items[] = '<a title="'.$strmovefull.'" href="'.$CFG->wwwroot.'/course/mod.php?moveto='.$mod->id.'&amp;sesskey='.sesskey().'">'.
+                            '<img style="height:16px; width:80px; border:0px" src="'.$OUTPUT->image_url('movehere') . '" alt="'.$strmovehere.'" /></a>';
+                        $this->content->icons[] = '';
+                    }
+                    if ($mod->indent > 0) {
+                        $indent = '<div class="mod-indent mod-indent-'.$mod->indent.'"></div>';
+                    } else {
+                        $indent = '';
+                    }
+                    if (!$mod->url) {
+                        $content = $courserenderer->course_section_cm_text($mod);
+                    } else {
+                        $content = html_writer::div($courserenderer->course_section_cm_name($mod), ' activity');
+                    }
+                    $this->content->items[] = $indent . html_writer::div($content . $editbuttons, 'main-menu-content');
+                }
+            }
+        }
+
+        if ($ismoving) {
+            $this->content->items[] = '<a title="'.$strmovefull.'" href="'.$CFG->wwwroot.'/course/mod.php?movetosection='.$section->id.'&amp;sesskey='.sesskey().'">'.
+                                      '<img style="height:16px; width:80px; border:0px" src="'.$OUTPUT->image_url('movehere') . '" alt="'.$strmovehere.'" /></a>';
+            $this->content->icons[] = '';
+        }
+
+        $this->content->footer = $courserenderer->course_section_add_cm_control($course,
+                0, null, array('inblock' => true));
+
+        return $this->content;
+    }
+}
+
+
diff --git a/site_main_menu/classes/privacy/provider.php b/site_main_menu/classes/privacy/provider.php
new file mode 100644
index 0000000..b9e6991
--- /dev/null
+++ b/site_main_menu/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_site_main_menu.
+ *
+ * @package    block_site_main_menu
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_site_main_menu\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_site_main_menu implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/site_main_menu/db/access.php b/site_main_menu/db/access.php
new file mode 100644
index 0000000..31100e7
--- /dev/null
+++ b/site_main_menu/db/access.php
@@ -0,0 +1,41 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Site main menu block caps.
+ *
+ * @package    block_site_main_menu
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/site_main_menu:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/site_main_menu/lang/en/block_site_main_menu.php b/site_main_menu/lang/en/block_site_main_menu.php
new file mode 100644
index 0000000..aba47e3
--- /dev/null
+++ b/site_main_menu/lang/en/block_site_main_menu.php
@@ -0,0 +1,28 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_site_main_menu', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_site_main_menu
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['pluginname'] = 'Main menu';
+$string['site_main_menu:addinstance'] = 'Add a new main menu block';
+$string['privacy:metadata'] = 'The Main menu block only shows data stored in other locations.';
diff --git a/site_main_menu/styles.css b/site_main_menu/styles.css
new file mode 100644
index 0000000..9f4747a
--- /dev/null
+++ b/site_main_menu/styles.css
@@ -0,0 +1,34 @@
+.block_site_main_menu li {
+    clear: both;
+}
+
+.block_site_main_menu.block.list_block .unlist > li > .column {
+    /* Made specific to win over .block.list_block .unlist > li > .column. */
+    width: 100%;
+    display: table;
+}
+
+.block_site_main_menu li .buttons {
+    float: right;
+    margin: 0;
+    padding: 0;
+    border: 0;
+    background-color: inherit;
+}
+
+.block_site_main_menu li .buttons a img {
+    vertical-align: text-bottom;
+}
+
+.block_site_main_menu .footer {
+    margin-top: 1em;
+}
+
+.block_site_main_menu .section_add_menus noscript div {
+    display: inline;
+}
+
+.block_site_main_menu .mod-indent,
+.block_site_main_menu .main-menu-content {
+    display: table-cell;
+}
diff --git a/site_main_menu/tests/behat/add_url.feature b/site_main_menu/tests/behat/add_url.feature
new file mode 100644
index 0000000..a9cfb61
--- /dev/null
+++ b/site_main_menu/tests/behat/add_url.feature
@@ -0,0 +1,19 @@
+@block @block_site_main_menu
+Feature: Add URL to main menu block
+  In order to add helpful resources for students
+  As a admin
+  I need to add URLs to the main menu block and check it works.
+
+  @javascript
+  Scenario: Add a URL in menu block and ensure it appears
+    Given I log in as "admin"
+    And I am on site homepage
+    And I navigate to "Turn editing on" node in "Front page settings"
+    And I add the "Main menu" block
+    When I add a "URL" to section "0" and I fill the form with:
+      | Name | google |
+      | Description | gooooooooogle |
+      | External URL | http://www.google.com |
+      | id_display | In pop-up |
+    Then "google" "link" should exist in the "Main menu" "block"
+    And "Add an activity or resource" "link" should exist in the "Main menu" "block"
diff --git a/site_main_menu/tests/behat/behat_block_site_main_menu.php b/site_main_menu/tests/behat/behat_block_site_main_menu.php
new file mode 100644
index 0000000..f523116
--- /dev/null
+++ b/site_main_menu/tests/behat/behat_block_site_main_menu.php
@@ -0,0 +1,157 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Behat steps definitions for block site main menu
+ *
+ * @package    block_site_main_menu
+ * @category   test
+ * @copyright  2016 Marina Glancy
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
+
+require_once(__DIR__ . '/../../../../lib/behat/behat_base.php');
+
+use Behat\Mink\Exception\ExpectationException as ExpectationException,
+    Behat\Mink\Exception\DriverException as DriverException,
+    Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException;
+
+/**
+ * Behat steps definitions for block site main menu
+ *
+ * @package    block_site_main_menu
+ * @category   test
+ * @copyright  2016 Marina Glancy
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class behat_block_site_main_menu extends behat_base {
+
+    /**
+     * Returns the DOM node of the activity in the site menu block
+     *
+     * @throws ElementNotFoundException Thrown by behat_base::find
+     * @param string $activityname The activity name
+     * @return NodeElement
+     */
+    protected function get_site_menu_activity_node($activityname) {
+        $activityname = behat_context_helper::escape($activityname);
+        $xpath = "//*[contains(concat(' ',normalize-space(@class),' '),' block_site_main_menu ')]//li[contains(., $activityname)]";
+
+        return $this->find('xpath', $xpath);
+    }
+
+    /**
+     * Checks that the specified activity's action menu contains an item.
+     *
+     * @Then /^"(?P<activity_name_string>(?:[^"]|\\")*)" activity in site main menu block should have "(?P<icon_name_string>(?:[^"]|\\")*)" editing icon$/
+     * @param string $activityname
+     * @param string $iconname
+     */
+    public function activity_in_site_main_menu_block_should_have_editing_icon($activityname, $iconname) {
+        $activitynode = $this->get_site_menu_activity_node($activityname);
+
+        $notfoundexception = new ExpectationException('"' . $activityname . '" doesn\'t have a "' .
+            $iconname . '" editing icon', $this->getSession());
+        $this->find('named_partial', array('link', $iconname), $notfoundexception, $activitynode);
+    }
+
+    /**
+     * Checks that the specified activity's action menu contains an item.
+     *
+     * @Then /^"(?P<activity_name_string>(?:[^"]|\\")*)" activity in site main menu block should not have "(?P<icon_name_string>(?:[^"]|\\")*)" editing icon$/
+     * @param string $activityname
+     * @param string $iconname
+     */
+    public function activity_in_site_main_menu_block_should_not_have_editing_icon($activityname, $iconname) {
+        $activitynode = $this->get_site_menu_activity_node($activityname);
+
+        try {
+            $this->find('named_partial', array('link', $iconname), false, $activitynode);
+            throw new ExpectationException('"' . $activityname . '" has a "' . $iconname .
+                '" editing icon when it should not', $this->getSession());
+        } catch (ElementNotFoundException $e) {
+            // This is good, the menu item should not be there.
+        }
+    }
+
+    /**
+     * Clicks on the specified element of the activity. You should be in the course page with editing mode turned on.
+     *
+     * @Given /^I click on "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>(?:[^"]|\\")*)" in the "(?P<activity_name_string>(?:[^"]|\\")*)" activity in site main menu block$/
+     * @param string $element
+     * @param string $selectortype
+     * @param string $activityname
+     */
+    public function i_click_on_in_the_activity_in_site_main_menu_block($element, $selectortype, $activityname) {
+        $element = $this->get_site_menu_activity_element($element, $selectortype, $activityname);
+        $element->click();
+    }
+
+    /**
+     * Clicks on the specified element inside the activity container.
+     *
+     * @throws ElementNotFoundException
+     * @param string $element
+     * @param string $selectortype
+     * @param string $activityname
+     * @return NodeElement
+     */
+    protected function get_site_menu_activity_element($element, $selectortype, $activityname) {
+        $activitynode = $this->get_site_menu_activity_node($activityname);
+
+        // Transforming to Behat selector/locator.
+        list($selector, $locator) = $this->transform_selector($selectortype, $element);
+        $exception = new ElementNotFoundException($this->getSession(), '"' . $element . '" "' .
+            $selectortype . '" in "' . $activityname . '" ');
+
+        return $this->find($selector, $locator, $exception, $activitynode);
+    }
+
+    /**
+     * Checks that the specified activity is hidden.
+     *
+     * @Then /^"(?P<activity_name_string>(?:[^"]|\\")*)" activity in site main menu block should be hidden$/
+     * @param string $activityname
+     */
+    public function activity_in_site_main_menu_block_should_be_hidden($activityname) {
+        $this->get_site_menu_activity_element("a.dimmed", "css_element", $activityname);
+    }
+
+    /**
+     * Checks that the specified activity is hidden.
+     *
+     * @Then /^"(?P<activity_name_string>(?:[^"]|\\")*)" activity in site main menu block should be available but hidden from course page$/
+     * @param string $activityname
+     */
+    public function activity_in_site_main_menu_block_should_be_available_but_hidden_from_course_page($activityname) {
+        $this->get_site_menu_activity_element("a.stealth", "css_element", $activityname);
+    }
+
+    /**
+     * Opens an activity actions menu if it is not already opened.
+     *
+     * @Given /^I open "(?P<activity_name_string>(?:[^"]|\\")*)" actions menu in site main menu block$/
+     * @throws DriverException The step is not available when Javascript is disabled
+     * @param string $activityname
+     */
+    public function i_open_actions_menu_in_site_main_menu_block($activityname) {
+        $activityname = behat_context_helper::escape($activityname);
+        $xpath = "//*[contains(concat(' ',normalize-space(@class),' '),' block_site_main_menu ')]//li[contains(., $activityname)]";
+        $this->execute('behat_action_menu::i_open_the_action_menu_in', [$xpath, 'xpath_element']);
+    }
+}
diff --git a/site_main_menu/tests/behat/edit_activities.feature b/site_main_menu/tests/behat/edit_activities.feature
new file mode 100644
index 0000000..c577b9f
--- /dev/null
+++ b/site_main_menu/tests/behat/edit_activities.feature
@@ -0,0 +1,67 @@
+@block @block_site_main_menu
+Feature: Edit activities in main menu block
+  In order to use main menu block
+  As an admin
+  I need to add and edit activities there
+
+  @javascript
+  Scenario: Edit name of acitivity in-place in site main menu block
+    Given I log in as "admin"
+    And I am on site homepage
+    And I navigate to "Turn editing on" node in "Front page settings"
+    And I add the "Main menu" block
+    When I add a "Forum" to section "0" and I fill the form with:
+      | Forum name | My forum name |
+    And I click on "Edit title" "link" in the "My forum name" activity in site main menu block
+    And I set the field "New name for activity My forum name" to "New forum name"
+    And I press key "13" in the field "New name for activity My forum name"
+    Then I should not see "My forum name"
+    And I should see "New forum name"
+    And I follow "New forum name"
+    And I should not see "My forum name"
+    And I should see "New forum name"
+
+  @javascript
+  Scenario: Activities in main menu block can be made available but not visible on a course page
+    And I log in as "admin"
+    And I set the following administration settings values:
+      | allowstealth | 1 |
+    And I am on site homepage
+    And I navigate to "Turn editing on" node in "Front page settings"
+    And I add the "Main menu" block
+    When I add a "Forum" to section "0" and I fill the form with:
+      | Forum name | Visible forum |
+    When I add a "Forum" to section "0" and I fill the form with:
+      | Forum name | My forum name |
+    And "My forum name" activity in site main menu block should have "Hide" editing icon
+    And "My forum name" activity in site main menu block should not have "Show" editing icon
+    And "My forum name" activity in site main menu block should not have "Make available" editing icon
+    And "My forum name" activity in site main menu block should not have "Make unavailable" editing icon
+    And I open "My forum name" actions menu in site main menu block
+    And I click on "Hide" "link" in the "My forum name" activity in site main menu block
+    And "My forum name" activity in site main menu block should be hidden
+    And "My forum name" activity in site main menu block should not have "Hide" editing icon
+    And "My forum name" activity in site main menu block should have "Show" editing icon
+    And "My forum name" activity in site main menu block should have "Make available" editing icon
+    And "My forum name" activity in site main menu block should not have "Make unavailable" editing icon
+    And I open "My forum name" actions menu in site main menu block
+    And I click on "Make available" "link" in the "My forum name" activity in site main menu block
+    And "My forum name" activity in site main menu block should be available but hidden from course page
+    And "My forum name" activity in site main menu block should not have "Hide" editing icon
+    And "My forum name" activity in site main menu block should have "Show" editing icon
+    And "My forum name" activity in site main menu block should not have "Make available" editing icon
+    And "My forum name" activity in site main menu block should have "Make unavailable" editing icon
+    # Make sure that "Availability" dropdown in the edit menu has three options.
+    And I open "My forum name" actions menu in site main menu block
+    And I click on "Edit settings" "link" in the "My forum name" activity in site main menu block
+    And I expand all fieldsets
+    And the "Availability" select box should contain "Show on course page"
+    And the "Availability" select box should contain "Hide from students"
+    And the field "Availability" matches value "Make available but not shown on course page"
+    And I press "Save and return to course"
+    And "My forum name" activity in site main menu block should be available but hidden from course page
+    And I navigate to "Turn editing off" node in "Front page settings"
+    And "My forum name" activity in site main menu block should be available but hidden from course page
+    And I log out
+    And I should not see "My forum name" in the "Main menu" "block"
+    And I should see "Visible forum" in the "Main menu" "block"
diff --git a/site_main_menu/version.php b/site_main_menu/version.php
new file mode 100644
index 0000000..48f164c
--- /dev/null
+++ b/site_main_menu/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_site_main_menu
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_site_main_menu'; // Full name of the plugin (used for diagnostics)
diff --git a/social_activities/block_social_activities.php b/social_activities/block_social_activities.php
new file mode 100644
index 0000000..2e5ec90
--- /dev/null
+++ b/social_activities/block_social_activities.php
@@ -0,0 +1,153 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Social activities block.
+ *
+ * @package    block_social_activities
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class block_social_activities extends block_list {
+    function init(){
+        $this->title = get_string('pluginname', 'block_social_activities');
+    }
+
+    function applicable_formats() {
+        return array('course-view-social' => true);
+    }
+
+    function get_content() {
+        global $USER, $CFG, $DB, $OUTPUT;
+
+        if ($this->content !== NULL) {
+            return $this->content;
+        }
+
+        $this->content = new stdClass();
+        $this->content->items = array();
+        $this->content->icons = array();
+        $this->content->footer = '';
+
+        if (empty($this->instance)) {
+            return $this->content;
+        }
+
+        $course = $this->page->course;
+        $courserenderer = $this->page->get_renderer('core', 'course');
+
+        require_once($CFG->dirroot.'/course/lib.php');
+
+        $context = context_course::instance($course->id);
+        $isediting = $this->page->user_is_editing() && has_capability('moodle/course:manageactivities', $context);
+        $modinfo = get_fast_modinfo($course);
+
+/// extra fast view mode
+        if (!$isediting) {
+            if (!empty($modinfo->sections[0])) {
+                foreach($modinfo->sections[0] as $cmid) {
+                    $cm = $modinfo->cms[$cmid];
+                    if (!$cm->uservisible || !$cm->is_visible_on_course_page()) {
+                        continue;
+                    }
+
+                    if (!$cm->url) {
+                        $content = $courserenderer->course_section_cm_text($cm);
+                        $this->content->items[] = $content;
+                        $this->content->icons[] = '';
+                    } else {
+                        $this->content->items[] = html_writer::div($courserenderer->course_section_cm_name($cm), 'activity');
+                    }
+                }
+            }
+            return $this->content;
+        }
+
+
+        // Slow & hacky editing mode.
+        $ismoving = ismoving($course->id);
+        $section = $modinfo->get_section_info(0);
+
+        if ($ismoving) {
+            $strmovehere = get_string('movehere');
+            $strmovefull = strip_tags(get_string('movefull', '', "'$USER->activitycopyname'"));
+            $strcancel= get_string('cancel');
+        } else {
+            $strmove = get_string('move');
+        }
+
+        if ($ismoving) {
+            $this->content->icons[] = '&nbsp;' . $OUTPUT->pix_icon('t/move', get_string('move'));
+            $this->content->items[] = $USER->activitycopyname.'&nbsp;(<a href="'.$CFG->wwwroot.'/course/mod.php?cancelcopy=true&amp;sesskey='.sesskey().'">'.$strcancel.'</a>)';
+        }
+
+        if (!empty($modinfo->sections[0])) {
+            foreach ($modinfo->sections[0] as $modnumber) {
+                $mod = $modinfo->cms[$modnumber];
+                if (!$mod->uservisible || !$mod->is_visible_on_course_page()) {
+                    continue;
+                }
+                if (!$ismoving) {
+                    $actions = course_get_cm_edit_actions($mod, -1);
+
+                    // Prepend list of actions with the 'move' action.
+                    $actions = array('move' => new action_menu_link_primary(
+                        new moodle_url('/course/mod.php', array('sesskey' => sesskey(), 'copy' => $mod->id)),
+                        new pix_icon('t/move', $strmove, 'moodle', array('class' => 'iconsmall', 'title' => '')),
+                        $strmove
+                    )) + $actions;
+
+                    $editbuttons = html_writer::tag('div',
+                        $courserenderer->course_section_cm_edit_actions($actions, $mod, array('donotenhance' => true)),
+                        array('class' => 'buttons')
+                    );
+                } else {
+                    $editbuttons = '';
+                }
+                if ($mod->visible || has_capability('moodle/course:viewhiddenactivities', $mod->context)) {
+                    if ($ismoving) {
+                        if ($mod->id == $USER->activitycopy) {
+                            continue;
+                        }
+                        $this->content->items[] = '<a title="'.$strmovefull.'" href="'.$CFG->wwwroot.'/course/mod.php?moveto='.$mod->id.'&amp;sesskey='.sesskey().'">'.
+                            '<img style="height:16px; width:80px; border:0px" src="'.$OUTPUT->image_url('movehere') . '" alt="'.$strmovehere.'" /></a>';
+                        $this->content->icons[] = '';
+                    }
+                    if (!$mod->url) {
+                        $content = $courserenderer->course_section_cm_text($mod);
+                        $this->content->items[] = $content . $editbuttons;
+                        $this->content->icons[] = '';
+                    } else {
+                        $this->content->items[] = html_writer::div($courserenderer->course_section_cm_name($mod), 'activity') .
+                            $editbuttons;
+                    }
+                }
+            }
+        }
+
+        if ($ismoving) {
+            $this->content->items[] = '<a title="'.$strmovefull.'" href="'.$CFG->wwwroot.'/course/mod.php?movetosection='.$section->id.'&amp;sesskey='.sesskey().'">'.
+                                      '<img style="height:16px; width:80px; border:0px" src="'.$OUTPUT->image_url('movehere') . '" alt="'.$strmovehere.'" /></a>';
+            $this->content->icons[] = '';
+        }
+
+        $this->content->footer = $courserenderer->course_section_add_cm_control($course,
+                0, null, array('inblock' => true));
+
+        return $this->content;
+    }
+}
diff --git a/social_activities/classes/privacy/provider.php b/social_activities/classes/privacy/provider.php
new file mode 100644
index 0000000..cad5ba3
--- /dev/null
+++ b/social_activities/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_social_activities.
+ *
+ * @package    block_social_activities
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_social_activities\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_social_activities implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/social_activities/db/access.php b/social_activities/db/access.php
new file mode 100644
index 0000000..caa4303
--- /dev/null
+++ b/social_activities/db/access.php
@@ -0,0 +1,41 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Social activities block caps.
+ *
+ * @package    block_social_activities
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/social_activities:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/social_activities/lang/en/block_social_activities.php b/social_activities/lang/en/block_social_activities.php
new file mode 100644
index 0000000..3ec6b65
--- /dev/null
+++ b/social_activities/lang/en/block_social_activities.php
@@ -0,0 +1,27 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_social_activities', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_social_activities
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['pluginname'] = 'Social activities';
+$string['social_activities:addinstance'] = 'Add a new social activities block';
+$string['privacy:metadata'] = 'The Social activities block only shows data stored in other locations.';
diff --git a/social_activities/styles.css b/social_activities/styles.css
new file mode 100644
index 0000000..14dea69
--- /dev/null
+++ b/social_activities/styles.css
@@ -0,0 +1,16 @@
+.block_social_activities li {
+    clear: both;
+}
+
+.block_social_activities li .column {
+    width: 100%;
+}
+
+.block_social_activities li .buttons {
+    float: right;
+    margin: 0;
+}
+
+.block_social_activities li .buttons a img {
+    vertical-align: text-bottom;
+}
diff --git a/social_activities/tests/behat/behat_block_social_activities.php b/social_activities/tests/behat/behat_block_social_activities.php
new file mode 100644
index 0000000..2fe5526
--- /dev/null
+++ b/social_activities/tests/behat/behat_block_social_activities.php
@@ -0,0 +1,157 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Behat steps definitions for block social activities
+ *
+ * @package    block_social_activities
+ * @category   test
+ * @copyright  2016 Marina Glancy
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
+
+require_once(__DIR__ . '/../../../../lib/behat/behat_base.php');
+
+use Behat\Mink\Exception\ExpectationException as ExpectationException,
+    Behat\Mink\Exception\DriverException as DriverException,
+    Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException;
+
+/**
+ * Behat steps definitions for block social activities
+ *
+ * @package    block_social_activities
+ * @category   test
+ * @copyright  2016 Marina Glancy
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class behat_block_social_activities extends behat_base {
+
+    /**
+     * Returns the DOM node of the activity in the social activities block
+     *
+     * @throws ElementNotFoundException Thrown by behat_base::find
+     * @param string $activityname The activity name
+     * @return NodeElement
+     */
+    protected function get_social_block_activity_node($activityname) {
+        $activityname = behat_context_helper::escape($activityname);
+        $xpath = "//*[contains(concat(' ',normalize-space(@class),' '),' block_social_activities ')]//li[contains(., $activityname)]";
+
+        return $this->find('xpath', $xpath);
+    }
+
+    /**
+     * Checks that the specified activity's action menu contains an item.
+     *
+     * @Then /^"(?P<activity_name_string>(?:[^"]|\\")*)" activity in social activities block should have "(?P<icon_name_string>(?:[^"]|\\")*)" editing icon$/
+     * @param string $activityname
+     * @param string $iconname
+     */
+    public function activity_in_social_activities_block_should_have_editing_icon($activityname, $iconname) {
+        $activitynode = $this->get_social_block_activity_node($activityname);
+
+        $notfoundexception = new ExpectationException('"' . $activityname . '" doesn\'t have a "' .
+            $iconname . '" editing icon', $this->getSession());
+        $this->find('named_partial', array('link', $iconname), $notfoundexception, $activitynode);
+    }
+
+    /**
+     * Checks that the specified activity's action menu contains an item.
+     *
+     * @Then /^"(?P<activity_name_string>(?:[^"]|\\")*)" activity in social activities block should not have "(?P<icon_name_string>(?:[^"]|\\")*)" editing icon$/
+     * @param string $activityname
+     * @param string $iconname
+     */
+    public function activity_in_social_activities_block_should_not_have_editing_icon($activityname, $iconname) {
+        $activitynode = $this->get_social_block_activity_node($activityname);
+
+        try {
+            $this->find('named_partial', array('link', $iconname), false, $activitynode);
+            throw new ExpectationException('"' . $activityname . '" has a "' . $iconname .
+                '" editing icon when it should not', $this->getSession());
+        } catch (ElementNotFoundException $e) {
+            // This is good, the menu item should not be there.
+        }
+    }
+
+    /**
+     * Clicks on the specified element of the activity. You should be in the course page with editing mode turned on.
+     *
+     * @Given /^I click on "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>(?:[^"]|\\")*)" in the "(?P<activity_name_string>(?:[^"]|\\")*)" activity in social activities block$/
+     * @param string $element
+     * @param string $selectortype
+     * @param string $activityname
+     */
+    public function i_click_on_in_the_activity_in_social_activities_block($element, $selectortype, $activityname) {
+        $element = $this->get_social_block_activity_element($element, $selectortype, $activityname);
+        $element->click();
+    }
+
+    /**
+     * Clicks on the specified element inside the activity container.
+     *
+     * @throws ElementNotFoundException
+     * @param string $element
+     * @param string $selectortype
+     * @param string $activityname
+     * @return NodeElement
+     */
+    protected function get_social_block_activity_element($element, $selectortype, $activityname) {
+        $activitynode = $this->get_social_block_activity_node($activityname);
+
+        // Transforming to Behat selector/locator.
+        list($selector, $locator) = $this->transform_selector($selectortype, $element);
+        $exception = new ElementNotFoundException($this->getSession(), '"' . $element . '" "' .
+            $selectortype . '" in "' . $activityname . '" ');
+
+        return $this->find($selector, $locator, $exception, $activitynode);
+    }
+
+    /**
+     * Checks that the specified activity is hidden.
+     *
+     * @Then /^"(?P<activity_name_string>(?:[^"]|\\")*)" activity in social activities block should be hidden$/
+     * @param string $activityname
+     */
+    public function activity_in_social_activities_block_should_be_hidden($activityname) {
+        $this->get_social_block_activity_element("a.dimmed", "css_element", $activityname);
+    }
+
+    /**
+     * Checks that the specified activity is hidden.
+     *
+     * @Then /^"(?P<activity_name_string>(?:[^"]|\\")*)" activity in social activities block should be available but hidden from course page$/
+     * @param string $activityname
+     */
+    public function activity_in_social_activities_block_should_be_available_but_hidden_from_course_page($activityname) {
+        $this->get_social_block_activity_element("a.stealth", "css_element", $activityname);
+    }
+
+    /**
+     * Opens an activity actions menu if it is not already opened.
+     *
+     * @Given /^I open "(?P<activity_name_string>(?:[^"]|\\")*)" actions menu in social activities block$/
+     * @throws DriverException The step is not available when Javascript is disabled
+     * @param string $activityname
+     */
+    public function i_open_actions_menu_in_social_activities_block($activityname) {
+        $activityname = behat_context_helper::escape($activityname);
+        $xpath = "//*[contains(concat(' ',normalize-space(@class),' '),' block_social_activities ')]//li[contains(., $activityname)]";
+        $this->execute('behat_action_menu::i_open_the_action_menu_in', [$xpath, 'xpath_element']);
+    }
+}
diff --git a/social_activities/tests/behat/edit_activities.feature b/social_activities/tests/behat/edit_activities.feature
new file mode 100644
index 0000000..ad67635
--- /dev/null
+++ b/social_activities/tests/behat/edit_activities.feature
@@ -0,0 +1,85 @@
+@block @block_social_activities @format_social
+Feature: Edit activities in social activities block
+  In order to use social activities block
+  As a teacher
+  I need to add and edit activities there
+
+  Background:
+    Given the following "courses" exist:
+      | fullname | shortname | format |
+      | Course 1 | C1        | social |
+    And the following "users" exist:
+      | username | firstname | lastname |
+      | user1 | User | One |
+      | student1 | Student | One |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | user1 | C1 | editingteacher |
+      | student1 | C1 | student |
+
+  @javascript
+  Scenario: Edit name of acitivity in-place in social activities block
+    Given I log in as "user1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I set the field "Add an activity to section 'section 0'" to "Forum"
+    And I set the field "Forum name" to "My forum name"
+    And I press "Save and return to course"
+    And I click on "Edit title" "link" in the "My forum name" activity in social activities block
+    And I set the field "New name for activity My forum name" to "New forum name"
+    And I press key "13" in the field "New name for activity My forum name"
+    Then I should not see "My forum name" in the "Social activities" "block"
+    And I should see "New forum name"
+    And I follow "New forum name"
+    And I should not see "My forum name"
+    And I should see "New forum name"
+
+  @javascript
+  Scenario: Activities in social activities block can be made available but not visible on a course page
+    And I log in as "admin"
+    And I set the following administration settings values:
+      | allowstealth | 1 |
+    And I log out
+    And I log in as "user1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Recent activity" block
+    And I set the field "Add an activity to section 'section 0'" to "Forum"
+    And I set the field "Forum name" to "My forum name"
+    And I press "Save and return to course"
+    And "My forum name" activity in social activities block should have "Hide" editing icon
+    And "My forum name" activity in social activities block should not have "Show" editing icon
+    And "My forum name" activity in social activities block should not have "Make available" editing icon
+    And "My forum name" activity in social activities block should not have "Make unavailable" editing icon
+    And I wait until the page is ready
+    And I open "My forum name" actions menu in social activities block
+    And I click on "Hide" "link" in the "My forum name" activity in social activities block
+    And "My forum name" activity in social activities block should be hidden
+    And "My forum name" activity in social activities block should not have "Hide" editing icon
+    And "My forum name" activity in social activities block should have "Show" editing icon
+    And "My forum name" activity in social activities block should have "Make available" editing icon
+    And "My forum name" activity in social activities block should not have "Make unavailable" editing icon
+    And I open "My forum name" actions menu in social activities block
+    And I click on "Make available" "link" in the "My forum name" activity in social activities block
+    And "My forum name" activity in social activities block should be available but hidden from course page
+    And "My forum name" activity in social activities block should not have "Hide" editing icon
+    And "My forum name" activity in social activities block should have "Show" editing icon
+    And "My forum name" activity in social activities block should not have "Make available" editing icon
+    And "My forum name" activity in social activities block should have "Make unavailable" editing icon
+    # Make sure that "Availability" dropdown in the edit menu has three options.
+    And I open "My forum name" actions menu in social activities block
+    And I click on "Edit settings" "link" in the "My forum name" activity in social activities block
+    And I expand all fieldsets
+    And the "Availability" select box should contain "Show on course page"
+    And the "Availability" select box should contain "Hide from students"
+    And the field "Availability" matches value "Make available but not shown on course page"
+    And I press "Save and return to course"
+    And "My forum name" activity in social activities block should be available but hidden from course page
+    And I turn editing mode off
+    And "My forum name" activity in social activities block should be available but hidden from course page
+    And I log out
+    # Student will not see the module on the course page but can access it from other reports and blocks:
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    And I should not see "My forum name" in the "Social activities" "block"
+    And I click on "My forum name" "link" in the "Recent activity" "block"
+    And I should see "My forum name" in the ".breadcrumb" "css_element"
+    And I log out
diff --git a/social_activities/version.php b/social_activities/version.php
new file mode 100644
index 0000000..491fc5f
--- /dev/null
+++ b/social_activities/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_social_activities
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_social_activities'; // Full name of the plugin (used for diagnostics)
diff --git a/tag_flickr/block_tag_flickr.php b/tag_flickr/block_tag_flickr.php
new file mode 100644
index 0000000..22471f3
--- /dev/null
+++ b/tag_flickr/block_tag_flickr.php
@@ -0,0 +1,183 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Flickr tag block.
+ *
+ * @package    block_tag_flickr
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+define('FLICKR_DEV_KEY', '4fddbdd7ff2376beec54d7f6afad425e');
+define('DEFAULT_NUMBER_OF_PHOTOS', 6);
+
+class block_tag_flickr extends block_base {
+
+    function init() {
+        $this->title = get_string('pluginname','block_tag_flickr');
+    }
+
+    function applicable_formats() {
+        return array('tag' => true);
+    }
+
+    function specialization() {
+        $this->title = !empty($this->config->title) ? $this->config->title : get_string('pluginname', 'block_tag_flickr');
+    }
+
+    function instance_allow_multiple() {
+        return true;
+    }
+
+    function get_content() {
+        global $CFG, $USER;
+
+        //note: do NOT include files at the top of this file
+        require_once($CFG->libdir . '/filelib.php');
+
+        if ($this->content !== NULL) {
+            return $this->content;
+        }
+
+        $tagid = optional_param('id', 0, PARAM_INT);   // tag id - for backware compatibility
+        $tag = optional_param('tag', '', PARAM_TAG); // tag
+        $tc = optional_param('tc', 0, PARAM_INT); // Tag collection id.
+
+        if ($tagid) {
+            $tagobject = core_tag_tag::get($tagid);
+        } else if ($tag) {
+            $tagobject = core_tag_tag::get_by_name($tc, $tag);
+        }
+
+        if (empty($tagobject)) {
+            $this->content = new stdClass;
+            $this->content->text = '';
+            $this->content->footer = '';
+            return $this->content;
+        }
+
+        //include related tags in the photo query ?
+        $tagscsv = $tagobject->name;
+        if (!empty($this->config->includerelatedtags)) {
+            foreach ($tagobject->get_related_tags() as $t) {
+                $tagscsv .= ',' . $t->get_display_name(false);
+            }
+        }
+        $tagscsv = urlencode($tagscsv);
+
+        //number of photos to display
+        $numberofphotos = DEFAULT_NUMBER_OF_PHOTOS;
+        if( !empty($this->config->numberofphotos)) {
+            $numberofphotos = $this->config->numberofphotos;
+        }
+
+        //sort search results by
+        $sortby = 'relevance';
+        if( !empty($this->config->sortby)) {
+            $sortby = $this->config->sortby;
+        }
+
+        //pull photos from a specific photoset
+        if(!empty($this->config->photoset)){
+
+            $request = 'https://api.flickr.com/services/rest/?method=flickr.photosets.getPhotos';
+            $request .= '&api_key='.FLICKR_DEV_KEY;
+            $request .= '&photoset_id='.$this->config->photoset;
+            $request .= '&per_page='.$numberofphotos;
+            $request .= '&format=php_serial';
+
+            $response = $this->fetch_request($request);
+
+            $search = unserialize($response);
+
+            foreach ($search['photoset']['photo'] as $p){
+                $p['owner'] = $search['photoset']['owner'];
+            }
+
+            $photos = array_values($search['photoset']['photo']);
+
+        }
+        //search for photos tagged with $tagscsv
+        else{
+
+            $request = 'https://api.flickr.com/services/rest/?method=flickr.photos.search';
+            $request .= '&api_key='.FLICKR_DEV_KEY;
+            $request .= '&tags='.$tagscsv;
+            $request .= '&per_page='.$numberofphotos;
+            $request .= '&sort='.$sortby;
+            $request .= '&format=php_serial';
+
+            $response = $this->fetch_request($request);
+
+            $search = unserialize($response);
+            $photos = array_values($search['photos']['photo']);
+        }
+
+
+        if(strcmp($search['stat'], 'ok') != 0) return; //if no results were returned, exit...
+
+        //Accessibility: render the list of photos
+        $text = '<ul class="inline-list">';
+         foreach ($photos as $photo) {
+            $text .= '<li><a href="http://www.flickr.com/photos/' . $photo['owner'] . '/' . $photo['id'] . '/" title="'.s($photo['title']).'">';
+            $text .= '<img alt="'.s($photo['title']).'" class="flickr-photos" src="'. $this->build_photo_url($photo, 'square') ."\" /></a></li>\n";
+         }
+        $text .= "</ul>\n";
+
+        $this->content = new stdClass;
+        $this->content->text = $text;
+        $this->content->footer = '';
+
+        return $this->content;
+    }
+
+    function fetch_request($request){
+        $c =  new curl(array('cache' => true, 'module_cache'=> 'tag_flickr'));
+
+        $response = $c->get($request);
+
+        return $response;
+    }
+
+    function build_photo_url ($photo, $size='medium') {
+        //receives an array (can use the individual photo data returned
+        //from an API call) and returns a URL (doesn't mean that the
+        //file size exists)
+        $sizes = array(
+            'square' => '_s',
+            'thumbnail' => '_t',
+            'small' => '_m',
+            'medium' => '',
+            'large' => '_b',
+            'original' => '_o'
+        );
+
+        $size = strtolower($size);
+        if (!array_key_exists($size, $sizes)) {
+            $size = 'medium';
+        }
+
+        if ($size == 'original') {
+            $url = 'http://farm' . $photo['farm'] . '.static.flickr.com/' . $photo['server'] . '/' . $photo['id'] . '_' . $photo['originalsecret'] . '_o' . '.' . $photo['originalformat'];
+        } else {
+            $url = 'http://farm' . $photo['farm'] . '.static.flickr.com/' . $photo['server'] . '/' . $photo['id'] . '_' . $photo['secret'] . $sizes[$size] . '.jpg';
+        }
+        return $url;
+    }
+}
+
+
diff --git a/tag_flickr/classes/privacy/provider.php b/tag_flickr/classes/privacy/provider.php
new file mode 100644
index 0000000..fb3673d
--- /dev/null
+++ b/tag_flickr/classes/privacy/provider.php
@@ -0,0 +1,94 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_tag_flickr.
+ *
+ * @package    block_tag_flickr
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_tag_flickr\privacy;
+
+use core_privacy\local\metadata\collection;
+use core_privacy\local\request\approved_contextlist;
+use core_privacy\local\request\context;
+use core_privacy\local\request\contextlist;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_tag_flickr implementing metadata and plugin provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\provider, \core_privacy\local\request\plugin\provider {
+
+    /**
+     * Returns meta data about this system.
+     *
+     * @param   collection $collection The initialised collection to add items to.
+     * @return  collection     A listing of user data stored through this system.
+     */
+    public static function get_metadata(collection $collection) : collection {
+        $collection->add_external_location_link(
+            'flickr.com',
+            [
+                'tags' => 'privacy:metadata:block_tag_flickr:tags'
+            ],
+            'privacy:metadata:block_tag_flickr'
+        );
+
+        return $collection;
+    }
+
+    /**
+     * Get the list of contexts that contain user information for the specified user.
+     *
+     * @param   int $userid The user to search.
+     * @return  contextlist   $contextlist  The contextlist containing the list of contexts used in this plugin.
+     */
+    public static function get_contexts_for_userid(int $userid) : contextlist {
+        return new contextlist();
+    }
+
+    /**
+     * Export all user data for the specified user, in the specified contexts.
+     *
+     * @param   approved_contextlist $contextlist The approved contexts to export information for.
+     */
+    public static function export_user_data(approved_contextlist $contextlist) {
+    }
+
+    /**
+     * Delete all data for all users in the specified context.
+     *
+     * @param   context $context The specific context to delete data for.
+     */
+    public static function delete_data_for_all_users_in_context(\context $context) {
+    }
+
+    /**
+     * Delete all user data for the specified user, in the specified contexts.
+     *
+     * @param   approved_contextlist $contextlist The approved contexts and user information to delete information for.
+     */
+    public static function delete_data_for_user(approved_contextlist $contextlist) {
+    }
+
+}
diff --git a/tag_flickr/db/access.php b/tag_flickr/db/access.php
new file mode 100644
index 0000000..2e38dec
--- /dev/null
+++ b/tag_flickr/db/access.php
@@ -0,0 +1,41 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Tag flickr block caps.
+ *
+ * @package    block_tag_flickr
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/tag_flickr:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/tag_flickr/edit_form.php b/tag_flickr/edit_form.php
new file mode 100644
index 0000000..da0a23f
--- /dev/null
+++ b/tag_flickr/edit_form.php
@@ -0,0 +1,59 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Form for editing tag_flickr block instances.
+ *
+ * @package    block_tag_flickr
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Form for editing tag_flickr block instances.
+ *
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_tag_flickr_edit_form extends block_edit_form {
+    protected function specific_definition($mform) {
+        $mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
+
+        $mform->addElement('text', 'config_title', get_string('configtitle', 'block_tag_flickr'));
+        $mform->setType('config_title', PARAM_TEXT);
+
+        $mform->addElement('text', 'config_numberofphotos', get_string('numberofphotos', 'block_tag_flickr'), array('size' => 5));
+        $mform->setType('config_numberofphotos', PARAM_INT);
+
+        $mform->addElement('selectyesno', 'config_includerelatedtags', get_string('includerelatedtags', 'block_tag_flickr'));
+        $mform->setDefault('config_includerelatedtags', 0);
+
+        $sortoptions = array(
+            'date-posted-asc'  => get_string('date-posted-asc', 'block_tag_flickr'),
+            'date-posted-desc' => get_string('date-posted-desc', 'block_tag_flickr'),
+            'date-taken-asc' => get_string('date-taken-asc', 'block_tag_flickr'),
+            'date-taken-desc' => get_string('date-taken-desc', 'block_tag_flickr'),
+            'interestingness-asc' => get_string('interestingness-asc', 'block_tag_flickr'),
+            'interestingness-desc' => get_string('interestingness-desc', 'block_tag_flickr'),
+            'relevance' => get_string('relevance', 'block_tag_flickr'),
+        );
+        $mform->addElement('select', 'config_sortby', get_string('sortby', 'block_tag_flickr'), $sortoptions);
+        $mform->setDefault('config_sortby', 'relevance');
+
+        $mform->addElement('text', 'config_photoset', get_string('getfromphotoset', 'block_tag_flickr'));
+        $mform->setType('config_photoset', PARAM_ALPHANUM);
+    }
+}
diff --git a/tag_flickr/lang/en/block_tag_flickr.php b/tag_flickr/lang/en/block_tag_flickr.php
new file mode 100644
index 0000000..637d015
--- /dev/null
+++ b/tag_flickr/lang/en/block_tag_flickr.php
@@ -0,0 +1,41 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_tag_flickr', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_tag_flickr
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['configtitle'] = 'Flickr block title';
+$string['date-posted-asc'] = 'Date posted ASC';
+$string['date-posted-desc'] = 'Date posted DESC';
+$string['date-taken-asc'] = 'Date taken ASC';
+$string['date-taken-desc'] = 'Date taken DESC';
+$string['defaulttile'] = 'Flickr';
+$string['getfromphotoset'] = 'Get photos from photoset with id';
+$string['includerelatedtags'] = 'Include related tags in query';
+$string['interestingness-asc'] = 'Interestingness ASC';
+$string['interestingness-desc'] = 'Interestingness DESC';
+$string['numberofphotos'] = 'Number of photos';
+$string['pluginname'] = 'Flickr';
+$string['relevance'] = 'Relevance';
+$string['sortby'] = 'Sort by';
+$string['tag_flickr:addinstance'] = 'Add a new flickr block';
+$string['privacy:metadata:block_tag_flickr'] = 'The Flickr block plugin does not store any personal data, but does transmit user data from Moodle to the remote system.';
+$string['privacy:metadata:block_tag_flickr:tags'] = 'The tag values sent as CSV format to search for Flickr images.';
diff --git a/tag_flickr/styles.css b/tag_flickr/styles.css
new file mode 100644
index 0000000..08a9a60
--- /dev/null
+++ b/tag_flickr/styles.css
@@ -0,0 +1,3 @@
+.block_tag_flickr .flickr-photos {
+    padding: 3px;
+}
\ No newline at end of file
diff --git a/tag_flickr/tests/behat/configuring_tag_flickr_block.feature b/tag_flickr/tests/behat/configuring_tag_flickr_block.feature
new file mode 100644
index 0000000..f213f66
--- /dev/null
+++ b/tag_flickr/tests/behat/configuring_tag_flickr_block.feature
@@ -0,0 +1,20 @@
+@block @block_tag_flickr
+Feature: Adding and configuring Flickr block
+  In order to have the Flickr block used
+  As a admin
+  I need to add the Flickr block to the tags site page
+
+  @javascript
+  Scenario: Adding Flickr block to the tags site page
+    Given I log in as "admin"
+    And I press "Customise this page"
+    # TODO MDL-57120 site "Tags" link not accessible without navigation block.
+    And I add the "Navigation" block if not present
+    And I navigate to "Tags" node in "Site pages"
+    And I add the "Flickr" block
+    And I configure the "Flickr" block
+    Then I should see "Flickr block title"
+    And I set the field "Flickr block title" to "The Flickr block header"
+    And I press "Save changes"
+    And "block_tag_flickr" "block" should exist
+    Then "The Flickr block header" "block" should exist
diff --git a/tag_flickr/version.php b/tag_flickr/version.php
new file mode 100644
index 0000000..36247e3
--- /dev/null
+++ b/tag_flickr/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_tag_flickr
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_tag_flickr'; // Full name of the plugin (used for diagnostics)
diff --git a/tag_youtube/block_tag_youtube.php b/tag_youtube/block_tag_youtube.php
new file mode 100644
index 0000000..9c79fe8
--- /dev/null
+++ b/tag_youtube/block_tag_youtube.php
@@ -0,0 +1,402 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Tag youtube block
+ *
+ * @package    block_tag_youtube
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+define('DEFAULT_NUMBER_OF_VIDEOS', 5);
+
+class block_tag_youtube extends block_base {
+
+    /**
+     * @var Google_Service_Youtube
+     */
+    protected $service = null;
+
+    function init() {
+        $this->title = get_string('pluginname','block_tag_youtube');
+        $this->config = new stdClass();
+    }
+
+    function applicable_formats() {
+        return array('tag' => true);
+    }
+
+    /**
+     * It can be configured.
+     *
+     * @return bool
+     */
+    public function has_config() {
+        return true;
+    }
+
+    function specialization() {
+        $this->title = !empty($this->config->title) ? $this->config->title : get_string('pluginname', 'block_tag_youtube');
+        // Convert numeric categories (old YouTube API) to
+        // textual ones (new Google Data API)
+        $this->config->category = !empty($this->config->category) ? $this->category_map_old2new($this->config->category) : '0';
+    }
+
+    function instance_allow_multiple() {
+        return true;
+    }
+
+    function get_content() {
+        global $CFG;
+
+        //note: do NOT include files at the top of this file
+        require_once($CFG->libdir . '/filelib.php');
+
+        if ($this->content !== NULL) {
+            return $this->content;
+        }
+
+        $this->content = new stdClass();
+        $this->content->footer = '';
+
+        if (!$this->get_service()) {
+            $this->content->text = $this->get_error_message();
+            return $this->content;
+        }
+
+        $text = '';
+        if(!empty($this->config->playlist)){
+            //videos from a playlist
+            $text = $this->get_videos_by_playlist();
+        }
+        else{
+            if(!empty($this->config->category)){
+                //videos from category with tag
+                $text = $this->get_videos_by_tag_and_category();
+            }
+            else {
+                //videos with tag
+                $text = $this->get_videos_by_tag();
+            }
+        }
+
+        $this->content->text = $text;
+
+        return $this->content;
+    }
+
+    function get_videos_by_playlist(){
+
+        if (!$service = $this->get_service()) {
+            return $this->get_error_message();
+        }
+
+        $numberofvideos = DEFAULT_NUMBER_OF_VIDEOS;
+        if( !empty($this->config->numberofvideos)) {
+            $numberofvideos = $this->config->numberofvideos;
+        }
+
+        try {
+            $response = $service->playlistItems->listPlaylistItems('id,snippet', array(
+                'playlistId' => $this->config->playlist,
+                'maxResults' => $numberofvideos
+            ));
+        } catch (Google_Service_Exception $e) {
+            debugging('Google service exception: ' . $e->getMessage(), DEBUG_DEVELOPER);
+            return $this->get_error_message(get_string('requesterror', 'block_tag_youtube'));
+        }
+
+        return $this->render_items($response);
+    }
+
+    function get_videos_by_tag(){
+
+        if (!$service = $this->get_service()) {
+            return $this->get_error_message();
+        }
+
+        $tagid = optional_param('id', 0, PARAM_INT);   // tag id - for backware compatibility
+        $tag = optional_param('tag', '', PARAM_TAG); // tag
+        $tc = optional_param('tc', 0, PARAM_INT); // Tag collection id.
+
+        if ($tagid) {
+            $tagobject = core_tag_tag::get($tagid);
+        } else if ($tag) {
+            $tagobject = core_tag_tag::get_by_name($tc, $tag);
+        }
+
+        if (empty($tagobject)) {
+            return '';
+        }
+
+        $querytag = urlencode($tagobject->name);
+
+        $numberofvideos = DEFAULT_NUMBER_OF_VIDEOS;
+        if ( !empty($this->config->numberofvideos) ) {
+            $numberofvideos = $this->config->numberofvideos;
+        }
+
+        try {
+            $response = $service->search->listSearch('id,snippet', array(
+                'q' => $querytag,
+                'type' => 'video',
+                'maxResults' => $numberofvideos
+            ));
+        } catch (Google_Service_Exception $e) {
+            debugging('Google service exception: ' . $e->getMessage(), DEBUG_DEVELOPER);
+            return $this->get_error_message(get_string('requesterror', 'block_tag_youtube'));
+        }
+
+        return $this->render_items($response);
+    }
+
+    function get_videos_by_tag_and_category(){
+
+        if (!$service = $this->get_service()) {
+            return $this->get_error_message();
+        }
+
+        $tagid = optional_param('id', 0, PARAM_INT);   // tag id - for backware compatibility
+        $tag = optional_param('tag', '', PARAM_TAG); // tag
+        $tc = optional_param('tc', 0, PARAM_INT); // Tag collection id.
+
+        if ($tagid) {
+            $tagobject = core_tag_tag::get($tagid);
+        } else if ($tag) {
+            $tagobject = core_tag_tag::get_by_name($tc, $tag);
+        }
+
+        if (empty($tagobject)) {
+            return '';
+        }
+
+        $querytag = urlencode($tagobject->name);
+
+        $numberofvideos = DEFAULT_NUMBER_OF_VIDEOS;
+        if( !empty($this->config->numberofvideos)) {
+            $numberofvideos = $this->config->numberofvideos;
+        }
+
+        try {
+            $response = $service->search->listSearch('id,snippet', array(
+                'q' => $querytag,
+                'type' => 'video',
+                'maxResults' => $numberofvideos,
+                'videoCategoryId' => $this->config->category
+            ));
+        } catch (Google_Service_Exception $e) {
+            debugging('Google service exception: ' . $e->getMessage(), DEBUG_DEVELOPER);
+            return $this->get_error_message(get_string('requesterror', 'block_tag_youtube'));
+        }
+
+        return $this->render_items($response);
+    }
+
+    /**
+     * Sends a request to fetch data.
+     *
+     * @see block_tag_youtube::service
+     * @deprecated since Moodle 2.8.8, 2.9.2 and 3.0 MDL-49085 - please do not use this function any more.
+     * @param string $request
+     * @throws coding_exception
+     */
+    public function fetch_request($request) {
+        throw new coding_exception('Sorry, this function has been deprecated in Moodle 2.8.8, 2.9.2 and 3.0. Use block_tag_youtube::get_service instead.');
+
+        $c = new curl(array('cache' => true, 'module_cache'=>'tag_youtube'));
+        $c->setopt(array('CURLOPT_TIMEOUT' => 3, 'CURLOPT_CONNECTTIMEOUT' => 3));
+
+        $response = $c->get($request);
+
+        $xml = new SimpleXMLElement($response);
+        return $this->render_video_list($xml);
+    }
+
+    /**
+     * Renders the video list.
+     *
+     * @see block_tag_youtube::render_items
+     * @deprecated since Moodle 2.8.8, 2.9.2 and 3.0 MDL-49085 - please do not use this function any more.
+     * @param SimpleXMLElement $xml
+     * @throws coding_exception
+     */
+    function render_video_list(SimpleXMLElement $xml){
+        throw new coding_exception('Sorry, this function has been deprecated in Moodle 2.8.8, 2.9.2 and 3.0. Use block_tag_youtube::render_items instead.');
+    }
+
+    /**
+     * Returns an error message.
+     *
+     * Useful when the block is not properly set or something goes wrong.
+     *
+     * @param string $message The message to display.
+     * @return string HTML
+     */
+    protected function get_error_message($message = null) {
+        global $OUTPUT;
+
+        if (empty($message)) {
+            $message = get_string('apierror', 'block_tag_youtube');
+        }
+        return $OUTPUT->notification($message);
+    }
+
+    /**
+     * Gets the youtube service object.
+     *
+     * @return Google_Service_YouTube
+     */
+    protected function get_service() {
+        global $CFG;
+
+        if (!$apikey = get_config('block_tag_youtube', 'apikey')) {
+            return false;
+        }
+
+        // Wrapped in an if in case we call different get_videos_* multiple times.
+        if (!isset($this->service)) {
+            require_once($CFG->libdir . '/google/lib.php');
+            $client = get_google_client();
+            $client->setDeveloperKey($apikey);
+            $client->setScopes(array(Google_Service_YouTube::YOUTUBE_READONLY));
+            $this->service = new Google_Service_YouTube($client);
+        }
+
+        return $this->service;
+    }
+
+    /**
+     * Renders the list of items.
+     *
+     * @param array $videosdata
+     * @return string HTML
+     */
+    protected function render_items($videosdata) {
+
+        if (!$videosdata || empty($videosdata->items)) {
+            if (!empty($videosdata->error)) {
+                debugging('Error fetching data from youtube: ' . $videosdata->error->message, DEBUG_DEVELOPER);
+            }
+            return '';
+        }
+
+        // If we reach that point we already know that the API key is set.
+        $service = $this->get_service();
+
+        $text = html_writer::start_tag('ul', array('class' => 'yt-video-entry unlist img-text'));
+        foreach ($videosdata->items as $video) {
+
+            // Link to the video included in the playlist if listing a playlist.
+            if (!empty($video->snippet->resourceId)) {
+                $id = $video->snippet->resourceId->videoId;
+                $playlist = '&list=' . $video->snippet->playlistId;
+            } else {
+                $id = $video->id->videoId;
+                $playlist = '';
+            }
+
+            $thumbnail = $video->snippet->getThumbnails()->getDefault();
+            $url = 'http://www.youtube.com/watch?v=' . $id . $playlist;
+
+            $videodetails = $service->videos->listVideos('id,contentDetails', array('id' => $id));
+            if ($videodetails && !empty($videodetails->items)) {
+
+                // We fetch by id so we just use the first one.
+                $details = $videodetails->items[0];
+                $start = new DateTime('@0');
+                $start->add(new DateInterval($details->contentDetails->duration));
+                $seconds = $start->format('U');
+            }
+
+            $text .= html_writer::start_tag('li');
+
+            $imgattrs = array('class' => 'youtube-thumb', 'src' => $thumbnail->url, 'alt' => $video->snippet->title);
+            $thumbhtml = html_writer::empty_tag('img', $imgattrs);
+            $link = html_writer::tag('a', $thumbhtml, array('href' => $url));
+            $text .= html_writer::tag('div', $link, array('class' => 'clearfix'));
+
+            $text .= html_writer::tag('span', html_writer::tag('a', $video->snippet->title, array('href' => $url)));
+
+            if (!empty($seconds)) {
+                $text .= html_writer::tag('div', format_time($seconds));
+            }
+            $text .= html_writer::end_tag('li');
+        }
+        $text .= html_writer::end_tag('ul');
+
+        return $text;
+    }
+
+    function get_categories() {
+        // TODO: Right now using sticky categories from
+        // http://gdata.youtube.com/schemas/2007/categories.cat
+        // This should be performed from time to time by the block insead
+        // and cached somewhere, avoiding deprecated ones and observing regions
+        return array (
+            '0' => get_string('anycategory', 'block_tag_youtube'),
+            'Film'  => get_string('filmsanimation', 'block_tag_youtube'),
+            'Autos' => get_string('autosvehicles', 'block_tag_youtube'),
+            'Music' => get_string('music', 'block_tag_youtube'),
+            'Animals'=> get_string('petsanimals', 'block_tag_youtube'),
+            'Sports' => get_string('sports', 'block_tag_youtube'),
+            'Travel' => get_string('travel', 'block_tag_youtube'),
+            'Games'  => get_string('gadgetsgames', 'block_tag_youtube'),
+            'Comedy' => get_string('comedy', 'block_tag_youtube'),
+            'People' => get_string('peopleblogs', 'block_tag_youtube'),
+            'News'   => get_string('newspolitics', 'block_tag_youtube'),
+            'Entertainment' => get_string('entertainment', 'block_tag_youtube'),
+            'Education' => get_string('education', 'block_tag_youtube'),
+            'Howto'  => get_string('howtodiy', 'block_tag_youtube'),
+            'Tech'   => get_string('scienceandtech', 'block_tag_youtube')
+        );
+    }
+
+    /**
+     * Provide conversion from old numeric categories available in youtube API
+     * to the new ones available in the Google API
+     *
+     * @param int $oldcat old category code
+     * @return mixed new category code or 0 (if no match found)
+     *
+     * TODO: Someday this should be applied on upgrade for all the existing
+     * block instances so we won't need the mapping any more. That would imply
+     * to implement restore handling to perform the conversion of old blocks.
+     */
+    function category_map_old2new($oldcat) {
+        $oldoptions = array (
+            0  => '0',
+            1  => 'Film',
+            2  => 'Autos',
+            23 => 'Comedy',
+            24 => 'Entertainment',
+            10 => 'Music',
+            25 => 'News',
+            22 => 'People',
+            15 => 'Animals',
+            26 => 'Howto',
+            17 => 'Sports',
+            19 => 'Travel',
+            20 => 'Games'
+        );
+        if (array_key_exists($oldcat, $oldoptions)) {
+            return $oldoptions[$oldcat];
+        } else {
+            return $oldcat;
+        }
+    }
+}
+
diff --git a/tag_youtube/classes/privacy/provider.php b/tag_youtube/classes/privacy/provider.php
new file mode 100644
index 0000000..e4b1c08
--- /dev/null
+++ b/tag_youtube/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_tag_youtube.
+ *
+ * @package    block_tag_youtube
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_tag_youtube\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_tag_youtube implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/tag_youtube/db/access.php b/tag_youtube/db/access.php
new file mode 100644
index 0000000..36eee9e
--- /dev/null
+++ b/tag_youtube/db/access.php
@@ -0,0 +1,41 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Tag youtube block caps.
+ *
+ * @package    block_tag_youtube
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/tag_youtube:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/tag_youtube/db/install.php b/tag_youtube/db/install.php
new file mode 100644
index 0000000..0572762
--- /dev/null
+++ b/tag_youtube/db/install.php
@@ -0,0 +1,36 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Tag Youtube block installation.
+ *
+ * @package    block_tag_youtube
+ * @copyright  2015 Jun Pataleta
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Sets the install values for the tag_youtube entry in the block table.
+ *
+ * @return void
+ */
+function xmldb_block_tag_youtube_install() {
+    global $DB;
+
+    // Disable this block by default.
+    $DB->set_field('block', 'visible', 0, array('name' => 'tag_youtube'));
+}
+
diff --git a/tag_youtube/edit_form.php b/tag_youtube/edit_form.php
new file mode 100644
index 0000000..92b54d9
--- /dev/null
+++ b/tag_youtube/edit_form.php
@@ -0,0 +1,48 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Form for editing tag_youtube block instances.
+ *
+ * @package    block_tag_youtube
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Form for editing tag_youtube block instances.
+ *
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_tag_youtube_edit_form extends block_edit_form {
+    protected function specific_definition($mform) {
+        $mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
+
+        $mform->addElement('text', 'config_title', get_string('configtitle', 'block_tag_youtube'));
+        $mform->setType('config_title', PARAM_TEXT);
+
+        $mform->addElement('text', 'config_numberofvideos', get_string('numberofvideos', 'block_tag_youtube'), array('size' => 5));
+        $mform->setType('config_numberofvideos', PARAM_INT);
+
+        $categorychoices = $this->block->get_categories();
+        $mform->addElement('select', 'config_category', get_string('category', 'block_tag_youtube'), $categorychoices);
+        $mform->setDefault('config_category', 0);
+
+        $mform->addElement('text', 'config_playlist', get_string('includeonlyvideosfromplaylist', 'block_tag_youtube'));
+        $mform->setType('config_playlist', PARAM_ALPHANUM);
+    }
+}
diff --git a/tag_youtube/lang/en/block_tag_youtube.php b/tag_youtube/lang/en/block_tag_youtube.php
new file mode 100644
index 0000000..05ecc00
--- /dev/null
+++ b/tag_youtube/lang/en/block_tag_youtube.php
@@ -0,0 +1,50 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_tag_youtube', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_tag_youtube
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['anycategory'] = 'Any category';
+$string['apierror'] = 'The YouTube API key is not set. Contact your administrator.';
+$string['apikey'] = 'API key';
+$string['apikeyinfo'] = 'Get a <a href="https://developers.google.com/youtube/v3/getting-started">Google API key</a> for your Moodle site.';
+$string['autosvehicles'] = 'Autos &amp; Vehicles';
+$string['category'] = 'Category';
+$string['comedy'] = 'Comedy';
+$string['configtitle'] = 'YouTube block title';
+$string['education'] = 'Education';
+$string['entertainment'] = 'Entertainment';
+$string['filmsanimation'] = 'Films &amp; Animation';
+$string['gadgetsgames'] = 'Gadgets &amp; Games';
+$string['howtodiy'] = 'How-to &amp; DIY';
+$string['includeonlyvideosfromplaylist'] = 'Include only videos from the playlist with id';
+$string['music'] = 'Music';
+$string['newspolitics'] = 'News &amp; Politics';
+$string['numberofvideos'] = 'Number of videos';
+$string['peopleblogs'] = 'People &amp; Blogs';
+$string['petsanimals'] = 'Pets &amp; Animals';
+$string['pluginname'] = 'YouTube';
+$string['requesterror'] = 'Data could not be obtained from the server. Contact your administrator if the problem persists.';
+$string['scienceandtech'] = 'Science &amp; Tech';
+$string['sports'] = 'Sports';
+$string['tag_youtube:addinstance'] = 'Add a new YouTube block';
+$string['travel'] = 'Travel &amp; Places';
+$string['privacy:metadata'] = 'The YouTube block only shows data stored in other locations.';
diff --git a/tag_youtube/settings.php b/tag_youtube/settings.php
new file mode 100644
index 0000000..ad9f443
--- /dev/null
+++ b/tag_youtube/settings.php
@@ -0,0 +1,30 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Settings for the RSS client block.
+ *
+ * @package   block_tag_youtube
+ * @copyright 2015 David Monllao
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die;
+
+if ($ADMIN->fulltree) {
+    $settings->add(new admin_setting_configtext('block_tag_youtube/apikey', get_string('apikey', 'block_tag_youtube'),
+                       get_string('apikeyinfo', 'block_tag_youtube'), '', PARAM_RAW_TRIMMED, 40));
+}
diff --git a/tag_youtube/styles.css b/tag_youtube/styles.css
new file mode 100644
index 0000000..0956ff3
--- /dev/null
+++ b/tag_youtube/styles.css
@@ -0,0 +1,10 @@
+.block_tag_youtube .youtube-thumb {
+    padding: 3px;
+    padding-bottom: 0.5em;
+    display: block;
+    float: left;
+}
+
+.block_tag_youtube .yt-video-entry li {
+    clear: left;
+}
\ No newline at end of file
diff --git a/tag_youtube/tests/block_tag_youtube_test.php b/tag_youtube/tests/block_tag_youtube_test.php
new file mode 100644
index 0000000..6434c44
--- /dev/null
+++ b/tag_youtube/tests/block_tag_youtube_test.php
@@ -0,0 +1,51 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Block Tag Youtube tests
+ *
+ * @package    block_tag_youtube
+ * @category   test
+ * @copyright  2015 Jun Pataleta
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Block Tag Youtube test class.
+ *
+ * @package   block_tag_youtube
+ * @category  test
+ * @copyright 2015 Jun Pataleta
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class core_block_tag_youtube_testcase extends advanced_testcase {
+
+    /**
+     * Testing the tag youtube block's initial state after a new installation.
+     *
+     * @return void
+     */
+    public function test_after_install() {
+        global $DB;
+
+        $this->resetAfterTest(true);
+
+        // Assert that tag_youtube entry exists and that its visible attribute is set to 0 (disabled).
+        $this->assertTrue($DB->record_exists('block', array('name' => 'tag_youtube', 'visible' => 0)));
+    }
+}
diff --git a/tag_youtube/upgrade.txt b/tag_youtube/upgrade.txt
new file mode 100644
index 0000000..ae3d80d
--- /dev/null
+++ b/tag_youtube/upgrade.txt
@@ -0,0 +1,8 @@
+This files describes API changes in the block tag_youtube code.
+
+=== 3.0 ===
+
+* Due to the final YouTube API v2.0 deprecation we needed to adapt the current
+  code to YouTube Data API v3. block_tag_youtube::fetch_request and
+  block_tag_youtube::render_video_list have been deprecated as they can not be
+  used any more.
diff --git a/tag_youtube/version.php b/tag_youtube/version.php
new file mode 100644
index 0000000..ae3bfef
--- /dev/null
+++ b/tag_youtube/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_tag_youtube
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_tag_youtube'; // Full name of the plugin (used for diagnostics)
diff --git a/tags/backup/moodle2/restore_tags_block_task.class.php b/tags/backup/moodle2/restore_tags_block_task.class.php
new file mode 100644
index 0000000..11d2087
--- /dev/null
+++ b/tags/backup/moodle2/restore_tags_block_task.class.php
@@ -0,0 +1,88 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * @package   block_tags
+ * @copyright 2016 Marina Glancy
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Specialised restore task for the tags block
+ * (using execute_after_tasks for recoding of tag collection id)
+ *
+ * @package   block_tags
+ * @copyright 2016 Marina Glancy
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class restore_tags_block_task extends restore_block_task {
+
+    protected function define_my_settings() {
+    }
+
+    protected function define_my_steps() {
+    }
+
+    public function get_fileareas() {
+        return array(); // No associated fileareas.
+    }
+
+    public function get_configdata_encoded_attributes() {
+        return array(); // No special handling of configdata.
+    }
+
+    /**
+     * This function, executed after all the tasks in the plan
+     * have been executed, will remove tag collection reference in case block was restored into another site.
+     * Also get mapping of contextid.
+     */
+    public function after_restore() {
+        global $DB;
+
+        // Get the blockid.
+        $blockid = $this->get_blockid();
+
+        // Extract block configdata and remove tag collection reference if this is another site. Also map contextid.
+        if ($configdata = $DB->get_field('block_instances', 'configdata', array('id' => $blockid))) {
+            $config = unserialize(base64_decode($configdata));
+            $changed = false;
+            if (!empty($config->tagcoll) && $config->tagcoll > 1 && !$this->is_samesite()) {
+                $config->tagcoll = 0;
+                $changed = true;
+            }
+            if (!empty($config->ctx)) {
+                if ($ctxmap = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'context', $config->ctx)) {
+                    $config->ctx = $ctxmap->newitemid;
+                } else {
+                    $config->ctx = 0;
+                }
+                $changed = true;
+            }
+            if ($changed) {
+                $configdata = base64_encode(serialize($config));
+                $DB->set_field('block_instances', 'configdata', $configdata, array('id' => $blockid));
+            }
+        }
+    }
+
+    static public function define_decode_contents() {
+        return array();
+    }
+
+    static public function define_decode_rules() {
+        return array();
+    }
+}
diff --git a/tags/block_tags.php b/tags/block_tags.php
new file mode 100644
index 0000000..f263ddf
--- /dev/null
+++ b/tags/block_tags.php
@@ -0,0 +1,112 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Tags block.
+ *
+ * @package   block_tags
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class block_tags extends block_base {
+    public function init() {
+        $this->title = get_string('pluginname', 'block_tags');
+    }
+
+    public function instance_allow_multiple() {
+        return true;
+    }
+
+    public function applicable_formats() {
+        return array('all' => true);
+    }
+
+    public function instance_allow_config() {
+        return true;
+    }
+
+    public function specialization() {
+
+        // Load userdefined title and make sure it's never empty.
+        if (empty($this->config->title)) {
+            $this->title = get_string('pluginname', 'block_tags');
+        } else {
+            $this->title = format_string($this->config->title, true, ['context' => $this->context]);
+        }
+    }
+
+    public function get_content() {
+
+        global $CFG, $COURSE, $USER, $SCRIPT, $OUTPUT;
+
+        if (empty($CFG->usetags)) {
+            $this->content = new stdClass();
+            $this->content->text = '';
+            if ($this->page->user_is_editing()) {
+                $this->content->text = get_string('disabledtags', 'block_tags');
+            }
+            return $this->content;
+        }
+
+        if (!isset($this->config)) {
+            $this->config = new stdClass();
+        }
+
+        if (empty($this->config->numberoftags)) {
+            $this->config->numberoftags = 80;
+        }
+
+        if (empty($this->config->showstandard)) {
+            $this->config->showstandard = core_tag_tag::BOTH_STANDARD_AND_NOT;
+        }
+
+        if (empty($this->config->ctx)) {
+            $this->config->ctx = 0;
+        }
+
+        if (empty($this->config->rec)) {
+            $this->config->rec = 1;
+        }
+
+        if (empty($this->config->tagcoll)) {
+            $this->config->tagcoll = 0;
+        }
+
+        if ($this->content !== NULL) {
+            return $this->content;
+        }
+
+        if (empty($this->instance)) {
+            $this->content = '';
+            return $this->content;
+        }
+
+        $this->content = new stdClass;
+        $this->content->text = '';
+        $this->content->footer = '';
+
+        // Get a list of tags.
+
+        $tagcloud = core_tag_collection::get_tag_cloud($this->config->tagcoll,
+                $this->config->showstandard == core_tag_tag::STANDARD_ONLY,
+                $this->config->numberoftags,
+                'name', '', $this->page->context->id, $this->config->ctx, $this->config->rec);
+        $this->content->text = $OUTPUT->render_from_template('core_tag/tagcloud', $tagcloud->export_for_template($OUTPUT));
+
+        return $this->content;
+    }
+}
diff --git a/tags/classes/privacy/provider.php b/tags/classes/privacy/provider.php
new file mode 100644
index 0000000..8ce5159
--- /dev/null
+++ b/tags/classes/privacy/provider.php
@@ -0,0 +1,46 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Privacy Subsystem implementation for block_tags.
+ *
+ * @package    block_tags
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_tags\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for block_tags implementing null_provider.
+ *
+ * @copyright  2018 Zig Tan <zig@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/tags/db/access.php b/tags/db/access.php
new file mode 100644
index 0000000..7ba3459
--- /dev/null
+++ b/tags/db/access.php
@@ -0,0 +1,51 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Tags block caps.
+ *
+ * @package    block_tags
+ * @copyright  Mark Nelson <markn@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    'block/tags:myaddinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/my:manageblocks'
+    ),
+
+    'block/tags:addinstance' => array(
+        'riskbitmask' => RISK_SPAM | RISK_XSS,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_BLOCK,
+        'archetypes' => array(
+            'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/site:manageblocks'
+    ),
+);
diff --git a/tags/edit_form.php b/tags/edit_form.php
new file mode 100644
index 0000000..4ea8209
--- /dev/null
+++ b/tags/edit_form.php
@@ -0,0 +1,100 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Form for editing tag block instances.
+ *
+ * @package   block_tags
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Form for editing tag block instances.
+ *
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_tags_edit_form extends block_edit_form {
+    protected function specific_definition($mform) {
+        global $CFG;
+        // Fields for editing HTML block title and contents.
+        $mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
+
+        $mform->addElement('text', 'config_title', get_string('configtitle', 'block_tags'));
+        $mform->setType('config_title', PARAM_TEXT);
+        $mform->setDefault('config_title', get_string('pluginname', 'block_tags'));
+
+        $this->add_collection_selector($mform);
+
+        $numberoftags = array();
+        for ($i = 1; $i <= 200; $i++) {
+            $numberoftags[$i] = $i;
+        }
+        $mform->addElement('select', 'config_numberoftags', get_string('numberoftags', 'blog'), $numberoftags);
+        $mform->setDefault('config_numberoftags', 80);
+
+        $defaults = array(
+            core_tag_tag::STANDARD_ONLY => get_string('standardonly', 'block_tags'),
+            core_tag_tag::BOTH_STANDARD_AND_NOT => get_string('anytype', 'block_tags'));
+        $mform->addElement('select', 'config_showstandard', get_string('defaultdisplay', 'block_tags'), $defaults);
+        $mform->setDefault('config_showstandard', core_tag_tag::BOTH_STANDARD_AND_NOT);
+
+        $defaults = array(0 => context_system::instance()->get_context_name());
+        $parentcontext = context::instance_by_id($this->block->instance->parentcontextid);
+        if ($parentcontext->contextlevel > CONTEXT_COURSE) {
+            $coursecontext = $parentcontext->get_course_context();
+            $defaults[$coursecontext->id] = $coursecontext->get_context_name();
+        }
+        if ($parentcontext->contextlevel != CONTEXT_SYSTEM) {
+            $defaults[$parentcontext->id] = $parentcontext->get_context_name();
+        }
+        $mform->addElement('select', 'config_ctx', get_string('taggeditemscontext', 'block_tags'), $defaults);
+        $mform->addHelpButton('config_ctx', 'taggeditemscontext', 'block_tags');
+        $mform->setDefault('config_ctx', 0);
+
+        $mform->addElement('advcheckbox', 'config_rec', get_string('recursivecontext', 'block_tags'));
+        $mform->addHelpButton('config_rec', 'recursivecontext', 'block_tags');
+        $mform->setDefault('config_rec', 1);
+    }
+
+    /**
+     * Add the tag collection selector
+     *
+     * @param object $mform the form being built.
+     */
+    protected function add_collection_selector($mform) {
+        $tagcolls = core_tag_collection::get_collections_menu(false, false, get_string('anycollection', 'block_tags'));
+        if (count($tagcolls) <= 1) {
+            return;
+        }
+
+        $tagcollssearchable = core_tag_collection::get_collections_menu(false, true);
+        $hasunsearchable = false;
+        foreach ($tagcolls as $id => $name) {
+            if ($id && !array_key_exists($id, $tagcollssearchable)) {
+                $hasunsearchable = true;
+                $tagcolls[$id] = $name . '*';
+            }
+        }
+
+        $mform->addElement('select', 'config_tagcoll', get_string('tagcollection', 'block_tags'), $tagcolls);
+        if ($hasunsearchable) {
+            $mform->addHelpButton('config_tagcoll', 'tagcollection', 'block_tags');
+        }
+        $mform->setDefault('config_tagcoll', 0);
+    }
+}
diff --git a/tags/lang/en/block_tags.php b/tags/lang/en/block_tags.php
new file mode 100644
index 0000000..afacdd0
--- /dev/null
+++ b/tags/lang/en/block_tags.php
@@ -0,0 +1,41 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'block_tags', language 'en', branch 'MOODLE_20_STABLE'
+ *
+ * @package   block_tags
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['anycollection'] = 'Any';
+$string['anytype'] = 'All';
+$string['configtitle'] = 'Tags block title';
+$string['disabledtags'] = 'Tags are disabled';
+$string['defaultdisplay'] = 'Display tags';
+$string['pluginname'] = 'Tags';
+$string['recursivecontext'] = 'Include child contexts';
+$string['recursivecontext_help'] = 'If unticked, tags of items in the context specified above will be displayed, but not tags of items in lower contexts. For example, course tags may be displayed, but not course activity tags.';
+$string['standardonly'] = 'Only standard';
+$string['tagcollection'] = 'Tag collection';
+$string['tagcollection_help'] = 'Select tag collection to display tags from. If you choose "Any" '
+        . 'the tags from all collections except for those marked with * will be displayed';
+$string['taggeditemscontext'] = 'Tagged items context';
+$string['taggeditemscontext_help'] = 'You can limit the tag cloud to the tags that are present in the current course category, course or module';
+$string['tags:addinstance'] = 'Add a new tags block';
+$string['tags:myaddinstance'] = 'Add a new tags block to Dashboard';
+$string['privacy:metadata'] = 'The Tags block only shows data stored in other locations.';
diff --git a/tags/tests/behat/tagcloud.feature b/tags/tests/behat/tagcloud.feature
new file mode 100644
index 0000000..6a8bd41
--- /dev/null
+++ b/tags/tests/behat/tagcloud.feature
@@ -0,0 +1,49 @@
+@block @block_tags @core_tag
+Feature: Block tags displaying tag cloud
+  In order to view system tags
+  As a user
+  I need to be able to use the block tags
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email | interests |
+      | teacher1 | Teacher | 1 | teacher1@example.com | Dogs, Cats |
+      | student1 | Student | 1 | student1@example.com | |
+    And the following "courses" exist:
+      | fullname  | shortname |
+      | Course 1  | c1        |
+    And the following "tags" exist:
+      | name         | isstandard  |
+      | Neverusedtag | 1           |
+    And the following "course enrolments" exist:
+      | user     | course | role           |
+      | teacher1 | c1     | editingteacher |
+      | student1 | c1     | student        |
+
+  Scenario: Add Tags block on a front page
+    When I log in as "admin"
+    And I am on site homepage
+    And I follow "Turn editing on"
+    And I add the "Tags" block
+    And I log out
+    And I am on site homepage
+    Then I should see "Dogs" in the "Tags" "block"
+    And I should see "Cats" in the "Tags" "block"
+    And I should not see "Neverusedtag" in the "Tags" "block"
+    And I click on "Dogs" "link" in the "Tags" "block"
+    And I should see "You are not logged in"
+
+  Scenario: Add Tags block in a course
+    When I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Tags" block
+    And I log out
+    And I log in as "student1"
+    And I am on "Course 1" course homepage
+    Then I should see "Dogs" in the "Tags" "block"
+    And I should see "Cats" in the "Tags" "block"
+    And I should not see "Neverusedtag" in the "Tags" "block"
+    And I click on "Dogs" "link" in the "Tags" "block"
+    And I should see "User interests" in the ".tag-index-items h3" "css_element"
+    And I should see "Teacher 1"
+    And I log out
diff --git a/tags/version.php b/tags/version.php
new file mode 100644
index 0000000..7a24646
--- /dev/null
+++ b/tags/version.php
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Version details
+ *
+ * @package    block_tags
+ * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
+$plugin->component = 'block_tags';      // Full name of the plugin (used for diagnostics)
diff --git a/tests/behat/add_blocks.feature b/tests/behat/add_blocks.feature
new file mode 100644
index 0000000..4fadd47
--- /dev/null
+++ b/tests/behat/add_blocks.feature
@@ -0,0 +1,27 @@
+@core @core_block
+Feature: Add blocks
+  In order to add more functionality to pages
+  As a teacher
+  I need to add blocks to pages
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email |
+      | student1 | Student | 1 | student1@example.com |
+      | student2 | Student | 2 | student2@example.com |
+    And the following "courses" exist:
+      | fullname | shortname | format |
+      | Course 1 | C1 | topics |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | student1 | C1 | student |
+      | student2 | C1 | student |
+    And I log in as "admin"
+    And I am on "Course 1" course homepage with editing mode on
+    When I add the "Blog menu" block
+    Then I should see "View my entries about this course"
+
+  @javascript
+  Scenario: Add a block to a course with Javascript enabled
+
+  Scenario: Add a block to a course with Javascript disabled
diff --git a/tests/behat/behat_blocks.php b/tests/behat/behat_blocks.php
new file mode 100644
index 0000000..b05d84c
--- /dev/null
+++ b/tests/behat/behat_blocks.php
@@ -0,0 +1,152 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Steps definitions related with blocks.
+ *
+ * @package   core_block
+ * @category  test
+ * @copyright 2012 David Monllaó
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
+
+use Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException;
+
+require_once(__DIR__ . '/../../../lib/behat/behat_base.php');
+
+/**
+ * Blocks management steps definitions.
+ *
+ * @package    core_block
+ * @category   test
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class behat_blocks extends behat_base {
+
+    /**
+     * Adds the selected block. Editing mode must be previously enabled.
+     *
+     * @Given /^I add the "(?P<block_name_string>(?:[^"]|\\")*)" block$/
+     * @param string $blockname
+     */
+    public function i_add_the_block($blockname) {
+        $this->execute('behat_forms::i_set_the_field_to',
+            array("bui_addblock", $this->escape($blockname))
+        );
+
+        // If we are running without javascript we need to submit the form.
+        if (!$this->running_javascript()) {
+            $this->execute('behat_general::i_click_on_in_the',
+                array(get_string('go'), "button", "#add_block", "css_element")
+            );
+        }
+    }
+
+    /**
+     * Adds the selected block if it is not already present. Editing mode must be previously enabled.
+     *
+     * @Given /^I add the "(?P<block_name_string>(?:[^"]|\\")*)" block if not present$/
+     * @param string $blockname
+     */
+    public function i_add_the_block_if_not_present($blockname) {
+        try {
+            $this->get_text_selector_node('block', $blockname);
+        } catch (ElementNotFoundException $e) {
+            $this->execute('behat_blocks::i_add_the_block', [$blockname]);
+        }
+    }
+
+    /**
+     * Docks a block. Editing mode should be previously enabled.
+     *
+     * @Given /^I dock "(?P<block_name_string>(?:[^"]|\\")*)" block$/
+     * @param string $blockname
+     */
+    public function i_dock_block($blockname) {
+
+        // Looking for both title and alt.
+        $xpath = "//input[@type='image'][@title='" . get_string('dockblock', 'block', $blockname) . "' or @alt='" . get_string('addtodock', 'block') . "']";
+        $this->execute('behat_general::i_click_on_in_the',
+            array($xpath, "xpath_element", $this->escape($blockname), "block")
+        );
+    }
+
+    /**
+     * Opens a block's actions menu if it is not already opened.
+     *
+     * @Given /^I open the "(?P<block_name_string>(?:[^"]|\\")*)" blocks action menu$/
+     * @throws DriverException The step is not available when Javascript is disabled
+     * @param string $blockname
+     */
+    public function i_open_the_blocks_action_menu($blockname) {
+
+        if (!$this->running_javascript()) {
+            // Action menu does not need to be open if Javascript is off.
+            return;
+        }
+
+        // If it is already opened we do nothing.
+        $blocknode = $this->get_text_selector_node('block', $blockname);
+        if ($blocknode->hasClass('action-menu-shown')) {
+            return;
+        }
+
+        $this->execute('behat_general::i_click_on_in_the',
+            array(get_string('actions'), "link", $this->escape($blockname), "block")
+        );
+    }
+
+    /**
+     * Clicks on Configure block for specified block. Page must be in editing mode.
+     *
+     * Argument block_name may be either the name of the block or CSS class of the block.
+     *
+     * @Given /^I configure the "(?P<block_name_string>(?:[^"]|\\")*)" block$/
+     * @param string $blockname
+     */
+    public function i_configure_the_block($blockname) {
+        // Note that since $blockname may be either block name or CSS class, we can not use the exact label of "Configure" link.
+
+        $this->execute("behat_blocks::i_open_the_blocks_action_menu", $this->escape($blockname));
+
+        $this->execute('behat_general::i_click_on_in_the',
+            array("Configure", "link", $this->escape($blockname), "block")
+        );
+    }
+
+    /**
+     * Ensures that block can be added to the page but does not actually add it.
+     *
+     * @Then /^the add block selector should contain "(?P<block_name_string>(?:[^"]|\\")*)" block$/
+     * @param string $blockname
+     */
+    public function the_add_block_selector_should_contain_block($blockname) {
+        $this->execute('behat_forms::the_select_box_should_contain', [get_string('addblock'), $blockname]);
+    }
+
+    /**
+     * Ensures that block can not be added to the page.
+     *
+     * @Then /^the add block selector should not contain "(?P<block_name_string>(?:[^"]|\\")*)" block$/
+     * @param string $blockname
+     */
+    public function the_add_block_selector_should_not_contain_block($blockname) {
+        $this->execute('behat_forms::the_select_box_should_not_contain', [get_string('addblock'), $blockname]);
+    }
+}
diff --git a/tests/behat/configure_block_throughout_site.feature b/tests/behat/configure_block_throughout_site.feature
new file mode 100644
index 0000000..84fefa7
--- /dev/null
+++ b/tests/behat/configure_block_throughout_site.feature
@@ -0,0 +1,73 @@
+@core @core_block
+Feature: Add and configure blocks throughout the site
+  In order to maintain some patterns across all the site
+  As a manager
+  I need to set and configure blocks throughout the site
+
+  Background:
+    Given the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "users" exist:
+      | username | firstname | lastname | email |
+      | manager1 | Manager | 1 | manager1@example.com |
+      | teacher1 | teacher | 1 | teacher@example.com |
+    And the following "course enrolments" exist:
+      | user     | course | role           |
+      | teacher1 | C1     | editingteacher |
+    And the following "system role assigns" exist:
+      | user | course | role |
+      | manager1 | Acceptance test site | manager |
+    # Allow at least one role assignment in the block context:
+    And I log in as "admin"
+    And I navigate to "Define roles" node in "Site administration > Users > Permissions"
+    And I follow "Edit Non-editing teacher role"
+    And I set the following fields to these values:
+      | Block | 1 |
+    And I press "Save changes"
+    And I log out
+
+  Scenario: Add and configure a block throughtout the site
+    Given I log in as "manager1"
+    And I am on site homepage
+    And I follow "Turn editing on"
+    And I add the "Comments" block
+    And I configure the "Comments" block
+    And I set the following fields to these values:
+      | Page contexts | Display throughout the entire site |
+    And I press "Save changes"
+    When I am on "Course 1" course homepage
+    Then I should see "Comments" in the "Comments" "block"
+    And I should see "Save comment" in the "Comments" "block"
+    And I am on site homepage
+    And I configure the "Comments" block
+    And I set the following fields to these values:
+      | Default weight | -10 (first) |
+    And I press "Save changes"
+    And I am on "Course 1" course homepage
+    # The first block matching the pattern should be top-left block
+    And I should see "Comments" in the "//*[@id='region-pre' or @id='block-region-side-pre']/descendant::*[contains(concat(' ', normalize-space(@class), ' '), ' block ')]" "xpath_element"
+
+  Scenario: Blocks on the dashboard page can have roles assigned to them
+    Given I log in as "manager1"
+    When I press "Customise this page"
+    Then I should see "Assign roles in Private files block"
+
+  Scenario: Blocks on courses can have roles assigned to them
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Search forums" block
+    Then I should see "Assign roles in Search forums block"
+
+  @javascript
+  Scenario: Blocks can safely be customised
+    Given I log in as "admin"
+    And I am on homepage
+    And I press "Customise this page"
+    And I add the "HTML" block
+    And I configure the "(new HTML block)" block
+    And I set the following fields to these values:
+      | HTML block title | Foo " onload="document.getElementsByTagName('body')[0].remove()" alt=" |
+      | Content     | Example |
+    When I press "Save changes"
+    Then I should see "Course overview"
diff --git a/tests/behat/hidden_block_region.feature b/tests/behat/hidden_block_region.feature
new file mode 100644
index 0000000..e41f9f2
--- /dev/null
+++ b/tests/behat/hidden_block_region.feature
@@ -0,0 +1,52 @@
+@core @core_block
+Feature: Show hidden blocks in a docked block region when editing
+  In order to edit blocks in a hidden region
+  As a teacher
+  I need to be able to see the blocks when editing is on
+
+  Background:
+    Given the following "courses" exist:
+      | fullname | shortname | format |
+      | Course 1 | C1 | topics |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | admin | C1 | editingteacher |
+    And I log in as "admin"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Search forums" block
+    And I add the "Latest announcements" block
+    And I add the "Upcoming events" block
+    And I add the "Recent activity" block
+    # Hide all the blocks in the non-default region
+    And I configure the "Search forums" block
+    And I set the following fields to these values:
+      | Visible | No |
+    And I click on "Save changes" "button"
+    And I configure the "Latest announcements" block
+    And I set the following fields to these values:
+      | Visible | No |
+    And I click on "Save changes" "button"
+    And I configure the "Upcoming events" block
+    And I set the following fields to these values:
+      | Visible | No |
+    And I click on "Save changes" "button"
+    And I configure the "Recent activity" block
+    And I set the following fields to these values:
+      | Visible | No |
+    When I click on "Save changes" "button"
+    # Editing is on so they should be visible
+    Then I should see "Search forums"
+    And I should see "Latest announcements"
+    And I should see "Upcoming events"
+    And I should see "Recent activity"
+    And I turn editing mode off
+    # Editing is off, so they should no longer be visible
+    And I should not see "Search forums"
+    And I should not see "Latest announcements"
+    And I should not see "Upcoming events"
+    And I should not see "Recent activity"
+
+  @javascript
+  Scenario: Check that a region with only hidden blocks is not docked in editing mode (javascript enabled)
+
+  Scenario: Check that a region with only hidden blocks is not docked in editing mode (javascript disabled)
diff --git a/tests/behat/hide_blocks.feature b/tests/behat/hide_blocks.feature
new file mode 100644
index 0000000..db11e3f
--- /dev/null
+++ b/tests/behat/hide_blocks.feature
@@ -0,0 +1,27 @@
+@core @core_block
+Feature: Block visibility
+  In order to configure blocks visibility
+  As a teacher
+  I need to show and hide blocks on a page
+
+  Background:
+    Given the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And I log in as "admin"
+    And I am on "Course 1" course homepage with editing mode on
+
+  @javascript
+  Scenario: Hiding all blocks on the page should remove the column they're in
+    Given I add the "Search forums" block
+    And I open the "Search forums" blocks action menu
+    And I click on "Configure Search forums block" "link" in the "Search forums" "block"
+    And I set the field "Region" to "Right"
+    And I press "Save changes"
+    And I turn editing mode off
+    And ".empty-region-side-post" "css_element" should not exist in the "body" "css_element"
+    And I turn editing mode on
+    And I open the "Search forums" blocks action menu
+    And I click on "Hide Search forums block" "link" in the "Search forums" "block"
+    And I follow "Turn editing off"
+    And ".empty-region-side-post" "css_element" should exist in the "body" "css_element"
diff --git a/tests/behat/manage_blocks.feature b/tests/behat/manage_blocks.feature
new file mode 100644
index 0000000..19b0fc6
--- /dev/null
+++ b/tests/behat/manage_blocks.feature
@@ -0,0 +1,60 @@
+@core @core_block
+Feature: Block appearances
+  In order to configure blocks appearance
+  As a teacher
+  I need to add and modify block configuration for the page
+
+  Background:
+    Given the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "users" exist:
+      | username | firstname | lastname | email |
+      | teacher1 | teacher | 1 | teacher1@example.com |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+    And I log in as "admin"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add a "Survey" to section "1" and I fill the form with:
+      | Name | Test survey name |
+      | Survey type | ATTLS (20 item version) |
+      | Description | Test survey description |
+    And I add a "Book" to section "1" and I fill the form with:
+      | Name | Test book name |
+      | Description | Test book description |
+    And I follow "Test book name"
+    And I set the following fields to these values:
+      | Chapter title | Book title |
+      | Content       | Book content test test |
+    And I press "Save changes"
+    And I log out
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Comments" block
+    And I configure the "Comments" block
+    And I set the following fields to these values:
+      | Display on page types | Any page |
+    And I press "Save changes"
+
+  Scenario: Block settings can be modified so that a block apprears on any page
+    When I follow "Test survey name"
+    Then I should see "Comments" in the "Comments" "block"
+    And I am on "Course 1" course homepage
+    And I configure the "Comments" block
+    And I set the following fields to these values:
+      | Display on page types | Any course page |
+    And I press "Save changes"
+    And I follow "Turn editing off"
+    And I follow "Test survey name"
+    And I should not see "Comments"
+
+  Scenario: Block settings can be modified so that a block can be hidden
+    When I follow "Test book name"
+    And I configure the "Comments" block
+    And I set the following fields to these values:
+      | Visible | No |
+    And I press "Save changes"
+    And I follow "Turn editing off"
+    And I follow "Test book name"
+    Then I should not see "Comments"
diff --git a/tests/behat/move_blocks.feature b/tests/behat/move_blocks.feature
new file mode 100644
index 0000000..6a312ce
--- /dev/null
+++ b/tests/behat/move_blocks.feature
@@ -0,0 +1,46 @@
+@core @core_block
+Feature: Block region moving
+  In order to configure blocks appearance
+  As a teacher
+  I need to modify block region for the page
+
+  Background:
+    Given the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "users" exist:
+      | username | firstname | lastname | email |
+      | teacher1 | teacher | 1 | teacher1@example.com |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+    And I log in as "admin"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add a "Survey" to section "1" and I fill the form with:
+      | Name | Test survey name |
+      | Survey type | ATTLS (20 item version) |
+      | Description | Test survey description |
+    And I add a "Book" to section "1" and I fill the form with:
+      | Name | Test book name |
+      | Description | Test book description |
+    And I follow "Test book name"
+    And I set the following fields to these values:
+      | Chapter title | Book title |
+      | Content       | Book content test test |
+    And I press "Save changes"
+    And I log out
+    And I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Comments" block
+    And I configure the "Comments" block
+    And I set the following fields to these values:
+      | Display on page types | Any page |
+    And I press "Save changes"
+
+  Scenario: Block settings can be modified so that a block can be moved
+    When I follow "Test book name"
+    And I configure the "Comments" block
+    And I set the following fields to these values:
+      | Region  | Right |
+    And I press "Save changes"
+    And I should see "Comments" in the "//*[@id='region-post' or @id='block-region-side-post']" "xpath_element"
diff --git a/tests/behat/restrict_available_blocks.feature b/tests/behat/restrict_available_blocks.feature
new file mode 100644
index 0000000..581d0f8
--- /dev/null
+++ b/tests/behat/restrict_available_blocks.feature
@@ -0,0 +1,38 @@
+@core @core_block
+Feature: Allowed blocks controls
+  In order to prevent the use of some blocks
+  As an admin
+  I need to restrict some blocks to be used in courses
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email |
+      | teacher1 | Teacher | 1 | teacher1@example.com |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+
+  Scenario: Blocks can be added with the default permissions
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    When I add the "Course completion status" block
+    And I add the "Activities" block
+    Then I should see "Activities" in the "Activities" "block"
+    And I should see "Course completion status" in the "Course completion status" "block"
+
+  Scenario: Blocks can not be added when the admin restricts the permissions
+    Given I log in as "admin"
+    And I set the following system permissions of "Teacher" role:
+      | block/activity_modules:addinstance | Prohibit |
+    And I am on "Course 1" course homepage
+    And I navigate to "Users > Permissions" in current page administration
+    And I override the system permissions of "Teacher" role with:
+      | block/completionstatus:addinstance | Prohibit |
+    And I log out
+    When I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    Then the add block selector should not contain "Activities" block
+    And the add block selector should not contain "Course completion status" block
diff --git a/tests/behat/return_block_original_state.feature b/tests/behat/return_block_original_state.feature
new file mode 100644
index 0000000..79c4b97
--- /dev/null
+++ b/tests/behat/return_block_original_state.feature
@@ -0,0 +1,47 @@
+@core @core_block
+Feature: The context of a block can always be returned to it's original state.
+  In order to revert actions when configuring blocks
+  As an admin
+  I need to be able to return the block to original state
+
+  Scenario: Add and configure a block to display on every page and revert back
+    Given the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And I log in as "admin"
+    When I am on "Course 1" course homepage with editing mode on
+    And I add the "Tags" block
+    Then I should see "Tags" in the "Tags" "block"
+    And I navigate to course participants
+    And I configure the "Tags" block
+    And I set the following fields to these values:
+      | Display on page types | Any page |
+    And I press "Save changes"
+    And I am on "Course 1" course homepage
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Assignment1 |
+      | Description | Description |
+    And I follow "Assignment1"
+    And I configure the "Tags" block
+    And I set the following fields to these values:
+      | Display on page types | Any assignment module page |
+    And I press "Save changes"
+    And I should see "Tags" in the "Tags" "block"
+    And I am on "Course 1" course homepage
+    And "Tags" "block" should not exist
+    And I navigate to course participants
+    And "Tags" "block" should not exist
+    And I am on "Course 1" course homepage
+    And I add a "Assignment" to section "1" and I fill the form with:
+      | Assignment name | Assignment2 |
+      | Description | Description |
+    And I follow "Assignment2"
+    And I should see "Tags" in the "Tags" "block"
+    And I configure the "Tags" block
+    And I set the following fields to these values:
+      | Display on page types | Any page |
+    And I press "Save changes"
+    And I am on "Course 1" course homepage
+    And I should see "Tags" in the "Tags" "block"
+    And I navigate to course participants
+    And I should see "Tags" in the "Tags" "block"
diff --git a/tests/externallib_test.php b/tests/externallib_test.php
new file mode 100644
index 0000000..fdf3bea
--- /dev/null
+++ b/tests/externallib_test.php
@@ -0,0 +1,141 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * External block functions unit tests
+ *
+ * @package    core_block
+ * @category   external
+ * @copyright  2017 Juan Leyva <juan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since      Moodle 3.3
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+
+require_once($CFG->dirroot . '/webservice/tests/helpers.php');
+
+/**
+ * External block functions unit tests
+ *
+ * @package    core_block
+ * @category   external
+ * @copyright  2015 Juan Leyva <juan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since      Moodle 3.0
+ */
+class core_block_externallib_testcase extends externallib_advanced_testcase {
+
+    /**
+     * Test get_course_blocks
+     */
+    public function test_get_course_blocks() {
+        global $DB, $FULLME;
+
+        $this->resetAfterTest(true);
+
+        $user = $this->getDataGenerator()->create_user();
+        $course = $this->getDataGenerator()->create_course();
+        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
+        $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
+
+        $page = new moodle_page();
+        $page->set_context(context_course::instance($course->id));
+        $page->set_pagelayout('course');
+        $course->format = course_get_format($course)->get_format();
+        $page->set_pagetype('course-view-' . $course->format);
+        $page->blocks->load_blocks();
+        $newblock = 'calendar_upcoming';
+        $page->blocks->add_block_at_end_of_default_region($newblock);
+        $this->setUser($user);
+
+        // Check for the new block.
+        $result = core_block_external::get_course_blocks($course->id);
+        // We need to execute the return values cleaning process to simulate the web service server.
+        $result = external_api::clean_returnvalue(core_block_external::get_course_blocks_returns(), $result);
+
+        // Expect the new block.
+        $this->assertCount(1, $result['blocks']);
+        $this->assertEquals($newblock, $result['blocks'][0]['name']);
+    }
+
+    /**
+     * Test get_course_blocks on site home
+     */
+    public function test_get_course_blocks_site_home() {
+        global $DB, $FULLME;
+
+        $this->resetAfterTest(true);
+
+        $user = $this->getDataGenerator()->create_user();
+
+        $page = new moodle_page();
+        $page->set_context(context_course::instance(SITEID));
+        $page->set_pagelayout('frontpage');
+        $page->set_pagetype('site-index');
+        $page->blocks->load_blocks();
+        $newblock = 'calendar_upcoming';
+        $page->blocks->add_block_at_end_of_default_region($newblock);
+        $this->setUser($user);
+
+        // Check for the new block.
+        $result = core_block_external::get_course_blocks(SITEID);
+        // We need to execute the return values cleaning process to simulate the web service server.
+        $result = external_api::clean_returnvalue(core_block_external::get_course_blocks_returns(), $result);
+
+        // Expect the new block.
+        $this->assertCount(1, $result['blocks']);
+        $this->assertEquals($newblock, $result['blocks'][0]['name']);
+    }
+
+    /**
+     * Test get_course_blocks
+     */
+    public function test_get_course_blocks_overrides() {
+        global $DB, $CFG, $FULLME;
+
+        $this->resetAfterTest(true);
+
+        $CFG->defaultblocks_override = 'participants,search_forums,course_list:calendar_upcoming,recent_activity';
+
+        $user = $this->getDataGenerator()->create_user();
+        $course = $this->getDataGenerator()->create_course();
+        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
+        $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
+
+        $this->setUser($user);
+
+        // Try default blocks.
+        $result = core_block_external::get_course_blocks($course->id);
+        // We need to execute the return values cleaning process to simulate the web service server.
+        $result = external_api::clean_returnvalue(core_block_external::get_course_blocks_returns(), $result);
+
+        // Expect 5 default blocks.
+        $this->assertCount(5, $result['blocks']);
+
+        $expectedblocks = array('navigation', 'settings', 'participants', 'search_forums', 'course_list',
+                                'calendar_upcoming', 'recent_activity');
+        foreach ($result['blocks'] as $block) {
+            if (!in_array($block['name'], $expectedblocks)) {
+                $this->fail("Unexpected block found: " . $block['name']);
+            }
+        }
+
+    }
+
+}
diff --git a/tests/privacy_test.php b/tests/privacy_test.php
new file mode 100644
index 0000000..8c6327e
--- /dev/null
+++ b/tests/privacy_test.php
@@ -0,0 +1,364 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Data provider tests.
+ *
+ * @package    core_block
+ * @category   test
+ * @copyright  2018 Frédéric Massart
+ * @author     Frédéric Massart <fred@branchup.tech>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+global $CFG;
+
+use core_privacy\tests\provider_testcase;
+use core_privacy\local\request\approved_contextlist;
+use core_privacy\local\request\transform;
+use core_privacy\local\request\writer;
+use core_block\privacy\provider;
+
+/**
+ * Data provider testcase class.
+ *
+ * @package    core_block
+ * @category   test
+ * @copyright  2018 Frédéric Massart
+ * @author     Frédéric Massart <fred@branchup.tech>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class core_block_privacy_testcase extends provider_testcase {
+
+    public function setUp() {
+        $this->resetAfterTest();
+    }
+
+    public function test_get_contexts_for_userid() {
+        $dg = $this->getDataGenerator();
+        $c1 = $dg->create_course();
+        $c2 = $dg->create_course();
+        $u1 = $dg->create_user();
+        $u2 = $dg->create_user();
+        $c1ctx = context_course::instance($c1->id);
+        $c2ctx = context_course::instance($c2->id);
+        $u1ctx = context_user::instance($u1->id);
+        $u2ctx = context_user::instance($u2->id);
+
+        $manager = $this->get_block_manager(['region-a'], $c1ctx);
+        $manager->add_block('myprofile', 'region-a', 0, false);
+        $manager->load_blocks();
+        $blockmyprofile = $manager->get_blocks_for_region('region-a')[0];
+
+        $manager = $this->get_block_manager(['region-a'], $c2ctx);
+        $manager->add_block('login', 'region-a', 0, false);
+        $manager->add_block('mentees', 'region-a', 1, false);
+        $manager->load_blocks();
+        list($blocklogin, $blockmentees) = $manager->get_blocks_for_region('region-a');
+
+        $manager = $this->get_block_manager(['region-a'], $u1ctx);
+        $manager->add_block('private_files', 'region-a', 0, false);
+        $manager->load_blocks();
+        $blockprivatefiles = $manager->get_blocks_for_region('region-a')[0];
+
+        $this->set_hidden_pref($blocklogin, true, $u1->id);
+        $this->set_hidden_pref($blockprivatefiles, true, $u1->id);
+        $this->set_docked_pref($blockmyprofile, true, $u1->id);
+        $this->set_docked_pref($blockmentees, true, $u1->id);
+        $this->set_docked_pref($blockmentees, true, $u2->id);
+
+        $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
+        $this->assertCount(4, $contextids);
+        $this->assertTrue(in_array($blocklogin->context->id, $contextids));
+        $this->assertTrue(in_array($blockprivatefiles->context->id, $contextids));
+        $this->assertTrue(in_array($blockmyprofile->context->id, $contextids));
+        $this->assertTrue(in_array($blockmentees->context->id, $contextids));
+
+        $contextids = provider::get_contexts_for_userid($u2->id)->get_contextids();
+        $this->assertCount(1, $contextids);
+        $this->assertTrue(in_array($blockmentees->context->id, $contextids));
+    }
+
+    public function test_delete_data_for_user() {
+        global $DB;
+        $dg = $this->getDataGenerator();
+        $c1 = $dg->create_course();
+        $c2 = $dg->create_course();
+        $u1 = $dg->create_user();
+        $u2 = $dg->create_user();
+        $c1ctx = context_course::instance($c1->id);
+        $c2ctx = context_course::instance($c2->id);
+        $u1ctx = context_user::instance($u1->id);
+        $u2ctx = context_user::instance($u2->id);
+
+        $manager = $this->get_block_manager(['region-a'], $c1ctx);
+        $manager->add_block('myprofile', 'region-a', 0, false);
+        $manager->load_blocks();
+        $blockmyprofile = $manager->get_blocks_for_region('region-a')[0];
+
+        $manager = $this->get_block_manager(['region-a'], $c2ctx);
+        $manager->add_block('login', 'region-a', 0, false);
+        $manager->add_block('mentees', 'region-a', 1, false);
+        $manager->load_blocks();
+        list($blocklogin, $blockmentees) = $manager->get_blocks_for_region('region-a');
+
+        $manager = $this->get_block_manager(['region-a'], $u1ctx);
+        $manager->add_block('private_files', 'region-a', 0, false);
+        $manager->load_blocks();
+        $blockprivatefiles = $manager->get_blocks_for_region('region-a')[0];
+
+        $this->set_hidden_pref($blocklogin, true, $u1->id);
+        $this->set_hidden_pref($blocklogin, true, $u2->id);
+        $this->set_hidden_pref($blockprivatefiles, true, $u1->id);
+        $this->set_hidden_pref($blockmyprofile, true, $u1->id);
+        $this->set_docked_pref($blockmyprofile, true, $u1->id);
+        $this->set_docked_pref($blockmentees, true, $u1->id);
+        $this->set_docked_pref($blockmentees, true, $u2->id);
+
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "block{$blocklogin->instance->id}hidden"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u2->id,
+            'name' => "block{$blocklogin->instance->id}hidden"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "block{$blockprivatefiles->instance->id}hidden"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "block{$blockmyprofile->instance->id}hidden"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "docked_block_instance_{$blockmyprofile->instance->id}"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "docked_block_instance_{$blockmentees->instance->id}"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u2->id,
+            'name' => "docked_block_instance_{$blockmentees->instance->id}"]));
+
+        provider::delete_data_for_user(new approved_contextlist($u1, 'core_block', [$blocklogin->context->id,
+            $blockmyprofile->context->id, $blockmentees->context->id]));
+
+        $this->assertFalse($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "block{$blocklogin->instance->id}hidden"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u2->id,
+            'name' => "block{$blocklogin->instance->id}hidden"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "block{$blockprivatefiles->instance->id}hidden"]));
+        $this->assertFalse($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "block{$blockmyprofile->instance->id}hidden"]));
+        $this->assertFalse($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "docked_block_instance_{$blockmyprofile->instance->id}"]));
+        $this->assertFalse($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "docked_block_instance_{$blockmentees->instance->id}"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u2->id,
+            'name' => "docked_block_instance_{$blockmentees->instance->id}"]));
+    }
+
+    public function test_delete_data_for_all_users_in_context() {
+        global $DB;
+        $dg = $this->getDataGenerator();
+        $c1 = $dg->create_course();
+        $c2 = $dg->create_course();
+        $u1 = $dg->create_user();
+        $u2 = $dg->create_user();
+        $c1ctx = context_course::instance($c1->id);
+        $c2ctx = context_course::instance($c2->id);
+        $u1ctx = context_user::instance($u1->id);
+        $u2ctx = context_user::instance($u2->id);
+
+        $manager = $this->get_block_manager(['region-a'], $c1ctx);
+        $manager->add_block('myprofile', 'region-a', 0, false);
+        $manager->load_blocks();
+        $blockmyprofile = $manager->get_blocks_for_region('region-a')[0];
+
+        $manager = $this->get_block_manager(['region-a'], $c2ctx);
+        $manager->add_block('login', 'region-a', 0, false);
+        $manager->add_block('mentees', 'region-a', 1, false);
+        $manager->load_blocks();
+        list($blocklogin, $blockmentees) = $manager->get_blocks_for_region('region-a');
+
+        $manager = $this->get_block_manager(['region-a'], $u1ctx);
+        $manager->add_block('private_files', 'region-a', 0, false);
+        $manager->load_blocks();
+        $blockprivatefiles = $manager->get_blocks_for_region('region-a')[0];
+
+        $this->set_hidden_pref($blocklogin, true, $u1->id);
+        $this->set_hidden_pref($blocklogin, true, $u2->id);
+        $this->set_hidden_pref($blockprivatefiles, true, $u1->id);
+        $this->set_hidden_pref($blockmyprofile, true, $u1->id);
+        $this->set_docked_pref($blockmyprofile, true, $u1->id);
+        $this->set_docked_pref($blockmentees, true, $u1->id);
+        $this->set_docked_pref($blockmentees, true, $u2->id);
+
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "block{$blocklogin->instance->id}hidden"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u2->id,
+            'name' => "block{$blocklogin->instance->id}hidden"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "block{$blockprivatefiles->instance->id}hidden"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "block{$blockmyprofile->instance->id}hidden"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "docked_block_instance_{$blockmyprofile->instance->id}"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "docked_block_instance_{$blockmentees->instance->id}"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u2->id,
+            'name' => "docked_block_instance_{$blockmentees->instance->id}"]));
+
+        // Nothing happens.
+        provider::delete_data_for_all_users_in_context($c1ctx);
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "block{$blocklogin->instance->id}hidden"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u2->id,
+            'name' => "block{$blocklogin->instance->id}hidden"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "block{$blockprivatefiles->instance->id}hidden"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "block{$blockmyprofile->instance->id}hidden"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "docked_block_instance_{$blockmyprofile->instance->id}"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "docked_block_instance_{$blockmentees->instance->id}"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u2->id,
+            'name' => "docked_block_instance_{$blockmentees->instance->id}"]));
+
+        // Delete one block.
+        provider::delete_data_for_all_users_in_context($blocklogin->context);
+        $this->assertFalse($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "block{$blocklogin->instance->id}hidden"]));
+        $this->assertFalse($DB->record_exists('user_preferences', ['userid' => $u2->id,
+            'name' => "block{$blocklogin->instance->id}hidden"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "block{$blockprivatefiles->instance->id}hidden"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "block{$blockmyprofile->instance->id}hidden"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "docked_block_instance_{$blockmyprofile->instance->id}"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "docked_block_instance_{$blockmentees->instance->id}"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u2->id,
+            'name' => "docked_block_instance_{$blockmentees->instance->id}"]));
+
+        // Delete another block.
+        provider::delete_data_for_all_users_in_context($blockmyprofile->context);
+        $this->assertFalse($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "block{$blocklogin->instance->id}hidden"]));
+        $this->assertFalse($DB->record_exists('user_preferences', ['userid' => $u2->id,
+            'name' => "block{$blocklogin->instance->id}hidden"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "block{$blockprivatefiles->instance->id}hidden"]));
+        $this->assertFalse($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "block{$blockmyprofile->instance->id}hidden"]));
+        $this->assertFalse($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "docked_block_instance_{$blockmyprofile->instance->id}"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u1->id,
+            'name' => "docked_block_instance_{$blockmentees->instance->id}"]));
+        $this->assertTrue($DB->record_exists('user_preferences', ['userid' => $u2->id,
+            'name' => "docked_block_instance_{$blockmentees->instance->id}"]));
+    }
+
+    public function test_export_data_for_user() {
+        global $DB;
+        $dg = $this->getDataGenerator();
+        $c1 = $dg->create_course();
+        $c2 = $dg->create_course();
+        $u1 = $dg->create_user();
+        $u2 = $dg->create_user();
+        $c1ctx = context_course::instance($c1->id);
+        $c2ctx = context_course::instance($c2->id);
+        $u1ctx = context_user::instance($u1->id);
+        $u2ctx = context_user::instance($u2->id);
+        $yes = transform::yesno(true);
+        $no = transform::yesno(false);
+
+        $manager = $this->get_block_manager(['region-a'], $c1ctx);
+        $manager->add_block('myprofile', 'region-a', 0, false);
+        $manager->add_block('login', 'region-a', 1, false);
+        $manager->add_block('mentees', 'region-a', 2, false);
+        $manager->add_block('private_files', 'region-a', 3, false);
+        $manager->load_blocks();
+        list($bmyprofile, $blogin, $bmentees, $bprivatefiles) = $manager->get_blocks_for_region('region-a');
+
+        // Set some user preferences.
+        $this->set_hidden_pref($blogin, true, $u1->id);
+        $this->set_docked_pref($blogin, false, $u1->id);
+        $this->set_docked_pref($blogin, true, $u2->id);
+        $this->set_hidden_pref($bprivatefiles, false, $u1->id);
+        $this->set_docked_pref($bprivatefiles, true, $u2->id);
+        $this->set_docked_pref($bmyprofile, true, $u1->id);
+        $this->set_docked_pref($bmentees, true, $u2->id);
+
+        // Export data.
+        provider::export_user_data(new approved_contextlist($u1, 'core_block', [$bmyprofile->context->id, $blogin->context->id,
+            $bmentees->context->id, $bprivatefiles->context->id]));
+        $prefs = writer::with_context($bmentees->context)->get_user_context_preferences('core_block');
+        $this->assertEmpty((array) $prefs);
+
+        $prefs = writer::with_context($blogin->context)->get_user_context_preferences('core_block');
+        $this->assertEquals($no, $prefs->block_is_docked->value);
+        $this->assertEquals($yes, $prefs->block_is_hidden->value);
+
+        $prefs = writer::with_context($bprivatefiles->context)->get_user_context_preferences('core_block');
+        $this->assertObjectNotHasAttribute('block_is_docked', $prefs);
+        $this->assertEquals($no, $prefs->block_is_hidden->value);
+
+        $prefs = writer::with_context($bmyprofile->context)->get_user_context_preferences('core_block');
+        $this->assertEquals($yes, $prefs->block_is_docked->value);
+        $this->assertObjectNotHasAttribute('block_is_hidden', $prefs);
+    }
+
+    /**
+     * Get the block manager.
+     *
+     * @param array $regions The regions.
+     * @param context $context The context.
+     * @param string $pagetype The page type.
+     * @param string $subpage The sub page.
+     * @return block_manager
+     */
+    protected function get_block_manager($regions, $context, $pagetype = 'page-type', $subpage = '') {
+        $page = new moodle_page();
+        $page->set_context($context);
+        $page->set_pagetype($pagetype);
+        $page->set_subpage($subpage);
+        $page->set_url(new moodle_url('/'));
+
+        $blockmanager = new block_manager($page);
+        $blockmanager->add_regions($regions, false);
+        $blockmanager->set_default_region($regions[0]);
+
+        return $blockmanager;
+    }
+
+    /**
+     * Set a docked preference.
+     *
+     * @param block_base $block The block.
+     * @param bool $value The value.
+     * @param int $userid The user ID.
+     */
+    protected function set_docked_pref($block, $value, $userid) {
+        set_user_preference("docked_block_instance_{$block->instance->id}", $value, $userid);
+    }
+
+    /**
+     * Set a hidden preference.
+     *
+     * @param block_base $block The block.
+     * @param bool $value The value.
+     * @param int $userid The user ID.
+     */
+    protected function set_hidden_pref($block, $value, $userid) {
+        set_user_preference("block{$block->instance->id}hidden", $value, $userid);
+    }
+
+}
diff --git a/upgrade 14.04.12.txt b/upgrade 14.04.12.txt
new file mode 100644
index 0000000..7ef8f0a
--- /dev/null
+++ b/upgrade 14.04.12.txt	
@@ -0,0 +1,82 @@
+This files describes API changes in /blocks/* - activity modules,
+information provided here is intended especially for developers.
+
+=== 3.4 ===
+
+* The block_instances table now contains fields timecreated and timemodified. If third-party code
+  creates or updates these rows (without using the standard API), it should be modified to set
+  these fields as appropriate.
+* Blocks can now be included in Moodle global search, with some limitations (at present, the search
+  works only for blocks located directly on course pages or site home page). See the HTML block for
+  an example.
+* Block block_messages is no longer a part of core.
+
+=== 3.3 ===
+
+* block_manager::get_required_by_theme_block_types() is no longer static.
+* The plugin block_course_overview has been removed from core and is being replaced by block_myoverview.
+  During the upgrade process the block_course_overview block will be uninstalled and all its settings will be deleted.
+  If you wish to keep the block_course_overview block and its settings, download it from moodle.org and put it back in
+  the blocks/ directory BEFORE UPGRADING.
+
+=== 3.1 ===
+
+* The collapsed class was removed from the navigation block to make it compatible with aria.
+* New aria attributes were added on the navigation block [aria-expanded="false"].
+* The tree JS handling were moved from YUI to AMD module (Jquery).
+
+=== 2.9 ===
+
+* The obsolete method preferred_width() was removed (it was not doing anything)
+* Deprecated block_base::config_save as is not called anywhere and should not be used.
+* Added instance_copy() function to the block_base class. This function allows for block
+  specific data to be copied when a block is copied.
+
+=== 2.8 ===
+
+* The instance_config_print() function was removed. It was deprecated in
+  Moodle 2.0, but without debugging notices. Since it was no longer a part
+  of the code path, debugging notices would not have been displayed.
+* Deprecated functions were removed from the block_base class:
+** _print_block()
+** _print_shadow()
+** _title_html()
+** _add_edit_controls()
+** config_print()
+
+=== 2.6 ===
+
+* Deprecated /admin/block.php was removed, make sure blocks are using settings.php instead.
+
+=== 2.4 ===
+
+Created new capability 'blocks/xxx:myaddinstance' that determines whether a user can add
+a specific block to their My Home page. This capability was only defined for blocks where
+the applicable_formats function does not include "'my' => false" in the returned array,
+allowing it be added to the My Home page.
+
+=== 2.3 ===
+
+required changes in code:
+* block_xxx_pluginfile() is now given the 7th parameter (hopefully the last one) that
+  contains additional options for the file serving. The array should be re-passed
+  to send_stored_file().
+
+=== 2.0 ===
+
+required changes in code:
+* use new DML syntax everywhere
+* use new DDL syntax in db/upgrade.php
+* replace defaults.php by settings.php and db/install.php
+* replace STATEMENTS section in db/install.xml by db/install.php
+* move post instalation code from install() method into db/install.php
+* completely rewrite file handling
+* rewrite backup/restore
+* theme changes: move plugin styles into blocks/xxx/styles.css and use new css markers for images,
+                 move all images into new blocks/xxx/pix/ directory and use new outputlib api
+                 old global $THEME is fully replaced by $OUTPUT
+* remove '_utf8' from language pack names, use new {$a} syntax in language packs
+* use 'pluginname' lang pack identifier instead of 'blockname'
+* move cron and version number into standard version.php
+* removed support for old config_global.html, use settings.php
+
-- 
GitLab