/**
  * Render the special page
  *
  * @param string $subpage
  */
 public function execute($subpage)
 {
     $out = $this->getOutput();
     $out->addModules(array('ext.gather.special', 'ext.gather.moderation'));
     $out->addModuleStyles(array('mobile.special.pagefeed.styles', 'mediawiki.ui.anchor', 'mediawiki.ui.icon', 'ext.gather.icons', 'ext.gather.styles', 'ext.gather.menu.icon'));
     if (!isset($subpage) || $subpage === '') {
         // Root subpage. For anons will be active collections, for logged in,
         // their own.
         $user = $this->getUser();
         if (!$user->isAnon()) {
             $page = SpecialPage::getTitleFor('Gather')->getSubPage('by')->getSubPage($user->getName());
         } else {
             $page = SpecialPage::getTitleFor('Gather')->getSubPage('all')->getSubPage('recent');
         }
         $out->redirect($page->getLocalUrl());
     } elseif ($subpage === 'by' || $subpage === 'by/') {
         // User owned collections.
         // For listing own lists, you need to be logged in
         $this->requireLogin('gather-anon-view-lists');
         $user = $this->getUser();
         $url = SpecialPage::getTitleFor('Gather')->getSubPage('by')->getSubPage($user->getName())->getLocalUrl();
         $out->redirect($url);
     } elseif (preg_match('/^explore\\/(?<key>.*)$/', $subpage, $matches)) {
         // Special explorable collections
         // /explore/:type & /explore/
         $key = $matches['key'];
         if ($key) {
             // /explore/:type -> Show the collection of type :type
             if (isset($this->specialCollections[$key])) {
                 $args = $this->specialCollections[$key];
                 $c = new models\Collection(0, null, $args['title'], $args['description']);
                 $c = models\Collection::newFromApi($c, $args['params'], $args['limit'], isset($args['continue']) ? $args['continue'] : array());
                 $c->setUrl(SpecialPage::getTitleFor('Gather')->getSubpage('explore')->getSubpage($key)->getLocalUrl());
                 $this->renderCollection($c);
             } else {
                 $this->renderError(new views\NotFound());
             }
         } else {
             // /explore/ -> List all explorable collections
             $collectionList = new models\CollectionsList();
             foreach ($this->specialCollections as $key => $definition) {
                 $ci = new models\CollectionInfo(null, null, $definition['title'], $definition['description']);
                 $ci->setCount('∞');
                 $ci->setUrl(SpecialPage::getTitleFor('Gather')->getSubpage('explore')->getSubpage($key)->getLocalUrl());
                 $collectionList->add($ci);
             }
             $this->renderCollectionsList($collectionList);
         }
     } elseif (preg_match('/^by\\/(?<user>[^\\/]+)\\/?$/', $subpage, $matches)) {
         // User's collections
         // /by/:user = /by/:user/
         $user = User::newFromName($matches['user']);
         if (!($user && $user->getId())) {
             // Invalid user
             $this->renderError(new views\NotFound());
         } else {
             $this->renderUserCollectionsList($user);
         }
     } elseif (preg_match('/^id\\/(?<id>\\d+)(\\/.*$|$)/', $subpage, $matches)) {
         // Collection page
         // /id/:id
         $id = (int) $matches['id'];
         $this->renderUserCollection($id);
     } elseif (preg_match('/^by\\/(?<user>[^\\/]+)\\/(?<id>\\d+)$/', $subpage, $matches)) {
         // Collection page
         // /by/:user/:id -- Deprecated -- Redirects to /id/:id
         $id = (int) $matches['id'];
         $this->getOutput()->redirect(SpecialPage::getTitleFor('Gather')->getSubPage('id')->getSubPage($id)->getLocalURL());
     } elseif (preg_match('/^all(\\/(?<cond>[^\\/]+))?\\/?$/', $subpage, $matches)) {
         // All collections. Public or hidden or pending review
         // /all = /all/ = /all/public = /all/public/
         // /all/hidden = /all/hidden/
         // /all/recent = /all/recent/
         // /all/review = /all/review/
         $apiParams = array();
         $displayAsTable = true;
         // Mode defaults to public
         $allowedModes = array('public', 'hidden', 'recent', 'review');
         if (!isset($matches['cond'])) {
             $mode = 'public';
         } elseif (in_array($matches['cond'], $allowedModes)) {
             $mode = $matches['cond'];
         } else {
             $mode = 'error';
         }
         $originalMode = $mode;
         if ($mode === 'recent') {
             // Fancy list of collections with a certain amount of items.
             $displayAsTable = false;
             $apiParams = array('lstminitems' => 4);
             // Active is a concrete view of public with different params.
             $mode = 'public';
         } elseif ($mode === 'hidden' || $mode === 'review') {
             // Table list of hidden collections.
             // If user doesn't have permissions, bail out.
             if (!$this->canHideLists()) {
                 $view = new views\NotFound();
                 $this->renderError($view);
                 return;
             }
             $out->addSubtitle($this->getSubTitle());
         } elseif ($mode === 'public') {
             // Table list of public collections.
             // If the user has permissions to hide add a link to the /all/hidden
             // view for switching there.
             if ($this->canHideLists()) {
                 $out->addSubtitle($this->getSubTitle(true));
             }
         } else {
             $this->renderError(new views\NotFound());
             return;
         }
         $req = $this->getRequest();
         $apiParams = array_merge($apiParams, $req->getValues());
         $cList = models\CollectionsList::newFromApi(null, $mode, false, $apiParams, $mode, 100);
         $cList->setMode($originalMode);
         if ($displayAsTable) {
             $this->renderRows($cList, $mode === 'hidden' ? 'show' : 'hide');
         } else {
             $this->renderTabs(0);
             $this->renderCollectionsList($cList);
         }
     } else {
         // Unknown subpage
         $this->renderError(new views\NotFound());
     }
 }