diff --git a/app/controllers/admin/domain.php b/app/controllers/admin/domain.php
index e4bb9c8695e7348829b612a60d51794e992a4d1f..37ab11f29bb29b048bf491270566ab766bd9f0cb 100644
--- a/app/controllers/admin/domain.php
+++ b/app/controllers/admin/domain.php
@@ -70,7 +70,7 @@ class Admin_DomainController extends AuthenticatedController
     {
         foreach ($args as $arg) {
             if ($arg && !preg_match('/' . UserDomain::REGEXP . '/', $arg)) {
-                throw new Trails_Exception(400);
+                throw new Trails\Exception(400);
             }
         }
 
diff --git a/app/controllers/admin/install.php b/app/controllers/admin/install.php
index 9ede078859ab3b23d7f548f6ee3b1d81089153da..e45c281e128e40811150208fe86d1aa34820b4c0 100644
--- a/app/controllers/admin/install.php
+++ b/app/controllers/admin/install.php
@@ -1,7 +1,7 @@
 <?php
 require_once __DIR__ . '/../../../lib/classes/StudipControllerPropertiesTrait.php';
 
-class Admin_InstallController extends Trails_Controller
+class Admin_InstallController extends Trails\Controller
 {
     use StudipControllerPropertiesTrait;
 
diff --git a/app/controllers/admin/lockrules.php b/app/controllers/admin/lockrules.php
index 56879febfb5c879c5a55c3b3ef6bd1c81106606e..202a2e9b71188684e529066f667eb12aeba7b667 100644
--- a/app/controllers/admin/lockrules.php
+++ b/app/controllers/admin/lockrules.php
@@ -164,7 +164,7 @@ class Admin_LockrulesController extends AuthenticatedController
     {
         $this->lock_rule = LockRule::find($lock_rule_id);
         if (!(!$this->lock_rule->isNew() && ($GLOBALS['perm']->have_perm('root') || $this->lock_rule->user_id === $GLOBALS['user']->id))) {
-            throw new Trails_Exception(403);
+            throw new Trails\Exception(403);
         }
         CSRFProtection::verifyUnsafeRequest();
         if ($this->lock_rule->delete()) {
@@ -186,4 +186,4 @@ class Admin_LockrulesController extends AuthenticatedController
         }
         return $this->lock_rule->store();
     }
-}
\ No newline at end of file
+}
diff --git a/app/controllers/api/oauth2/applications.php b/app/controllers/api/oauth2/applications.php
index d08ec1e9bdaeb78b487133b643b630022e576d92..fd6a1bb7b7508eef3703ff98734b24b412a0ce69 100644
--- a/app/controllers/api/oauth2/applications.php
+++ b/app/controllers/api/oauth2/applications.php
@@ -31,7 +31,7 @@ class Api_Oauth2_ApplicationsController extends AuthenticatedController
         $this->application = $this->formatApplication($accessToken);
 
         if (!$this->application) {
-            throw new Trails_Exception(500, 'Error finding client.');
+            throw new Trails\Exception(500, 'Error finding client.');
         }
     }
 
@@ -42,7 +42,7 @@ class Api_Oauth2_ApplicationsController extends AuthenticatedController
         $user = User::findCurrent();
         $accessToken = AccessToken::find(Request::option('application'));
         if (!$accessToken) {
-            throw new Trails_Exception(404);
+            throw new Trails\Exception(404);
         }
         if ($accessToken['user_id'] !== $user->id) {
             throw new AccessDeniedException();
diff --git a/app/controllers/api/oauth2/authorize.php b/app/controllers/api/oauth2/authorize.php
index 5628d49563dfa1e058fd7999aca8fb21e458b8b0..451b766a53f7c8c1056d22cf9f1d8e78feaf0940 100644
--- a/app/controllers/api/oauth2/authorize.php
+++ b/app/controllers/api/oauth2/authorize.php
@@ -13,7 +13,7 @@ class Api_Oauth2_AuthorizeController extends OAuth2Controller
         parent::before_filter($action, $args);
 
         if ('index' !== $action) {
-            throw new Trails_Exception(404);
+            throw new Trails\Exception(404);
         }
 
         $action = $this->determineAction();
diff --git a/app/controllers/api/oauth2/oauth2_controller.php b/app/controllers/api/oauth2/oauth2_controller.php
index fd02ea9ee19384fb7cedf07fe2a4adcf6837dd90..6b3dacd37158609030c11bcd9fd21bd432bcea4c 100644
--- a/app/controllers/api/oauth2/oauth2_controller.php
+++ b/app/controllers/api/oauth2/oauth2_controller.php
@@ -42,7 +42,7 @@ abstract class OAuth2Controller extends StudipController
             return $this->convertPsrResponse($psrResponse);
         }
 
-        return new Trails_Response($exception->getMessage(), [], 500);
+        return new Trails\Response($exception->getMessage(), [], 500);
     }
 
     protected function getAuthorizationServer(): AuthorizationServer
diff --git a/app/controllers/api/oauth2/token.php b/app/controllers/api/oauth2/token.php
index 0ae7ffbd2d87fe3bf73155e9568421495bc5c5c4..755d6b722f00b01eb29f1b7d305ca2c18cbb9cc9 100644
--- a/app/controllers/api/oauth2/token.php
+++ b/app/controllers/api/oauth2/token.php
@@ -8,11 +8,11 @@ class Api_Oauth2_TokenController extends OAuth2Controller
         parent::before_filter($action, $args);
 
         if ('index' !== $action) {
-            throw new Trails_Exception(404);
+            throw new Trails\Exception(404);
         }
 
         if (!Request::isPost()) {
-            throw new Trails_Exception(405);
+            throw new Trails\Exception(405);
         }
 
         $action = 'issue_token';
diff --git a/app/controllers/contents/courseware.php b/app/controllers/contents/courseware.php
index c1d807f314d71aa22f2434db3b5ba7317f9d4220..d4291df6abba08be15faa8b7a0e4abf9150abd1f 100644
--- a/app/controllers/contents/courseware.php
+++ b/app/controllers/contents/courseware.php
@@ -311,7 +311,7 @@ class Contents_CoursewareController extends CoursewareController
         );
 
         if (!$struct) {
-            throw new Trails_Exception(404, _('Der geteilte Inhalt kann nicht gefunden werden.'));
+            throw new Trails\Exception(404, _('Der geteilte Inhalt kann nicht gefunden werden.'));
         }
 
         if (!$struct->canRead($user) && !$struct->canEdit($user)) {
diff --git a/app/controllers/course/admission.php b/app/controllers/course/admission.php
index 56342bb78fe5eccffd5782102a55f64ca7dfba2c..14a9b200b831c2c4fdf27f4e0ccbf1010af7d87f 100644
--- a/app/controllers/course/admission.php
+++ b/app/controllers/course/admission.php
@@ -31,7 +31,7 @@ class Course_AdmissionController extends AuthenticatedController
         if (!get_object_type($this->course_id, ['sem']) ||
             SeminarCategories::GetBySeminarId($this->course_id)->studygroup_mode ||
             !$GLOBALS['perm']->have_studip_perm('tutor', $this->course_id)) {
-            throw new Trails_Exception(403);
+            throw new Trails\Exception(403);
         }
 
         $this->course = Course::find($this->course_id);
@@ -488,7 +488,7 @@ class Course_AdmissionController extends AuthenticatedController
             }
             $this->course_set_name = $course_set->getName();
         } else {
-            throw new Trails_Exception(400);
+            throw new Trails\Exception(400);
         }
     }
 
@@ -503,7 +503,7 @@ class Course_AdmissionController extends AuthenticatedController
                 $this->redirect($response->headers['Location']);
             }
         } else {
-            throw new Trails_Exception(403);
+            throw new Trails\Exception(403);
         }
     }
 
@@ -518,7 +518,7 @@ class Course_AdmissionController extends AuthenticatedController
                 $this->redirect($response->headers['Location']);
             }
         } else {
-            throw new Trails_Exception(403);
+            throw new Trails\Exception(403);
         }
     }
 
diff --git a/app/controllers/course/block_appointments.php b/app/controllers/course/block_appointments.php
index fef0d31b691ca677f73bb25ba9a9cdb2c82552d8..ad28b1e140b10a6621e6d654d4ade710e9646e06 100644
--- a/app/controllers/course/block_appointments.php
+++ b/app/controllers/course/block_appointments.php
@@ -33,7 +33,7 @@ class Course_BlockAppointmentsController extends AuthenticatedController
             SeminarCategories::GetBySeminarId($this->course_id)->studygroup_mode ||
             !$GLOBALS['perm']->have_studip_perm("tutor", $this->course_id)
         ) {
-            throw new Trails_Exception(400);
+            throw new Trails\Exception(400);
         }
         PageLayout::setHelpKeyword('Basis.VeranstaltungenVerwaltenAendernVonZeitenUndTerminen');
         PageLayout::setTitle(Course::findCurrent()->getFullName() . " - " . _('Blockveranstaltungstermine anlegen'));
diff --git a/app/controllers/course/cancel_dates.php b/app/controllers/course/cancel_dates.php
index 0d5463cf86c7e419bc244a6255783c86b8bf687a..8da0d09818f87cddc7d2514dd7cf8c5827097a70 100644
--- a/app/controllers/course/cancel_dates.php
+++ b/app/controllers/course/cancel_dates.php
@@ -39,7 +39,7 @@ class Course_CancelDatesController extends AuthenticatedController
             $this->course_id = $this->dates[0]->range_id;
         }
         if (!get_object_type($this->course_id, ['sem']) || !$perm->have_studip_perm("tutor", $this->course_id)) {
-            throw new Trails_Exception(400);
+            throw new Trails\Exception(400);
         }
         PageLayout::setHelpKeyword('Basis.VeranstaltungenVerwaltenAendernVonZeitenUndTerminen');
         PageLayout::setTitle(Course::findCurrent()->getFullName() . " - " . _('Veranstaltungstermine absagen'));
diff --git a/app/controllers/course/change_view.php b/app/controllers/course/change_view.php
index 156a68a8fc77f88d6b64580bfeb8f893165bd419..63395b6758f9bfeaf4e1539564a57620cbe1ccd8 100644
--- a/app/controllers/course/change_view.php
+++ b/app/controllers/course/change_view.php
@@ -16,7 +16,6 @@
  */
 class Course_ChangeViewController extends AuthenticatedController
 {
-    // see Trails_Controller#before_filter
     public function before_filter(&$action, &$args)
     {
         parent::before_filter($action, $args);
@@ -28,7 +27,7 @@ class Course_ChangeViewController extends AuthenticatedController
      * Sets the current course into participant view.
      * Only available for tutor upwards.
      *
-     * @throws Trails_Exception Someone with unfitting rights tried to call here.
+     * @throws Trails\Exception Someone with unfitting rights tried to call here.
      */
     public function set_changed_view_action()
     {
@@ -43,7 +42,7 @@ class Course_ChangeViewController extends AuthenticatedController
      * Resets a course currently in participant view to normal view
      * with real rights.
      *
-     * @throws Trails_Exception Someone with unfitting rights tried to call here.
+     * @throws Trails\Exception Someone with unfitting rights tried to call here.
      */
     public function reset_changed_view_action()
     {
diff --git a/app/controllers/course/details.php b/app/controllers/course/details.php
index 2a330e3dfcc12c3d4de318de9eb73a08b5e57284..e1c9493ada803dccbdc4a0e227eca9ef1369a269 100644
--- a/app/controllers/course/details.php
+++ b/app/controllers/course/details.php
@@ -32,7 +32,7 @@ class Course_DetailsController extends AuthenticatedController
 
         $this->course = Course::find($course_id);
         if (!$this->course) {
-            throw new Trails_Exception(
+            throw new Trails\Exception(
                 404,
                 _('Es konnte keine Veranstaltung gefunden werden')
             );
diff --git a/app/controllers/course/enrolment.php b/app/controllers/course/enrolment.php
index eb4428e197ac149e0d5a8bbb574a55570c2b89ff..420b5ca91bc86bad618f8fbce6024c55642a038c 100644
--- a/app/controllers/course/enrolment.php
+++ b/app/controllers/course/enrolment.php
@@ -37,7 +37,7 @@ class Course_EnrolmentController extends AuthenticatedController
             return false;
         }
         if (!get_object_type($this->course_id, ['sem'])) {
-            throw new Trails_Exception(400);
+            throw new Trails\Exception(400);
         }
         $course = Seminar::GetInstance($this->course_id);
         $enrolment_info = $course->getEnrolmentInfo($GLOBALS['user']->id);
diff --git a/app/controllers/course/forum/forum_controller.php b/app/controllers/course/forum/forum_controller.php
index 71d1aa094feec94a3e7b4488f4376a403213647b..65eec638beeebd06d54c29fb17f8d644dcbf5a27 100644
--- a/app/controllers/course/forum/forum_controller.php
+++ b/app/controllers/course/forum/forum_controller.php
@@ -23,7 +23,7 @@ abstract class ForumController extends StudipController {
 
         parent::before_filter($action, $args);
 
-        $this->flash = Trails_Flash::instance();
+        $this->flash = Trails\Flash::instance();
 
         // Set help keyword for Stud.IP's user-documentation and page title
         PageLayout::setHelpKeyword('Basis.Forum');
diff --git a/app/controllers/course/gradebook/lecturers.php b/app/controllers/course/gradebook/lecturers.php
index b3b1f820e9e765a16d21e08f140b84a926570304..7ab02e7f9babe7e3a6d87591226fd9c6afd2064f 100644
--- a/app/controllers/course/gradebook/lecturers.php
+++ b/app/controllers/course/gradebook/lecturers.php
@@ -258,7 +258,7 @@ class Course_Gradebook_LecturersController extends AuthenticatedController
     public function edit_custom_definition_action($definitionId)
     {
         if (!$this->definition = Definition::findOneBySQL('id = ? AND course_id = ?', [$definitionId, \Context::getId()])) {
-            throw new \Trails_Exception(404);
+            throw new \Trails\Exception(404);
         }
 
         // show template
@@ -271,7 +271,7 @@ class Course_Gradebook_LecturersController extends AuthenticatedController
     {
         CSRFProtection::verifyUnsafeRequest();
         if (!$definition = Definition::findOneBySQL('id = ? AND course_id = ?', [$definitionId, \Context::getId()])) {
-            throw new \Trails_Exception(404);
+            throw new \Trails\Exception(404);
         }
 
         $name = trim(\Request::get('name', ''));
diff --git a/app/controllers/course/lvgselector.php b/app/controllers/course/lvgselector.php
index 171f3d524220464b5c67b6fc14df21dd32ec4a19..c8223a99827a5fc2278062aba4c3ef316593ab5f 100644
--- a/app/controllers/course/lvgselector.php
+++ b/app/controllers/course/lvgselector.php
@@ -17,15 +17,13 @@ require 'config/mvv_config.php';
 
 class Course_LvgselectorController extends AuthenticatedController
 {
-
-    // see Trails_Controller#before_filter
     public function before_filter(&$action, &$args)
     {
         parent::before_filter($action, $args);
 
         $this->course = Course::findCurrent();
         if (!$this->course) {
-            throw new Trails_Exception(404, _('Es wurde keine Veranstaltung ausgewählt!'));
+            throw new Trails\Exception(404, _('Es wurde keine Veranstaltung ausgewählt!'));
         }
         $this->course_id = $this->course->id;
         if (!$GLOBALS['perm']->have_studip_perm('tutor', $this->course_id)) {
diff --git a/app/controllers/course/members.php b/app/controllers/course/members.php
index 3eae083e5f552e7e168bf7d1b6f60e62ddd376c4..1ec1587abd932e6a27cbdaa24b58967f6283a563 100644
--- a/app/controllers/course/members.php
+++ b/app/controllers/course/members.php
@@ -232,7 +232,7 @@ class Course_MembersController extends AuthenticatedController
             $course_member = AdmissionApplication::find([$user_id, $this->course_id]);
         }
         if (is_null($course_member)) {
-            throw new Trails_Exception(400);
+            throw new Trails\Exception(400);
         }
         $this->comment = $course_member->comment;
         $this->user = User::find($user_id);
@@ -265,7 +265,7 @@ class Course_MembersController extends AuthenticatedController
             $course_member = AdmissionApplication::find([$user_id, $this->course_id]);
         }
         if (!Request::submitted('save') || is_null($course_member)) {
-            throw new Trails_Exception(400);
+            throw new Trails\Exception(400);
         }
         $course_member->comment = Request::get('comment');
 
diff --git a/app/controllers/course/room_requests.php b/app/controllers/course/room_requests.php
index a31e61ab5804207ae584fc5106ceffcf1a29c21a..926e000a441161df5644ef8cf98a472082426ec6 100644
--- a/app/controllers/course/room_requests.php
+++ b/app/controllers/course/room_requests.php
@@ -46,7 +46,7 @@ class Course_RoomRequestsController extends AuthenticatedController
             SeminarCategories::GetBySeminarId($this->course_id)->studygroup_mode ||
             !$GLOBALS['perm']->have_studip_perm("tutor", $this->course_id)
         ) {
-            throw new Trails_Exception(400);
+            throw new Trails\Exception(400);
         }
 
         PageLayout::setHelpKeyword('Basis.VeranstaltungenVerwaltenAendernVonZeitenUndTerminen');
@@ -663,7 +663,7 @@ class Course_RoomRequestsController extends AuthenticatedController
     {
         $request = RoomRequest::find($request_id);
         if (!$request) {
-            throw new Trails_Exception(403);
+            throw new Trails\Exception(403);
         }
         if (Request::isGet()) {
             PageLayout::postQuestion(sprintf(
diff --git a/app/controllers/course/scm.php b/app/controllers/course/scm.php
index 66af981b4ce7e7389f87aecc4472481b0eab437a..4c5d4ebb071da396f106bb33dace090973c3819b 100644
--- a/app/controllers/course/scm.php
+++ b/app/controllers/course/scm.php
@@ -93,7 +93,7 @@ class Course_ScmController extends AuthenticatedController
         $this->scm  = $id ? $this->scms->find($id) : $this->scms->first();
 
         if (!$this->scm && $this->scms->count() > 0) {
-            throw new Trails_Exception(404, _('Es konnte keine freie Informationsseite mit der angegebenen Id gefunden werden.'));
+            throw new Trails\Exception(404, _('Es konnte keine freie Informationsseite mit der angegebenen Id gefunden werden.'));
         }
 
         if (Request::get('verify') === 'delete') {
diff --git a/app/controllers/course/statusgroups.php b/app/controllers/course/statusgroups.php
index 48939bdea8d69426218c1d6a522d4554b05259f4..6f96299409fac10494cf45031132e461088274fe 100644
--- a/app/controllers/course/statusgroups.php
+++ b/app/controllers/course/statusgroups.php
@@ -762,7 +762,7 @@ class Course_StatusgroupsController extends AuthenticatedController
 
             // Safety check if no group_id at all.
             if (!$group_id) {
-                throw new Trails_Exception(400);
+                throw new Trails\Exception(400);
             }
         }
 
diff --git a/app/controllers/course/study_areas.php b/app/controllers/course/study_areas.php
index df54bb4d38f3df8fdde328b3e626f858243440de..e951d11e78fe709e93f9aa98634a5dc01cf6f047 100644
--- a/app/controllers/course/study_areas.php
+++ b/app/controllers/course/study_areas.php
@@ -18,7 +18,6 @@ require_once 'lib/webservices/api/studip_lecture_tree.php';
 
 class Course_StudyAreasController extends AuthenticatedController
 {
-    // see Trails_Controller#before_filter
     public function before_filter(&$action, &$args)
     {
         parent::before_filter($action, $args);
@@ -101,7 +100,7 @@ class Course_StudyAreasController extends AuthenticatedController
     public function save_action()
     {
         if($this->locked) {
-            throw new Trails_Exception(403);
+            throw new Trails\Exception(403);
         }
 
         $params = [];
diff --git a/app/controllers/course/studygroup.php b/app/controllers/course/studygroup.php
index c37577897290d959a5bfb90b74141fc0591c6f97..cd08ba3ce3d0943632c1d65350b5689d1db7f1be 100644
--- a/app/controllers/course/studygroup.php
+++ b/app/controllers/course/studygroup.php
@@ -10,8 +10,6 @@ require_once 'lib/user_visible.inc.php';
  */
 class Course_StudygroupController extends AuthenticatedController
 {
-
-    // see Trails_Controller#before_filter
     public function before_filter(&$action, &$args)
     {
         parent::before_filter($action, $args);
@@ -851,7 +849,7 @@ class Course_StudygroupController extends AuthenticatedController
                 return;
             }
         }
-        throw new Trails_Exception(401);
+        throw new Trails\Exception(401);
     }
 
 
diff --git a/app/controllers/course/timesrooms.php b/app/controllers/course/timesrooms.php
index ddd6883ae4dcf180be9b91f9ca154118f4c76cab..f6cab248a372f7b557bc6756c4115f4bb2afbb55 100644
--- a/app/controllers/course/timesrooms.php
+++ b/app/controllers/course/timesrooms.php
@@ -14,7 +14,7 @@ class Course_TimesroomsController extends AuthenticatedController
      * @param String $action Action to be executed
      * @param Array  $args Arguments passed to the action
      *
-     * @throws Trails_Exception when either no course was found or the user
+     * @throws Trails\Exception when either no course was found or the user
      *                          may not access this area
      */
     public function before_filter(&$action, &$args)
@@ -23,7 +23,7 @@ class Course_TimesroomsController extends AuthenticatedController
 
         // Try to find a valid course
         if (!Course::findCurrent()) {
-            throw new Trails_Exception(404, _('Es wurde keine Veranstaltung ausgewählt!'));
+            throw new Trails\Exception(404, _('Es wurde keine Veranstaltung ausgewählt!'));
         }
 
         if (!$GLOBALS['perm']->have_studip_perm('tutor', Course::findCurrent()->id)) {
@@ -250,7 +250,7 @@ class Course_TimesroomsController extends AuthenticatedController
     /**
      * Edit the start-semester of a course
      *
-     * @throws Trails_DoubleRenderError
+     * @throws Trails\Exceptions\DoubleRenderError
      */
     public function editSemester_action()
     {
@@ -368,7 +368,7 @@ class Course_TimesroomsController extends AuthenticatedController
      *
      * @param $termin_id
      *
-     * @throws Trails_DoubleRenderError
+     * @throws Trails\Exceptions\DoubleRenderError
      */
     public function saveDate_action($termin_id)
     {
@@ -544,7 +544,7 @@ class Course_TimesroomsController extends AuthenticatedController
     /**
      * Save Single Date
      *
-     * @throws Trails_DoubleRenderError
+     * @throws Trails\Exceptions\DoubleRenderError
      */
     public function saveSingleDate_action()
     {
diff --git a/app/controllers/document.php b/app/controllers/document.php
index da15ebe47d0dd42590ee9eca0afa334f1756ed3c..5057d9e56e25e2fc21c83480da01b53aaaab5711 100644
--- a/app/controllers/document.php
+++ b/app/controllers/document.php
@@ -21,7 +21,7 @@ class DocumentController extends StudipController
         if ($file_ref) {
             $this->redirect($file_ref->getDownloadURL($disposition === 'inline' ? 'normal' : 'force'));
         } else {
-            throw new Trails_Exception(404);
+            throw new Trails\Exception(404);
         }
     }
 }
diff --git a/app/controllers/extern.php b/app/controllers/extern.php
index 6cde6f397e2eb4f6e9200074648837ab110912c2..9296a345adc9be9dacd68b38b4384710fe361d28 100644
--- a/app/controllers/extern.php
+++ b/app/controllers/extern.php
@@ -21,7 +21,7 @@ class ExternController extends StudipController
      * Action shows rendered external page.
      *
      * @param string $config_id The id of the configuration of the external page to show.
-     * @throws Trails_DoubleRenderError
+     * @throws Trails\Exceptions\DoubleRenderError
      */
     public function index_action(string $config_id)
     {
diff --git a/app/controllers/fachabschluss/kategorien.php b/app/controllers/fachabschluss/kategorien.php
index 205f1f1d95ddd9a7bf02ec769d3b71ae9c9b1578..f9ba041fb105994fde518758d4e99b0d72e7ca35 100644
--- a/app/controllers/fachabschluss/kategorien.php
+++ b/app/controllers/fachabschluss/kategorien.php
@@ -114,7 +114,7 @@ class Fachabschluss_KategorienController extends MVVController
             if (Request::submitted('delete')) {
                 CSRFProtection::verifyUnsafeRequest();
                 if (!MvvPerm::get('AbschlussKategorie')->haveFieldPerm('position')) {
-                    throw new Trails_Exception(403);
+                    throw new Trails\Exception(403);
                 }
                 if (!count($abschluss_kategorie->abschluesse)) {
                     PageLayout::postSuccess(sprintf(
@@ -142,7 +142,7 @@ class Fachabschluss_KategorienController extends MVVController
         $orderedIds = Request::getArray('newOrder');
         if ($list === 'abschluss_kategorien') {
             if (!MvvPerm::get('AbschlussKategorie')->haveFieldPerm('position')) {
-                throw new Trails_Exception(403);
+                throw new Trails\Exception(403);
             }
             $kategorien = SimpleORMapCollection::createFromArray(
                 AbschlussKategorie::findBySql('1 ORDER BY position')
@@ -162,7 +162,7 @@ class Fachabschluss_KategorienController extends MVVController
             }
         } else {
             if (!MvvPerm::get('AbschlussZuord')->haveFieldPerm('position')) {
-                throw new Trails_Exception(403);
+                throw new Trails\Exception(403);
             }
             list(, $kategorie_id) = explode('_', $list);
             $abschluss_kategorie = AbschlussKategorie::find($kategorie_id);
diff --git a/app/controllers/file.php b/app/controllers/file.php
index 095e295ce64273e370d04f87f7c5781f58c6a079..376a74e627b266c2fc9e8d9d6d2374066c6ca3cb 100644
--- a/app/controllers/file.php
+++ b/app/controllers/file.php
@@ -66,7 +66,7 @@ class FileController extends AuthenticatedController
             }
             $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin"));
             if (!$plugin) {
-                throw new Trails_Exception(404, _('Plugin existiert nicht.'));
+                throw new Trails\Exception(404, _('Plugin existiert nicht.'));
             }
             $folder = $plugin->getFolder($folder_id);
         } else {
@@ -184,10 +184,10 @@ class FileController extends AuthenticatedController
             //Plugin file area.
             $plugin = PluginManager::getInstance()->getPlugin($this->to_plugin);
             if (!$plugin) {
-                throw new Trails_Exception(404, _('Plugin existiert nicht.'));
+                throw new Trails\Exception(404, _('Plugin existiert nicht.'));
             }
             if (!($plugin instanceof FilesystemPlugin)) {
-                throw new Trails_Exception(400, _('Das Plugin ist kein Dateibereich-Plugin.'));
+                throw new Trails\Exception(400, _('Das Plugin ist kein Dateibereich-Plugin.'));
             }
             $file_ids = Request::getArray('file_refs');
             foreach ($file_ids as $file_id) {
@@ -294,7 +294,7 @@ class FileController extends AuthenticatedController
             }
             $plugin = PluginManager::getInstance()->getPlugin($this->from_plugin);
             if (!$plugin) {
-                throw new Trails_Exception(404, _('Plugin existiert nicht.'));
+                throw new Trails\Exception(404, _('Plugin existiert nicht.'));
             }
             $this->file = $plugin->getPreparedFile($file_id);
         } else {
@@ -383,7 +383,7 @@ class FileController extends AuthenticatedController
             $file_ref_id = $file_id;
             $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin"));
             if (!$plugin) {
-                throw new Trails_Exception(404, _('Plugin existiert nicht.'));
+                throw new Trails\Exception(404, _('Plugin existiert nicht.'));
             }
 
             $this->file = $plugin->getPreparedFile($file_id);
@@ -666,7 +666,7 @@ class FileController extends AuthenticatedController
             }
             $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin"));
             if (!$plugin) {
-                throw new Trails_Exception(404, _('Plugin existiert nicht.'));
+                throw new Trails\Exception(404, _('Plugin existiert nicht.'));
             }
             $this->file = $plugin->getPreparedFile($file_id);
             $this->from_plugin = Request::get("from_plugin");
@@ -760,7 +760,7 @@ class FileController extends AuthenticatedController
 
             $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin"));
             if (!$plugin) {
-                throw new Trails_Exception(404, _('Plugin existiert nicht.'));
+                throw new Trails\Exception(404, _('Plugin existiert nicht.'));
             }
 
             $this->file_ref = $plugin->getPreparedFile($file_id);
@@ -814,7 +814,7 @@ class FileController extends AuthenticatedController
             }
             $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin"));
             if (!$plugin) {
-                throw new Trails_Exception(404, _('Plugin existiert nicht.'));
+                throw new Trails\Exception(404, _('Plugin existiert nicht.'));
             }
             $foldertype = $plugin->getFolder($folder_id);
 
@@ -1325,7 +1325,7 @@ class FileController extends AuthenticatedController
             }
             $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin"));
             if (!$plugin) {
-                throw new Trails_Exception(404, _('Plugin existiert nicht.'));
+                throw new Trails\Exception(404, _('Plugin existiert nicht.'));
             }
             $filetype = $plugin->getPreparedFile($file_id);
             $folder = $filetype->getFolderType();
@@ -1335,7 +1335,7 @@ class FileController extends AuthenticatedController
             $filetype = $file_ref->getFileType();
         }
         if (!$filetype) {
-            throw new Trails_Exception(404, _('Datei nicht gefunden.'));
+            throw new Trails\Exception(404, _('Datei nicht gefunden.'));
         }
 
         if (!$filetype->isWritable($GLOBALS['user']->id)) {
@@ -1792,7 +1792,7 @@ class FileController extends AuthenticatedController
             }
             $plugin = PluginManager::getInstance()->getPlugin(Request::get("to_plugin"));
             if (!$plugin) {
-                throw new Trails_Exception(404, _('Plugin existiert nicht.'));
+                throw new Trails\Exception(404, _('Plugin existiert nicht.'));
             }
             $this->top_folder = $plugin->getFolder($folder_id);
         } else {
@@ -1857,7 +1857,7 @@ class FileController extends AuthenticatedController
             }
             $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin"));
             if (!$plugin) {
-                throw new Trails_Exception(404, _('Plugin existiert nicht.'));
+                throw new Trails\Exception(404, _('Plugin existiert nicht.'));
             }
             $parent_folder = $plugin->getFolder($folder_id);
         } else {
@@ -1963,7 +1963,7 @@ class FileController extends AuthenticatedController
             }
             $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin"));
             if (!$plugin) {
-                throw new Trails_Exception(404, _('Plugin existiert nicht.'));
+                throw new Trails\Exception(404, _('Plugin existiert nicht.'));
             }
             $folder = $plugin->getFolder($folder_id);
         } else {
@@ -2050,7 +2050,7 @@ class FileController extends AuthenticatedController
             }
             $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin"));
             if (!$plugin) {
-                throw new Trails_Exception(404, _('Plugin existiert nicht.'));
+                throw new Trails\Exception(404, _('Plugin existiert nicht.'));
             }
             $folder = $plugin->getFolder($folder_id);
         } else {
@@ -2085,7 +2085,7 @@ class FileController extends AuthenticatedController
             }
             $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin"));
             if (!$plugin) {
-                throw new Trails_Exception(404, _('Plugin existiert nicht.'));
+                throw new Trails\Exception(404, _('Plugin existiert nicht.'));
             }
             $parent_folder = $plugin->getFolder($folder_id);
         } else {
diff --git a/app/controllers/files.php b/app/controllers/files.php
index 2d4de4e1593e1ed4cb01ded418c69d70584f2d53..df4657c832a089d0b3364534a7ec3494dfb102ab 100644
--- a/app/controllers/files.php
+++ b/app/controllers/files.php
@@ -711,7 +711,7 @@ class FilesController extends AuthenticatedController
 
             $destination_plugin = PluginManager::getInstance()->getPlugin($to_plugin);
             if (!$destination_plugin) {
-                throw new Trails_Exception(404, _('Plugin existiert nicht.'));
+                throw new Trails\Exception(404, _('Plugin existiert nicht.'));
             }
             $destination_folder = $destination_plugin->getFolder($destination_id);
         } else {
@@ -731,7 +731,7 @@ class FilesController extends AuthenticatedController
                 if ($from_plugin) {
                     $source_plugin = PluginManager::getInstance()->getPlugin($from_plugin);
                     if (!$source_plugin) {
-                        throw new Trails_Exception(404, _('Plugin existiert nicht.'));
+                        throw new Trails\Exception(404, _('Plugin existiert nicht.'));
                     }
                     if (Request::get("isfolder")) {
                         if ($source_folder = $source_plugin->getFolder($fileref)) {
diff --git a/app/controllers/materialien/files.php b/app/controllers/materialien/files.php
index 804668ef60355c82984cb5c1379deaaa4b5662d1..6f457677483cb8a83ac6b568c29164884b55a7c9 100644
--- a/app/controllers/materialien/files.php
+++ b/app/controllers/materialien/files.php
@@ -510,7 +510,7 @@ class Materialien_FilesController extends MVVController
 
         $mvv_file = MvvFile::find($mvvfile_id);
         if (!$mvv_file) {
-            throw new Trails_Exception(404);
+            throw new Trails\Exception(404);
         }
 
         $this->doc_year = $mvv_file->year;
diff --git a/app/controllers/media_proxy.php b/app/controllers/media_proxy.php
index 50dc3df54d537e13276c188ec9661510af94787e..b98b49c9c738f1139c26aba1e36828b3d009181e 100644
--- a/app/controllers/media_proxy.php
+++ b/app/controllers/media_proxy.php
@@ -46,7 +46,7 @@ class MediaProxyController extends StudipController
         ini_set('default_socket_timeout', 5);
         $this->render_nothing();
 
-        //stop output buffering started in Trails_Dispatcher::dispatch()
+        //stop output buffering started in Trails\Dispatcher::dispatch()
         while (ob_get_level()) {
             ob_end_clean();
         }
diff --git a/app/controllers/module/module.php b/app/controllers/module/module.php
index e57156fa4306b0049cbf14d2dcdc2e14dd7ee256..854b04536102f9b860a9c39a708b0e7830e273f9 100644
--- a/app/controllers/module/module.php
+++ b/app/controllers/module/module.php
@@ -395,17 +395,17 @@ class Module_ModuleController extends MVVController
      * Deletes a descriptor from module
      *
      * @param type $deskriptor_id
-     * @throws Trails_Exception
+     * @throws Trails\Exception
      */
     public function delete_modul_deskriptor_action($deskriptor_id, $language)
     {
         $deskriptor = ModulDeskriptor::find($deskriptor_id);
         if (is_null($deskriptor)) {
-            throw new Trails_Exception(404, _('Unbekannter Deskriptor'));
+            throw new Trails\Exception(404, _('Unbekannter Deskriptor'));
         }
         $def_lang = $deskriptor->modul->getDefaultLanguage();
         if ($language === $def_lang) {
-            throw new Trails_Exception(403, _('Ein Deskriptor in der Original-Sprache kann nicht gelöscht werden.'));
+            throw new Trails\Exception(403, _('Ein Deskriptor in der Original-Sprache kann nicht gelöscht werden.'));
         }
         if (Request::submitted('delete')) {
             CSRFProtection::verifyUnsafeRequest();
@@ -819,17 +819,17 @@ class Module_ModuleController extends MVVController
      * Deletes a descriptor from Modulteil
      *
      * @param type $deskriptor_id
-     * @throws Trails_Exception
+     * @throws Trails\Exception
      */
     public function delete_modulteil_deskriptor_action($deskriptor_id, $language)
     {
         $deskriptor = ModulteilDeskriptor::find($deskriptor_id);
         if (is_null($deskriptor)) {
-            throw new Trails_Exception(404, _('Unbekannter Deskriptor'));
+            throw new Trails\Exception(404, _('Unbekannter Deskriptor'));
         }
         $def_lang = $deskriptor->modulteil->getDefaultLanguage();
         if ($language === $def_lang) {
-            throw new Trails_Exception(403, _('Ein Deskriptor in der Original-Sprache kann nicht gelöscht werden.'));
+            throw new Trails\Exception(403, _('Ein Deskriptor in der Original-Sprache kann nicht gelöscht werden.'));
         }
         if (Request::submitted('delete')) {
             CSRFProtection::verifyUnsafeRequest();
diff --git a/app/controllers/module/mvv_controller.php b/app/controllers/module/mvv_controller.php
index e84b37cd264e9db609736d1ef1a08a2dfe7ef5e4..b70ddefa13859de0bef71c9fb4f7a14dfc26bc76 100644
--- a/app/controllers/module/mvv_controller.php
+++ b/app/controllers/module/mvv_controller.php
@@ -77,7 +77,7 @@ abstract class MVVController extends AuthenticatedController
         PageLayout::setTitle(_('Module'));
 
         // Setup flash instance
-        $this->flash = Trails_Flash::instance();
+        $this->flash = Trails\Flash::instance();
 
         $this->me             = 'mvv';
         self::$items_per_page = Config::get()->getValue('ENTRIES_PER_PAGE');
@@ -218,7 +218,7 @@ abstract class MVVController extends AuthenticatedController
      * This action is used to show a select box instead of an input field
      * if the user has clicked on the magnifier icon of a quicksearch.
      *
-     * @throws Trails_Exception
+     * @throws Trails\Exception
      */
     public function qs_result_action()
     {
@@ -228,7 +228,7 @@ abstract class MVVController extends AuthenticatedController
                 Request::get('qs_term')
             ));
         } else {
-            throw new Trails_Exception(404);
+            throw new Trails\Exception(404);
         }
     }
 
diff --git a/app/controllers/oer/endpoints.php b/app/controllers/oer/endpoints.php
index 31563f531c02dd274cf217cebbe900fb0992f280..9a0f3f5a8a539f62bc7e85bff77c5e31f1aaedfc 100644
--- a/app/controllers/oer/endpoints.php
+++ b/app/controllers/oer/endpoints.php
@@ -410,7 +410,7 @@ class Oer_EndpointsController extends StudipController
             $this->response->add_header('Content-Length', filesize($this->material->getFrontImageFilePath()));
             $this->render_text(file_get_contents($this->material->getFrontImageFilePath()));
         } else {
-            throw new Trails_Exception(404);
+            throw new Trails\Exception(404);
         }
     }
 
diff --git a/app/controllers/search/studiengaenge.php b/app/controllers/search/studiengaenge.php
index ae271061e3cb25b0258ab974290c05881c3a1ea0..e17eb2a9773c3a8d93c2738dabaf79be22d5b9f5 100644
--- a/app/controllers/search/studiengaenge.php
+++ b/app/controllers/search/studiengaenge.php
@@ -423,7 +423,7 @@ class Search_StudiengaengeController extends MVVController
     {
         $this->abschnitt = StgteilAbschnitt::find($abschnitt_id);
         if (!$this->abschnitt) {
-            throw new Trails_Exception(404);
+            throw new Trails\Exception(404);
         }
         $this->render_template('search/studiengaenge/kommentar', $this->layout);
     }
diff --git a/app/controllers/settings/settings.php b/app/controllers/settings/settings.php
index 327b62d7507d0c7e3efccb3aaee8426dfc7898c0..9cd00c09d1f6f7d804e0aa3aa682de075b67d339 100644
--- a/app/controllers/settings/settings.php
+++ b/app/controllers/settings/settings.php
@@ -121,7 +121,7 @@ abstract class Settings_SettingsController extends AuthenticatedController
     public function get_default_template($action)
     {
         $class = get_class($this);
-        $controller_name = Trails_Inflector::underscore(mb_substr($class, 0, -10));
+        $controller_name = Trails\Inflector::underscore(mb_substr($class, 0, -10));
         return file_exists($this->dispatcher->trails_root . '/views/' . $controller_name . '.php')
             ? $controller_name
             : $controller_name . '/' . $action;
diff --git a/app/controllers/shared/contacts.php b/app/controllers/shared/contacts.php
index 62dd7a88816158b230351267539ab33029114df2..820d2ab761aca980f4c0529c5115e7042f1e2ef7 100644
--- a/app/controllers/shared/contacts.php
+++ b/app/controllers/shared/contacts.php
@@ -114,7 +114,7 @@ class Shared_ContactsController extends MVVController
         if ($this->contact_id) {
             $contact_range = MvvContactRange::findOneBySQL('contact_id=?', [$this->contact_id]);
             if (!$contact_range) {
-                throw new Trails_Exception(404);
+                throw new Trails\Exception(404);
             }
             $this->relations = $contact_range->getRelations($this->filter);
             $this->origin = 'index';
@@ -155,7 +155,7 @@ class Shared_ContactsController extends MVVController
     {
         $this->contact_range = MvvContactRange::findOneBySQL('contact_id = ?', [$contact_id]);
         if (!$this->contact_range) {
-            throw new Trails_Exception(404);
+            throw new Trails\Exception(404);
         }
 
         $this->relations = $this->contact_range->getRelations($this->filter);
diff --git a/app/controllers/siteinfo.php b/app/controllers/siteinfo.php
index ab81660bf2541baec0ef3aac696a5b57f0f6bdb1..7bc95cb494ea027508d3c4e5c3a5db31cd2d7d0a 100644
--- a/app/controllers/siteinfo.php
+++ b/app/controllers/siteinfo.php
@@ -37,7 +37,7 @@ class SiteinfoController extends StudipController
         } else {
             $action = 'show';
             if ($this->page_is_draft || ($this->page_disabled_nobody && $GLOBALS['user']->id === 'nobody')) {
-                throw new Trails_Exception(404);
+                throw new Trails\Exception(404);
             }
         }
         $this->add_navigation($action);
diff --git a/app/controllers/studiengaenge/abschluesse.php b/app/controllers/studiengaenge/abschluesse.php
index 8ec055b665744321dd31f36118ba476edcfaef1e..60bc0919d684e4267fd612ef55d6a9930a28805a 100644
--- a/app/controllers/studiengaenge/abschluesse.php
+++ b/app/controllers/studiengaenge/abschluesse.php
@@ -50,7 +50,7 @@ class Studiengaenge_AbschluesseController extends Studiengaenge_StudiengaengeCon
         $perm_institutes = MvvPerm::getOwnInstitutes();
         $abschluss = Abschluss::find($abschluss_id);
         if (!$abschluss) {
-            throw new Trails_Exception(404);
+            throw new Trails\Exception(404);
         }
         $this->abschluss_id = $abschluss->id;
         if (count($perm_institutes)) {
@@ -59,7 +59,7 @@ class Studiengaenge_AbschluesseController extends Studiengaenge_StudiengaengeCon
                 $perm_institutes
             );
             if (!count($institutes_abschluss)) {
-                throw new Trails_Exception(403);
+                throw new Trails\Exception(403);
             }
             $this->studiengaenge = SimpleORMapCollection::createFromArray(
                 Studiengang::findByAbschluss_id($this->abschluss_id)
@@ -91,4 +91,4 @@ class Studiengaenge_AbschluesseController extends Studiengaenge_StudiengaengeCon
             $this->perform_relayed('index');
         }
     }
-}
\ No newline at end of file
+}
diff --git a/app/controllers/studiengaenge/fachbereiche.php b/app/controllers/studiengaenge/fachbereiche.php
index 970c8d984de7add94ff74c374cdf97ef179dcb3b..35f997b8b1ecc69419c851b79d2781249539f752 100644
--- a/app/controllers/studiengaenge/fachbereiche.php
+++ b/app/controllers/studiengaenge/fachbereiche.php
@@ -51,7 +51,7 @@ class Studiengaenge_FachbereicheController extends Studiengaenge_StudiengaengeCo
         $this->fachbereich_id = $fachbereich_id;
         if (count($perm_institutes)) {
             if (!in_array($this->fachbereich_id, $perm_institutes)) {
-                throw new Trails_Exception(403);
+                throw new Trails\Exception(403);
             }
         }
 
diff --git a/app/controllers/studiengaenge/fachbereichestgteile.php b/app/controllers/studiengaenge/fachbereichestgteile.php
index c8037dc1fc5cf5aea1e20b2e07fed674afa11bd7..73ad2aa15aa53ea3b22ebbedf8ce6e4dcc2ef65a 100644
--- a/app/controllers/studiengaenge/fachbereichestgteile.php
+++ b/app/controllers/studiengaenge/fachbereichestgteile.php
@@ -67,7 +67,7 @@ class Studiengaenge_FachbereichestgteileController extends Studiengaenge_Studien
             $this->fachbereich = $fachbereich;
             $this->perform_relayed('stgteil');
         } else {
-            throw new Trails_Exception(404);
+            throw new Trails\Exception(404);
         }
     }
 }
diff --git a/app/controllers/studiengaenge/faecher.php b/app/controllers/studiengaenge/faecher.php
index c9546a3bddb003bec0ec558a652e2f25dc56967b..9990f7d6ae5e9d1ddca485ab7cd282e54d4ab1a5 100644
--- a/app/controllers/studiengaenge/faecher.php
+++ b/app/controllers/studiengaenge/faecher.php
@@ -83,7 +83,7 @@ class Studiengaenge_FaecherController extends Studiengaenge_StudiengangteileCont
             $this->stgteil = StudiengangTeil::get();
             $this->stgteil->assignFach($fach->getId());
         } else {
-            throw new Trails_Exception(404);
+            throw new Trails\Exception(404);
         }
         $this->perform_relayed('stgteil');
     }
diff --git a/app/controllers/studiengaenge/kategorien.php b/app/controllers/studiengaenge/kategorien.php
index 03d28fc9e118f39bd6e552df903e254ec7675369..8f6a98dd4ac6de04f390e704361d25b8753fc11d 100644
--- a/app/controllers/studiengaenge/kategorien.php
+++ b/app/controllers/studiengaenge/kategorien.php
@@ -73,7 +73,7 @@ class Studiengaenge_KategorienController extends Studiengaenge_StudiengaengeCont
             
             if (count($perm_institutes)) {
                 if (!in_array($studiengang->institut_id, $perm_institutes)) {
-                    throw new Trails_Exception(403);
+                    throw new Trails\Exception(403);
                 }
             }
             
@@ -98,4 +98,4 @@ class Studiengaenge_KategorienController extends Studiengaenge_StudiengaengeCont
             $this->perform_relayed('index');
         }
     }
-}
\ No newline at end of file
+}
diff --git a/app/controllers/studiengaenge/shared_version.php b/app/controllers/studiengaenge/shared_version.php
index 696fac081a7181f0e972a9f673da7e47fd38c2c6..a6265b098a0f89ea4eb3ceb6b37852db1a056a4b 100644
--- a/app/controllers/studiengaenge/shared_version.php
+++ b/app/controllers/studiengaenge/shared_version.php
@@ -11,18 +11,18 @@ abstract class SharedVersionController extends MVVController
     {
         $this->stgteil = StudiengangTeil::find($stgteil_id);
         if (!$this->stgteil) {
-            throw new Trails_Exception(404);
+            throw new Trails\Exception(404);
         }
 
         if (!MvvPerm::haveFieldPermVersionen($this->stgteil, MvvPerm::PERM_READ)) {
-            throw new Trails_Exception(403);
+            throw new Trails\Exception(403);
         }
 
         if (!isset($this->version)) {
             $this->version = StgteilVersion::find($version_id);
             if (!$this->version) {
                 if (!MvvPerm::haveFieldPermVersionen($this->stgteil, MvvPerm::PERM_CREATE)) {
-                    throw new Trails_Exception(403);
+                    throw new Trails\Exception(403);
                 }
                 $this->version = new StgteilVersion();
             }
@@ -51,7 +51,7 @@ abstract class SharedVersionController extends MVVController
         if (Request::submitted('store')) {
             CSRFProtection::verifyUnsafeRequest();
             if (!MvvPerm::haveFieldPermVersionen($this->stgteil)) {
-                throw new Trails_Exception(403);
+                throw new Trails\Exception(403);
             }
             $stored = false;
             $this->version->stgteil_id = $this->stgteil->getId();
@@ -220,7 +220,7 @@ abstract class SharedVersionController extends MVVController
     {
         $version = StgteilVersion::find($version_id);
         if (!$version) {
-             throw new Trails_Exception(404, _('Unbekannte Version'));
+             throw new Trails\Exception(404, _('Unbekannte Version'));
         }
         if (Request::isPost()) {
             CSRFProtection::verifyUnsafeRequest();
@@ -267,16 +267,16 @@ abstract class SharedVersionController extends MVVController
         $perm = MvvPerm::get($this->version);
 
         if (!$perm->haveFieldPerm('abschnitte', MvvPerm::PERM_READ)) {
-            throw new Trails_Exception(403);
+            throw new Trails\Exception(403);
         }
         if ($this->abschnitt->isNew() && !$perm->haveFieldPerm('abschnitte', MvvPerm::PERM_CREATE)) {
-            throw new Trails_Exception(403);
+            throw new Trails\Exception(403);
         }
 
         if (Request::submitted('store')) {
             CSRFProtection::verifyUnsafeRequest();
             if (!$perm->haveFieldPerm('abschnitte', MvvPerm::PERM_WRITE)) {
-                throw new Trails_Exception(403);
+                throw new Trails\Exception(403);
             }
             $this->abschnitt->version_id = $this->version->getId();
             $this->abschnitt->name = Request::i18n('name')->trim();
@@ -494,7 +494,7 @@ abstract class SharedVersionController extends MVVController
         $abschnitt = StgteilAbschnitt::find($abschnitt_id);
         if ($abschnitt) {
             if (!MvvPerm::haveFieldPermModul_zuordnungen($abschnitt, MvvPerm::PERM_CREATE)) {
-                throw new Trails_Exception(403);
+                throw new Trails\Exception(403);
             }
             $modul = Modul::find($modul_id);
             if (!$modul) {
@@ -614,7 +614,7 @@ abstract class SharedVersionController extends MVVController
     {
         $version = StgteilVersion::find($version_id);
         if (!$version) {
-             throw new Trails_Exception(404, _('Unbekannte Version'));
+             throw new Trails\Exception(404, _('Unbekannte Version'));
         } else {
             if (Request::isPost()) {
                 CSRFProtection::verifyUnsafeRequest();
@@ -754,7 +754,7 @@ abstract class SharedVersionController extends MVVController
                     $this->redirect($this->action_url('abschnitte/' . $version_id));
                 }
             } else {
-                throw new Trails_Exception(403);
+                throw new Trails\Exception(403);
             }
         }
         if (Request::isXhr()) {
diff --git a/app/controllers/studiengaenge/studiengaenge.php b/app/controllers/studiengaenge/studiengaenge.php
index d053f48291598d342422e4e20e3f4cc39dadb294..8465665125f4305d3d977143fa55da78b0b57d8f 100644
--- a/app/controllers/studiengaenge/studiengaenge.php
+++ b/app/controllers/studiengaenge/studiengaenge.php
@@ -541,7 +541,7 @@ class Studiengaenge_StudiengaengeController extends MVVController
                 if (Request::isPost()) {
                     CSRFProtection::verifyRequest();
                     if (!MvvPerm::haveFieldPermStudiengangteile($studiengang, MvvPerm::PERM_CREATE)) {
-                        throw new Trails_Exception(403);
+                        throw new Trails\Exception(403);
                     }
                     $stgteil_name = $this->stg_stgteil->stgteil_name;
                     $stgbez_name = $this->stg_stgteil->stgbez_name;
@@ -588,7 +588,7 @@ class Studiengaenge_StudiengaengeController extends MVVController
                 if (Request::isPost()) {
                     CSRFProtection::verifyUnsafeRequest();
                     if (!MvvPerm::haveFieldPermStudiengangteile($studiengang, MvvPerm::PERM_CREATE)) {
-                        throw new Trails_Exception(403);
+                        throw new Trails\Exception(403);
                     }
                     $stgteil_name = $stg_stgteil->stgteil_name;
                     $stgbez_name = $stg_stgteil->stgbez_name;
diff --git a/app/controllers/studiengaenge/studiengangteile.php b/app/controllers/studiengaenge/studiengangteile.php
index 0fddd44d1cf58164b1c94a99c6cead42e85c1b44..bc1449ff2194cbe979e482e77cbfd41e445e8764 100644
--- a/app/controllers/studiengaenge/studiengangteile.php
+++ b/app/controllers/studiengaenge/studiengangteile.php
@@ -144,7 +144,7 @@ class Studiengaenge_StudiengangteileController extends SharedVersionController
             $this->stgteil->contact_assignments = $stgteil_orig->contact_assignments;
 
         } else {
-            throw new Trails_Exception(404);
+            throw new Trails\Exception(404);
         }
         $this->perform_relayed('stgteil');
     }
diff --git a/app/controllers/studiengaenge/versionen.php b/app/controllers/studiengaenge/versionen.php
index 9b60b3d4238f6d642a6ec269a14a2c867fda5c6d..41625bf275288c6e5e043cd9ee153755286bdce9 100644
--- a/app/controllers/studiengaenge/versionen.php
+++ b/app/controllers/studiengaenge/versionen.php
@@ -52,7 +52,7 @@ class Studiengaenge_VersionenController extends SharedVersionController
                 $this->redirect($this->action_url('index/' .  $this->chooser_filter['stgteile']));
                 return;
             default :
-                throw new Trails_Exception(400);
+                throw new Trails\Exception(400);
         }
         $this->name = $list;
         if (!empty($this->lists[$list]['elements'])) {
@@ -218,7 +218,7 @@ class Studiengaenge_VersionenController extends SharedVersionController
         if ($stgteil_id) {
             $this->stgteil = StudiengangTeil::find($stgteil_id);
             if (!$this->stgteil) {
-                throw new Trails_Exception(404, _('Unbekannter Studiengangteil'));
+                throw new Trails\Exception(404, _('Unbekannter Studiengangteil'));
             }
 
             $this->initPageParams();
diff --git a/app/views/consultation/admin/create.php b/app/views/consultation/admin/create.php
index c973ccfe8ec589a31fac9067c7bb9e52f72aca4e..3da70e064d8dac412ede76c17cf0f01e3861c024 100644
--- a/app/views/consultation/admin/create.php
+++ b/app/views/consultation/admin/create.php
@@ -1,7 +1,7 @@
 <?php
 /**
  * @var Consultation_AdminController $controller
- * @var Trails_Flash $flash
+ * @var Trails\Flash $flash
  * @var string|null $room
  * @var array $responsible
  * @var Range $range
diff --git a/app/views/news/admin_news.php b/app/views/news/admin_news.php
index db07d03a1bc46829ff364589899a075063600f5f..e12047a6f0edb76b486d0575a794144fbef96b5b 100644
--- a/app/views/news/admin_news.php
+++ b/app/views/news/admin_news.php
@@ -2,7 +2,7 @@
 /**
  * @var NewsController $controller
  * @var string $area_type
- * @var Trails_Flash $flash
+ * @var Trails\Flash $flash
  * @var string $news_searchterm
  * @var string $news_startdate
  * @var string $news_enddate
diff --git a/cli/Commands/Checks/HelpTours.php b/cli/Commands/Checks/HelpTours.php
index b4b2fa7665142c2e9371098cf70ea5132901caaf..b0c201ae37a476ca3d65db1e2a1a0055fc86b0ff 100644
--- a/cli/Commands/Checks/HelpTours.php
+++ b/cli/Commands/Checks/HelpTours.php
@@ -59,7 +59,7 @@ class HelpTours extends Command
                         $plugin = new $plugin_info['class']();
 
                         if ($result[1]) {
-                            $dispatcher = app(\Trails_Dispatcher::class);
+                            $dispatcher = app(\Trails\Dispatcher::class);
                             $dispatcher->trails_root = $GLOBALS['ABSOLUTE_PATH_STUDIP'] . $plugin->getPluginPath();
                             $dispatcher->trails_uri = rtrim(\PluginEngine::getLink($plugin, [], null, true), '/');
                             $dispatcher->default_controller = 'index';
@@ -71,7 +71,7 @@ class HelpTours extends Command
                             }
                         }
                     } elseif (match_route('dispatch.php/*', $step->route)) {
-                        $dispatcher = app(\Trails_Dispatcher::class);
+                        $dispatcher = app(\Trails\Dispatcher::class);
                         $parsed = $dispatcher->parse(substr($step->route, strlen('dispatch.php') + 1));
                         $controller = $dispatcher->load_controller($parsed[0]);
                         if ($parsed[1] && !$controller->has_action($parsed[1])) {
diff --git a/lib/bootstrap-autoload.php b/lib/bootstrap-autoload.php
index 0bbad8187c6d26620b7ddbc30342a8eb058a37f0..cc39fe7e5c066851fc8d90eec19a247e3ed35bea 100644
--- a/lib/bootstrap-autoload.php
+++ b/lib/bootstrap-autoload.php
@@ -63,6 +63,22 @@ class_alias(Flexi\Template::class, 'Flexi_Template');
 class_alias(Flexi\Factory::class, 'Flexi_TemplateFactory');
 class_alias(Flexi\TemplateNotFoundException::class, 'Flexi_TemplateNotFoundException');
 
+// Trails
+StudipAutoloader::addAutoloadPath('lib/trails', 'Trails');
+class_alias(Trails\Controller::class, 'Trails_Controller');
+class_alias(Trails\Dispatcher::class, 'Trails_Dispatcher');
+class_alias(Trails\Exception::class, 'Trails_Exception');
+class_alias(Trails\Flash::class, 'Trails_Flash');
+class_alias(Trails\Inflector::class, 'Trails_Inflector');
+class_alias(Trails\Response::class, 'Trails_Response');
+
+class_alias(Trails\Exceptions\DoubleRenderError::class, 'Trails_DoubleRenderError');
+class_alias(Trails\Exceptions\MissingFile::class, 'Trails_MissingFile');
+class_alias(Trails\Exceptions\RoutingError::class, 'Trails_RoutingError');
+class_alias(Trails\Exceptions\SessionRequiredException::class, 'Trails_SessionRequiredException');
+class_alias(Trails\Exceptions\UnknownAction::class, 'Trails_UnknownAction');
+class_alias(Trails\Exceptions\UnknownController::class, 'Trails_UnknownController');
+
 // Messy file names
 StudipAutoloader::addClassLookups([
     'email_validation_class' => 'lib/phplib/email_validation.class.php',
@@ -71,19 +87,6 @@ StudipAutoloader::addClassLookups([
     'MVVController'          => 'app/controllers/module/mvv_controller.php'
 ]);
 
-// Trails
-$trails_classes = [
-    'Trails_Dispatcher', 'Trails_Response', 'Trails_Controller',
-    'Trails_Inflector', 'Trails_Flash',
-    'Trails_Exception', 'Trails_DoubleRenderError', 'Trails_MissingFile',
-    'Trails_RoutingError', 'Trails_UnknownAction', 'Trails_UnknownController',
-    'Trails_SessionRequiredException',
-];
-StudipAutoloader::addClassLookup(
-    $trails_classes,
-    'vendor/trails/trails.php'
-);
-
 // Vendor
 StudipAutoloader::addClassLookups([
     'PasswordHash' => 'vendor/phpass/PasswordHash.php',
diff --git a/lib/bootstrap-definitions.php b/lib/bootstrap-definitions.php
index ee80135be09cabd42e8dded7cfb1d982fe53b4d7..d34d0231dbb7b15b90612520f70ad8fbaa63ea2c 100644
--- a/lib/bootstrap-definitions.php
+++ b/lib/bootstrap-definitions.php
@@ -20,7 +20,7 @@ return [
     StudipPDO::class => DI\factory(function () {
         return DBManager::get();
     }),
-    Trails_Dispatcher::class => DI\factory(function (ContainerInterface $container) {
+    Trails\Dispatcher::class => DI\factory(function (ContainerInterface $container) {
         return new \StudipDispatcher($container);
     }),
 ];
diff --git a/lib/classes/OAuth2/NegotiatesWithPsr7.php b/lib/classes/OAuth2/NegotiatesWithPsr7.php
index 0edf2431cfef7790b1e0e85d271b876d905e7c11..b2ee5a1c6caf535151da8e1cf3de06006e9813f9 100644
--- a/lib/classes/OAuth2/NegotiatesWithPsr7.php
+++ b/lib/classes/OAuth2/NegotiatesWithPsr7.php
@@ -5,7 +5,7 @@ namespace Studip\OAuth2;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use Slim\Psr7\Response;
-use Trails_Response;
+use Trails\Response as TrailsResponse;
 
 trait NegotiatesWithPsr7
 {
@@ -19,9 +19,9 @@ trait NegotiatesWithPsr7
         return new Response();
     }
 
-    protected function convertPsrResponse(ResponseInterface $response): Trails_Response
+    protected function convertPsrResponse(ResponseInterface $response): TrailsResponse
     {
-        $trailsResponse = new Trails_Response((string) $response->getBody(), [], $response->getStatusCode());
+        $trailsResponse = new TrailsResponse((string) $response->getBody(), [], $response->getStatusCode());
         foreach ($response->getHeaders() as $key => $values) {
             foreach ($values as $value) {
                 $trailsResponse->add_header($key, $value);
diff --git a/lib/classes/StudipController.php b/lib/classes/StudipController.php
index ae316c1b8350e115e9ddd4a1da4f0c76b667beaa..4fbcc429ef96883df630d556dd0ee8a181b4418c 100644
--- a/lib/classes/StudipController.php
+++ b/lib/classes/StudipController.php
@@ -16,7 +16,7 @@ use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
 /**
  * @property StudipResponse $response
  */
-abstract class StudipController extends Trails_Controller
+abstract class StudipController extends Trails\Controller
 {
     use StudipControllerPropertiesTrait;
 
@@ -48,7 +48,7 @@ abstract class StudipController extends Trails_Controller
             $GLOBALS['auth']->login_if((Request::get('again') || !$this->allow_nobody) && $GLOBALS['user']->id == 'nobody');
 
             // Setup flash instance
-            $this->flash = Trails_Flash::instance();
+            $this->flash = Trails\Flash::instance();
 
             // set up user session
             include 'lib/seminar_open.php';
@@ -107,7 +107,7 @@ abstract class StudipController extends Trails_Controller
      *
      * @param String $unconsumed_path Path segment containing action and
      *                                optionally arguments or format
-     * @return Trails_Response from parent controller
+     * @return Trails\Response from parent controller
      */
     public function perform($unconsumed_path)
     {
@@ -212,7 +212,7 @@ abstract class StudipController extends Trails_Controller
 
                 case 'option':
                     if (preg_match('/[^\\w,-]/', $arg)) {
-                        throw new Trails_Exception(400);
+                        throw new Trails\Exception(400);
                     }
                     break;
 
@@ -231,7 +231,7 @@ abstract class StudipController extends Trails_Controller
 
                     $sorm = $reflection->newInstance($id);
                     if (!$info['optional'] && $sorm->isNew()) {
-                        throw new Trails_Exception(
+                        throw new Trails\Exception(
                             404,
                             "Parameter {$info['var']} could not be resolved with value {$arg}"
                         );
@@ -247,7 +247,7 @@ abstract class StudipController extends Trails_Controller
                     break;
 
                 default:
-                    throw new Trails_Exception(500, 'Unknown type "' . $type . '"');
+                    throw new Trails\Exception(500, 'Unknown type "' . $type . '"');
             }
         }
 
@@ -497,11 +497,11 @@ abstract class StudipController extends Trails_Controller
         $chunk_size = 262144
     ) {
         if (!file_exists($file)) {
-            throw new Trails_Exception(404);
+            throw new Trails\Exception(404);
         }
 
         if (!is_readable($file)) {
-            throw new Trails_Exception(500);
+            throw new Trails\Exception(500);
         }
 
         if ($content_type === null) {
@@ -593,7 +593,7 @@ abstract class StudipController extends Trails_Controller
      * through
      *
      * @param string $to_uri a trails route
-     * @return Trails_Response
+     * @return Trails\Response
      */
     public function relay($to_uri/* , ... */)
     {
@@ -617,11 +617,11 @@ abstract class StudipController extends Trails_Controller
      * Relays current request and performs redirect if neccessary.
      *
      * @param string $to_uri a trails route
-     * @return Trails_Response
+     * @return Trails\Response
      *
      * @see StudipController::relay()
      */
-    public function relayWithRedirect(...$args): Trails_Response
+    public function relayWithRedirect(...$args): Trails\Response
     {
         $response = $this->relay(...$args);
 
@@ -641,7 +641,7 @@ abstract class StudipController extends Trails_Controller
      *
      * @see perform
      * @param string $unconsumed
-     * @return Trails_Response
+     * @return Trails\Response
      */
     public function perform_relayed($unconsumed/* , ... */)
     {
@@ -695,9 +695,9 @@ abstract class StudipController extends Trails_Controller
      *    <code>$controller->baz($param)</code>
      *
      * @param String $method    Called method name
-     * @param array  $argumetns Provided arguments
-     * @return url to the requested action
-     * @throws Trails_UnknownAction if no action matches the method
+     * @param array  $arguments Provided arguments
+     * @return string url to the requested action
+     * @throws Trails\Exceptions\UnknownAction if no action matches the method
      */
     public function __call($method, $arguments)
     {
@@ -710,7 +710,7 @@ abstract class StudipController extends Trails_Controller
         }
 
         if (!$this->has_action($method)) {
-            throw new Trails_UnknownAction("Unknown action '{$method}'");
+            throw new Trails\Exceptions\UnknownAction("Unknown action '{$method}'");
         }
 
         array_unshift($arguments, $method);
@@ -858,7 +858,7 @@ abstract class StudipController extends Trails_Controller
 
         // Extract controller name from class name
         $controller = preg_replace('/Controller$/', '', get_class($this));
-        $controller = Trails_Inflector::underscore($controller);
+        $controller = Trails\Inflector::underscore($controller);
 
         // Build main parts of the body element id
         $body_id_parts = explode('/', $controller);
diff --git a/lib/classes/StudipDispatcher.php b/lib/classes/StudipDispatcher.php
index af0ea48b9aae078a97bc2e7e3f183d8f83f25cd4..a41635a9034e30ef9a00c07b4e07712046d525ce 100644
--- a/lib/classes/StudipDispatcher.php
+++ b/lib/classes/StudipDispatcher.php
@@ -18,29 +18,31 @@ use Psr\Container\ContainerInterface;
 
 /**
  * Use this subclass to easily get an Stud.IP specific
- * Trails_Dispatcher.
+ * Trails\Dispatcher.
  *
  * Example of use:
+ *
  * @code
  * // deep in the Stud.IP jungle
  * $dispatcher = new StudipDispatcher();
  * $dispatcher->dispatch($requested_uri);
  * @endcode
  */
-class StudipDispatcher extends Trails_Dispatcher {
-
-  /**
-   * This variable contains the DI-Container.
-   * @var ContainerInterface
-   */
-  protected $container;
+class StudipDispatcher extends Trails\Dispatcher
+{
+    /**
+     * This variable contains the DI-Container.
+     *
+     * @var ContainerInterface
+     */
+    protected $container;
 
-  /**
-   * Create a new Trails_Dispatcher with Stud.IP specific parameters
-   * for: trails_root is "$STUDIP_BASE_PATH/app", trails_uri is
-   * "dispatch.php" and default_controller is "default" (which does
-   * not map to anything).
-   */
+    /**
+     * Create a new Trails\Dispatcher with Stud.IP specific parameters
+     * for: trails_root is "$STUDIP_BASE_PATH/app", trails_uri is
+     * "dispatch.php" and default_controller is "default" (which does
+     * not map to anything).
+     */
     public function __construct(ContainerInterface $container)
     {
         global $STUDIP_BASE_PATH, $ABSOLUTE_URI_STUDIP;
@@ -58,6 +60,7 @@ class StudipDispatcher extends Trails_Dispatcher {
      * exception instead of the standard trails handling.
      *
      * @param Exception $exception The exception that occured
+     *
      * @throws Exception
      */
     public function trails_error($exception)
@@ -66,21 +69,22 @@ class StudipDispatcher extends Trails_Dispatcher {
     }
 
     /**
-   * Loads the controller file for a given controller path and return an
-   * instance of that controller. If an error occures, an exception will be
-   * thrown.
-   *
-   * @param  string            the relative controller path
-   *
-   * @return TrailsController  an instance of that controller
-   */
-  function load_controller($controller) {
-    require_once "{$this->trails_root}/controllers/{$controller}.php";
-    $class = Trails_Inflector::camelize($controller) . 'Controller';
-    if (!class_exists($class)) {
-      throw new Trails_UnknownController("Controller missing: '$class'");
-    }
+     * Loads the controller file for a given controller path and return an
+     * instance of that controller. If an error occures, an exception will be
+     * thrown.
+     *
+     * @param string $controller the relative controller path
+     * @return Trails\Controller  an instance of that controller
+     * @throws \Trails\Exceptions\UnknownController
+     */
+    public function load_controller($controller)
+    {
+        require_once "{$this->trails_root}/controllers/{$controller}.php";
+        $class = Trails\Inflector::camelize($controller) . 'Controller';
+        if (!class_exists($class)) {
+            throw new Trails\Exceptions\UnknownController("Controller missing: '$class'");
+        }
 
-    return $this->container->make($class, ['dispatcher' => $this]);
-  }
+        return $this->container->make($class, ['dispatcher' => $this]);
+    }
 }
diff --git a/lib/classes/StudipResponse.php b/lib/classes/StudipResponse.php
index 1c153265de9a940a0f856196cf754af35cc3e24d..a9f1a4c36997643edafe7ba358079fcc4946efb7 100644
--- a/lib/classes/StudipResponse.php
+++ b/lib/classes/StudipResponse.php
@@ -1,5 +1,5 @@
 <?php
-class StudipResponse extends Trails_Response
+class StudipResponse extends Trails\Response
 {
     /**
      * Outputs this response to the client using "echo" and "header".
diff --git a/lib/functions.php b/lib/functions.php
index 6b006084e77189673e022a88c4e021eba5e06d3a..e1b29ed01598d6719bf8a8f05d03778cf7075483 100644
--- a/lib/functions.php
+++ b/lib/functions.php
@@ -1319,7 +1319,7 @@ function get_route($route = '')
         $route = 'plugins.php/' . $pieces[0] . (!empty($pieces[1]) ? '/' . $pieces[1] : '') . (!empty($pieces[2]) ? '/' . $pieces[2] : '');
     } elseif (mb_strpos($route, 'dispatch.php/') !== false) {
         $trails = explode('dispatch.php/', $route);
-        $dispatcher = app(\Trails_Dispatcher::class);
+        $dispatcher = app(\Trails\Dispatcher::class);
         $pieces = explode('/', $trails[1]);
         $trail = '';
         foreach ($pieces as $index => $piece) {
@@ -1399,7 +1399,7 @@ function studip_default_exception_handler($exception) {
     } elseif ($exception instanceof LoginException) {
         $GLOBALS['auth']->login_if(true);
     } else {
-        if ($exception instanceOf Trails_Exception) {
+        if ($exception instanceOf Trails\Exception) {
             $status = $exception->getCode();
         } else {
             $status = 500;
@@ -1457,6 +1457,19 @@ function strtocamelcase($string, $ucfirst = false) {
     return implode($chunks);
 }
 
+/**
+ * Converts a string to PascalCase.
+ *
+ * @param String $string  The string that should be converted
+ * @return String containing the converted input string
+ */
+function strtopascalcase(string $string): string {
+    return strtocamelcase(
+        str_replace('_', ' ', $string),
+        true
+    );
+}
+
 /**
  * Converts a string to snake_case.
  *
diff --git a/lib/modules/EvaluationsWidget.php b/lib/modules/EvaluationsWidget.php
index dab271f932a6efd91e29e9e568335862a1a08937..21410e2430a573ce2ea62f9bb17bc8c732ee70dd 100644
--- a/lib/modules/EvaluationsWidget.php
+++ b/lib/modules/EvaluationsWidget.php
@@ -43,7 +43,7 @@ class EvaluationsWidget extends CorePlugin implements PortalPlugin
         }
 
         // include and show votes and tests
-        $controller = app(AuthenticatedController::class, ['dispatcher' => app(\Trails_Dispatcher::class)]);
+        $controller = app(AuthenticatedController::class, ['dispatcher' => app(\Trails\Dispatcher::class)]);
         $controller->suppress_empty_output = true;
         $response = $controller->relay('questionnaire/widget/start')->body;
 
diff --git a/lib/modules/MyCoursesWidget.php b/lib/modules/MyCoursesWidget.php
index 81aceeda0d7103bed8983241955866fe1f629cdc..ba73e5b0405eb69c4dde1f22ce4c06aaaca52965 100644
--- a/lib/modules/MyCoursesWidget.php
+++ b/lib/modules/MyCoursesWidget.php
@@ -26,7 +26,7 @@ class MyCoursesWidget extends CorePlugin implements PortalPlugin
     public function getPortalTemplate()
     {
         // get the MyCoursesController in order to prepare the correct data for the overview
-        $controller = app(MyCoursesController::class, ['dispatcher' => app(\Trails_Dispatcher::class)]);
+        $controller = app(MyCoursesController::class, ['dispatcher' => app(\Trails\Dispatcher::class)]);
         $data = $controller->getPortalWidgetData();
 
         // add the json data to the head so vue can grab it
diff --git a/lib/modules/NewsWidget.php b/lib/modules/NewsWidget.php
index fc3befdb0ced6766b139170ff6f517aa237414bb..ae211f2b7c2dccddde1a348166a2a054902e98c5 100644
--- a/lib/modules/NewsWidget.php
+++ b/lib/modules/NewsWidget.php
@@ -25,7 +25,7 @@ class NewsWidget extends CorePlugin implements PortalPlugin
 
     function getPortalTemplate()
     {
-        $controller = app(\Trails_Dispatcher::class)->load_controller('news');
+        $controller = app(\Trails\Dispatcher::class)->load_controller('news');
         $response = $controller->relayWithRedirect('news/display/studip');
         $template = $GLOBALS['template_factory']->open('shared/string');
         $template->content = $response->body;
diff --git a/lib/modules/TerminWidget.php b/lib/modules/TerminWidget.php
index 773e6923948d73a028c2a0483d8b3a0877c7c89d..4274ee411c39a3449b78dfab94c05e582b4a3287 100644
--- a/lib/modules/TerminWidget.php
+++ b/lib/modules/TerminWidget.php
@@ -26,7 +26,7 @@ class TerminWidget extends CorePlugin implements PortalPlugin
 
     public function getPortalTemplate()
     {
-        $controller = app(\Trails_Dispatcher::class)->load_controller('calendar/contentbox');
+        $controller = app(\Trails\Dispatcher::class)->load_controller('calendar/contentbox');
         $response = $controller->relay('calendar/contentbox/display/'.$GLOBALS['user']->id);
         $template = $GLOBALS['template_factory']->open('shared/string');
         $template->content = $response->body;
diff --git a/lib/plugins/core/StudIPPlugin.class.php b/lib/plugins/core/StudIPPlugin.class.php
index ea5c8ff0d97f890acea9f9edafc6242f9a5bd981..fe74259dcff280de242d15527aa27ec8fb6d1577 100644
--- a/lib/plugins/core/StudIPPlugin.class.php
+++ b/lib/plugins/core/StudIPPlugin.class.php
@@ -196,14 +196,14 @@ abstract class StudIPPlugin
         $action = $args[0] !== '' ? array_shift($args).'_action' : 'show_action';
 
         if (!method_exists($this, $action)) {
-            $dispatcher = app(\Trails_Dispatcher::class);
+            $dispatcher = app(\Trails\Dispatcher::class);
             $dispatcher->trails_root = $this->getPluginPath();
             $dispatcher->trails_uri = rtrim(PluginEngine::getLink($this, [], null, true), '/');
             $dispatcher->default_controller = 'index';
             $dispatcher->current_plugin = $this;
             try {
                 $dispatcher->dispatch($unconsumed_path);
-            } catch (Trails_UnknownAction $exception) {
+            } catch (Trails\Exceptions\UnknownAction $exception) {
                 if (count($args) > 0) {
                     throw $exception;
                 } else {
diff --git a/lib/seminar_open.php b/lib/seminar_open.php
index 1c0056b35778f9b036358c28ac49ea742d847d5a..2e831bf7ce1035f812bee2bf0e5c01d7acdf0b04 100644
--- a/lib/seminar_open.php
+++ b/lib/seminar_open.php
@@ -216,7 +216,7 @@ if (is_object($GLOBALS['user'])
     if (!Request::isXhr()) {
         header('Location: ' . URLHelper::getURL('dispatch.php/terms', ['return_to' => $_SERVER['REQUEST_URI'], 'redirect_token' => Token::create(600)], true));
     } else {
-        throw new Trails_Exception(400);
+        throw new Trails\Exception(400);
     }
     page_close();
     die;
diff --git a/lib/trails/Controller.php b/lib/trails/Controller.php
new file mode 100644
index 0000000000000000000000000000000000000000..a5a0ba7b3e37f828cbbff059d8397d85df0cf055
--- /dev/null
+++ b/lib/trails/Controller.php
@@ -0,0 +1,411 @@
+<?php
+namespace Trails;
+
+use Flexi\Factory;
+use Flexi\Template;
+use Flexi\TemplateNotFoundException;
+use Trails\Exceptions\DoubleRenderError;
+use Trails\Exceptions\UnknownAction;
+
+/**
+ * A Controller is responsible for matching the unconsumed part of an URI
+ * to an action using the left over words as arguments for that action. The
+ * action is then mapped to method of the controller instance which is called
+ * with the just mentioned arguments. That method can send the #render_action,
+ * #render_template, #render_text, #render_nothing or #redirect method.
+ * Otherwise the #render_action is called with the current action as argument.
+ * If the action method sets instance variables during performing, they will be
+ * be used as attributes for the flexi-template opened by #render_action or
+ * #render_template. A controller's response's body is populated with the output
+ * of the #render_* methods. The action methods can add additional headers or
+ * change the status of that response.
+ *
+ * @package       trails
+ *
+ * @author        mlunzena
+ * @copyright (c) Authors
+ * @version       $Id: trails.php 7001 2008-04-04 11:20:27Z mlunzena $
+ */
+class Controller
+{
+    protected Dispatcher $dispatcher;
+    protected Response $response;
+    protected bool $performed = false;
+    protected Template|string|null $layout;
+    protected string $format = 'html';
+
+    /**
+     * @param Dispatcher $dispatcher the dispatcher who creates this instance
+     */
+    public function __construct(Dispatcher $dispatcher)
+    {
+        $this->dispatcher = $dispatcher;
+        $this->erase_response();
+    }
+
+    /**
+     * Resets the response of the controller
+     *
+     * @return void
+     */
+    public function erase_response()
+    {
+        $this->performed = false;
+        $this->response = new Response();
+    }
+
+    /**
+     * Return this controller's response
+     *
+     * @return Response the controller's response
+     */
+    public function get_response()
+    {
+        return $this->response;
+    }
+
+    /**
+     * This method extracts an action string and further arguments from it's
+     * parameter. The action string is mapped to a method being called afterwards
+     * using the said arguments. That method is called and a response object is
+     * generated, populated and sent back to the dispatcher.
+     *
+     * @param string $unconsumed
+     *
+     * @return Response
+     * @throws UnknownAction
+     */
+    public function perform($unconsumed)
+    {
+        [$action, $args, $format] = $this->extract_action_and_args($unconsumed);
+
+        $this->format = $format ?? 'html';
+
+        $before_filter_result = $this->before_filter($action, $args);
+
+        # send action to controller
+        # TODO (mlunzena) shouldn't the after filter be triggered too?
+        if (!($before_filter_result === false || $this->performed)) {
+
+            $callable = $this->map_action($action);
+
+            if (is_callable($callable)) {
+                $callable(...$args);
+            } else {
+                $this->does_not_understand($action, $args);
+            }
+
+            if (!$this->performed) {
+                $this->render_action($action);
+            }
+
+            $this->after_filter($action, $args);
+        }
+
+        return $this->response;
+    }
+
+    /**
+     * Extracts action and args from a string.
+     *
+     * @param string $string the processed string
+     * @return array        an array with two elements - a string containing the
+     *                      action and an array of strings representing the args
+     */
+    public function extract_action_and_args($string)
+    {
+        if ('' === $string) {
+            return $this->default_action_and_args();
+        }
+
+        // find optional file extension
+        $format = null;
+        if (preg_match('/^(.*[^\/.])\.(\w+)$/', $string, $matches)) {
+            [, $string, $format] = $matches;
+        }
+
+        // TODO this should possibly remove empty tokens
+        $args = explode('/', $string);
+        $action = array_shift($args);
+        return [$action, $args, $format];
+    }
+
+    /**
+     * Return the default action and arguments
+     *
+     * @return array containing the action, an array of args and the format
+     */
+    public function default_action_and_args()
+    {
+        return ['index', [], null];
+    }
+
+    /**
+     * Maps the action to an actual method name.
+     *
+     * @param string $action
+     * @return array  the mapped method name
+     */
+    public function map_action($action)
+    {
+        return [&$this, $action . '_action'];
+    }
+
+    /**
+     * Callback function being called before an action is executed. If this
+     * function does not return FALSE, the action will be called, otherwise
+     * an error will be generated and processing will be aborted. If this function
+     * already #rendered or #redirected, further processing of the action is
+     * withheld.
+     *
+     * @param string $action Name of the action to perform.
+     * @param array  $args   An array of arguments to the action.
+     * @return bool|void
+     */
+    public function before_filter(&$action, &$args)
+    {
+    }
+
+    /**
+     * Callback function being called after an action is executed.
+     *
+     * @param string $action Name of the action to perform.
+     * @param array  $args   An array of arguments to the action.
+     * @return void
+     */
+    public function after_filter($action, $args)
+    {
+    }
+
+    /**
+     * @param string $action
+     * @param array  $args
+     * @return void
+     * @throws UnknownAction
+     */
+    public function does_not_understand($action, $args)
+    {
+        throw new Exceptions\UnknownAction("No action responded to '$action'.");
+    }
+
+    /**
+     * @param string $to
+     *
+     * @return void
+     * @throws DoubleRenderError
+     */
+    public function redirect($to)
+    {
+        if ($this->performed) {
+            throw new Exceptions\DoubleRenderError();
+        }
+
+        $this->performed = true;
+
+        # get uri; keep absolute URIs
+        $url = preg_match('#^(/|\w+://)#', $to)
+            ? $to
+            : $this->url_for($to);
+
+        $this->response->add_header('Location', $url)->set_status(302);
+    }
+
+    /**
+     * Renders the given text as the body of the response.
+     *
+     * @param string $text the text to be rendered
+     * @return void
+     * @throws DoubleRenderError
+     */
+    public function render_text($text = ' ')
+    {
+        if ($this->performed) {
+            throw new Exceptions\DoubleRenderError();
+        }
+
+        $this->performed = true;
+
+        $this->response->set_body($text);
+    }
+
+    /**
+     * Renders the empty string as the response's body.
+     *
+     * @return void
+     * @throws DoubleRenderError
+     */
+    public function render_nothing()
+    {
+        $this->render_text('');
+    }
+
+    /**
+     * Renders the template of the given action as the response's body.
+     *
+     * @param string $action the action
+     * @return void
+     */
+    public function render_action($action)
+    {
+        $this->render_template(
+            $this->get_default_template($action),
+            $this->layout
+        );
+    }
+
+    public function get_default_template($action)
+    {
+        $controller_name = Inflector::underscore(
+            substr(static::class, 0, -10)
+        );
+        return $controller_name . '/' . $action;
+    }
+
+    /**
+     * Renders a template using an optional layout template.
+     *
+     * @param Template|string      $template_name a flexi template
+     * @param Template|string|null $layout        a flexi template which is used as layout
+     *
+     * @return void
+     * @throws DoubleRenderError
+     * @throws TemplateNotFoundException
+     */
+    public function render_template($template_name, $layout = null)
+    {
+        $factory = $this->get_template_factory();
+        $template = $factory->open($template_name);
+
+        $template->set_attributes($this->get_assigned_variables());
+
+        if (isset($layout)) {
+            $template->set_layout($layout);
+        }
+
+        $this->render_text($template->render());
+    }
+
+    /**
+     * Create and return a template factory for this controller.
+     *
+     * @return Factory
+     */
+    public function get_template_factory()
+    {
+        return new Factory($this->dispatcher->trails_root . '/views/');
+    }
+
+    /**
+     * This method returns all the set instance variables to be used as attributes
+     * for a template. This controller is returned too as value for
+     * key 'controller'.
+     *
+     * @return array  an associative array of variables for the template
+     */
+    public function get_assigned_variables()
+    {
+        $assigns = [];
+        $protected = get_class_vars(static::class);
+
+        foreach (get_object_vars($this) as $var => $value) {
+            if (!array_key_exists($var, $protected)) {
+                $assigns[$var] =& $this->$var;
+            }
+        }
+
+        $assigns['controller'] = $this;
+
+        return $assigns;
+    }
+
+    /**
+     * Sets the layout to be used by this controller per default.
+     *
+     * @param Template|string|null $layout a flexi template to be used as layout
+     * @return void
+     */
+    public function set_layout($layout)
+    {
+        $this->layout = $layout;
+    }
+
+    /**
+     * Returns a URL to a specified route to your Trails application.
+     *
+     * Example:
+     * Your Trails application is located at 'http://example.com/dispatch.php'.
+     * So your dispatcher's trails_uri is set to 'http://example.com/dispatch.php'
+     * If you want the URL to your 'wiki' controller with action 'show' and
+     * parameter 'page' you should send:
+     *
+     *   $url = $controller->url_for('wiki/show', 'page');
+     *
+     * $url should then contain 'http://example.com/dispatch.php/wiki/show/page'.
+     *
+     * The first parameter is a string containing the controller and optionally an
+     * action:
+     *
+     *   - "{controller}/{action}"
+     *   - "path/to/controller/action"
+     *   - "controller"
+     *
+     * This "controller/action" string is not url encoded. You may provide
+     * additional parameter which will be urlencoded and concatenated with
+     * slashes:
+     *
+     *     $controller->url_for('wiki/show', 'page');
+     *     -> 'wiki/show/page'
+     *
+     *     $controller->url_for('wiki/show', 'page', 'one and a half');
+     *     -> 'wiki/show/page/one+and+a+half'
+     *
+     * @param string $to a string containing a controller and optionally an action
+     * @return string  a URL to this route
+     */
+    public function url_for($to/*, ...*/)
+    {
+        # urlencode all but the first argument
+        $args = func_get_args();
+        $args = array_map('urlencode', $args);
+        $args[0] = $to;
+
+        return $this->dispatcher->trails_uri . '/' . implode('/', $args);
+    }
+
+    /**
+     * @param int $status
+     * @return void
+     */
+    public function set_status($status, $reason_phrase = null)
+    {
+        $this->response->set_status($status, $reason_phrase);
+    }
+
+    /**
+     * Sets the content type of the controller's response.
+     *
+     * @param string $type the content type
+     * @return void
+     */
+    public function set_content_type($type)
+    {
+        $this->response->add_header('Content-Type', $type);
+    }
+
+    /**
+     * Exception handler called when the performance of an action raises an
+     * exception.
+     *
+     * @param \Throwable $exception the thrown exception
+     * @return Response  a response object
+     */
+    public function rescue($exception)
+    {
+        return $this->dispatcher->trails_error($exception);
+    }
+
+    public function respond_to($ext)
+    {
+        return $this->format === $ext;
+    }
+}
diff --git a/lib/trails/Dispatcher.php b/lib/trails/Dispatcher.php
new file mode 100644
index 0000000000000000000000000000000000000000..efa90c7319c13a3e3595388b4215c81a74b627a1
--- /dev/null
+++ b/lib/trails/Dispatcher.php
@@ -0,0 +1,262 @@
+<?php
+namespace Trails;
+
+use Trails\Exceptions\MissingFile;
+use Trails\Exceptions\RoutingError;
+use Trails\Exceptions\UnknownController;
+
+/**
+ * The Dispatcher is used to map an incoming HTTP request to a Controller
+ * producing a response which is then rendered. To initialize an instance of
+ * class Dispatcher you have to give three configuration settings:
+ *
+ *          trails_root - the absolute file path to a directory containing the
+ *                        applications controllers, views etc.
+ *           trails_uri - the URI to which routes to mapped Controller/Actions
+ *                        are appended
+ *   default_controller - the route to a controller, that is used if no
+ *                        controller is given, that is the route is equal to '/'
+ *
+ * After instantiation of a dispatcher you have to call method #dispatch with
+ * the request uri to be mapped to a controller/action pair.
+ *
+ * @package       trails
+ *
+ * @author        mlunzena
+ * @copyright (c) Authors
+ * @version       $Id: trails.php 7001 2008-04-04 11:20:27Z mlunzena $
+ */
+class Dispatcher
+{
+    # TODO (mlunzena) Konfiguration muss anders geschehen
+
+    /**
+     * This is the absolute file path to the trails application directory.
+     */
+    public string $trails_root;
+
+    /**
+     * This is the URI to which routes to controller/actions are appended.
+     */
+    public string $trails_uri;
+
+    /**
+     * This variable contains the route to the default controller.
+     */
+    public string $default_controller;
+
+    /**
+     * @param string $trails_root        absolute file path to a directory containing the
+     *                 applications controllers, views etc.
+     * @param string $trails_uri         the URI to which routes to mapped Controller/Actions
+     *                 are appended
+     * @param string $default_controller the route to a controller, that is used if no
+     *                 controller is given, that is the route is equal to '/'
+     */
+    public function __construct(
+        string $trails_root,
+        string $trails_uri,
+        string $default_controller
+    ) {
+        $this->trails_root = $trails_root;
+        $this->trails_uri = $trails_uri;
+        $this->default_controller = $default_controller;
+    }
+
+    /**
+     * Maps a string to a response which is then rendered.
+     *
+     * @param string $uri The requested URI.
+     */
+    public function dispatch($uri)
+    {
+        # E_USER_ERROR|E_USER_WARNING|E_USER_NOTICE|E_RECOVERABLE_ERROR = 5888
+        $old_handler = set_error_handler([$this, 'error_handler'], 5888);
+
+        ob_start();
+        $level = ob_get_level();
+
+        $this->map_uri_to_response($this->clean_request_uri((string) $uri))->output();
+
+        while (ob_get_level() >= $level) {
+            ob_end_flush();
+        }
+
+        if (isset($old_handler)) {
+            set_error_handler($old_handler);
+        }
+    }
+
+    /**
+     * Maps an URI to a response by figuring out first what controller to
+     * instantiate, then delegating the unconsumed part of the URI to the
+     * controller who returns an appropriate response object or throws an
+     * Exception.
+     *
+     * @param string $uri the URI string
+     * @return Response a response object
+     */
+    public function map_uri_to_response($uri)
+    {
+        try {
+            [$controller_path, $unconsumed] = '' === $uri ? $this->default_route() : $this->parse($uri);
+
+            $controller = $this->load_controller($controller_path);
+
+            $response = $controller->perform($unconsumed);
+        } catch (Exception $e) {
+            $response = isset($controller) ? $controller->rescue($e) : $this->trails_error($e);
+        }
+
+        return $response;
+    }
+
+    /**
+     * @return array  an array containing the default controller and an
+     *                empty unconsumed route
+     * @throws MissingFile
+     */
+    public function default_route()
+    {
+        if (!$this->file_exists($this->default_controller . '.php')) {
+            throw new Exceptions\MissingFile(
+                "Default controller '{$this->default_controller}' not found'"
+            );
+        }
+        return [$this->default_controller, ''];
+    }
+
+    public function trails_error($exception)
+    {
+        ob_clean();
+
+        # show details for local requests
+        $detailed = @$_SERVER['REMOTE_ADDR'] === '127.0.0.1';
+
+        $body = sprintf('<html><head><title>Trails Error</title></head>' .
+            '<body><h1>%s</h1><pre>%s</pre></body></html>',
+            htmlentities($exception->__toString()),
+            $detailed
+                ? htmlentities($exception->getTraceAsString())
+                : '');
+
+        if ($exception instanceof Exception) {
+            $response = new Response(
+                $body,
+                $exception->getHeaders(),
+                $exception->getCode(),
+                $exception->getMessage()
+            );
+        } else {
+            $response = new Response(
+                $body,
+                [],
+                500,
+                $exception->getMessage()
+            );
+        }
+
+        return $response;
+    }
+
+    /**
+     * Clean up URI string by removing the query part and leading slashes.
+     *
+     * @param string $uri an URI string
+     * @return string  the cleaned string
+     */
+    public function clean_request_uri($uri)
+    {
+        $pos = strpos($uri, '?');
+        if ($pos !== false) {
+            $uri = substr($uri, 0, $pos);
+        }
+        return ltrim($uri, '/');
+    }
+
+    /**
+     * @param string $unconsumed
+     * @param string $controller
+     * @return array
+     * @throws RoutingError
+     */
+    public function parse($unconsumed, $controller = null)
+    {
+        [$head, $tail] = $this->split_on_first_slash($unconsumed);
+
+        if (!preg_match('/^\w+$/', $head)) {
+            throw new RoutingError("No route matches '$head'");
+        }
+
+        $controller = (isset($controller) ? $controller . '/' : '') . $head;
+
+        if ($this->file_exists($controller . '.php')) {
+            return [$controller, $tail];
+        }
+
+        if ($this->file_exists($controller)) {
+            return $this->parse($tail, $controller);
+        }
+
+        throw new RoutingError("No route matches '$head'");
+    }
+
+    /**
+     * @param string $str
+     * @return array
+     */
+    public function split_on_first_slash($str)
+    {
+        preg_match(":([^/]*)(/+)?(.*):", $str, $matches);
+        return [$matches[1], $matches[3]];
+    }
+
+    /**
+     * @param string $path
+     * @return bool
+     */
+    public function file_exists($path)
+    {
+        return file_exists("{$this->trails_root}/controllers/$path");
+    }
+
+    /**
+     * Loads the controller file for a given controller path and return an
+     * instance of that controller. If an error occures, an exception will be
+     * thrown.
+     *
+     * @param string $controller the relative controller path
+     * @return Controller  an instance of that controller
+     * @throws UnknownController
+     */
+    public function load_controller($controller)
+    {
+        require_once "{$this->trails_root}/controllers/{$controller}.php";
+        $class = Inflector::camelize($controller) . 'Controller';
+        if (!class_exists($class)) {
+            throw new UnknownController("Controller missing: '$class'");
+        }
+        return new $class($this);
+    }
+
+    /**
+     * This method transforms E_USER_* and E_RECOVERABLE_ERROR to
+     * Exceptions.
+     *
+     * @param integer $errno  the level of the error raised
+     * @param string  $string the error message
+     * @param string  $file   the filename that the error was raised in
+     * @param integer $line   the line number the error was raised at
+     *
+     * @return bool
+     * @throws Exception
+     *
+     */
+    public function error_handler($errno, $string, $file, $line)
+    {
+        if (!(5888 & $errno)) {
+            return false;
+        }
+        throw new Exception(500, $string);
+    }
+}
diff --git a/lib/trails/Exception.php b/lib/trails/Exception.php
new file mode 100644
index 0000000000000000000000000000000000000000..fd92b356cb399c01d8ea95b65abb33dd8c9cecc6
--- /dev/null
+++ b/lib/trails/Exception.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace Trails;
+
+/**
+ * @author        mlunzena
+ * @copyright (c) Authors
+ * @version       $Id: trails.php 7001 2008-04-04 11:20:27Z mlunzena $
+ */
+class Exception extends \Exception
+{
+    protected array $headers;
+
+    /**
+     * @param int         $status  the status code to be set in the response
+     * @param string|null $reason  a human readable presentation of the status code
+     * @param array       $headers a hash of additional headers to be set in the response
+     */
+    public function __construct(int $status = 500, string $reason = null, array $headers = [])
+    {
+        parent::__construct(
+            $reason ?? Response::get_reason($status),
+            $status
+        );
+
+        $this->setHeaders($headers);
+    }
+
+    public function setHeaders(array $headers): void
+    {
+        $this->headers = $headers;
+    }
+
+    public function getHeaders(): array
+    {
+        return $this->headers;
+    }
+
+    public function __toString(): string
+    {
+        return "{$this->code} {$this->message}";
+    }
+}
diff --git a/lib/trails/Exceptions/DoubleRenderError.php b/lib/trails/Exceptions/DoubleRenderError.php
new file mode 100644
index 0000000000000000000000000000000000000000..c2dfe9ea24467d5e42ddf5c12fd33788783e709b
--- /dev/null
+++ b/lib/trails/Exceptions/DoubleRenderError.php
@@ -0,0 +1,13 @@
+<?php
+namespace Trails\Exceptions;
+
+class DoubleRenderError extends \Trails\Exception
+{
+    public function __construct()
+    {
+        $message  = 'Render and/or redirect were called multiple times in this ';
+        $message .= 'action. Please note that you may only call render OR ';
+        $message .= 'redirect, and at most once per action.';
+        parent::__construct(500, $message);
+    }
+}
diff --git a/lib/trails/Exceptions/MissingFile.php b/lib/trails/Exceptions/MissingFile.php
new file mode 100644
index 0000000000000000000000000000000000000000..59e8480c4675a6f196dae8647834c7de305b8e58
--- /dev/null
+++ b/lib/trails/Exceptions/MissingFile.php
@@ -0,0 +1,10 @@
+<?php
+namespace Trails\Exceptions;
+
+class MissingFile extends \Trails\Exception
+{
+    public function __construct(string $message)
+    {
+        parent::__construct(500, $message);
+    }
+}
diff --git a/lib/trails/Exceptions/RoutingError.php b/lib/trails/Exceptions/RoutingError.php
new file mode 100644
index 0000000000000000000000000000000000000000..e62459ef526f5fac247025dc0f74cff6af3afcde
--- /dev/null
+++ b/lib/trails/Exceptions/RoutingError.php
@@ -0,0 +1,10 @@
+<?php
+namespace Trails\Exceptions;
+
+class RoutingError extends \Trails\Exception
+{
+    public function __construct(string $message)
+    {
+        parent::__construct(400, $message);
+    }
+}
diff --git a/lib/trails/Exceptions/SessionRequiredException.php b/lib/trails/Exceptions/SessionRequiredException.php
new file mode 100644
index 0000000000000000000000000000000000000000..b77a344c48eb24d6532d1a09f56e4d354c2faae3
--- /dev/null
+++ b/lib/trails/Exceptions/SessionRequiredException.php
@@ -0,0 +1,11 @@
+<?php
+namespace Trails\Exceptions;
+
+class SessionRequiredException extends \Trails\Exception
+{
+    public function __construct()
+    {
+        $message = 'Tried to access a non existing session.';
+        parent::__construct(500, $message);
+    }
+}
diff --git a/lib/trails/Exceptions/UnknownAction.php b/lib/trails/Exceptions/UnknownAction.php
new file mode 100644
index 0000000000000000000000000000000000000000..f749a51fbf6e061a4c0c5d107b01e32ac52b2d67
--- /dev/null
+++ b/lib/trails/Exceptions/UnknownAction.php
@@ -0,0 +1,10 @@
+<?php
+namespace Trails\Exceptions;
+
+class UnknownAction extends \Trails\Exception
+{
+    public function __construct(string $message)
+    {
+        parent::__construct(404, $message);
+    }
+}
diff --git a/lib/trails/Exceptions/UnknownController.php b/lib/trails/Exceptions/UnknownController.php
new file mode 100644
index 0000000000000000000000000000000000000000..420c2388e62e99c4a33c775ac56f7ed90a05705b
--- /dev/null
+++ b/lib/trails/Exceptions/UnknownController.php
@@ -0,0 +1,10 @@
+<?php
+namespace Trails\Exceptions;
+
+class UnknownController extends \Trails\Exception
+{
+    public function __construct(string $message)
+    {
+        parent::__construct(404, $message);
+    }
+}
diff --git a/lib/trails/Flash.php b/lib/trails/Flash.php
new file mode 100644
index 0000000000000000000000000000000000000000..eede7afb4108635c92cf97b08bbfaa39837f37ab
--- /dev/null
+++ b/lib/trails/Flash.php
@@ -0,0 +1,184 @@
+<?php
+
+namespace Trails;
+
+use Trails\Exceptions\SessionRequiredException;
+
+/**
+ * The flash provides a way to pass temporary objects between actions.
+ * Anything you place in the flash will be exposed to the very next action and
+ * then cleared out. This is a great way of doing notices and alerts, such as
+ * a create action that sets
+ * <tt>$flash->set('notice', "Successfully created")</tt>
+ * before redirecting to a display action that can then expose the flash to its
+ * template.
+ *
+ * @package       trails
+ *
+ * @author        mlunzena
+ * @copyright (c) Authors
+ * @version       $Id: trails.php 7001 2008-04-04 11:20:27Z mlunzena $
+ */
+final class Flash implements \ArrayAccess
+{
+    private array $flash = [];
+    private array $used = [];
+
+    /**
+     * @return self
+     * @throws SessionRequiredException
+     */
+    public static function instance()
+    {
+        if (!isset($_SESSION)) {
+            throw new Exceptions\SessionRequiredException();
+        }
+
+        if (!isset($_SESSION[self::class])) {
+            $_SESSION[self::class] = new self();
+        }
+        return $_SESSION[self::class];
+    }
+
+    public function offsetExists($offset): bool
+    {
+        return isset($this->flash[$offset]);
+    }
+
+    public function offsetGet($offset): mixed
+    {
+        return $this->get($offset);
+    }
+
+    public function offsetSet($offset, $value): void
+    {
+        $this->set($offset, $value);
+    }
+
+    public function offsetUnset($offset): void
+    {
+        unset($this->flash[$offset], $this->used[$offset]);
+    }
+
+    /**
+     * Used internally by the <tt>keep</tt> and <tt>discard</tt> methods
+     *     use()               # marks the entire flash as used
+     *     use('msg')          # marks the "msg" entry as used
+     *     use(null, false)    # marks the entire flash as unused
+     *                         # (keeps it around for one more action)
+     *     use('msg', false)   # marks the "msg" entry as unused
+     *                         # (keeps it around for one more action)
+     *
+     */
+    private function use(?string $key = null, bool $isUsed = true): void
+    {
+        if ($key) {
+            $this->used[$key] = $isUsed;
+        } else {
+            foreach (array_keys($this->used) as $key) {
+                $this->use($key, $isUsed);
+            }
+        }
+    }
+
+    /**
+     * Marks the entire flash or a single flash entry to be discarded by the end
+     * of the current action.
+     *
+     *     $flash->discard()             # discards entire flash
+     *                                   # (it'll still be available for the
+     *                                   # current action)
+     *     $flash->discard('warning')    # discard the "warning" entry
+     *                                   # (it'll still be available for the
+     *                                   # current action)
+     */
+    public function discard(?string $key = null): void
+    {
+        $this->use($key);
+    }
+
+    /**
+     * Returns the value to the specified key.
+     *
+     * @return mixed the key's value.
+     */
+    public function &get(string $key): mixed
+    {
+        $return = null;
+        if (isset($this->flash[$key])) {
+            $return =& $this->flash[$key];
+        }
+        return $return;
+    }
+
+    /**
+     * Keeps either the entire current flash or a specific flash entry available
+     * for the next action:
+     *
+     *    $flash->keep()           # keeps the entire flash
+     *    $flash->keep('notice')   # keeps only the "notice" entry, the rest of
+     *                             # the flash is discarded
+     */
+    public function keep(?string $key = null): void
+    {
+        $this->use($key, false);
+    }
+
+    /**
+     * Sets a key's value.
+     */
+    public function set(string $key, mixed $value): void
+    {
+        $this->keep($key);
+        $this->flash[$key] = $value;
+    }
+
+    /**
+     * Sets a key's value by reference.
+     */
+    public function set_ref(string $key, mixed &$value): void
+    {
+        $this->keep($key);
+        $this->flash[$key] =& $valze;
+    }
+
+    /**
+     * Removes all used values
+     */
+    public function sweep(): void
+    {
+        foreach (array_keys($this->flash) as $k) {
+            if ($this->used[$k]) {
+                unset($this->flash[$k], $this->used[$k]);
+            } else {
+                $this->use($k);
+            }
+        }
+    }
+
+    public function __toString()
+    {
+        $values = [];
+        foreach ($this->flash as $key => $value) {
+            $values[] = sprintf(
+                "'%s': [%s, '%s']",
+                $key,
+                var_export($value, true),
+                !empty($this->used[$key]) ? 'used' : 'unused'
+            );
+        }
+        return '{' . implode(', ', $values) . '}'. "\n";
+    }
+
+    public function __sleep(): array
+    {
+        $this->sweep();
+        return ['flash', 'used'];
+    }
+
+
+    public function __wakeUp()
+    {
+        $this->discard();
+    }
+}
diff --git a/lib/trails/Inflector.php b/lib/trails/Inflector.php
new file mode 100644
index 0000000000000000000000000000000000000000..bbc6b5834a8a94c28e81cff6113fdef55794b153
--- /dev/null
+++ b/lib/trails/Inflector.php
@@ -0,0 +1,44 @@
+<?php
+namespace Trails;
+
+/**
+ * The Inflector class is a namespace for inflections methods.
+ *
+ * @package       trails
+ *
+ * @author        mlunzena
+ * @copyright (c) Authors
+ * @version       $Id: trails.php 7001 2008-04-04 11:20:27Z mlunzena $
+ */
+class Inflector
+{
+    /**
+     * Returns a camelized string from a lower case and underscored string by
+     * replacing slash with underscore and upper-casing each letter preceded
+     * by an underscore.
+     *
+     * @param string $word String to camelize.
+     * @return string Camelized string.
+     */
+    public static function camelize(string $word): string
+    {
+        $parts = explode('/', $word);
+        foreach ($parts as $key => $part) {
+            $parts[$key] = strtopascalcase($part);
+        }
+        return implode('_', $parts);
+    }
+
+    /**
+     * @param string $word
+     * @return string
+     */
+    public static function underscore(string $word): string
+    {
+        $parts = explode('_', $word);
+        foreach ($parts as $key => $part) {
+            $parts[$key] = strtosnakecase($part);
+        }
+        return implode('/', $parts);
+    }
+}
diff --git a/lib/trails/Response.php b/lib/trails/Response.php
new file mode 100644
index 0000000000000000000000000000000000000000..b3f14d8003139bb04616effe42f46c23d4477a54
--- /dev/null
+++ b/lib/trails/Response.php
@@ -0,0 +1,185 @@
+<?php
+namespace Trails;
+
+/**
+ * This class represents a response returned by a controller that was asked to
+ * perform for a given request. A Response contains the body, status and
+ * additional headers which can be renderer back to the client.
+ *
+ * @package       trails
+ *
+ * @author        mlunzena
+ * @copyright (c) Authors
+ * @version       $Id: trails.php 7001 2008-04-04 11:20:27Z mlunzena $
+ */
+class Response
+{
+    public $body = '';
+    public $status;
+    public $reason;
+    public $headers = [];
+
+    /**
+     * Constructor.
+     *
+     * @param string      $body    the body of the response defaulting to ''
+     * @param array       $headers an array of additional headers defaulting to an
+     *                             empty array
+     * @param int|null    $status  the status code of the response defaulting to a
+     *                             regular 200
+     * @param string|null $reason  the descriptional reason for a status code defaulting to
+     *                             the standard reason phrases defined in RFC 2616
+     */
+    public function __construct(
+        string $body = '',
+        array $headers = [],
+        ?int $status = null,
+        ?string $reason = null
+    ) {
+        $this->set_body($body);
+
+        $this->headers = $headers;
+
+        if (isset($status)) {
+            $this->set_status($status, $reason);
+        }
+    }
+
+    /**
+     * Sets the body of the response.
+     *
+     * @param string $body the body
+     * @return static   this response object. Useful for cascading method calls.
+     */
+    public function set_body($body)
+    {
+        $this->body = $body;
+        return $this;
+    }
+
+    /**
+     * Sets the status code and an optional custom reason. If none is given, the
+     * standard reason phrase as of RFC 2616 is used.
+     *
+     * @param integer $status the status code
+     * @param string  $reason the custom reason, defaulting to the one given in RFC 2616
+     * @return static    this response object. Useful for cascading method calls.
+     */
+    public function set_status($status, $reason = null)
+    {
+        $this->status = $status;
+        $this->reason = $reason ?? self::get_reason($status);
+        return $this;
+    }
+
+    /**
+     * Returns the reason phrase of this response according to RFC2616.
+     *
+     * @param int $status the response's status
+     * @return string  the reason phrase for this response's status
+     */
+    public static function get_reason($status)
+    {
+        return match ($status) {
+            100 => 'Continue',
+            101 => 'Switching Protocols',
+
+            200 => 'OK',
+            201 => 'Created',
+            202 => 'Accepted',
+            203 => 'Non-Authoritative Information',
+            204 => 'No Content',
+            205 => 'Reset Content',
+            206 => 'Partial Content',
+
+            300 => 'Multiple Choices',
+            301 => 'Moved Permanently',
+            302 => 'Found',
+            303 => 'See Other',
+            304 => 'Not Modified',
+            305 => 'Use Proxy',
+            306 => '(Unused)',
+            307 => 'Temporary Redirect',
+
+            400 => 'Bad Request',
+            401 => 'Unauthorized',
+            402 => 'Payment Required',
+            403 => 'Forbidden',
+            404 => 'Not Found',
+            405 => 'Method Not Allowed',
+            406 => 'Not Acceptable',
+            407 => 'Proxy Authentication Required',
+            408 => 'Request Timeout',
+            409 => 'Conflict',
+            410 => 'Gone',
+            411 => 'Length Required',
+            412 => 'Precondition Failed',
+            413 => 'Request Entity Too Large',
+            414 => 'Request-URI Too Long',
+            415 => 'Unsupported Media Type',
+            416 => 'Requested Range Not Satisfiable',
+            417 => 'Expectation Failed',
+
+            500 => 'Internal Server Error',
+            501 => 'Not Implemented',
+            502 => 'Bad Gateway',
+            503 => 'Service Unavailable',
+            504 => 'Gateway Timeout',
+            505 => 'HTTP Version Not Supported',
+
+            default => '',
+        };
+    }
+
+    /**
+     * Adds an additional header to the response.
+     *
+     * @param string $key   the left hand key part
+     * @param string $value the right hand value part
+     * @return static   this response object. Useful for cascading method calls.
+     */
+    public function add_header($key, $value)
+    {
+        $this->headers[$key] = $value;
+        return $this;
+    }
+
+    /**
+     * Outputs this response to the client using "echo" and "header".
+     * @return void
+     */
+    public function output()
+    {
+        if (isset($this->status)) {
+            $this->send_header(
+                "HTTP/1.1 {$this->status} {$this->reason}",
+                true,
+                $this->status
+            );
+        }
+
+        foreach ($this->headers as $k => $v) {
+            $this->send_header("{$k}: {$v}");
+        }
+
+        echo $this->body;
+    }
+
+    /**
+     * Internally used function to actually send headers
+     *
+     * @param string  $header  the HTTP header
+     * @param bool    $replace optional; TRUE if previously sent header should be
+     *                    replaced - FALSE otherwise (default)
+     * @param integer $status  optional; the HTTP response code
+     * @return void
+     */
+    public function send_header($header, $replace = false, $status = null)
+    {
+        if (isset($status)) {
+            header($header, $replace, $status);
+        } else {
+            header($header, $replace);
+        }
+    }
+}
diff --git a/public/assets.php b/public/assets.php
index a0baa6dcd05df7746b815622d7b7040fa0d99d2d..3610a13ef1fda062adeb918f6bdecb85d0617011 100644
--- a/public/assets.php
+++ b/public/assets.php
@@ -19,7 +19,7 @@ $uri = ltrim(Request::pathInfo(), '/');
 list($type, $id) = explode('/', $uri, 2);
 
 // Setup response
-$response = new Trails_Response();
+$response = new Trails\Response();
 
 // Create response
 if (!$type || !$id) {
diff --git a/public/dispatch.php b/public/dispatch.php
index 68d03996bef498b5ca5dd7a91d5eaf3615ca023b..77c593310f9d94edcab0c568fe5eb97583b63b2f 100644
--- a/public/dispatch.php
+++ b/public/dispatch.php
@@ -21,5 +21,5 @@ require '../lib/bootstrap.php';
 // prepare environment
 URLHelper::setBaseUrl($GLOBALS['ABSOLUTE_URI_STUDIP']);
 
-$dispatcher = app(\Trails_Dispatcher::class);
+$dispatcher = app(\Trails\Dispatcher::class);
 $dispatcher->dispatch(Request::pathInfo());
diff --git a/public/install.php b/public/install.php
index 4e54575875b6454759f84a11752502871cf15c5c..e32cf7544ab59f97507c9481e309fbd1a90b4dc8 100644
--- a/public/install.php
+++ b/public/install.php
@@ -17,7 +17,6 @@ set_include_path($GLOBALS['STUDIP_BASE_PATH']);
 
 require_once 'composer/autoload.php';
 require_once 'lib/visual.inc.php';
-require_once 'vendor/trails/trails.php';
 require_once 'lib/classes/URLHelper.php';
 require_once 'lib/classes/LayoutMessage.interface.php';
 require_once 'lib/classes/MessageBox.class.php';
@@ -33,6 +32,18 @@ require_once 'lib/flexi/Factory.php';
 require_once 'lib/flexi/PhpTemplate.php';
 require_once 'lib/flexi/Template.php';
 require_once 'lib/flexi/TemplateNotFoundException.php';
+require_once 'lib/trails/Controller.php';
+require_once 'lib/trails/Dispatcher.php';
+require_once 'lib/trails/Exception.php';
+require_once 'lib/trails/Flash.php';
+require_once 'lib/trails/Inflector.php';
+require_once 'lib/trails/Response.php';
+require_once 'lib/trails/Exceptions/DoubleRenderError.php';
+require_once 'lib/trails/Exceptions/MissingFile.php';
+require_once 'lib/trails/Exceptions/RoutingError.php';
+require_once 'lib/trails/Exceptions/SessionRequiredException.php';
+require_once 'lib/trails/Exceptions/UnknownAction.php';
+require_once 'lib/trails/Exceptions/UnknownController.php';
 require_once 'vendor/phpass/PasswordHash.php';
 
 // Mock gettext functions if extension is not available
@@ -61,5 +72,5 @@ $GLOBALS['template_factory'] = new Flexi\Factory('../templates/');
 # get plugin class from request
 $dispatch_to = ltrim(Request::pathInfo(), '/');
 
-$dispatcher = new Trails_Dispatcher( '../app', $_SERVER['SCRIPT_NAME'], 'admin/install');
+$dispatcher = new Trails\Dispatcher( '../app', $_SERVER['SCRIPT_NAME'], 'admin/install');
 $dispatcher->dispatch("admin/install/{$dispatch_to}");
diff --git a/public/sendfile.php b/public/sendfile.php
index 7d6517cea0819c5d1a9bfc522e0805e5f6196b03..03157b8ada10e994897b33ac57511fd88d3cf033 100644
--- a/public/sendfile.php
+++ b/public/sendfile.php
@@ -156,7 +156,7 @@ if (
 ) {
     $link_data = FileManager::fetchURLMetadata($file_ref->file->metadata['url']);
     if ($link_data['response_code'] != 200) {
-        throw new Trails_Exception(404, _("Diese Datei wird von einem externen Server geladen und ist dort momentan nicht erreichbar!"));
+        throw new Trails\Exception(404, _("Diese Datei wird von einem externen Server geladen und ist dort momentan nicht erreichbar!"));
     }
     $content_type = $link_data['Content-Type'] ? strstr($link_data['Content-Type'], ';', true) : get_mime_type($file_name);
 
@@ -166,7 +166,7 @@ if (
 if (isset($file)) {
     $filesize = $file->getSize();
     if ($filesize === false) {
-        throw new Trails_Exception(404, _('Fehler beim Laden der Inhalte der Datei'));
+        throw new Trails\Exception(404, _('Fehler beim Laden der Inhalte der Datei'));
     }
 }
 
@@ -186,7 +186,7 @@ if (isset($file_ref, $file_ref->file, $file_ref->file->metadata['access_type'])
 
 // Check if file actually exists
 if (!parse_url($path_file, PHP_URL_SCHEME) && !file_exists($path_file)) {
-    throw new Trails_Exception(404, _('Fehler beim Laden der Inhalte der Datei'));
+    throw new Trails\Exception(404, _('Fehler beim Laden der Inhalte der Datei'));
 }
 
 $allowed_mime_types = get_mime_types();
diff --git a/public/web_migrate.php b/public/web_migrate.php
index c01c6002074336731a6951f05327f7c67be2cf68..0ee4de554638e7dc40240a64ef450fcc407521f0 100644
--- a/public/web_migrate.php
+++ b/public/web_migrate.php
@@ -36,6 +36,6 @@ $GLOBALS['template_factory'] = new Flexi\Factory('../templates/');
 # get plugin class from request
 $dispatch_to = Request::pathInfo() ?: '';
 
-$dispatcher = app(\Trails_Dispatcher::class);
+$dispatcher = app(\Trails\Dispatcher::class);
 $dispatcher->trails_uri = $_SERVER['SCRIPT_NAME'];
 $dispatcher->dispatch("web_migrate/{$dispatch_to}");
diff --git a/tests/unit/_bootstrap.php b/tests/unit/_bootstrap.php
index a1dbdd1deb73056f0b1c46f05b1dc4200a4b2b6a..87dedca7c0f23d181b8656f06728d9f88b597051 100644
--- a/tests/unit/_bootstrap.php
+++ b/tests/unit/_bootstrap.php
@@ -62,18 +62,7 @@ StudipAutoloader::addAutoloadPath('lib/flexi', 'Flexi');
 StudipAutoloader::addAutoloadPath('lib/plugins/engine');
 StudipAutoloader::addAutoloadPath('lib/plugins/core');
 StudipAutoloader::addAutoloadPath('lib/plugins/db');
-
-$trails_classes = [
-    'Trails_Dispatcher', 'Trails_Response', 'Trails_Controller',
-    'Trails_Inflector', 'Trails_Flash',
-    'Trails_Exception', 'Trails_DoubleRenderError', 'Trails_MissingFile',
-    'Trails_RoutingError', 'Trails_UnknownAction', 'Trails_UnknownController',
-    'Trails_SessionRequiredException',
-];
-StudipAutoloader::addClassLookup(
-    $trails_classes,
-    'vendor/trails/trails.php'
-);
+StudipAutoloader::addAutoloadPath('lib/trails', 'Trails');
 
 // load config-variables
 $added_configs = [];
diff --git a/tests/unit/lib/FunctionsTest.php b/tests/unit/lib/FunctionsTest.php
index 670d00c74b8ea59dedeeee595c048be9e407a000..c254fda807eb1920dc3d5e4637353c6d13cc701d 100644
--- a/tests/unit/lib/FunctionsTest.php
+++ b/tests/unit/lib/FunctionsTest.php
@@ -75,11 +75,12 @@ class FunctionsTest extends \Codeception\Test\Unit
     }
 
     /**
-     * @covers Trails_Controller::extract_action_and_args()
+     * @covers Trails\Controller::extract_action_and_args()
      */
     public function testTrailsControllerExtractActionAndArgs()
     {
-        $controller = new Trails_Controller(null);
+        $dispatcher = new Trails\Dispatcher('', '', '');
+        $controller = new Trails\Controller($dispatcher);
         [$action, $args, $format] = $controller->extract_action_and_args('foo/bar//42.html');
 
         $this->assertEquals('foo', $action);
diff --git a/tests/unit/lib/classes/StudipControllerTest.php b/tests/unit/lib/classes/StudipControllerTest.php
index f7e4ef441a0e959c8e0d19529809b400a9a81c19..51359ab494f3e56a1cb3fd4de0331e5f6f42831a 100644
--- a/tests/unit/lib/classes/StudipControllerTest.php
+++ b/tests/unit/lib/classes/StudipControllerTest.php
@@ -27,13 +27,13 @@ final class StudipControllerTest extends Codeception\Test\Unit
         parent::tearDown();
     }
 
-    private function getDispatcher(): Trails_Dispatcher
+    private function getDispatcher(): Trails\Dispatcher
     {
         $trails_root = $GLOBALS['STUDIP_BASE_PATH'] . DIRECTORY_SEPARATOR . 'app';
         $trails_uri = rtrim($GLOBALS['ABSOLUTE_URI_STUDIP'], '/') . '/dispatch.php';
         $default_controller = 'default';
 
-        return new Trails_Dispatcher($trails_root, $trails_uri, $default_controller);
+        return new Trails\Dispatcher($trails_root, $trails_uri, $default_controller);
     }
 
     private function getController(): StudipController
@@ -247,7 +247,7 @@ final class StudipControllerTest extends Codeception\Test\Unit
     {
         $args = [$should_fail];
 
-        $this->expectException(Trails_Exception::class);
+        $this->expectException(Trails\Exception::class);
         $this->getController()->validate_args($args);
     }
 
diff --git a/tests/unit/lib/classes/TrailsTest.php b/tests/unit/lib/classes/TrailsTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..d51b7956771ef4bbb7676e6f3e74ff202c37d145
--- /dev/null
+++ b/tests/unit/lib/classes/TrailsTest.php
@@ -0,0 +1,25 @@
+<?php
+class TrailsTest extends \Codeception\Test\Unit
+{
+    /**
+     * @covers Trails\Inflector::camelize
+     */
+    public function testInflectorCamelize(): void
+    {
+        $this->assertEquals(
+            'Path_SubPath_UnderscoreController',
+            Trails\Inflector::camelize('path/sub_path/underscore_controller')
+        );
+    }
+
+    /**
+     * @covers Trails\Inflector::underscore
+     */
+    public function testInflectorUnderscore(): void
+    {
+        $this->assertEquals(
+            'path/sub_path/underscore_controller',
+            Trails\Inflector::underscore('Path_SubPath_UnderscoreController')
+        );
+    }
+}
diff --git a/vendor/trails/extras/tramp.php b/vendor/trails/extras/tramp.php
deleted file mode 100644
index 9292a9619baddb971190c2463e897fbb144d5a6f..0000000000000000000000000000000000000000
--- a/vendor/trails/extras/tramp.php
+++ /dev/null
@@ -1,55 +0,0 @@
-<?php
-
-# Copyright (c)  2007 - Marcus Lunzenauer <mlunzena@uos.de>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-
-class Tramp_Controller extends Trails_Controller {
-
-  /**
-   * Extracts action and args from a string.
-   *
-   * @param  string       the processed string
-   *
-   * @return arraye       an array with two elements - a string containing the
-   *                      action and an array of strings representing the args
-   */
-  protected function extract_action_and_args($string) {
-    return array($this->get_verb(), explode('/', $string));
-  }
-
-
-  protected function map_action($action) {
-    return strtolower($action);
-  }
-
-
-  protected function get_verb() {
-
-    $verb = strtoupper(isset($_REQUEST['_method'])
-      ? $_REQUEST['_method'] : @$_SERVER['REQUEST_METHOD']);
-
-    if (!preg_match('/^DELETE|GET|POST|PUT|HEAD|OPTIONS$/', $verb)) {
-      throw new Trails_Exception(405);
-    }
-
-    return $verb;
-  }
-}
diff --git a/vendor/trails/src/HEADER.php b/vendor/trails/src/HEADER.php
deleted file mode 100644
index 75bb516052cd97b7e747a06ae412752aea9a683f..0000000000000000000000000000000000000000
--- a/vendor/trails/src/HEADER.php
+++ /dev/null
@@ -1,27 +0,0 @@
-<?
-
-# Copyright (c)  2007 - Marcus Lunzenauer <mlunzena@uos.de>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-
-/**
- * The version of the trails library.
- */
-define('TRAILS_VERSION', '0.6.9');
diff --git a/vendor/trails/src/controller.php b/vendor/trails/src/controller.php
deleted file mode 100644
index 6ab954238417c6b7cde75244b29f083b609d3b29..0000000000000000000000000000000000000000
--- a/vendor/trails/src/controller.php
+++ /dev/null
@@ -1,430 +0,0 @@
-<?php
-/**
- * A Trails_Controller is responsible for matching the unconsumed part of an URI
- * to an action using the left over words as arguments for that action. The
- * action is then mapped to method of the controller instance which is called
- * with the just mentioned arguments. That method can send the #render_action,
- * #render_template, #render_text, #render_nothing or #redirect method.
- * Otherwise the #render_action is called with the current action as argument.
- * If the action method sets instance variables during performing, they will be
- * be used as attributes for the flexi-template opened by #render_action or
- * #render_template. A controller's response's body is populated with the output
- * of the #render_* methods. The action methods can add additional headers or
- * change the status of that response.
- *
- * @package   trails
- *
- * @author    mlunzena
- * @copyright (c) Authors
- * @version   $Id: trails.php 7001 2008-04-04 11:20:27Z mlunzena $
- */
-
-class Trails_Controller {
-
-
-  /**
-   * @ignore
-   */
-  protected
-    $dispatcher,
-    $response,
-    $performed,
-    $layout;
-
-
-  /**
-   * Constructor.
-   *
-   * @param  mixed  the dispatcher who creates this instance
-   *
-   * @return void
-   */
-  function __construct($dispatcher) {
-    $this->dispatcher = $dispatcher;
-    $this->erase_response();
-  }
-
-
-  /**
-   * Resets the response of the controller
-   *
-   * @return void
-   */
-  function erase_response() {
-    $this->performed = FALSE;
-    $this->response = new Trails_Response();
-  }
-
-
-  /**
-   * Return this controller's response
-   *
-   * @return mixed  the controller's response
-   */
-  function get_response() {
-    return $this->response;
-  }
-
-
-  /**
-   * This method extracts an action string and further arguments from it's
-   * parameter. The action string is mapped to a method being called afterwards
-   * using the said arguments. That method is called and a response object is
-   * generated, populated and sent back to the dispatcher.
-   *
-   * @param type <description>
-   *
-   * @return type <description>
-   */
-  function perform($unconsumed) {
-
-    list($action, $args, $format) = $this->extract_action_and_args($unconsumed);
-
-    $this->format = isset($format) ? $format : 'html';
-
-    $before_filter_result = $this->before_filter($action, $args);
-
-    # send action to controller
-    # TODO (mlunzena) shouldn't the after filter be triggered too?
-    if (!(FALSE === $before_filter_result || $this->performed)) {
-
-      $callable = $this->map_action($action);
-
-      if (is_callable($callable)) {
-        call_user_func_array($callable, $args);
-      }
-      else {
-        $this->does_not_understand($action, $args);
-      }
-
-      if (!$this->performed) {
-        $this->render_action($action);
-      }
-
-      $this->after_filter($action, $args);
-    }
-
-    return $this->response;
-  }
-
-
-  /**
-   * Extracts action and args from a string.
-   *
-   * @param  string       the processed string
-   *
-   * @return array        an array with two elements - a string containing the
-   *                      action and an array of strings representing the args
-   */
-  function extract_action_and_args($string) {
-
-    if ('' === $string) {
-      return $this->default_action_and_args();
-    }
-
-    // find optional file extension
-    $format = NULL;
-    if (preg_match('/^(.*[^\/.])\.(\w+)$/', $string, $matches)) {
-      list($_, $string, $format) = $matches;
-    }
-
-    // TODO this should possibly remove empty tokens
-    $args = explode('/', $string);
-    $action = array_shift($args);
-    return array($action, $args, $format);
-  }
-
-  /**
-   * Return the default action and arguments
-   *
-   * @return an array containing the action, an array of args and the format
-   *
-   */
-  function default_action_and_args() {
-    return array('index', array(), NULL);
-  }
-
-  /**
-   * Maps the action to an actual method name.
-   *
-   * @param  string  the action
-   *
-   * @return string  the mapped method name
-   */
-  function map_action($action) {
-    return array(&$this, $action . '_action');
-  }
-
-
-  /**
-   * Callback function being called before an action is executed. If this
-   * function does not return FALSE, the action will be called, otherwise
-   * an error will be generated and processing will be aborted. If this function
-   * already #rendered or #redirected, further processing of the action is
-   * withheld.
-   *
-   * @param string  Name of the action to perform.
-   * @param array   An array of arguments to the action.
-   *
-   * @return bool
-   */
-  function before_filter(&$action, &$args) {
-  }
-
-
-  /**
-   * Callback function being called after an action is executed.
-   *
-   * @param string Name of the action to perform.
-   * @param array  An array of arguments to the action.
-   *
-   * @return void
-   */
-  function after_filter($action, $args) {
-  }
-
-
-  /**
-   * <MethodDescription>
-   *
-   * @param type <description>
-   * @param type <description>
-   *
-   * @return void
-   */
-  function does_not_understand($action, $args) {
-    throw new Trails_UnknownAction("No action responded to '$action'.");
-  }
-
-
-  /**
-   * <MethodDescription>
-   *
-   * @param string <description>
-   *
-   * @return void
-   */
-  function redirect($to) {
-
-    if ($this->performed) {
-      throw new Trails_DoubleRenderError();
-    }
-
-    $this->performed = TRUE;
-
-    # get uri; keep absolute URIs
-    $url = preg_match('#^(/|\w+://)#', $to)
-           ? $to
-           : $this->url_for($to);
-
-    $this->response->add_header('Location', $url)->set_status(302);
-  }
-
-
-  /**
-   * Renders the given text as the body of the response.
-   *
-   * @param string  the text to be rendered
-   *
-   * @return void
-   */
-  function render_text($text = ' ') {
-
-    if ($this->performed) {
-      throw new Trails_DoubleRenderError();
-    }
-
-    $this->performed = TRUE;
-
-    $this->response->set_body($text);
-  }
-
-
-  /**
-   * Renders the empty string as the response's body.
-   *
-   * @return void
-   */
-  function render_nothing() {
-    $this->render_text('');
-  }
-
-
-  /**
-   * Renders the template of the given action as the response's body.
-   *
-   * @param string  the action
-   *
-   * @return void
-   */
-  function render_action($action) {
-    $this->render_template($this->get_default_template($action), $this->layout);
-  }
-
-
-  function get_default_template($action)
-  {
-    $class = get_class($this);
-    $controller_name =
-      Trails_Inflector::underscore(substr($class, 0, -10));
-    return $controller_name.'/'.$action;
-  }
-
-
-  /**
-   * Renders a template using an optional layout template.
-   *
-   * @param mixed  a flexi template
-   * @param mixes  a flexi template which is used as layout
-   *
-   * @return void
-   */
-  function render_template($template_name, $layout = NULL) {
-
-    # open template
-    $factory = $this->get_template_factory();
-    $template = $factory->open($template_name);
-
-    $template->set_attributes($this->get_assigned_variables());
-
-    if (isset($layout)) {
-      $template->set_layout($layout);
-    }
-
-    $this->render_text($template->render());
-  }
-
-
-  /**
-   * Create and return a template factory for this controller.
-   *
-   * @return Flexi\Factory
-   */
-  function get_template_factory() {
-    return new Flexi\Factory($this->dispatcher->trails_root .
-                                     '/views/');
-  }
-
-
-  /**
-   * This method returns all the set instance variables to be used as attributes
-   * for a template. This controller is returned too as value for
-   * key 'controller'.
-   *
-   * @return array  an associative array of variables for the template
-   */
-  function get_assigned_variables() {
-
-    $assigns = array();
-    $protected = get_class_vars(get_class($this));
-
-    foreach (get_object_vars($this) as $var => $value) {
-      if (!array_key_exists($var, $protected)) {
-        $assigns[$var] =& $this->$var;
-      }
-    }
-
-    $assigns['controller'] = $this;
-
-    return $assigns;
-  }
-
-
-  /**
-   * Sets the layout to be used by this controller per default.
-   *
-   * @param  mixed  a flexi template to be used as layout
-   *
-   * @return void
-   */
-  function set_layout($layout) {
-    $this->layout = $layout;
-  }
-
-
-  /**
-   * Returns a URL to a specified route to your Trails application.
-   *
-   * Example:
-   * Your Trails application is located at 'http://example.com/dispatch.php'.
-   * So your dispatcher's trails_uri is set to 'http://example.com/dispatch.php'
-   * If you want the URL to your 'wiki' controller with action 'show' and
-   * parameter 'page' you should send:
-   *
-   *   $url = $controller->url_for('wiki/show', 'page');
-   *
-   * $url should then contain 'http://example.com/dispatch.php/wiki/show/page'.
-   *
-   * The first parameter is a string containing the controller and optionally an
-   * action:
-   *
-   *   - "{controller}/{action}"
-   *   - "path/to/controller/action"
-   *   - "controller"
-   *
-   * This "controller/action" string is not url encoded. You may provide
-   * additional parameter which will be urlencoded and concatenated with
-   * slashes:
-   *
-   *     $controller->url_for('wiki/show', 'page');
-   *     -> 'wiki/show/page'
-   *
-   *     $controller->url_for('wiki/show', 'page', 'one and a half');
-   *     -> 'wiki/show/page/one+and+a+half'
-   *
-   * @param  string   a string containing a controller and optionally an action
-   * @param  strings  optional arguments
-   *
-   * @return string  a URL to this route
-   */
-  function url_for($to/*, ...*/) {
-
-    # urlencode all but the first argument
-    $args = func_get_args();
-    $args = array_map('urlencode', $args);
-    $args[0] = $to;
-
-    return $this->dispatcher->trails_uri . '/' . join('/', $args);
-  }
-
-
-  /**
-   * <MethodDescription>
-   *
-   * @param  type       <description>
-   *
-   * @return type       <description>
-   */
-  function set_status($status, $reason_phrase = NULL) {
-    $this->response->set_status($status, $reason_phrase);
-  }
-
-
-  /**
-   * Sets the content type of the controller's response.
-   *
-   * @param  string  the content type
-   *
-   * @return void
-   */
-  function set_content_type($type) {
-    $this->response->add_header('Content-Type', $type);
-  }
-
-
-  /**
-   * Exception handler called when the performance of an action raises an
-   * exception.
-   *
-   * @param  object     the thrown exception
-   *
-   * @return object     a response object
-   */
-  function rescue($exception) {
-    return $this->dispatcher->trails_error($exception);
-  }
-
-  function respond_to($ext) {
-    return $this->format === $ext;
-  }
-}
diff --git a/vendor/trails/src/dispatcher.php b/vendor/trails/src/dispatcher.php
deleted file mode 100644
index 58f55b1b89a97d9647eeb11148cf43001e2273be..0000000000000000000000000000000000000000
--- a/vendor/trails/src/dispatcher.php
+++ /dev/null
@@ -1,269 +0,0 @@
-<?php
-
-/**
- * The Dispatcher is used to map an incoming HTTP request to a Controller
- * producing a response which is then rendered. To initialize an instance of
- * class Trails_Dispatcher you have to give three configuration settings:
- *
- *          trails_root - the absolute file path to a directory containing the
- *                        applications controllers, views etc.
- *           trails_uri - the URI to which routes to mapped Controller/Actions
- *                        are appended
- *   default_controller - the route to a controller, that is used if no
- *                        controller is given, that is the route is equal to '/'
- *
- * After instantiation of a dispatcher you have to call method #dispatch with
- * the request uri to be mapped to a controller/action pair.
- *
- * @package   trails
- *
- * @author    mlunzena
- * @copyright (c) Authors
- * @version   $Id: trails.php 7001 2008-04-04 11:20:27Z mlunzena $
- */
-
-class Trails_Dispatcher {
-
-  # TODO (mlunzena) Konfiguration muss anders geschehen
-
-  /**
-   * This is the absolute file path to the trails application directory.
-   *
-   * @access public
-   * @var    string
-   */
-  public $trails_root;
-
-
-  /**
-   * This is the URI to which routes to controller/actions are appended.
-   *
-   * @access public
-   * @var    string
-   */
-  public $trails_uri;
-
-
-  /**
-   * This variable contains the route to the default controller.
-   *
-   * @access public
-   * @var    string
-   */
-  public $default_controller;
-
-
-  /**
-   * Constructor.
-   *
-   * @param  string  absolute file path to a directory containing the
-   *                 applications controllers, views etc.
-   * @param  string  the URI to which routes to mapped Controller/Actions
-   *                 are appended
-   * @param  string  the route to a controller, that is used if no
-   *                 controller is given, that is the route is equal to '/'
-   *
-   * @return void
-   */
-  function __construct($trails_root,
-                       $trails_uri,
-                       $default_controller) {
-
-    $this->trails_root        = $trails_root;
-    $this->trails_uri         = $trails_uri;
-    $this->default_controller = $default_controller;
-  }
-
-
-  /**
-   * Maps a string to a response which is then rendered.
-   *
-   * @param string The requested URI.
-   *
-   * @return void
-   */
-  function dispatch($uri) {
-
-    # E_USER_ERROR|E_USER_WARNING|E_USER_NOTICE|E_RECOVERABLE_ERROR = 5888
-    $old_handler = set_error_handler(array($this, 'error_handler'), 5888);
-
-    ob_start();
-    $level = ob_get_level();
-
-    $this->map_uri_to_response($this->clean_request_uri((string) $uri))->output();
-
-    while (ob_get_level() >= $level) {
-      ob_end_flush();
-    }
-
-    if (isset($old_handler)) {
-      set_error_handler($old_handler);
-    }
-  }
-
-
-  /**
-   * Maps an URI to a response by figuring out first what controller to
-   * instantiate, then delegating the unconsumed part of the URI to the
-   * controller who returns an appropriate response object or throws a
-   * Trails_Exception.
-   *
-   * @param  string  the URI string
-   *
-   * @return mixed   a response object
-   */
-  function map_uri_to_response($uri) {
-
-    try {
-
-      list($controller_path, $unconsumed) =
-          '' === $uri
-          ? $this->default_route()
-            : $this->parse($uri);
-
-      $controller = $this->load_controller($controller_path);
-
-      $response = $controller->perform($unconsumed);
-
-    } catch (Exception $e) {
-
-      $response = isset($controller) ? $controller->rescue($e)
-                                     : $this->trails_error($e);
-    }
-
-    return $response;
-  }
-
-
-  /**
-   *
-   * @return array  an array containing the default controller and an
-   *                empty unconsumed route
-   */
-  function default_route() {
-      if (!$this->file_exists($this->default_controller . '.php')) {
-          throw new Trails_MissingFile(
-              "Default controller '{$this->default_controller}' not found'");
-      }
-      return array($this->default_controller, '');
-  }
-
-
-  function trails_error($exception) {
-    ob_clean();
-
-    # show details for local requests
-    $detailed = @$_SERVER['REMOTE_ADDR'] === '127.0.0.1';
-
-    $body = sprintf('<html><head><title>Trails Error</title></head>'.
-                    '<body><h1>%s</h1><pre>%s</pre></body></html>',
-                    htmlentities($exception->__toString()),
-                    $detailed
-                      ? htmlentities($exception->getTraceAsString())
-                      : '');
-
-    if ($exception instanceof Trails_Exception) {
-      $response = new Trails_Response($body,
-                                      $exception->headers,
-                                      $exception->getCode(),
-                                      $exception->getMessage());
-    }
-    else {
-      $response = new Trails_Response($body, array(), 500,
-                                      $exception->getMessage());
-    }
-
-    return $response;
-  }
-
-
-  /**
-   * Clean up URI string by removing the query part and leading slashes.
-   *
-   * @param  string  an URI string
-   *
-   * @return string  the cleaned string
-   */
-  function clean_request_uri($uri) {
-    if (FALSE !== ($pos = strpos($uri, '?'))) {
-      $uri = substr($uri, 0, $pos);
-    }
-    return ltrim($uri, '/');
-  }
-
-
-  /**
-   * <MethodDescription>
-   *
-   * @param  type       <description>
-   * @param  type       <description>
-   *
-   * @return type       <description>
-   */
-  function parse($unconsumed, $controller = NULL) {
-    list($head, $tail) = $this->split_on_first_slash($unconsumed);
-
-    if (!preg_match('/^\w+$/', $head)) {
-      throw new Trails_RoutingError("No route matches '$head'");
-    }
-
-    $controller = (isset($controller) ? $controller . '/' : '') . $head;
-
-    if ($this->file_exists($controller . '.php')) {
-      return array($controller, $tail);
-    }
-    else if ($this->file_exists($controller)) {
-      return $this->parse($tail, $controller);
-    }
-
-    throw new Trails_RoutingError("No route matches '$head'");
-  }
-
-  function split_on_first_slash($str) {
-    preg_match(":([^/]*)(/+)?(.*):", $str, $matches);
-    return array($matches[1], $matches[3]);
-  }
-
-  function file_exists($path) {
-    return file_exists("{$this->trails_root}/controllers/$path");
-  }
-
-  /**
-   * Loads the controller file for a given controller path and return an
-   * instance of that controller. If an error occures, an exception will be
-   * thrown.
-   *
-   * @param  string            the relative controller path
-   *
-   * @return TrailsController  an instance of that controller
-   */
-  function load_controller($controller) {
-    require_once "{$this->trails_root}/controllers/{$controller}.php";
-    $class = Trails_Inflector::camelize($controller) . 'Controller';
-    if (!class_exists($class)) {
-      throw new Trails_UnknownController("Controller missing: '$class'");
-    }
-    return new $class($this);
-  }
-
-
-  /**
-   * This method transforms E_USER_* and E_RECOVERABLE_ERROR to
-   * Trails_Exceptions.
-   *
-   * @param  integer    the level of the error raised
-   * @param  string     the error message
-   * @param  string     the filename that the error was raised in
-   * @param  integer    the line number the error was raised at
-   *
-   * @throws Trails_Exception
-   *
-   * @return void
-   */
-  function error_handler($errno, $string, $file, $line) {
-    if (!(5888 & $errno)) {
-      return false;
-    }
-    throw new Trails_Exception(500, $string);
-  }
-}
diff --git a/vendor/trails/src/exception.php b/vendor/trails/src/exception.php
deleted file mode 100644
index 4c21831fc8b081a8fd5f74c4794027c3ec4f17d3..0000000000000000000000000000000000000000
--- a/vendor/trails/src/exception.php
+++ /dev/null
@@ -1,101 +0,0 @@
-<?php
-
-/**
- * TODO
- *
- * @package   trails
- *
- * @author    mlunzena
- * @copyright (c) Authors
- * @version   $Id: trails.php 7001 2008-04-04 11:20:27Z mlunzena $
- */
-
-class Trails_Exception extends Exception {
-
-  /**
-   * <FieldDescription>
-   *
-   * @access private
-   * @var <type>
-   */
-  public $headers;
-
-
-  /**
-   * @param  int     the status code to be set in the response
-   * @param  string  a human readable presentation of the status code
-   * @param  array   a hash of additional headers to be set in the response
-   *
-   * @return void
-   */
-  function __construct($status = 500, $reason = NULL, $headers = array()) {
-    if ($reason === NULL) {
-      $reason = Trails_Response::get_reason($status);
-    }
-    parent::__construct($reason, $status);
-    $this->headers = $headers;
-  }
-
-
-  /**
-   * <MethodDescription>
-   *
-   * @param  type       <description>
-   *
-   * @return type       <description>
-   */
-  function __toString() {
-    return "{$this->code} {$this->message}";
-  }
-}
-
-
-class Trails_DoubleRenderError extends Trails_Exception {
-
-  function __construct() {
-    $message =
-      "Render and/or redirect were called multiple times in this action. ".
-      "Please note that you may only call render OR redirect, and at most ".
-      "once per action.";
-    parent::__construct(500, $message);
-  }
-}
-
-
-class Trails_MissingFile extends Trails_Exception {
-  function __construct($message) {
-    parent::__construct(500, $message);
-  }
-}
-
-
-class Trails_RoutingError extends Trails_Exception {
-
-  function __construct($message) {
-    parent::__construct(400, $message);
-  }
-}
-
-
-class Trails_UnknownAction extends Trails_Exception {
-
-  function __construct($message) {
-    parent::__construct(404, $message);
-  }
-}
-
-
-class Trails_UnknownController extends Trails_Exception {
-
-  function __construct($message) {
-    parent::__construct(404, $message);
-  }
-}
-
-
-class Trails_SessionRequiredException extends Trails_Exception {
-  function __construct() {
-    $message = "Tried to access a non existing session.";
-    parent::__construct(500, $message);
-  }
-}
diff --git a/vendor/trails/src/flash.php b/vendor/trails/src/flash.php
deleted file mode 100644
index cee08e5deb3254c01739a9e60c95162249946a12..0000000000000000000000000000000000000000
--- a/vendor/trails/src/flash.php
+++ /dev/null
@@ -1,241 +0,0 @@
-<?php
-
-/**
- * The flash provides a way to pass temporary objects between actions.
- * Anything you place in the flash will be exposed to the very next action and
- * then cleared out. This is a great way of doing notices and alerts, such as
- * a create action that sets
- * <tt>$flash->set('notice', "Successfully created")</tt>
- * before redirecting to a display action that can then expose the flash to its
- * template.
- *
- * @package   trails
- *
- * @author    mlunzena
- * @copyright (c) Authors
- * @version   $Id: trails.php 7001 2008-04-04 11:20:27Z mlunzena $
- */
-
-class Trails_Flash implements ArrayAccess {
-
-
-  /**
-   * @ignore
-   */
-  public
-    $flash = array(), $used = array();
-
-
-  /**
-   * <MethodDescription>
-   *
-   * @return type       <description>
-   */
-  static function instance() {
-
-    if (!isset($_SESSION)) {
-      throw new Trails_SessionRequiredException();
-    }
-
-
-    if (!isset($_SESSION['trails_flash'])) {
-      $_SESSION['trails_flash'] = new Trails_Flash();
-    }
-    return $_SESSION['trails_flash'];
-  }
-
-
-  function offsetExists($offset) {
-    return isset($this->flash[$offset]);
-  }
-
-
-  function offsetGet($offset) {
-    return $this->get($offset);
-  }
-
-
-  function offsetSet($offset, $value) {
-    $this->set($offset, $value);
-  }
-
-
-  function offsetUnset($offset) {
-    unset($this->flash[$offset], $this->used[$offset]);
-  }
-
-
-  /**
-   * Used internally by the <tt>keep</tt> and <tt>discard</tt> methods
-   *     use()               # marks the entire flash as used
-   *     use('msg')          # marks the "msg" entry as used
-   *     use(null, false)    # marks the entire flash as unused
-   *                         # (keeps it around for one more action)
-   *     use('msg', false)   # marks the "msg" entry as unused
-   *                         # (keeps it around for one more action)
-   *
-   * @param mixed  a key.
-   * @param bool   used flag.
-   *
-   * @return void
-   */
-  function _use($k = NULL, $v = TRUE) {
-    if ($k) {
-      $this->used[$k] = $v;
-    }
-    else {
-      foreach ($this->used as $k => $value) {
-        $this->_use($k, $v);
-      }
-    }
-  }
-
-
-  /**
-   * Marks the entire flash or a single flash entry to be discarded by the end
-   * of the current action.
-   *
-   *     $flash->discard()             # discards entire flash
-   *                                   # (it'll still be available for the
-   *                                   # current action)
-   *     $flash->discard('warning')    # discard the "warning" entry
-   *                                   # (it'll still be available for the
-   *                                   # current action)
-   *
-   * @param mixed  a key.
-   *
-   * @return void
-   */
-  function discard($k = NULL) {
-    $this->_use($k);
-  }
-
-
-  /**
-   * Returns the value to the specified key.
-   *
-   * @param mixed  a key.
-   *
-   * @return mixed the key's value.
-   */
-  function &get($k) {
-    $return = NULL;
-    if (isset($this->flash[$k])) {
-      $return =& $this->flash[$k];
-    }
-    return $return;
-  }
-
-
-  /**
-   * Keeps either the entire current flash or a specific flash entry available
-   * for the next action:
-   *
-   *    $flash->keep()           # keeps the entire flash
-   *    $flash->keep('notice')   # keeps only the "notice" entry, the rest of
-   *                             # the flash is discarded
-   *
-   * @param mixed  a key.
-   *
-   * @return void
-   */
-  function keep($k = NULL) {
-    $this->_use($k, FALSE);
-  }
-
-
-  /**
-   * Sets a key's value.
-   *
-   * @param mixed  a key.
-   * @param mixed  its value.
-   *
-   * @return void
-   */
-  function set($k, $v) {
-    $this->keep($k);
-    $this->flash[$k] = $v;
-  }
-
-
-  /**
-   * Sets a key's value by reference.
-   *
-   * @param mixed  a key.
-   * @param mixed  its value.
-   *
-   * @return void
-   */
-  function set_ref($k, &$v) {
-    $this->keep($k);
-    $this->flash[$k] =& $v;
-  }
-
-
-
-  /**
-   * <MethodDescription>
-   *
-   * @return type       <description>
-   */
-  function sweep() {
-
-    # remove used values
-    foreach (array_keys($this->flash) as $k) {
-      if ($this->used[$k]) {
-        unset($this->flash[$k], $this->used[$k]);
-      } else {
-        $this->_use($k);
-      }
-    }
-
-    # cleanup if someone meddled with flash or used
-    $fkeys = array_keys($this->flash);
-    $ukeys = array_keys($this->used);
-    foreach (array_diff($fkeys, $ukeys) as $k => $v) {
-      unset($this->used[$k]);
-    }
-  }
-
-
-  /**
-   * <MethodDescription>
-   *
-   * @return type       <description>
-   */
-  function __toString() {
-    $values = array();
-    foreach ($this->flash as $k => $v) {
-      $values[] = sprintf("'%s': [%s, '%s']",
-                          $k, var_export($v, TRUE),
-                          $this->used[$k] ? "used" : "unused");
-    }
-    return "{" . join(", ", $values) . "}\n";
-  }
-
-
-  /**
-   * <MethodDescription>
-   *
-   * @param  type       <description>
-   *
-   * @return type       <description>
-   */
-  function __sleep() {
-    $this->sweep();
-    return array('flash', 'used');
-  }
-
-
-  /**
-   * <MethodDescription>
-   *
-   * @param  type       <description>
-   *
-   * @return type       <description>
-   */
-  function __wakeUp() {
-    $this->discard();
-  }
-}
-
diff --git a/vendor/trails/src/inflector.php b/vendor/trails/src/inflector.php
deleted file mode 100644
index 6646eee681567143e4f1a0b6319e829f2dc22c59..0000000000000000000000000000000000000000
--- a/vendor/trails/src/inflector.php
+++ /dev/null
@@ -1,49 +0,0 @@
-<?php
-
-/**
- * The Inflector class is a namespace for inflections methods.
- *
- * @package   trails
- *
- * @author    mlunzena
- * @copyright (c) Authors
- * @version   $Id: trails.php 7001 2008-04-04 11:20:27Z mlunzena $
- */
-
-class Trails_Inflector {
-
-
-  /**
-   * Returns a camelized string from a lower case and underscored string by
-   * replacing slash with underscore and upper-casing each letter preceded
-   * by an underscore. TODO
-   *
-   * @param string String to camelize.
-   *
-   * @return string Camelized string.
-   */
-  static function camelize($word) {
-    $parts = explode('/', $word);
-    foreach ($parts as $key => $part) {
-      $parts[$key] = str_replace(' ', '',
-                                 ucwords(str_replace('_', ' ', $part)));
-    }
-    return join('_', $parts);
-  }
-
-
-  /**
-   * <MethodDescription>
-   *
-   * @param type <description>
-   *
-   * @return type <description>
-   */
-  static function underscore($word) {
-    $parts = explode('_', $word);
-    foreach ($parts as $key => $part) {
-      $parts[$key] = preg_replace('/(?<=\w)([A-Z])/', '_\\1', $part);
-    }
-    return strtolower(join('/', $parts));
-  }
-}
diff --git a/vendor/trails/src/response.php b/vendor/trails/src/response.php
deleted file mode 100644
index 474bfc1a1eeb2a4cd0efa830e548322eb6e60cfc..0000000000000000000000000000000000000000
--- a/vendor/trails/src/response.php
+++ /dev/null
@@ -1,166 +0,0 @@
-<?php
-
-/**
- * This class represents a response returned by a controller that was asked to
- * perform for a given request. A Trails_Response contains the body, status and
- * additional headers which can be renderer back to the client.
- *
- * @package   trails
- *
- * @author    mlunzena
- * @copyright (c) Authors
- * @version   $Id: trails.php 7001 2008-04-04 11:20:27Z mlunzena $
- */
-
-class Trails_Response {
-
-
-  /**
-   * @ignore
-   */
-  public
-    $body = '',
-    $status,
-    $reason,
-    $headers = array();
-
-
-  /**
-   * Constructor.
-   *
-   * @param  string   the body of the response defaulting to ''
-   * @param  array    an array of additional headers defaulting to an
-   *                  empty array
-   * @param  integer  the status code of the response defaulting to a
-   *                  regular 200
-   * @param  string   the descriptional reason for a status code defaulting to
-   *                  the standard reason phrases defined in RFC 2616
-   *
-   * @return void
-   */
-  function __construct($body = '', $headers = array(),
-                       $status = NULL, $reason = NULL) {
-
-    $this->set_body($body);
-
-    $this->headers = $headers;
-
-    if (isset($status)) {
-      $this->set_status($status, $reason);
-    }
-  }
-
-
-  /**
-   * Sets the body of the response.
-   *
-   * @param  string  the body
-   *
-   * @return mixed   this response object. Useful for cascading method calls.
-   */
-  function set_body($body) {
-    $this->body = $body;
-    return $this;
-  }
-
-
-  /**
-   * Sets the status code and an optional custom reason. If none is given, the
-   * standard reason phrase as of RFC 2616 is used.
-   *
-   * @param  integer  the status code
-   * @param  string   the custom reason, defaulting to the one given in RFC 2616
-   *
-   * @return mixed    this response object. Useful for cascading method calls.
-   */
-  function set_status($status, $reason = NULL) {
-    $this->status = $status;
-    $this->reason = isset($reason) ? $reason : self::get_reason($status);
-    return $this;
-  }
-
-
-  /**
-   * Returns the reason phrase of this response according to RFC2616.
-   *
-   * @param int      the response's status
-   *
-   * @return string  the reason phrase for this response's status
-   */
-  public static function get_reason($status) {
-    $reason = array(
-      100 => 'Continue', 'Switching Protocols',
-      200 => 'OK', 'Created', 'Accepted', 'Non-Authoritative Information',
-             'No Content', 'Reset Content', 'Partial Content',
-      300 => 'Multiple Choices', 'Moved Permanently', 'Found', 'See Other',
-             'Not Modified', 'Use Proxy', '(Unused)', 'Temporary Redirect',
-      400 => 'Bad Request', 'Unauthorized', 'Payment Required','Forbidden',
-             'Not Found', 'Method Not Allowed', 'Not Acceptable',
-             'Proxy Authentication Required', 'Request Timeout', 'Conflict',
-             'Gone', 'Length Required', 'Precondition Failed',
-             'Request Entity Too Large', 'Request-URI Too Long',
-             'Unsupported Media Type', 'Requested Range Not Satisfiable',
-             'Expectation Failed',
-      500 => 'Internal Server Error', 'Not Implemented', 'Bad Gateway',
-             'Service Unavailable', 'Gateway Timeout',
-             'HTTP Version Not Supported');
-
-    return isset($reason[$status]) ? $reason[$status] : '';
-  }
-
-
-  /**
-   * Adds an additional header to the response.
-   *
-   * @param  string  the left hand key part
-   * @param  string  the right hand value part
-   *
-   * @return mixed   this response object. Useful for cascading method calls.
-   */
-  function add_header($key, $value) {
-    $this->headers[$key] = $value;
-    return $this;
-  }
-
-
-  /**
-   * Outputs this response to the client using "echo" and "header".
-   *
-   * @return void
-   */
-  function output() {
-    if (isset($this->status)) {
-      $this->send_header(sprintf('HTTP/1.1 %d %s',
-                                 $this->status, $this->reason),
-                         TRUE,
-                         $this->status);
-    }
-
-    foreach ($this->headers as $k => $v) {
-      $this->send_header("$k: $v");
-    }
-
-    echo $this->body;
-  }
-
-
-  /**
-   * Internally used function to actually send headers
-   *
-   * @param  string     the HTTP header
-   * @param  bool       optional; TRUE if previously sent header should be
-   *                    replaced - FALSE otherwise (default)
-   * @param  integer    optional; the HTTP response code
-   *
-   * @return void
-   */
-  function send_header($header, $replace = FALSE, $status = NULL) {
-    if (isset($status)) {
-      header($header, $replace, $status);
-    }
-    else {
-      header($header, $replace);
-    }
-  }
-}
-
diff --git a/vendor/trails/src/trails.php b/vendor/trails/src/trails.php
deleted file mode 100644
index 2e9e8e2c504697ec98c7a8f78fdc5d7896befb91..0000000000000000000000000000000000000000
--- a/vendor/trails/src/trails.php
+++ /dev/null
@@ -1,16 +0,0 @@
-<?php
-function fgc($files/*, ... */) {
-  $result = '';
-  $files = func_get_args();
-  foreach ($files as $file) {
-    $string = file_get_contents(dirname(__FILE__)."/$file.php");
-    $result .= preg_replace("/^(<\?(php)?)|(\?>)\s*\v+$/", "", $string);
-  }
-  return $result;
-}
-?>
-<?= "<?php" ?>
-<?= fgc("HEADER") ?>
-
-<?= fgc("dispatcher", "response", "controller",
-        "inflector", "flash", "exception") ?>
diff --git a/vendor/trails/trails-abridged.php b/vendor/trails/trails-abridged.php
deleted file mode 100644
index 07b337a0e8f4f4d58a466080b46b094d05fade85..0000000000000000000000000000000000000000
--- a/vendor/trails/trails-abridged.php
+++ /dev/null
@@ -1,3 +0,0 @@
-<?php
-
-define('TRAILS_VERSION','0.6.9');class Trails_Dispatcher{public$trails_root;public$trails_uri;public$default_controller;function __construct($trails_root, $trails_uri, $default_controller){$this->trails_root=$trails_root;$this->trails_uri=$trails_uri;$this->default_controller=$default_controller;}function dispatch($uri){$old_handler=set_error_handler(array($this, 'error_handler'),5888);ob_start();$level=ob_get_level();$this->map_uri_to_response($this->clean_request_uri((string)$uri))->output();while(ob_get_level()>=$level){ob_end_flush();}if(isset($old_handler)){set_error_handler($old_handler);}}function map_uri_to_response($uri){try{[$controller_path, $unconsumed]=''===$uri?$this->default_route():$this->parse($uri);$controller=$this->load_controller($controller_path);$response=$controller->perform($unconsumed);}catch(Exception$e){$response=isset($controller)?$controller->rescue($e):$this->trails_error($e);}return$response;}function default_route(){if(!$this->file_exists($this->default_controller.'.php')){throw new Trails_MissingFile("Default controller '{$this->default_controller}' not found'");}return array($this->default_controller, '');}function trails_error($exception){ob_clean();$detailed=@$_SERVER['REMOTE_ADDR']==='127.0.0.1';$body=sprintf('<html><head><title>Trails Error</title></head>'.'<body><h1>%s</h1><pre>%s</pre></body></html>',htmlentities($exception->__toString()),$detailed?htmlentities($exception->getTraceAsString()):'');if($exception instanceof Trails_Exception){$response=new Trails_Response($body,$exception->headers,$exception->getCode(),$exception->getMessage());}else{$response=new Trails_Response($body,array(),500,$exception->getMessage());}return$response;}function clean_request_uri($uri){if(FALSE!==($pos=strpos($uri,'?'))){$uri=substr($uri,0,$pos);}return ltrim($uri,'/');}function parse($unconsumed, $controller=NULL){[$head, $tail]=$this->split_on_first_slash($unconsumed);if(!preg_match('/^\w+$/',$head)){throw new Trails_RoutingError("No route matches '$head'");}$controller=(isset($controller)?$controller.'/':'').$head;if($this->file_exists($controller.'.php')){return array($controller, $tail);}else if($this->file_exists($controller)){return$this->parse($tail,$controller);}throw new Trails_RoutingError("No route matches '$head'");}function split_on_first_slash($str){preg_match(":([^/]*)(/+)?(.*):",$str,$matches);return array($matches[1], $matches[3]);}function file_exists($path){return file_exists("{$this->trails_root}/controllers/$path");}function load_controller($controller){require_once"{$this->trails_root}/controllers/{$controller}.php";$class=Trails_Inflector::camelize($controller).'Controller';if(!class_exists($class)){throw new Trails_UnknownController("Controller missing: '$class'");}return new$class($this);}function error_handler($errno, $string, $file, $line, $context){if(!(5888&$errno))return false;throw new Trails_Exception(500,$string);}}class Trails_Response{public$body='',$status,$reason,$headers=array();function __construct($body='', $headers=array(), $status=NULL, $reason=NULL){$this->set_body($body);$this->headers=$headers;if(isset($status)){$this->set_status($status,$reason);}}function set_body($body){$this->body=$body;return$this;}function set_status($status, $reason=NULL){$this->status=$status;$this->reason=isset($reason)?$reason:$this->get_reason($status);return$this;}function get_reason($status){$reason=array(100 =>'Continue', 'Switching Protocols', 200 =>'OK', 'Created', 'Accepted', 'Non-Authoritative Information', 'No Content', 'Reset Content', 'Partial Content', 300 =>'Multiple Choices', 'Moved Permanently', 'Found', 'See Other', 'Not Modified', 'Use Proxy', '(Unused)', 'Temporary Redirect', 400 =>'Bad Request', 'Unauthorized', 'Payment Required', 'Forbidden', 'Not Found', 'Method Not Allowed', 'Not Acceptable', 'Proxy Authentication Required', 'Request Timeout', 'Conflict', 'Gone', 'Length Required', 'Precondition Failed', 'Request Entity Too Large', 'Request-URI Too Long', 'Unsupported Media Type', 'Requested Range Not Satisfiable', 'Expectation Failed', 500 =>'Internal Server Error', 'Not Implemented', 'Bad Gateway', 'Service Unavailable', 'Gateway Timeout', 'HTTP Version Not Supported');return isset($reason[$status])? $reason[$status]:'';}function add_header($key, $value){$this->headers[$key]=$value;return$this;}function output(){if(isset($this->status)){$this->send_header(sprintf('HTTP/1.1 %d %s',$this->status,$this->reason),TRUE,$this->status);}foreach($this->headers as $k=> $v){$this->send_header("$k: $v");}echo$this->body;}function send_header($header, $replace=FALSE, $status=NULL){if(isset($status)){header($header,$replace,$status);}else{header($header,$replace);}}}class Trails_Controller{protected$dispatcher,$response,$performed,$layout;function __construct($dispatcher){$this->dispatcher=$dispatcher;$this->erase_response();}function erase_response(){$this->performed=FALSE;$this->response=new Trails_Response();}function get_response(){return$this->response;}function perform($unconsumed){[$action, $args, $format]=$this->extract_action_and_args($unconsumed);$this->format=isset($format)?$format:'html';$before_filter_result=$this->before_filter($action,$args);if(!(FALSE===$before_filter_result||$this->performed)){$callable=$this->map_action($action);if(is_callable($callable)){call_user_func_array($callable,$args);}else{$this->does_not_understand($action,$args);}if(!$this->performed){$this->render_action($action);}$this->after_filter($action,$args);}return$this->response;}function extract_action_and_args($string){if(''===$string){return$this->default_action_and_args();}$format=NULL;if(preg_match('/^(.*[^\/.])\.(\w+)$/',$string,$matches)){[$_, $string, $format]=$matches;}$args=explode('/',$string);$action=array_shift($args);return array($action, $args, $format);}function default_action_and_args(){return array('index', array(), NULL);}function map_action($action){return array(&$this, $action.'_action');}function before_filter(&$action, &$args){}function after_filter($action, $args){}function does_not_understand($action, $args){throw new Trails_UnknownAction("No action responded to '$action'.");}function redirect($to){if($this->performed){throw new Trails_DoubleRenderError();}$this->performed=TRUE;$url=preg_match('#^(/|\w+://)#',$to)?$to:$this->url_for($to);$this->response->add_header('Location',$url)->set_status(302);}function render_text($text=' '){if($this->performed){throw new Trails_DoubleRenderError();}$this->performed=TRUE;$this->response->set_body($text);}function render_nothing(){$this->render_text('');}function render_action($action){$this->render_template($this->get_default_template($action),$this->layout);}function get_default_template($action){$class=get_class($this);$controller_name=Trails_Inflector::underscore(substr($class,0,-10));return$controller_name.'/'.$action;}function render_template($template_name, $layout=NULL){$factory=$this->get_template_factory();$template=$factory->open($template_name);$template->set_attributes($this->get_assigned_variables());if(isset($layout)){$template->set_layout($layout);}$this->render_text($template->render());}function get_template_factory(){return new Flexi\Factory($this->dispatcher->trails_root.'/views/');}function get_assigned_variables(){$assigns=array();$protected=get_class_vars(get_class($this));foreach(get_object_vars($this) as $var=> $value){if(!array_key_exists($var,$protected)){$assigns[$var]=&$this->$var;}}$assigns['controller']=$this;return$assigns;}function set_layout($layout){$this->layout=$layout;}function url_for($to){$args=func_get_args();$args=array_map('urlencode',$args);$args[0]=$to;return$this->dispatcher->trails_uri.'/'.join('/',$args);}function set_status($status, $reason_phrase=NULL){$this->response->set_status($status,$reason_phrase);}function set_content_type($type){$this->response->add_header('Content-Type',$type);}function rescue($exception){return$this->dispatcher->trails_error($exception);}function respond_to($ext){return$this->format===$ext;}}class Trails_Inflector{static function camelize($word){$parts=explode('/',$word);foreach($parts as $key=> $part){$parts[$key]=str_replace(' ','',ucwords(str_replace('_',' ',$part)));}return join('_',$parts);}static function underscore($word){$parts=explode('_',$word);foreach($parts as $key=> $part){$parts[$key]=preg_replace('/(?<=\w)([A-Z])/','_\\1',$part);}return strtolower(join('/',$parts));}}class Trails_Flash implements ArrayAccess{public$flash=array(),$used=array();static function instance(){if(!isset($_SESSION)){throw new Trails_SessionRequiredException();}if(!isset($_SESSION['trails_flash'])){$_SESSION['trails_flash']=new Trails_Flash();}return $_SESSION['trails_flash'];}function offsetExists($offset){return isset($this->flash[$offset]);}function offsetGet($offset){return$this->get($offset);}function offsetSet($offset, $value){$this->set($offset,$value);}function offsetUnset($offset){unset($this->flash[$offset], $this->used[$offset]);}function _use($k=NULL, $v=TRUE){if($k){$this->used[$k]=$v;}else{foreach($this->used as $k=> $value){$this->_use($k,$v);}}}function discard($k=NULL){$this->_use($k);}function&get($k){$return=NULL;if(isset($this->flash[$k])){$return=& $this->flash[$k];}return$return;}function keep($k=NULL){$this->_use($k,FALSE);}function set($k, $v){$this->keep($k);$this->flash[$k]=$v;}function set_ref($k, &$v){$this->keep($k);$this->flash[$k]=&$v;}function sweep(){foreach(array_keys($this->flash) as $k){if($this->used[$k]){unset($this->flash[$k], $this->used[$k]);}else{$this->_use($k);}}$fkeys=array_keys($this->flash);$ukeys=array_keys($this->used);foreach(array_diff($fkeys,$ukeys) as $k=> $v){unset($this->used[$k]);}}function __toString(){$values=array();foreach($this->flash as $k=> $v){$values[]=sprintf("'%s': [%s, '%s']",$k,var_export($v,TRUE), $this->used[$k]?"used":"unused");}return"{".join(", ",$values)."}\n";}function __sleep(){$this->sweep();return array('flash', 'used');}function __wakeUp(){$this->discard();}}class Trails_Exception extends Exception{public$headers;function __construct($status=500, $reason=NULL, $headers=array()){if($reason===NULL){$reason=Trails_Response::get_reason($status);}parent::__construct($reason,$status);$this->headers=$headers;}function __toString(){return"{$this->code} {$this->message}";}}class Trails_DoubleRenderError extends Trails_Exception{function __construct(){$message="Render and/or redirect were called multiple times in this action. "."Please note that you may only call render OR redirect, and at most "."once per action.";parent::__construct(500,$message);}}class Trails_MissingFile extends Trails_Exception{function __construct($message){parent::__construct(500,$message);}}class Trails_RoutingError extends Trails_Exception{function __construct($message){parent::__construct(400,$message);}}class Trails_UnknownAction extends Trails_Exception{function __construct($message){parent::__construct(404,$message);}}class Trails_UnknownController extends Trails_Exception{function __construct($message){parent::__construct(404,$message);}}class Trails_SessionRequiredException extends Trails_Exception{function __construct(){$message="Tried to access a non existing session.";parent::__construct(500,$message);}}
diff --git a/vendor/trails/trails.php b/vendor/trails/trails.php
deleted file mode 100644
index 911765555570ed3fe3e7b3463c4414928a126b25..0000000000000000000000000000000000000000
--- a/vendor/trails/trails.php
+++ /dev/null
@@ -1,1289 +0,0 @@
-<?php
-
-# Copyright (c)  2007 - Marcus Lunzenauer <mlunzena@uos.de>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-
-/**
- * The version of the trails library.
- */
-
-define('TRAILS_VERSION', '0.6.9');
-
-
-
-/**
- * The Dispatcher is used to map an incoming HTTP request to a Controller
- * producing a response which is then rendered. To initialize an instance of
- * class Trails_Dispatcher you have to give three configuration settings:
- *
- *          trails_root - the absolute file path to a directory containing the
- *                        applications controllers, views etc.
- *           trails_uri - the URI to which routes to mapped Controller/Actions
- *                        are appended
- *   default_controller - the route to a controller, that is used if no
- *                        controller is given, that is the route is equal to '/'
- *
- * After instantiation of a dispatcher you have to call method #dispatch with
- * the request uri to be mapped to a controller/action pair.
- *
- * @package   trails
- *
- * @author    mlunzena
- * @copyright (c) Authors
- * @version   $Id: trails.php 7001 2008-04-04 11:20:27Z mlunzena $
- */
-
-class Trails_Dispatcher {
-
-  # TODO (mlunzena) Konfiguration muss anders geschehen
-
-  /**
-   * This is the absolute file path to the trails application directory.
-   *
-   * @access public
-   * @var    string
-   */
-  public $trails_root;
-
-
-  /**
-   * This is the URI to which routes to controller/actions are appended.
-   *
-   * @access public
-   * @var    string
-   */
-  public $trails_uri;
-
-
-  /**
-   * This variable contains the route to the default controller.
-   *
-   * @access public
-   * @var    string
-   */
-  public $default_controller;
-
-
-  /**
-   * Constructor.
-   *
-   * @param  string  absolute file path to a directory containing the
-   *                 applications controllers, views etc.
-   * @param  string  the URI to which routes to mapped Controller/Actions
-   *                 are appended
-   * @param  string  the route to a controller, that is used if no
-   *                 controller is given, that is the route is equal to '/'
-   *
-   * @return void
-   */
-  function __construct($trails_root,
-                       $trails_uri,
-                       $default_controller) {
-
-    $this->trails_root        = $trails_root;
-    $this->trails_uri         = $trails_uri;
-    $this->default_controller = $default_controller;
-  }
-
-
-  /**
-   * Maps a string to a response which is then rendered.
-   *
-   * @param string The requested URI.
-   *
-   * @return void
-   */
-  function dispatch($uri) {
-
-    # E_USER_ERROR|E_USER_WARNING|E_USER_NOTICE|E_RECOVERABLE_ERROR = 5888
-    $old_handler = set_error_handler(array($this, 'error_handler'), 5888);
-
-    ob_start();
-    $level = ob_get_level();
-
-    $this->map_uri_to_response($this->clean_request_uri((string) $uri))->output();
-
-    while (ob_get_level() >= $level) {
-      ob_end_flush();
-    }
-
-    if (isset($old_handler)) {
-      set_error_handler($old_handler);
-    }
-  }
-
-
-  /**
-   * Maps an URI to a response by figuring out first what controller to
-   * instantiate, then delegating the unconsumed part of the URI to the
-   * controller who returns an appropriate response object or throws a
-   * Trails_Exception.
-   *
-   * @param  string  the URI string
-   *
-   * @return mixed   a response object
-   */
-  function map_uri_to_response($uri) {
-
-    try {
-
-      list($controller_path, $unconsumed) =
-          '' === $uri
-          ? $this->default_route()
-            : $this->parse($uri);
-
-      $controller = $this->load_controller($controller_path);
-
-      $response = $controller->perform($unconsumed);
-
-    } catch (Exception $e) {
-
-      $response = isset($controller) ? $controller->rescue($e)
-                                     : $this->trails_error($e);
-    }
-
-    return $response;
-  }
-
-
-  /**
-   *
-   * @return array  an array containing the default controller and an
-   *                empty unconsumed route
-   */
-  function default_route() {
-      if (!$this->file_exists($this->default_controller . '.php')) {
-          throw new Trails_MissingFile(
-              "Default controller '{$this->default_controller}' not found'");
-      }
-      return array($this->default_controller, '');
-  }
-
-
-  function trails_error($exception) {
-    ob_clean();
-
-    # show details for local requests
-    $detailed = @$_SERVER['REMOTE_ADDR'] === '127.0.0.1';
-
-    $body = sprintf('<html><head><title>Trails Error</title></head>'.
-                    '<body><h1>%s</h1><pre>%s</pre></body></html>',
-                    htmlentities($exception->__toString()),
-                    $detailed
-                      ? htmlentities($exception->getTraceAsString())
-                      : '');
-
-    if ($exception instanceof Trails_Exception) {
-      $response = new Trails_Response($body,
-                                      $exception->headers,
-                                      $exception->getCode(),
-                                      $exception->getMessage());
-    }
-    else {
-      $response = new Trails_Response($body, array(), 500,
-                                      $exception->getMessage());
-    }
-
-    return $response;
-  }
-
-
-  /**
-   * Clean up URI string by removing the query part and leading slashes.
-   *
-   * @param  string  an URI string
-   *
-   * @return string  the cleaned string
-   */
-  function clean_request_uri($uri) {
-    if (FALSE !== ($pos = strpos($uri, '?'))) {
-      $uri = substr($uri, 0, $pos);
-    }
-    return ltrim($uri, '/');
-  }
-
-
-  /**
-   * <MethodDescription>
-   *
-   * @param  type       <description>
-   * @param  type       <description>
-   *
-   * @return type       <description>
-   */
-  function parse($unconsumed, $controller = NULL) {
-    list($head, $tail) = $this->split_on_first_slash($unconsumed);
-
-    if (!preg_match('/^\w+$/', $head)) {
-      throw new Trails_RoutingError("No route matches '$head'");
-    }
-
-    $controller = (isset($controller) ? $controller . '/' : '') . $head;
-
-    if ($this->file_exists($controller . '.php')) {
-      return array($controller, $tail);
-    }
-    else if ($this->file_exists($controller)) {
-      return $this->parse($tail, $controller);
-    }
-
-    throw new Trails_RoutingError("No route matches '$head'");
-  }
-
-  function split_on_first_slash($str) {
-    preg_match(":([^/]*)(/+)?(.*):", $str, $matches);
-    return array($matches[1], $matches[3]);
-  }
-
-  function file_exists($path) {
-    return file_exists("{$this->trails_root}/controllers/$path");
-  }
-
-  /**
-   * Loads the controller file for a given controller path and return an
-   * instance of that controller. If an error occures, an exception will be
-   * thrown.
-   *
-   * @param  string            the relative controller path
-   *
-   * @return TrailsController  an instance of that controller
-   */
-  function load_controller($controller) {
-    require_once "{$this->trails_root}/controllers/{$controller}.php";
-    $class = Trails_Inflector::camelize($controller) . 'Controller';
-    if (!class_exists($class)) {
-      throw new Trails_UnknownController("Controller missing: '$class'");
-    }
-    return new $class($this);
-  }
-
-
-  /**
-   * This method transforms E_USER_* and E_RECOVERABLE_ERROR to
-   * Trails_Exceptions.
-   *
-   * @param  integer    the level of the error raised
-   * @param  string     the error message
-   * @param  string     the filename that the error was raised in
-   * @param  integer    the line number the error was raised at
-   *
-   * @throws Trails_Exception
-   *
-   * @return void
-   */
-  function error_handler($errno, $string, $file, $line) {
-    if (!(5888 & $errno)) {
-      return false;
-    }
-    throw new Trails_Exception(500, $string);
-  }
-}
-
-
-/**
- * This class represents a response returned by a controller that was asked to
- * perform for a given request. A Trails_Response contains the body, status and
- * additional headers which can be renderer back to the client.
- *
- * @package   trails
- *
- * @author    mlunzena
- * @copyright (c) Authors
- * @version   $Id: trails.php 7001 2008-04-04 11:20:27Z mlunzena $
- */
-
-class Trails_Response {
-
-
-  /**
-   * @ignore
-   */
-  public
-    $body = '',
-    $status,
-    $reason,
-    $headers = array();
-
-
-  /**
-   * Constructor.
-   *
-   * @param  string   the body of the response defaulting to ''
-   * @param  array    an array of additional headers defaulting to an
-   *                  empty array
-   * @param  integer  the status code of the response defaulting to a
-   *                  regular 200
-   * @param  string   the descriptional reason for a status code defaulting to
-   *                  the standard reason phrases defined in RFC 2616
-   *
-   * @return void
-   */
-  function __construct($body = '', $headers = array(),
-                       $status = NULL, $reason = NULL) {
-
-    $this->set_body($body);
-
-    $this->headers = $headers;
-
-    if (isset($status)) {
-      $this->set_status($status, $reason);
-    }
-  }
-
-
-  /**
-   * Sets the body of the response.
-   *
-   * @param  string  the body
-   *
-   * @return mixed   this response object. Useful for cascading method calls.
-   */
-  function set_body($body) {
-    $this->body = $body;
-    return $this;
-  }
-
-
-  /**
-   * Sets the status code and an optional custom reason. If none is given, the
-   * standard reason phrase as of RFC 2616 is used.
-   *
-   * @param  integer  the status code
-   * @param  string   the custom reason, defaulting to the one given in RFC 2616
-   *
-   * @return mixed    this response object. Useful for cascading method calls.
-   */
-  function set_status($status, $reason = NULL) {
-    $this->status = $status;
-    $this->reason = isset($reason) ? $reason : self::get_reason($status);
-    return $this;
-  }
-
-
-  /**
-   * Returns the reason phrase of this response according to RFC2616.
-   *
-   * @param int      the response's status
-   *
-   * @return string  the reason phrase for this response's status
-   */
-  public static function get_reason($status) {
-    $reason = array(
-      100 => 'Continue', 'Switching Protocols',
-      200 => 'OK', 'Created', 'Accepted', 'Non-Authoritative Information',
-             'No Content', 'Reset Content', 'Partial Content',
-      300 => 'Multiple Choices', 'Moved Permanently', 'Found', 'See Other',
-             'Not Modified', 'Use Proxy', '(Unused)', 'Temporary Redirect',
-      400 => 'Bad Request', 'Unauthorized', 'Payment Required','Forbidden',
-             'Not Found', 'Method Not Allowed', 'Not Acceptable',
-             'Proxy Authentication Required', 'Request Timeout', 'Conflict',
-             'Gone', 'Length Required', 'Precondition Failed',
-             'Request Entity Too Large', 'Request-URI Too Long',
-             'Unsupported Media Type', 'Requested Range Not Satisfiable',
-             'Expectation Failed',
-      500 => 'Internal Server Error', 'Not Implemented', 'Bad Gateway',
-             'Service Unavailable', 'Gateway Timeout',
-             'HTTP Version Not Supported');
-
-    return isset($reason[$status]) ? $reason[$status] : '';
-  }
-
-
-  /**
-   * Adds an additional header to the response.
-   *
-   * @param  string  the left hand key part
-   * @param  string  the right hand value part
-   *
-   * @return mixed   this response object. Useful for cascading method calls.
-   */
-  function add_header($key, $value) {
-    $this->headers[$key] = $value;
-    return $this;
-  }
-
-
-  /**
-   * Outputs this response to the client using "echo" and "header".
-   *
-   * @return void
-   */
-  function output() {
-    if (isset($this->status)) {
-      $this->send_header(sprintf('HTTP/1.1 %d %s',
-                                 $this->status, $this->reason),
-                         TRUE,
-                         $this->status);
-    }
-
-    foreach ($this->headers as $k => $v) {
-      $this->send_header("$k: $v");
-    }
-
-    echo $this->body;
-  }
-
-
-  /**
-   * Internally used function to actually send headers
-   *
-   * @param  string     the HTTP header
-   * @param  bool       optional; TRUE if previously sent header should be
-   *                    replaced - FALSE otherwise (default)
-   * @param  integer    optional; the HTTP response code
-   *
-   * @return void
-   */
-  function send_header($header, $replace = FALSE, $status = NULL) {
-    if (isset($status)) {
-      header($header, $replace, $status);
-    }
-    else {
-      header($header, $replace);
-    }
-  }
-}
-
-
-
-/**
- * A Trails_Controller is responsible for matching the unconsumed part of an URI
- * to an action using the left over words as arguments for that action. The
- * action is then mapped to method of the controller instance which is called
- * with the just mentioned arguments. That method can send the #render_action,
- * #render_template, #render_text, #render_nothing or #redirect method.
- * Otherwise the #render_action is called with the current action as argument.
- * If the action method sets instance variables during performing, they will be
- * be used as attributes for the flexi-template opened by #render_action or
- * #render_template. A controller's response's body is populated with the output
- * of the #render_* methods. The action methods can add additional headers or
- * change the status of that response.
- *
- * @package   trails
- *
- * @author    mlunzena
- * @copyright (c) Authors
- * @version   $Id: trails.php 7001 2008-04-04 11:20:27Z mlunzena $
- */
-
-class Trails_Controller {
-
-
-  /**
-   * @ignore
-   */
-  protected
-    $dispatcher,
-    $response,
-    $performed,
-    $layout;
-
-
-  /**
-   * Constructor.
-   *
-   * @param  mixed  the dispatcher who creates this instance
-   *
-   * @return void
-   */
-  function __construct($dispatcher) {
-    $this->dispatcher = $dispatcher;
-    $this->erase_response();
-  }
-
-
-  /**
-   * Resets the response of the controller
-   *
-   * @return void
-   */
-  function erase_response() {
-    $this->performed = FALSE;
-    $this->response = new Trails_Response();
-  }
-
-
-  /**
-   * Return this controller's response
-   *
-   * @return mixed  the controller's response
-   */
-  function get_response() {
-    return $this->response;
-  }
-
-
-  /**
-   * This method extracts an action string and further arguments from it's
-   * parameter. The action string is mapped to a method being called afterwards
-   * using the said arguments. That method is called and a response object is
-   * generated, populated and sent back to the dispatcher.
-   *
-   * @param type <description>
-   *
-   * @return type <description>
-   */
-  function perform($unconsumed) {
-
-    list($action, $args, $format) = $this->extract_action_and_args($unconsumed);
-
-    $this->format = isset($format) ? $format : 'html';
-
-    $before_filter_result = $this->before_filter($action, $args);
-
-    # send action to controller
-    # TODO (mlunzena) shouldn't the after filter be triggered too?
-    if (!(FALSE === $before_filter_result || $this->performed)) {
-
-      $callable = $this->map_action($action);
-
-      if (is_callable($callable)) {
-        call_user_func_array($callable, $args);
-      }
-      else {
-        $this->does_not_understand($action, $args);
-      }
-
-      if (!$this->performed) {
-        $this->render_action($action);
-      }
-
-      $this->after_filter($action, $args);
-    }
-
-    return $this->response;
-  }
-
-
-  /**
-   * Extracts action and args from a string.
-   *
-   * @param  string       the processed string
-   *
-   * @return array        an array with two elements - a string containing the
-   *                      action and an array of strings representing the args
-   */
-  function extract_action_and_args($string) {
-
-    if ('' === $string) {
-      return $this->default_action_and_args();
-    }
-
-    // find optional file extension
-    $format = NULL;
-    if (preg_match('/^(.*[^\/.])\.(\w+)$/', $string, $matches)) {
-      list($_, $string, $format) = $matches;
-    }
-
-    // TODO this should possibly remove empty tokens
-    $args = explode('/', $string);
-    $action = array_shift($args);
-    return array($action, $args, $format);
-  }
-
-  /**
-   * Return the default action and arguments
-   *
-   * @return an array containing the action, an array of args and the format
-   *
-   */
-  function default_action_and_args() {
-    return array('index', array(), NULL);
-  }
-
-  /**
-   * Maps the action to an actual method name.
-   *
-   * @param  string  the action
-   *
-   * @return string  the mapped method name
-   */
-  function map_action($action) {
-    return array(&$this, $action . '_action');
-  }
-
-
-  /**
-   * Callback function being called before an action is executed. If this
-   * function does not return FALSE, the action will be called, otherwise
-   * an error will be generated and processing will be aborted. If this function
-   * already #rendered or #redirected, further processing of the action is
-   * withheld.
-   *
-   * @param string  Name of the action to perform.
-   * @param array   An array of arguments to the action.
-   *
-   * @return bool
-   */
-  function before_filter(&$action, &$args) {
-  }
-
-
-  /**
-   * Callback function being called after an action is executed.
-   *
-   * @param string Name of the action to perform.
-   * @param array  An array of arguments to the action.
-   *
-   * @return void
-   */
-  function after_filter($action, $args) {
-  }
-
-
-  /**
-   * <MethodDescription>
-   *
-   * @param type <description>
-   * @param type <description>
-   *
-   * @return void
-   */
-  function does_not_understand($action, $args) {
-    throw new Trails_UnknownAction("No action responded to '$action'.");
-  }
-
-
-  /**
-   * <MethodDescription>
-   *
-   * @param string <description>
-   *
-   * @return void
-   */
-  function redirect($to) {
-
-    if ($this->performed) {
-      throw new Trails_DoubleRenderError();
-    }
-
-    $this->performed = TRUE;
-
-    # get uri; keep absolute URIs
-    $url = preg_match('#^(/|\w+://)#', $to)
-           ? $to
-           : $this->url_for($to);
-
-    $this->response->add_header('Location', $url)->set_status(302);
-  }
-
-
-  /**
-   * Renders the given text as the body of the response.
-   *
-   * @param string  the text to be rendered
-   *
-   * @return void
-   */
-  function render_text($text = ' ') {
-
-    if ($this->performed) {
-      throw new Trails_DoubleRenderError();
-    }
-
-    $this->performed = TRUE;
-
-    $this->response->set_body($text);
-  }
-
-
-  /**
-   * Renders the empty string as the response's body.
-   *
-   * @return void
-   */
-  function render_nothing() {
-    $this->render_text('');
-  }
-
-
-  /**
-   * Renders the template of the given action as the response's body.
-   *
-   * @param string  the action
-   *
-   * @return void
-   */
-  function render_action($action) {
-    $this->render_template($this->get_default_template($action), $this->layout);
-  }
-
-
-  function get_default_template($action)
-  {
-    $class = get_class($this);
-    $controller_name =
-      Trails_Inflector::underscore(substr($class, 0, -10));
-    return $controller_name.'/'.$action;
-  }
-
-
-  /**
-   * Renders a template using an optional layout template.
-   *
-   * @param mixed  a flexi template
-   * @param mixes  a flexi template which is used as layout
-   *
-   * @return void
-   */
-  function render_template($template_name, $layout = NULL) {
-
-    # open template
-    $factory = $this->get_template_factory();
-    $template = $factory->open($template_name);
-
-    $template->set_attributes($this->get_assigned_variables());
-
-    if (isset($layout)) {
-      $template->set_layout($layout);
-    }
-
-    $this->render_text($template->render());
-  }
-
-
-  /**
-   * Create and return a template factory for this controller.
-   *
-   * @return Flexi\Factory
-   */
-  function get_template_factory() {
-    return new Flexi\Factory($this->dispatcher->trails_root .
-                                     '/views/');
-  }
-
-
-  /**
-   * This method returns all the set instance variables to be used as attributes
-   * for a template. This controller is returned too as value for
-   * key 'controller'.
-   *
-   * @return array  an associative array of variables for the template
-   */
-  function get_assigned_variables() {
-
-    $assigns = array();
-    $protected = get_class_vars(get_class($this));
-
-    foreach (get_object_vars($this) as $var => $value) {
-      if (!array_key_exists($var, $protected)) {
-        $assigns[$var] =& $this->$var;
-      }
-    }
-
-    $assigns['controller'] = $this;
-
-    return $assigns;
-  }
-
-
-  /**
-   * Sets the layout to be used by this controller per default.
-   *
-   * @param  mixed  a flexi template to be used as layout
-   *
-   * @return void
-   */
-  function set_layout($layout) {
-    $this->layout = $layout;
-  }
-
-
-  /**
-   * Returns a URL to a specified route to your Trails application.
-   *
-   * Example:
-   * Your Trails application is located at 'http://example.com/dispatch.php'.
-   * So your dispatcher's trails_uri is set to 'http://example.com/dispatch.php'
-   * If you want the URL to your 'wiki' controller with action 'show' and
-   * parameter 'page' you should send:
-   *
-   *   $url = $controller->url_for('wiki/show', 'page');
-   *
-   * $url should then contain 'http://example.com/dispatch.php/wiki/show/page'.
-   *
-   * The first parameter is a string containing the controller and optionally an
-   * action:
-   *
-   *   - "{controller}/{action}"
-   *   - "path/to/controller/action"
-   *   - "controller"
-   *
-   * This "controller/action" string is not url encoded. You may provide
-   * additional parameter which will be urlencoded and concatenated with
-   * slashes:
-   *
-   *     $controller->url_for('wiki/show', 'page');
-   *     -> 'wiki/show/page'
-   *
-   *     $controller->url_for('wiki/show', 'page', 'one and a half');
-   *     -> 'wiki/show/page/one+and+a+half'
-   *
-   * @param  string   a string containing a controller and optionally an action
-   * @param  strings  optional arguments
-   *
-   * @return string  a URL to this route
-   */
-  function url_for($to/*, ...*/) {
-
-    # urlencode all but the first argument
-    $args = func_get_args();
-    $args = array_map('urlencode', $args);
-    $args[0] = $to;
-
-    return $this->dispatcher->trails_uri . '/' . join('/', $args);
-  }
-
-
-  /**
-   * <MethodDescription>
-   *
-   * @param  type       <description>
-   *
-   * @return type       <description>
-   */
-  function set_status($status, $reason_phrase = NULL) {
-    $this->response->set_status($status, $reason_phrase);
-  }
-
-
-  /**
-   * Sets the content type of the controller's response.
-   *
-   * @param  string  the content type
-   *
-   * @return void
-   */
-  function set_content_type($type) {
-    $this->response->add_header('Content-Type', $type);
-  }
-
-
-  /**
-   * Exception handler called when the performance of an action raises an
-   * exception.
-   *
-   * @param  object     the thrown exception
-   *
-   * @return object     a response object
-   */
-  function rescue($exception) {
-    return $this->dispatcher->trails_error($exception);
-  }
-
-  function respond_to($ext) {
-    return $this->format === $ext;
-  }
-}
-
-
-/**
- * The Inflector class is a namespace for inflections methods.
- *
- * @package   trails
- *
- * @author    mlunzena
- * @copyright (c) Authors
- * @version   $Id: trails.php 7001 2008-04-04 11:20:27Z mlunzena $
- */
-
-class Trails_Inflector {
-
-
-  /**
-   * Returns a camelized string from a lower case and underscored string by
-   * replacing slash with underscore and upper-casing each letter preceded
-   * by an underscore. TODO
-   *
-   * @param string String to camelize.
-   *
-   * @return string Camelized string.
-   */
-  static function camelize($word) {
-    $parts = explode('/', $word);
-    foreach ($parts as $key => $part) {
-      $parts[$key] = str_replace(' ', '',
-                                 ucwords(str_replace('_', ' ', $part)));
-    }
-    return join('_', $parts);
-  }
-
-
-  /**
-   * <MethodDescription>
-   *
-   * @param type <description>
-   *
-   * @return type <description>
-   */
-  static function underscore($word) {
-    $parts = explode('_', $word);
-    foreach ($parts as $key => $part) {
-      $parts[$key] = preg_replace('/(?<=\w)([A-Z])/', '_\\1', $part);
-    }
-    return strtolower(join('/', $parts));
-  }
-}
-
-
-/**
- * The flash provides a way to pass temporary objects between actions.
- * Anything you place in the flash will be exposed to the very next action and
- * then cleared out. This is a great way of doing notices and alerts, such as
- * a create action that sets
- * <tt>$flash->set('notice', "Successfully created")</tt>
- * before redirecting to a display action that can then expose the flash to its
- * template.
- *
- * @package   trails
- *
- * @author    mlunzena
- * @copyright (c) Authors
- * @version   $Id: trails.php 7001 2008-04-04 11:20:27Z mlunzena $
- */
-
-class Trails_Flash implements ArrayAccess {
-
-
-  /**
-   * @ignore
-   */
-  public
-    $flash = array(), $used = array();
-
-
-  /**
-   * <MethodDescription>
-   *
-   * @return type       <description>
-   */
-  static function instance() {
-
-    if (!isset($_SESSION)) {
-      throw new Trails_SessionRequiredException();
-    }
-
-
-    if (!isset($_SESSION['trails_flash'])) {
-      $_SESSION['trails_flash'] = new Trails_Flash();
-    }
-    return $_SESSION['trails_flash'];
-  }
-
-
-  #[ReturnTypeWillChange]
-  function offsetExists($offset) {
-    return isset($this->flash[$offset]);
-  }
-
-
-  #[ReturnTypeWillChange]
-  function offsetGet($offset) {
-    return $this->get($offset);
-  }
-
-
-  function offsetSet($offset, $value) {
-    $this->set($offset, $value);
-  }
-
-
-  #[ReturnTypeWillChange]
-  function offsetUnset($offset) {
-    unset($this->flash[$offset], $this->used[$offset]);
-  }
-
-
-  /**
-   * Used internally by the <tt>keep</tt> and <tt>discard</tt> methods
-   *     use()               # marks the entire flash as used
-   *     use('msg')          # marks the "msg" entry as used
-   *     use(null, false)    # marks the entire flash as unused
-   *                         # (keeps it around for one more action)
-   *     use('msg', false)   # marks the "msg" entry as unused
-   *                         # (keeps it around for one more action)
-   *
-   * @param mixed  a key.
-   * @param bool   used flag.
-   *
-   * @return void
-   */
-  function _use($k = NULL, $v = TRUE) {
-    if ($k) {
-      $this->used[$k] = $v;
-    }
-    else {
-      foreach ($this->used as $k => $value) {
-        $this->_use($k, $v);
-      }
-    }
-  }
-
-
-  /**
-   * Marks the entire flash or a single flash entry to be discarded by the end
-   * of the current action.
-   *
-   *     $flash->discard()             # discards entire flash
-   *                                   # (it'll still be available for the
-   *                                   # current action)
-   *     $flash->discard('warning')    # discard the "warning" entry
-   *                                   # (it'll still be available for the
-   *                                   # current action)
-   *
-   * @param mixed  a key.
-   *
-   * @return void
-   */
-  function discard($k = NULL) {
-    $this->_use($k);
-  }
-
-
-  /**
-   * Returns the value to the specified key.
-   *
-   * @param mixed  a key.
-   *
-   * @return mixed the key's value.
-   */
-  function &get($k) {
-    $return = NULL;
-    if (isset($this->flash[$k])) {
-      $return =& $this->flash[$k];
-    }
-    return $return;
-  }
-
-
-  /**
-   * Keeps either the entire current flash or a specific flash entry available
-   * for the next action:
-   *
-   *    $flash->keep()           # keeps the entire flash
-   *    $flash->keep('notice')   # keeps only the "notice" entry, the rest of
-   *                             # the flash is discarded
-   *
-   * @param mixed  a key.
-   *
-   * @return void
-   */
-  function keep($k = NULL) {
-    $this->_use($k, FALSE);
-  }
-
-
-  /**
-   * Sets a key's value.
-   *
-   * @param mixed  a key.
-   * @param mixed  its value.
-   *
-   * @return void
-   */
-  function set($k, $v) {
-    $this->keep($k);
-    $this->flash[$k] = $v;
-  }
-
-
-  /**
-   * Sets a key's value by reference.
-   *
-   * @param mixed  a key.
-   * @param mixed  its value.
-   *
-   * @return void
-   */
-  function set_ref($k, &$v) {
-    $this->keep($k);
-    $this->flash[$k] =& $v;
-  }
-
-
-
-  /**
-   * <MethodDescription>
-   *
-   * @return type       <description>
-   */
-  function sweep() {
-
-    # remove used values
-    foreach (array_keys($this->flash) as $k) {
-      if ($this->used[$k]) {
-        unset($this->flash[$k], $this->used[$k]);
-      } else {
-        $this->_use($k);
-      }
-    }
-
-    # cleanup if someone meddled with flash or used
-    $fkeys = array_keys($this->flash);
-    $ukeys = array_keys($this->used);
-    foreach (array_diff($fkeys, $ukeys) as $k => $v) {
-      unset($this->used[$k]);
-    }
-  }
-
-
-  /**
-   * <MethodDescription>
-   *
-   * @return type       <description>
-   */
-  function __toString() {
-    $values = array();
-    foreach ($this->flash as $k => $v) {
-      $values[] = sprintf("'%s': [%s, '%s']",
-                          $k, var_export($v, TRUE),
-                          $this->used[$k] ? "used" : "unused");
-    }
-    return "{" . join(", ", $values) . "}\n";
-  }
-
-
-  /**
-   * <MethodDescription>
-   *
-   * @param  type       <description>
-   *
-   * @return type       <description>
-   */
-  function __sleep() {
-    $this->sweep();
-    return array('flash', 'used');
-  }
-
-
-  /**
-   * <MethodDescription>
-   *
-   * @param  type       <description>
-   *
-   * @return type       <description>
-   */
-  function __wakeUp() {
-    $this->discard();
-  }
-}
-
-
-
-/**
- * TODO
- *
- * @package   trails
- *
- * @author    mlunzena
- * @copyright (c) Authors
- * @version   $Id: trails.php 7001 2008-04-04 11:20:27Z mlunzena $
- */
-
-class Trails_Exception extends Exception {
-
-  /**
-   * <FieldDescription>
-   *
-   * @access private
-   * @var <type>
-   */
-  public $headers;
-
-
-  /**
-   * @param  int     the status code to be set in the response
-   * @param  string  a human readable presentation of the status code
-   * @param  array   a hash of additional headers to be set in the response
-   *
-   * @return void
-   */
-  function __construct($status = 500, $reason = NULL, $headers = array()) {
-    if ($reason === NULL) {
-      $reason = Trails_Response::get_reason($status);
-    }
-    parent::__construct($reason, $status);
-    $this->headers = $headers;
-  }
-
-
-  /**
-   * <MethodDescription>
-   *
-   * @param  type       <description>
-   *
-   * @return type       <description>
-   */
-  function __toString() {
-    return "{$this->code} {$this->message}";
-  }
-}
-
-
-class Trails_DoubleRenderError extends Trails_Exception {
-
-  function __construct() {
-    $message =
-      "Render and/or redirect were called multiple times in this action. ".
-      "Please note that you may only call render OR redirect, and at most ".
-      "once per action.";
-    parent::__construct(500, $message);
-  }
-}
-
-
-class Trails_MissingFile extends Trails_Exception {
-  function __construct($message) {
-    parent::__construct(500, $message);
-  }
-}
-
-
-class Trails_RoutingError extends Trails_Exception {
-
-  function __construct($message) {
-    parent::__construct(400, $message);
-  }
-}
-
-
-class Trails_UnknownAction extends Trails_Exception {
-
-  function __construct($message) {
-    parent::__construct(404, $message);
-  }
-}
-
-
-class Trails_UnknownController extends Trails_Exception {
-
-  function __construct($message) {
-    parent::__construct(404, $message);
-  }
-}
-
-
-class Trails_SessionRequiredException extends Trails_Exception {
-  function __construct() {
-    $message = "Tried to access a non existing session.";
-    parent::__construct(500, $message);
-  }
-}