فهرست منبع

merge with 1.11.x

jmontoyaa 7 سال پیش
والد
کامیت
b76f9a2ef6
100فایلهای تغییر یافته به همراه5752 افزوده شده و 3730 حذف شده
  1. 2 1
      .codeclimate.yml
  2. 2 1
      .scrutinizer.yml
  3. 50 36
      app/Migrations/Schema/V111/Version111.php
  4. 38 0
      app/Migrations/Schema/V111/Version20170522120000.php
  5. 4 4
      app/Resources/public/assets/i18next/.bower.json
  6. 27 0
      app/Resources/public/assets/i18next/CHANGELOG.md
  7. 1 1
      app/Resources/public/assets/i18next/LICENSE
  8. 57 28
      app/Resources/public/assets/i18next/i18next.js
  9. 0 0
      app/Resources/public/assets/i18next/i18next.min.js
  10. 4 4
      app/Resources/public/assets/imagesloaded/.bower.json
  11. 5 5
      app/Resources/public/assets/imagesloaded/README.md
  12. 0 5
      app/Resources/public/assets/imagesloaded/gulpfile.js
  13. 2 2
      app/Resources/public/assets/imagesloaded/imagesloaded.js
  14. 3 3
      app/Resources/public/assets/imagesloaded/imagesloaded.pkgd.js
  15. 1 1
      app/Resources/public/assets/imagesloaded/imagesloaded.pkgd.min.js
  16. 5 5
      app/Resources/public/assets/simpleWebRTC/.bower.json
  17. 6 0
      app/Resources/public/assets/simpleWebRTC/.gitignore
  18. 1 1
      app/Resources/public/assets/simpleWebRTC/.jshintignore
  19. 34 0
      app/Resources/public/assets/simpleWebRTC/.travis.yml
  20. 213 6
      app/Resources/public/assets/simpleWebRTC/README.md
  21. 4 4
      app/Resources/public/assets/simpleWebRTC/build.js
  22. 2 3
      app/Resources/public/assets/simpleWebRTC/index.html
  23. 0 0
      app/Resources/public/assets/simpleWebRTC/latest-v2.js
  24. 0 0
      app/Resources/public/assets/simpleWebRTC/latest.js
  25. 30 14
      app/Resources/public/assets/simpleWebRTC/package.json
  26. 302 0
      app/Resources/public/assets/simpleWebRTC/peer.js
  27. 3100 2760
      app/Resources/public/assets/simpleWebRTC/simplewebrtc.bundle.js
  28. 34 28
      app/Resources/public/assets/simpleWebRTC/simplewebrtc.js
  29. 1 1
      app/Resources/public/assets/simpleWebRTC/socketioconnection.js
  30. 26 0
      app/Resources/public/assets/simpleWebRTC/test/run-selenium
  31. 7 0
      app/Resources/public/assets/simpleWebRTC/test/selenium/index.js
  32. 54 0
      app/Resources/public/assets/simpleWebRTC/test/selenium/p2p.js
  33. 33 0
      app/Resources/public/assets/simpleWebRTC/test/selenium/selenium-lib.js
  34. 101 0
      app/Resources/public/assets/simpleWebRTC/test/selenium/three.js
  35. 157 0
      app/Resources/public/assets/simpleWebRTC/webrtc.js
  36. 3 0
      app/Resources/public/css/editor.css
  37. 1 1
      bower.json
  38. 15 10
      composer.json
  39. 557 18
      documentation/changelog.html
  40. 1 1
      documentation/dependencies.html
  41. 1 1
      documentation/installation_guide.html
  42. 1 1
      documentation/installation_guide_es_ES.html
  43. 1 1
      documentation/installation_guide_fr_FR.html
  44. 1 1
      documentation/installation_guide_it_IT.html
  45. 10 6
      index.php
  46. 2 2
      main/admin/access_url_add_courses_to_url.php
  47. 2 2
      main/admin/access_url_add_usergroup_to_url.php
  48. 4 3
      main/admin/access_url_add_users_to_url.php
  49. 1 1
      main/admin/access_url_edit_usergroup_to_url.php
  50. 2 2
      main/admin/access_url_edit_users_to_url.php
  51. 20 19
      main/admin/access_urls.php
  52. 1 1
      main/admin/add_courses_to_usergroup.php
  53. 1 1
      main/admin/add_sessions_to_promotion.php
  54. 1 1
      main/admin/add_sessions_to_usergroup.php
  55. 1 1
      main/admin/configure_extensions.php
  56. 149 149
      main/admin/configure_homepage.php
  57. 2 2
      main/admin/configure_inscription.php
  58. 25 5
      main/admin/course_add.php
  59. 1 1
      main/admin/course_import.php
  60. 2 1
      main/admin/course_intro_pdf_import.php
  61. 6 1
      main/admin/course_list.php
  62. 3 2
      main/admin/course_request_accepted.php
  63. 2 1
      main/admin/course_request_rejected.php
  64. 2 1
      main/admin/course_request_review.php
  65. 1 1
      main/admin/course_user_import.php
  66. 1 1
      main/admin/dashboard_add_courses_to_user.php
  67. 1 1
      main/admin/filler.php
  68. 3 3
      main/admin/grade_models.php
  69. 13 4
      main/admin/index.php
  70. 3 3
      main/admin/languages.php
  71. 17 17
      main/admin/ldap_import_students.php
  72. 1 1
      main/admin/ldap_import_students_to_session.php
  73. 128 157
      main/admin/ldap_users_list.php
  74. 1 1
      main/admin/ldap_users_synchro.php
  75. 1 1
      main/admin/legal_list.php
  76. 1 1
      main/admin/promotions.php
  77. 39 25
      main/admin/settings.lib.php
  78. 4 1
      main/admin/settings.php
  79. 1 1
      main/admin/skills_gradebook.php
  80. 2 2
      main/admin/skills_import.php
  81. 6 6
      main/admin/special_exports.php
  82. 14 6
      main/admin/specific_fields_add.php
  83. 1 1
      main/admin/sub_language.php
  84. 3 3
      main/admin/sub_language_add.php
  85. 11 7
      main/admin/subscribe_user2course.php
  86. 1 1
      main/admin/system_announcements.php
  87. 43 7
      main/admin/user_add.php
  88. 110 112
      main/admin/user_edit.php
  89. 132 135
      main/admin/user_export.php
  90. 4 3
      main/admin/user_import.php
  91. 8 1
      main/admin/user_list.php
  92. 62 64
      main/admin/user_move_stats.php
  93. 1 1
      main/admin/user_update_import.php
  94. 3 3
      main/admin/usergroup_import.php
  95. 1 1
      main/admin/usergroup_user_import.php
  96. 1 1
      main/announcements/announcements.php
  97. 1 1
      main/attendance/attendance_add.php
  98. 3 3
      main/attendance/attendance_calendar.php
  99. 1 1
      main/attendance/attendance_edit.php
  100. 5 4
      main/attendance/attendance_sheet.php

+ 2 - 1
.codeclimate.yml

@@ -59,12 +59,13 @@ exclude_paths:
 - main/lang/
 - plugin/buycourses/src/Culqi/
 - plugin/buycourses/src/Requests/
+- plugin/buycourses/src/Requests.php
+- plugin/buycourses/src/paypalfunctions.php
 - plugin/kannelsms/vendor/
 - plugin/clockworksms/vendor/
 - plugin/pens/lib
 - plugin/bbb/lib/bbb_api.php
 - plugin/ims_lti/OAuthSimple.php
-- plugin/buycourses/src/Requests.php
 - tests/
 - vendor/
 - web/

+ 2 - 1
.scrutinizer.yml

@@ -162,12 +162,13 @@ filter:
         - 'main/default_course_document'
         - 'plugin/buycourses/src/Culqi/*'
         - 'plugin/buycourses/src/Requests/*'
+        - 'plugin/buycourses/src/paypalfunctions.php'
+        - 'plugin/buycourses/src/Requests.php'
         - 'plugin/kannelsms/vendor/*'
         - 'plugin/clockworksms/vendor/*'
         - 'plugin/pens/lib/'
         - 'plugin/bbb/lib/bbb_api.php'
         - 'plugin/ims_lti/OAuthSimple.php'
-        - 'plugin/buycourses/src/Requests.php'
         - 'tests/*'
         - 'vendor/*'
         - 'web/*'

+ 50 - 36
app/Migrations/Schema/V111/Version111.php

@@ -176,48 +176,53 @@ class Version111 extends AbstractMigrationChamilo
             $this->addSql('ALTER TABLE plugin_ticket_ticket DROP ticket_id, DROP ticket_code, DROP request_user');
             $this->addSql('ALTER TABLE plugin_ticket_ticket MODIFY COLUMN id INT NOT NULL PRIMARY KEY AUTO_INCREMENT');
 
+            $table = $schema->getTable('plugin_ticket_ticket');
+            if ($table->hasIndex('fk_ticket_priority')) {
+                $table->renameIndex('fk_ticket_priority', 'IDX_EDE2C768497B19F9');
+            }
+
             if ($schema->hasTable('plugin_ticket_assigned_log')) {
+                $table = $schema->getTable('plugin_ticket_assigned_log');
+                if ($table->hasIndex('fk_ticket_assigned_log')) {
+                    $table->renameIndex('fk_ticket_assigned_log', 'IDX_54B65868700047D2');
+                }
                 $this->addSql('RENAME TABLE plugin_ticket_assigned_log TO ticket_assigned_log');
+                $this->addSql('ALTER TABLE ticket_assigned_log ENGINE=InnoDB');
             }
 
             if ($schema->hasTable('plugin_ticket_category')) {
                 $this->addSql('RENAME TABLE plugin_ticket_category TO ticket_category');
+                $this->addSql('ALTER TABLE ticket_category ENGINE=InnoDB');
             }
 
             if ($schema->hasTable('plugin_ticket_message')) {
-                $this->addSql(
-                    'RENAME TABLE plugin_ticket_message TO ticket_message'
-                );
-            }
+                $table = $schema->getTable('plugin_ticket_message');
+                if ($table->hasIndex('fk_tick_message')) {
+                    $table->renameIndex('fk_tick_message', 'IDX_BA71692D700047D2');
+                }
 
-            if ($schema->hasTable('plugin_ticket_message_attachments')) {
-                $this->addSql(
-                    'RENAME TABLE plugin_ticket_message_attachments TO ticket_message_attachments'
-                );
+                $this->addSql('RENAME TABLE plugin_ticket_message TO ticket_message');
+                $this->addSql('ALTER TABLE ticket_message ENGINE=InnoDB');
             }
 
             if ($schema->hasTable('plugin_ticket_priority')) {
-                $this->addSql(
-                    'RENAME TABLE plugin_ticket_priority TO ticket_priority'
-                );
+                $this->addSql('RENAME TABLE plugin_ticket_priority TO ticket_priority');
+                $this->addSql('ALTER TABLE ticket_priority ENGINE=InnoDB');
             }
 
             if ($schema->hasTable('plugin_ticket_project')) {
-                $this->addSql(
-                    'RENAME TABLE plugin_ticket_project TO ticket_project'
-                );
+                $this->addSql('RENAME TABLE plugin_ticket_project TO ticket_project');
+                $this->addSql('ALTER TABLE ticket_project ENGINE=InnoDB');
             }
 
             if ($schema->hasTable('plugin_ticket_status')) {
-                $this->addSql(
-                    'RENAME TABLE plugin_ticket_status TO ticket_status'
-                );
+                $this->addSql('RENAME TABLE plugin_ticket_status TO ticket_status');
+                $this->addSql('ALTER TABLE ticket_status ENGINE=InnoDB');
             }
 
             if ($schema->hasTable('plugin_ticket_ticket')) {
-                $this->addSql(
-                    'RENAME TABLE plugin_ticket_ticket TO ticket_ticket'
-                );
+                $this->addSql('RENAME TABLE plugin_ticket_ticket TO ticket_ticket');
+                $this->addSql('ALTER TABLE ticket_ticket ENGINE=InnoDB');
             }
 
             $this->addSql('ALTER TABLE ticket_project DROP project_id, CHANGE id id INT AUTO_INCREMENT NOT NULL, CHANGE name name VARCHAR(255) NOT NULL, CHANGE description description LONGTEXT DEFAULT NULL, CHANGE email email VARCHAR(255) DEFAULT NULL, CHANGE other_area other_area INT DEFAULT NULL, CHANGE sys_insert_user_id sys_insert_user_id INT NOT NULL, CHANGE sys_insert_datetime sys_insert_datetime DATETIME NOT NULL, CHANGE sys_lastedit_user_id sys_lastedit_user_id INT DEFAULT NULL;');
@@ -238,9 +243,8 @@ class Version111 extends AbstractMigrationChamilo
             if ($schema->hasTable('plugin_ticket_category_rel_user')) {
                 $table = $schema->getTable('plugin_ticket_category_rel_user');
                 $this->addSql('RENAME TABLE plugin_ticket_category_rel_user TO ticket_category_rel_user');
+                $this->addSql('ALTER TABLE ticket_category_rel_user ENGINE=InnoDB');
                 $this->addSql('ALTER TABLE ticket_category_rel_user CHANGE id id INT AUTO_INCREMENT NOT NULL, CHANGE category_id category_id INT DEFAULT NULL, CHANGE user_id user_id INT DEFAULT NULL;');
-                $this->addSql('CREATE INDEX IDX_5B8A98712469DE2 ON ticket_category_rel_user (category_id);');
-                $this->addSql('CREATE INDEX IDX_5B8A987A76ED395 ON ticket_category_rel_user (user_id);');
 
                 if ($table->hasIndex('fk_5b8a98712469de2')) {
                     $table->dropIndex('fk_5b8a98712469de2');
@@ -249,16 +253,32 @@ class Version111 extends AbstractMigrationChamilo
                 if ($table->hasIndex('fk_5b8a987a76ed395')) {
                     $table->dropIndex('fk_5b8a987a76ed395');
                 }
+
+                $this->addSql('CREATE INDEX IDX_5B8A98712469DE2 ON ticket_category_rel_user (category_id);');
+                $this->addSql('CREATE INDEX IDX_5B8A987A76ED395 ON ticket_category_rel_user (user_id);');
             } else {
                 $this->addSql('CREATE TABLE IF NOT EXISTS ticket_category_rel_user (id INT AUTO_INCREMENT NOT NULL, category_id INT DEFAULT NULL, user_id INT DEFAULT NULL, INDEX IDX_5B8A98712469DE2 (category_id), INDEX IDX_5B8A987A76ED395 (user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
                 $this->addSql('ALTER TABLE ticket_category_rel_user ADD CONSTRAINT FK_5B8A98712469DE2 FOREIGN KEY (category_id) REFERENCES ticket_category (id)');
                 $this->addSql('ALTER TABLE ticket_category_rel_user ADD CONSTRAINT FK_5B8A987A76ED395 FOREIGN KEY (user_id) REFERENCES user (id)');
             }
 
-            $this->addSql('ALTER TABLE ticket_message_attachments DROP message_attch_id, CHANGE id id INT AUTO_INCREMENT NOT NULL, CHANGE message_id message_id INT DEFAULT NULL, CHANGE ticket_id ticket_id INT DEFAULT NULL, CHANGE filename filename LONGTEXT NOT NULL, CHANGE size size INT NOT NULL, CHANGE sys_insert_user_id sys_insert_user_id INT NOT NULL, CHANGE sys_insert_datetime sys_insert_datetime DATETIME NOT NULL, CHANGE sys_lastedit_user_id sys_lastedit_user_id INT DEFAULT NULL;');
-            $this->addSql('ALTER TABLE ticket_message_attachments ADD CONSTRAINT FK_70BF9E26700047D2 FOREIGN KEY (ticket_id) REFERENCES ticket_ticket (id);');
-            $this->addSql('CREATE INDEX IDX_70BF9E26700047D2 ON ticket_message_attachments (ticket_id);');
-            $this->addSql('ALTER TABLE ticket_message_attachments RENAME INDEX ticket_message_id_fk TO IDX_70BF9E26537A1329;');
+            if ($schema->hasTable('plugin_ticket_message_attachments')) {
+                $table = $schema->getTable('plugin_ticket_message_attachments');
+                if ($table->hasIndex('ticket_message_id_fk')) {
+                    $table->renameIndex('ticket_message_id_fk', 'IDX_70BF9E26537A1329');
+                }
+
+                $this->addSql('RENAME TABLE plugin_ticket_message_attachments TO ticket_message_attachments');
+                $this->addSql('ALTER TABLE ticket_message_attachments ENGINE=InnoDB');
+                $this->addSql('ALTER TABLE ticket_message_attachments DROP message_attch_id, CHANGE id id INT AUTO_INCREMENT NOT NULL, CHANGE message_id message_id INT DEFAULT NULL, CHANGE ticket_id ticket_id INT DEFAULT NULL, CHANGE filename filename LONGTEXT NOT NULL, CHANGE size size INT NOT NULL, CHANGE sys_insert_user_id sys_insert_user_id INT NOT NULL, CHANGE sys_insert_datetime sys_insert_datetime DATETIME NOT NULL, CHANGE sys_lastedit_user_id sys_lastedit_user_id INT DEFAULT NULL;');
+                $this->addSql('ALTER TABLE ticket_message_attachments ADD CONSTRAINT FK_70BF9E26700047D2 FOREIGN KEY (ticket_id) REFERENCES ticket_ticket (id);');
+                $this->addSql('ALTER TABLE ticket_message_attachments ADD CONSTRAINT FK_70BF9E26537A1329 FOREIGN KEY (message_id) REFERENCES ticket_message (id);');
+                $this->addSql('CREATE INDEX IDX_70BF9E26700047D2 ON ticket_message_attachments (ticket_id);');
+            } else {
+                $this->addSql('CREATE TABLE IF NOT EXISTS ticket_message_attachments (id INT AUTO_INCREMENT NOT NULL, ticket_id INT DEFAULT NULL, message_id INT DEFAULT NULL, path VARCHAR(255) NOT NULL, filename LONGTEXT NOT NULL, size INT NOT NULL, sys_insert_user_id INT NOT NULL, sys_insert_datetime DATETIME NOT NULL, sys_lastedit_user_id INT DEFAULT NULL, sys_lastedit_datetime DATETIME DEFAULT NULL, INDEX IDX_70BF9E26700047D2 (ticket_id), INDEX IDX_70BF9E26537A1329 (message_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
+                $this->addSql('ALTER TABLE ticket_message_attachments ADD CONSTRAINT FK_70BF9E26700047D2 FOREIGN KEY (ticket_id) REFERENCES ticket_ticket (id)');
+                $this->addSql('ALTER TABLE ticket_message_attachments ADD CONSTRAINT FK_70BF9E26537A1329 FOREIGN KEY (message_id) REFERENCES ticket_message (id)');
+            }
 
             $this->addSql('UPDATE ticket_priority SET sys_insert_user_id = 1 WHERE sys_insert_user_id IS NULL');
             $this->addSql('UPDATE ticket_priority SET sys_insert_datetime = NOW() WHERE sys_insert_datetime IS NULL');
@@ -272,13 +292,9 @@ class Version111 extends AbstractMigrationChamilo
             $this->addSql('UPDATE ticket_priority SET urgency = priority_urgency');
 
             $this->addSql('ALTER TABLE ticket_priority DROP priority_id, DROP priority, DROP priority_desc, DROP priority_color, DROP priority_urgency');
-
             $this->addSql('UPDATE ticket_ticket t SET priority_id = (SELECT id FROM ticket_priority t2 WHERE t2.code = t.priority_id)');
             $this->addSql('UPDATE ticket_ticket t SET status_id = (SELECT id FROM ticket_status t2 WHERE t2.code = t.status_id)');
-
-
             $this->addSql('ALTER TABLE ticket_ticket ADD CONSTRAINT FK_EDE2C768497B19F9 FOREIGN KEY (priority_id) REFERENCES ticket_priority (id);');
-
             $this->addSql('UPDATE ticket_ticket SET project_id = 1 WHERE project_id is NULL or project_id = 0');
             $this->addSql('ALTER TABLE ticket_ticket ADD CONSTRAINT FK_EDE2C768166D1F9C FOREIGN KEY (project_id) REFERENCES ticket_project (id);');
 
@@ -294,7 +310,6 @@ class Version111 extends AbstractMigrationChamilo
             $this->addSql('CREATE INDEX IDX_EDE2C768613FECDF ON ticket_ticket (session_id);');
             $this->addSql('CREATE INDEX IDX_EDE2C7686BF700BD ON ticket_ticket (status_id);');
 
-            $this->addSql('ALTER TABLE ticket_ticket RENAME INDEX fk_ticket_priority TO IDX_EDE2C768497B19F9;');
             $this->addSql('ALTER TABLE ticket_assigned_log CHANGE id id INT AUTO_INCREMENT NOT NULL, CHANGE ticket_id ticket_id INT DEFAULT NULL, CHANGE user_id user_id INT DEFAULT NULL, CHANGE assigned_date assigned_date DATETIME NOT NULL, CHANGE sys_insert_user_id sys_insert_user_id INT NOT NULL;');
             $this->addSql('ALTER TABLE ticket_assigned_log ADD CONSTRAINT FK_54B65868700047D2 FOREIGN KEY (ticket_id) REFERENCES ticket_ticket (id);');
 
@@ -302,17 +317,15 @@ class Version111 extends AbstractMigrationChamilo
 
             $this->addSql('ALTER TABLE ticket_assigned_log ADD CONSTRAINT FK_54B65868A76ED395 FOREIGN KEY (user_id) REFERENCES user (id);');
             $this->addSql('CREATE INDEX IDX_54B65868A76ED395 ON ticket_assigned_log (user_id);');
-            $this->addSql('ALTER TABLE ticket_assigned_log RENAME INDEX fk_ticket_assigned_log TO IDX_54B65868700047D2;');
 
 
             $this->addSql('ALTER TABLE ticket_message DROP message_id, CHANGE id id INT AUTO_INCREMENT NOT NULL, CHANGE ticket_id ticket_id INT DEFAULT NULL, CHANGE subject subject VARCHAR(255) DEFAULT NULL, CHANGE message message LONGTEXT DEFAULT NULL, CHANGE status status VARCHAR(255) NOT NULL, CHANGE ip_address ip_address VARCHAR(255) NOT NULL, CHANGE sys_insert_user_id sys_insert_user_id INT NOT NULL, CHANGE sys_insert_datetime sys_insert_datetime DATETIME NOT NULL, CHANGE sys_lastedit_user_id sys_lastedit_user_id INT DEFAULT NULL;');
             $this->addSql('ALTER TABLE ticket_message ADD CONSTRAINT FK_BA71692D700047D2 FOREIGN KEY (ticket_id) REFERENCES ticket_ticket (id);');
-            $this->addSql('ALTER TABLE ticket_message RENAME INDEX fk_tick_message TO IDX_BA71692D700047D2;');
+
+
             $this->addSql('ALTER TABLE ticket_ticket CHANGE category_id category_id INT DEFAULT NULL;');
             $this->addSql('ALTER TABLE ticket_ticket ADD CONSTRAINT FK_EDE2C76812469DE2 FOREIGN KEY (category_id) REFERENCES ticket_category (id);');
             $this->addSql('CREATE INDEX IDX_EDE2C76812469DE2 ON ticket_ticket (category_id);');
-
-            $this->addSql('ALTER TABLE ticket_message_attachments ADD CONSTRAINT FK_70BF9E26537A1329 FOREIGN KEY (message_id) REFERENCES ticket_message (id);');
             $this->addSql('DELETE FROM settings_current WHERE title = "Ticket"');
         } else {
             // Plugin was never installed. Create ticket tables
@@ -387,7 +400,8 @@ class Version111 extends AbstractMigrationChamilo
         $this->addSql("ALTER TABLE session MODIFY COLUMN name VARCHAR(150) NOT NULL DEFAULT ''");
 
         if (!$schema->hasTable('version')) {
-            $this->addSql('CREATE TABLE version (id int unsigned NOT NULL AUTO_INCREMENT, version varchar(255), PRIMARY KEY(id), UNIQUE(version));');
+            $sql = getVersionTable();
+            $this->addSql($sql);
         }
 
         if ($schema->hasTable('resource')) {

+ 38 - 0
app/Migrations/Schema/V111/Version20170522120000.php

@@ -0,0 +1,38 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Application\Migrations\Schema\V111;
+
+use Application\Migrations\AbstractMigrationChamilo;
+use Doctrine\DBAL\Schema\Schema;
+
+/**
+ * Class Version20170522120000
+ * Remove track_e_attempt.course_code which is deleted between 1.9 and 1.10
+ * but somehow still existed in the 1.10 entity (and it is not deleted from 
+ * 1.10 to 1.11)
+ * @package Application\Migrations\Schema\V111
+ */
+class Version20170522120000 extends AbstractMigrationChamilo
+{
+    /**
+     * @param Schema $schema
+     */
+    public function up(Schema $schema)
+    {
+        $trackEAttempt = $schema->getTable('track_e_attempt');
+
+        if ($trackEAttempt->hasColumn('course_code')) {
+            $this->addSql("ALTER TABLE track_e_attempt DROP COLUMN course_code");
+        }
+    }
+
+    /**
+     * Down does not do anything in this case because the field shouldn't
+     * have been there in the first place
+     * @param Schema $schema
+     */
+    public function down(Schema $schema)
+    {
+    }
+}

+ 4 - 4
app/Resources/public/assets/i18next/.bower.json

@@ -18,12 +18,12 @@
     "karma.conf.js"
   ],
   "homepage": "https://github.com/i18next/i18next",
-  "version": "7.1.3",
-  "_release": "7.1.3",
+  "version": "8.2.1",
+  "_release": "8.2.1",
   "_resolution": {
     "type": "version",
-    "tag": "v7.1.3",
-    "commit": "eb036b4b3db9c2dd2f0dc079ec4f07e01da23590"
+    "tag": "v8.2.1",
+    "commit": "030a200df42689ebdc0f334a0fc6f3deb22e6e82"
   },
   "_source": "https://github.com/i18next/i18next.git",
   "_target": ">=2.4.0",

+ 27 - 0
app/Resources/public/assets/i18next/CHANGELOG.md

@@ -1,3 +1,30 @@
+### 8.2.1
+- fixes issue in async lng detection
+
+### 8.2.0
+- supports now async language detection - when language detector has member async = true
+
+### 8.1.0
+- option to disable nesting by calling `i18next.t('key', { nest: false })` [PR920](https://github.com/i18next/i18next/pull/920)
+- fixes passing lng from options to formatter function if available
+
+### 8.0.0
+- nonExplicitWhitelist flag now not only gets considered on a fallback lng but also on user language. Eg. userlng 'de-AT' and whitelist ['de'] will now let de-AT pass as whitelisted if nonExplicitWhitelist is set true.
+
+### 7.2.3
+- rebuild seems we had a mistake in pushing latest build
+
+### 7.2.2
+- fixes issue in accepting string as a result of "nested" lookup [PR909](https://github.com/i18next/i18next/pull/909)
+
+### 7.2.1
+- fixes iterating over object's own properties [#904](https://github.com/i18next/i18next/pull/904)
+
+### 7.2.0
+- new init option simplifyPluralSuffix - setting it to false will treat all plurals using suffix numbers even for locals only having singular and plural
+- even if no lng set or detected at least load the fallback languages
+- delay init call on createInstance if not set initImmediate to false [#879](https://github.com/i18next/i18next/issues/879)
+
 ### 7.1.3
 - fixes issue in returnObject tree called with options including ns: [react-i18next #240](https://github.com/i18next/react-i18next/issues/240)
 

+ 1 - 1
app/Resources/public/assets/i18next/LICENSE

@@ -1,6 +1,6 @@
 The MIT License (MIT)
 
-Copyright (c) 2015 i18next
+Copyright (c) 2017 i18next
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal

+ 57 - 28
app/Resources/public/assets/i18next/i18next.js

@@ -279,16 +279,20 @@ function getLastOfPath(object, path, Empty) {
     return key && key.indexOf('###') > -1 ? key.replace(/###/g, '.') : key;
   }
 
+  function canNotTraverseDeeper() {
+    return !object || typeof object === 'string';
+  }
+
   var stack = typeof path !== 'string' ? [].concat(path) : path.split('.');
   while (stack.length > 1) {
-    if (!object) return {};
+    if (canNotTraverseDeeper()) return {};
 
     var key = cleanKey(stack.shift());
     if (!object[key] && Empty) object[key] = new Empty();
     object = object[key];
   }
 
-  if (!object) return {};
+  if (canNotTraverseDeeper()) return {};
   return {
     obj: object,
     k: cleanKey(stack.shift())
@@ -752,7 +756,9 @@ var Translator = function (_EventEmitter) {
         var copy$$1 = resType === '[object Array]' ? [] : {}; // apply child translation on a copy
 
         for (var m in res) {
-          copy$$1[m] = this.translate('' + key + keySeparator + m, _extends({}, options, { joinArrays: false, ns: namespaces }));
+          if (res.hasOwnProperty(m)) {
+            copy$$1[m] = this.translate('' + key + keySeparator + m, _extends({}, options, { joinArrays: false, ns: namespaces }));
+          }
         }
         res = copy$$1;
       }
@@ -827,10 +833,10 @@ var Translator = function (_EventEmitter) {
     // interpolate
     var data = options.replace && typeof options.replace !== 'string' ? options.replace : options;
     if (this.options.interpolation.defaultVariables) data = _extends({}, this.options.interpolation.defaultVariables, data);
-    res = this.interpolator.interpolate(res, data, this.language);
+    res = this.interpolator.interpolate(res, data, options.lng || this.language);
 
     // nesting
-    res = this.interpolator.nest(res, function () {
+    if (options.nest !== false) res = this.interpolator.nest(res, function () {
       for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
         args[_key] = arguments[_key];
       }
@@ -984,11 +990,11 @@ var LanguageUtil = function () {
     }
   };
 
-  LanguageUtil.prototype.isWhitelisted = function isWhitelisted(code, exactMatch) {
-    if (this.options.load === 'languageOnly' || this.options.nonExplicitWhitelist && !exactMatch) {
+  LanguageUtil.prototype.isWhitelisted = function isWhitelisted(code) {
+    if (this.options.load === 'languageOnly' || this.options.nonExplicitWhitelist) {
       code = this.getLanguagePartFromCode(code);
     }
-    return !this.whitelist || !this.whitelist.length || this.whitelist.indexOf(code) > -1 ? true : false;
+    return !this.whitelist || !this.whitelist.length || this.whitelist.indexOf(code) > -1;
   };
 
   LanguageUtil.prototype.getFallbackCodes = function getFallbackCodes(fallbacks, code) {
@@ -1014,10 +1020,8 @@ var LanguageUtil = function () {
 
     var codes = [];
     var addCode = function addCode(code) {
-      var exactMatch = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
-
       if (!code) return;
-      if (_this.isWhitelisted(code, exactMatch)) {
+      if (_this.isWhitelisted(code)) {
         codes.push(code);
       } else {
         _this.logger.warn('rejecting non-whitelisted language code: ' + code);
@@ -1025,8 +1029,8 @@ var LanguageUtil = function () {
     };
 
     if (typeof code === 'string' && code.indexOf('-') > -1) {
-      if (this.options.load !== 'languageOnly') addCode(this.formatLanguageCode(code), true);
-      if (this.options.load !== 'languageOnly' && this.options.load !== 'currentOnly') addCode(this.getScriptPartFromCode(code), true);
+      if (this.options.load !== 'languageOnly') addCode(this.formatLanguageCode(code));
+      if (this.options.load !== 'languageOnly' && this.options.load !== 'currentOnly') addCode(this.getScriptPartFromCode(code));
       if (this.options.load !== 'currentOnly') addCode(this.getLanguagePartFromCode(code));
     } else if (typeof code === 'string') {
       addCode(this.formatLanguageCode(code));
@@ -1166,7 +1170,7 @@ var PluralResolver = function () {
       var suffix = rule.numbers[idx];
 
       // special treatment for lngs only having singular and plural
-      if (rule.numbers.length === 2 && rule.numbers[0] === 1) {
+      if (this.options.simplifyPluralSuffix && rule.numbers.length === 2 && rule.numbers[0] === 1) {
         if (suffix === 2) {
           suffix = 'plural';
         } else if (suffix === 1) {
@@ -1697,6 +1701,7 @@ function get$1() {
     load: 'all', // | currentOnly | languageOnly
     preload: false, // array with preload languages
 
+    simplifyPluralSuffix: true,
     keySeparator: '.',
     nsSeparator: ':',
     pluralSeparator: '_',
@@ -1770,7 +1775,15 @@ var I18n = function (_EventEmitter) {
     _this.logger = baseLogger;
     _this.modules = { external: [] };
 
-    if (callback && !_this.isInitialized && !options.isClone) _this.init(options, callback);
+    if (callback && !_this.isInitialized && !options.isClone) {
+      var _ret;
+
+      // https://github.com/i18next/i18next/issues/879
+      if (!_this.options.initImmediate) return _ret = _this.init(options, callback), possibleConstructorReturn(_this, _ret);
+      setTimeout(function () {
+        _this.init(options, callback);
+      }, 0);
+    }
     return _this;
   }
 
@@ -1816,7 +1829,7 @@ var I18n = function (_EventEmitter) {
         s.cacheConnector.save();
       });
       s.languageUtils = lu;
-      s.pluralResolver = new PluralResolver(lu, { prepend: this.options.pluralSeparator, compatibilityJSON: this.options.compatibilityJSON });
+      s.pluralResolver = new PluralResolver(lu, { prepend: this.options.pluralSeparator, compatibilityJSON: this.options.compatibilityJSON, simplifyPluralSuffix: this.options.simplifyPluralSuffix });
       s.interpolator = new Interpolator(this.options);
 
       s.backendConnector = new Connector(createClassOnDemand(this.modules.backend), s.resourceStore, s, this.options);
@@ -1911,11 +1924,19 @@ var I18n = function (_EventEmitter) {
         });
       };
 
-      append(this.language);
+      if (!this.language) {
+        // at least load fallbacks in this case
+        var fallbacks = this.services.languageUtils.getFallbackCodes(this.options.fallbackLng);
+        fallbacks.forEach(function (l) {
+          return append(l);
+        });
+      } else {
+        append(this.language);
+      }
 
       if (this.options.preload) {
         this.options.preload.forEach(function (l) {
-          append(l);
+          return append(l);
         });
       }
 
@@ -1979,20 +2000,28 @@ var I18n = function (_EventEmitter) {
       });
     };
 
-    if (!lng && this.services.languageDetector) lng = this.services.languageDetector.detect();
+    var setLng = function setLng(l) {
+      if (l) {
+        _this4.language = l;
+        _this4.languages = _this4.services.languageUtils.toResolveHierarchy(l);
 
-    if (lng) {
-      this.language = lng;
-      this.languages = this.services.languageUtils.toResolveHierarchy(lng);
+        _this4.translator.changeLanguage(l);
 
-      this.translator.changeLanguage(lng);
+        if (_this4.services.languageDetector) _this4.services.languageDetector.cacheUserLanguage(l);
+      }
 
-      if (this.services.languageDetector) this.services.languageDetector.cacheUserLanguage(lng);
-    }
+      _this4.loadResources(function (err) {
+        done(err);
+      });
+    };
 
-    this.loadResources(function (err) {
-      done(err);
-    });
+    if (!lng && this.services.languageDetector && !this.services.languageDetector.async) {
+      setLng(this.services.languageDetector.detect());
+    } else if (!lng && this.services.languageDetector && this.services.languageDetector.async) {
+      this.services.languageDetector.detect(setLng);
+    } else {
+      setLng(lng);
+    }
   };
 
   I18n.prototype.getFixedT = function getFixedT(lng, ns) {

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
app/Resources/public/assets/i18next/i18next.min.js


+ 4 - 4
app/Resources/public/assets/imagesloaded/.bower.json

@@ -33,12 +33,12 @@
     "images"
   ],
   "license": "MIT",
-  "version": "4.1.1",
-  "_release": "4.1.1",
+  "version": "4.1.2",
+  "_release": "4.1.2",
   "_resolution": {
     "type": "version",
-    "tag": "v4.1.1",
-    "commit": "2646b88563dbc19ef44da453be92d9be3bdd78d6"
+    "tag": "v4.1.2",
+    "commit": "60ce45d675567970993a52cb11763ba9b49aa5d0"
   },
   "_source": "https://github.com/desandro/imagesloaded.git",
   "_target": ">=3.0.0",

+ 5 - 5
app/Resources/public/assets/imagesloaded/README.md

@@ -10,15 +10,15 @@ Detect when images have been loaded.
 
 ### Download
 
-+ [imagesloaded.pkgd.min.js](https://npmcdn.com/imagesloaded@4/imagesloaded.pkgd.min.js) minified
-+ [imagesloaded.pkgd.js](https://npmcdn.com/imagesloaded@4/imagesloaded.pkgd.js) un-minified
++ [imagesloaded.pkgd.min.js](https://unpkg.com/imagesloaded@4/imagesloaded.pkgd.min.js) minified
++ [imagesloaded.pkgd.js](https://unpkg.com/imagesloaded@4/imagesloaded.pkgd.js) un-minified
 
 ### CDN
 
 ``` html
-<script src="https://npmcdn.com/imagesloaded@4.1/imagesloaded.pkgd.min.js"></script>
+<script src="https://unpkg.com/imagesloaded@4/imagesloaded.pkgd.min.js"></script>
 <!-- or -->
-<script src="https://npmcdn.com/imagesloaded@4.1/imagesloaded.pkgd.js"></script>
+<script src="https://unpkg.com/imagesloaded@4/imagesloaded.pkgd.js"></script>
 ```
 
 ### Package managers
@@ -219,7 +219,7 @@ _Image_ - The `img` element
 
 ### LoadingImage.isLoaded
 
-_Boolean_ - `true` when the image has succesfully loaded
+_Boolean_ - `true` when the image has successfully loaded
 
 ### imagesLoaded.images
 

+ 0 - 5
app/Resources/public/assets/imagesloaded/gulpfile.js

@@ -157,11 +157,6 @@ gulp.task( 'version', function() {
   gulp.src( [ 'bower.json', 'package.json' ] )
     .pipe( replace( /"version": "\d+\.\d+\.\d+"/, '"version": "' + version + '"' ) )
     .pipe( gulp.dest('.') );
-  // replace CDN links in README
-  var minorVersion = version.match( /^\d+\.\d+/ )[0];
-  gulp.src('README.md')
-    .pipe( replace( /imagesloaded@\d+\.\d+/g, 'imagesloaded@' + minorVersion ))
-    .pipe( gulp.dest('.') );
 });
 
 // ----- default ----- //

+ 2 - 2
app/Resources/public/assets/imagesloaded/imagesloaded.js

@@ -1,5 +1,5 @@
 /*!
- * imagesLoaded v4.1.1
+ * imagesLoaded v4.1.2
  * JavaScript is all like "You images are done yet or what?"
  * MIT License
  */
@@ -30,7 +30,7 @@
     );
   }
 
-})( window,
+})( typeof window !== 'undefined' ? window : this,
 
 // --------------------------  factory -------------------------- //
 

+ 3 - 3
app/Resources/public/assets/imagesloaded/imagesloaded.pkgd.js

@@ -1,5 +1,5 @@
 /*!
- * imagesLoaded PACKAGED v4.1.1
+ * imagesLoaded PACKAGED v4.1.2
  * JavaScript is all like "You images are done yet or what?"
  * MIT License
  */
@@ -115,7 +115,7 @@ return EvEmitter;
 }));
 
 /*!
- * imagesLoaded v4.1.1
+ * imagesLoaded v4.1.2
  * JavaScript is all like "You images are done yet or what?"
  * MIT License
  */
@@ -146,7 +146,7 @@ return EvEmitter;
     );
   }
 
-})( window,
+})( typeof window !== 'undefined' ? window : this,
 
 // --------------------------  factory -------------------------- //
 

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
app/Resources/public/assets/imagesloaded/imagesloaded.pkgd.min.js


+ 5 - 5
app/Resources/public/assets/simpleWebRTC/.bower.json

@@ -1,14 +1,14 @@
 {
   "name": "simpleWebRTC",
   "homepage": "https://github.com/HenrikJoreteg/SimpleWebRTC",
-  "version": "1.15.4",
-  "_release": "1.15.4",
+  "version": "2.2.3",
+  "_release": "2.2.3",
   "_resolution": {
     "type": "version",
-    "tag": "v1.15.4",
-    "commit": "6f84fbcd42bd6ab1af8134ef0c495e8a6c3175f7"
+    "tag": "2.2.3",
+    "commit": "0eeba55fd186a1ee45e06665e5be7e30aab4b5dd"
   },
   "_source": "https://github.com/HenrikJoreteg/SimpleWebRTC.git",
-  "_target": "1.15.*",
+  "_target": "2.2.*",
   "_originalSource": "simpleWebRTC"
 }

+ 6 - 0
app/Resources/public/assets/simpleWebRTC/.gitignore

@@ -1,3 +1,9 @@
 node_modules
 .DS_Store
 npm-debug.log
+
+browsers
+firefox*.bz2
+
+# JetBrains IDEs
+.idea

+ 1 - 1
app/Resources/public/assets/simpleWebRTC/.jshintignore

@@ -1,4 +1,4 @@
 node_modules
 *.bundle.js
 socket.io.js
-latest.js
+latest-v2.js

+ 34 - 0
app/Resources/public/assets/simpleWebRTC/.travis.yml

@@ -0,0 +1,34 @@
+sudo: false
+language: node_js
+node_js:
+  - 6
+addons:
+  apt:
+    sources:
+      - ubuntu-toolchain-r-test
+    packages:
+      - g++-4.8
+cache:
+  directories:
+    - node_modules
+
+env:
+  global:
+    - CXX=g++-4.8
+  matrix:
+    - BROWSER=chrome  BVER=stable
+
+before_script:
+  - ./node_modules/travis-multirunner/setup.sh
+  - export DISPLAY=:99.0
+  - sh -e /etc/init.d/xvfb start
+
+script:
+  - npm run test-travis
+
+after_failure:
+  - for file in *.log; do echo $file; echo "======================"; cat $file; done || true
+
+notifications:
+  email:
+  - 

+ 213 - 6
app/Resources/public/assets/simpleWebRTC/README.md

@@ -3,7 +3,7 @@
 [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/HenrikJoreteg/SimpleWebRTC?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
 
 
-Want to see it in action? Check out the demo: https://talky.io/
+Want to see it in action? Check out the demo: https://simplewebrtc.com/demo.html
 
 
 ## It's so easy:
@@ -14,7 +14,7 @@ Want to see it in action? Check out the demo: https://talky.io/
 <!DOCTYPE html>
 <html>
     <head>
-        <script src="http://simplewebrtc.com/latest.js"></script> 
+        <script src="https://simplewebrtc.com/latest-v2.js"></script>
         <style>
             #remoteVideos video {
                 height: 150px;
@@ -58,17 +58,30 @@ webrtc.on('readyToCall', function () {
 ### Available options
 
 
-`peerConnectionConfig` - Set this to specify your own STUN and TURN servers. By default, SimpleWebRTC uses Google's public STUN server (`stun.l.google.com:19302`), which is intended for public use according to: https://twitter.com/HenrikJoreteg/status/354105684591251456
+`peerConnectionConfig` - Set this to specify your own STUN and TURN servers. By
+default, SimpleWebRTC uses Google's public STUN server
+(`stun.l.google.com:19302`), which is intended for public use according to:
+https://twitter.com/HenrikJoreteg/status/354105684591251456
 
-Note that you will most likely also need to run your own TURN servers. See http://www.html5rocks.com/en/tutorials/webrtc/infrastructure/ for a basic tutorial. 
+Note that you will most likely also need to run your own TURN servers. See
+http://www.html5rocks.com/en/tutorials/webrtc/infrastructure/ for a basic
+tutorial.
+
+## Filetransfer
+Sending files between individual participants is supported. See
+http://simplewebrtc.com/filetransfer.html for a demo.
+
+Note that this is not file sharing between a group which requires a completely
+different approach.
 
 ## It's not always that simple...
 
-Sometimes you need to do more advanced stuff. See http://simplewebrtc.com/notsosimple.html for some examples.
+Sometimes you need to do more advanced stuff. See
+http://simplewebrtc.com/notsosimple.html for some examples.
 
 ## Got questions?
 
-Join the SimpleWebRTC discussion list: 
+Join the SimpleWebRTC discussion list:
 
 http://lists.andyet.com/mailman/listinfo/simplewebrtc
 
@@ -77,3 +90,197 @@ or the Gitter channel:
 https://gitter.im/HenrikJoreteg/SimpleWebRTC
 
 ## API
+
+### Constructor
+
+`new SimpleWebRTC(options)`
+
+- `object options` - options object provided to constructor consisting of:
+  - `string url` - *required* url for signaling server. Defaults to signaling
+  server URL which can be used for development. You must use your own signaling
+  server for production.
+  - `object socketio` - *optional* object to be passed as options to the signaling
+  server connection.
+  - `Connection connection` - *optional* connection object for signaling. See
+  `Connection` below. Defaults to a new SocketIoConnection
+  - `bool debug` - *optional* flag to set the instance to debug mode
+  - `[string|DomElement] localVideoEl` - ID or Element to contain the local video
+  element
+  - `[string|DomElement] remoteVideosEl` - ID or Element to contain the
+  remote video elements
+  - `bool autoRequestMedia` - *optional(=false)* option to automatically request
+  user media. Use `true` to request automatically, or `false` to request media
+  later with `startLocalVideo`
+  - `bool enableDataChannels` *optional(=true)* option to enable/disable data
+  channels (used for volume levels or direct messaging)
+  - `bool autoRemoveVideos` - *optional(=true)* option to automatically remove
+  video elements when streams are stopped.
+  - `bool adjustPeerVolume` - *optional(=false)* option to reduce peer volume
+  when the local participant is speaking
+  - `number peerVolumeWhenSpeaking` - *optional(=.0.25)* value used in
+  conjunction with `adjustPeerVolume`. Uses values between 0 and 1.
+  - `object media` - media options to be passed to `getUserMedia`. Defaults to
+  `{ video: true, audio: true }`. Valid configurations described
+  [on MDN](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia)
+  with official spec
+  [at w3c](http://w3c.github.io/mediacapture-main/#dom-mediadevices-getusermedia).
+  - `object receiveMedia` - *optional* RTCPeerConnection options. Defaults to
+  `{ offerToReceiveAudio: 1, offerToReceiveVideo: 1 }`.
+  - `object localVideo` - *optional* options for attaching the local video
+  stream to the page. Defaults to
+  ```javascript
+  {
+      autoplay: true, // automatically play the video stream on the page
+      mirror: true, // flip the local video to mirror mode (for UX)
+      muted: true // mute local video stream to prevent echo
+  }
+  ```
+  - `object logger` - *optional* alternate logger for the instance; any object
+  that implements `log`, `warn`, and `error` methods.
+
+### Fields
+
+`capabilities` - the
+[`webrtcSupport`](https://github.com/HenrikJoreteg/webrtcsupport) object that
+describes browser capabilities, for convenience
+
+`config` - the configuration options extended from options passed to the
+constructor
+
+`connection` - the socket (or alternate) signaling connection
+
+`webrtc` - the underlying WebRTC session manager
+
+### Events
+
+To set up event listeners, use the SimpleWebRTC instance created with the
+constructor. Example:
+
+```javascript
+var webrtc = new SimpleWebRTC(options);
+webrtc.on('connectionReady', function (sessionId) {
+    // ...
+})
+```
+
+`'connectionReady', sessionId` - emitted when the signaling connection emits the
+`connect` event, with the unique id for the session.
+
+`'createdPeer', peer` - emitted three times:
+
+- when joining a room with existing peers, once for each peer
+- when a new peer joins a joined room
+- when sharing screen, once for each peer
+
+- `peer` - the object representing the peer and underlying peer connection
+
+`'stunservers', [...args]` - emitted when the signaling connection emits the
+same event
+
+`'turnservers', [...args]` - emitted when the signaling connection emits the
+same event
+
+`'localScreenAdded', el` - emitted after triggering the start of screen sharing
+
+- `el` the element that contains the local screen stream
+
+`'leftRoom', roomName` - emitted after successfully leaving the current room,
+ending all peers, and stopping the local screen stream
+
+`'videoAdded', videoEl, peer` - emitted when a peer stream is added
+
+- `videoEl` - the video element associated with the stream that was added
+- `peer` - the peer associated with the stream that was added
+
+`'videoRemoved', videoEl, peer` - emitted when a peer stream is removed
+
+- `videoEl` - the video element associated with the stream that was removed
+- `peer` - the peer associated with the stream that was removed
+
+### Methods
+
+`createRoom(name, callback)` - emits the `create` event on the connection with
+`name` and (if provided) invokes `callback` on response
+
+`joinRoom(name, callback)` - joins the conference in room `name`. Callback is
+invoked with `callback(err, roomDescription)` where `roomDescription` is yielded
+by the connection on the `join` event. See [signalmaster](https://github.com/andyet/signalmaster) for more details.
+
+`startLocalVideo()` - starts the local media with the `media` options provided
+in the config passed to the constructor
+
+`testReadiness()` - tests that the connection is ready and that (if media is
+enabled) streams have started
+
+`mute()` - mutes the local audio stream for all peers (pauses sending audio)
+
+`unmute()` - unmutes local audio stream for all peers (resumes sending audio)
+
+`pauseVideo()` - pauses sending video to peers
+
+`resumeVideo()` - resumes sending video to all peers
+
+`pause()` - pauses sending audio and video to all peers
+
+`resume()` - resumes sending audio and video to all peers
+
+`sendToAll(messageType, payload)` - broadcasts a message to all peers in the
+room via the signaling channel (websocket)
+
+- `string messageType` - the key for the type of message being sent
+- `object payload` - an arbitrary value or object to send to peers
+
+`sendDirectlyToAll(channelLabel, messageType, payload)` - broadcasts a message
+to all peers in the room via a dataChannel
+
+- `string channelLabel` - the label for the dataChannel to send on
+- `string messageType` - the key for the type of message being sent
+- `object payload` - an arbitrary value or object to send to peers
+
+`getPeers(sessionId, type)` - returns all peers by `sessionId` and/or `type`
+
+`shareScreen(callback)` - initiates screen capture request to browser, then
+adds the stream to the conference
+
+`getLocalScreen()` - returns the local screen stream
+
+`stopScreenShare()` - stops the screen share stream and removes it from the room
+
+`stopLocalVideo()` - stops all local media streams
+
+`setVolumeForAll(volume)` - used to set the volume level for all peers
+
+- `volume` - the volume level, between 0 and 1
+
+`leaveRoom()` - leaves the currently joined room and stops local screen share
+
+`disconnect()` - calls `disconnect` on the signaling connection and deletes it
+
+`handlePeerStreamAdded(peer)` - used internally to attach media stream to the
+DOM and perform other setup
+
+`handlePeerStreamRemoved(peer)` - used internally to remove the video container
+from the DOM and emit `videoRemoved`
+
+`getDomId(peer)` - used internally to get the DOM id associated with a peer
+
+`getEl(idOrEl)` - helper used internally to get an element where `idOrEl` is
+either an element, or an id of an element
+
+`getLocalVideoContainer()` - used internally to get the container that will hold
+the local video element
+
+`getRemoteVideoContainer()` - used internally to get the container that holds
+the remote video elements
+
+### Connection
+
+By default, SimpleWebRTC uses a [socket.io](http://socket.io/) connection to
+communicate with the signaling server. However, you can provide an alternate
+connection object to use. All that your alternate connection need provide are
+four methods:
+
+- `on(ev, fn)` - A method to invoke `fn` when event `ev` is triggered
+- `emit()` - A method to send/emit arbitrary arguments on the connection
+- `getSessionId()` - A method to get a unique session Id for the connection
+- `disconnect()` - A method to disconnect the connection

+ 4 - 4
app/Resources/public/assets/simpleWebRTC/build.js

@@ -1,13 +1,13 @@
-var bundle = require('browserify')(),
+var bundle = require('browserify')({standalone: 'SimpleWebRTC'}),
     fs = require('fs'),
     request = require('request'),
     uglify = require('uglify-js');
 
 bundle.add('./simplewebrtc');
-bundle.bundle({standalone: 'SimpleWebRTC'}, function (err, source) {
+bundle.bundle(function (err, source) {
     if (err) console.error(err);
     fs.writeFileSync('simplewebrtc.bundle.js', source);
-    fs.writeFile('latest.js', uglify.minify(source, {fromString: true}).code, function (err) {
-        if (err) throw err;
+    fs.writeFile('latest-v2.js', uglify.minify(source.toString('utf8'), {fromString: true}).code, function (err) {
+      if (err) throw err;
     });
 });

+ 2 - 3
app/Resources/public/assets/simpleWebRTC/index.html

@@ -36,7 +36,7 @@
             <div id="localVolume" class="volume_bar"></div>
         </div>
         <div id="remotes"></div>
-        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
+        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
         <script src="simplewebrtc.bundle.js"></script>
         <script>
             // grab the room from the URL
@@ -51,8 +51,7 @@
                 // immediately ask for camera access
                 autoRequestMedia: true,
                 debug: false,
-                detectSpeakingEvents: true,
-                autoAdjustMic: false
+                detectSpeakingEvents: true
             });
 
             // when it's ready, join if we got a room from the URL

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
app/Resources/public/assets/simpleWebRTC/latest-v2.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
app/Resources/public/assets/simpleWebRTC/latest.js


+ 30 - 14
app/Resources/public/assets/simpleWebRTC/package.json

@@ -1,28 +1,44 @@
 {
   "name": "simplewebrtc",
-  "version": "1.15.4",
+  "version": "2.2.3",
   "repository": {
     "type": "git",
-    "url": "git@github.com:henrikjoreteg/SimpleWebRTC.git"
+    "url": "https://github.com/andyet/SimpleWebRTC.git"
   },
   "main": "./simplewebrtc.js",
   "description": "World's easiest webrtc",
   "dependencies": {
-    "webrtcsupport": "^1.0.0",
-    "wildemitter": "1.x",
-    "socket.io-client": "0.9.16",
-    "attachmediastream": "1.0.1",
-    "webrtc": "1.14.x",
+    "filetransfer": "^2.0.4",
+    "localmedia": "^2.2.1",
+    "rtcpeerconnection": "^5.1.1",
+    "webrtcsupport": "^2.2.0",
+    "wildemitter": "^1.2.0",
+    "socket.io-client": "1.3.7",
+    "attachmediastream": "^1.4.1",
     "mockconsole": "0.0.1"
   },
   "devDependencies": {
-    "express": "3.x.x",
-    "browserify": "2.22.0",
-    "precommit-hook": "0.3.x",
-    "request": "",
-    "uglify-js": "2.3.6"
+    "browserify": "^13.1.0",
+    "chromedriver": "^2.16.0",
+    "express": "^4.14.1",
+    "geckodriver": "^1.3.0",
+    "precommit-hook": "^3.0.0",
+    "request": "^2.72.0",
+    "selenium-webdriver": "^3.0.1",
+    "tape": "^4.0.0",
+    "testling": "^1.7.1",
+    "travis-multirunner": "^3.0.0",
+    "uglify-js": "^2.7.3"
   },
+  "license": "MIT",
   "scripts": {
-    "updateLatest": "./scripts/updateLatest.sh"
-  }
+    "test-travis": "test/run-selenium",
+    "updateLatest": "./scripts/updateLatest.sh",
+    "lint": "jshint .",
+    "validate": "npm ls"
+  },
+  "pre-commit": [
+    "lint",
+    "validate"
+  ]
 }

+ 302 - 0
app/Resources/public/assets/simpleWebRTC/peer.js

@@ -0,0 +1,302 @@
+var util = require('util');
+var webrtcSupport = require('webrtcsupport');
+var PeerConnection = require('rtcpeerconnection');
+var WildEmitter = require('wildemitter');
+var FileTransfer = require('filetransfer');
+
+// the inband-v1 protocol is sending metadata inband in a serialized JSON object
+// followed by the actual data. Receiver closes the datachannel upon completion
+var INBAND_FILETRANSFER_V1 = 'https://simplewebrtc.com/protocol/filetransfer#inband-v1';
+
+function isAllTracksEnded(stream) {
+    var isAllTracksEnded = true;
+    stream.getTracks().forEach(function (t) {
+        isAllTracksEnded = t.readyState === 'ended' && isAllTracksEnded;
+    });
+    return isAllTracksEnded;
+}
+
+function Peer(options) {
+    var self = this;
+
+    // call emitter constructor
+    WildEmitter.call(this);
+
+    this.id = options.id;
+    this.parent = options.parent;
+    this.type = options.type || 'video';
+    this.oneway = options.oneway || false;
+    this.sharemyscreen = options.sharemyscreen || false;
+    this.browserPrefix = options.prefix;
+    this.stream = options.stream;
+    this.enableDataChannels = options.enableDataChannels === undefined ? this.parent.config.enableDataChannels : options.enableDataChannels;
+    this.receiveMedia = options.receiveMedia || this.parent.config.receiveMedia;
+    this.channels = {};
+    this.sid = options.sid || Date.now().toString();
+    // Create an RTCPeerConnection via the polyfill
+    this.pc = new PeerConnection(this.parent.config.peerConnectionConfig, this.parent.config.peerConnectionConstraints);
+    this.pc.on('ice', this.onIceCandidate.bind(this));
+    this.pc.on('endOfCandidates', function (event) {
+        self.send('endOfCandidates', event);
+    });
+    this.pc.on('offer', function (offer) {
+        if (self.parent.config.nick) offer.nick = self.parent.config.nick;
+        self.send('offer', offer);
+    });
+    this.pc.on('answer', function (answer) {
+        if (self.parent.config.nick) answer.nick = self.parent.config.nick;
+        self.send('answer', answer);
+    });
+    this.pc.on('addStream', this.handleRemoteStreamAdded.bind(this));
+    this.pc.on('addChannel', this.handleDataChannelAdded.bind(this));
+    this.pc.on('removeStream', this.handleStreamRemoved.bind(this));
+    // Just fire negotiation needed events for now
+    // When browser re-negotiation handling seems to work
+    // we can use this as the trigger for starting the offer/answer process
+    // automatically. We'll just leave it be for now while this stabalizes.
+    this.pc.on('negotiationNeeded', this.emit.bind(this, 'negotiationNeeded'));
+    this.pc.on('iceConnectionStateChange', this.emit.bind(this, 'iceConnectionStateChange'));
+    this.pc.on('iceConnectionStateChange', function () {
+        switch (self.pc.iceConnectionState) {
+        case 'failed':
+            // currently, in chrome only the initiator goes to failed
+            // so we need to signal this to the peer
+            if (self.pc.pc.peerconnection.localDescription.type === 'offer') {
+                self.parent.emit('iceFailed', self);
+                self.send('connectivityError');
+            }
+            break;
+        }
+    });
+    this.pc.on('signalingStateChange', this.emit.bind(this, 'signalingStateChange'));
+    this.logger = this.parent.logger;
+
+    // handle screensharing/broadcast mode
+    if (options.type === 'screen') {
+        if (this.parent.localScreen && this.sharemyscreen) {
+            this.logger.log('adding local screen stream to peer connection');
+            this.pc.addStream(this.parent.localScreen);
+            this.broadcaster = options.broadcaster;
+        }
+    } else {
+        this.parent.localStreams.forEach(function (stream) {
+            self.pc.addStream(stream);
+        });
+    }
+
+    this.on('channelOpen', function (channel) {
+        if (channel.protocol === INBAND_FILETRANSFER_V1) {
+            channel.onmessage = function (event) {
+                var metadata = JSON.parse(event.data);
+                var receiver = new FileTransfer.Receiver();
+                receiver.receive(metadata, channel);
+                self.emit('fileTransfer', metadata, receiver);
+                receiver.on('receivedFile', function (file, metadata) {
+                    receiver.channel.close();
+                });
+            };
+        }
+    });
+
+    // proxy events to parent
+    this.on('*', function () {
+        self.parent.emit.apply(self.parent, arguments);
+    });
+}
+
+util.inherits(Peer, WildEmitter);
+
+Peer.prototype.handleMessage = function (message) {
+    var self = this;
+
+    this.logger.log('getting', message.type, message);
+
+    if (message.prefix) this.browserPrefix = message.prefix;
+
+    if (message.type === 'offer') {
+        if (!this.nick) this.nick = message.payload.nick;
+        delete message.payload.nick;
+        this.pc.handleOffer(message.payload, function (err) {
+            if (err) {
+                return;
+            }
+            // auto-accept
+            self.pc.answer(function (err, sessionDescription) {
+                //self.send('answer', sessionDescription);
+            });
+        });
+    } else if (message.type === 'answer') {
+        if (!this.nick) this.nick = message.payload.nick;
+        delete message.payload.nick;
+        this.pc.handleAnswer(message.payload);
+    } else if (message.type === 'candidate') {
+        this.pc.processIce(message.payload);
+    } else if (message.type === 'connectivityError') {
+        this.parent.emit('connectivityError', self);
+    } else if (message.type === 'mute') {
+        this.parent.emit('mute', {id: message.from, name: message.payload.name});
+    } else if (message.type === 'unmute') {
+        this.parent.emit('unmute', {id: message.from, name: message.payload.name});
+    } else if (message.type === 'endOfCandidates') {
+        // Edge requires an end-of-candidates. Since only Edge will have mLines or tracks on the
+        // shim this will only be called in Edge.
+        var mLines = this.pc.pc.peerconnection.transceivers || [];
+        mLines.forEach(function (mLine) {
+            if (mLine.iceTransport) {
+                mLine.iceTransport.addRemoteCandidate({});
+            }
+        });
+    }
+};
+
+// send via signalling channel
+Peer.prototype.send = function (messageType, payload) {
+    var message = {
+        to: this.id,
+        sid: this.sid,
+        broadcaster: this.broadcaster,
+        roomType: this.type,
+        type: messageType,
+        payload: payload,
+        prefix: webrtcSupport.prefix
+    };
+    this.logger.log('sending', messageType, message);
+    this.parent.emit('message', message);
+};
+
+// send via data channel
+// returns true when message was sent and false if channel is not open
+Peer.prototype.sendDirectly = function (channel, messageType, payload) {
+    var message = {
+        type: messageType,
+        payload: payload
+    };
+    this.logger.log('sending via datachannel', channel, messageType, message);
+    var dc = this.getDataChannel(channel);
+    if (dc.readyState != 'open') return false;
+    dc.send(JSON.stringify(message));
+    return true;
+};
+
+// Internal method registering handlers for a data channel and emitting events on the peer
+Peer.prototype._observeDataChannel = function (channel) {
+    var self = this;
+    channel.onclose = this.emit.bind(this, 'channelClose', channel);
+    channel.onerror = this.emit.bind(this, 'channelError', channel);
+    channel.onmessage = function (event) {
+        self.emit('channelMessage', self, channel.label, JSON.parse(event.data), channel, event);
+    };
+    channel.onopen = this.emit.bind(this, 'channelOpen', channel);
+};
+
+// Fetch or create a data channel by the given name
+Peer.prototype.getDataChannel = function (name, opts) {
+    if (!webrtcSupport.supportDataChannel) return this.emit('error', new Error('createDataChannel not supported'));
+    var channel = this.channels[name];
+    opts || (opts = {});
+    if (channel) return channel;
+    // if we don't have one by this label, create it
+    channel = this.channels[name] = this.pc.createDataChannel(name, opts);
+    this._observeDataChannel(channel);
+    return channel;
+};
+
+Peer.prototype.onIceCandidate = function (candidate) {
+    if (this.closed) return;
+    if (candidate) {
+        var pcConfig = this.parent.config.peerConnectionConfig;
+        if (webrtcSupport.prefix === 'moz' && pcConfig && pcConfig.iceTransports &&
+                candidate.candidate && candidate.candidate.candidate &&
+                candidate.candidate.candidate.indexOf(pcConfig.iceTransports) < 0) {
+            this.logger.log('Ignoring ice candidate not matching pcConfig iceTransports type: ', pcConfig.iceTransports);
+        } else {
+            this.send('candidate', candidate);
+        }
+    } else {
+        this.logger.log("End of candidates.");
+    }
+};
+
+Peer.prototype.start = function () {
+    var self = this;
+
+    // well, the webrtc api requires that we either
+    // a) create a datachannel a priori
+    // b) do a renegotiation later to add the SCTP m-line
+    // Let's do (a) first...
+    if (this.enableDataChannels) {
+        this.getDataChannel('simplewebrtc');
+    }
+
+    this.pc.offer(this.receiveMedia, function (err, sessionDescription) {
+        //self.send('offer', sessionDescription);
+    });
+};
+
+Peer.prototype.icerestart = function () {
+    var constraints = this.receiveMedia;
+    constraints.mandatory.IceRestart = true;
+    this.pc.offer(constraints, function (err, success) { });
+};
+
+Peer.prototype.end = function () {
+    if (this.closed) return;
+    this.pc.close();
+    this.handleStreamRemoved();
+};
+
+Peer.prototype.handleRemoteStreamAdded = function (event) {
+    var self = this;
+    if (this.stream) {
+        this.logger.warn('Already have a remote stream');
+    } else {
+        this.stream = event.stream;
+
+        this.stream.getTracks().forEach(function (track) {
+            track.addEventListener('ended', function () {
+                if (isAllTracksEnded(self.stream)) {
+                    self.end();
+                }
+            });
+        });
+
+        this.parent.emit('peerStreamAdded', this);
+    }
+};
+
+Peer.prototype.handleStreamRemoved = function () {
+    var peerIndex = this.parent.peers.indexOf(this);
+    if (peerIndex > -1) {
+        this.parent.peers.splice(peerIndex, 1);
+        this.closed = true;
+        this.parent.emit('peerStreamRemoved', this);
+    }
+};
+
+Peer.prototype.handleDataChannelAdded = function (channel) {
+    this.channels[channel.label] = channel;
+    this._observeDataChannel(channel);
+};
+
+Peer.prototype.sendFile = function (file) {
+    var sender = new FileTransfer.Sender();
+    var dc = this.getDataChannel('filetransfer' + (new Date()).getTime(), {
+        protocol: INBAND_FILETRANSFER_V1
+    });
+    // override onopen
+    dc.onopen = function () {
+        dc.send(JSON.stringify({
+            size: file.size,
+            name: file.name
+        }));
+        sender.send(file, dc);
+    };
+    // override onclose
+    dc.onclose = function () {
+        console.log('sender received transfer');
+        sender.emit('complete');
+    };
+    return sender;
+};
+
+module.exports = Peer;

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 3100 - 2760
app/Resources/public/assets/simpleWebRTC/simplewebrtc.bundle.js


+ 34 - 28
app/Resources/public/assets/simpleWebRTC/simplewebrtc.js

@@ -1,4 +1,4 @@
-var WebRTC = require('webrtc');
+var WebRTC = require('./webrtc');
 var WildEmitter = require('wildemitter');
 var webrtcSupport = require('webrtcsupport');
 var attachMediaStream = require('attachmediastream');
@@ -9,7 +9,7 @@ function SimpleWebRTC(opts) {
     var self = this;
     var options = opts || {};
     var config = this.config = {
-            url: 'https://signaling.simplewebrtc.com:443/',
+            url: 'https://sandbox.simplewebrtc.com:443/',
             socketio: {/* 'force new connection':true*/},
             connection: null,
             debug: false,
@@ -18,17 +18,15 @@ function SimpleWebRTC(opts) {
             enableDataChannels: true,
             autoRequestMedia: false,
             autoRemoveVideos: true,
-            adjustPeerVolume: true,
+            adjustPeerVolume: false,
             peerVolumeWhenSpeaking: 0.25,
             media: {
                 video: true,
                 audio: true
             },
-            receiveMedia: { // FIXME: remove old chrome <= 37 constraints format
-                mandatory: {
-                    OfferToReceiveAudio: true,
-                    OfferToReceiveVideo: true
-                }
+            receiveMedia: {
+                offerToReceiveAudio: 1,
+                offerToReceiveVideo: 1
             },
             localVideo: {
                 autoplay: true,
@@ -57,7 +55,9 @@ function SimpleWebRTC(opts) {
 
     // set our config from options
     for (item in options) {
-        this.config[item] = options[item];
+        if (options.hasOwnProperty(item)) {
+            this.config[item] = options[item];
+        }
     }
 
     // attach detected support for convenience
@@ -128,7 +128,7 @@ function SimpleWebRTC(opts) {
     this.webrtc = new WebRTC(opts);
 
     // attach a few methods from underlying lib to simple.
-    ['mute', 'unmute', 'pauseVideo', 'resumeVideo', 'pause', 'resume', 'sendToAll', 'sendDirectlyToAll'].forEach(function (method) {
+    ['mute', 'unmute', 'pauseVideo', 'resumeVideo', 'pause', 'resume', 'sendToAll', 'sendDirectlyToAll', 'getPeers'].forEach(function (method) {
         self[method] = self.webrtc[method].bind(self.webrtc);
     });
 
@@ -218,10 +218,8 @@ function SimpleWebRTC(opts) {
                     sharemyscreen: true,
                     enableDataChannels: false,
                     receiveMedia: {
-                        mandatory: {
-                            OfferToReceiveAudio: false,
-                            OfferToReceiveVideo: false
-                        }
+                        offerToReceiveAudio: 0,
+                        offerToReceiveVideo: 0
                     },
                     broadcaster: self.connection.getSessionid(),
                 });
@@ -231,7 +229,9 @@ function SimpleWebRTC(opts) {
         });
     });
     this.webrtc.on('localScreenStopped', function (stream) {
-        self.stopScreenShare();
+        if (self.getLocalScreen()) {
+            self.stopScreenShare();
+        }
         /*
         self.connection.emit('unshareScreen');
         self.webrtc.peers.forEach(function (peer) {
@@ -261,9 +261,9 @@ SimpleWebRTC.prototype = Object.create(WildEmitter.prototype, {
 SimpleWebRTC.prototype.leaveRoom = function () {
     if (this.roomName) {
         this.connection.emit('leave');
-        this.webrtc.peers.forEach(function (peer) {
-            peer.end();
-        });
+        while (this.webrtc.peers.length) {
+            this.webrtc.peers[0].end();
+        }
         if (this.getLocalScreen()) {
             this.stopScreenShare();
         }
@@ -328,6 +328,7 @@ SimpleWebRTC.prototype.joinRoom = function (name, cb) {
     var self = this;
     this.roomName = name;
     this.connection.emit('join', name, function (err, roomDescription) {
+        console.log('join CB', err, roomDescription);
         if (err) {
             self.emit('error', err);
         } else {
@@ -344,10 +345,8 @@ SimpleWebRTC.prototype.joinRoom = function (name, cb) {
                             type: type,
                             enableDataChannels: self.config.enableDataChannels && type !== 'screen',
                             receiveMedia: {
-                                mandatory: {
-                                    OfferToReceiveAudio: type !== 'screen' && self.config.receiveMedia.mandatory.OfferToReceiveAudio,
-                                    OfferToReceiveVideo: self.config.receiveMedia.mandatory.OfferToReceiveVideo
-                                }
+                                offerToReceiveAudio: type !== 'screen' && self.config.receiveMedia.offerToReceiveAudio ? 1 : 0,
+                                offerToReceiveVideo: self.config.receiveMedia.offerToReceiveVideo
                             }
                         });
                         self.emit('createdPeer', peer);
@@ -419,7 +418,6 @@ SimpleWebRTC.prototype.stopScreenShare = function () {
     this.connection.emit('unshareScreen');
     var videoEl = document.getElementById('localScreen');
     var container = this.getRemoteVideoContainer();
-    var stream = this.getLocalScreen();
 
     if (this.config.autoRemoveVideos && container && videoEl) {
         container.removeChild(videoEl);
@@ -427,24 +425,32 @@ SimpleWebRTC.prototype.stopScreenShare = function () {
 
     // a hack to emit the event the removes the video
     // element that we want
-    if (videoEl) this.emit('videoRemoved', videoEl);
-    if (stream) stream.stop();
+    if (videoEl) {
+        this.emit('videoRemoved', videoEl);
+    }
+    if (this.getLocalScreen()) {
+        this.webrtc.stopScreenShare();
+    }
     this.webrtc.peers.forEach(function (peer) {
         if (peer.broadcaster) {
             peer.end();
         }
     });
-    //delete this.webrtc.localScreen;
 };
 
 SimpleWebRTC.prototype.testReadiness = function () {
     var self = this;
-    if (this.webrtc.localStream && this.sessionReady) {
-        self.emit('readyToCall', self.connection.getSessionid());
+    if (this.sessionReady) {
+        if (!this.config.media.video && !this.config.media.audio) {
+            self.emit('readyToCall', self.connection.getSessionid());
+        } else if (this.webrtc.localStreams.length > 0) {
+            self.emit('readyToCall', self.connection.getSessionid());
+        }
     }
 };
 
 SimpleWebRTC.prototype.createRoom = function (name, cb) {
+    this.roomName = name;
     if (arguments.length === 2) {
         this.connection.emit('create', name, cb);
     } else {

+ 1 - 1
app/Resources/public/assets/simpleWebRTC/socketioconnection.js

@@ -13,7 +13,7 @@ SocketIoConnection.prototype.emit = function () {
 };
 
 SocketIoConnection.prototype.getSessionid = function () {
-    return this.connection.socket.sessionid;
+    return this.connection.id;
 };
 
 SocketIoConnection.prototype.disconnect = function () {

+ 26 - 0
app/Resources/public/assets/simpleWebRTC/test/run-selenium

@@ -0,0 +1,26 @@
+#!/bin/sh
+#
+# Installs Chrome or Firefox if missing and sets default browser to
+# chrome stable.
+#
+echo -e "\nPreparing Selenium webdriver tests."
+
+BINDIR=./browsers/bin
+export BROWSER=chrome
+export BVER=stable
+BROWSERBIN=$BINDIR/$BROWSER-$BVER
+if [ ! -x $BROWSERBIN ]; then
+  echo "Installing Chrome"
+  ./node_modules/travis-multirunner/setup.sh
+fi
+export BROWSER=firefox
+export BVER=stable
+BROWSERBIN=$BINDIR/$BROWSER-$BVER
+if [ ! -x $BROWSERBIN ]; then
+  echo "Installing Firefox"
+  ./node_modules/travis-multirunner/setup.sh
+fi
+echo "Starting browser."
+PATH=$PATH:./node_modules/.bin
+
+node test/selenium/index.js

+ 7 - 0
app/Resources/public/assets/simpleWebRTC/test/selenium/index.js

@@ -0,0 +1,7 @@
+// Test 1-1 selenium.
+require('./p2p');
+
+// Test three-party mesh.
+// apparently too much for travis :-(
+// TODO: investigate sauce labs
+//require('./three');

+ 54 - 0
app/Resources/public/assets/simpleWebRTC/test/selenium/p2p.js

@@ -0,0 +1,54 @@
+'use strict';
+var test = require('tape');
+
+// https://code.google.com/p/selenium/wiki/WebDriverJs
+var seleniumHelpers = require('./selenium-lib');
+var webdriver = require('selenium-webdriver');
+
+function doJoin(driver, room) {
+    return driver.get('file://' + process.cwd() + '/index.html?' + room);
+}
+
+function testP2P(browserA, browserB, t) {
+    var room = 'testing_' + Math.floor(Math.random() * 100000);
+
+    var userA = seleniumHelpers.buildDriver(browserA);
+    doJoin(userA, room);
+
+    var userB = seleniumHelpers.buildDriver(browserB);
+    doJoin(userB, room);
+
+    userA.wait(function () {
+        return userA.executeScript(function () {
+            return window.webrtc.getPeers().length === 1 && window.webrtc.getPeers()[0].pc.iceConnectionState === 'connected';
+        });
+    }, 30 * 1000)
+    .then(function () {
+        t.pass('P2P connected');
+        userA.quit();
+        userB.quit().then(function () {
+            t.end();
+        });
+    })
+    .then(null, function (err) {
+        t.fail(err);
+        userA.quit();
+        userB.quit();
+    });
+}
+
+test('P2P, Chrome-Chrome', function (t) {
+    testP2P('chrome', 'chrome', t);
+});
+
+test('P2P, Firefox-Firefox', function (t) {
+    testP2P('firefox', 'firefox', t);
+});
+
+test('P2P, Chrome-Firefox', function (t) {
+    testP2P('chrome', 'firefox', t);
+});
+
+test('P2P, Firefox-Chrome', function (t) {
+    testP2P('firefox', 'chrome', t);
+});

+ 33 - 0
app/Resources/public/assets/simpleWebRTC/test/selenium/selenium-lib.js

@@ -0,0 +1,33 @@
+// https://code.google.com/p/selenium/wiki/WebDriverJs
+var webdriver = require('selenium-webdriver');
+var chrome = require('selenium-webdriver/chrome');
+var firefox = require('selenium-webdriver/firefox');
+
+function buildDriver(browser) {
+    // Firefox options.
+    // http://selenium.googlecode.com/git/docs/api/javascript/module_selenium-webdriver_firefox.html
+    var profile = new firefox.Profile();
+    profile.setPreference('media.navigator.streams.fake', true);
+    var firefoxOptions = new firefox.Options()
+        .setBinary('browsers/bin/firefox-stable')
+        .setProfile(profile);
+
+    // Chrome options.
+    // http://selenium.googlecode.com/git/docs/api/javascript/module_selenium-webdriver_chrome_class_Options.html#addArguments
+    var chromeOptions = new chrome.Options()
+        .setChromeBinaryPath('browsers/bin/chrome-stable')
+        .addArguments('allow-file-access-from-files')
+        .addArguments('use-fake-device-for-media-stream')
+        .addArguments('use-fake-ui-for-media-stream');
+        // use-file-for-fake-audio-capture -- see https://code.google.com/p/chromium/issues/detail?id=421054
+
+    return new webdriver.Builder()
+        .forBrowser(browser || process.env.BROWSER || 'firefox')
+        .setFirefoxOptions(firefoxOptions)
+        .setChromeOptions(chromeOptions)
+        .build();
+}
+
+module.exports = {
+    buildDriver: buildDriver
+};

+ 101 - 0
app/Resources/public/assets/simpleWebRTC/test/selenium/three.js

@@ -0,0 +1,101 @@
+'use strict';
+var test = require('tape');
+
+// https://code.google.com/p/selenium/wiki/WebDriverJs
+var webdriver = require('selenium-webdriver');
+var chrome = require('selenium-webdriver/chrome');
+var firefox = require('selenium-webdriver/firefox');
+
+function buildDriver(browser) {
+    // Firefox options.
+    // http://selenium.googlecode.com/git/docs/api/javascript/module_selenium-webdriver_firefox.html
+    var profile = new firefox.Profile();
+    profile.setPreference('media.navigator.streams.fake', true);
+    var firefoxOptions = new firefox.Options()
+        .setProfile(profile);
+
+    // Chrome options.
+    // http://selenium.googlecode.com/git/docs/api/javascript/module_selenium-webdriver_chrome_class_Options.html#addArguments
+    var chromeOptions = new chrome.Options()
+        /*
+        .addArguments('enable-logging=1')
+        .addArguments('v=1')
+        .addArguments('vmodule=*libjingle/source/talk/*=4')
+        .addArguments('user-data-dir=/some/where')
+        */
+        .addArguments('allow-file-access-from-files')
+        .addArguments('use-fake-device-for-media-stream')
+        .addArguments('use-fake-ui-for-media-stream');
+        // use-file-for-fake-audio-capture -- see https://code.google.com/p/chromium/issues/detail?id=421054
+
+    return new webdriver.Builder()
+      .forBrowser(browser || process.env.BROWSER || 'firefox')
+      .setFirefoxOptions(firefoxOptions)
+      .setChromeOptions(chromeOptions)
+      .build();
+}
+
+function doJoin(driver, room) {
+    return driver.get('file://' + process.cwd() + '/index.html?' + room);
+}
+
+function test3(browserA, browserB, browserC, t) {
+    var room = 'testing_' + Math.floor(Math.random() * 100000);
+
+    var userA = buildDriver(browserA);
+    doJoin(userA, room);
+
+    var userB = buildDriver(browserB);
+    doJoin(userB, room);
+
+    var userC = buildDriver(browserC);
+    doJoin(userC, room);
+    userA.wait(function () {
+        return userA.executeScript('return (function() {' +
+            'var connected = 0;' +
+            'webrtc.getPeers().forEach(function (peer) {' +
+            '  if (peer.pc.iceConnectionState === \'connected\' || peer.pc.iceConnectionState === \'completed\') connected++;' +
+            '});' +
+            'return connected === 2;' +
+            '})()');
+    }, 15 * 1000)
+    .then(function () {
+        //return userA.sleep(2000);
+    })
+    .then(function () {
+        t.pass('Mesh connected');
+        userA.quit();
+        userB.quit();
+        userC.quit().then(function () {
+            t.end();
+        });
+    })
+    .then(null, function (err) {
+        t.fail('Mesh failed');
+        userA.quit();
+        userB.quit();
+        userC.quit().then(function () {
+            t.end();
+        });
+    });
+}
+
+test('Mesh, Chrome-Chrome-Chrome', function (t) {
+    test3('chrome', 'chrome', 'chrome', t);
+});
+
+test('Mesh, Chrome-Firefox-Firefox', function (t) {
+    test3('chrome', 'firefox', 'firefox', t);
+});
+
+test('Mesh, Firefox-Firefox-Chrome', function (t) {
+    test3('firefox', 'firefox', 'chrome', t);
+});
+
+test('Mesh, Chrome-Chrome-Firefox', function (t) {
+    test3('chrome', 'chrome', 'chrome', t);
+});
+
+test('Mesh, Firefox-Firefox-Firefox', function (t) {
+    test3('firefox', 'firefox', 'firefox', t);
+});

+ 157 - 0
app/Resources/public/assets/simpleWebRTC/webrtc.js

@@ -0,0 +1,157 @@
+var util = require('util');
+var webrtcSupport = require('webrtcsupport');
+var mockconsole = require('mockconsole');
+var localMedia = require('localmedia');
+var Peer = require('./peer');
+
+
+function WebRTC(opts) {
+    var self = this;
+    var options = opts || {};
+    var config = this.config = {
+            debug: false,
+            // makes the entire PC config overridable
+            peerConnectionConfig: {
+                iceServers: [{'urls': 'stun:stun.l.google.com:19302'}]
+            },
+            peerConnectionConstraints: {
+                optional: []
+            },
+            receiveMedia: {
+                offerToReceiveAudio: 1,
+                offerToReceiveVideo: 1
+            },
+            enableDataChannels: true
+        };
+    var item;
+
+    // We also allow a 'logger' option. It can be any object that implements
+    // log, warn, and error methods.
+    // We log nothing by default, following "the rule of silence":
+    // http://www.linfo.org/rule_of_silence.html
+    this.logger = function () {
+        // we assume that if you're in debug mode and you didn't
+        // pass in a logger, you actually want to log as much as
+        // possible.
+        if (opts.debug) {
+            return opts.logger || console;
+        } else {
+        // or we'll use your logger which should have its own logic
+        // for output. Or we'll return the no-op.
+            return opts.logger || mockconsole;
+        }
+    }();
+
+    // set options
+    for (item in options) {
+        if (options.hasOwnProperty(item)) {
+            this.config[item] = options[item];
+        }
+    }
+
+    // check for support
+    if (!webrtcSupport.support) {
+        this.logger.error('Your browser doesn\'t seem to support WebRTC');
+    }
+
+    // where we'll store our peer connections
+    this.peers = [];
+
+    // call localMedia constructor
+    localMedia.call(this, this.config);
+
+    this.on('speaking', function () {
+        if (!self.hardMuted) {
+            // FIXME: should use sendDirectlyToAll, but currently has different semantics wrt payload
+            self.peers.forEach(function (peer) {
+                if (peer.enableDataChannels) {
+                    var dc = peer.getDataChannel('hark');
+                    if (dc.readyState != 'open') return;
+                    dc.send(JSON.stringify({type: 'speaking'}));
+                }
+            });
+        }
+    });
+    this.on('stoppedSpeaking', function () {
+        if (!self.hardMuted) {
+            // FIXME: should use sendDirectlyToAll, but currently has different semantics wrt payload
+            self.peers.forEach(function (peer) {
+                if (peer.enableDataChannels) {
+                    var dc = peer.getDataChannel('hark');
+                    if (dc.readyState != 'open') return;
+                    dc.send(JSON.stringify({type: 'stoppedSpeaking'}));
+                }
+            });
+        }
+    });
+    this.on('volumeChange', function (volume, treshold) {
+        if (!self.hardMuted) {
+            // FIXME: should use sendDirectlyToAll, but currently has different semantics wrt payload
+            self.peers.forEach(function (peer) {
+                if (peer.enableDataChannels) {
+                    var dc = peer.getDataChannel('hark');
+                    if (dc.readyState != 'open') return;
+                    dc.send(JSON.stringify({type: 'volume', volume: volume }));
+                }
+            });
+        }
+    });
+
+    // log events in debug mode
+    if (this.config.debug) {
+        this.on('*', function (event, val1, val2) {
+            var logger;
+            // if you didn't pass in a logger and you explicitly turning on debug
+            // we're just going to assume you're wanting log output with console
+            if (self.config.logger === mockconsole) {
+                logger = console;
+            } else {
+                logger = self.logger;
+            }
+            logger.log('event:', event, val1, val2);
+        });
+    }
+}
+
+util.inherits(WebRTC, localMedia);
+
+WebRTC.prototype.createPeer = function (opts) {
+    var peer;
+    opts.parent = this;
+    peer = new Peer(opts);
+    this.peers.push(peer);
+    return peer;
+};
+
+// removes peers
+WebRTC.prototype.removePeers = function (id, type) {
+    this.getPeers(id, type).forEach(function (peer) {
+        peer.end();
+    });
+};
+
+// fetches all Peer objects by session id and/or type
+WebRTC.prototype.getPeers = function (sessionId, type) {
+    return this.peers.filter(function (peer) {
+        return (!sessionId || peer.id === sessionId) && (!type || peer.type === type);
+    });
+};
+
+// sends message to all
+WebRTC.prototype.sendToAll = function (message, payload) {
+    this.peers.forEach(function (peer) {
+        peer.send(message, payload);
+    });
+};
+
+// sends message to all using a datachannel
+// only sends to anyone who has an open datachannel
+WebRTC.prototype.sendDirectlyToAll = function (channel, message, payload) {
+    this.peers.forEach(function (peer) {
+        if (peer.enableDataChannels) {
+            peer.sendDirectly(channel, message, payload);
+        }
+    });
+};
+
+module.exports = WebRTC;

+ 3 - 0
app/Resources/public/css/editor.css

@@ -172,6 +172,9 @@ blockquote p {
   border: 1px solid transparent;
   border-radius: 4px;
 }
+.alert-dismissible {
+    padding-right: 35px;
+}
 .alert h4 {
   margin-top: 0;
   color: inherit;

+ 1 - 1
bower.json

@@ -21,7 +21,7 @@
     "jqueryui-timepicker-addon": "1.5.*",
     "image-map-resizer": "0.5.*",
     "fullcalendar": "3.1.0",
-    "simpleWebRTC": "1.15.*",
+    "simpleWebRTC": "2.2.*",
     "select2": "4.*",
     "MathJax": "2.5.*",
     "webcamjs": "1.0.*",

+ 15 - 10
composer.json

@@ -36,10 +36,14 @@
         {
             "type": "vcs",
             "url": "https://github.com/ywarnier/iCalcreator"
+        },
+        {
+            "type": "vcs",
+            "url": "https://github.com/jmontoyaa/PHPWord"
         }
     ],
     "require": {
-        "php": ">=5.4",
+        "php": ">=5.5",
         "ext-intl": "*",
         "ext-gd": "*",
         "ext-curl": "*",
@@ -118,9 +122,11 @@
         "sabre/vobject": "~3.1",
 
         "emojione/emojione": "1.3.0",
-        "zendframework/zend-config": "~2.6",
-        "zendframework/zend-feed": "~2.7",
-        "zendframework/zend-http": "^2.5",
+
+        "zendframework/zend-config": "2.5.1|~2.6",
+        "zendframework/zend-feed": "2.5.1|~2.6",
+        "zendframework/zend-http": "2.5.1|~2.6",
+        "zendframework/zend-soap": "2.5.1|~2.6",
 
         "ezyang/htmlpurifier": "4.6.0",
         "szymach/c-pchart": "2.0.4",
@@ -129,11 +135,9 @@
         "studio-42/elfinder": "2.1.*",
         "jbroadway/urlify": "dev-master",
         "monolog/monolog": "~1.0",
-
         "ircmaxell/password-compat": "~1.0.4",
         "sylius/attribute": "0.13.0",
         "sylius/translation": "0.13.0",
-        "ramsey/array_column": "~1.1",
         "patchwork/utf8": "~1.2",
         "ddeboer/data-import": "@stable",
         "phpoffice/phpexcel": "~1.8",
@@ -151,12 +155,13 @@
         "lunetics/locale-bundle": "^2.4",
         "theodo-evolution/session-bundle": "1.0.*",
         "jimmiw/php-time-ago": "^0.4.14",
-        "phpoffice/phpword": "^0.12.1",
-        "facebook/php-sdk-v4" : "~5.0",
-        "kigkonsult/icalcreator" : "0.1.0",
+        "phpoffice/phpword": "^0.12.1|dev-master",
+        "facebook/php-sdk-v4": "~5.0",
+        "kigkonsult/icalcreator": "0.1.0",
         "essence/essence": "2.6.1",
         "pclzip/pclzip": "2.8.2",
-        "ircmaxell/random-lib": "^1.2"
+        "ircmaxell/random-lib": "^1.2",
+        "ocramius/proxy-manager": "~1.0|2.0.*"
     },
     "require-dev": {
         "behat/behat": "@stable",

+ 557 - 18
documentation/changelog.html

@@ -56,7 +56,7 @@
 
     <a name="1.11.4"></a>
 
-    <h1>Chamilo 1.11.4 - Uyuni, April 2017?</h1>
+    <h1>Chamilo 1.11.4 - Uyuni, ? May 2017</h1>
     <h3>Release notes - summary</h3>
     <p>Chamilo 1.11.4 is a minor, bugfix release of the 1.11.x branch, with a large number of bugfixes on top of 1.11.2.</p>
     <h3>Release name</h3>
@@ -69,6 +69,7 @@
     </ul>
     <h3>Possibly breaking changes</h3>
       <ul>
+        <li>Dropped support for PHP 5.4 and inferior (now REQUIRES PHP 5.5 or more)</li>
         <li>As Chamilo becomes more popular, we are facing new security-based challenges that come as consequences of the simplicity
             that we offer our users. As such, in this version of Chamilo, the administrator *must* enable a configuration setting as follows
             in order <b>to authorize teachers and students to use iframes</b> (embedding things from outside) inside the online text areas in their courses and personal spaces.
@@ -80,40 +81,570 @@
     <h3>Notable new Features</h3>
     <h4>For end-users, teachers and Chamilo admins</h4>
     <ul>
-        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/056b9cdf2dbe7853e6d500ca33d6f0dd50f6e90c">056b9cdf</a> - <a href="https://task.beeznest.com/issues/12212">BT#12212</a>) Added configuration value ConsideredWorkingTime work extra field variable show in MyStudents page works report</li>
         <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/c0f6582be1ea7b15d176467f1e5de4d91f1a6461">c0f6582b</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1693">GH#1693</a>) Add new social report to user information page</li>
         <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ef1a70bd840255376d12f41bb4b4582acb93d602">ef1a70bd</a> - <a href="https://task.beeznest.com/issues/12289">BT#12289</a>) Add button to pause recording in oral expression question</li>
         <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e01349fca6b4d2032cdb6760be27ef089207b452">e01349fc</a> - <a href="https://task.beeznest.com/issues/12288">BT#12288</a>) Add custom message notification for exercise review by teacher</li>
-        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ffb18e01335c7cde154e38ae23582d44eb46afe6">ffb18e01</a> - <a href="https://task.beeznest.com/issues/12383">BT#12383</a>) Add setting 'hide_header_footer_in_certificate'</li>
-        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e6faa0ee9f5ed69e715cf81f29e7b48a9cb1067b">e6faa0ee</a>) Add hide_main_navigation_menu setting.</li>
-        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/62083f65953eee0ffea5a7375e9258c7ae308396">62083f65</a> - <a href="https://task.beeznest.com/issues/11019">BT#11019</a> - <a href="https://github.com/chamilo/chamilo-lms/commit/0204752ed1c39a9f91c0a946377d1d4a5c057548">0204752e</a>) Add configuration "certificate_pdf_orientation"</li>
-        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ffb966dbc2aafe0982c9c8b428cb2121234e2fb8">ffb966db</a> - <a href="https://support.chamilo.org/issues/12302">CT#12302</a>) Add setting "update_users_email_to_dummy_except_admins"</li>
-        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/5c5795fdfeff259aaa41e9282c6abed19b994711">5c5795fd</a> - <a href="https://task.beeznest.com/issues/12244">BT#12244</a>) Add configuration setting "course_introduction_html_strict_filtering" to allow course introduction html in low security for removeXSS</li>
-        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/3a04f0d3812ed3e41a18e185cbf49e33193986ba">3a04f0d3</a>) Add setting "personal_agenda_show_all_session_events"</li>
-        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/632923da80723ac1a506614e39bc1982b2b177ee">632923da</a>) Add differentiation of sessions options based on limit_session_admin_role setting in admin homepage</li>
-        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/bfdf62f0f2dfa1ad4c23d3cbfb6bbaf3b74dee97">bfdf62f0</a> - <a href="https://task.beeznest.com/issues/12162">BT#12162</a>) Learning paths: Add configuration setting show_prerequisite_as_blocked to show all prerequisites in gray</li>
-        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/03a24ebd34d203d2e58f37f56125faac45a3d41b">03a24ebd</a>) Add new configuration parameter "send_score_in_exam_notification_mail_to_manager"</li>
-        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/4da7aca854dd46e2e6f9ca9e10b85588858227de">4da7aca8</a>) Add configuration setting add_all_files_in_lp_export</li>
         <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/92aba7ec1c08cb98121d4a189d069cd6a805ce19">92aba7ec</a> - <a href="https://task.beeznest.com/issues/12220">BT#12220</a>) Add feature to redirect to session after registration (previously only available for courses)</li>
-        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/8ffb7fe9123883f0003938dfbbfc026b49649aad">8ffb7fe9</a> - <a href="https://task.beeznest.com/issues/12052">BT#12052</a>) Add user_portal_load_notification_by_ajax setting to improve page load</li>
         <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/b662ece7f84d66d0e021ca418e348aeacbf910dc">b662ece7</a> - <a href="https://task.beeznest.com/issues/11371">BT#11371</a>) Add Google Maps Plugin with a map to show extra field coordinates markers</li>
-        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/8e7ef78b4ec97cae7c7d0206a4ce2e47e14b0629">8e7ef78b</a> - <a href="https://task.beeznest.com/issues/12665">BT#12665</a>) Add configuration setting <code>thematic_pdf_orientation</code> to allow set the orientation when exporting thematic to pdf</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/a54d416acb0e826a36c0918000e068433bfe3b25">a54d416a</a>) Exercises: Add support for random questions in QTI import</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/b07d954ef1d190cd2b6ff3749e8e5c8520443f13">b07d954e</a> - <a href="https://task.beeznest.com/issues/12494">BT#12494</a>) Plugin: BBB: Allow hiding BBB meetings without recording when using sessions</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/f80eadf8cf35e5d90a9c0db771c5ee01ed5faff0">f80eadf8</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1791">GH#1791</a>) Exercises: Add support for unclosed attempts in exercises reports</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/16adcd2d72662ae49f50d0542c48bcf9449f169b">16adcd2d</a>) Add sessions dates in sessions catalogue</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/88093b27111e0d53c6913ca9d90e101dac85e578">88093b27</a>) Show session duration in sessions catalogue</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/d265a83c34b13eeac5be87383fe166a627eba54f">d265a83c</a> - <a href="https://task.beeznest.com/issues/12478">BT#12478</a>) Add MaintenanceMode Plugin</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ad36b1226ac3dd44b14d9b999bc2c6c09384e4df">ad36b122</a> - <a href="https://task.beeznest.com/issues/12538">BT#12538</a>) Collapse CKEditor when full_ckeditor_toolbar_set is enabled</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/026707555d5c558c71136fb983e9c3ef0ea85b3d">02670755</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1896">GH#1896</a>) Exercises: Add reading speed/comprehension question type</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/99e1afa964d4f21941d9edb5d931960d6e86bb9c">99e1afa9</a>) Improve learnpath tracking details</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/1f68292b9065b2ffcf3aa44434db51bc056bb42f">1f68292b</a> - <a href="https://task.beeznest.com/issues/12625">BT#12625</a>) Exercises: Add option to display draggable question like with vertical orientation</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/pull/1734">PR 1734</a>) Add SEPE plugin for Spanish Employment and Social Security Ministry compliance / Añadido plugin SEPE para cumplimiento con normas del Ministerio de Empleo y Seguridad Social de España</li>
     </ul>
 
     <h4>For developers and sysadmins</h4>
     <ul>
         <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/2d487172027a9ce87d882e406396dce489833e3c">2d487172</a> - <a href="https://task.beeznest.com/issues/12383">BT#12383</a>) Add support for configuration settings per multi-url (portal)</li>
         <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/dcd32e69f2f03c68ce1614064d99861bbb45a0f8">dcd32e69</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1692">GH#1692</a>) Add Twig filter local_format_date</li>
-        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/5ee5dc6dc81772140cb815b18b7127dbac921b1d">5ee5dc6d</a>) Added configuration value assignment_prevent_duplicate_upload to prevent duplicate upload</li>
-        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/423e8efd3f90f569b06b375489b70c7aef5a89df">423e8efd</a> - <a href="https://github.com/chamilo/chamilo-lms/commit/e8c03d30460a823293bbabcb3188611a912316c3">e8c03d30</a> - <a href="https://task.beeznest.com/issues/12156">BT#12156</a>) Add mail_content_style setting support to api_mail_html()</li>
         <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/def3633aa9e70f05ca4a1cdf129790bee3c41c1e">def3633a</a>) Migration: add main/admin/sync_db_with_schema.php UI file (to sync current db with schema) and sync_db_with_schema configuration setting to allow it</li>
         <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/19ff6440fa04f383f687bb4ed219e37dead56b77">19ff6440</a>) Use app/cache/course_backups instead of main app/cache folder for course backups</li>
         <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/296ef3352e9dc79d2fbfce2f932ab6efd5e4e3d2">296ef335</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1868">GH#1686</a>) Replace <code>Twig_Filter_Function</code> with <code>Twig_SimpleFilter</code></li>
-        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/8af6ed9d4e7286386043dd32b5d799bdfea1aa06">8af6ed9d</a> - <a href="https://task.beeznest.com/issues/12665">BT#12665</a>) Allow set the orientation when exporting thematic to pdf</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/423e8efd3f90f569b06b375489b70c7aef5a89df">423e8efd</a> - <a href="https://github.com/chamilo/chamilo-lms/commit/e8c03d30460a823293bbabcb3188611a912316c3">e8c03d30</a> - <a href="https://task.beeznest.com/issues/12156">BT#12156</a>) Add configuration setting mail_content_style for api_mail_html()</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/5ee5dc6dc81772140cb815b18b7127dbac921b1d">5ee5dc6d</a>) Add configuration setting assignment_prevent_duplicate_upload to prevent duplicate upload</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/056b9cdf2dbe7853e6d500ca33d6f0dd50f6e90c">056b9cdf</a> - <a href="https://task.beeznest.com/issues/12212">BT#12212</a>) Add configuration setting considered_working_time work extra field variable show in MyStudents page works report</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ffb18e01335c7cde154e38ae23582d44eb46afe6">ffb18e01</a> - <a href="https://task.beeznest.com/issues/12383">BT#12383</a>) Add configuration setting 'hide_header_footer_in_certificate'</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e6faa0ee9f5ed69e715cf81f29e7b48a9cb1067b">e6faa0ee</a>) Add configuration setting hide_main_navigation_menu.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/62083f65953eee0ffea5a7375e9258c7ae308396">62083f65</a> - <a href="https://task.beeznest.com/issues/11019">BT#11019</a> - <a href="https://github.com/chamilo/chamilo-lms/commit/0204752ed1c39a9f91c0a946377d1d4a5c057548">0204752e</a>) Add configuration setting "certificate_pdf_orientation"</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ffb966dbc2aafe0982c9c8b428cb2121234e2fb8">ffb966db</a> - <a href="https://support.chamilo.org/issues/12302">CT#12302</a>) Add configuration setting "update_users_email_to_dummy_except_admins"</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/5c5795fdfeff259aaa41e9282c6abed19b994711">5c5795fd</a> - <a href="https://task.beeznest.com/issues/12244">BT#12244</a>) Add configuration setting "course_introduction_html_strict_filtering" to allow course introduction html in low security for removeXSS</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/3a04f0d3812ed3e41a18e185cbf49e33193986ba">3a04f0d3</a>) Add configuration setting "personal_agenda_show_all_session_events"</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/632923da80723ac1a506614e39bc1982b2b177ee">632923da</a>) Add configuration setting limit_session_admin_role - Add differentiation of sessions options based on limit_session_admin_role setting in admin homepage</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/bfdf62f0f2dfa1ad4c23d3cbfb6bbaf3b74dee97">bfdf62f0</a> - <a href="https://task.beeznest.com/issues/12162">BT#12162</a>) Add configuration setting show_prerequisite_as_blocked to show all learning paths prerequisites in gray</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/03a24ebd34d203d2e58f37f56125faac45a3d41b">03a24ebd</a>) Add configuration setting parameter "send_score_in_exam_notification_mail_to_manager"</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/4da7aca854dd46e2e6f9ca9e10b85588858227de">4da7aca8</a>) Add configuration setting add_all_files_in_lp_export</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/8ffb7fe9123883f0003938dfbbfc026b49649aad">8ffb7fe9</a> - <a href="https://task.beeznest.com/issues/12052">BT#12052</a>) Add configuration setting user_portal_load_notification_by_ajax to improve page load</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/8e7ef78b4ec97cae7c7d0206a4ce2e47e14b0629">8e7ef78b</a> - <a href="https://task.beeznest.com/issues/12665">BT#12665</a>) Add configuration setting <code>thematic_pdf_orientation</code> to allow set the orientation when exporting thematic to pdf</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/6de5b9ce4dda28c6b1583ef6200e65c2b4e2005a">6de5b9ce</a> - <a href="https://task.beeznest.com/issues/12430">BT#12430</a>) Add configuration setting hide_course_notification - Courses list: Add option to hide the course changes notifications</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/00ecb30cc9e5bb8982ddad941dac56d6b09e39aa">00ecb30c</a> - <a href="https://task.beeznest.com/issues/12430">BT#12430</a>) Add configuration setting view_grid_courses_grouped_categories_in_sessions - Courses list: Allow showing courses grouped by category in session list. Only works in grid mode.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/f7e0b798892905ec590004070da031816c89b71c">f7e0b798</a> - <a href="https://task.beeznest.com/issues/12539">BT#12539</a>) Add configuration setting show_simple_session_info</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/6335a05b3455c623fdabd780e36d5eaa0b303a61">6335a05b</a>) Rename configuration setting allow_course_introduction_low_security to course_introduction_html_strict_filtering</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/a98f331670a29ebefb27957f62933ccfe53f3646">a98f3316</a> - <a href="https://task.beeznest.com/issues/12521">BT#12521</a>) Add configuration setting 'hide_lp_time'</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/3ce40fd7e874aa52527c0c16ba142531dbb9094c">3ce40fd7</a>) Add configuration setting tracking_columns to change the columns shown on tracking page</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/05ace29d1be79d557cd141bdba0d4a2889b034e2">05ace29d</a>) Add configuration setting "remove_session_url" to show/hide session link in "My courses" page</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/2d580b6a1873a5b1a9d769052c76c4de3503e425">2d580b6a</a> - <a href="https://task.beeznest.com/issues/12500">BT#12500</a>) Add configuration setting 'agenda_legend'</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/04047d2932a3d9bb373dc453b386b3fff29e9654">04047d29</a>) Add configuration sub-settings for my_students_lp/my_progress_lp tracking column display</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/9757d82b56e15cc0f654b6fc52d28828e1e5ed4d">9757d82b</a> - <a href="https://task.beeznest.com/issues/12471">BT#12471</a>) Add configuration setting 'session_list_show_count_users'</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e28086e08460a1db1b36f4941eece53dc82e3791">e28086e0</a> - <a href="https://task.beeznest.com/issues/12725">BT#12725</a>) Add configuration setting hide_course_rating support in course catalog</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/2069223b433577eb65c4d473b28aa5ff533c9100">2069223b</a> - <a href="https://task.beeznest.com/issues/12510">BT#12510</a>) Add configuration setting "session_admins_access_all_content" BT#12510</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/a07a88657b8b08854c6e4ffc013e8fd8439c12d5">a07a8865</a>) Add configuration setting 'system_announce_extra_roles'</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/5e765870e210315f53ef66f72592a4a8550c61c8">5e765870</a> - <a href="https://task.beeznest.com/issues/11019">BT#11019</a>) Add configuration setting "pdf_img_dpi" option</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/661239d80e2d6aa41de9893f426f3ba89a23f3f9">661239d8</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1772">GH#1772</a>) Add configuration setting SMTP_UNIQUE_REPLY_TO setting + support in api_mail_html() - fixes #1772</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/a5ba257b2b5a22dbefd11716585aa25115fcc0a0">a5ba257b</a> - <a href="https://task.beeznest.com/issues/12631">BT#12631</a>) Add configuration setting 'allow_edit_tool_visibility_in_session'</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/0767c9b06b5c3ec28acae0279ebba65980270cb1">0767c9b0</a> - <a href="https://task.beeznest.com/issues/12413">BT#12413</a>) Add script to generate a table of missing terms in a language. Edit to set $language, then run in a browser and copy-paste in a spreadsheet soft to hand out to professional translators</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/3d83d694ec1af9b0b59ad8d88d73762f2f481fec">3d83d694</a>) Improve Apache and Nginx rules in installation guide in English based on the .htaccess file</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/d8f78f1660c941c25ac748ca3f2cc04b7697f83c">d8f78f16</a> - <a href="https://task.beeznest.com/issues/12476">BT#12476</a>) System announcements: rework to use an array of visibilities (requires database changes)</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/4601bc570ed80cde5f77f29d4c48fa10a9a80f22">4601bc57</a>) New options added to setting 'email_alert_manager_on_new_quiz'</li>
     </ul>
 
     <h3>Improvements (minor features) and debug</h3>
     <ul>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/c14fdf78b1b2a59d49520579c7ac1b4ed9c14926">c14fdf78</a>) Add update-configuration to upgrade process from 1.10 to 1.11 to update the version number</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/98eb7229334bd7ce707c5b83f2494446b31f3c25">98eb7229</a>) Add migration fix for course_code column that shouldn't have been there in the first place</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/a17717aee7ca6e60b9b1e91cd78caf4b105de7f7">a17717ae</a> - <a href="https://task.beeznest.com/issues/12892">BT#12892</a>) Improve code for Question::resizePicture</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/dde61135e00bad3e39a32a172aa03a01eeadfbee">dde61135</a> - <a href="https://task.beeznest.com/issues/12892">BT#12892</a>) Fix resize question image</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/486e1e6f5c5be19c8d0d897ffdbb2c742932514c">486e1e6f</a> - <a href="https://task.beeznest.com/issues/10892">BT#10892</a>) Fix annotation question</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/b0ff7b792373b9e3fab8aa1cd6ac6a1882253552">b0ff7b79</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1871">GH#1871</a>) Fix phpoffice word dependency version (alternate configs in Composer to cover different PHP versions)</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/fdadb054d2446ad02c5d3c1e3aaab5aa0a90ddeb">fdadb054</a> - <a href="https://task.beeznest.com/issues/10891">BT#10891</a>) Fix course question category copy</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/4a2ca73213c091e7d7cc6806146c43f58553a954">4a2ca732</a> - <a href="https://task.beeznest.com/issues/10891">BT#10891</a>) Fix exercise category import</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/2d11c835feaf026573d8cca4ae43ccfee4c22400">2d11c835</a> - <a href="https://task.beeznest.com/issues/12799">BT#12799</a>) Add visibility field to CSV import of courses</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/7e7d73e168eabe26bec0674c3148a016aebd424b">7e7d73e1</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1954">GH#1954</a>) Fix installation issues with ticket tables when ticket plugin was enabled in 1.10 (2)</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/3f22b2c831b8dbe3e803841dd0fe1342aebc3490">3f22b2c8</a> - <a href="https://task.beeznest.com/issues/12757">BT#12757</a>) Improve code readability when listing documents</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ea5d3788b0fa2d098c345d139d489d4db678bb5d">ea5d3788</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1954">GH#1954</a>) Fix installation issues with ticket tables when ticket plugin was enabled in 1.10</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/50e5f3387004dddb2c9f1991474af45fa32ef8b0">50e5f338</a> - <a href="https://task.beeznest.com/issues/11972">BT#11972</a>) Fix events visibilities when connected as student</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ee8b90887db1c1ba0c286a0304a520e872e83311">ee8b9088</a> - <a href="https://task.beeznest.com/issues/11972">BT#11972</a>) Fix agenda visibility when using groups</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/12af7e8db2f75cfd20c5674faf8679ba6faa7a14">12af7e8d</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1954">GH#1954</a>) Fix ticket_message_attachments table creation</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/7582301f01684efe4901f35b183e1471f59cfd89">7582301f</a> - <a href="https://task.beeznest.com/issues/12723">BT#12723</a>) Plugins: SFS: Show complete post children info</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/b74301c24d8727b73e3a3ea6d2102a4d059e8c60">b74301c2</a> - <a href="https://task.beeznest.com/issues/12671">BT#12671</a>) Block group category CRUD if inside session</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/d58854a0814d17a3ef542a0053517382299e8371">d58854a0</a> - <a href="https://task.beeznest.com/issues/12723">BT#12723</a>) Plugins: SFS: Improve care detail UI</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/23e95f52c4076b56ae457eb9ff2f3a23adacf5ad">23e95f52</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1954">GH#1954</a>) Use schema to rename indexes</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/d5d8d1cfbfd5663bd89d35be38913e06a831e5b7">d5d8d1cf</a> - <a href="https://task.beeznest.com/issues/10896">BT#10896</a>) Remove OverwriteFile option on dropbox update</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/cb80d33cdb9ab8e9cff01db62ac2bd87a156b91e">cb80d33c</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1954">GH#1954</a>) Fix installation issues with ticket tables when ticket plugin was enabled in 1.10: Change table to ENGINE=InnoDB</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/66237ed991d75ba9b0dc07f3302181d1dd720477">66237ed9</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1959">GH#1959</a>) Update apc cache if exists (2)</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/bd8537963e3828b2f253e33044de98a97e2c8530">bd853796</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1959">GH#1959</a>) Update apc cache if exists</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/adad453dfc5fb82778dff6e39252ea716abe8988">adad453d</a> - <a href="https://task.beeznest.com/issues/12794">BT#12794</a>) Fix session grid tpl</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/5fa816b1add6fe786fe7f90c2bd32ce5ac9b597b">5fa816b1</a>) Plugin: SFS: Update permissions</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/790b33e2e353d87b266a0096b119d65ad2e19a89">790b33e2</a> - <a href="https://task.beeznest.com/issues/12723">BT#12723</a>) Update permissions rules</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/4601bc570ed80cde5f77f29d4c48fa10a9a80f22">4601bc57</a>) New options added to setting 'email_alert_manager_on_new_quiz'</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/9a2455a17e575a9dacca6670986a3c4d95e6f394">9a2455a1</a> - <a href="https://task.beeznest.com/issues/12776">BT#12776</a>) Admin: Fix multiple URL support in sessions list</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/3605599152fdee150607674b825be0e06d7c8d20">36055991</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1954">GH#1954</a>) First delete FKs if exists then add new ones</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/5d3752fa9d5c644f19f05c1aa091c9a78981484e">5d3752fa</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1924">GH#1924</a>) Fix issue with structure of 'hide_user_field_from_list' setting</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/4a8471b4a83d53a4de3379b3f1f8d752b3fcaa9b">4a8471b4</a>) Plugin: Buy Courses: Add multiple url support for sessions and courses</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e38ba5b7cbbf22cb80b5764e997a125fd98eaf33">e38ba5b7</a> - <a href="https://task.beeznest.com/issues/12748">BT#12748</a>) Fix fake-image for audio in CKEditor plugin</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/1ef930f380d802805bca4dda0201489b2bacce70">1ef930f3</a> - <a href="https://task.beeznest.com/issues/12748">BT#12748</a>) Fix option to set autoplay to audio in CKEditor plugin</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/2ad1efe3b2ab04e14233bf504d75748460e85dd5">2ad1efe3</a> - <a href="https://task.beeznest.com/issues/12748">BT#12748</a>) Remove field to set height to audio in CKEditor plugin</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ed59aea31dfc58aef0976bc7447370a854321d47">ed59aea3</a>) Renaming a document now use the new doc title not the old title</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/c3c3950f5b24e2d543e1b21fc63918361174b64a">c3c3950f</a>) General coach can get access to all courses inside a session</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/487703ebd655a0676c6a84c5fc84c9f5c45170d8">487703eb</a> - <a href="https://task.beeznest.com/issues/10887">BT#10887</a>) Fix document renaming in LP</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/a896b8bcf0625accb325fff8c2480d8b6aded132">a896b8bc</a> - <a href="https://task.beeznest.com/issues/10896">BT#10896</a>) Fix dropbox breadcrumb to show the right title</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/d1aba904f5c72c1be28579cfc95b04ec9fdb3627">d1aba904</a> - <a href="https://task.beeznest.com/issues/12755">BT#12755</a>) Fix css print.css in PDF export to use theme-specific CSS</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/684f709630af78262fb0a1848800daf9c35fc549">684f7096</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1787">GH#1787</a>) Use simpleWebRTC v2</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/2d7bc8eae8db315d6b1412ab912db0bc9b85c396">2d7bc8ea</a> - <a href="https://task.beeznest.com/issues/12755">BT#12755</a>) Add pdf_date_only variable in export pdf</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/d6384115de0b841da9e7adf6adf5e44edb10e47b">d6384115</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1941">GH#1941</a>) Fix extrafield of type tag when save a user info after replacement of FCBKComplete</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/0a790676cd70bd10fb5f6fe2780203a9c673963e">0a790676</a> - <a href="https://task.beeznest.com/issues/12754">BT#12754</a>) Add constant to handle page length fix card height</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/44113e685dcc5cc7e916845aa682c76a0ca57514">44113e68</a>) Fix visibility condition on course tools in sessions</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/a5e90982a0d1bac44731739a39cc3ab217e2eced">a5e90982</a> - <a href="https://task.beeznest.com/issues/12631">BT#12631</a>) Fix student view if c_tool has a session row</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/09cc2b750f6eb6dc8d84ec4e9f21c07d6c0eb3a9">09cc2b75</a>) Remove Gedmo\Timestampable dependency</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/4a3f5d0046548e87c0334965dfac27221eca4d08">4a3f5d00</a> - <a href="https://task.beeznest.com/issues/12723">BT#12723</a>) Plugin: Student Follow Up: Add related posts</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/6fc9149c7431232b7b3129661b46be704bc9d77a">6fc9149c</a> - <a href="https://task.beeznest.com/issues/12744">BT#12744</a>) Add js warning popup when deleting learning paths results</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/04c1a62c0f741a35a4a1009c86db671e9dbac6e6">04c1a62c</a>) Add CAPTCHA on lost_password</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/7b96ce354194b6eae250db7c7f6aa11ad7b0987f">7b96ce35</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1941">GH#1941</a>) Remove FCBKComplete</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/fffaf10cd6ff731e4cead0b197b345ccf1e0addc">fffaf10c</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1941">GH#1941</a>) Replace fcbkComplete with select2 for extra field of type tag</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/2a07dd39423b0c32cab10bc5d55ad55fb162638a">2a07dd39</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1941">GH#1941</a>) Replace FCBKComplete with select2 for student skill wheel</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/6a7895eea81c754bc1076e2f99874c1c161cc3ff">6a7895ee</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1941">GH#1941</a>) Include select2 files in page header</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/78c8b9c1a827e015fb9bc80fa1bd4291327c0836">78c8b9c1</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1941">GH#1941</a>) Fix skill wheel legend for student view</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/446cf9b85b57fe9e2b68f5f56f7ccc92d67a9920">446cf9b8</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1941">GH#1941</a>) Replace FCBKComplete with select2 for skill wheel</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/204aeef946d8b80b640ee3462e8042301810d1c8">204aeef9</a>) Add boss access to user report (from ofaj branch)</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/6fd95e4f74833653d54f952e1e1c3899a4e5068f">6fd95e4f</a> - <a href="https://task.beeznest.com/issues/12749">BT#12749</a>) Forum: Fix forum tool in session for API</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ce6bcc54f8e0c2731580d6ec99230602d1e59141">ce6bcc54</a> - <a href="https://task.beeznest.com/issues/12749">BT#12749</a>) Sessions: Fix session display dates and show session duration in API</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/9eb67a0c041b972aef832f0e9536943a81d6e910">9eb67a0c</a>) Gradebook: Fix showing possible tags to use when creating a certificate</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/79c7f17832d6fecdc0bcd49b2c4ebeb0189adb35">79c7f178</a> - <a href="https://task.beeznest.com/issues/12612">BT#12612</a>) LP: If exercise is inside LP send the LP-exercise link</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/62ef5505087cde9caa8dc8267b925c135254eed0">62ef5505</a> - <a href="https://task.beeznest.com/issues/12581">BT#12581</a>) LP: Open links in new window when building a LP</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/fbac3ecb56a296c35ec344f61b56fa615acc7144">fbac3ecb</a>) USERNAME_MAX_LENGTH default changed from 40 to 50.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/41f408aaf592f9679baef29d8deaff76e48c32f2">41f408aa</a> - <a href="https://task.beeznest.com/issues/12702">BT#12702</a>) Boss has access to student report</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/981560ab35207ea58b0f7c3185fce85d3597f12e">981560ab</a> - <a href="https://task.beeznest.com/issues/12739">BT#12739</a>) Fix lp order when using categories</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/789a77664495fbe9658624996ffd416b845ad196">789a7766</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1908">GH#1908</a>) New TPL for learning paths</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/013347ff73167cca86fe9ffe3dd11a972bbfd8da">013347ff</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1960">GH#1960</a>) Improve use of the FOR attribute in LABEL tags</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/f74cecbf839f74f330e1d2d66b76309b933ccaa2">f74cecbf</a> - <a href="https://task.beeznest.com/issues/12630">BT#12630</a>) Exercises: Fix student answers with html entities</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e710e460e94ce00256b89427e6615350ecfbee63">e710e460</a> - <a href="https://task.beeznest.com/issues/12630">BT#12630</a>) Exercises: Remove excess white spaces in Fill in the Blanks questions</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/078b23766abf6dadb3d2443bd72dd30228638f03">078b2376</a> - <a href="https://task.beeznest.com/issues/12738">BT#12738</a>) Exercises: Fix QTI import issues</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/376a55486b7f7ce626ef8d9d47b2498eac9511b5">376a5548</a> - <a href="https://task.beeznest.com/issues/12738">BT#12738</a>) Exercises: Clean exercise description when importing QTI</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/2a9f177df925be167c5fdf1e5274c149aea249a2">2a9f177d</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1933">GH#1933</a>) Fix headers of export to xls and csv</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/8c5215a0bde8172a7d5bddb53b2cf921de37ac11">8c5215a0</a>) Exercises: Improve responsive design for draggable question type</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/5ee57edb0998c719b2dc94c79d73638329249c08">5ee57edb</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1930">GH#1930</a>) Restore conditional when exporting users</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/632c6a6c89948258f95ee4a5924f477512133004">632c6a6c</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1930">GH#1930</a>) Fix the export of users to xls file</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/953b66991d6d39d57fae302d637f15476d4446d0">953b6699</a> - <a href="https://task.beeznest.com/issues/12702">BT#12702</a>) Student boss can access session course user exercise result</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/4b753742202556af8e40e09f95e45a63abf202a9">4b753742</a> - <a href="https://task.beeznest.com/issues/12702">BT#12702</a>) Student boss cannot edit exercise result</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/49562e3284c70402a392cf3af6e1e1b1e510be36">49562e32</a> - <a href="https://task.beeznest.com/issues/12702">BT#12702</a>) Student boss can see student exercise result</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/28667137d74834c70b3ffb2c4d86d5ca0c0fdc82">28667137</a>) Exercises: Fix question GLOBAL_MULTIPLE_ANSWER when importing from excel</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/6c03b39319ff58d361ddb900f1be0b7b6be126a4">6c03b393</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1924">GH#1924</a>) Always hide is_tutor and  user_status_in_course columns</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e18b651b7d61771125b38cec0b5c6f8b52fce652">e18b651b</a>) Fix use of setting 'allow_user_course_subscription_by_course_admin'</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/0143b2bc5e481dfd23ffcdb81fe15f6ade5fef47">0143b2bc</a> - <a href="https://task.beeznest.com/issues/12630">BT#12630</a>) Exercises: Show trimmed options in fill-in-blanks question</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/216a0e6f35cd31c4bed05bc53b4db289e6e82c3e">216a0e6f</a> - <a href="https://task.beeznest.com/issues/12712">BT#12712</a>) Exercises: Fix multiples draggable questions</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ab271c07808fb4e4b3c5934c59e50f47d223622a">ab271c07</a> - <a href="https://task.beeznest.com/issues/12625">BT#12625</a>) Exercises: Fix default value for orientation in draggable question</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/99b45360112a47a8a402d4356dfaa2c2d197686f">99b45360</a> - <a href="https://task.beeznest.com/issues/12100">BT#12100</a>) Work: Work UI changes, add correction title in drag n drop</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/8bc77d1299fee15362dfb176291836ac8d1fbe10">8bc77d12</a> - <a href="https://task.beeznest.com/issues/12100">BT#12100</a>) Work: Show correction status even if work doesn't have score</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/c331ae167ccbce343f78d7ee8d64fea13c380405">c331ae16</a> - <a href="https://task.beeznest.com/issues/12665">BT#12665</a>) Add tpl for generic thematic plan</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/5aa408c927984913ce9de51b568cd4eae5fd4226">5aa408c9</a>) Plugins: User new twig filters in plugins templates</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/73f7e1a60c578c5efdd372449c3568d8ea0d058c">73f7e1a6</a>) Plugins: Update tpl for new api_get_setting in buycourse plugin</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/8c0d723d49a6372f534c44535b812d01cff97498">8c0d723d</a> - <a href="https://task.beeznest.com/issues/12665">BT#12665</a>) Allow export all thematic progresses to pdf with thematic_pdf_orientation</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/51311d0187f688d474829bc60cd37863053544cc">51311d01</a>) Important - Fix missing '&' in api_protect_course_script()</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/f4d492c3620f122b84a5467d64b482e1072c7edc">f4d492c3</a>) Fix agenda event list view, teachers can see all events in group</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/8fcadc40673d8ef25cc9273b79dcf4e67bf39aeb">8fcadc40</a> - <a href="https://task.beeznest.com/issues/12671">BT#12671</a>) Fix add agenda group element</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/73b885fff489b6670d092abada972ca94a044879">73b885ff</a>) If user has access or is tutor then he can add events.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/3cf853ab47b68664d70aa8dee2d059c829ebcb2d">3cf853ab</a> - <a href="https://task.beeznest.com/issues/12671">BT#12671</a>) Send message to coach instead of going to profile</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e98b1db75c0a9f9a2fd5c4bcabfb54f1c7f64331">e98b1db7</a>) Fix list items from user menu</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/a8ced59f6532d87c1315b7be9b3ce94f7b041086">a8ced59f</a>) Use button instead of anchor</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/49debe3faf67597a7a9c33fa41706018f19e1bd5">49debe3f</a>) Show page header and footer in learnpath tracking when user is not allowed</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/fce6c479dbdd914e70b894a95cfe94c4c750aea4">fce6c479</a>) Fix gradebook imp/export: only copy when "overwrite file" option is selected.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/aefe9d4a5a2acd20765cef4766285c4645bcc9f2">aefe9d4a</a> - <a href="https://task.beeznest.com/issues/12403">BT#12403</a>) Create new unique folder when importing aiken folder</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/9c21563a7f40c0e487554adeeae301eac2f82b5a">9c21563a</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1768">GH#1768</a>) Fix MathJax usage in CKEditor</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/40c60b5c70558445480d9d7e66b31c90845235a1">40c60b5c</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1530">GH#1530</a>) Check if tutor is subscribed to the course when importing groups</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/30ba0275837b185b863133812b43276e82178df8">30ba0275</a>) Avoid showing panel body when there is no content</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/048b1064860f0d840b07205e34324c2e14d8d728">048b1064</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1860">GH#1860</a>) Show general link category only when there are link categories</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/42758f218a5ef3cb782e1bca4761a492aa79dcdb">42758f21</a>) Change function name display_announcement to displayAnnouncement</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/4b040db21bc111819b568522de85e24115d8173b">4b040db2</a> - <a href="https://task.beeznest.com/issues/12671">BT#12671</a>) Fix send announcement to everyone</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/030ecb7bd3f794329e19d2faec96e2711c811c63">030ecb7b</a> - <a href="https://task.beeznest.com/issues/12100">BT#12100</a>) Fix array key</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/cf3b649380ae77d4f7728634591293540e54f6d5">cf3b6493</a> - <a href="https://task.beeznest.com/issues/12694">BT#12694</a>) Remove gradebook edit in post, only edit in thread</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/8701af4a877e3f9b9d4d5cb5b28dbe94a6fa9ad1">8701af4a</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1863">GH#1863</a>) Announcements: Description (message body) is now required</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/72e496ef1c5e2b8a8d1316d86d4543baa4e4b5b3">72e496ef</a>) Override origin in lp_view to avoid not showing header</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/cab6d74fe2d0ed3936fdef9f4c2fd70ae02db734">cab6d74f</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1901">GH#1901</a>) Fix wrong variable $group_id</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/3a0d8fbc24272f041253e17967599ca1555b664c">3a0d8fbc</a> - <a href="https://task.beeznest.com/issues/12706">BT#12706</a>) Exercises: Adding Asciimath, Asciisvg options to question answers</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/af8b76d16c8f23f1a2e38fcd16196dc8e85d3685">af8b76d1</a>) Allow edit simple info but show warning if gradebook is empty</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/fbf1d267fb153258acf62197fef6d78a07a8394e">fbf1d267</a> - <a href="https://task.beeznest.com/issues/12694">BT#12694</a>) Forum: Fix update post</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/6a2f77b8de5e822af4868fe3bbfe7b96feb9d2aa">6a2f77b8</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1897">GH#1897</a>) Remove datepicker requirement</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/465b82ab9d150d763d8cb5672b3b757c04139f21">465b82ab</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1901">GH#1901</a>) Fix wrong variable $group_id fixes #1901</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ebe8694f9875b840c5a5fec21b6da52bbd4d0f52">ebe8694f</a>) Exercises: Fix mysql error in questions category</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/38549de8b2cf013606aede2d3990b3713ef1cd8f">38549de8</a>) Fix mistaken search by code instead of by path in get_course_image AJAX call</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/34cef4c3b786c46526bea6780c13819592d4783f">34cef4c3</a>) Rename selectLevel() to getLevel() in question class</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/caf965709c01e1041b8db9fb8c4d51de2d73710e">caf96570</a> - <a href="https://task.beeznest.com/issues/12441">BT#12441</a>) Fix exercise title as html</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/88fdd79ad8a4a1f43638fe4f4deeea6d7a9a04a7">88fdd79a</a> - <a href="https://task.beeznest.com/issues/12531">BT#12531</a>) Tracking= Use api_get_local_time()</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/547bdb5d838e28e659120dcf57b630b7332e95e7">547bdb5d</a> - <a href="https://task.beeznest.com/issues/1244">BT#1244</a>) Rename save_titles_as_html to save_titles_as_html</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/f5a0a44efb6116b9a1bb5dc1dcf0e0776140f8f2">f5a0a44e</a> - <a href="https://task.beeznest.com/issues/12653">BT#12653</a>) Fix issue in CSV import preventing importing users because key to check in CSV is Username where doc for CSV import says UserName</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/2d3a9b3f61124347c69d02f7010ad55d78edb17d">2d3a9b3f</a>) Improvement of appearance of promotions and careers</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e7406cf633d7e06f7164f1b5726d7e5af90a1dc4">e7406cf6</a> - <a href="https://task.beeznest.com/issues/12441">BT#12441</a>) Replace question_title_html with save_titles_like_html</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/07ee2da0d4ac34aac8ef6a36fe7d94838dc7b2ac">07ee2da0</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1607">GH#1607</a>) Fix space between radio buttons and text</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/2cb51e80806697da07880774c36323e12c8631de">2cb51e80</a>) Learning paths: Display improvements to prerequisites</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/8af6ed9d4e7286386043dd32b5d799bdfea1aa06">8af6ed9d</a> - <a href="https://task.beeznest.com/issues/12665">BT#12665</a>) Allow setting the orientation when exporting thematic to pdf</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/dbfd7a865e7909bc11f3eb98d6270a20b66beb1d">dbfd7a86</a>) Replace local_format_date with api_convert_and_format_date</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/c144e0714ce55d52e1b9e2c5f6c174305e947955">c144e071</a>) Restore img and allow the use of twig "dump" filter in templates</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/296ef3352e9dc79d2fbfce2f932ab6efd5e4e3d2">296ef335</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1868">GH#1868</a>) Replace Twig_Filter_Function with Twig_SimpleFilter for compatibility with Twig 3</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/fa451a149d21a6ea3c7244e57bd245ef3be25394">fa451a14</a>) Remove unused function 'get_course_users' + format code.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/881874ccbbbfed3bf3ae597a4b5ef96473cef9c8">881874cc</a>) Fix error when editing an announcement, the announcement disappeared.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e9a82bec6d5b13bef63a93681abbd729021b2e1a">e9a82bec</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1861">GH#1861</a>) Announcements: Fix issue with dynamic tags</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/d9edc1f9a34337a8b37adca533ce6f97da3cbbdf">d9edc1f9</a> - <a href="https://task.beeznest.com/issues/12531">BT#12531</a>) Use api_get_local_time()</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/139e3bbd0489003e0bff6d8763b6a0e4215b80b0">139e3bbd</a>) Remove deprecated function count_rows_course_table()</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/fa85b0daab4dd1b708e573508844058166110684">fa85b0da</a> - <a href="https://task.beeznest.com/issues/12658">BT#12658</a>) Add StudentFollowUp Plugin structure</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/1f328cb8dfcc6c769627536d9349a8a626c11e5c">1f328cb8</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1504">GH#1504</a>) Add option to show main plugin tab to anonymous users in BuyCourses plugin</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/1c568a04f3e53ff36d17add14503f964ce2e5bea">1c568a04</a>) Show custom plugins tabs in the public part of the platform</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/2165bebb992a4fe29e33c0da4721a9421576ce00">2165bebb</a>) Improve check on APCu to avoid warnings when calling apcu_cache_info()</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/c3dc49b363167d2c751e7c2f253aa64ab96d5d61">c3dc49b3</a> - <a href="https://task.beeznest.com/issues/12478">BT#12478</a>) Do not check permissions of .htaccess file if plugin is not enabled, in maintenance plugin</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/14d98c30bb4869de91d2ab704bde4d632f28bb68">14d98c30</a> - <a href="https://task.beeznest.com/issues/12478">BT#12478</a>) Add plugin class method to tell if the plugin is enabled ("status" field = "installed" in settings_current table) - loosely refs BT#12478</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/63bf4de1f451adcd5747d0bacd832bea4603b76e">63bf4de1</a> - <a href="https://task.beeznest.com/issues/12674">BT#12674</a>) Add unified policy to sign in/up to Azure Active Directory plugin</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/04b67955ca549627ad07cc47c122af437e59c524">04b67955</a>) Moved pdf logo to the set_header() function</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/fd42bdb1e9894e8e15b4f71d283cd406ce3a4b93">fd42bdb1</a> - <a href="https://task.beeznest.com/issues/12624">BT#12624</a>) Add username to course exam tracking</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/2fc2015ffc3b569099f93957abfb477c343695bb">2fc2015f</a> - <a href="https://task.beeznest.com/issues/12624">BT#12624</a>) Show first name in gradebook flat view when exporting xls</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/8179bf20c5c1b6ab5b067efc927fa0e5f023ca80">8179bf20</a> - <a href="https://task.beeznest.com/issues/12624">BT#12624</a>) Add username to gradebook flat view</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/d8b988f13103907e4d8320b6cfedfda5818d44f1">d8b988f1</a>) Removing check_parameter and check_parameter_or_fail functions from CourseManager</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/aabbf9d4f46d855fa37d815c0c587e0ed5905606">aabbf9d4</a>) Exercises: Fix flash message when saving an exercise question</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/195312a31b938615d2769d1c1cafe843d8ec9762">195312a3</a>) Update - exclude paths</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/aaed6f151098b1a02c27ba4fa83aaaa915cc8796">aaed6f15</a>) Space between casting: $a = (int) $a;</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/b2141e6b0c2e2957921240c45e017f82476622b4">b2141e6b</a>) Use Display::dateToStringAgoAndLongDate()</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ca8ee7f55cfa5b29dd858a1ce0deac85c6ce0ca4">ca8ee7f5</a> - <a href="https://task.beeznest.com/issues/12100">BT#12100</a>) Fix work field list</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/9f224fa4e10affc08292a7a69219ad79d6c17548">9f224fa4</a> - <a href="https://task.beeznest.com/issues/12664">BT#12664</a>) Fix admin calendar</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/1f7644e5570da76747d6b58b477f3b63266410ea">1f7644e5</a>) Removing session name to form when adding forum</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/536d52304a1f266dee6736f5bbf8952929414d0f">536d5230</a>) Improvement in the courses catalogue</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/7d6e9953e3dfd126692fe97812fa74d3a01d6c20">7d6e9953</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1530">GH#1530</a>) Check if user is subcribed to course when importing groups</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/2b3748c87fcc571ac62e46b1bb429152103775df">2b3748c8</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1530">GH#1530</a>) Fix import groups with max_students</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/35f8dc45e914c9254743bd0ff1ecb785750cb65e">35f8dc45</a> - <a href="https://task.beeznest.com/issues/12663">BT#12663</a>) Reduce database usage of get_all_exercise_results_by_course() by removing query of which results are unused. In test case with 1000 students and 5M records in track_e_attempt, provides a performance gain of 29% for "My progress" page</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/7a83fddccf3b423d0cb46669208610e19da95349">7a83fddc</a> - <a href="https://task.beeznest.com/issues/12663">BT#12663</a>) Reduce memory usage of get_all_exercise_results_by_course() by 60%</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/b90565686e5228720f5515920368c0e370622f92">b9056568</a> - <a href="https://task.beeznest.com/issues/12635">BT#12635</a>) Fix wrong Skill Wheel template</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/0d7196ed65faa6e65ba3d18d64446ecc5550262f">0d7196ed</a>) Fix warnings in student skills wheel view</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/213fdf397eb9ad2f30f61ac4916ee5aa5ecd5ef4">213fdf39</a>) Fix undefined variable in SkillVisualizer</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/c046a987bddfe64ebdf8bba17d94080893fefc4b">c046a987</a> - <a href="https://task.beeznest.com/issues/12660">BT#12660</a>) Fix session list for DRH on Works In Session report</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/6f5f7282f8684989bf4d46e0619bcdc16151ad3f">6f5f7282</a> - <a href="https://task.beeznest.com/issues/12441">BT#12441</a>) Add pdf header when exporting</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/9ac68524c16cbd93e91c6b3993ad23f19bfb2685">9ac68524</a> - <a href="https://task.beeznest.com/issues/12539">BT#12539</a>) Fix breadcrumb in basis course</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/6e221d59dad03730f6ac6d77b0be4090c157714b">6e221d59</a> - <a href="https://task.beeznest.com/issues/12539">BT#12539</a>) Show information message with the duration days left</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/fdab116cf5d1cd223466d8440e366924d5c4d70b">fdab116c</a> - <a href="https://task.beeznest.com/issues/12539">BT#12539</a>) Calculate total session duration when calculating the duration days left</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/249a0c3d3fe0d5f50a60bc7c48f90249421cf160">249a0c3d</a>) Fix checking all languages when creating a CMS page</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/0d4d1d276e1b52156de39255cfcdbec7c80f15bb">0d4d1d27</a>) To be watched: change complex condition to avoid use of empty conditions in gradebook display</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/2cc7335b780a7c26cb6b178ec43e09a370407ce6">2cc7335b</a>) Fix issue in auth ldap code not setting the _uid in session correctly</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/d0daa49b537d12f1368ff3078169e2960147dfb7">d0daa49b</a>) Return empty array or 0 in Database methods when first param is null</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/3ba8fd0184c405f1aadc4e6408180b07dbf58b8b">3ba8fd01</a> - <a href="https://task.beeznest.com/issues/12478">BT#12478</a>) Avoid warning if maintenance file does not exist in maintenance plugin</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ea85874a73d7feacdb65657cd2e56f1e27954a1c">ea85874a</a>) Add check on $attributes param in QuickForm/text to avoid warnings in PHP 7.1</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/f5a8f94596f6910eee6d3145ee0b37f43a073516">f5a8f945</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1502">GH#1502</a>) Fix BBB language variables</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/b37413797ba4e6f6afa5df1e5cab5b16c0698d4e">b3741379</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1502">GH#1502</a>) Remove participants from BBB room</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/fed51da5cc0b21ea892060bf738110baec5caa33">fed51da5</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1502">GH#1502</a>) Remove duplicated code in BBB plugin</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/521ed43a2001f720ad22053bfc14ccaa6f92448b">521ed43a</a>) Allow erasing video-conference records that do not have session recording</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/4492f89287ae418f161f3d588e6826752b043425">4492f892</a> - <a href="https://task.beeznest.com/issues/12415">BT#12415</a>) Show score results in LP (depending on test settings)</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/62720eecd1d7b293565358656cc01713728cbfd8">62720eec</a>) Fix htaccess</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/d76c2ead159c37be24f36d6746963a82b19d8228">d76c2ead</a>) Remove plugin/bbb/lib/bbb_api.php</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/3600597812e550cda092796831c6400831b4accb">36005978</a>) Hide teacher icon when teachers are hidden</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/76e8a62b182c58b6d5c15585d2bc506398d5fa5b">76e8a62b</a>) Remove unused function 'api_number_of_plugins'</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/80997534940f377da6ce766637c6d30871c82a2e">80997534</a>) Remove unused function api_is_internal_path()</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e670b9d791e997001f2cadbdb57159e78969338c">e670b9d7</a>) Fix constant names</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/823c8232fae11d1eebe3d95e0c39471dd2f11812">823c8232</a>) Set ckeditor configuration correctly</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/a444e677913dd5c24e3aed7f923461d64033844b">a444e677</a>) Use CourseManager::get_user_course_categories() instead of custom code.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/1d19142825d2363372eebc2f3aa99ddb494c1e60">1d191428</a> - <a href="https://task.beeznest.com/issues/12478">BT#12478</a>) Plugins: MaintenanceMode: Add maintenance HTML ckeditor + add htaccess template</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/a8afbc9e34aefb95c9aae899c11ddd2607794f89">a8afbc9e</a>) Fix HTML editor settings</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/f8191a18215269cec8587d12a0d42f2c20c334c5">f8191a18</a>) Add status + add has correction not to be shown yet in work list.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ba5fc44f12b4421649055459f9c20f001929d60e">ba5fc44f</a> - <a href="https://task.beeznest.com/issues/12554">BT#12554</a>) Fix message for survey invitations sent</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/80c806f5fa1d3b756faf6be7b3b772a16a3bf172">80c806f5</a> - <a href="https://task.beeznest.com/issues/12646">BT#12646</a>) Fix session blocks in catalogue and courses list</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/5be16f07521d0b17684d10e7b07b92005d9e518e">5be16f07</a>) Fix syntax error, unexpected '.1' on plugins admin page</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/bf90910718b1822171ee899c400e4c8eba38ba49">bf909107</a> - <a href="https://task.beeznest.com/issues/12646">BT#12646</a>) Restoring .black-shadow to sessions blocks in catalog</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/096c2097a3504e57ca407b739fc2f8c2c75d4d7e">096c2097</a> - <a href="https://task.beeznest.com/issues/12646">BT#12646</a>) Improve sessions catalogue template</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/1d79465fe3bf68777f166f6220e58f16d1a0e586">1d79465f</a>) Fix UI - blog header shows platform header.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/a755108eb98d01259c3b956ae09859af493b7563">a755108e</a>) Improve code, use api_get_user_info(). Replace info_user with user_info</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/6d25684d2b7b8fc9c08ea47508cf7759052186f1">6d25684d</a> - <a href="https://task.beeznest.com/issues/12499">BT#12499</a>) Fix moment.js localization file</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/227c36526afc44f80d35aa3e976ac282451e1ae3">227c3652</a>) Fix "getUserCourseCategoryForCourse" calls and return value.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e0d21096e321135181b00fbf0056514ad0551aa0">e0d21096</a> - <a href="https://task.beeznest.com/issues/12538">BT#12538</a>) Show the full toolbar set to all CKEditor</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/f34970e21f65df1559617f6b83ba5db5e7e76bd2">f34970e2</a> - <a href="https://task.beeznest.com/issues/12538">BT#12538</a>) Allow save question titles with HTML</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/9d0e3b74cea59ef4dbec4c7f3c55b1900169178e">9d0e3b74</a> - <a href="https://task.beeznest.com/issues/12554">BT#12554</a>) Avoid showing link to survey when access is not allowed</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/13f623e8d250f8afe1b485f549e3dc6772ad5319">13f623e8</a>) Remove unused parameters in methods definition + added comments in gradebook</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/7234823cd69aec32c3387d3b63d783f5b0f1a433">7234823c</a>) Remove unused "weight" column in survey (probably imported through a copy of an exercise method)</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/b067dbd8cccc8e990fa0b8a4221db0c2feacd7c8">b067dbd8</a>) Fix missing breaks in switch-case for stop_previous_item() and rl_get_resource_link_for_learnpath()</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/74b41af637ddfdb558ddf5b25c9d83a239a1d12b">74b41af6</a>) Move break to ensure the break is clear + minor code style changes</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/0cff15541c39247c5d971a50b94d6030064a87e3">0cff1554</a>) Fix document creation inside LP when selecting root folder</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/205587f9ed42393598eceda9dbf616468bd720f7">205587f9</a> - <a href="https://task.beeznest.com/issues/12641">BT#12641</a>) Check $showOnlyThisFields before setting defaults</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/7ae6411c4d1dcea7f8504fa3f0d86ecc607c1fd3">7ae6411c</a>) Add aria label for icon buttons</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/5b25f936fb592e36a75f3c1802cfa74f4bd89f7d">5b25f936</a>) Add alternative display for teacher profile picture</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/66b973f48efaf572392399c975f2305c8347ad07">66b973f4</a>) Add aria label for icon buttons</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/667af5ab24485e48d43e7032545e974c917523a9">667af5ab</a>) Add aria label for icon buttons</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/5e50bff6ccf682bf0bfbabd3e3626da3dbef70fb">5e50bff6</a>) Add label for course description.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e865c98e484f4b3b574979ab54992f74811709fa">e865c98e</a>) Add aria-label to 'social wall' textarea</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/a288a93f4bb364debe4e284b5e06d4cbe4bdd6c6">a288a93f</a>) Add accessibility label</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/0468c0237c2859e96ac8edd54e167627053adfa7">0468c023</a>) Update search user form</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/80dced28841ff886f3be6d30d9438ae5b2a569a1">80dced28</a>) Add alternative display for teacher profile picture</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/8433b76eac708eb0b26d8acf32f2be1c6f61bc80">8433b76e</a>) Add alternative display for profile picture</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/3877abe8a452a5a35ade99a1d2891004061108a7">3877abe8</a> - <a href="https://task.beeznest.com/issues/12642">BT#12642</a>) Fix double "leave group" option in menu if "can leave group" option is set</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/6cc11e3998d8d79b822914897dfd64b999ab2e50">6cc11e39</a>) Remove unused TicketPlugin class (now core feature)</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/a1320fb4cd73d904e985c6dd3c3084fcf155f1f7">a1320fb4</a>) Make course copy error messaging even clearer</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/a763b8039b750fc8ba9bd13f4f5f10603d996b7d">a763b803</a>) Make course copy error messaging a bit clearer</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/c04e34b30591d05fbdc4434d6ef42245ac35d8bc">c04e34b3</a>) Use api_get_course_info_by_id($id) rather than api_get_course_id() as the $id might not exist in this context (for example when creating a course from a template in the admin section)</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/87cb80d819083ca749a47ef2b3015c5ed6eb6e53">87cb80d8</a>) Add HTML encoding header depending on received parameter rather than exporting it to UTF-8 in export_table_xls_html()</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/9b9f3308657176322678041d92c8111f864addcc">9b9f3308</a>) Change visibility of CAS methods log() and error() to allow static calls from other classes</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ad0f69061fab98486d94aa39e496b29506e4d06e">ad0f6906</a> - <a href="https://task.beeznest.com/issues/10894">BT#10894</a>) Change moderated workflow</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/8480b72c80cbc80af381763582a9644b642e51db">8480b72c</a> - <a href="https://task.beeznest.com/issues/10896">BT#10896</a>) Add update dropbox file</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/739289a12301dfba85bf730c4ad250d8dd49711a">739289a1</a>) Rename add_category_for_question_id to addCategoryToQuestion</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/4bea5f943169cf6c1b615c2e5f3f86036268e78b">4bea5f94</a> - <a href="https://task.beeznest.com/issues/10891">BT#10891</a>) Fix test category quiz export</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/1a51a5880900b7f92221094cbf681e51f0f8aea3">1a51a588</a>) Exercises: Avoid double escape string in quiz category</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/f4b414adbc39f1c34ef8bb2c3c8a6a00d81be624">f4b414ad</a>) Upgrade: Don't update category id, probably category_id = 2 is being used.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/d144f4e06d6ae29a3422c2617a24a78a30f0583e">d144f4e0</a>) LP: Remove custom code, use object instead.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/61ea0f7e091b47a3a6214dcd34bcac33a6bae5a6">61ea0f7e</a> - <a href="https://task.beeznest.com/issues/12234">BT#12234</a>) LP: Fix link insertion</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/063278adc93cf3558cef097aa3f1178f349f2de9">063278ad</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1835">GH#1835</a>) My courses: "remove_session_url" setting set to false by default</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/a5b40fed6b76e9d1313da134b3f465494e06dd9f">a5b40fed</a>) Show course title in Tracking::show_user_progress()</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/450a49df676a49ec580618ca3141648209a7458a">450a49df</a> - <a href="https://task.beeznest.com/issues/12609">BT#12609</a>) Fix query, restore use of groupIid</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/8f44b589fec53c4a160e4d92d7a492ed70303002">8f44b589</a> - <a href="https://task.beeznest.com/issues/12624">BT#12624</a>) Fix exam tracking for courses</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ed9da7fe562286314989a869559ab99be2432584">ed9da7fe</a>) Forum toolbar view in mobile (2)</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ab84875934c02b45f49ad8a038b2d9a740a5b23b">ab848759</a>) Forum toolbar view in mobile</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/7e99733ff9b271810791fa7be64d08d318c3b5de">7e99733f</a> - <a href="https://task.beeznest.com/issues/12624">BT#12624</a>) Fix course reporting</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/7e7b16f9977292b9ede04e93537aabea9c216b68">7e7b16f9</a>) Fix mobile view for scorm</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/683d68afeefd38fd80126e61a50bf89bec25029b">683d68af</a> - <a href="https://task.beeznest.com/issues/12608">BT#12608</a>) Fix learning paths with audio</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/8296d6718f82aeda0b5b22a64a34025244472ec1">8296d671</a>) Add Behat testing requirement for new features in documentation</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/6098653c0d0376e24be8cc4f4ef523e27d347164">6098653c</a> - <a href="https://task.beeznest.com/issues/12609">BT#12609</a>) Upgrade: Update function calls due to group id change (previous commit) BT#12609</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/3c285f525fa271ab8ea34da7be72d64ea9f50bc9">3c285f52</a> - <a href="https://task.beeznest.com/issues/12609">BT#12609</a>) Upgrade: Fix group id after migration</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/0daa9b46b5ceb69bf94a065cfc4fb14ee6a07b97">0daa9b46</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1825">GH#1825</a>) Remove double filter Database::escape_string() fixes #1825</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/14e0e594c469d2664120c6973f60d907d244910a">14e0e594</a> - <a href="https://task.beeznest.com/issues/12607">BT#12607</a>) Fix user list extra field advanced search form</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/7160e393d097a2f375949c9bbd718f80e8152ab5">7160e393</a>) Clean also opcache when cleaning archive if opcache_reset available.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/43fe062076e66ff28cd6a6b24a17fa555fc0d3dd">43fe0620</a> - <a href="https://task.beeznest.com/issues/10897">BT#10897</a>) Exercises: Fix my exercises list in session view</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/faf54feadbd54e61e86f9ac7bf93d5c967fe00ca">faf54fea</a>) Fix php warning, add course parameter in get_exam_results_data()</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/635ca665c83dd8e738138fcfabe2ab650dbb8f1f">635ca665</a>) If course doesn't exist, return array in GroupManager::get_groups()</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/36a698fe602146262068bda98288c8d71aa3ed7c">36a698fe</a>) Fix courses list toolbar</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/05f899b4721fc6431fce80cff9f86e10f4a7fe78">05f899b4</a>) Fix tickets toolbar</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/cee1f01ef14236928ac836f151be2cfeffe92b35">cee1f01e</a>) Fix skill profile and skill level toolbar</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/078e380f459ecf4d516fe9bbd84e7a7c29882b1c">078e380f</a>) Add skills icons</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/0f6208345d5c9bd2a06753037062abd614e6228f">0f620834</a> - <a href="https://task.beeznest.com/issues/12571">BT#12571</a>) Fix warning in PHP 7.1 when using undefined array index</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/a24673a33d66db691c149e626d913a7bf9f11b4c">a24673a3</a>) Fix introduction tools</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/3c15c718c1799dd587aa9ca82f7094ce2324f860">3c15c718</a>) Fix action toolbars</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/8b15e83db9cd9cf8d613f238a3344999cecfbe23">8b15e83d</a>) Calculate columns width for action toolbar</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/261b27c0d9121f270f455a8d007ffae46ab8d6f5">261b27c0</a> - <a href="https://task.beeznest.com/issues/10897">BT#10897</a>) Use 'session_id' key instead 'id_session' to show reports from course_home page</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/fc370bb3875e6c388422bee17841e65aca860fbe">fc370bb3</a> - <a href="https://support.chamilo.org/issues/12603">CT#12603</a>) Add email in list, setting "show_email_addresses" must be true</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/acec555f756fb62c361bb59b047fe4f0521eea46">acec555f</a> - <a href="https://task.beeznest.com/issues/12472">BT#12472</a>) Session admin can check user courses via ajax</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/d5785b6b8a0c5ac48c72ec4be0d244f06c9d6f5c">d5785b6b</a> - <a href="https://task.beeznest.com/issues/12474">BT#12474</a>) Exercises: Show average and latest attempt as before</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/41d98ccc03f6324915d23dba722b7ddcad048805">41d98ccc</a>) Exercises: Fix best score show percentage, add debug, format code, fix query</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/166c7f077a608b5c121dcd5545442e059c181074">166c7f07</a> - <a href="https://task.beeznest.com/issues/12532">BT#12532</a>) Exercises: Add best score column</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/466b9f96bd08db612253cbe958224d0d77b96a05">466b9f96</a>) Fix Link, fix get_lang variable with LearningPath</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/106199f9ca12cf98721f48b5c25f78a8baaf783f">106199f9</a>) Add course_session_data anchor & minor changes</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e19d6b1d5b273ce7c8b2fdd369a777960b501008">e19d6b1d</a>) Add 'form->addPasswordRule' in order to centralize pass validation</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/c7335f2de0a697affab1130223de668ef3326471">c7335f2d</a>) WIP: edit dropbox file</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/9f7c26af150ade6a289467255df27ef1748511f6">9f7c26af</a> - <a href="https://task.beeznest.com/issues/12532">BT#12532</a>) Exercises: Show best score in my progress</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/0407630444780a90a10e9f29ffd212c76510ef4f">04076304</a>) Fix toolbars action</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/48202b086edf587e598e5bf208756d4614d4fdf1">48202b08</a>) Improve Display::toolbarAction()</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/f1d54c7496868acd10b4095269fdf9a766deaca7">f1d54c74</a>) Fix course progress info student</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/210f92e6bcf2517f4f01429c472d875330aff81e">210f92e6</a>) Fix progress certificate</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ed4ad6cf6e21039d93c4ca339de1ce10d70212bf">ed4ad6cf</a>) Fix course student info</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/c04497467375dca9fcb0c8b974386e5f67dfa003">c0449746</a>) CSS style for the option to show student progress in My courses</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/984e741b974bed214586ff0f91750fb0f6da9406">984e741b</a>) Remove dégradé from exercise results</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/3f81c3f10b433f6d805e4123bfe56be3a3588a58">3f81c3f1</a>) Use Display::dateToStringAgoAndLongDate() instead of "date_to_str_ago".</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/076aedf36135d7117886f36a75bb27fb8859adec">076aedf3</a> - <a href="https://task.beeznest.com/issues/10887">BT#10887</a>) Fix inline layout for group, radio and checkbox elements</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/01d19bdc9b8c9af82ae9dc3e42641b6d4000857f">01d19bdc</a>) Move $columnsSize variable in Element class as protected.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/1e1c8a284983d756db0dcca60d79f4db845f367a">1e1c8a28</a>) Remove unused parameter, remove unused renderer.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/2c2279d923aede00981e6fc1d57508c98d2d7580">2c2279d9</a> - <a href="https://task.beeznest.com/issues/10887">BT#10887</a>) Remove &lt;br /&gt; from upload form</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/f3bc08523a18821b98a1ec27786f775707944e54">f3bc0852</a> - <a href="https://task.beeznest.com/issues/12472">BT#12472</a>) Session admin can check one user's sessions list</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/6704865f73f3d064ed94fcbb171ef137c3d5611b">6704865f</a> - <a href="https://task.beeznest.com/issues/12474">BT#12474</a>) Show best score instead of average score</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/cddd18dd358d0270b1614f22eda84ea2f8d7c20e">cddd18dd</a> - <a href="https://task.beeznest.com/issues/12474">BT#12474</a>) Show best score instead of just score</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ea6028f44b76f2b53bcf7fb7b79ce520615af034">ea6028f4</a>) Fix fatal error: wrong query parameter</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/fc033ebbd061f2d722053ed6455684acb427a705">fc033ebb</a>) Exercises: Add $getOnlyBestAttempt parameter. Show only best attempt in report</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/1e7f9590870a5e7df7b8d7b83b48410c831f2e1a">1e7f9590</a> - <a href="https://task.beeznest.com/issues/12585">BT#12585</a>) Gradebook: Allow score to be set to 0 in all evaluations result edition</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/2078b88abf858cd0a5e2184538d6fa52071df413">2078b88a</a> - <a href="https://task.beeznest.com/issues/12585">BT#12585</a>) Gradebook: Fix edit all evaluation results</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/6ce3776b2b54292624a011bf324dcd9001fb8c01">6ce3776b</a> - <a href="https://task.beeznest.com/issues/12585">BT#12585</a>) Gradebook: Fix form to edit evaluation result</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/f7a338bc0b36a18f6804ab523fd3fb1e5c9d37d2">f7a338bc</a>) Multiple changes in CourseRestorer to sanitize code, of which one could have impact on the creation of learning path items when restoring a backup and the learning path is not created appropriately #scrutinizer</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/5687f738b3c3c5a2ebaf4b57da72ab28dd4fe74e">5687f738</a>) Exercises: Fix add question button</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/29a47c19a1369f129d4cfdd533f8b5e0a580d396">29a47c19</a> - <a href="https://task.beeznest.com/issues/12441">BT#12441</a>) Add feature to set PDF footer from tpl</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/fe8b1a70ea2805b17c6a73caf8a8762e5a3bfa2e">fe8b1a70</a>) Fix get template tpl ckeditor</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/528f9e01feb3cea9db733ef32f88eede6cc7c3e5">528f9e01</a>) Add check to avoid treating non-numerical indexes as sorteable tables</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/8ff55e20771b33b2607039218d85c21e02196007">8ff55e20</a> - <a href="https://task.beeznest.com/issues/12441">BT#12441</a>) Add feature to define PDF "signature" field</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/0d6deaf9e1231fcd69fee4def1bacb399b58d29f">0d6deaf9</a> - <a href="https://task.beeznest.com/issues/12441">BT#12441</a>) Create PDF template when exporting single course thematic</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/4b8ee47ef938a4a7ebf8bfc8ef1dce6459d69aaf">4b8ee47e</a>) Change meaning of setting "course_introduction_html_strict_filtering"</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/be1b2d80cbd195222a29ee05a59b32334d4d4ddf">be1b2d80</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1816">GH#1816</a>) Don't load default theme in install process</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/acf90c4e8671680177113a0aa76bf1bd8d141c6c">acf90c4e</a> - <a href="https://task.beeznest.com/issues/12583">BT#12583</a>) Admin can see extra fields in user addition form (admin section)</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/1574d378cbc7f1363671d04b61c6ffc7eb3a103d">1574d378</a> - <a href="https://task.beeznest.com/issues/12470">BT#12470</a>) Add search form to sessions list (main/session/session_list.php)</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/60617a2735f65794e5a04de35aad5102a756011e">60617a27</a> - <a href="https://task.beeznest.com/issues/12532">BT#12532</a>) Add anchor "#course_session_header"</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/616ed8eef41f972d585c3805896cdbbf9ba0cc0a">616ed8ee</a>) Use addSelectLanguage instead of custom code.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/dd0dab1edbf01aab6671e26b3605e24ae553a53a">dd0dab1e</a>) Add option "set_custom_default" in SelectLanguage form type</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/91c267920d85523c2f4367c195cdace18a94eaaf">91c26792</a>) Plugins: Add buy_course_redirect redirect for non-authenticated users</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/807cf5697be5d5ed3540314ffe0937d0c29c5aa1">807cf569</a>) Rewrite generate password and check password - requires composer update</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/00754f960d916bf6ab4fced4caae281aa1fe3cf4">00754f96</a>) CHECK_PASS_EASY_TO_FIND must be true.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/8b37c098f30cec6c72595d1c06e6adba74822be1">8b37c098</a>) Add support for HTTPS in YouTube/Vimeo videos embed</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/8b0e4189c87886e9ed9c82c0b568746cc24900dd">8b0e4189</a>) Change button for already registered user in courses catalogue</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/d65772811beb2411965bb28c91919680b7dd6767">d6577281</a>) Fix course_catalog_published check preventing public catalogue to be seen by anonymous users</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ec6c1f73d551f8b0aac8bf98449c4fd56ad11f49">ec6c1f73</a>) Fix french lang variables in image2_chamilo CKEditor plugin</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/7725b66df2e8ba6f422850ffe1c9efcc8181bf73">7725b66d</a> - <a href="https://task.beeznest.com/issues/12530">BT#12530</a>) List all sessions for admin in work-in-session and teacher-time reports</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e473bd26e371f3033dae9635cfee8cc58475e13a">e473bd26</a>) Fix student's course list in grid mode</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/2ca3f3f3b489c458848d9b98677eec48f9619f0a">2ca3f3f3</a>) Exercises: Fix HotSpot answers colors</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/442f7271144a4348ddbc286583067d3f9b39b4fc">442f7271</a>) Exercises: Show answer list on admin view</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/6bbfe4f9df328ff737b49fc25eeb2c93a1007990">6bbfe4f9</a>) Exercises: Fix HotSpot answers list</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/edf206198903cd508523f501f2d4278b17b0299f">edf20619</a>) Exercises: Improve code readability for export question images code</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e77a1f2b3c9f1afcbb72c15d5aeb11eee9de8d6d">e77a1f2b</a>) Exercises: Fix export question image when copying question</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e4b9278f0c24864f3d8eebf7873801e709fa41bd">e4b9278f</a> - <a href="https://task.beeznest.com/issues/12324">BT#12324</a>) Blog: Allow show 'Read more' link when adding page-break to blog post</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ef5380517e6d2dcab7b5545c4a97f642937b0141">ef538051</a>) Behat: Add update student profile test</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/82b557e80bb90e2c6bae15960f65e775ab66e158">82b557e8</a>) Admin: Fix FK error when deleting a user</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/011e556d6804331e6a9af2bf6070ec9c909df852">011e556d</a>) Behat: Add registration feature main/auth/inscription.php on page</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/4f430176949948151462b40dbbf791dde288b0e9">4f430176</a>) Documents: Hide "current folder selector" when moving a file to avoid confusion</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/41906da0563f0d193b28ea1d8fdf8978c288ab99">41906da0</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1540">GH#1540</a>) Documents: If cannot move then try to copy (on windows)</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/be1758a613bceb98c22c1d9e1c6303c63a11bd17">be1758a6</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1766">GH#1766</a>) Design: Update hot course div</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/94312b0ffd398c9ed9e21f5be500477399f0a676">94312b0f</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1810">GH#1810</a>) Tickets: Fix ticket table, simple and advanced search forms</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/c90e69d62677ab0a99499d4894efadff6a6f63fb">c90e69d6</a> - <a href="https://task.beeznest.com/issues/12513">BT#12513</a>) Sessions: Add career and promotion info to session admin page</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/6ad8026dca90b6001153f61f843461957b287ac4">6ad8026d</a> - <a href="https://task.beeznest.com/issues/12513">BT#12513</a>) Careers: Change careerId for career in Promotion entity and link to Career entity</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/bc935b0a54ed899e93dab0ba0dd56fe35f5e0da5">bc935b0a</a> - <a href="https://task.beeznest.com/issues/12513">BT#12513</a>) Sessions: Fix warnings in promotion-session assignment screen</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/35ac7e6792f6399722bb6db7ca6d7ae0d8d55942">35ac7e67</a> - <a href="https://task.beeznest.com/issues/12513">BT#12513</a>) Careers: Fix careers display</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/1f391940d1236fa947038dde94f7b88e6aa2a804">1f391940</a> - <a href="https://task.beeznest.com/issues/12513">BT#12513</a>) Careers: Fix issue displaying table of careers</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/63214df8f16badd5c75a974dd10a73f63c097f64">63214df8</a>) Exercises: Improve design of convert answer type button to reduce confusion</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/02220e09392b68ef639c993b452acd3fcd26fdb8">02220e09</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1738">GH#1738</a>) Editor: Integrating image2_chamilo with CKEditor toolbars #1738</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/b0378df4c96f5691cca8785a74144f39631faa4e">b0378df4</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1738">GH#1738</a>) Editor: Creating image2_chamilo plugin for CKEditor #1738</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/12cd5ac6f117172ab0f0b039588f751b3b4af400">12cd5ac6</a>) Update bower assets</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/031ac00eb6777e0dc4949282942cb18c9e69d7c9">031ac00e</a>) Add tpl layout for course progress</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/9f2cf5d77ebe2122d48623c48ad5a0859b5210e1">9f2cf5d7</a>) Fix error notice in course progress</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/a72072610281504e6cf2b4851ffe8f9d8cf20b77">a7207261</a> - <a href="https://task.beeznest.com/issues/12212">BT#12212</a>) Tracking= Fix mySpace statistics for assignments</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e6653a1182112a199dbc3f17b9326fb8ba06337c">e6653a11</a> - <a href="https://task.beeznest.com/issues/12212">BT#12212</a>) Work: Avoid count deleted assignments</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/0b393212d86235d1c27940e70406bffbc61fe47d">0b393212</a> - <a href="https://task.beeznest.com/issues/1771">BT#1771</a>) Exercises: Set course destination id</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/d965010f8084f193effb2dcc552b8221a0201de0">d965010f</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1771">GH#1771</a>) Exercises: Fix hotspot question copy</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/92ef60533b2294b41a869bcf43e75a19e1b44c79">92ef6053</a>) Accessibility: Add aria label for icon buttons</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/0e8531f87ad6bd2ba24129434f7fab6ba25c7934">0e8531f8</a>) Accessibility: Add aria label for icon buttons</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/c1c0918124c51e248b7657ac776756746a58b0cd">c1c09181</a>) Accessibility: Add label for course description.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/144cb73f132173bac39d22c8035b627ad71c985a">144cb73f</a>) Accessibility: Add aria-label to 'social wall' textarea</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/52560feb9830d8499cd433969113d3f2c225efbd">52560feb</a>) Accessibility: Add accessibility label</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/3ffb2ab2f5749f90cd52f00db876350b20488aea">3ffb2ab2</a>) Update search user form</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/af886ec2b3466f6e8dd53c1b950f26c9af58822e">af886ec2</a>) Add alternative display for teacher profile picture</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/83883a1872ee8aa5bbf04842ea0a2fc31d448cd9">83883a18</a>) Add alternative display for profile picture</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/6dc440ad773d57e03b41a4fbc996afd652772494">6dc440ad</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1771">GH#1771</a>) Exercises: Change saved quiz filename to quiz-now().jpg</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/12e56f40c53dbe6aa4de4446550e33b7b8c8c096">12e56f40</a>) Exercises: TestCategory improvements:</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/9582074f9f2b10c30aa4c2913b76102a78741f30">9582074f</a>) Wiki: Fix wiki form comments</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/c8ae6c6611c5d1f90e821abc87548502830db130">c8ae6c66</a> - <a href="https://task.beeznest.com/issues/12430">BT#12430</a>) Show teacher avatar in course list</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/104e35961227cab48b765ed617da6a8778af8275">104e3596</a>) Fix thematic advance TPL</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/9be713c268574fcceb1a37d92d3f59d18a858a2b">9be713c2</a> - <a href="https://task.beeznest.com/issues/12441">BT#12441</a>) New template TPL for course progress</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/5ae1998c775509a8ed87de096f08818599ae7446">5ae1998c</a> - <a href="https://task.beeznest.com/issues/12324">BT#12324</a>) Blog: Fix issue with detailed counting of characters in blog (cut() already counts with UTF-8)</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ccc929a4b2639837a18d5f61c69253f5e427b35f">ccc929a4</a> - <a href="https://task.beeznest.com/issues/12567">BT#12567</a>) Gradebook: Avoid show gradebook from all courses in a gradebook tool for teacher Student View is enabled</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/7b1b31fe5a54f6297d75d45d551c5bc4210e8329">7b1b31fe</a> - <a href="https://task.beeznest.com/issues/12324">BT#12324</a>) Blog: Fix issue with detailed counting of characters in blog</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/47c11fc515c199f79c07523a5c53d2c9608f04eb">47c11fc5</a>) Sessions: Show complete name + username.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/14525afe496bc2169222b099c291ad8037509838">14525afe</a> - <a href="https://task.beeznest.com/issues/12564">BT#12564</a>) Sessions: Add "session admin" to see sessions in reporting page</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e8bb581032aa214a7046e511cf3d675436efedcf">e8bb5810</a>) Exercises: Add c_id in query to avoid issues for question categories between courses</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/9c0c77acb6cc0a9f2f42083046640520bf0ab789">9c0c77ac</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1795">GH#1795</a>) Exercises: Show all questions to teacher when building an exercise with limited number of questions picked randomly</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/9f9e5278a7bf6bc5585600e84a52956513d78670">9f9e5278</a> - <a href="https://task.beeznest.com/issues/12444">BT#12444</a>) Avoid setting forced height to iframe for ios</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ed163930d08716fe476133ac5be584d6cc44c896">ed163930</a> - <a href="https://task.beeznest.com/issues/12444">BT#12444</a>) Remove erroneous semi-colon in CSS</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/9ebcedc92abdce7d431d4207f439fd9be6b8dede">9ebcedc9</a> - <a href="https://task.beeznest.com/issues/12441">BT#12441</a>) Fix thematic advance TPL</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/23f0e5d55c80e374630731237032e177f15f1f4f">23f0e5d5</a> - <a href="https://task.beeznest.com/issues/12444">BT#12444</a>) Exercises: Fix jquery selectors to save exercises</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/cbc13d6c69676c76c65a5bf435345ecee8849063">cbc13d6c</a> - <a href="https://task.beeznest.com/issues/12324">BT#12324</a>) Blog: Fix the post excerpt length</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/cdb7c1c1b1afdcf30432cd75d2162b5f9dbbccce">cdb7c1c1</a>) Exercises: Update questions list to show "score" column title instead of "Performance", that is more for students</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/695f83cacfaf7bf0ceef71f2f04fce2fdcafd0b5">695f83ca</a> - <a href="https://task.beeznest.com/issues/12514">BT#12514</a>) Exercises: Allow qualify with score <= max</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/5d7f4ff579807b245674bc2808d9d46cc9feab93">5d7f4ff5</a>) Behat: Fix test trying exercise</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/3d645f971d9da92b5b0f2ad0b58be14da45e9237">3d645f97</a> - <a href="https://task.beeznest.com/issues/12234">BT#12234</a>) LP: Hide breadcrumb when using LP</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/69df3022c67790d651b02d7e44418fa1d24fa4a9">69df3022</a> - <a href="https://task.beeznest.com/issues/12234">BT#12234</a>) Forum: Forum image can be clicked</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/79294a73889998b85de5222c18bcfd472574b2a9">79294a73</a> - <a href="https://task.beeznest.com/issues/12234">BT#12234</a>) LP: Fix edit final lp item</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/336fbd60ffdafc2715f720dc5bc6e2d8b7f2075e">336fbd60</a> - <a href="https://task.beeznest.com/issues/12234">BT#12234</a>) LP: Hide navigation bar when entering a LP</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/78b985803625cace89002ddd8fea9ea7514ce332">78b98580</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1795">GH#1795</a>) Exercises: Remove unused specialCategoryOrders variable</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/13f5bc23d41e565c5ab9e3260c50081c72a67f7d">13f5bc23</a> - <a href="https://task.beeznest.com/issues/12557">BT#12557</a>) Wiki: Fix new page title</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/d3e746f1f44d222c0130ce266f6b0670a2172d25">d3e746f1</a> - <a href="https://task.beeznest.com/issues/12546">BT#12546</a>) LP: Fix visibility parameter and query</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/6f04f4c213f4ffc86201966808fb67dd25ff6d7b">6f04f4c2</a>) LP: Fix update LP category users list</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/5a1fdb5585fc4921ca9b9ce575561b5e4de7a5d3">5a1fdb55</a>) Accessibility: Add aria label for icon buttons</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/1d05960a88c71112ecbd40a71728bbbacba9f5b5">1d05960a</a>) Accessibility: Add aria label for icon buttons</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/44b404a0ab1a403cdda68f7d734e0e57bbab129c">44b404a0</a>) Course visibility fixes in hot courses list</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/f0734fecd021893e6d38a2f7a8127b7f0e0c26c7">f0734fec</a>) Courses catalogue: Correction in link when the user is not registered</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/eff98c5f4273bf3b5b11e590dac5e33b4dabe129">eff98c5f</a> - <a href="https://task.beeznest.com/issues/12444">BT#12444</a>) Exercises: iPad: WIP set -webkit-overflow-scrolling as important</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/a8b575064027c99958aebacefa19d537e6b22fea">a8b57506</a> - <a href="https://task.beeznest.com/issues/12444">BT#12444</a>) Exercises: iPad: Use buttons instead of anchors in exercise submit</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/82ff09884a07c93ad188329b375bb056acab952f">82ff0988</a> - <a href="https://task.beeznest.com/issues/12444">BT#12444</a>) Exercises: iPad: Use buttons instead of anchors in exercise submit</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e6281cde910ad7cf1757d89135ef6ea91fac3c70">e6281cde</a>) Add tpl courses_progress, fix thematic controller</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/0f9d2111a1953ac27535930072c01b499d3cf0d2">0f9d2111</a> - <a href="https://task.beeznest.com/issues/12553">BT#12553</a>) Tracking: Fix course/session visibility</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/7370461f36feeab21ec7d3212022e51c2e059613">7370461f</a>) A theme folder is considered only if there's a default.css file in it.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/5c302828805ac15a0716efa8a939367aeb0c1b1f">5c302828</a>) Exercises: Fix update when updating quiz "hide_question_title"</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/bc22a13e7a788775c302e85bf74252f1a176ff70">bc22a13e</a>) Fix query in UserManager::get_user_list</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/70946e7e2f46c3603fdd555b94e75d5d86a7b263">70946e7e</a> - <a href="https://task.beeznest.com/issues/12212">BT#12212</a>) Work: Remove work_time when work is deleted</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/1a80c8d1dd8680c84f4e7ace4ff9cfe6155b6951">1a80c8d1</a> - <a href="https://task.beeznest.com/issues/12546">BT#12546</a>) LP: Avoid save empty dates as modified_on/expired_on in lp</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/bcd3670c7b7d946fd9784f4589a7e1a35fd93ad0">bcd3670c</a> - <a href="https://task.beeznest.com/issues/10892">BT#10892</a>) Exercises: Add annotation question type icon (and handy create.svg)</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/bf54e9738f8967773a8be21c1a8a92fe22954fa4">bf54e973</a> - <a href="https://task.beeznest.com/issues/12546">BT#12546</a>) LP: Fix insert/update lp_item_view</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/1a68775e22df78fe90d825de441bf4bfb4547a36">1a68775e</a> - <a href="https://task.beeznest.com/issues/12539">BT#12539</a>) Sessions: Restore the count of days to go in session for user</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/b43c3d3627dfb1984a004a6daba9e64d2afa9fe2">b43c3d36</a> - <a href="https://task.beeznest.com/issues/12490">BT#12490</a>) Plugins: VChamilo: Add virtual instance theme feature</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/a018bc60f18f2cfe2c6ea16610fd28f7d89be4d8">a018bc60</a>) Admin: Use api_get_current_url_id in isStyleChangeable()</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/391267d234ad035277b15f0ce56b078d5524ae46">391267d2</a>) Admin: Add security check to CSS download link generator</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/029776f32d752917cc0941d205e8af18acdf18e5">029776f3</a>) Admin: Improve CSS stylesheet change/upload</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/445cf69bfc794eccb7977f4e416da479f85d6c1b">445cf69b</a>) Replace custom queries to use CourseManager and UserManager libs</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/67686f59d6840fb43ab6a5bcc832b97218c448f8">67686f59</a> - <a href="https://task.beeznest.com/issues/12534">BT#12534</a>) Sessions: Fix session list table issue</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e6eaa0425e73ca25c2f752ac3e851ad751e4619b">e6eaa042</a>) Remove unused function: display_localised_html_file()</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/34ea2c6cdcaf0a7fdf6b7f49da63373917894aba">34ea2c6c</a>) Change function name from getCurrentUrlBuild() to getCurrentBuildingModeURL()</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/c9bdce0c208944485751a6b1eea6cbcffa27552c">c9bdce0c</a> - <a href="https://task.beeznest.com/issues/12514">BT#12514</a>) Forum: Allow save forum thread with weight qualification = 0</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/426b157946c085e401c7af20f1b2809a183de360">426b1579</a> - <a href="https://task.beeznest.com/issues/12514">BT#12514</a>) Forum: Show flash messages when updating forum thread</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/b7bfd0940798d89c946e67137d7d6ac2ecaac553">b7bfd094</a>) LP: Change __construct in order to avoid error if paremeters are not set.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/929f4ea57617f1bf92ccd1efd475891191df7aae">929f4ea5</a> - <a href="https://task.beeznest.com/issues/12528">BT#12528</a>) Gradebook: Avoid multiple creation of default certificates</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/15e6313c90348eab1a82fd131c95f4feab644fc8">15e6313c</a>) Speed: Remove triple api_get_session_condition()</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/b2910dcc84f7388dc81afd8908fdb4c04d703d4f">b2910dcc</a> - <a href="https://task.beeznest.com/issues/12303">BT#12303</a>) Exercises: Add ckeditor to matching and matching drag n drop</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e5b740666cf6716044493e0db68fa7f277b72e9f">e5b74066</a>) Courses list: Improvement of Student info: Now the admin is allowed to activate the options (‘progress’,’score’,’certificate’) individually.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/84f77f0d24750ef440653703b99fae87eca09d29">84f77f0d</a> - <a href="https://task.beeznest.com/issues/12514">BT#12514</a>) Forum: Fix user list for qualify in forum thread</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/d80e22670ac7789f09fa5a68cf38ce4866777453">d80e2267</a> - <a href="https://task.beeznest.com/issues/12324">BT#12324</a>) Blog: Allow show full post content on blog home</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/adf0fc1ce83212a54e5244a5f314c10e9aa08065">adf0fc1c</a> - <a href="https://task.beeznest.com/issues/12494">BT#12494</a>) Plugin: BBB: Fix meeting list for BBB</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/1a306ff5ba12af09835708ebfe35a631b6c363bf">1a306ff5</a>) LP: Fix condition in LearnpathItem constructor</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/6ae7ef3d49dff4d796a545742b6ab7ed598f4a66">6ae7ef3d</a>) Remove use of $_SERVER[QUERY_STRING]</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/f45b5e4f20048d829633b1f1db5dbc277c3fdb67">f45b5e4f</a>) LP: document creation/editions changes</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/825037afefb4a750b210aee712e3e94c201b4555">825037af</a>) Add Security::remove_XSS</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/fa9c1e6f65cb8d069fca3531b5611fcf6f3022d0">fa9c1e6f</a>) Add c_id, format code, add Security::remove_XSS, add api_get_cidreq()</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/527c94f444ca39f66843970e6be9383aea62ac33">527c94f4</a> - <a href="https://task.beeznest.com/issues/12236">BT#12236</a>) LP: Add preview link</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/b4ed8e914552424a974c7fb6ed572ab963817b57">b4ed8e91</a>) LP: Avoid invisible LP if blocked for user/lp subscription.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/0b6e2e030434546d631e0d03b2b338607afc1df9">0b6e2e03</a> - <a href="https://task.beeznest.com/issues/12527">BT#12527</a>) Registration: Fix setting allow_fields_inscription</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/42f046aca39b15facb52c6639accdaa6230f6383">42f046ac</a> - <a href="https://task.beeznest.com/issues/10892">BT#10892</a>) Exercises: Add score to annotation question</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/9c8528e4b3508670aedcefaab7a839a9c0e494a8">9c8528e4</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1577">GH#1577</a>) Fix (as best as possible) issue with UTF-8 titles in PHPMailer</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/f041d62f1ce488726b85daaea3f4c7825e1a3214">f041d62f</a> - <a href="https://task.beeznest.com/issues/10892">BT#10892</a>) Exercises: Show annotation question on exercises results</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/cc9cbb93ed439f7c0be30e47a93d6eae33ba5ab4">cc9cbb93</a> - <a href="https://task.beeznest.com/issues/10892">BT#10892</a>) Exercises: Allow add text to annotation when clicking</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/b7d32c59bc4ab7f85e66714e6317ff1bc473c2bf">b7d32c59</a> - <a href="https://task.beeznest.com/issues/10892">BT#10892</a>) Exercises: Simplify hidden input when elements changing values on annotation question</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/b76340f4eff499266061621cc90befc686ed15de">b76340f4</a> - <a href="https://task.beeznest.com/issues/10892">BT#10892</a>) Exercises: Fix add new element to annotation question</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/a472b8db0700f52a477708d3d9ec9c8aedf4ba13">a472b8db</a> - <a href="https://task.beeznest.com/issues/10892">BT#10892</a>) Exercises: Fix showing image for annotation question in admin list</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/c84b21858ed7a53dd27fb0209b2a7a3c5f3eae9d">c84b2185</a> - <a href="https://task.beeznest.com/issues/12324">BT#12324</a>) Blog: Change length of post extract in blog to 800 chars</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/1e5d710cc09c63f470af7906655d3890bb9f2c80">1e5d710c</a> - <a href="https://task.beeznest.com/issues/10892">BT#10892</a>) Exercises: WIP Allow add text to annotation question</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/b200ee91c162a196a595f9d99dc50c8868d3abbe">b200ee91</a>) Rename getFormatedSessionsBlock() to getFormattedSessionsBlock()</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/308cd52ff4735f9065706ee5e3cccd6fe5bef040">308cd52f</a>) Forum/Work: Use api_get_origin()/api_get_group_id()</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/97a0275a0890fcf438a771db3d239848b41ffc71">97a0275a</a> - <a href="https://task.beeznest.com/issues/10892">BT#10892</a>) Exercises: Show image in question list for admin</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/f81564a22a3536e50b03fd483c35dc9227b0e85a">f81564a2</a>) Accessibility: Add label for course description.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/fac07c2d5d70107f8d5f3717d88608e52523b836">fac07c2d</a>) Accessibility: Add aria-label to 'social wall' textarea</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/cfe2fdb10cc1628337bf85584773be02edbc324a">cfe2fdb1</a>) Accessibility: Add accessibility label</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/41392ebd26df8a032df4cf4e386b8ba05124cf4e">41392ebd</a>) Accessibility: Update search user form</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/140e065e960d9570cbf7222c22cabf16a2ffbe31">140e065e</a>) Accessibility: Add alternative display for teacher profile picture</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/6a3ee006f7398b60c3c518acceb9597938a6551b">6a3ee006</a> - <a href="https://task.beeznest.com/issues/10894">BT#10894</a>) Forum: Add function postIsEditableByStudent</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/32e6a5ef38f692f455d2d2fc77d6216a6f11dede">32e6a5ef</a> - <a href="https://task.beeznest.com/issues/12235">BT#12235</a>) Link: Fix double link creation</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/5b36d80cd66b88214bb9a7b824353efdb58a972c">5b36d80c</a> - <a href="https://task.beeznest.com/issues/12235">BT#12235</a>) Link: Fix link previews use link_goto.php script</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/98eeac993ea37546e4378e2ca98f2b680a7ab61b">98eeac99</a> - <a href="https://task.beeznest.com/issues/10884">BT#10884</a>) LP: Fix thread preview</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/c94bf0097390d9077d56f0e1f90db1987df37fb8">c94bf009</a> - <a href="https://task.beeznest.com/issues/12521">BT#12521</a>) Tracking: Add table id and class for LP tracking</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/cf1539af17250606d4e894d74a6ace5c70188ed0">cf1539af</a> - <a href="https://task.beeznest.com/issues/10897">BT#10897</a>) Exercises: Fix course ID parameter in visibility info recovery</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/a1c4c6fe62c53f39717d485cb7d4b816f3f62355">a1c4c6fe</a> - <a href="https://task.beeznest.com/issues/10892">BT#10892</a>) Exercises: Adding Annotation question type</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e8eab300103df32b940eaa4a2b52f3e9c7f13122">e8eab300</a> - <a href="https://task.beeznest.com/issues/12324">BT#12324</a>) Blog: Fix date creation for blog and first post</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/c1477dec9768734db2e653d7a3d7ad9c2f76e220">c1477dec</a> - <a href="https://task.beeznest.com/issues/12514">BT#12514</a>) Forum: Fix thread user to qualify within session</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/5291112e1fd5aac3a6c11149f411b76c314ee859">5291112e</a>) Survey: Split the file containing the SurveyManager and SurveyUtil classes</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/58a8171a17dc9184186fb75e7aa1570d42d66add">58a8171a</a> - <a href="https://task.beeznest.com/issues/12514">BT#12514</a>) Forum: Redirect to qualified learners page when qualifying</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/d923568cf471972525d8542f4402f5ed06e318b1">d923568c</a> - <a href="https://task.beeznest.com/issues/12514">BT#12514</a>) Forum: Remove unnecessary validation</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/fb93a142b141bf0db1aeab6fbafe3d3a41e2cc78">fb93a142</a> - <a href="https://task.beeznest.com/issues/10896">BT#10896</a>) Files upload: Add hover dropzone css style feature</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/45e1ef5377c70d11c81d9cfd1a291e0a97a6c8fa">45e1ef53</a> - <a href="https://task.beeznest.com/issues/12515">BT#12515</a>) Gradebook: Fix gradebook table</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/cfcfef4113eee3e9fff4cdc90a725f77166f3b90">cfcfef41</a> - <a href="https://task.beeznest.com/issues/12235">BT#12235</a>) Link: Fix preview icon in links</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/bcab2ee6acb8b0a7871016f995d7eb94d9e99862">bcab2ee6</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1603">GH#1603</a>) Registration: Freeze inputs if changeable is off</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/f7b84a0df343aa54e457a8f3d7066ea0c4a9c42a">f7b84a0d</a> - <a href="https://task.beeznest.com/issues/10884">BT#10884</a>) Forum: Add forum/thread preview</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/5c044175aa1bdf3a519f9b02e90cd208127b5dab">5c044175</a>) Add #homepage-home and welcome-home-top-temp CSS blocks</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/3932254d2e71a00bd03e327ae87b25887cbfc12c">3932254d</a> - <a href="https://task.beeznest.com/issues/10892">BT#10892</a>) Exercises: Remove unused function around exercise.class.php</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/bc3475d26f550206fc83e99b713bbb4b59f3025a">bc3475d2</a>) Catalogue: Fix search catalogue</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/fe95628d65b6ccc031c9b36318652b6e359b2b1b">fe95628d</a>) Catalogue: Fix new layout catalogue course</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/5d50bf934ebd9a33d7ebb73109b8357985ef90f6">5d50bf93</a>) Catalogue: Move php files from the catalog of courses tpl in folder auth</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/3da03a5e0331c7abbf4eb3779685a03e032378e0">3da03a5e</a> - <a href="https://task.beeznest.com/issues/10893">BT#10893</a>) Work: Change icon for corrections upload</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/bdb1dbdd685582404f81e5bfd7e17ba14dedb22d">bdb1dbdd</a> - <a href="https://task.beeznest.com/issues/12509">BT#12509</a>) Course restore: Check if user exists</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/d47bbb4a25755d31e8f97ca18c96001a5550d706">d47bbb4a</a>) Gradebook: Avoid use of DOMDocument</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/f818a6b928b6f2ed732a1d8b6a711f8cdb6a576b">f818a6b9</a>) Gradebook: Fix certificate export to HTMl</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/c5a51fc0d10436eac77ae2d6b789a6e26314a556">c5a51fc0</a> - <a href="https://task.beeznest.com/issues/11830">BT#11830</a>) Use PHPExcel class instead of Spreadsheet_Excel_Reader</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/2feffcce8aa1732c027823686d58a361c5d8cdcd">2feffcce</a>) Remove pear/excelreader replaced by PHPExcel</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/f7ee2fba067bf32b39f2d5a37737904328eff04b">f7ee2fba</a> - <a href="https://task.beeznest.com/issues/12482">BT#12482</a>) Social: Removing Bold Text from Output Tray</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/1e28447577b91c05423062d7639084f64441b71f">1e284475</a> - <a href="https://task.beeznest.com/issues/12324">BT#12324</a>) Blog: Show nested post comments</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/640d152943622140fb754e72ccd288a6b4f96852">640d1529</a> - <a href="https://task.beeznest.com/issues/12324">BT#12324</a>) Blog: Fix edit post and delete comment</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/40abbbc63a0236a22cbe32000eedc2dadc230517">40abbbc6</a> - <a href="https://task.beeznest.com/issues/12324">BT#12324</a>) Blog: Show post when it is added</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/514f70384ab50219765e226bed004b482a625154">514f7038</a> - <a href="https://task.beeznest.com/issues/12324">BT#12324</a>) Blog: Fix post comments template</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/883d71fdf25e503c33f1c47e3ac717b5fcf6ad02">883d71fd</a> - <a href="https://task.beeznest.com/issues/12324">BT#12324</a>) Blog: Fix post date</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e91d3dc3575502eec7c08a2da8789459b591d72b">e91d3dc3</a> - <a href="https://task.beeznest.com/issues/12238">BT#12238</a>) LP: Add session star in links when building a LP</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/cdcb2c71a5177a1b07472833919c41a15da0bf3d">cdcb2c71</a> - <a href="https://task.beeznest.com/issues/12238">BT#12238</a>) LP: Add session star in exercises when building a LP</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/78a7fea385f6a947fc60503c8802793163801d4b">78a7fea3</a> - <a href="https://task.beeznest.com/issues/12238">BT#12238</a>) LP: Show "session star" when adding docs in a LP</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/c274cd87338b50f530cbb82ae672826b5d51e721">c274cd87</a>) User portal: Fix missing sql data & wrong variable name</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/4aa97efd7e26966e02ed128448f1b24b68c68a85">4aa97efd</a>) Blog: Rename blog methods to camelCase</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/5608fdd25c870866fb7e9f966a2dcce2d0e4d9bf">5608fdd2</a>) Blog: Move blog functions into class and avoid using course_code where course_id can be used</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/ac3a93206e49e44806a3755e56aa8799d91015d0">ac3a9320</a>) Applying code conventions, improving PHPDoc and minor logic changes (return if ID not defined, ...)</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/91d0e0564c45ebef2c27e92344d55b1dbba09058">91d0e056</a>) Exercises: Improve responsive design</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/20cded81589a87f3f99aeab80c1cb40324e57bf9">20cded81</a>) Fix global menu responsiveness</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/88de33947dd27627820aa6fe30996c060fd04c06">88de3394</a> - <a href="https://task.beeznest.com/issues/12493">BT#12493</a>) Add link for teacher for access to closed course</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/22b0c5652b39afaad5c252d994479cdcc82dcd22">22b0c565</a>) Fix global menu responsiveness</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/6f388997a3aa02b1fac73cae7c3f880d40ffa663">6f388997</a>) Fix home mobile view blocks</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/7fcd6ff1cd3fc3e032ed0c09c155b71e25b997d1">7fcd6ff1</a> - <a href="https://task.beeznest.com/issues/12324">BT#12324</a>) Blog: Fix post edit blog</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/9a6e69a12fe20c130da02cb87f14c60c93938ca3">9a6e69a1</a> - <a href="https://task.beeznest.com/issues/12324">BT#12324</a>) Blog: Display post score ranking</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/94bf02463d0a2e417eaed9ee650f768f3c42cb9e">94bf0246</a> - <a href="https://task.beeznest.com/issues/12324">BT#12324</a>) Blog: Fix blog post style</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/3a231f4eb7f483ef35c90e8ac8b488c3cf5e28fc">3a231f4e</a> - <a href="https://task.beeznest.com/issues/12324">BT#12324</a>) Blog: Using Display::addFlash when showing messages in blog tool</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/be8b67fc1a9c695784ca826e84846cc4e0dd3a11">be8b67fc</a> - <a href="https://task.beeznest.com/issues/12324">BT#12324</a>) Blog: Fix template for blog task</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/c57abfd90086a4910a9c7f3f99d47153aebfb803">c57abfd9</a> - <a href="https://task.beeznest.com/issues/12324">BT#12324</a>) Blog: Fix add comment to post</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/37cddd152efa5a870862e5f8450df9e14e77bcde">37cddd15</a> - <a href="https://task.beeznest.com/issues/12491">BT#12491</a>) LP: Fix double question mark in learning paths url building</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/543db6f663e24bfc75af2e8d232e37b3616e9a7e">543db6f6</a> - <a href="https://task.beeznest.com/issues/12324">BT#12324</a>) Blog: Improve/format code for blog post</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e73b38d508b1c913f8871638fc7c552451c606a9">e73b38d5</a> - <a href="https://task.beeznest.com/issues/12324">BT#12324</a>) Blog: Remove use of Display::display_header on blog tool</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/1057fa57dcac9dc0a901e99e3eb7d89be1afdf7d">1057fa57</a>) Add alternative display for profile picture</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/63080063dd04cf7d251a2cb12f7627ea93d249ee">63080063</a>) Install: Fix bootstrap-select reference in install page</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/4794ebbb005052a32c9b19656ba407cbef9e6a79">4794ebbb</a> - <a href="https://task.beeznest.com/issues/12324">BT#12324</a>) Blog: Fix blog search</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/bea616652e73365ae7fec2847aac70202d44c294">bea61665</a> - <a href="https://task.beeznest.com/issues/12324">BT#12324</a>) Blog: Fix blog search</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/9e73f2845bd805cb88878f66bcab3b8a92a38852">9e73f284</a>) Plugins: VChamilo: Add info about Archive, Home and Upload URL configs in instance edition</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/3720bd89f95f22c16b20a44792ae518480c94d5f">3720bd89</a>) Plugins: VChamilo: Add DB queries for vChamilo plugin v1.6</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/1e66f454d6e54bcd9b4db1a6967e18582a2e6248">1e66f454</a> - <a href="https://task.beeznest.com/issues/12324">BT#12324</a>) Blog: Add blog layout</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/2b70b021ef33dd672192efc54949a4171b8c4897">2b70b021</a> - <a href="https://task.beeznest.com/issues/12324">BT#12324</a>) Blog: Adding attachments in comments</li>
         <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/654fb09347462e2270a5d97fddef3ce0693cb3b7">654fb093</a> - <a href="https://task.beeznest.com/issues/12441">BT#12441</a>) Allow single thematic plan chapter export to pdf</li>
         <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/157754fd77d393688a9574c52390a72448231012">157754fd</a>) Tickets: Add log on ticket assignation.</li>
         <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/3f5bb90ae99554fdbc5f0867f5b91d80b461cbad">3f5bb90a</a> - <a href="https://task.beeznest.com/issues/12486">BT#12486</a>) Assignments: Add security::remove_XSS</li>
@@ -666,9 +1197,14 @@
         <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/6e681e096db4f96398022f8ce02545130e28ded7">6e681e09</a>) Announcements: Use getLasteditDate instead of creation date</li>
     </ul>
     <h3>Stylesheets and theming</h3>
-    <p>A series of changes have been applied to the main/template/default/ folder in this version, so if you use your own template, make sure you update it to use the latest displays. Most notably:</p>
+    <p>A series of changes have been applied to the main/template/default/ folder in this version, so if you use your own template, make sure you update it to use the latest displays (otherwise some pages might fail and show TWIG-related error messages). Most notably:</p>
     <ul>
         <li>A change has been made to include image2_chamilo in the ckeditor plugins in default/layout/header.js.tpl. If you have a custom version of this file, please search for the image2_chamilo text in the default TPL and make sure you apply the change, otherwise CKeditor might not display anymore.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/7c4f0d6453fb422009facc404db664e3e525fa3c">7c4f0d64</a>) Add margin to all Bootstrap tabs</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/b53b86fbeaeb773b8877af14119b888acc8750d6">b53b86fb</a>) Remove jquery-ui tabs from Stylesheets Settings</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e85abd8dbc99d2a876e432e697147264ac325a00">e85abd8d</a> - <a href="https://task.beeznest.com/issues/12665">BT#12665</a>) Add template pdf_general_thematic.tpl</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/d975e2e6b9672ae34e1c82878d93a387d248a591">d975e2e6</a>) Add career dashboard.tpl</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/b3f626cd9bc8432d2040583412341618650e345f">b3f626cd</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/1868">GH#1868</a>) Remove duplicated twig filters</li>
     </ul>
     <h3>Web services</h3>
     <ul>
@@ -692,6 +1228,8 @@
         <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/caca50ed403705c3e8771f9bb5ff4e88a927b10b">caca50ed</a>) Remove unused file lp_list_search.css</li>
         <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/267940d0911c2034d66a8db66a70c2cb9a3f43b5">267940d0</a>) Remove unused session ascii_math_loaded</li>
         <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/d8b988f13103907e4d8320b6cfedfda5818d44f1">d8b988f1</a>) Removing <code>check_parameter</code> and <code>check_parameter_or_fail</code> functions from <code>CourseManager</code></li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/e23d0a50f736b649bb3d189d3fb71f5ef23030eb">e23d0a50</a>) Removed unused main/exercise/feedback.php file.</li>
+        <li>(<a href="https://github.com/chamilo/chamilo-lms/commit/f2ff57db641c2791dede96bd634486d5d7b89a59">f2ff57db</a>) Add deprecated in main/exercise/feedback.php file. Probably not used.</li>
     </ul>
     <h3>Known issues</h3>
     <ul>
@@ -699,6 +1237,7 @@
         <li>In Internet Explorer 9, learning paths might not show other pages than the first to be opened. We lacked computers with IE9 at the time of release of 1.10.8. Guaranteeing IE9 support will likely require additional services. See <a href="https://support.chamilo.org/issues/8075">the corresponding bug report</a></li>
         <li>The Xapian search module is broken. We hope to fix that soon, but not a lot of people use it, so no real priority is given to this.</li>
         <li>Encoding issues when importing accentuated characters from MS-Office-generated .xlsx files (for example when importing exercises). This isn't really a Chamilo issue, but since some users might have issues with that, we've decided to report it to avoid any surprise.</li>
+        <li>The text-to-speech providers are not supporting a free option anymore, making this feature non-functional - see <a href="https://github.com/chamilo/chamilo-lms/issues/1956">#1956</a></li>
     </ul>
 
 

+ 1 - 1
documentation/dependencies.html

@@ -71,7 +71,7 @@ We recommend using HTML5-compatible technology.
 <h2>Dependencies - server-side</h2>
 <ul>
   <li>Apache 2+</li>
-  <li> PHP 5.4 or higher with MySQL bindings (mysqlnd is recommended) and php-gd extension to allow Chamilo to resize pictures. Now also supports PHP 7.0</li>
+  <li> PHP 5.5 or higher with MySQL bindings (mysqlnd is recommended) and php-gd extension to allow Chamilo to resize pictures. Now also supports PHP 7.0</li>
   <li>MySQL 5.1+ or any version of MariaDB database server</li>
   <li>php5-intl package (for international behaviour support)</li>
   <li>php5-mbstring package (for international behaviour support)</li>

+ 1 - 1
documentation/installation_guide.html

@@ -78,7 +78,7 @@ Chamilo is mainly a LMS running (the so called <span style="font-weight: bold;">
 <ul>
 <li><span style="font-weight: bold;">Apache 2.2+</span></li>
 <li><span style="font-weight: bold;">MySQL 5.1+ or MariaDB 5+</span></li>
-<li><span style="font-weight: bold;">PHP 5.4+ (5.6 recommended for greater efficiency) (support for PHP7 seems OK but not evaluated on high load setups just yet)</span></li>
+<li><span style="font-weight: bold;">PHP 5.5+ (5.6 recommended for greater efficiency) (support for PHP7 seems OK but not evaluated on high load setups just yet)</span></li>
 </ul>
 <br />
 All these pieces of software are free software and freely available. <br /><br />

+ 1 - 1
documentation/installation_guide_es_ES.html

@@ -86,7 +86,7 @@
 Chamilo puede ser instalado indiferentemente en servidores Windows, Linux, Mac OS X y UNIX. Sin embargo, nosotros recomendamos el uso de un servidor Linux para una óptima flexibilidad, control remoto y escalabilidad.
 </p>
 <p>
-Chamilo es fundamentalmente un LMS que se ejecuta con Apache (2.2+), MySQL 5.1+ (o MariaDB) y PHP 5.4+ (trilogía también llamada AMP).
+Chamilo es fundamentalmente un LMS que se ejecuta con Apache (2.2+), MySQL 5.1+ (o MariaDB) y PHP 5.5+ (trilogía también llamada AMP).
 </p>
 <p>
 Todo este software es software de código abierto y está disponible libremente.

+ 1 - 1
documentation/installation_guide_fr_FR.html

@@ -80,7 +80,7 @@
 
             Chamilo est un système de gestion de l'apprentissage (LMS) qui fonctionne
             principallement sur base d'un <span style="font-weight: bold;">serveur web (Apache 2.2+)</span>, de <span style="font-weight: bold;">MySQL 5.1+ ou de MariaDB 5+
-                (5 ou 10)</span> et de <span style="font-weight: bold;">PHP 5.4+</span> (le support de PHP 7 n'a pas été pleinement testé). <br />
+                (5 ou 10)</span> et de <span style="font-weight: bold;">PHP 5.5+</span> (le support de PHP 7 n'a pas été pleinement testé). <br />
 
 
             <br />

+ 1 - 1
documentation/installation_guide_it_IT.html

@@ -73,7 +73,7 @@
 <p class="p8"><span class="s1"></span><br></p>
 <p class="p2"><span class="s1"><b>Chamilo</b> può essere installato indifferentemente su server Windows, Linux, Mac OS X e Unix. Tuttavia raccomandiamo l’utilizzo di server Linux per sfruttarne al meglio le caratteristiche di flessibilità, controllo remoto e scalabilità.</span></p>
 <p class="p3"><span class="s1"></span><br></p>
-<p class="p2"><span class="s1"><b>Chamilo</b> è principalmente un <b>LMS (Learning Management System)</b> che gira sulla piattaforma composta da <b>Apache (1.3,2.0 or 2.2)</b>, <b>MySQL 5.1 (o MariaDB</b>) e <b>PHP 5.4, 5.5 o 5.6</b>, meglio nota come piattaforma <b>AMP</b>.</span></p>
+<p class="p2"><span class="s1"><b>Chamilo</b> è principalmente un <b>LMS (Learning Management System)</b> che gira sulla piattaforma composta da <b>Apache (1.3,2.0 or 2.2)</b>, <b>MySQL 5.1 (o MariaDB</b>) e <b>PHP 5.5 o 5.6</b>, meglio nota come piattaforma <b>AMP</b>.</span></p>
 <p class="p3"><span class="s1"></span><br></p>
 <p class="p2"><span class="s1">Tutti questi software sono gratuiti e liberamente scaricabili.</span></p>
 <p class="p3"><span class="s1"></span><br></p>

+ 10 - 6
index.php

@@ -38,7 +38,10 @@ if (!empty($_GET['logout'])) {
 /**
  * Registers in the track_e_default table (view in important activities in admin
  * interface) a possible attempted break in, sending auth data through get.
- * @todo This piece of code should probably move to local.inc.php where the actual login / logout procedure is handled. The real use of this code block should be seriously considered as well. This form should just use a security token and get done with it.
+ * @todo This piece of code should probably move to local.inc.php where the
+ * actual login / logout procedure is handled.
+ * The real use of this code block should be seriously considered as well.
+ * This form should just use a security token and get done with it.
  */
 if (isset($_GET['submitAuth']) && $_GET['submitAuth'] == 1) {
     $i = api_get_anonymous_id();
@@ -69,12 +72,13 @@ if (!api_get_user_id() && CustomPages::enabled()) {
 }
 
 /**
- * @todo This piece of code should probably move to local.inc.php where the actual login procedure is handled.
- * @todo Check if this code is used. I think this code is never executed because after clicking the submit button
- *       the code does the stuff in local.inc.php and then redirects to index.php or user_portal.php depending
- *       on api_get_setting('page_after_login').
+ * @todo This piece of code should probably move to local.inc.php where the
+ * actual login procedure is handled.
+ * @todo Check if this code is used. I think this code is never executed because
+ * after clicking the submit button the code does the stuff
+ * in local.inc.php and then redirects to index.php or user_portal.php depending
+ * on api_get_setting('page_after_login').
  */
-
 if (!empty($_POST['submitAuth'])) {
     // The user has been already authenticated, we are now to find the last login of the user.
     if (isset($_user['user_id'])) {

+ 2 - 2
main/admin/access_url_add_courses_to_url.php

@@ -58,10 +58,10 @@ if (isset($_POST['form_sent']) && $_POST['form_sent']) {
 
     if ($form_sent == 1) {
         if (count($courses) == 0 || count($url_list) == 0) {
-            Display::addFlash(Display::return_message(get_lang('AtLeastOneCourseAndOneURL'), 'error'));
+            echo Display::return_message(get_lang('AtLeastOneCourseAndOneURL'), 'error');
         } else {
             UrlManager::add_courses_to_urls($courses, $url_list);
-            Display::addFlash(Display::return_message(get_lang('CourseBelongURL'), 'confirm'));
+            echo Display::return_message(get_lang('CourseBelongURL'), 'confirm');
         }
     }
 }

+ 2 - 2
main/admin/access_url_add_usergroup_to_url.php

@@ -51,10 +51,10 @@ if (isset($_POST['form_sent']) && $_POST['form_sent']) {
 
     if ($form_sent == 1) {
         if (count($userGroups) == 0 || count($urlList) == 0) {
-            Display :: display_error_message(get_lang('AtLeastOneUserGroupAndOneURL'));
+            echo Display::return_message(get_lang('AtLeastOneUserGroupAndOneURL'), 'error');
         } else {
             UrlManager::addUserGroupListToUrl($userGroups, $urlList);
-            Display::display_confirmation_message(get_lang('UserGroupBelongURL'));
+            echo Display::return_message(get_lang('UserGroupBelongURL'), 'confirm');
         }
     }
 }

+ 4 - 3
main/admin/access_url_add_users_to_url.php

@@ -55,12 +55,13 @@ if ($_POST['form_sent']) {
 
     if ($form_sent == 1) {
         if (count($users) == 0 || count($url_list) == 0) {
-            Display:: display_error_message(
-                get_lang('AtLeastOneUserAndOneURL')
+            echo Display::return_message(
+                get_lang('AtLeastOneUserAndOneURL'),
+                'error'
             );
         } else {
             UrlManager::add_users_to_urls($users, $url_list);
-            Display:: display_confirmation_message(get_lang('UsersBelongURL'));
+            echo Display::return_message(get_lang('UsersBelongURL'), 'confirm');
         }
     }
 }

+ 1 - 1
main/admin/access_url_edit_usergroup_to_url.php

@@ -202,7 +202,7 @@ $url_list = UrlManager::get_url_data();
         <input type="hidden" name="add_type" value="<?php echo $add_type ?>"/>
         <?php
         if (!empty($errorMsg)) {
-            Display::addFlash(Display::return_message($errorMsg, 'normal')); //main API
+            echo Display::return_message($errorMsg, 'normal'); //main API
         }
         ?>
         <div class="row">

+ 2 - 2
main/admin/access_url_edit_users_to_url.php

@@ -134,7 +134,7 @@ if (isset($_POST['form_sent']) && $_POST['form_sent']) {
 Display::display_header($tool_name);
 
 if (!empty($message)) {
-    Display::addFlash(Display::return_message($message, 'normal', false));
+    echo Display::return_message($message, 'normal', false);
 }
 
 echo '<div class="actions">';
@@ -221,7 +221,7 @@ $url_list = UrlManager::get_url_data();
 
 <?php
 if (!empty($errorMsg)) {
-    Display::addFlash(Display::return_message($errorMsg, 'normal')); //main API
+    echo Display::return_message($errorMsg, 'normal'); //main API
 }
 ?>
 

+ 20 - 19
main/admin/access_urls.php

@@ -19,7 +19,7 @@ if (!api_get_multiple_access_url()) {
     exit;
 }
 
-$interbreadcrumb[] = array ("url" => 'index.php', 'name' => get_lang('PlatformAdmin'));
+$interbreadcrumb[] = array("url" => 'index.php', 'name' => get_lang('PlatformAdmin'));
 $tool_name = get_lang('MultipleAccessURLs');
 Display :: display_header($tool_name);
 
@@ -35,36 +35,34 @@ if (isset($_GET['action'])) {
         case 'delete_url':
             $result = UrlManager::delete($url_id);
             if ($result) {
-                Display::addFlash(Display::return_message(get_lang('URLDeleted'), 'normal'));
+                echo Display::return_message(get_lang('URLDeleted'), 'normal');
             } else {
-                Display :: display_error_message(get_lang('CannotDeleteURL'));
+                echo Display::return_message(get_lang('CannotDeleteURL'), 'error');
             }
             break;
         case 'lock':
             UrlManager::set_url_status('lock', $url_id);
-            Display::addFlash(Display::return_message(get_lang('URLInactive'), 'normal'));
+            echo Display::return_message(get_lang('URLInactive'), 'normal');
             break;
         case 'unlock':
             UrlManager::set_url_status('unlock', $url_id);
-            Display::addFlash(Display::return_message(get_lang('URLActive'), 'normal'));
+            echo Display::return_message(get_lang('URLActive'), 'normal');
             break;
         case 'register':
             // we are going to register the admin
             if (api_is_platform_admin()) {
-                if ($current_access_url_id!=-1) {
+                if ($current_access_url_id != -1) {
                     $url_str = '';
                     foreach ($url_list as $my_url) {
                         if (!in_array($my_url['id'], $my_user_url_list)) {
                             UrlManager::add_user_to_url(api_get_user_id(), $my_url['id']);
-                            $url_str.=$my_url['url'].' <br />';
+                            $url_str .= $my_url['url'].' <br />';
                         }
                     }
-                    Display::addFlash(
-                        Display::return_message(
-                            get_lang('AdminUserRegisteredToThisURL').': '.$url_str.'<br />',
-                            'normal',
-                            false
-                        )
+                    echo Display::return_message(
+                        get_lang('AdminUserRegisteredToThisURL').': '.$url_str.'<br />',
+                        'normal',
+                        false
                     );
                 }
             }
@@ -83,16 +81,18 @@ foreach ($url_list as $my_url) {
     }
 }
 if (!empty($url_string)) {
-    Display:: display_warning_message(
+    echo Display::return_message(
         get_lang('AdminShouldBeRegisterInSite').'<br />'.$url_string,
+        'warning',
         false
     );
 }
 
 // checking the current installation
 if ($current_access_url_id == -1) {
-    Display::display_warning_message(
-        get_lang('URLNotConfiguredPleaseChangedTo').': '.api_get_path(WEB_PATH)
+    echo Display::return_message(
+        get_lang('URLNotConfiguredPleaseChangedTo').': '.api_get_path(WEB_PATH),
+        'warning'
     );
 } elseif (api_is_platform_admin()) {
     $quant = UrlManager::relation_url_user_exist(
@@ -100,8 +100,9 @@ if ($current_access_url_id == -1) {
         $current_access_url_id
     );
     if ($quant == 0) {
-        Display:: display_warning_message(
+        echo Display::return_message(
             '<a href="'.api_get_self().'?action=register&sec_token='.$parameters['sec_token'].'">'.get_lang('ClickToRegisterAdmin').'</a>',
+            'warning',
             false
         );
     }
@@ -155,7 +156,7 @@ foreach ($sortable_data as $row) {
         $image = 'wrong';
     }
     // you cannot lock the default
-    if ($row['id']=='1') {
+    if ($row['id'] == '1') {
         $status = Display::return_icon($image.'.gif', get_lang(ucfirst($action)));
     } else {
         $status = '<a href="access_urls.php?action='.$action.'&amp;url_id='.$row['id'].'">'.
@@ -165,7 +166,7 @@ foreach ($sortable_data as $row) {
     $url_id = $row['id'];
     $actions = Display::url(Display::return_icon('edit.png', get_lang('Edit'), array(), ICON_SIZE_SMALL), "access_url_edit.php?url_id=$url_id");
     if ($url_id != '1') {
-        $actions .= '<a href="access_urls.php?action=delete_url&amp;url_id='.$url_id.'" onclick="javascript:if(!confirm('."'".addslashes(api_htmlentities(get_lang("ConfirmYourChoice"),ENT_QUOTES,$charset))."'".')) return false;">'.
+        $actions .= '<a href="access_urls.php?action=delete_url&amp;url_id='.$url_id.'" onclick="javascript:if(!confirm('."'".addslashes(api_htmlentities(get_lang("ConfirmYourChoice"), ENT_QUOTES, $charset))."'".')) return false;">'.
             Display::return_icon('delete.png', get_lang('Delete'), array(), ICON_SIZE_SMALL).'</a>';
     }
     $urls[] = array($url, $description, $status, $actions);

+ 1 - 1
main/admin/add_courses_to_usergroup.php

@@ -206,7 +206,7 @@ echo Display::input('hidden', 'id', $id);
 echo Display::input('hidden', 'form_sent', '1');
 echo Display::input('hidden', 'add_type', null);
 if (!empty($errorMsg)) {
-    Display::addFlash(Display::return_message($errorMsg, 'normal')); //main API
+    echo Display::return_message($errorMsg, 'normal'); //main API
 }
 ?>
 

+ 1 - 1
main/admin/add_sessions_to_promotion.php

@@ -158,7 +158,7 @@ echo Display::input('hidden', 'id', $id);
 echo Display::input('hidden', 'form_sent', '1');
 echo Display::input('hidden', 'add_type', null);
 if (!empty($errorMsg)) {
-    Display::addFlash(Display::return_message($errorMsg, 'normal')); //main API
+    echo Display::return_message($errorMsg, 'normal'); //main API
 }
 ?>
 

+ 1 - 1
main/admin/add_sessions_to_usergroup.php

@@ -179,7 +179,7 @@ echo Display::input('hidden', 'id', $id);
 echo Display::input('hidden', 'form_sent', '1');
 echo Display::input('hidden', 'add_type', null);
 if (!empty($errorMsg)) {
-    Display::addFlash(Display::return_message($errorMsg, 'normal')); //main API
+    echo Display::return_message($errorMsg, 'normal'); //main API
 }
 ?>
 

+ 1 - 1
main/admin/configure_extensions.php

@@ -136,7 +136,7 @@ Display::display_header($nameTool);
 <div id="message" style="display: none">
 	<?php
 	if (!empty($message)) {
-        Display::addFlash(Display::return_message($message, 'normal'));
+        echo Display::return_message($message, 'normal');
     }
 	?>
 </div>

+ 149 - 149
main/admin/configure_homepage.php

@@ -49,7 +49,7 @@ function home_tabs($file_logged_in)
 }
 
 $cidReset = true;
-require_once __DIR__ . '/../inc/global.inc.php';
+require_once __DIR__.'/../inc/global.inc.php';
 
 $this_section = SECTION_PLATFORM_ADMIN;
 $_SESSION['this_section'] = $this_section;
@@ -150,8 +150,8 @@ if (api_is_multiple_url_enabled()) {
         $clean_url .= '/';
 
         $homep = $homePath; //homep for Home Path
-        $homep_new = $homePath . $clean_url; //homep for Home Path added the url
-        $new_url_dir = $homePath . $clean_url;
+        $homep_new = $homePath.$clean_url; //homep for Home Path added the url
+        $new_url_dir = $homePath.$clean_url;
         //we create the new dir for the new sites
         if (!is_dir($new_url_dir)) {
             mkdir($new_url_dir, api_get_permissions_for_new_directories());
@@ -175,18 +175,18 @@ $homef = array($menuf, $newsf, $topf, $noticef, $menutabs, $mtloggedin);
 // If language-specific file does not exist, create it by copying default file
 foreach ($homef as $my_file) {
     if (api_is_multiple_url_enabled()) {
-        if (!file_exists($homep_new . $my_file . '_' . $lang . $ext)) {
-            if (!file_exists($homep . $my_file . $ext)) {
-                touch($homep . $my_file . $ext);
+        if (!file_exists($homep_new.$my_file.'_'.$lang.$ext)) {
+            if (!file_exists($homep.$my_file.$ext)) {
+                touch($homep.$my_file.$ext);
             }
-            @copy($homep . $my_file . $ext, $homep_new . $my_file . '_' . $lang . $ext);
+            @copy($homep.$my_file.$ext, $homep_new.$my_file.'_'.$lang.$ext);
         }
     } else {
-        if (!file_exists($homep . $my_file . '_' . $lang . $ext)) {
-            if (!file_exists($homep . $my_file . $ext)) {
-                touch($homep . $my_file . $ext);
+        if (!file_exists($homep.$my_file.'_'.$lang.$ext)) {
+            if (!file_exists($homep.$my_file.$ext)) {
+                touch($homep.$my_file.$ext);
             }
-            @copy($homep . $my_file . $ext, $homep . $my_file . '_' . $lang . $ext);
+            @copy($homep.$my_file.$ext, $homep.$my_file.'_'.$lang.$ext);
         }
     }
 }
@@ -224,8 +224,8 @@ if (!empty($action)) {
                 // Write
                 if (is_writable($homep)) {
                     // Default
-                    if (is_writable($homep . $topf . '_' . $lang . $ext)) {
-                        $fp = fopen($homep . $topf . '_' . $lang . $ext, 'w');
+                    if (is_writable($homep.$topf.'_'.$lang.$ext)) {
+                        $fp = fopen($homep.$topf.'_'.$lang.$ext, 'w');
                         fputs($fp, $home_top);
                         fclose($fp);
 
@@ -233,7 +233,7 @@ if (!empty($action)) {
                         foreach ($_languages['name'] as $key => $value) {
                             $lang_name = $_languages['folder'][$key];
                             if (isset($_POST[$lang_name])) {
-                                $fp = fopen($homep . $topf . '_' . $lang_name . $ext, 'w');
+                                $fp = fopen($homep.$topf.'_'.$lang_name.$ext, 'w');
                                 fputs($fp, $home_top);
                                 fclose($fp);
                             }
@@ -243,15 +243,15 @@ if (!empty($action)) {
                     }
                 } else {
                     //File does not exist
-                    $fp = fopen($homep . $topf . '_' . $lang . $ext, 'w');
+                    $fp = fopen($homep.$topf.'_'.$lang.$ext, 'w');
                     fputs($fp, $home_top);
                     fclose($fp);
 
                     foreach ($_languages['name'] as $key => $value) {
                         $lang_name = $_languages['folder'][$key];
                         if (isset($_POST[$lang_name])) {
-                            if (file_exists($homep . $topf . '_' . $lang_name . $ext)) {
-                                $fp = fopen($homep . $topf . '_' . $lang_name . $ext, 'w');
+                            if (file_exists($homep.$topf.'_'.$lang_name.$ext)) {
+                                $fp = fopen($homep.$topf.'_'.$lang_name.$ext, 'w');
                                 fputs($fp, $home_top);
                                 fclose($fp);
                             }
@@ -278,18 +278,18 @@ if (!empty($action)) {
                     $errorMsg = get_lang('NoticeWillBeNotDisplayed');
                 }
                 // Write
-                if (file_exists($homep . $noticef . '_' . $lang . $ext)) {
-                    if (is_writable($homep . $noticef . '_' . $lang . $ext)) {
-                        $fp = fopen($homep . $noticef . '_' . $lang . $ext, 'w');
+                if (file_exists($homep.$noticef.'_'.$lang.$ext)) {
+                    if (is_writable($homep.$noticef.'_'.$lang.$ext)) {
+                        $fp = fopen($homep.$noticef.'_'.$lang.$ext, 'w');
                         if ($errorMsg == '') {
                             fputs($fp, "<h5>$notice_title</h5><p>\n$notice_text");
 
                             foreach ($_languages['name'] as $key => $value) {
                                 $lang_name = $_languages['folder'][$key];
                                 if (isset($_POST[$lang_name])) {
-                                    if (file_exists($homep . $noticef . '_' . $lang_name . $ext)) {
-                                        if (is_writable($homep . $noticef . '_' . $lang_name . $ext)) {
-                                            $fp = fopen($homep . $noticef . '_' . $lang_name . $ext, 'w');
+                                    if (file_exists($homep.$noticef.'_'.$lang_name.$ext)) {
+                                        if (is_writable($homep.$noticef.'_'.$lang_name.$ext)) {
+                                            $fp = fopen($homep.$noticef.'_'.$lang_name.$ext, 'w');
                                             fputs($fp, "<h5>$notice_title</h5><p>\n$notice_text");
                                             fclose($fp);
                                         }
@@ -302,8 +302,8 @@ if (!empty($action)) {
                             foreach ($_languages['name'] as $key => $value) {
                                 $lang_name = $_languages['folder'][$key];
                                 if (isset($_POST[$lang_name])) {
-                                    if (file_exists($homep . $noticef . '_' . $lang_name . $ext)) {
-                                        $fp1 = fopen($homep . $noticef . '_' . $lang_name . $ext, 'w');
+                                    if (file_exists($homep.$noticef.'_'.$lang_name.$ext)) {
+                                        $fp1 = fopen($homep.$noticef.'_'.$lang_name.$ext, 'w');
                                         fputs($fp1, '');
                                         fclose($fp1);
                                     }
@@ -312,11 +312,11 @@ if (!empty($action)) {
                         }
                         fclose($fp);
                     } else {
-                        $errorMsg .= "<br/>\n" . get_lang('HomePageFilesNotWritable');
+                        $errorMsg .= "<br/>\n".get_lang('HomePageFilesNotWritable');
                     }
                 } else {
                     //File does not exist
-                    $fp = fopen($homep . $noticef . '_' . $lang . $ext, 'w');
+                    $fp = fopen($homep.$noticef.'_'.$lang.$ext, 'w');
                     fputs($fp, "<h5>$notice_title</h5><p>\n$notice_text");
                     fclose($fp);
                 }
@@ -334,9 +334,9 @@ if (!empty($action)) {
 
                 //Write
                 if ($s_languages_news != 'all') {
-                    if (file_exists($homep . $newsf . '_' . $s_languages_news . $ext)) {
-                        if (is_writable($homep . $newsf . '_' . $s_languages_news . $ext)) {
-                            $fp = fopen($homep . $newsf . '_' . $s_languages_news . $ext, 'w');
+                    if (file_exists($homep.$newsf.'_'.$s_languages_news.$ext)) {
+                        if (is_writable($homep.$newsf.'_'.$s_languages_news.$ext)) {
+                            $fp = fopen($homep.$newsf.'_'.$s_languages_news.$ext, 'w');
                             fputs($fp, $home_news);
                             fclose($fp);
                         } else {
@@ -344,7 +344,7 @@ if (!empty($action)) {
                         }
                     } else {
                         // File does not exist
-                        $fp = fopen($homep . $newsf . '_' . $s_languages_news . $ext, 'w');
+                        $fp = fopen($homep.$newsf.'_'.$s_languages_news.$ext, 'w');
                         fputs($fp, $home_news);
                         fclose($fp);
                     }
@@ -352,9 +352,9 @@ if (!empty($action)) {
                     // We update all the news file
                     foreach ($_languages['name'] as $key => $value) {
                         $english_name = $_languages['folder'][$key];
-                        if (file_exists($homep . $newsf . '_' . $english_name . $ext)) {
-                            if (is_writable($homep . $newsf . '_' . $english_name . $ext)) {
-                                $fp = fopen($homep . $newsf . '_' . $english_name . $ext, 'w');
+                        if (file_exists($homep.$newsf.'_'.$english_name.$ext)) {
+                            if (is_writable($homep.$newsf.'_'.$english_name.$ext)) {
+                                $fp = fopen($homep.$newsf.'_'.$english_name.$ext, 'w');
                                 fputs($fp, $home_news);
                                 fclose($fp);
                             } else {
@@ -362,7 +362,7 @@ if (!empty($action)) {
                             }
                         } else {
                             // File does not exist
-                            $fp = fopen($homep . $newsf . '_' . $english_name . $ext, 'w');
+                            $fp = fopen($homep.$newsf.'_'.$english_name.$ext, 'w');
                             fputs($fp, $home_news);
                             fclose($fp);
                         }
@@ -392,18 +392,18 @@ if (!empty($action)) {
                 if ($link_url == 'http://' || $link_url == 'https://') {
                     $link_url = '';
                 } elseif (!empty($link_url) && !strstr($link_url, '://')) {
-                    $link_url = 'http://' . $link_url;
+                    $link_url = 'http://'.$link_url;
                 }
                 $menuf = ($action == 'insert_tabs' || $action == 'edit_tabs') ? $mtloggedin : $menuf;
 
-                if (!is_writable($homep . $menuf . '_' . $lang . $ext)) {
+                if (!is_writable($homep.$menuf.'_'.$lang.$ext)) {
                     $errorMsg = get_lang('HomePageFilesNotWritable');
                 } elseif (empty($link_name)) {
                     $errorMsg = get_lang('PleaseEnterLinkName');
                 } else {
                     // New links are added as new files in the home/ directory
                     if ($action == 'insert_link' || $action == 'insert_tabs' || empty($filename) || strstr($filename, '/') || !strstr($filename, '.html')) {
-                        $filename = api_replace_dangerous_char($link_name) . '.html';
+                        $filename = api_replace_dangerous_char($link_name).'.html';
                     }
 
                     // "home_" prefix for links are renamed to "user_" prefix (to avoid name clash with existing home page files)
@@ -412,12 +412,12 @@ if (!empty($action)) {
                     }
                     // If the typical language suffix is not found in the file name,
                     // replace the ".html" suffix by "_en.html" or the active menu language
-                    if (!strstr($filename, '_' . $lang . $ext)) {
-                        $filename = str_replace($ext, '_' . $lang . $ext, $filename);
+                    if (!strstr($filename, '_'.$lang.$ext)) {
+                        $filename = str_replace($ext, '_'.$lang.$ext, $filename);
                     }
                     // Get the contents of home_menu_en.html (or active menu language
                     // version) into $home_menu as an array of one entry per line
-                    $home_menu = file($homep . $menuf . '_' . $lang . $ext);
+                    $home_menu = file($homep.$menuf.'_'.$lang.$ext);
                     $home_menu = implode("\n", $home_menu);
                     $home_menu = api_to_system_encoding($home_menu, api_detect_encoding(strip_tags($home_menu)));
                     $home_menu = explode("\n", $home_menu);
@@ -435,18 +435,18 @@ if (!empty($action)) {
                     // If the given link url is empty, then replace the link url by a link to the link file created
 
                     if (empty($link_url) || $link_url == 'http://' || $link_url == 'https://') {
-                        $link_url = api_get_path(WEB_PATH) . 'index.php?include=' . urlencode($filename);
+                        $link_url = api_get_path(WEB_PATH).'index.php?include='.urlencode($filename);
                         // If the file doesn't exist, then create it and
                         // fill it with default text
 
-                        $fp = @fopen($homep . $filename, 'w');
+                        $fp = @fopen($homep.$filename, 'w');
                         if ($fp) {
                             if (empty($link_html)) {
                                 fputs($fp, get_lang('MyTextHere'));
-                                home_tabs($homep . $filename);
+                                home_tabs($homep.$filename);
                             } else {
                                 fputs($fp, $link_html);
-                                home_tabs($homep . $filename);
+                                home_tabs($homep.$filename);
                             }
                             fclose($fp);
                         }
@@ -454,10 +454,10 @@ if (!empty($action)) {
                     // If the requested action is to edit a link, open the file and
                     // write to it (if the file doesn't exist, create it)
                     if (in_array($action, array('edit_link')) && !empty($link_html)) {
-                        $fp = @fopen($homep . $filename, 'w');
+                        $fp = @fopen($homep.$filename, 'w');
                         if ($fp) {
                             fputs($fp, $link_html);
-                            home_tabs($homep . $filename);
+                            home_tabs($homep.$filename);
                             fclose($fp);
                         }
                     }
@@ -480,36 +480,36 @@ if (!empty($action)) {
                                 break;
                             }
                         }
-                        $home_menu[$insert_where + 1] = '<li ' . $class_add_in_tab . '><a href="' . $link_url . '" target="' . ($target_blank ? '_blank' : '_self') . '">' . $link_name . '</a></li>';
+                        $home_menu[$insert_where + 1] = '<li '.$class_add_in_tab.'><a href="'.$link_url.'" target="'.($target_blank ? '_blank' : '_self').'">'.$link_name.'</a></li>';
                     } else {
                         // If the request is about a link edition, change the link
-                        $home_menu[$link_index] = '<li ' . $class_add_in_tab . '><a href="' . $link_url . '" target="' . ($target_blank ? '_blank' : '_self') . '">' . $link_name . '</a></li>';
+                        $home_menu[$link_index] = '<li '.$class_add_in_tab.'><a href="'.$link_url.'" target="'.($target_blank ? '_blank' : '_self').'">'.$link_name.'</a></li>';
                     }
                     // Re-build the file from the home_menu array
                     $home_menu = implode("\n", $home_menu);
                     // Write
-                    if (file_exists($homep . $menuf . '_' . $lang . $ext)) {
-                        if (is_writable($homep . $menuf . '_' . $lang . $ext)) {
-                            $fp = fopen($homep . $menuf . '_' . $lang . $ext, 'w');
+                    if (file_exists($homep.$menuf.'_'.$lang.$ext)) {
+                        if (is_writable($homep.$menuf.'_'.$lang.$ext)) {
+                            $fp = fopen($homep.$menuf.'_'.$lang.$ext, 'w');
                             fputs($fp, $home_menu);
-                            home_tabs($homep . $menuf . '_' . $lang . $ext);
+                            home_tabs($homep.$menuf.'_'.$lang.$ext);
                             fclose($fp);
 
                             foreach ($_languages['name'] as $key => $value) {
                                 $lang_name = $_languages['folder'][$key];
                                 if (isset($_POST[$lang_name])) {
-                                    $fp = fopen($homep . $menuf . '_' . $lang_name . $ext, 'w');
+                                    $fp = fopen($homep.$menuf.'_'.$lang_name.$ext, 'w');
                                     fputs($fp, $home_menu);
-                                    home_tabs($homep . $menuf . '_' . $lang_name . $ext);
+                                    home_tabs($homep.$menuf.'_'.$lang_name.$ext);
                                     fclose($fp);
                                 }
                             }
 
-                            if (file_exists($homep . $menuf . $ext)) {
-                                if (is_writable($homep . $menuf . $ext)) {
-                                    $fpo = fopen($homep . $menuf . $ext, 'w');
+                            if (file_exists($homep.$menuf.$ext)) {
+                                if (is_writable($homep.$menuf.$ext)) {
+                                    $fpo = fopen($homep.$menuf.$ext, 'w');
                                     fputs($fpo, $home_menu);
-                                    home_tabs($homep . $menuf . $ext);
+                                    home_tabs($homep.$menuf.$ext);
                                     fclose($fpo);
                                 }
                             }
@@ -518,17 +518,17 @@ if (!empty($action)) {
                         }
                     } else {
                         //File does not exist
-                        $fp = fopen($homep . $menuf . '_' . $lang . $ext, 'w');
+                        $fp = fopen($homep.$menuf.'_'.$lang.$ext, 'w');
                         fputs($fp, $home_menu);
-                        home_tabs($homep . $menuf . '_' . $lang . $ext);
+                        home_tabs($homep.$menuf.'_'.$lang.$ext);
                         fclose($fp);
 
                         foreach ($_languages['name'] as $key => $value) {
                             $lang_name = $_languages['folder'][$key];
                             if (isset($_POST[$lang_name])) {
-                                $fp = fopen($homep . $menuf . '_' . $lang_name . $ext, 'w');
+                                $fp = fopen($homep.$menuf.'_'.$lang_name.$ext, 'w');
                                 fputs($fp, $home_menu);
-                                home_tabs($homep . $menuf . '_' . $lang_name . $ext);
+                                home_tabs($homep.$menuf.'_'.$lang_name.$ext);
                                 fclose($fp);
                             }
                         }
@@ -537,7 +537,7 @@ if (!empty($action)) {
                 Event::addEvent(
                     LOG_HOMEPAGE_CHANGED,
                     $action,
-                    cut($link_name . ':' . $link_url, 254),
+                    cut($link_name.':'.$link_url, 254),
                     api_get_utc_datetime(),
                     api_get_user_id()
                 );
@@ -545,7 +545,7 @@ if (!empty($action)) {
         } //end of switch($action)
 
         if (empty($errorMsg)) {
-            header('Location: ' . $selfUrl . '?language=' . $languageGet);
+            header('Location: '.$selfUrl.'?language='.$languageGet);
             exit();
         }
     } else {
@@ -561,7 +561,7 @@ if (!empty($action)) {
                 // link and re-writing the array to the file
                 $link_index = intval($_GET['link_index']);
                 $menuf = ($action == 'delete_tabs') ? $mtloggedin : $menuf;
-                $home_menu = @file($homep . $menuf . '_' . $lang . $ext);
+                $home_menu = @file($homep.$menuf.'_'.$lang.$ext);
                 if (empty($home_menu)) {
                     $home_menu = array();
                 }
@@ -575,28 +575,28 @@ if (!empty($action)) {
                 $home_menu = implode("\n", $home_menu);
                 $home_menu = api_to_system_encoding($home_menu, api_detect_encoding(strip_tags($home_menu)));
 
-                $fp = fopen($homep . $menuf . '_' . $lang . $ext, 'w');
+                $fp = fopen($homep.$menuf.'_'.$lang.$ext, 'w');
                 fputs($fp, $home_menu);
-                home_tabs($homep . $menuf . '_' . $lang . $ext);
+                home_tabs($homep.$menuf.'_'.$lang.$ext);
                 fclose($fp);
-                if (file_exists($homep . $menuf . $ext)) {
-                    if (is_writable($homep . $menuf . $ext)) {
-                        $fpo = fopen($homep . $menuf . $ext, 'w');
+                if (file_exists($homep.$menuf.$ext)) {
+                    if (is_writable($homep.$menuf.$ext)) {
+                        $fpo = fopen($homep.$menuf.$ext, 'w');
                         fputs($fpo, $home_menu);
-                        home_tabs($homep . $menuf . $ext);
+                        home_tabs($homep.$menuf.$ext);
                         fclose($fpo);
                     }
                 }
-                header('Location: ' . $selfUrl);
+                header('Location: '.$selfUrl);
                 exit();
                 break;
             case 'edit_top':
                 // This request is only the preparation for the update of the home_top
                 $home_top = '';
-                if (is_file($homep . $topf . '_' . $lang . $ext) && is_readable($homep . $topf . '_' . $lang . $ext)) {
-                    $home_top = @(string)file_get_contents($homep . $topf . '_' . $lang . $ext);
-                } elseif (is_file($homep . $topf . $lang . $ext) && is_readable($homep . $topf . $lang . $ext)) {
-                    $home_top = @(string)file_get_contents($homep . $topf . $lang . $ext);
+                if (is_file($homep.$topf.'_'.$lang.$ext) && is_readable($homep.$topf.'_'.$lang.$ext)) {
+                    $home_top = @(string) file_get_contents($homep.$topf.'_'.$lang.$ext);
+                } elseif (is_file($homep.$topf.$lang.$ext) && is_readable($homep.$topf.$lang.$ext)) {
+                    $home_top = @(string) file_get_contents($homep.$topf.$lang.$ext);
                 } else {
                     $errorMsg = get_lang('HomePageFilesNotReadable');
                 }
@@ -605,10 +605,10 @@ if (!empty($action)) {
             case 'edit_notice':
                 // This request is only the preparation for the update of the home_notice
                 $home_notice = '';
-                if (is_file($homep . $noticef . '_' . $lang . $ext) && is_readable($homep . $noticef . '_' . $lang . $ext)) {
-                    $home_notice = @file($homep . $noticef . '_' . $lang . $ext);
-                } elseif (is_file($homep . $noticef . $lang . $ext) && is_readable($homep . $noticef . $lang . $ext)) {
-                    $home_notice = @file($homep . $noticef . $lang . $ext);
+                if (is_file($homep.$noticef.'_'.$lang.$ext) && is_readable($homep.$noticef.'_'.$lang.$ext)) {
+                    $home_notice = @file($homep.$noticef.'_'.$lang.$ext);
+                } elseif (is_file($homep.$noticef.$lang.$ext) && is_readable($homep.$noticef.$lang.$ext)) {
+                    $home_notice = @file($homep.$noticef.$lang.$ext);
                 } else {
                     $errorMsg = get_lang('HomePageFilesNotReadable');
                 }
@@ -623,10 +623,10 @@ if (!empty($action)) {
             case 'edit_news':
                 // This request is the preparation for the update of the home_news page
                 $home_news = '';
-                if (is_file($homep . $newsf . '_' . $lang . $ext) && is_readable($homep . $newsf . '_' . $lang . $ext)) {
-                    $home_news = @(string)file_get_contents($homep . $newsf . '_' . $lang . $ext);
-                } elseif (is_file($homep . $newsf . $lang . $ext) && is_readable($homep . $newsf . $lang . $ext)) {
-                    $home_news = @(string)file_get_contents($homep . $newsf . $lang . $ext);
+                if (is_file($homep.$newsf.'_'.$lang.$ext) && is_readable($homep.$newsf.'_'.$lang.$ext)) {
+                    $home_news = @(string) file_get_contents($homep.$newsf.'_'.$lang.$ext);
+                } elseif (is_file($homep.$newsf.$lang.$ext) && is_readable($homep.$newsf.$lang.$ext)) {
+                    $home_news = @(string) file_get_contents($homep.$newsf.$lang.$ext);
                 } else {
                     $errorMsg = get_lang('HomePageFilesNotReadable');
                 }
@@ -636,10 +636,10 @@ if (!empty($action)) {
                 // This request is the preparation for the addition of an item in home_menu
                 $home_menu = '';
                 $menuf = ($action == 'edit_tabs') ? $mtloggedin : $menuf;
-                if (is_file($homep . $menuf . '_' . $lang . $ext) && is_readable($homep . $menuf . '_' . $lang . $ext)) {
-                    $home_menu = @file($homep . $menuf . '_' . $lang . $ext);
-                } elseif (is_file($homep . $menuf . $lang . $ext) && is_readable($homep . $menuf . $lang . $ext)) {
-                    $home_menu = @file($homep . $menuf . $lang . $ext);
+                if (is_file($homep.$menuf.'_'.$lang.$ext) && is_readable($homep.$menuf.'_'.$lang.$ext)) {
+                    $home_menu = @file($homep.$menuf.'_'.$lang.$ext);
+                } elseif (is_file($homep.$menuf.$lang.$ext) && is_readable($homep.$menuf.$lang.$ext)) {
+                    $home_menu = @file($homep.$menuf.$lang.$ext);
                 } else {
                     $errorMsg = get_lang('HomePageFilesNotReadable');
                 }
@@ -656,12 +656,12 @@ if (!empty($action)) {
             case 'insert_tabs':
                 // This request is the preparation for the addition of an item in home_menu
                 $home_menu = '';
-                if (is_file($homep . $mtloggedin . '_' . $lang . $ext) && is_readable($homep . $mtloggedin . '_' . $lang . $ext)) {
-                    $home_menu = @file($homep . $mtloggedin . '_' . $lang . $ext);
-                } elseif (is_file($homep . $mtloggedin . $lang . $ext) && is_readable($homep . $mtloggedin . $lang . $ext)) {
-                    $home_menu = @file($homep . $mtloggedin . $lang . $ext);
-                } elseif (touch($homep . $mtloggedin . '_' . $lang . $ext)) {
-                    $home_menu = @file($homep . $mtloggedin . '_' . $lang . $ext);
+                if (is_file($homep.$mtloggedin.'_'.$lang.$ext) && is_readable($homep.$mtloggedin.'_'.$lang.$ext)) {
+                    $home_menu = @file($homep.$mtloggedin.'_'.$lang.$ext);
+                } elseif (is_file($homep.$mtloggedin.$lang.$ext) && is_readable($homep.$mtloggedin.$lang.$ext)) {
+                    $home_menu = @file($homep.$mtloggedin.$lang.$ext);
+                } elseif (touch($homep.$mtloggedin.'_'.$lang.$ext)) {
+                    $home_menu = @file($homep.$mtloggedin.'_'.$lang.$ext);
                 } else {
                     $errorMsg = get_lang('HomePageFilesNotReadable');
                 }
@@ -680,17 +680,17 @@ if (!empty($action)) {
                 // This request is the preparation for the edition of the links array
                 $home_menu = '';
                 $menuf = ($action == 'edit_tabs') ? $mtloggedin : $menuf;
-                if (is_file($homep . $menuf . '_' . $lang . $ext) && is_readable($homep . $menuf . '_' . $lang . $ext)) {
-                    $home_menu = @file($homep . $menuf . '_' . $lang . $ext);
-                } elseif (is_file($homep . $menuf . $lang . $ext) && is_readable($homep . $menuf . $lang . $ext)) {
-                    $home_menu = @file($homep . $menuf . $lang . $ext);
+                if (is_file($homep.$menuf.'_'.$lang.$ext) && is_readable($homep.$menuf.'_'.$lang.$ext)) {
+                    $home_menu = @file($homep.$menuf.'_'.$lang.$ext);
+                } elseif (is_file($homep.$menuf.$lang.$ext) && is_readable($homep.$menuf.$lang.$ext)) {
+                    $home_menu = @file($homep.$menuf.$lang.$ext);
                 } else {
                     $errorMsg = get_lang('HomePageFilesNotReadable');
                 }
 
                 if (empty($home_menu)) {
-                    if (file_exists($homep . $menutabs . '_' . $lang . $ext)) {
-                        $home_menu = @file($homep . $menutabs . '_' . $lang . $ext);
+                    if (file_exists($homep.$menutabs.'_'.$lang.$ext)) {
+                        $home_menu = @file($homep.$menutabs.'_'.$lang.$ext);
                     }
                 }
 
@@ -757,7 +757,7 @@ if (!empty($action)) {
 
                             if (!strstr($filename, '/') && strstr($filename, '.html')) {
                                 // Get oonly the contents of the link file
-                                $link_html = @file($homep . $filename);
+                                $link_html = @file($homep.$filename);
                                 $link_html = implode('', $link_html);
                                 $link_url = '';
                             } else {
@@ -783,7 +783,7 @@ switch ($action) {
     case 'open_link':
         if (!empty($link)) {
             // $link is only set in case of action=open_link and is filtered
-            $open = @(string)file_get_contents($homep . $link);
+            $open = @(string) file_get_contents($homep.$link);
             $open = api_to_system_encoding($open, api_detect_encoding(strip_tags($open)));
             echo $open;
         }
@@ -796,7 +796,7 @@ switch ($action) {
             <input type="hidden" name="formSent" value="1"/>
             <?php
             if (!empty($errorMsg)) {
-                Display::addFlash(Display::return_message($errorMsg, 'normal'));
+                echo Display::return_message($errorMsg, 'normal');
             }
             ?>
             <div class="row">
@@ -847,11 +847,11 @@ switch ($action) {
     case 'edit_link':
         $menuf = ($action == 'insert_tabs' || $action == 'edit_tabs') ? $mtloggedin : $menuf;
         if (!empty($errorMsg)) {
-            Display::addFlash(Display::return_message($errorMsg, 'normal'));
+            echo Display::return_message($errorMsg, 'normal');
         }
         $default = array();
-        $form = new FormValidator('configure_homepage_' . $action, 'post', $selfUrl . '?action=' . $action, '', array('style' => 'margin: 0px;'));
-        $renderer =& $form->defaultRenderer();
+        $form = new FormValidator('configure_homepage_'.$action, 'post', $selfUrl.'?action='.$action, '', array('style' => 'margin: 0px;'));
+        $renderer = & $form->defaultRenderer();
 
         $form->addElement('header', '', $tool_name);
         $form->addElement('hidden', 'formSent', '1');
@@ -863,7 +863,7 @@ switch ($action) {
             $default['link_name'] = $link_name;
         }
         $default['link_url'] = empty($link_url) ? 'http://' : api_htmlentities($link_url, ENT_QUOTES);
-        $linkUrlComment = ($action == 'insert_tabs') ? get_lang('Optional') . '<br />' . get_lang('GlobalLinkUseDoubleColumnPrivateToShowPrivately') : '';
+        $linkUrlComment = ($action == 'insert_tabs') ? get_lang('Optional').'<br />'.get_lang('GlobalLinkUseDoubleColumnPrivateToShowPrivately') : '';
         $form->addElement('text', 'link_url', array(get_lang('LinkURL'), $linkUrlComment), array('size' => '30', 'maxlength' => '100', 'style' => 'width: 350px;'));
 
         $options = array('-1' => get_lang('FirstPlace'));
@@ -875,7 +875,7 @@ switch ($action) {
             if (is_array($home_menu)) {
                 foreach ($home_menu as $key => $enreg) {
                     if (strlen($enreg = trim(strip_tags($enreg))) > 0) {
-                        $options[$key] = get_lang('After') . ' &quot;' . $enreg . '&quot;';
+                        $options[$key] = get_lang('After').' &quot;'.$enreg.'&quot;';
                         $formSentCheck = (!empty($_POST['formSent']) ? true : false);
                         $selected = $formSentCheck && $insert_where == $key ? $key : '';
                     }
@@ -913,7 +913,7 @@ switch ($action) {
                 $i++;
                 $lang_name = $_languages['folder'][$key];
                 $html_langs = '<td width="300">';
-                $html_langs .= '<label><input type="checkbox" id="lang" name="' . $lang_name . '" />&nbsp;' . $lang_name . '<label/>';
+                $html_langs .= '<label><input type="checkbox" id="lang" name="'.$lang_name.'" />&nbsp;'.$lang_name.'<label/>';
                 $html_langs .= '</td>';
                 if ($i % 5 == 0) {
                     $html_langs .= '</tr><tr>';
@@ -935,23 +935,23 @@ switch ($action) {
             $open = $home_top;
         } else {
             $name = $newsf;
-            $open = @(string)file_get_contents($homep . $newsf . '_' . $lang . $ext);
+            $open = @(string) file_get_contents($homep.$newsf.'_'.$lang.$ext);
         }
         $open = api_to_system_encoding($open, api_detect_encoding(strip_tags($open)));
 
         if (!empty($errorMsg)) {
-            Display::addFlash(Display::return_message($errorMsg, 'normal')); //main API
+            echo Display::return_message($errorMsg, 'normal'); //main API
         }
 
         $default = array();
         $form = new FormValidator(
-            'configure_homepage_' . $action,
+            'configure_homepage_'.$action,
             'post',
-            $selfUrl . '?action=' . $action,
+            $selfUrl.'?action='.$action,
             '',
             array('style' => 'margin: 0px;')
         );
-        $renderer =& $form->defaultRenderer();
+        $renderer = & $form->defaultRenderer();
         $renderer->setHeaderTemplate('');
         $renderer->setFormTemplate('<form{attributes}><table border="0" cellpadding="5" cellspacing="0" width="100%">{content}</table></form>');
         $renderer->setCustomElementTemplate('<tr><td>{element}</td></tr>');
@@ -960,15 +960,15 @@ switch ($action) {
 
         if ($action == 'edit_news') {
             $_languages = api_get_languages();
-            $html = '<tr><td>' . get_lang('ChooseNewsLanguage') . ' : ';
+            $html = '<tr><td>'.get_lang('ChooseNewsLanguage').' : ';
             $html .= '<select name="news_languages">';
-            $html .= '<option value="all">' . get_lang('ApplyAllLanguages') . '</option>';
+            $html .= '<option value="all">'.get_lang('ApplyAllLanguages').'</option>';
             foreach ($_languages['name'] as $key => $value) {
                 $english_name = $_languages['folder'][$key];
                 if ($language == $english_name) {
-                    $html .= '<option value="' . $english_name . '" selected="selected">' . $value . '</option>';
+                    $html .= '<option value="'.$english_name.'" selected="selected">'.$value.'</option>';
                 } else {
-                    $html .= '<option value="' . $english_name . '">' . $value . '</option>';
+                    $html .= '<option value="'.$english_name.'">'.$value.'</option>';
                 }
             }
             $html .= '</select></td></tr>';
@@ -991,7 +991,7 @@ switch ($action) {
                 $checked = "checked";
             }
             $html_langs = '<td width="300">';
-            $html_langs .= '<label><input type="checkbox" ' . $checked . ' id="lang" name="' . $lang_name . '" />&nbsp;' . $value . '<label/>';
+            $html_langs .= '<label><input type="checkbox" '.$checked.' id="lang" name="'.$lang_name.'" />&nbsp;'.$value.'<label/>';
             $html_langs .= '</td>';
             if ($i % 5 == 0) {
                 $html_langs .= '</tr><tr>';
@@ -1056,10 +1056,10 @@ switch ($action) {
                                 <div class="panel-body">
                                     <?php
                                     $home_notice = '';
-                                    if (file_exists($homep . $noticef . '_' . $lang . $ext)) {
-                                        $home_notice = @(string)file_get_contents($homep . $noticef . '_' . $lang . $ext);
+                                    if (file_exists($homep.$noticef.'_'.$lang.$ext)) {
+                                        $home_notice = @(string) file_get_contents($homep.$noticef.'_'.$lang.$ext);
                                     } else {
-                                        $home_notice = @(string)file_get_contents($homep . $noticef . $ext);
+                                        $home_notice = @(string) file_get_contents($homep.$noticef.$ext);
                                     }
                                     $home_notice = api_to_system_encoding($home_notice, api_detect_encoding(strip_tags($home_notice)));
                                     echo '<div class="homepage_notice">';
@@ -1086,15 +1086,15 @@ switch ($action) {
                             <div id="links-list" class="panel-collapse collapse in" role="tabpanel"
                                  aria-labelledby="headingOne">
                                 <div class="panel-body">
-                                    <a href="<?php echo $selfUrl; ?>?action=insert_link"><?php echo Display::return_icon('add.png', get_lang('InsertLink')) . '&nbsp;' . get_lang('InsertLink'); ?>
+                                    <a href="<?php echo $selfUrl; ?>?action=insert_link"><?php echo Display::return_icon('add.png', get_lang('InsertLink')).'&nbsp;'.get_lang('InsertLink'); ?>
                                     </a>
                                     <ul class="menulist">
                                         <?php
                                         $home_menu = '';
-                                        if (file_exists($homep . $menuf . '_' . $lang . $ext)) {
-                                            $home_menu = @file($homep . $menuf . '_' . $lang . $ext);
+                                        if (file_exists($homep.$menuf.'_'.$lang.$ext)) {
+                                            $home_menu = @file($homep.$menuf.'_'.$lang.$ext);
                                         } else {
-                                            $home_menu = @file($homep . $menuf . $ext);
+                                            $home_menu = @file($homep.$menuf.$ext);
                                         }
                                         if (empty($home_menu)) {
                                             $home_menu = array();
@@ -1108,9 +1108,9 @@ switch ($action) {
                                         foreach ($home_menu as $enreg) {
                                             $enreg = trim($enreg);
                                             if (!empty($enreg)) {
-                                                $edit_link = '<a href="' . $selfUrl . '?action=edit_link&amp;link_index=' . $i . '">' . Display::return_icon('edit.png', get_lang('Edit')) . '</a>';
-                                                $delete_link = '<a href="' . $selfUrl . '?action=delete_link&amp;link_index=' . $i . '" onclick="javascript:if(!confirm(\'' . addslashes(api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES)) . '\')) return false;">' . Display::return_icon('delete.png', get_lang('Delete')) . '</a>';
-                                                echo str_replace(array('href="' . api_get_path(WEB_PATH) . 'index.php?include=', '</li>'), array('href="' . api_get_path(WEB_CODE_PATH) . 'admin/' . basename($selfUrl) . '?action=open_link&link=', $edit_link . ' ' . $delete_link . '</li>'), $enreg);
+                                                $edit_link = '<a href="'.$selfUrl.'?action=edit_link&amp;link_index='.$i.'">'.Display::return_icon('edit.png', get_lang('Edit')).'</a>';
+                                                $delete_link = '<a href="'.$selfUrl.'?action=delete_link&amp;link_index='.$i.'" onclick="javascript:if(!confirm(\''.addslashes(api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES)).'\')) return false;">'.Display::return_icon('delete.png', get_lang('Delete')).'</a>';
+                                                echo str_replace(array('href="'.api_get_path(WEB_PATH).'index.php?include=', '</li>'), array('href="'.api_get_path(WEB_CODE_PATH).'admin/'.basename($selfUrl).'?action=open_link&link=', $edit_link.' '.$delete_link.'</li>'), $enreg);
                                                 $i++;
                                             }
                                         }
@@ -1125,16 +1125,16 @@ switch ($action) {
                 <div class="col-md-9">
                     <div class="actions">
                         <a href="<?php echo $selfUrl; ?>?action=edit_top&language=<?php echo $languageGet; ?>">
-                            <?php echo Display::return_icon('edit.png', get_lang('EditHomePage'), null, ICON_SIZE_SMALL) . '&nbsp;' . get_lang('EditHomePage'); ?>
+                            <?php echo Display::return_icon('edit.png', get_lang('EditHomePage'), null, ICON_SIZE_SMALL).'&nbsp;'.get_lang('EditHomePage'); ?>
                         </a>
                     </div>
                     <section id="homepage-home">
                         <?php
                         //print home_top contents
-                        if (file_exists($homep . $topf . '_' . $lang . $ext)) {
-                            $home_top_temp = @(string)file_get_contents($homep . $topf . '_' . $lang . $ext);
+                        if (file_exists($homep.$topf.'_'.$lang.$ext)) {
+                            $home_top_temp = @(string) file_get_contents($homep.$topf.'_'.$lang.$ext);
                         } else {
-                            $home_top_temp = @(string)file_get_contents($homep . $topf . $ext);
+                            $home_top_temp = @(string) file_get_contents($homep.$topf.$ext);
                         }
                         $open = str_replace('{rel_path}', api_get_path(REL_PATH), $home_top_temp);
                         $open = api_to_system_encoding($open, api_detect_encoding(strip_tags($open)));
@@ -1151,14 +1151,14 @@ switch ($action) {
 
                     if ($access_url_id == 1) {
                         echo '<div class="actions">';
-                        echo '<a href="course_category.php">' . Display::return_icon('edit.png', get_lang('Edit')) . '&nbsp;' . get_lang('EditCategories') . '</a>';
+                        echo '<a href="course_category.php">'.Display::return_icon('edit.png', get_lang('Edit')).'&nbsp;'.get_lang('EditCategories').'</a>';
                         echo '</div>';
                     }
                     echo '<ul class="list-group">';
                     if ($access_url_id == 1) {
                         if (sizeof($Categories)) {
                             foreach ($Categories as $enreg) {
-                                echo '<li class="list-group-item">' . Display::return_icon('folder.png', $enreg['name']) . '&nbsp;' . $enreg['name'] . '</li>';
+                                echo '<li class="list-group-item">'.Display::return_icon('folder.png', $enreg['name']).'&nbsp;'.$enreg['name'].'</li>';
                             }
                             unset($Categories);
                         } else {
@@ -1169,12 +1169,12 @@ switch ($action) {
                     ?>
 
                     <?php
-                    if (file_exists($homep . $newsf . '_' . $lang . $ext)) {
-                        $open = @(string)file_get_contents($homep . $newsf . '_' . $lang . $ext);
+                    if (file_exists($homep.$newsf.'_'.$lang.$ext)) {
+                        $open = @(string) file_get_contents($homep.$newsf.'_'.$lang.$ext);
                         $open = api_to_system_encoding($open, api_detect_encoding(strip_tags($open)));
                         echo $open;
                     } else {
-                        $open = @(string)file_get_contents($homep . $newsf . $ext);
+                        $open = @(string) file_get_contents($homep.$newsf.$ext);
                         $open = api_to_system_encoding($open, api_detect_encoding(strip_tags($open)));
                         echo $open;
                     }
@@ -1183,14 +1183,14 @@ switch ($action) {
                     <?php
                     // Add new page
                     $home_menu = '';
-                    if (file_exists($homep . $mtloggedin . '_' . $lang . $ext)) {
-                        $home_menu = @file($homep . $mtloggedin . '_' . $lang . $ext);
+                    if (file_exists($homep.$mtloggedin.'_'.$lang.$ext)) {
+                        $home_menu = @file($homep.$mtloggedin.'_'.$lang.$ext);
                     } else {
-                        $home_menu = @file($homep . $mtloggedin . $ext);
+                        $home_menu = @file($homep.$mtloggedin.$ext);
                     }
                     if (empty($home_menu)) {
-                        if (file_exists($homep . $menutabs . '_' . $lang . $ext)) {
-                            $home_menu = @file($homep . $menutabs . '_' . $lang . $ext);
+                        if (file_exists($homep.$menutabs.'_'.$lang.$ext)) {
+                            $home_menu = @file($homep.$menutabs.'_'.$lang.$ext);
                         }
                     }
                     if (empty($home_menu)) {
@@ -1206,11 +1206,11 @@ switch ($action) {
                     foreach ($home_menu as $enreg) {
                         $enreg = trim($enreg);
                         if (!empty($enreg)) {
-                            $edit_link = ' <a href="' . $selfUrl . '?action=edit_tabs&amp;link_index=' . $tab_counter . '" ><span>' . Display::return_icon('edit.png', get_lang('Edit')) . '</span></a>';
-                            $delete_link = ' <a href="' . $selfUrl . '?action=delete_tabs&amp;link_index=' . $tab_counter . '"  onclick="javascript: if(!confirm(\'' . addslashes(api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES)) . '\')) return false;"><span>' . Display::return_icon('delete.png', get_lang('Delete')) . '</span></a>';
+                            $edit_link = ' <a href="'.$selfUrl.'?action=edit_tabs&amp;link_index='.$tab_counter.'" ><span>'.Display::return_icon('edit.png', get_lang('Edit')).'</span></a>';
+                            $delete_link = ' <a href="'.$selfUrl.'?action=delete_tabs&amp;link_index='.$tab_counter.'"  onclick="javascript: if(!confirm(\''.addslashes(api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES)).'\')) return false;"><span>'.Display::return_icon('delete.png', get_lang('Delete')).'</span></a>';
                             $tab_string = str_replace(
-                                array('href="' . api_get_path(WEB_PATH) . 'index.php?include=', '</li>'),
-                                array('href="' . api_get_path(WEB_CODE_PATH) . 'admin/' . basename($selfUrl) . '?action=open_link&link=', $edit_link . $delete_link . '</li>'),
+                                array('href="'.api_get_path(WEB_PATH).'index.php?include=', '</li>'),
+                                array('href="'.api_get_path(WEB_CODE_PATH).'admin/'.basename($selfUrl).'?action=open_link&link=', $edit_link.$delete_link.'</li>'),
                                 $enreg
                             );
                             $tab_string = str_replace([' class="hide_menu"', ' class="show_menu"'], '', $tab_string);
@@ -1222,7 +1222,7 @@ switch ($action) {
                     ?>
                     <div class="actions">
                         <a href="<?php echo $selfUrl; ?>?action=insert_tabs">
-                            <?php echo Display::return_icon('add.png', get_lang('InsertLink')) . '&nbsp;' . get_lang('InsertLink'); ?>
+                            <?php echo Display::return_icon('add.png', get_lang('InsertLink')).'&nbsp;'.get_lang('InsertLink'); ?>
                         </a>
                     </div>
                     <?php

+ 2 - 2
main/admin/configure_inscription.php

@@ -165,7 +165,7 @@ echo Display::page_header($tool_name);
 
 //api_display_tool_title($tool_name);
 if (api_get_setting('allow_registration') == 'approval') {
-    Display::addFlash(Display::return_message(get_lang('YourAccountHasToBeApproved'), 'normal'));
+    echo Display::return_message(get_lang('YourAccountHasToBeApproved'), 'normal');
 }
 //if openid was not found
 if (!empty($_GET['openid_msg']) && $_GET['openid_msg'] == 'idnotfound') {
@@ -364,7 +364,7 @@ switch ($action) {
         }
 
         if (!empty($errorMsg)) {
-            Display::addFlash(Display::return_message($errorMsg, 'normal'));
+            echo Display::return_message($errorMsg, 'normal');
         }
 
         $default = array();

+ 25 - 5
main/admin/course_add.php

@@ -42,7 +42,14 @@ $form = new FormValidator('update_course');
 $form->addElement('header', $tool_name);
 
 // Title
-$form->addText('title', get_lang('Title'), true);
+$form->addText(
+    'title',
+    get_lang('Title'),
+    true,
+    array(
+        'aria-label' => get_lang('Title')
+    )
+);
 $form->applyFilter('title', 'html_filter');
 $form->applyFilter('title', 'trim');
 
@@ -57,7 +64,8 @@ $form->addText(
     [
         'maxlength' => CourseManager::MAX_COURSE_LENGTH_CODE,
         'pattern' => '[a-zA-Z0-9]+',
-        'title' => get_lang('OnlyLettersAndNumbers')
+        'title' => get_lang('OnlyLettersAndNumbers'),
+        'id' => 'visual_code'
     ]
 );
 
@@ -92,12 +100,22 @@ $form->addElement(
 );
 
 // Course department
-$form->addText('department_name', get_lang('CourseDepartment'), false, array('size' => '60'));
+$form->addText(
+    'department_name',
+    get_lang('CourseDepartment'),
+    false,
+    array('size' => '60', 'id' => 'department_name')
+);
 $form->applyFilter('department_name', 'html_filter');
 $form->applyFilter('department_name', 'trim');
 
 // Department URL
-$form->addText('department_url', get_lang('CourseDepartmentURL'), false, array('size' => '60'));
+$form->addText(
+    'department_url',
+    get_lang('CourseDepartmentURL'),
+    false,
+    array('size' => '60', 'id' => 'department_url')
+);
 $form->applyFilter('department_url', 'html_filter');
 
 // Course language.
@@ -148,7 +166,9 @@ $group[] = $form->createElement('radio', 'unsubscribe', get_lang('Unsubscription
 $group[] = $form->createElement('radio', 'unsubscribe', null, get_lang('NotAllowedToUnsubscribe'), 0);
 $form->addGroup($group, '', get_lang('Unsubscription'));
 
-$form->addElement('text', 'disk_quota', array(get_lang('CourseQuota'), null, get_lang('MB')));
+$form->addElement('text', 'disk_quota', array(get_lang('CourseQuota'), null, get_lang('MB')), array(
+    'id' => 'disk_quota'
+));
 $form->addRule('disk_quota', get_lang('ThisFieldShouldBeNumeric'), 'numeric');
 
 $obj = new GradeModel();

+ 1 - 1
main/admin/course_import.php

@@ -139,7 +139,7 @@ function save_courses_data($courses)
     }
 
     if (!empty($msg)) {
-        Display::addFlash(Display::return_message($msg, 'normal', false));
+        echo Display::return_message($msg, 'normal', false);
     }
 }
 

+ 2 - 1
main/admin/course_intro_pdf_import.php

@@ -18,7 +18,6 @@ $errors = [];
 $interbreadcrumb[] = array('url' => 'index.php', 'name' => get_lang('PlatformAdmin'));
 
 set_time_limit(0);
-Display::display_header($tool_name);
 
 if ($_POST['formSent']) {
     if (empty($_FILES['import_file']['tmp_name'])) {
@@ -49,6 +48,8 @@ if (count($errors) != 0) {
 } elseif ($_POST['formSent']) {
     Display::addFlash(Display::return_message('CourseIntroductionsAllImportesSuccessfully', 'confirmation', false));
 }
+
+Display::display_header($tool_name);
 ?>
     <form method="post" action="<?php echo api_get_self(); ?>" enctype="multipart/form-data" style="margin: 0;">
         <h3><?php echo $tool_name; ?></h3>

+ 6 - 1
main/admin/course_list.php

@@ -358,7 +358,12 @@ if (isset($_GET['search']) && $_GET['search'] === 'advanced') {
         array(),
         FormValidator::LAYOUT_INLINE
     );
-    $form->addElement('text', 'keyword', null, array('id' => 'course-search-keyword'));
+    $form->addElement(
+        'text',
+        'keyword',
+        null,
+        array('id' => 'course-search-keyword', 'aria-label' => get_lang('SearchCourse'))
+    );
     $form->addButtonSearch(get_lang('SearchCourse'));
     $advanced = '<a class="btn btn-default" href="'.api_get_path(WEB_CODE_PATH).'admin/course_list.php?search=advanced"><em class="fa fa-search"></em> '.get_lang('AdvancedSearch').'</a>';
 

+ 3 - 2
main/admin/course_request_accepted.php

@@ -133,17 +133,18 @@ function modify_filter($id)
 $interbreadcrumb[] = array('url' => 'index.php', 'name' => get_lang('PlatformAdmin'));
 $interbreadcrumb[] = array('url' => 'course_list.php', 'name' => get_lang('CourseList'));
 $tool_name = get_lang('AcceptedCourseRequests');
-Display :: display_header($tool_name);
 
 // Display confirmation or error message.
 if (!empty($message)) {
     if ($is_error_message) {
-        Display::display_error_message($message, false);
+        Display::addFlash(Display::return_message($message, 'error', false));
     } else {
         Display::addFlash(Display::return_message($message, 'normal', false));
     }
 }
 
+Display :: display_header($tool_name);
+
 if (!$course_validation_feature) {
     Display :: display_footer();
     exit;

+ 2 - 1
main/admin/course_request_rejected.php

@@ -166,7 +166,6 @@ $interbreadcrumb[] = array('url' => 'index.php', 'name' => get_lang('PlatformAdm
 $interbreadcrumb[] = array('url' => 'course_list.php', 'name' => get_lang('CourseList'));
 
 $tool_name = get_lang('RejectedCourseRequests');
-Display :: display_header($tool_name);
 
 // Display confirmation or error message.
 if (!empty($message)) {
@@ -177,6 +176,8 @@ if (!empty($message)) {
     }
 }
 
+Display::display_header($tool_name);
+
 if (!$course_validation_feature) {
     Display :: display_footer();
     exit;

+ 2 - 1
main/admin/course_request_review.php

@@ -204,7 +204,6 @@ $interbreadcrumb[] = array('url' => 'index.php', 'name' => get_lang('PlatformAdm
 $interbreadcrumb[] = array('url' => 'course_list.php', 'name' => get_lang('CourseList'));
 
 $tool_name = get_lang('ReviewCourseRequests');
-Display :: display_header($tool_name);
 
 // Display confirmation or error message.
 if (!empty($message)) {
@@ -215,6 +214,8 @@ if (!empty($message)) {
     }
 }
 
+Display::display_header($tool_name);
+
 if (!$course_validation_feature) {
     Display :: display_footer();
     exit;

+ 1 - 1
main/admin/course_user_import.php

@@ -208,7 +208,7 @@ if (count($errors) != 0) {
         $error_message .= '</li>';
     }
     $error_message .= '</ul>';
-    Display :: display_error_message($error_message, false);
+    echo Display::return_message($error_message, 'error', false);
 }
 
 // Displaying the form.

+ 1 - 1
main/admin/dashboard_add_courses_to_user.php

@@ -223,7 +223,7 @@ $result = Database::query($sql);
 <input type="hidden" name="formSent" value="1" />
 <?php
 if (!empty($msg)) {
-	Display::addFlash(Display::return_message($msg, 'normal')); //main API
+	echo Display::return_message($msg, 'normal'); //main API
 }
 ?>
 

+ 1 - 1
main/admin/filler.php

@@ -58,7 +58,7 @@ if (count($output) > 0) {
     }
     $result .= '</table>';
     $result .= '</div>';
-    Display::addFlash(Display::return_message($result, 'normal', false));
+    echo Display::return_message($result, 'normal', false);
 }
 ?>
 <div id="datafiller" class="panel panel-default">

+ 3 - 3
main/admin/grade_models.php

@@ -151,7 +151,7 @@ switch ($action) {
                 $values = $form->exportValues();
                 $res    = $obj->save($values);
                 if ($res) {
-                    Display::display_confirmation_message(get_lang('ItemAdded'));
+                    echo Display::return_message(get_lang('ItemAdded'), 'confirm');
                 }
             }
             $obj->display();
@@ -174,7 +174,7 @@ switch ($action) {
             if ($check) {
                 $values = $form->exportValues();
                 $res    = $obj->update($values);
-                Display::display_confirmation_message(get_lang('ItemUpdated'), false);
+                echo Display::return_message(get_lang('ItemUpdated'), 'confirm', false);
             }
             $obj->display();
         } else {
@@ -191,7 +191,7 @@ switch ($action) {
         if ($check) {
             $res = $obj->delete($_GET['id']);
             if ($res) {
-                Display::display_confirmation_message(get_lang('ItemDeleted'));
+                echo Display::return_message(get_lang('ItemDeleted'), 'confirm');
             }
         }
         $obj->display();

+ 13 - 4
main/admin/index.php

@@ -82,7 +82,8 @@ if (api_is_platform_admin()) {
     $search_form = '
         <form method="get" class="form-inline" action="user_list.php">
             <div class="form-group">
-                <input class="form-control" type="text" name="keyword" value="">
+                <input class="form-control" type="text" name="keyword" value=""
+                 aria-label="'.get_lang('Search').'">
                 <button class="btn btn-default" type="submit">
                     <em class="fa fa-search"></em> ' . get_lang('Search').'
                 </button>
@@ -140,7 +141,8 @@ if (api_is_platform_admin()) {
 
     $search_form = ' <form method="get" class="form-inline" action="course_list.php">
             <div class="form-group">
-                <input class="form-control" type="text" name="keyword" value="">
+                <input class="form-control" type="text" name="keyword" value=""
+                 aria-label="'.get_lang('Search').'">
                 <button class="btn btn-default" type="submit">
                     <em class="fa fa-search"></em> ' . get_lang('Search').'
                 </button>
@@ -199,7 +201,10 @@ if (api_is_platform_admin()) {
 
     $search_form = ' <form method="get" action="settings.php" class="form-inline">
             <div class="form-group">
-                <input class="form-control" type="text" name="search_field" value="" >
+                <input class="form-control"
+                type="text"
+                name="search_field" value=""
+                aria-label="'.get_lang('Search').'" >
                 <input type="hidden" value="search_setting" name="category">
                 <button class="btn btn-default" type="submit">
                     <em class="fa fa-search"></em> ' . get_lang('Search').'
@@ -280,7 +285,11 @@ $sessionPath = api_get_path(WEB_CODE_PATH).'session/';
 
 $search_form = ' <form method="GET" class="form-inline" action="'.$sessionPath.'session_list.php">
                     <div class="form-group">
-                        <input class="form-control" type="text" name="keyword" value="">
+                        <input class="form-control"
+                        type="text"
+                        name="keyword"
+                        value=""
+                        aria-label="'.get_lang('Search').'">
                         <button class="btn btn-default" type="submit">
                             <em class="fa fa-search"></em> ' . get_lang('Search').'
                         </button>

+ 3 - 3
main/admin/languages.php

@@ -233,9 +233,6 @@ $tool_name = get_lang('PlatformLanguages');
 // setting breadcrumbs
 $interbreadcrumb[] = array('url' => 'index.php', 'name' => get_lang('PlatformAdmin'));
 
-// including the header file (which includes the banner itself)
-Display :: display_header($tool_name);
-
 if (isset($_GET['action']) && $_GET['action'] == 'make_unavailable_confirmed') {
     $language_info = SubLanguageManager::get_all_information_of_language($_GET['id']);
     if ($language_info['available'] == 1) {
@@ -249,6 +246,9 @@ if (isset($_GET['action']) && $_GET['action'] == 'make_unavailable_confirmed') {
 // displaying the explanation for this tool
 Display::addFlash(Display::return_message(get_lang('PlatformLanguagesExplanation'), 'normal'));
 
+// including the header file (which includes the banner itself)
+Display::display_header($tool_name);
+
 echo '<a id="disable_all_except_default" href="javascript:void(0)" class="btn btn-primary"><em class="fa fa-eye"></em> '.get_lang('LanguagesDisableAllExceptDefault').'</a><br /><br />';
 
 // selecting all the languages

+ 17 - 17
main/admin/ldap_import_students.php

@@ -6,7 +6,7 @@
  * Copyright (c) 2007 Mustapha Alouani (supervised by Michel Moreau-Belliard)
  */
 // resetting the course id
-$cidReset=true;
+$cidReset = true;
 require_once __DIR__.'/../inc/global.inc.php';
 // setting the section (for the tabs)
 $this_section = SECTION_PLATFORM_ADMIN;
@@ -15,11 +15,11 @@ $this_section = SECTION_PLATFORM_ADMIN;
 api_protect_admin_script();
 require('../auth/ldap/authldap.php');
 
-$annee_base=date('Y');
+$annee_base = date('Y');
 
 $tool_name = get_lang('LDAPImport');
 // setting breadcrumbs
-$interbreadcrumb[]=array('url' => 'index.php','name' => get_lang('PlatformAdmin'));
+$interbreadcrumb[] = array('url' => 'index.php', 'name' => get_lang('PlatformAdmin'));
 
 $htmlHeadXtra[] = '<script language="JavaScript" type="text/javascript">
 var buttoncheck = 1;
@@ -45,7 +45,7 @@ function checkAll() {
 
 $annee = $_GET['annee'];
 $composante = $_GET['composante'];
-$etape =  $_GET['etape'];
+$etape = $_GET['etape'];
 $course = $_POST['course'];
 
 
@@ -195,7 +195,7 @@ elseif ($annee <> "" && $composante <> "" && $etape == "") // form3 :annee!=0com
 	echo '</div>';
 }
 */
-elseif(!empty($annee) && empty($course))
+elseif (!empty($annee) && empty($course))
 {
 	Display::display_header($tool_name);
 	echo '<div style="align:center">';
@@ -203,7 +203,7 @@ elseif(!empty($annee) && empty($course))
 	echo '<form method="post" action="'.api_get_self().'?annee='.Security::remove_XSS($annee).'"><br />';
 	echo '<select name="course">';
 	$courses = CourseManager::get_courses_list();
-	foreach($courses as $row)
+	foreach ($courses as $row)
 	{
 		echo '<option value="'.$row['code'].'">'.api_htmlentities($row['title']).'</option>';
 	}
@@ -236,7 +236,7 @@ elseif (!empty($annee) && !empty($course) && empty($_POST['confirmed']))
 
 		$info = ldap_get_entries($ds, $sr);
 
-		for ($key = 0; $key < $info["count"]; $key ++) {
+		for ($key = 0; $key < $info["count"]; $key++) {
 			$nom_form[] = $info[$key]["sn"][0];
 			$prenom_form[] = $info[$key]["givenname"][0];
 			$email_form[] = $info[$key]["mail"][0];
@@ -256,7 +256,7 @@ elseif (!empty($annee) && !empty($course) && empty($_POST['confirmed']))
 		asort($nom_form);
 		reset($nom_form);
 
-		$statut=5;
+		$statut = 5;
 		include ('ldap_form_add_users_group.php');
 	} else {
 		echo '<h4>'.get_lang('UnableToConnectTo').' '.$host.'</h4>';
@@ -267,25 +267,25 @@ elseif (!empty($annee) && !empty($course) && empty($_POST['confirmed']))
     echo '</div>';
 
 }
-elseif (!empty($annee) && !empty($course) && ($_POST['confirmed']=='yes'))
+elseif (!empty($annee) && !empty($course) && ($_POST['confirmed'] == 'yes'))
 {
-	$id=$_POST['username_form'];
-	$UserList=array();
+	$id = $_POST['username_form'];
+	$UserList = array();
 	$userid_match_login = array();
 	foreach ($id as $form_index=>$user_id)
 	{
-		if(is_array($_POST['checkboxes']) && in_array($form_index,array_values($_POST['checkboxes'])))
+		if (is_array($_POST['checkboxes']) && in_array($form_index, array_values($_POST['checkboxes'])))
 		{
 			$tmp = ldap_add_user($user_id);
-			$UserList[]= $tmp;
+			$UserList[] = $tmp;
 			$userid_match_login[$tmp] = $user_id;
 		}
 	}
 	if (!empty($_POST['course']))
 	{
-		foreach($UserList as $user_id)
+		foreach ($UserList as $user_id)
 		{
-			CourseManager::add_user_to_course($user_id,$_POST['course']);
+			CourseManager::add_user_to_course($user_id, $_POST['course']);
 		}
 		header('Location: course_information.php?code='.Security::remove_XSS($_POST['course']));
 	}
@@ -310,9 +310,9 @@ elseif (!empty($annee) && !empty($course) && ($_POST['confirmed']=='yes'))
 	*/
 	else
 	{
-		Display::display_header($tool_name);
-		$message=get_lang('NoUserAdded');
+		$message = get_lang('NoUserAdded');
 		Display::addFlash(Display::return_message($message, 'normal', false));
+        Display::display_header($tool_name);
 	}
 	echo '<br /><br />';
     echo '<a href="ldap_import_students.php?annee=&composante=&etape=">'.get_lang('BackToNewSearch').'</a>';

+ 1 - 1
main/admin/ldap_import_students_to_session.php

@@ -204,9 +204,9 @@ elseif (!empty($annee) && !empty($id_session) && ($_POST['confirmed'] == 'yes'))
 	*/
 	else
 	{
-		Display::display_header($tool_name);
 		$message = get_lang('NoUserAdded');
 		Display::addFlash(Display::return_message($message, 'normal', false));
+        Display::display_header($tool_name);
 	}
 	echo '<br /><br />';
     echo '<a href="ldap_import_students.php?annee=&composante=&etape=">'.get_lang('BackToNewSearch').'</a>';

+ 128 - 157
main/admin/ldap_users_list.php

@@ -1,11 +1,8 @@
 <?php
 /* For licensing terms, see /license.txt */
 /**
- *	@author Mustapha Alouani
- *	@package chamilo.admin
- */
-/**
- * Init
+ * @author Mustapha Alouani
+ * @package chamilo.admin
  */
 $cidReset = true;
 require_once __DIR__.'/../inc/global.inc.php';
@@ -20,13 +17,13 @@ $login_as_user_id = @$_GET["user_id"] ?: null;
 // Login as ...
 if ($action == "login_as" && !empty ($login_as_user_id))
 {
-	login_user($login_as_user_id);
+    login_user($login_as_user_id);
 }
 
 //if we already have a session id and a user...
 /*
 if (($_GET['action']=="add_user") && ($_GET['id_session'] == strval(intval($_GET['id_session']))) && $_GET['id_session']>0 ){
-	header('Location: ldap_import_students_to_session.php?id_session='.$_GET['id_session'].'&ldap_user='.$_GET['id']);
+    header('Location: ldap_import_students_to_session.php?id_session='.$_GET['id_session'].'&ldap_user='.$_GET['id']);
 }
 */
 
@@ -37,150 +34,126 @@ $tool_name = get_lang('SearchLDAPUsers');
 
 if (isset ($_GET['action']))
 {
-	$check = Security::check_token('get');
-	if ($check)
-	{
-		switch ($_GET['action'])
-		{
-			case 'show_message' :
-				Display::display_header($tool_name);
-				Display::addFlash(Display::return_message($_GET['message'], 'normal'));
-				break;
-			case 'delete_user' :
-				Display::display_header($tool_name);
-				if ($user_id != $_user['user_id'] && UserManager::delete_user($_GET['user_id']))
-				{
-					Display::addFlash(Display::return_message(get_lang('UserDeleted'), 'normal'));
-				}
-				else
-				{
-					Display::addFlash(Display::return_message(get_lang('CannotDeleteUser'), 'error'));
-				}
-				break;
-			case 'lock' :
-				Display::display_header($tool_name);
-				$message = lock_unlock_user('lock', $_GET['user_id']);
-				Display::addFlash(Display::return_message($message, 'normal'));
-				break;
-			case 'unlock':
-				Display::display_header($tool_name);
-				$message = lock_unlock_user('unlock', $_GET['user_id']);
-				Display::addFlash(Display::return_message($message, 'normal'));
-				break;
+    $check = Security::check_token('get');
+    if ($check) {
+        switch ($_GET['action']) {
+            case 'show_message':
+                Display::addFlash(Display::return_message($_GET['message'], 'normal'));
+                Display::display_header($tool_name);
+                break;
+            case 'delete_user':
+                if ($user_id != $_user['user_id'] && UserManager::delete_user($_GET['user_id'])) {
+                    Display::addFlash(Display::return_message(get_lang('UserDeleted'), 'normal'));
+                } else {
+                    Display::addFlash(Display::return_message(get_lang('CannotDeleteUser'), 'error'));
+                }
+                Display::display_header($tool_name);
+                break;
+            case 'lock':
+                $message = lock_unlock_user('lock', $_GET['user_id']);
+                Display::addFlash(Display::return_message($message, 'normal'));
+                Display::display_header($tool_name);
+                break;
+            case 'unlock':
+                $message = lock_unlock_user('unlock', $_GET['user_id']);
+                Display::addFlash(Display::return_message($message, 'normal'));
+                Display::display_header($tool_name);
+                break;
             case 'add_user':
-				$id = $_GET['id'];
-				$UserList = array();
-				$userid_match_login = array();
-				foreach ($id as $user_id) {
-					$tmp = ldap_add_user($user_id);
-					$UserList[] = $tmp;
-					$userid_match_login[$tmp] = $user_id;
-				}
-				if (isset($_GET['id_session']) && ($_GET['id_session'] == strval(intval($_GET['id_session']))) && ($_GET['id_session'] > 0)) {
-					ldap_add_user_to_session($UserList, $_GET['id_session']);
-					header('Location: resume_session.php?id_session='.intval($_GET['id_session']));
-				} else {
-					Display::display_header($tool_name);
-					if (count($userid_match_login) > 0)
-					{
-						$message = get_lang('LDAPUsersAddedOrUpdated').':<br />';
-						foreach ($userid_match_login as $user_id => $login)
-						{
-							$message .= '- '.$login.'<br />';
-						}
-					}
-					else
-					{
-						$message = get_lang('NoUserAdded');
-					}
-					Display::addFlash(Display::return_message($message, 'normal', false));
-				}
-				break;
-			default:
-				Display::display_header($tool_name);
-		}
-		Security::clear_token();
-	}
-	else
-	{
-		Display::display_header($tool_name);
-	}
-}
-else
-{
-	Display::display_header($tool_name);
+                $id = $_GET['id'];
+                $UserList = array();
+                $userid_match_login = array();
+                foreach ($id as $user_id) {
+                    $tmp = ldap_add_user($user_id);
+                    $UserList[] = $tmp;
+                    $userid_match_login[$tmp] = $user_id;
+                }
+                if (isset($_GET['id_session']) && ($_GET['id_session'] == strval(intval($_GET['id_session']))) && ($_GET['id_session'] > 0)) {
+                    ldap_add_user_to_session($UserList, $_GET['id_session']);
+                    header('Location: resume_session.php?id_session='.intval($_GET['id_session']));
+                } else {
+                    Display::display_header($tool_name);
+                    if (count($userid_match_login) > 0) {
+                        $message = get_lang('LDAPUsersAddedOrUpdated').':<br />';
+                        foreach ($userid_match_login as $user_id => $login) {
+                            $message .= '- '.$login.'<br />';
+                        }
+                    } else {
+                        $message = get_lang('NoUserAdded');
+                    }
+                    Display::addFlash(Display::return_message($message, 'normal', false));
+                    Display::display_header($tool_name);
+                }
+                break;
+            default:
+                Display::display_header($tool_name);
+        }
+        Security::clear_token();
+    } else {
+        Display::display_header($tool_name);
+    }
+} else {
+    Display::display_header($tool_name);
 }
-if (isset ($_POST['action']))
-{
-	$check = Security::check_token('get');
-	if ($check)
-	{
-		switch ($_POST['action'])
-		{
-			case 'delete' :
-				$number_of_selected_users = count($_POST['id']);
-				$number_of_deleted_users = 0;
-				foreach ($_POST['id'] as $index => $user_id)
-				{
-					if ($user_id != $_user['user_id'])
-					{
-						if (UserManager::delete_user($user_id))
-						{
-							$number_of_deleted_users++;
-						}
-					}
-				}
-				if ($number_of_selected_users == $number_of_deleted_users)
-				{
-					Display::addFlash(Display::return_message(get_lang('SelectedUsersDeleted'), 'normal'));
-				}
-				else
-				{
-					Display::addFlash(Display::return_message(get_lang('SomeUsersNotDeleted'), 'error'));
-				}
-				break;
-			case 'add_user' :
-				$number_of_selected_users = count($_POST['id']);
-				$number_of_added_users = 0;
-				$UserList = array();
-				foreach ($_POST['id'] as $index => $user_id)
-				{
-					if ($user_id != $_user['user_id'])
-					{
-						$UserList[] = ldap_add_user($user_id);
-					}
-				}
-				if (isset($_GET['id_session']) && (trim($_GET['id_session']) != ""))
-					addUserToSession($UserList, $_GET['id_session']);
-				if (count($UserList) > 0)
-				{
-					Display::addFlash(Display::return_message(count($UserList)." ".get_lang('LDAPUsersAdded')));
-				}
-				else
-				{
-					Display::addFlash(Display::return_message(get_lang('NoUserAdded')));
-				}
-				break;
 
-		}
-		Security::clear_token();
-	}
+if (isset($_POST['action'])) {
+    $check = Security::check_token('get');
+    if ($check) {
+        switch ($_POST['action']) {
+            case 'delete':
+                $number_of_selected_users = count($_POST['id']);
+                $number_of_deleted_users = 0;
+                foreach ($_POST['id'] as $index => $user_id) {
+                    if ($user_id != $_user['user_id']) {
+                        if (UserManager::delete_user($user_id)) {
+                            $number_of_deleted_users++;
+                        }
+                    }
+                }
+                if ($number_of_selected_users == $number_of_deleted_users) {
+                    echo Display::return_message(get_lang('SelectedUsersDeleted'), 'normal');
+                } else {
+                    echo Display::return_message(get_lang('SomeUsersNotDeleted'), 'error');
+                }
+                break;
+            case 'add_user':
+                $number_of_selected_users = count($_POST['id']);
+                $number_of_added_users = 0;
+                $UserList = array();
+                foreach ($_POST['id'] as $index => $user_id) {
+                    if ($user_id != $_user['user_id']) {
+                        $UserList[] = ldap_add_user($user_id);
+                    }
+                }
+                if (isset($_GET['id_session']) && (trim($_GET['id_session']) != "")) {
+                    addUserToSession($UserList, $_GET['id_session']);
+                }
+                if (count($UserList) > 0) {
+                    echo Display::return_message(
+                        count($UserList)." ".get_lang('LDAPUsersAdded')
+                    );
+                } else {
+                    echo Display::return_message(get_lang('NoUserAdded'));
+                }
+                break;
+
+        }
+        Security::clear_token();
+    }
 }
 
 $form = new FormValidator('advanced_search', 'get');
 $form->addText('keyword_username', get_lang('LoginName'), false);
-if (api_is_western_name_order())
-{
-	$form->addText('keyword_firstname', get_lang('FirstName'), false);
-	$form->addText('keyword_lastname', get_lang('LastName'), false);
+if (api_is_western_name_order()) {
+    $form->addText('keyword_firstname', get_lang('FirstName'), false);
+    $form->addText('keyword_lastname', get_lang('LastName'), false);
+} else {
+    $form->addText('keyword_lastname', get_lang('LastName'), false);
+    $form->addText('keyword_firstname', get_lang('FirstName'), false);
 }
-else
-{
-	$form->addText('keyword_lastname', get_lang('LastName'), false);
-	$form->addText('keyword_firstname', get_lang('FirstName'), false);
+if (isset($_GET['id_session'])) {
+    $form->addElement('hidden', 'id_session', $_GET['id_session']);
 }
-if (isset($_GET['id_session']))
-	$form->addElement('hidden', 'id_session', $_GET['id_session']);
 
 $type = array();
 $type["all"] = get_lang('All');
@@ -194,28 +167,31 @@ $form->addElement('submit', 'submit', get_lang('Ok'));
 //$defaults['keyword_inactive'] = 1;
 //$form->setDefaults($defaults);
 $form->display();
-
-
-
 $parameters['keyword_username'] = @$_GET['keyword_username'] ?: null;
 $parameters['keyword_firstname'] = @$_GET['keyword_firstname'] ?: null;
 $parameters['keyword_lastname'] = @$_GET['keyword_lastname'] ?: null;
 $parameters['keyword_email'] = @$_GET['keyword_email'] ?: null;
-if (isset($_GET['id_session']))
-	$parameters['id_session'] = $_GET['id_session'];
+if (isset($_GET['id_session'])) {
+    $parameters['id_session'] = $_GET['id_session'];
+}
 // Create a sortable table with user-data
 
 $parameters['sec_token'] = Security::get_token();
-$table = new SortableTable('users', 'ldap_get_number_of_users', 'ldap_get_user_data', (api_is_western_name_order() xor api_sort_by_first_name()) ? 3 : 2);
+$table = new SortableTable(
+    'users',
+    'ldap_get_number_of_users',
+    'ldap_get_user_data',
+    (api_is_western_name_order() xor api_sort_by_first_name()) ? 3 : 2
+);
 $table->set_additional_parameters($parameters);
 $table->set_header(0, '', false);
 $table->set_header(1, get_lang('LoginName'));
 if (api_is_western_name_order()) {
-	$table->set_header(2, get_lang('FirstName'));
-	$table->set_header(3, get_lang('LastName'));
+    $table->set_header(2, get_lang('FirstName'));
+    $table->set_header(3, get_lang('LastName'));
 } else {
-	$table->set_header(2, get_lang('LastName'));
-	$table->set_header(3, get_lang('FirstName'));
+    $table->set_header(2, get_lang('LastName'));
+    $table->set_header(3, get_lang('FirstName'));
 }
 $table->set_header(4, get_lang('Email'));
 $table->set_header(5, get_lang('Actions'));
@@ -225,9 +201,4 @@ $table->set_column_filter(5, 'modify_filter');
 $table->set_form_actions(array('add_user' => get_lang('AddLDAPUsers')));
 $table->display();
 
-/*
-==============================================================================
-		FOOTER
-==============================================================================
-*/
 Display::display_footer();

+ 1 - 1
main/admin/ldap_users_synchro.php

@@ -62,7 +62,7 @@ Display::display_header($tool_name);
 if (isset($action) && ($action == "synchro")) {
 	$included = true;
 	require('ldap_synchro.php');
-	Display::addFlash(Display::return_message($message, 'normal', false));
+	echo Display::return_message($message, 'normal', false);
 }
 Display::display_footer();
 ?>

+ 1 - 1
main/admin/legal_list.php

@@ -26,7 +26,7 @@ $legal_count = LegalManager::count();
 $languages = api_get_languages();
 $available_languages = count($languages['folder']);
 if ($legal_count != $available_languages) {
-    Display::display_warning_message(get_lang('YouShouldCreateTermAndConditionsForAllAvailableLanguages'));
+    echo Display::return_message(get_lang('YouShouldCreateTermAndConditionsForAllAvailableLanguages'), 'warning');
 }
 
 $table = new SortableTable('conditions', 'count_mask', 'get_legal_data_mask', 2);

+ 1 - 1
main/admin/promotions.php

@@ -169,7 +169,7 @@ switch ($action) {
                 $res    = $promotion->update($values);
                 $promotion->update_all_sessions_status_by_promotion_id($values['id'], $values['status']);
                 if ($res) {
-                    Display::display_confirmation_message(get_lang('PromotionUpdated'), $values['name']);
+                    echo Display::return_message(get_lang('PromotionUpdated').': '.$values['name'], 'confirm');
                 }
             }
             $promotion->display();

+ 39 - 25
main/admin/settings.lib.php

@@ -34,7 +34,7 @@ function handleRegions()
             api_get_utc_datetime(),
             $user_id
         );
-        Display::addFlash(Display::return_message(get_lang('SettingsStored'), 'confirmation'));
+        echo Display::return_message(get_lang('SettingsStored'), 'confirmation');
     }
 
     $plugin_obj = new AppPlugin();
@@ -140,7 +140,7 @@ function handlePlugins()
             api_get_utc_datetime(),
             $user_id
         );
-        Display::addFlash(Display::return_message(get_lang('SettingsStored'), 'confirmation'));
+        echo Display::return_message(get_lang('SettingsStored'), 'confirmation');
     }
 
     $all_plugins = $plugin_obj->read_plugins_from_path();
@@ -285,12 +285,10 @@ function handleStylesheets()
     $urlId = api_get_current_access_url_id();
 
     if (!is_writable(CSS_UPLOAD_PATH)) {
-        Display::addFlash(
-            Display::return_message(
-                CSS_UPLOAD_PATH.get_lang('IsNotWritable'),
-                'error',
-                false
-            )
+        echo Display::return_message(
+            CSS_UPLOAD_PATH.get_lang('IsNotWritable'),
+            'error',
+            false
         );
     } else {
         // Uploading a new stylesheet.
@@ -323,11 +321,7 @@ function handleStylesheets()
             );
 
             if ($result) {
-                Display::addFlash(
-                    Display::return_message(
-                        get_lang('StylesheetAdded')
-                    )
-                );
+                echo Display::return_message(get_lang('StylesheetAdded'));
             }
         }
     }
@@ -579,7 +573,7 @@ function uploadStylesheet($values, $picture)
             }
             $zip->close();
         } else {
-            Display::addFlash(Display::return_message(get_lang('ErrorReadingZip').$info['extension'], 'error', false));
+            echo Display::return_message(get_lang('ErrorReadingZip').$info['extension'], 'error', false);
         }
     } else {
         // Simply move the file.
@@ -727,7 +721,7 @@ function handleSearch()
         $formValues = $form->exportValues();
         setConfigurationSettingsInDatabase($formValues, $_configuration['access_url']);
         $search_enabled = $formValues['search_enabled'];
-        Display::addFlash(Display::return_message($SettingsStored, 'confirm'));
+        echo Display::return_message($SettingsStored, 'confirm');
     }
     $specific_fields = get_specific_field_list();
 
@@ -1099,7 +1093,7 @@ function addEditTemplate()
                 Database::insert($table_system_template, $params);
 
                 // Display a feedback message.
-                Display::addFlash(Display::return_message(get_lang('TemplateAdded'), 'confirm'));
+                echo Display::return_message(get_lang('TemplateAdded'), 'confirm');
                 echo '<a href="settings.php?category=Templates&action=add">'.Display::return_icon('new_template.png', get_lang('AddTemplate'), '', ICON_SIZE_MEDIUM).'</a>';
             } else {
                 $content_template = '<head>{CSS}<style type="text/css">.text{font-weight: normal;}</style></head><body>'.Database::escape_string($values['template_text']).'</body>';
@@ -1111,7 +1105,7 @@ function addEditTemplate()
                 Database::query($sql);
 
                 // Display a feedback message.
-                Display::addFlash(Display::return_message(get_lang('TemplateEdited'), 'confirm'));
+                echo Display::return_message(get_lang('TemplateEdited'), 'confirm');
             }
         }
         Security::clear_token();
@@ -1150,7 +1144,7 @@ function deleteTemplate($id)
     Database::query($sql);
 
     // Display a feedback message.
-    Display::addFlash(Display::return_message(get_lang('TemplateDeleted'), 'confirm'));
+    echo Display::return_message(get_lang('TemplateDeleted'), 'confirm');
 }
 
 /**
@@ -1322,7 +1316,7 @@ function generateSettingsForm($settings, $settings_by_access_list)
                             get_lang($row['comment']),
                             get_lang('MB')
                         ),
-                        array('maxlength' => '8')
+                        array('maxlength' => '8', 'aria-label' => get_lang($row['title']))
                     );
                     $form->applyFilter($row['variable'], 'html_filter');
                     $default_values[$row['variable']] = round($row['selected_value'] / 1024 / 1024, 1);
@@ -1334,7 +1328,7 @@ function generateSettingsForm($settings, $settings_by_access_list)
                             get_lang($row['title']),
                             get_lang($row['comment']),
                         ),
-                        array('maxlength' => '5')
+                        array('maxlength' => '5', 'aria-label' => get_lang($row['title']))
                     );
                     $form->applyFilter($row['variable'], 'html_filter');
                     $default_values[$row['variable']] = $row['selected_value'];
@@ -1344,6 +1338,7 @@ function generateSettingsForm($settings, $settings_by_access_list)
                     continue;
                 } else {
                     $hideme['class'] = 'col-md-4';
+                    $hideme['aria-label'] = get_lang($row['title']);
                     $form->addElement(
                         'text',
                         $row['variable'],
@@ -1364,7 +1359,13 @@ function generateSettingsForm($settings, $settings_by_access_list)
                     if (file_exists($file)) {
                         $value = file_get_contents($file);
                     }
-                    $form->addElement('textarea', $row['variable'], array(get_lang($row['title']), get_lang($row['comment'])), array('rows'=>'10'), $hideme);
+                    $form->addElement(
+                        'textarea',
+                        $row['variable'],
+                        array(get_lang($row['title']), get_lang($row['comment'])),
+                        array('rows' => '10', 'id' => $row['variable']),
+                        $hideme
+                    );
                     $default_values[$row['variable']] = $value;
                 } elseif ($row['variable'] == 'footer_extra_content') {
                     $file = api_get_home_path().'footer_extra_content.txt';
@@ -1372,10 +1373,23 @@ function generateSettingsForm($settings, $settings_by_access_list)
                     if (file_exists($file)) {
                         $value = file_get_contents($file);
                     }
-                    $form->addElement('textarea', $row['variable'], array(get_lang($row['title']), get_lang($row['comment'])), array('rows'=>'10'), $hideme);
+                    $form->addElement(
+                        'textarea',
+                        $row['variable'],
+                        array(get_lang($row['title']), get_lang($row['comment'])),
+                        array('rows' => '10', 'id' => $row['variable']),
+                        $hideme
+                    );
                     $default_values[$row['variable']] = $value;
                 } else {
-                    $form->addElement('textarea', $row['variable'], array(get_lang($row['title']), get_lang($row['comment'])), array('rows'=>'10'), $hideme);
+                    $form->addElement(
+                        'textarea',
+                        $row['variable'],
+                        array(get_lang($row['title']),
+                        get_lang($row['comment'])),
+                        array('rows' => '10', 'id' => $row['variable']),
+                        $hideme
+                    );
                     $default_values[$row['variable']] = $row['selected_value'];
                 }
                 break;
@@ -1715,9 +1729,9 @@ function generateCSSDownloadLink($style)
 
         //@TODO: use more generic script to download.
         $str = '<a class="btn btn-primary btn-large" href="'.$url.'">'.get_lang('ClickHereToDownloadTheFile').'</a>';
-        Display::addFlash(Display::return_message($str, 'normal', false));
+        echo Display::return_message($str, 'normal', false);
     } else {
-        Display::addFlash(Display::return_message(get_lang('FileNotFound'), 'warning'));
+        echo Display::return_message(get_lang('FileNotFound'), 'warning');
     }
 }
 

+ 4 - 1
main/admin/settings.php

@@ -80,7 +80,10 @@ $form_search = new FormValidator(
     array(),
     FormValidator::LAYOUT_INLINE
 );
-$form_search->addElement('text', 'search_field');
+$form_search->addElement('text', 'search_field', null, array(
+    'id' => 'search_field',
+    'aria-label' => get_lang('Search')
+));
 $form_search->addElement('hidden', 'category', 'search_setting');
 $form_search->addButtonSearch(get_lang('Search'), 'submit_button');
 $form_search->setDefaults(

+ 1 - 1
main/admin/skills_gradebook.php

@@ -116,7 +116,7 @@ switch ($action) {
             $values = $form->exportValues();
             $res    = $gradebook->update_skills_to_gradebook($values['id'], $values['skill']);
             if ($res) {
-                Display::display_confirmation_message(get_lang('ItemAdded'));
+                echo Display::return_message(get_lang('ItemAdded'), 'confirm');
             }
         }
         $form->display();

+ 2 - 2
main/admin/skills_import.php

@@ -243,10 +243,10 @@ $interbreadcrumb[] = array("url" => 'skill_list.php', "name" => get_lang('Manage
 Display :: display_header($tool_name);
 
 if (!empty($error_message)) {
-    Display::addFlash(Display::return_message($error_message, 'error'));
+    echo Display::return_message($error_message, 'error');
 }
 if (!empty($see_message_import)) {
-    Display::addFlash(Display::return_message($see_message_import, 'normal'));
+    echo Display::return_message($see_message_import, 'normal');
 }
 
 $toolbar = Display::url(

+ 6 - 6
main/admin/special_exports.php

@@ -37,7 +37,7 @@ Display::display_header($nameTools);
 echo Display::page_header($nameTools);
 
 if (count($_POST) == 0) {
-    Display::addFlash(Display::return_message(get_lang('SpecialExportsIntroduction')));
+    echo Display::return_message(get_lang('SpecialExportsIntroduction'));
 }
 $error = 0;
 $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
@@ -64,7 +64,7 @@ if ((isset($_POST['action']) && $_POST['action'] == 'course_select_form') ||
 
         $zip_folder = new PclZip($FileZip['TEMP_FILE_ZIP']);
         if (!isset($_POST['resource']) || count($_POST['resource']) == 0) {
-            Display::addFlash(Display::return_message(get_lang('ErrorMsgSpecialExport'), 'error'));
+            echo Display::return_message(get_lang('ErrorMsgSpecialExport'), 'error');
         } else {
             $Resource = $_POST['resource'];
 
@@ -130,7 +130,7 @@ if ((isset($_POST['action']) && $_POST['action'] == 'course_select_form') ||
 }
 
 if ($export && $name) {
-    Display::addFlash(Display::return_message(get_lang('BackupCreated'), 'confirm'));
+    echo Display::return_message(get_lang('BackupCreated'), 'confirm');
     echo '<br /><a class="btn btn-default" href="'.api_get_path(WEB_CODE_PATH).'course_info/download.php?archive_path=&archive='.urlencode($name).'">'.get_lang('Download').'</a>';
 } else {
     // Display forms especial export
@@ -138,10 +138,10 @@ if ($export && $name) {
         $cb = new CourseBuilder();
         $course = $cb->build_session_course();
         if ($course === false) {
-            Display::addFlash(Display::return_message(get_lang('ErrorMsgSpecialExport'), 'error'));
+            echo Display::return_message(get_lang('ErrorMsgSpecialExport'), 'error');
             form_special_export();
         } else {
-            Display::addFlash(Display::return_message(get_lang('ToExportSpecialSelect'), 'normal'));
+            echo Display::return_message(get_lang('ToExportSpecialSelect'), 'normal');
             CourseSelectForm :: display_form_session_export($course);
         }
     } else {
@@ -310,7 +310,7 @@ function fullexportspecial()
             return $name;
         }
     } else {
-        Display::display_error_message(get_lang('ErrorMsgSpecialExport')); //main API
+        echo Display::return_message(get_lang('ErrorMsgSpecialExport'), 'error'); //main API
         $export = false;
         return false;
     }

+ 14 - 6
main/admin/specific_fields_add.php

@@ -1,5 +1,6 @@
 <?php
 /* For licensing terms, see /license.txt */
+
 /**
  * Add form
  * @package chamilo.admin
@@ -17,17 +18,24 @@ $this_section = SECTION_PLATFORM_ADMIN;
 
 // user permissions
 api_protect_admin_script();
-
 $fieldId = isset($_REQUEST['field_id']) ? intval($_REQUEST['field_id']) : 0;
-
-$interbreadcrumb[] = array('url' => 'index.php', 'name' => get_lang('PlatformAdmin'));
-$interbreadcrumb[] = array('url' => 'settings.php?category=Search', 'name' => get_lang('PlatformConfigSettings'));
-$interbreadcrumb[] = array('url' => 'specific_fields.php', 'name' => get_lang('SpecificSearchFields'));
+$interbreadcrumb[] = array(
+    'url' => 'index.php',
+    'name' => get_lang('PlatformAdmin'),
+);
+$interbreadcrumb[] = array(
+    'url' => 'settings.php?category=Search',
+    'name' => get_lang('PlatformConfigSettings'),
+);
+$interbreadcrumb[] = array(
+    'url' => 'specific_fields.php',
+    'name' => get_lang('SpecificSearchFields'),
+);
 
 $tool_name = get_lang('AddSpecificSearchField');
 
 if (isset($_GET['action']) && $_GET['action'] === 'edit') {
-  $tool_name = get_lang('EditSpecificSearchField');
+    $tool_name = get_lang('EditSpecificSearchField');
 }
 // Create the form
 $form = new FormValidator('specific_fields_add');

+ 1 - 1
main/admin/sub_language.php

@@ -115,7 +115,7 @@ $html .= '</div>';
 echo $html;
 echo '<br /><br /><br />';
 if (!empty($sublanguage_folder_error)) {
-    Display::display_warning_message($sublanguage_folder_error);
+    echo Display::return_message($sublanguage_folder_error, 'warning');
 }
 echo '<div id="div_message_information_id">&nbsp;</div>';
 

+ 3 - 3
main/admin/sub_language_add.php

@@ -261,9 +261,9 @@ echo $msg;
 if (isset($_POST['SubmitAddDeleteLanguage'])) {
     $rs = SubLanguageManager::remove_sub_language($_GET['id'], $_GET['sub_language_id']);
     if ($rs === true) {
-        Display::addFlash(Display::return_message(get_lang('TheSubLanguageHasBeenRemoved'), 'confirm'));
+        echo Display::return_message(get_lang('TheSubLanguageHasBeenRemoved'), 'confirm');
     } else {
-        Display::addFlash(Display::return_message(get_lang('TheSubLanguageHasNotBeenRemoved'), 'error'));
+        echo Display::return_message(get_lang('TheSubLanguageHasNotBeenRemoved'), 'error');
     }
 }
 // ckeck_if_is_parent_of_sub_language($parent_id)===false
@@ -302,7 +302,7 @@ if (isset($_GET['action']) && $_GET['action'] == 'definenewsublanguage') {
         $form->display();
     }
     if (isset($_GET['action']) && $_GET['action'] == 'definenewsublanguage') {
-        Display::addFlash(Display::return_message(get_lang('TheSubLanguageForThisLanguageHasBeenAdded')));
+        echo Display::return_message(get_lang('TheSubLanguageForThisLanguageHasBeenAdded'));
     }
 }
 /**

+ 11 - 7
main/admin/subscribe_user2course.php

@@ -92,7 +92,7 @@ if (isset($_POST['form_sent']) && $_POST['form_sent']) {
 
     if ($form_sent == 1) {
         if (count($users) == 0 || count($courses) == 0) {
-            Display :: display_error_message(get_lang('AtLeastOneUserAndOneCourse'));
+            echo Display::return_message(get_lang('AtLeastOneUserAndOneCourse'), 'error');
         } else {
             $errorDrh = 0;
             foreach ($courses as $course_code) {
@@ -107,9 +107,9 @@ if (isset($_POST['form_sent']) && $_POST['form_sent']) {
             }
 
             if ($errorDrh == 0) {
-                Display :: display_confirmation_message(get_lang('UsersAreSubscibedToCourse'));
+                echo Display::return_message(get_lang('UsersAreSubscibedToCourse'), 'confirm');
             } else {
-                Display :: display_error_message(get_lang('HumanResourcesManagerShouldNotBeRegisteredToCourses'));
+                echo Display::return_message(get_lang('HumanResourcesManagerShouldNotBeRegisteredToCourses'), 'error');
             }
         }
     }
@@ -292,8 +292,10 @@ if (is_array($extra_field_list)) {
     <td width="40%" align="center">
      <b><?php echo get_lang('UserList'); ?></b>
      <br/><br/>
-     <?php echo get_lang('FirstLetterUser'); ?> :
-     <select name="firstLetterUser" onchange="javascript:document.formulaire.form_sent.value='2'; document.formulaire.submit();">
+        <?php echo get_lang('FirstLetterUser'); ?> :
+     <select name="firstLetterUser"
+        onchange="javascript:document.formulaire.form_sent.value='2'; document.formulaire.submit();"
+        aria-label="<?php echo get_lang('FirstLetterUser'); ?>">
       <option value="">--</option>
       <?php
         echo Display :: get_alphabet_options($first_letter_user);
@@ -304,8 +306,10 @@ if (is_array($extra_field_list)) {
     <td width="40%" align="center">
      <b><?php echo get_lang('CourseList'); ?> :</b>
      <br/><br/>
-     <?php echo get_lang('FirstLetterCourse'); ?> :
-     <select name="firstLetterCourse" onchange="javascript:document.formulaire.form_sent.value='2'; document.formulaire.submit();">
+        <?php echo get_lang('FirstLetterCourse'); ?> :
+     <select name="firstLetterCourse" 
+        onchange="javascript:document.formulaire.form_sent.value='2'; document.formulaire.submit();"
+        aria-label="<?php echo get_lang('FirstLetterCourse'); ?>">
       <option value="">--</option>
       <?php
       echo Display :: get_alphabet_options($first_letter_course);

+ 1 - 1
main/admin/system_announcements.php

@@ -116,7 +116,7 @@ switch ($action) {
         $values['content'] = $announcement->content;
         $values['start'] = api_get_local_time($announcement->date_start);
         $values['end'] = api_get_local_time($announcement->date_end);
-        $values['range'] =substr(api_get_local_time($announcement->date_start), 0, 16).' / '.
+        $values['range'] = substr(api_get_local_time($announcement->date_start), 0, 16).' / '.
             substr(api_get_local_time($announcement->date_end), 0, 16);
 
         $data = (array) $announcement;

+ 43 - 7
main/admin/user_add.php

@@ -102,33 +102,69 @@ $form = new FormValidator('user_add');
 $form->addElement('header', '', $tool_name);
 if (api_is_western_name_order()) {
     // Firstname
-    $form->addElement('text', 'firstname', get_lang('FirstName'));
+    $form->addElement(
+        'text',
+        'firstname',
+        get_lang('FirstName'),
+        array(
+            'id' => 'firstname'
+        )
+    );
     $form->applyFilter('firstname', 'html_filter');
     $form->applyFilter('firstname', 'trim');
     $form->addRule('firstname', get_lang('ThisFieldIsRequired'), 'required');
     // Lastname
-    $form->addElement('text', 'lastname', get_lang('LastName'));
+    $form->addElement(
+        'text',
+        'lastname',
+        get_lang('LastName'),
+        array(
+            'id' => 'lastname'
+        )
+    );
     $form->applyFilter('lastname', 'html_filter');
     $form->applyFilter('lastname', 'trim');
     $form->addRule('lastname', get_lang('ThisFieldIsRequired'), 'required');
 } else {
     // Lastname
-    $form->addElement('text', 'lastname', get_lang('LastName'));
+    $form->addElement(
+        'text',
+        'lastname',
+        get_lang('LastName'),
+        array(
+            'id' => 'lastname'
+        )
+    );
     $form->applyFilter('lastname', 'html_filter');
     $form->applyFilter('lastname', 'trim');
     $form->addRule('lastname', get_lang('ThisFieldIsRequired'), 'required');
     // Firstname
-    $form->addElement('text', 'firstname', get_lang('FirstName'));
+    $form->addElement(
+        'text',
+        'firstname',
+        get_lang('FirstName'),
+        array(
+            'id' => 'firstname'
+        )
+    );
     $form->applyFilter('firstname', 'html_filter');
     $form->applyFilter('firstname', 'trim');
     $form->addRule('firstname', get_lang('ThisFieldIsRequired'), 'required');
 }
 // Official code
-$form->addElement('text', 'official_code', get_lang('OfficialCode'), array('size' => '40'));
+$form->addElement(
+    'text',
+    'official_code',
+    get_lang('OfficialCode'),
+    array(
+        'size' => '40',
+        'id' => 'official_code'
+    )
+);
 $form->applyFilter('official_code', 'html_filter');
 $form->applyFilter('official_code', 'trim');
 // Email
-$form->addElement('text', 'email', get_lang('Email'), array('size' => '40', 'autocomplete' => 'off'));
+$form->addElement('text', 'email', get_lang('Email'), array('size' => '40', 'autocomplete' => 'off', 'id' => 'email'));
 $form->addRule('email', get_lang('EmailWrong'), 'email');
 if (api_get_setting('registration', 'email') == 'true') {
     $form->addRule('email', get_lang('EmailWrong'), 'required');
@@ -140,7 +176,7 @@ if (api_get_setting('login_is_email') == 'true') {
 }
 
 // Phone
-$form->addElement('text', 'phone', get_lang('PhoneNumber'), ['autocomplete' => 'off']);
+$form->addElement('text', 'phone', get_lang('PhoneNumber'), ['autocomplete' => 'off', 'id' => 'phone']);
 // Picture
 $form->addFile(
     'picture',

+ 110 - 112
main/admin/user_edit.php

@@ -2,8 +2,9 @@
 /* For licensing terms, see /license.txt */
 
 /**
-*	@package chamilo.admin
+ * @package chamilo.admin
 */
+
 $cidReset = true;
 require_once __DIR__.'/../inc/global.inc.php';
 
@@ -12,11 +13,8 @@ $this_section = SECTION_PLATFORM_ADMIN;
 api_protect_admin_script(true);
 
 $user_id = isset($_GET['user_id']) ? intval($_GET['user_id']) : intval($_POST['user_id']);
-
 api_protect_super_admin($user_id, null, true);
-
 $is_platform_admin = api_is_platform_admin() ? 1 : 0;
-
 $userInfo = api_get_user_info($user_id);
 
 $htmlHeadXtra[] = '
@@ -24,39 +22,39 @@ $htmlHeadXtra[] = '
 var is_platform_id = "'.$is_platform_admin.'";
 
 function enable_expiration_date() {
-	document.user_edit.radio_expiration_date[0].checked=false;
-	document.user_edit.radio_expiration_date[1].checked=true;
+    document.user_edit.radio_expiration_date[0].checked=false;
+    document.user_edit.radio_expiration_date[1].checked=true;
 }
 
 function password_switch_radio_button(){
-	var input_elements = document.getElementsByTagName("input");
-	for (var i = 0; i < input_elements.length; i++) {
-		if(input_elements.item(i).name == "reset_password" && input_elements.item(i).value == "2") {
-			input_elements.item(i).checked = true;
-		}
-	}
+    var input_elements = document.getElementsByTagName("input");
+    for (var i = 0; i < input_elements.length; i++) {
+        if(input_elements.item(i).name == "reset_password" && input_elements.item(i).value == "2") {
+            input_elements.item(i).checked = true;
+        }
+    }
 }
 
 function display_drh_list(){
     var $radios = $("input:radio[name=platform_admin]");
-	if (document.getElementById("status_select").value=='.COURSEMANAGER.') {
+    if (document.getElementById("status_select").value=='.COURSEMANAGER.') {
         if (is_platform_id == 1)
             document.getElementById("id_platform_admin").style.display="block";
-	} else if (document.getElementById("status_select").value=='.STUDENT.') {
+    } else if (document.getElementById("status_select").value=='.STUDENT.') {
         if (is_platform_id == 1)
             document.getElementById("id_platform_admin").style.display="none";
         $radios.filter("[value=0]").attr("checked", true);
-	} else {
+    } else {
         if (is_platform_id == 1)
             document.getElementById("id_platform_admin").style.display="none";
         $radios.filter("[value=0]").attr("checked", true);
-	}
+    }
 }
 
 function show_image(image,width,height) {
-	width = parseInt(width) + 20;
-	height = parseInt(height) + 20;
-	window_x = window.open(image,\'windowX\',\'width=\'+ width + \', height=\'+ height + \' , resizable=0\');
+    width = parseInt(width) + 20;
+    height = parseInt(height) + 20;
+    window_x = window.open(image,\'windowX\',\'width=\'+ width + \', height=\'+ height + \' , resizable=0\');
 }
 
 function confirmation(name) {
@@ -72,8 +70,8 @@ $gMapsPlugin = GoogleMapsPlugin::create();
 $geolocalization = $gMapsPlugin->get('enable_api') === 'true';
 
 if ($geolocalization) {
-	$gmapsApiKey = $gMapsPlugin->get('api_key');
-	$htmlHeadXtra[] = '<script type="text/javascript" src="//maps.googleapis.com/maps/api/js?sensor=true&key='.$gmapsApiKey.'" ></script>';
+    $gmapsApiKey = $gMapsPlugin->get('api_key');
+    $htmlHeadXtra[] = '<script type="text/javascript" src="//maps.googleapis.com/maps/api/js?sensor=true&key='.$gmapsApiKey.'" ></script>';
 }
 
 $htmlHeadXtra[] = api_get_css_asset('cropper/dist/cropper.min.css');
@@ -117,27 +115,27 @@ $form->addElement('header', $tool_name);
 $form->addElement('hidden', 'user_id', $user_id);
 
 if (api_is_western_name_order()) {
-	// Firstname
-	$form->addElement('text', 'firstname', get_lang('FirstName'));
-	$form->applyFilter('firstname', 'html_filter');
-	$form->applyFilter('firstname', 'trim');
-	$form->addRule('firstname', get_lang('ThisFieldIsRequired'), 'required');
-	// Lastname
-	$form->addElement('text', 'lastname', get_lang('LastName'));
-	$form->applyFilter('lastname', 'html_filter');
-	$form->applyFilter('lastname', 'trim');
-	$form->addRule('lastname', get_lang('ThisFieldIsRequired'), 'required');
+    // Firstname
+    $form->addElement('text', 'firstname', get_lang('FirstName'));
+    $form->applyFilter('firstname', 'html_filter');
+    $form->applyFilter('firstname', 'trim');
+    $form->addRule('firstname', get_lang('ThisFieldIsRequired'), 'required');
+    // Lastname
+    $form->addElement('text', 'lastname', get_lang('LastName'));
+    $form->applyFilter('lastname', 'html_filter');
+    $form->applyFilter('lastname', 'trim');
+    $form->addRule('lastname', get_lang('ThisFieldIsRequired'), 'required');
 } else {
-	// Lastname
-	$form->addElement('text', 'lastname', get_lang('LastName'));
-	$form->applyFilter('lastname', 'html_filter');
-	$form->applyFilter('lastname', 'trim');
-	$form->addRule('lastname', get_lang('ThisFieldIsRequired'), 'required');
-	// Firstname
-	$form->addElement('text', 'firstname', get_lang('FirstName'));
-	$form->applyFilter('firstname', 'html_filter');
-	$form->applyFilter('firstname', 'trim');
-	$form->addRule('firstname', get_lang('ThisFieldIsRequired'), 'required');
+    // Lastname
+    $form->addElement('text', 'lastname', get_lang('LastName'));
+    $form->applyFilter('lastname', 'html_filter');
+    $form->applyFilter('lastname', 'trim');
+    $form->addRule('lastname', get_lang('ThisFieldIsRequired'), 'required');
+    // Firstname
+    $form->addElement('text', 'firstname', get_lang('FirstName'));
+    $form->applyFilter('firstname', 'html_filter');
+    $form->applyFilter('firstname', 'trim');
+    $form->addRule('firstname', get_lang('ThisFieldIsRequired'), 'required');
 }
 
 // Official code
@@ -159,7 +157,7 @@ if (api_get_setting('login_is_email') == 'true') {
 
 // OpenID
 if (api_get_setting('openid_authentication') == 'true') {
-	$form->addElement('text', 'openid', get_lang('OpenIDURL'));
+    $form->addElement('text', 'openid', get_lang('OpenIDURL'));
 }
 
 // Phone
@@ -174,18 +172,18 @@ $form->addFile(
 $allowed_picture_types = api_get_supported_image_extensions(false);
 
 $form->addRule(
-	'picture',
-	get_lang('OnlyImagesAllowed').' ('.implode(',', $allowed_picture_types).')',
-	'filetype',
-	$allowed_picture_types
+    'picture',
+    get_lang('OnlyImagesAllowed').' ('.implode(',', $allowed_picture_types).')',
+    'filetype',
+    $allowed_picture_types
 );
 if (strlen($user_data['picture_uri']) > 0) {
-	$form->addElement('checkbox', 'delete_picture', '', get_lang('DelImage'));
+    $form->addElement('checkbox', 'delete_picture', '', get_lang('DelImage'));
 }
 
 // Username
 if (api_get_setting('login_is_email') != 'true') {
-	$form->addElement('text', 'username', get_lang('LoginName'), array('maxlength' => USERNAME_MAX_LENGTH));
+    $form->addElement('text', 'username', get_lang('LoginName'), array('maxlength' => USERNAME_MAX_LENGTH));
     $form->addRule('username', get_lang('ThisFieldIsRequired'), 'required');
     $form->addRule('username', sprintf(get_lang('UsernameMaxXCharacters'), (string) USERNAME_MAX_LENGTH), 'maxlength', USERNAME_MAX_LENGTH);
     $form->addRule('username', get_lang('OnlyLettersAndNumbersAllowed'), 'username');
@@ -259,15 +257,15 @@ $display = isset($user_data['status']) && ($user_data['status'] == STUDENT || (i
 
 // Platform admin
 if (api_is_platform_admin()) {
-	$group = array();
-	$group[] = $form->createElement('radio', 'platform_admin', null, get_lang('Yes'), 1);
-	$group[] = $form->createElement('radio', 'platform_admin', null, get_lang('No'), 0);
+    $group = array();
+    $group[] = $form->createElement('radio', 'platform_admin', null, get_lang('Yes'), 1);
+    $group[] = $form->createElement('radio', 'platform_admin', null, get_lang('No'), 0);
 
-	$user_data['status'] == 1 ? $display = 'block' : $display = 'none';
+    $user_data['status'] == 1 ? $display = 'block' : $display = 'none';
 
-	$form->addElement('html', '<div id="id_platform_admin" style="display:'.$display.'">');
-	$form->addGroup($group, 'admin', get_lang('PlatformAdmin'), null, false);
-	$form->addElement('html', '</div>');
+    $form->addElement('html', '<div id="id_platform_admin" style="display:'.$display.'">');
+    $form->addGroup($group, 'admin', get_lang('PlatformAdmin'), null, false);
+    $form->addElement('html', '</div>');
 }
 
 //Language
@@ -285,16 +283,16 @@ $date = sprintf(get_lang('CreatedByXYOnZ'), 'user_information.php?user_id='.$use
 $form->addElement('label', get_lang('RegistrationDate'), $date);
 
 if (!$user_data['platform_admin']) {
-	// Expiration Date
-	$form->addElement('radio', 'radio_expiration_date', get_lang('ExpirationDate'), get_lang('NeverExpires'), 0);
-	$group = array();
-	$group[] = $form->createElement('radio', 'radio_expiration_date', null, get_lang('Enabled'), 1);
-	$group[] = $form->createElement('DateTimePicker', 'expiration_date', null, array('onchange' => 'javascript: enable_expiration_date();'));
-	$form->addGroup($group, 'max_member_group', null, null, false);
-
-	// Active account or inactive account
-	$form->addElement('radio', 'active', get_lang('ActiveAccount'), get_lang('Active'), 1);
-	$form->addElement('radio', 'active', '', get_lang('Inactive'), 0);
+    // Expiration Date
+    $form->addElement('radio', 'radio_expiration_date', get_lang('ExpirationDate'), get_lang('NeverExpires'), 0);
+    $group = array();
+    $group[] = $form->createElement('radio', 'radio_expiration_date', null, get_lang('Enabled'), 1);
+    $group[] = $form->createElement('DateTimePicker', 'expiration_date', null, array('onchange' => 'javascript: enable_expiration_date();'));
+    $form->addGroup($group, 'max_member_group', null, null, false);
+
+    // Active account or inactive account
+    $form->addElement('radio', 'active', get_lang('ActiveAccount'), get_lang('Active'), 1);
+    $form->addElement('radio', 'active', '', get_lang('Inactive'), 0);
 }
 $studentBossList = UserManager::getStudentBossList($user_data['user_id']);
 
@@ -333,7 +331,7 @@ $jquery_ready_content = $returnParams['jquery_ready_content'];
 // the $jquery_ready_content variable collects all functions that will be load in the $(document).ready javascript function
 $htmlHeadXtra[] = '<script>
 $(document).ready(function(){
-	'.$jquery_ready_content.'
+    '.$jquery_ready_content.'
 });
 </script>';
 
@@ -345,18 +343,18 @@ $user_data['reset_password'] = 0;
 $expiration_date = $user_data['expiration_date'];
 
 if (empty($expiration_date)) {
-	$user_data['radio_expiration_date'] = 0;
-	$user_data['expiration_date'] = api_get_local_time();
+    $user_data['radio_expiration_date'] = 0;
+    $user_data['expiration_date'] = api_get_local_time();
 } else {
-	$user_data['radio_expiration_date'] = 1;
-	$user_data['expiration_date'] = api_get_local_time($expiration_date);
+    $user_data['radio_expiration_date'] = 1;
+    $user_data['expiration_date'] = api_get_local_time($expiration_date);
 }
 $form->setDefaults($user_data);
 
 $error_drh = false;
 // Validate form
 if ($form->validate()) {
-	$user = $form->getSubmitValues(1);
+    $user = $form->getSubmitValues(1);
     $reset_password = intval($user['reset_password']);
     if ($reset_password == 2 && empty($user['password'])) {
         Display::addFlash(Display::return_message(get_lang('PasswordIsTooShort')));
@@ -364,49 +362,49 @@ if ($form->validate()) {
         exit();
     }
 
-	$is_user_subscribed_in_course = CourseManager::is_user_subscribed_in_course($user['user_id']);
+    $is_user_subscribed_in_course = CourseManager::is_user_subscribed_in_course($user['user_id']);
 
-	if ($user['status'] == DRH && $is_user_subscribed_in_course) {
-		$error_drh = true;
-	} else {
-		$picture_element = $form->getElement('picture');
-		$picture = $picture_element->getValue();
+    if ($user['status'] == DRH && $is_user_subscribed_in_course) {
+        $error_drh = true;
+    } else {
+        $picture_element = $form->getElement('picture');
+        $picture = $picture_element->getValue();
 
-		$picture_uri = $user_data['picture_uri'];
-		if (isset($user['delete_picture']) && $user['delete_picture']) {
-			$picture_uri = UserManager::delete_user_picture($user_id);
-		} elseif (!empty($picture['name'])) {
+        $picture_uri = $user_data['picture_uri'];
+        if (isset($user['delete_picture']) && $user['delete_picture']) {
+            $picture_uri = UserManager::delete_user_picture($user_id);
+        } elseif (!empty($picture['name'])) {
             $picture_uri = UserManager::update_user_picture(
                 $user_id,
                 $_FILES['picture']['name'],
                 $_FILES['picture']['tmp_name'],
                 $user['picture_crop_result']
             );
-		}
+        }
 
-		$lastname = $user['lastname'];
-		$firstname = $user['firstname'];
+        $lastname = $user['lastname'];
+        $firstname = $user['firstname'];
         $password = $user['password'];
         $auth_source = isset($user['auth_source']) ? $user['auth_source'] : $userInfo['auth_source'];
-		$official_code = $user['official_code'];
-		$email = $user['email'];
-		$phone = $user['phone'];
-		$username = isset($user['username']) ? $user['username'] : $userInfo['username'];
-		$status = intval($user['status']);
-		$platform_admin = intval($user['platform_admin']);
-		$send_mail = intval($user['send_mail']);
-		$reset_password = intval($user['reset_password']);
-		$hr_dept_id = isset($user['hr_dept_id']) ? intval($user['hr_dept_id']) : null;
-		$language = $user['language'];
+        $official_code = $user['official_code'];
+        $email = $user['email'];
+        $phone = $user['phone'];
+        $username = isset($user['username']) ? $user['username'] : $userInfo['username'];
+        $status = intval($user['status']);
+        $platform_admin = intval($user['platform_admin']);
+        $send_mail = intval($user['send_mail']);
+        $reset_password = intval($user['reset_password']);
+        $hr_dept_id = isset($user['hr_dept_id']) ? intval($user['hr_dept_id']) : null;
+        $language = $user['language'];
         $address = isset($user['address']) ? $user['address'] : null;
 
-		if ($user['radio_expiration_date'] == '1' && !$user_data['platform_admin']) {
+        if ($user['radio_expiration_date'] == '1' && !$user_data['platform_admin']) {
             $expiration_date = $user['expiration_date'];
-		} else {
-			$expiration_date = null;
-		}
+        } else {
+            $expiration_date = null;
+        }
 
-		$active = $user_data['platform_admin'] ? 1 : intval($user['active']);
+        $active = $user_data['platform_admin'] ? 1 : intval($user['active']);
 
         //If the user is set to admin the status will be overwrite by COURSEMANAGER = 1
         if ($platform_admin == 1) {
@@ -449,33 +447,33 @@ if ($form->validate()) {
             );
         }
 
-		if (api_get_setting('openid_authentication') == 'true' && !empty($user['openid'])) {
-			$up = UserManager::update_openid($user_id, $user['openid']);
-		}
+        if (api_get_setting('openid_authentication') == 'true' && !empty($user['openid'])) {
+            $up = UserManager::update_openid($user_id, $user['openid']);
+        }
         $currentUserId = api_get_user_id();
 
         $userObj = api_get_user_entity($user_id);
 
         UserManager::add_user_as_admin($userObj);
 
-		if ($user_id != $currentUserId) {
-			if ($platform_admin == 1) {
-				$userObj = api_get_user_entity($user_id);
+        if ($user_id != $currentUserId) {
+            if ($platform_admin == 1) {
+                $userObj = api_get_user_entity($user_id);
                 UserManager::add_user_as_admin($userObj);
-			} else {
+            } else {
                 UserManager::remove_user_admin($user_id);
-			}
-		}
+            }
+        }
 
         $extraFieldValue = new ExtraFieldValue('user');
         $extraFieldValue->saveFieldValues($user);
 
-		$tok = Security::get_token();
+        $tok = Security::get_token();
 
         Display::addFlash(Display::return_message(get_lang('UserUpdated')));
-		header('Location: user_list.php?sec_token='.$tok);
-		exit();
-	}
+        header('Location: user_list.php?sec_token='.$tok);
+        exit();
+    }
 }
 
 if ($error_drh) {

+ 132 - 135
main/admin/user_export.php

@@ -1,7 +1,8 @@
 <?php
 /* For licensing terms, see /license.txt */
+
 /**
- *	@package chamilo.admin
+ * @package chamilo.admin
  */
 
 $cidReset = true;
@@ -18,15 +19,12 @@ $course_user_table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
 $session_course_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
 
 $tool_name = get_lang('ExportUserListXMLCSV');
-
 $interbreadcrumb[] = array("url" => 'index.php', "name" => get_lang('PlatformAdmin'));
 
 set_time_limit(0);
 $coursesSessions = [];
 $coursesSessions[''] = '--';
-
 $allCoursesFromSessions = SessionManager::getAllCoursesFromAllSessions();
-
 $coursesSessions = array_merge($coursesSessions, $allCoursesFromSessions);
 
 $courses = array();
@@ -36,27 +34,26 @@ $sql = "SELECT code,visual_code,title FROM $course_table ORDER BY visual_code";
 global $_configuration;
 
 if (api_is_multiple_url_enabled()) {
-	$tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
-	$access_url_id = api_get_current_access_url_id();
-	if ($access_url_id != -1) {
-	$sql = "SELECT code,visual_code,title
-		FROM $course_table as c
-		INNER JOIN $tbl_course_rel_access_url as course_rel_url
-		ON (c.id = course_rel_url.c_id)
-		WHERE access_url_id = $access_url_id
-		ORDER BY visual_code";
-	}
+    $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
+    $access_url_id = api_get_current_access_url_id();
+    if ($access_url_id != -1) {
+        $sql = "SELECT code,visual_code,title
+            FROM $course_table as c
+            INNER JOIN $tbl_course_rel_access_url as course_rel_url
+            ON (c.id = course_rel_url.c_id)
+            WHERE access_url_id = $access_url_id
+            ORDER BY visual_code";
+    }
 }
 $result = Database::query($sql);
 while ($course = Database::fetch_object($result)) {
-	$courses[$course->code] = $course->visual_code.' - '.$course->title;
+    $courses[$course->code] = $course->visual_code.' - '.$course->title;
 }
 $form = new FormValidator('export_users');
 $form->addElement('header', $tool_name);
 $form->addElement('radio', 'file_type', get_lang('OutputFileType'), 'XML', 'xml');
 $form->addElement('radio', 'file_type', null, 'CSV', 'csv');
 $form->addElement('radio', 'file_type', null, 'XLS', 'xls');
-
 $form->addElement('checkbox', 'addcsvheader', get_lang('AddCSVHeader'), get_lang('YesAddCSVHeader'), '1');
 $form->addElement('select', 'course_code', get_lang('OnlyUsersFromCourse'), $courses);
 $form->addElement('select', 'course_session', get_lang('OnlyUsersFromCourseSession'), $coursesSessions);
@@ -64,19 +61,19 @@ $form->addButtonExport(get_lang('Export'));
 $form->setDefaults(array('file_type' => 'csv'));
 
 if ($form->validate()) {
-	$export = $form->exportValues();
-	$file_type = $export['file_type'];
-	$course_code = Database::escape_string($export['course_code']);
-	$courseInfo = api_get_course_info($course_code);
+    $export = $form->exportValues();
+    $file_type = $export['file_type'];
+    $course_code = Database::escape_string($export['course_code']);
+    $courseInfo = api_get_course_info($course_code);
     $courseId = isset($courseInfo['real_id']) ? $courseInfo['real_id'] : 0;
 
-	$courseSessionValue = explode(':', $export['course_session']);
-	$courseSessionCode = '';
-	$sessionId = 0;
-	$courseSessionId = 0;
-	$sessionInfo = [];
+    $courseSessionValue = explode(':', $export['course_session']);
+    $courseSessionCode = '';
+    $sessionId = 0;
+    $courseSessionId = 0;
+    $sessionInfo = [];
 
-	if (is_array($courseSessionValue) && isset($courseSessionValue[1])) {
+    if (is_array($courseSessionValue) && isset($courseSessionValue[1])) {
         $courseSessionCode = $courseSessionValue[0];
         $sessionId = $courseSessionValue[1];
         $courseSessionInfo = api_get_course_info($courseSessionCode);
@@ -84,121 +81,121 @@ if ($form->validate()) {
         $sessionInfo = api_get_session_info($sessionId);
     }
 
-	$sql = "SELECT
-				u.user_id 	AS UserId,
-				u.lastname 	AS LastName,
-				u.firstname 	AS FirstName,
-				u.email 		AS Email,
-				u.username	AS UserName,
-				".(($_configuration['password_encryption'] != 'none') ? " " : "u.password AS Password, ")."
-				u.auth_source	AS AuthSource,
-				u.status		AS Status,
-				u.official_code	AS OfficialCode,
-				u.phone		AS Phone,
-				u.registration_date AS RegistrationDate";
-	if (strlen($course_code) > 0) {
-		$sql .= " FROM $user_table u, $course_user_table cu
-					WHERE
-						u.user_id = cu.user_id AND
-						cu.c_id = $courseId AND
-						cu.relation_type<>".COURSE_RELATION_TYPE_RRHH."
-					ORDER BY lastname,firstname";
-		$filename = 'export_users_'.$course_code.'_'.api_get_local_time();
-	} else if (strlen($courseSessionCode) > 0) {
+    $sql = "SELECT
+                u.user_id 	AS UserId,
+                u.lastname 	AS LastName,
+                u.firstname 	AS FirstName,
+                u.email 		AS Email,
+                u.username	AS UserName,
+                ".(($_configuration['password_encryption'] != 'none') ? " " : "u.password AS Password, ")."
+                u.auth_source	AS AuthSource,
+                u.status		AS Status,
+                u.official_code	AS OfficialCode,
+                u.phone		AS Phone,
+                u.registration_date AS RegistrationDate";
+    if (strlen($course_code) > 0) {
+        $sql .= " FROM $user_table u, $course_user_table cu
+                    WHERE
+                        u.user_id = cu.user_id AND
+                        cu.c_id = $courseId AND
+                        cu.relation_type<>".COURSE_RELATION_TYPE_RRHH."
+                    ORDER BY lastname,firstname";
+        $filename = 'export_users_'.$course_code.'_'.api_get_local_time();
+    } else if (strlen($courseSessionCode) > 0) {
         $sql .= " FROM $user_table u, $session_course_user_table scu
-					WHERE
-						u.user_id = scu.user_id AND
-						scu.c_id = $courseSessionId AND
-						scu.session_id = $sessionId 
-					ORDER BY lastname,firstname";
+                    WHERE
+                        u.user_id = scu.user_id AND
+                        scu.c_id = $courseSessionId AND
+                        scu.session_id = $sessionId 
+                    ORDER BY lastname,firstname";
         $filename = 'export_users_'.$courseSessionCode.'_'.$sessionInfo['name'].'_'.api_get_local_time();
     } else {
-		if (api_is_multiple_url_enabled()) {
-			$tbl_user_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
-			$access_url_id = api_get_current_access_url_id();
-			if ($access_url_id != -1) {
-			$sql .= " FROM $user_table u
-					INNER JOIN $tbl_user_rel_access_url as user_rel_url
-				ON (u.user_id= user_rel_url.user_id)
-				WHERE access_url_id = $access_url_id
-				ORDER BY lastname,firstname";
-			}
-		} else {
-			$sql .= " FROM $user_table u ORDER BY lastname,firstname";
-		}
-		$filename = 'export_users_'.api_get_local_time();
-	}
-	$data = array();
-	$extra_fields = UserManager::get_extra_fields(0, 0, 5, 'ASC', false);
-        
-        if (!empty($export['addcsvheader'])) {  
-	if ($export['addcsvheader'] == '1' && ($export['file_type'] == 'csv' || $export['file_type'] == 'xls' )) {
-		if ($_configuration['password_encryption'] != 'none') {
-			$data[] = array(
-                            'UserId',
-                            'LastName',
-                            'FirstName',
-                            'Email',
-                            'UserName',
-                            'AuthSource',
-                            'Status',
-                            'OfficialCode',
-                            'PhoneNumber',
-                            'RegistrationDate'
-			);
-		} else {
-			$data[] = array(
-                            'UserId',
-                            'LastName',
-                            'FirstName',
-                            'Email',
-                            'UserName',
-                            'Password',
-                            'AuthSource',
-                            'Status',
-                            'OfficialCode',
-                            'PhoneNumber',
-                            'RegistrationDate'
-			);
-		}
-
-		foreach ($extra_fields as $extra) {
-			$data[0][] = $extra[1];
-		}
+        if (api_is_multiple_url_enabled()) {
+            $tbl_user_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
+            $access_url_id = api_get_current_access_url_id();
+            if ($access_url_id != -1) {
+                $sql .= " FROM $user_table u
+                          INNER JOIN $tbl_user_rel_access_url as user_rel_url
+                          ON (u.user_id= user_rel_url.user_id)
+                          WHERE access_url_id = $access_url_id
+                          ORDER BY lastname,firstname";
             }
+        } else {
+            $sql .= " FROM $user_table u ORDER BY lastname,firstname";
         }
+        $filename = 'export_users_'.api_get_local_time();
+    }
+    $data = array();
+    $extra_fields = UserManager::get_extra_fields(0, 0, 5, 'ASC', false);
+
+    if (!empty($export['addcsvheader'])) {
+        if ($export['addcsvheader'] == '1' && ($export['file_type'] == 'csv' || $export['file_type'] == 'xls')) {
+            if ($_configuration['password_encryption'] != 'none') {
+                $data[] = array(
+                    'UserId',
+                    'LastName',
+                    'FirstName',
+                    'Email',
+                    'UserName',
+                    'AuthSource',
+                    'Status',
+                    'OfficialCode',
+                    'PhoneNumber',
+                    'RegistrationDate',
+                );
+            } else {
+                $data[] = array(
+                    'UserId',
+                    'LastName',
+                    'FirstName',
+                    'Email',
+                    'UserName',
+                    'Password',
+                    'AuthSource',
+                    'Status',
+                    'OfficialCode',
+                    'PhoneNumber',
+                    'RegistrationDate',
+                );
+            }
 
-	$res = Database::query($sql);
-	while ($user = Database::fetch_array($res, 'ASSOC')) {
-		$student_data = UserManager:: get_extra_user_data(
-			$user['UserId'],
-			true,
-			false
-		);
-		foreach ($student_data as $key=>$value) {
-			$key = substr($key, 6);
-			if (is_array($value)) {
-				$user[$key] = $value['extra_'.$key];
-			} else {
-				$user[$key] = $value;
-			}
-		}
-		$data[] = $user;
-	}
-
-	switch ($file_type) {
-		case 'xml':
-			Export::arrayToXml($data, $filename, 'Contact', 'Contacts');
-			exit;
-			break;
-		case 'csv':
-			Export::arrayToCsv($data, $filename);
-			exit;
-		case 'xls':
-			Export::arrayToXls($data, $filename);
-			exit;
-			break;
-	}
+            foreach ($extra_fields as $extra) {
+                $data[0][] = $extra[1];
+            }
+        }
+    }
+
+    $res = Database::query($sql);
+    while ($user = Database::fetch_array($res, 'ASSOC')) {
+        $student_data = UserManager:: get_extra_user_data(
+            $user['UserId'],
+            true,
+            false
+        );
+        foreach ($student_data as $key => $value) {
+            $key = substr($key, 6);
+            if (is_array($value)) {
+                $user[$key] = $value['extra_'.$key];
+            } else {
+                $user[$key] = $value;
+            }
+        }
+        $data[] = $user;
+    }
+
+    switch ($file_type) {
+        case 'xml':
+            Export::arrayToXml($data, $filename, 'Contact', 'Contacts');
+            exit;
+            break;
+        case 'csv':
+            Export::arrayToCsv($data, $filename);
+            exit;
+        case 'xls':
+            Export::arrayToXls($data, $filename);
+            exit;
+            break;
+    }
 }
 
 Display :: display_header($tool_name);

+ 4 - 3
main/admin/user_import.php

@@ -171,7 +171,8 @@ function complete_missing_data($user)
  * Save the imported data
  * @param   array   $users List of users
  * @return  void
- * @uses global variable $inserted_in_course, which returns the list of courses the user was inserted in
+ * @uses global variable $inserted_in_course, which returns the list of
+ * courses the user was inserted in
  */
 function save_data($users)
 {
@@ -531,8 +532,8 @@ if ($count_fields > 0) {
     }
 }
 ?>
-    <p><?php echo get_lang('CSVMustLookLike').' ('.get_lang('MandatoryFields').')'; ?> :</p>
-    <blockquote>
+<p><?php echo get_lang('CSVMustLookLike').' ('.get_lang('MandatoryFields').')'; ?> :</p>
+<blockquote>
 <pre>
 <b>LastName</b>;<b>FirstName</b>;<b>Email</b>;UserName;Password;AuthSource;OfficialCode;PhoneNumber;Status;ExpiryDate;<span style="color:red;"><?php if (count($list) > 0) echo implode(';', $list).';'; ?></span>Courses;ClassId;
 <b>xxx</b>;<b>xxx</b>;<b>xxx</b>;xxx;xxx;<?php echo implode('/', $defined_auth_sources); ?>;xxx;xxx;user/teacher/drh;0000-00-00 00:00:00;<span style="color:red;"><?php if (count($list_reponse) > 0) echo implode(';', $list_reponse).';'; ?></span>xxx1|xxx2|xxx3;1;<br />

+ 8 - 1
main/admin/user_list.php

@@ -824,7 +824,14 @@ if (!empty($action)) {
 
 // Create a search-box
 $form = new FormValidator('search_simple', 'get', null, null, null, 'inline');
-$form->addText('keyword', get_lang('Search'), false);
+$form->addText(
+    'keyword',
+    get_lang('Search'),
+    false,
+    array(
+        'aria-label' => get_lang("SearchUsers")
+    )
+);
 $form->addButtonSearch(get_lang('Search'));
 
 $searchAdvanced = '

+ 62 - 64
main/admin/user_move_stats.php

@@ -8,11 +8,11 @@
 
 $cidReset = true;
 require_once __DIR__.'/../inc/global.inc.php';
-$this_section=SECTION_PLATFORM_ADMIN;
+$this_section = SECTION_PLATFORM_ADMIN;
 
 api_protect_admin_script();
 
-$interbreadcrumb[] = array ("url" => 'index.php', "name" => get_lang('PlatformAdmin'));
+$interbreadcrumb[] = array("url" => 'index.php', "name" => get_lang('PlatformAdmin'));
 $debug = 0;
 
 function compare_data($result_message) {
@@ -31,7 +31,7 @@ function compare_data($result_message) {
         if (is_array($data)) {
             foreach ($data as $id => $item) {
 
-                if ($table == 'TRACK_E_EXERCISES' || $table == 'TRACK_E_EXERCISES_IN_LP' ) {
+                if ($table == 'TRACK_E_EXERCISES' || $table == 'TRACK_E_EXERCISES_IN_LP') {
                     echo "<br /><h3>".get_lang('Attempt')." #$id</h3>";
                     echo '<h3>';
                     echo get_lang('Exercise').' #'.$item['exe_exo_id'];
@@ -42,17 +42,17 @@ function compare_data($result_message) {
                         echo '</h3>';
                     }
                     //Process data
-                    $array = array('exe_date' =>get_lang('Date'), 'exe_result' =>get_lang('Score'),'exe_weighting'=>get_lang('Weighting'));
-                    foreach($item as $key=> $value) {
-                        if (in_array($key,array_keys($array))) {
+                    $array = array('exe_date' =>get_lang('Date'), 'exe_result' =>get_lang('Score'), 'exe_weighting'=>get_lang('Weighting'));
+                    foreach ($item as $key=> $value) {
+                        if (in_array($key, array_keys($array))) {
                             $key = $array[$key];
                             echo "$key =  $value <br />";
                         }
                     }
-                } else  {
+                } else {
                     echo "<br /><h3>".get_lang('Id')." #$id</h3>";
                     //process data
-                    foreach($item as $key=> $value) {
+                    foreach ($item as $key=> $value) {
                         echo "$key =  $value <br />";
                     }
                 }
@@ -77,7 +77,7 @@ if (isset($_REQUEST['load_ajax'])) {
             $session = $em->find('ChamiloCoreBundle:Session', $new_session_id);
 
             //if (!isset($_REQUEST['view_stat'])) {
-            if ($origin_session_id == $new_session_id ) {
+            if ($origin_session_id == $new_session_id) {
                 echo get_lang('CantMoveToTheSameSession');
                 exit;
             }
@@ -97,7 +97,7 @@ if (isset($_REQUEST['load_ajax'])) {
             $result_message_compare = array();
 
             $update_database = true;
-            if (isset($_REQUEST['view_stat']) && $_REQUEST['view_stat'] == 1 ) {
+            if (isset($_REQUEST['view_stat']) && $_REQUEST['view_stat'] == 1) {
                 $update_database = false;
             }
 
@@ -109,7 +109,7 @@ if (isset($_REQUEST['load_ajax'])) {
                 if (empty($result) || !in_array($user_id, array_keys($result))) {
                     if ($debug) echo 'User added to the session';
                     //Registering user to the new session
-                    SessionManager::subscribe_users_to_session($new_session_id,array($user_id),false);
+                    SessionManager::subscribe_users_to_session($new_session_id, array($user_id), false);
                 }
 
                 //Begin with the import process
@@ -124,7 +124,7 @@ if (isset($_REQUEST['load_ajax'])) {
                 $TBL_LP_VIEW                = Database::get_course_table(TABLE_LP_VIEW);
                 $TBL_NOTEBOOK               = Database::get_course_table(TABLE_NOTEBOOK);
                 $TBL_STUDENT_PUBLICATION    = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
-                $TBL_STUDENT_PUBLICATION_ASSIGNMENT    = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT);
+                $TBL_STUDENT_PUBLICATION_ASSIGNMENT = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT);
                 $TBL_ITEM_PROPERTY          = Database::get_course_table(TABLE_ITEM_PROPERTY);
 
                 $TBL_DROPBOX_FILE = Database::get_course_table(TABLE_DROPBOX_FILE);
@@ -138,8 +138,8 @@ if (isset($_REQUEST['load_ajax'])) {
                         WHERE c_id = $course_id AND  session_id = $origin_session_id AND exe_user_id = $user_id ";
                 $res = Database::query($sql);
                 $list = array();
-                while($row = Database::fetch_array($res,'ASSOC')) {
-                    $list[$row['exe_id']]= $row;
+                while ($row = Database::fetch_array($res, 'ASSOC')) {
+                    $list[$row['exe_id']] = $row;
                 }
 
                 if (!empty($list))
@@ -149,7 +149,7 @@ if (isset($_REQUEST['load_ajax'])) {
                             $res = Database::query($sql);
                             $result_message[$TABLETRACK_EXERCICES]++;
                         } else {
-                            if(!empty($data['orig_lp_id']) &&  !empty($data['orig_lp_item_id'])) {
+                            if (!empty($data['orig_lp_id']) && !empty($data['orig_lp_item_id'])) {
                                 $result_message['TRACK_E_EXERCISES'][$exe_id] = $data;
                             } else {
                                 $result_message['TRACK_E_EXERCISES_IN_LP'][$exe_id] = $data;
@@ -165,8 +165,8 @@ if (isset($_REQUEST['load_ajax'])) {
                             WHERE c_id = $course_id AND  session_id = $new_session_id AND exe_user_id = $user_id ";
                     $res = Database::query($sql);
                     $list = array();
-                    while($row = Database::fetch_array($res,'ASSOC')) {
-                        $list[$row['exe_id']]= $row;
+                    while ($row = Database::fetch_array($res, 'ASSOC')) {
+                        $list[$row['exe_id']] = $row;
                     }
 
                     if (!empty($list))
@@ -176,7 +176,7 @@ if (isset($_REQUEST['load_ajax'])) {
                                 $res = Database::query($sql);
                                 $result_message[$TABLETRACK_EXERCICES]++;
                             } else {
-                                if(!empty($data['orig_lp_id']) &&  !empty($data['orig_lp_item_id'])) {
+                                if (!empty($data['orig_lp_id']) && !empty($data['orig_lp_item_id'])) {
                                     $result_message_compare['TRACK_E_EXERCISES'][$exe_id] = $data;
                                 } else {
                                     $result_message_compare['TRACK_E_EXERCISES_IN_LP'][$exe_id] = $data;
@@ -193,7 +193,7 @@ if (isset($_REQUEST['load_ajax'])) {
                         WHERE c_id  = $course_id AND session_id = $origin_session_id  AND user_id = $user_id ";
                 $res = Database::query($sql);
                 $list = array();
-                while($row = Database::fetch_array($res,'ASSOC')) {
+                while ($row = Database::fetch_array($res, 'ASSOC')) {
                     $list[$row['course_access_id']] = $row;
                 }
 
@@ -216,7 +216,7 @@ if (isset($_REQUEST['load_ajax'])) {
                         AND access_user_id = $user_id ";
                 $res = Database::query($sql);
                 $list = array();
-                while($row = Database::fetch_array($res,'ASSOC')) {
+                while ($row = Database::fetch_array($res, 'ASSOC')) {
                     $list[] = $row['access_id'];
                 }
                 if (!empty($list))
@@ -242,7 +242,7 @@ if (isset($_REQUEST['load_ajax'])) {
                 $flat_list = $lp_list->get_flat_list();
 
                 $list = array();
-                while($row = Database::fetch_array($res,'ASSOC')) {
+                while ($row = Database::fetch_array($res, 'ASSOC')) {
                     //Checking if the LP exist in the new session
                     if (in_array($row['lp_id'], array_keys($flat_list))) {
                         $list[$row['id']] = $row;
@@ -259,8 +259,8 @@ if (isset($_REQUEST['load_ajax'])) {
                             $result_message[$TBL_LP_VIEW]++;
                         } else {
                             //Getting all information of that lp_item_id
-                            $score    = Tracking::get_avg_student_score($user_id, $origin_course_code, array($data['lp_id']),$origin_session_id);
-                            $progress = Tracking::get_avg_student_progress($user_id, $origin_course_code, array($data['lp_id']),$origin_session_id);
+                            $score    = Tracking::get_avg_student_score($user_id, $origin_course_code, array($data['lp_id']), $origin_session_id);
+                            $progress = Tracking::get_avg_student_progress($user_id, $origin_course_code, array($data['lp_id']), $origin_session_id);
                             $result_message['LP_VIEW'][$data['lp_id']] = array('score' => $score, 'progress' =>$progress);
                         }
                     }
@@ -276,7 +276,7 @@ if (isset($_REQUEST['load_ajax'])) {
                     $flat_list = $lp_list->get_flat_list();
 
                     $list = array();
-                    while($row = Database::fetch_array($res,'ASSOC')) {
+                    while ($row = Database::fetch_array($res, 'ASSOC')) {
                         //Checking if the LP exist in the new session
                         if (in_array($row['lp_id'], array_keys($flat_list))) {
                             $list[$row['id']] = $row;
@@ -285,8 +285,8 @@ if (isset($_REQUEST['load_ajax'])) {
                     if (!empty($list))
                         foreach ($list as $id=>$data) {
                             //Getting all information of that lp_item_id
-                            $score    = Tracking::get_avg_student_score($user_id, $origin_course_code,        array($data['lp_id']), $new_session_id);
-                            $progress = Tracking::get_avg_student_progress($user_id, $origin_course_code,     array($data['lp_id']), $new_session_id);
+                            $score    = Tracking::get_avg_student_score($user_id, $origin_course_code, array($data['lp_id']), $new_session_id);
+                            $progress = Tracking::get_avg_student_progress($user_id, $origin_course_code, array($data['lp_id']), $new_session_id);
                             $result_message_compare['LP_VIEW'][$data['lp_id']] = array('score' => $score, 'progress' =>$progress);
                         }
                 }
@@ -297,7 +297,7 @@ if (isset($_REQUEST['load_ajax'])) {
                 //calendar_event_attachment no problems no session_id
                 $sql = "SELECT ref FROM $TBL_ITEM_PROPERTY WHERE tool = 'calendar_event' AND insert_user_id = $user_id AND c_id = $course_id ";
                 $res = Database::query($sql);
-                while($row = Database::fetch_array($res,'ASSOC')) {
+                while ($row = Database::fetch_array($res, 'ASSOC')) {
                     $id = $row['ref'];
                     if ($update_database) {
                         $sql = "UPDATE $TBL_AGENDA SET session_id = $new_session_id WHERE c_id = $course_id AND id = $id ";
@@ -317,24 +317,24 @@ if (isset($_REQUEST['load_ajax'])) {
                 $sql = "SELECT ref FROM $TBL_ITEM_PROPERTY WHERE tool = 'work' AND insert_user_id = $user_id AND c_id = $course_id";
                 if ($debug) echo $sql;
                 $res = Database::query($sql);
-                while($row = Database::fetch_array($res,'ASSOC')) {
+                while ($row = Database::fetch_array($res, 'ASSOC')) {
                     $id = $row['ref'];
                     $sql = "SELECT * FROM $TBL_STUDENT_PUBLICATION WHERE id = $id AND session_id = $origin_session_id AND c_id = $course_id";
                     if ($debug) var_dump($sql);
                     $sub_res = Database::query($sql);
-                    if (Database::num_rows($sub_res) > 0 ) {
-                        $data = Database::fetch_array($sub_res,'ASSOC');
+                    if (Database::num_rows($sub_res) > 0) {
+                        $data = Database::fetch_array($sub_res, 'ASSOC');
                         if ($debug) var_dump($data);
                         $parent_id = $data['parent_id'];
                         if (isset($data['parent_id']) && !empty($data['parent_id'])) {
                             $sql = "SELECT * FROM $TBL_STUDENT_PUBLICATION WHERE id = $parent_id AND c_id = $course_id";
                             $select_res     = Database::query($sql);
-                            $parent_data    = Database::fetch_array($select_res,'ASSOC');
+                            $parent_data    = Database::fetch_array($select_res, 'ASSOC');
                             if ($debug)     var_dump($parent_data);
 
                             $sys_course_path = api_get_path(SYS_COURSE_PATH);
-                            $course_dir = $sys_course_path . $course_info['path'];
-                            $base_work_dir = $course_dir . '/work';
+                            $course_dir = $sys_course_path.$course_info['path'];
+                            $base_work_dir = $course_dir.'/work';
                             require_once api_get_path(SYS_CODE_PATH).'work/work.lib.php';
 
                             //Creating the parent folder in the session if does not exists already
@@ -349,8 +349,8 @@ if (isset($_REQUEST['load_ajax'])) {
                             $sub_res = Database::query($sql);
                             $num_rows = Database::num_rows($sub_res);
 
-                            if ($num_rows > 0 ) {
-                                $new_result = Database::fetch_array($sub_res,'ASSOC');
+                            if ($num_rows > 0) {
+                                $new_result = Database::fetch_array($sub_res, 'ASSOC');
                                 $created_dir    = $new_result['url'];
                                 $new_parent_id  = $new_result['id'];
                             } else {
@@ -368,7 +368,7 @@ if (isset($_REQUEST['load_ajax'])) {
                                             ->setCId($course_id)
                                             ->setTitle($parent_data['title'])
                                             ->setDescription(
-                                                $parent_data['description'] . "folder_moved_from_session_id_$origin_session_id"
+                                                $parent_data['description']."folder_moved_from_session_id_$origin_session_id"
                                             )
                                             ->setActive(false)
                                             ->setAccepted(true)
@@ -390,11 +390,11 @@ if (isset($_REQUEST['load_ajax'])) {
                             //Creating student_publication_assignment if exists
                             $sql = "SELECT * FROM $TBL_STUDENT_PUBLICATION_ASSIGNMENT WHERE publication_id = $parent_id AND c_id = $course_id";
                             if ($debug) var_dump($sql);
-                            $rest_select     = Database::query($sql);
-                            if (Database::num_rows($rest_select) > 0 ) {
+                            $rest_select = Database::query($sql);
+                            if (Database::num_rows($rest_select) > 0) {
                                 if ($update_database) {
-                                    $assignment_data = Database::fetch_array($rest_select,'ASSOC');
-                                    $sql_add_publication = "INSERT INTO " . $TBL_STUDENT_PUBLICATION_ASSIGNMENT . " SET
+                                    $assignment_data = Database::fetch_array($rest_select, 'ASSOC');
+                                    $sql_add_publication = "INSERT INTO ".$TBL_STUDENT_PUBLICATION_ASSIGNMENT." SET
                                     	c_id = '$course_id',
                                        expires_on          = '".$assignment_data['expires_on']."',
                                        ends_on              = '".$assignment_data['ends_on']."',
@@ -402,15 +402,15 @@ if (isset($_REQUEST['load_ajax'])) {
                                        enable_qualification = '".$assignment_data['enable_qualification']."',
                                        publication_id       = '".$new_parent_id."'";
                                     if ($debug) echo $sql_add_publication;
-                                    $rest_select     = Database::query($sql_add_publication);
+                                    $rest_select = Database::query($sql_add_publication);
                                     $id = Database::insert_id();
 
-                                    $sql_update = "UPDATE " . $TBL_STUDENT_PUBLICATION . " SET " .
+                                    $sql_update = "UPDATE ".$TBL_STUDENT_PUBLICATION." SET ".
                                         "has_properties         = '".$id."',
                                        view_properties    = '1'
                                        WHERE id   = ".$new_parent_id;
                                     if ($debug) echo $sql_update;
-                                    $rest_update     = Database::query($sql_update);
+                                    $rest_update = Database::query($sql_update);
 
 
                                     if ($debug) var_dump($sql_update);
@@ -430,7 +430,7 @@ if (isset($_REQUEST['load_ajax'])) {
                                     ->setUrl($new_url)
                                     ->setCId($course_id)
                                     ->setTitle($data['title'])
-                                    ->setDescription($data['description'] . ' file moved')
+                                    ->setDescription($data['description'].' file moved')
                                     ->setActive($data['active'])
                                     ->setAccepted($data['accepted'])
                                     ->setPostGroupId($data['post_group_id'])
@@ -455,7 +455,7 @@ if (isset($_REQUEST['load_ajax'])) {
                                         unlink($full_file_name);
                                         $sql = "DELETE FROM $TBL_STUDENT_PUBLICATION WHERE id= ".$data['id'];
                                         if ($debug) var_dump($sql);
-                                        $result_delete     = Database::query($sql);
+                                        $result_delete = Database::query($sql);
                                         api_item_property_update($course_info, 'work', $data['id'], 'DocumentDeleted', api_get_user_id());
                                     }
                                 }
@@ -472,7 +472,7 @@ if (isset($_REQUEST['load_ajax'])) {
                 $sql = "SELECT id FROM $TBL_DROPBOX_FILE WHERE uploader_id = $user_id AND session_id = $origin_session_id AND c_id = $course_id";
                 if ($debug) var_dump($sql);
                 $res = Database::query($sql);
-                while($row = Database::fetch_array($res,'ASSOC')) {
+                while ($row = Database::fetch_array($res, 'ASSOC')) {
                     $id = $row['id'];
                     if ($update_database) {
                         $sql = "UPDATE $TBL_DROPBOX_FILE SET session_id = $new_session_id WHERE c_id = $course_id AND id = $id";
@@ -496,7 +496,7 @@ if (isset($_REQUEST['load_ajax'])) {
                         WHERE user_id = $user_id AND session_id = $origin_session_id AND course = '$origin_course_code' AND c_id = $course_id";
                 if ($debug) var_dump($sql);
                 $res = Database::query($sql);
-                while($row = Database::fetch_array($res,'ASSOC')) {
+                while ($row = Database::fetch_array($res, 'ASSOC')) {
                     $id = $row['notebook_id'];
                     if ($update_database) {
                         $sql = "UPDATE $TBL_NOTEBOOK SET session_id = $new_session_id WHERE c_id = $course_id AND notebook_id = $id";
@@ -520,7 +520,7 @@ if (isset($_REQUEST['load_ajax'])) {
                     echo '<tr>';
                     echo '<td width="50%" valign="top">';
 
-                    if ($origin_session_id == 0 ) {
+                    if ($origin_session_id == 0) {
                         echo '<h4>'.get_lang('OriginCourse').'</h4>';
                     } else {
                         echo '<h4>'.get_lang('OriginSession').' #'.$origin_session_id.'</h4>';
@@ -528,7 +528,7 @@ if (isset($_REQUEST['load_ajax'])) {
                     compare_data($result_message);
                     echo '</td>';
                     echo '<td width="50%" valign="top">';
-                    if ($new_session_id == 0 ) {
+                    if ($new_session_id == 0) {
                         echo '<h4>'.get_lang('DestinyCourse').'</h4>';
                     } else {
                         echo '<h4>'.get_lang('DestinySession').' #'.$new_session_id.'</h4>';
@@ -592,19 +592,17 @@ function get_courses_list_by_user_id_based_in_exercises($user_id) {
 
     $res = Database::query($sql);
     $course_list = array();
-    while ($row = Database::fetch_array($res,'ASSOC')) {
-        $course_list []= $row;
+    while ($row = Database::fetch_array($res, 'ASSOC')) {
+        $course_list [] = $row;
     }
     return $course_list;
 }
 
-
+Display::addFlash(Display::return_message(get_lang('CompareUserResultsBetweenCoursesAndCoursesInASession'), 'normal', false));
 Display::display_header(get_lang('MoveUserStats'));
 echo  '<div class="actions">';
-echo '<a href="../admin/index.php">'.Display::return_icon('back.png', get_lang('BackTo').' '.get_lang('PlatformAdmin'),'',ICON_SIZE_MEDIUM).'</a>';
+echo '<a href="../admin/index.php">'.Display::return_icon('back.png', get_lang('BackTo').' '.get_lang('PlatformAdmin'), '', ICON_SIZE_MEDIUM).'</a>';
 echo '</div>';
-Display::addFlash(Display::return_message(get_lang('CompareUserResultsBetweenCoursesAndCoursesInASession'), 'normal', false));
-
 
 // Some pagination
 $page = 1;
@@ -613,19 +611,19 @@ if (isset($_GET['page']) && !empty($_GET['page'])) {
 }
 $default = 20;
 $count          = UserManager::get_number_of_users();
-$nro_pages      = round($count/$default) + 1;
-$begin          = $default* ($page - 1);
-$end            = $default*$page;
+$nro_pages      = round($count / $default) + 1;
+$begin          = $default * ($page - 1);
+$end            = $default * $page;
 
 $navigation     = "$begin - $end  / $count<br />";
 
 if ($page > 1) {
-    $navigation .='<a href="'.api_get_self().'?page='.($page - 1).'">'.get_lang('Previous').'</a>';
+    $navigation .= '<a href="'.api_get_self().'?page='.($page - 1).'">'.get_lang('Previous').'</a>';
 } else {
     $navigation .= get_lang('Previous');
 }
 $navigation .= '&nbsp;';
-$page ++;
+$page++;
 if ($page < $nro_pages)
     $navigation .= '<a href="'.api_get_self().'?page='.$page.'">'.get_lang('Next').'</a>';
 else
@@ -633,11 +631,11 @@ else
 
 echo $navigation;
 $user_list      = UserManager::get_user_list(array(), array(), $begin, $default);
-$session_list   = SessionManager::get_sessions_list(array(),array('name'));
+$session_list   = SessionManager::get_sessions_list(array(), array('name'));
 $options = '';
 $options .= '<option value="0">--'.get_lang('SelectASession').'--</option>';
 foreach ($session_list as $session_data) {
-    $my_session_list[$session_data['id']] =$session_data['name'];
+    $my_session_list[$session_data['id']] = $session_data['name'];
     $options .= '<option value="'.$session_data['id'].'">'.$session_data['name'].'</option>';
 }
 
@@ -686,7 +684,7 @@ if (!empty($user_list)) {
             $course['name'] = $courseInfo['name'];
         }
 
-        $course_list  = $course_list_registered;
+        $course_list = $course_list_registered;
 
         echo '<div>';
         echo '<table class="data_table">';
@@ -721,7 +719,7 @@ if (!empty($user_list)) {
                     $session_id = $course['id_session'];
                 }
                 echo '<td>';
-                echo get_lang('MoveTo');    echo '<br />';
+                echo get_lang('MoveTo'); echo '<br />';
                 $unique_id = uniqid();
                 $combinations[$unique_id] = array('course_code' =>$course_code, 'session_id'=>$session_id);
 

+ 1 - 1
main/admin/user_update_import.php

@@ -424,7 +424,7 @@ if (isset($_POST['formSent']) && $_POST['formSent'] && $_FILES['import_file']['s
 Display :: display_header($tool_name);
 
 if (!empty($error_message)) {
-    Display::display_error_message($error_message);
+    echo Display::return_message($error_message, 'error');
 }
 
 $form = new FormValidator('user_update_import', 'post', api_get_self());

+ 3 - 3
main/admin/usergroup_import.php

@@ -90,9 +90,6 @@ $interbreadcrumb[] = array('url' => 'usergroups.php', 'name' => get_lang('Classe
 // Setting the name of the tool.
 $tool_name = get_lang('ImportClassListCSV');
 
-// Displaying the header.
-Display :: display_header($tool_name);
-
 set_time_limit(0);
 
 $form = new FormValidator('import_classes');
@@ -127,6 +124,9 @@ if ($form->validate()) {
     }
 }
 
+// Displaying the header.
+Display :: display_header($tool_name);
+
 $form->display();
 ?>
 <p><?php echo get_lang('CSVMustLookLike').' ('.get_lang('MandatoryFields').')'; ?> :</p>

+ 1 - 1
main/admin/usergroup_user_import.php

@@ -168,7 +168,7 @@ if (count($errors) != 0) {
         $error_message .= "<br />";
     }
     $error_message .= "\n";
-    Display :: display_error_message($error_message, false);
+    echo Display::return_message($error_message, 'error', false);
 }
 $form->display();
 ?>

+ 1 - 1
main/announcements/announcements.php

@@ -485,7 +485,7 @@ switch ($action) {
 
         $defaults['email_ann'] = true;
 
-        $form->addElement('text', 'title', get_lang('EmailTitle'));
+        $form->addElement('text', 'title', get_lang('EmailTitle'), array("onkeypress" => "return event.keyCode != 13;")); //do not submit on enter
         $form->addRule('title', get_lang('ThisFieldIsRequired'), 'required');
         $form->addElement('hidden', 'id');
         $htmlTags = "<b>".get_lang('Tags')."</b><br /><br />";

+ 1 - 1
main/attendance/attendance_add.php

@@ -12,7 +12,7 @@ api_protect_course_script(true);
 
 // error messages
 if (isset($error)) {
-    Display::display_error_message(get_lang('FormHasErrorsPleaseComplete'), false);
+    echo Display::return_message(get_lang('FormHasErrorsPleaseComplete'), 'error', false);
 }
 
 if (!isset($error)) {

+ 3 - 3
main/attendance/attendance_calendar.php

@@ -33,17 +33,17 @@ $message_information = get_lang('AttendanceCalendarDescription');
 if (!empty($message_information)) {
     $message = '<strong>'.get_lang('Information').'</strong><br />';
     $message .= $message_information;
-    Display::addFlash(Display::return_message($message, 'normal', false));
+    echo Display::return_message($message, 'normal', false);
 }
 
 if (isset($error_repeat_date) && $error_repeat_date) {
     $message = get_lang('EndDateMustBeMoreThanStartDate');
-    Display::addFlash(Display::return_message($message, 'error', false));
+    echo Display::return_message($message, 'error', false);
 }
 
 if (isset($error_checkdate) && $error_checkdate) {
     $message = get_lang('InvalidDate');
-    Display::addFlash(Display::return_message($message, 'error', false));
+    echo Display::return_message($message, 'error', false);
 }
 
 if (isset($action) && $action == 'calendar_add') {

+ 1 - 1
main/attendance/attendance_edit.php

@@ -12,7 +12,7 @@ api_protect_course_script(true);
 
 // error messages
 if (isset($error)) {
-    Display::display_error_message(get_lang('FormHasErrorsPleaseComplete'), false);
+    echo Display::return_message(get_lang('FormHasErrorsPleaseComplete'), 'error', false);
 }
 
 if (!isset($error)) {

+ 5 - 4
main/attendance/attendance_sheet.php

@@ -64,7 +64,7 @@ if (api_is_allowed_to_edit(null, true) ||
     }
 
     if (!$exists_attendance_today) {
-        Display::addFlash(Display::return_message(get_lang('ThereIsNoClassScheduledTodayTryPickingAnotherDay'), 'warning'));
+        echo Display::return_message(get_lang('ThereIsNoClassScheduledTodayTryPickingAnotherDay'), 'warning');
     }
 
     $form->addSelect(
@@ -118,11 +118,11 @@ if (api_is_allowed_to_edit(null, true) ||
     if (!empty($message_information)) {
         $message = '<strong>'.get_lang('Information').'</strong><br />';
         $message .= $message_information;
-        Display::addFlash(Display::return_message($message, 'normal', false));
+        echo Display::return_message($message, 'normal', false);
     }
 
     if ($is_locked_attendance) {
-        Display::addFlash(Display::return_message(get_lang('TheAttendanceSheetIsLocked'), 'warning', false));
+        echo Display::return_message(get_lang('TheAttendanceSheetIsLocked'), 'warning', false);
     }
 
     $param_filter = '&filter='.Security::remove_XSS($default_filter).'&group_id='.$groupId;
@@ -407,9 +407,10 @@ if (api_is_allowed_to_edit(null, true) ||
         </form>
     <?php
     } else {
-        echo Display::display_warning_message(
+        echo Display::return_message(
             '<a href="'.api_get_path(WEB_CODE_PATH).'user/user.php?'.api_get_cidreq().'">'.
             get_lang('ThereAreNoRegisteredLearnersInsidetheCourse').'</a>',
+            'warning',
             false
         );
     }

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است