Receive nonjs comment parameters

@param moodle_page $page The page object to initialise comments within
If not provided the global $PAGE is used
761959
public static function init(moodle_page $page = null) {
        global $PAGE;

        if (empty($page)) {
            $page = $PAGE;
        }
        // setup variables for non-js interface
        self::$nonjs = optional_param('nonjscomment', '', PARAM_ALPHANUM);
        self::$comment_itemid = optional_param('comment_itemid',  '', PARAM_INT);
        self::$comment_component = optional_param('comment_component', '', PARAM_COMPONENT);
        self::$comment_context = optional_param('comment_context', '', PARAM_INT);
        self::$comment_page = optional_param('comment_page',    '', PARAM_INT);
        self::$comment_area = optional_param('comment_area',    '', PARAM_AREA);

        $page->requires->strings_for_js(array(
                'addcomment',
                'comments',
                'commentscount',
                'commentsrequirelogin',
                'deletecommentbyon'
            ),
            'moodle'
        );
    }
943424
private function doPersistIfValid(Page $page)
    {
        if (null === $page->getParent() && !empty($this->persist)) {
            // If root, only persist
            $this->em->persist($page);
            return;
        }

        $method = '';
        if (self::PERSIST_AS_FIRST_CHILD === $this->persist) {
            $method = 'insertNodeAsFirstChildOf';
        } elseif (self::PERSIST_AS_LAST_CHILD === $this->persist) {
            $method = 'insertNodeAsLastChildOf';
        }

        if (!empty($method)) {
            $this->em->getRepository('BackBee\NestedNode\Page')->$method($page, $page->getParent(), $this->isSection);
            $this->em->persist($page);
        }
    }
322050
private function updatePageMenuPosition(Page $page)
    {
        $pageMenuRepository = $this->doctrine->getRepository('FulgurioLightCMSBundle:PageMenu');
        $em = $this->doctrine->getManager();
        $data = $this->request->get('page');
        if (isset($data['availableMenu']))
        {
            if (!is_null($page->getId()))
            {
                $menus = $page->getMenu();
                $alreadyInMenu = array();
                foreach ($menus as $menu)
                {
                    if (!in_array($menu->getLabel(), $data['availableMenu']))
                    {
                        $pageMenuRepository->upMenuPagesPosition($menu->getLabel(), $menu->getPosition() + 1);
                        $em->remove($menu);
                    }
                    else
                    {
                        $alreadyInMenu[] = $menu->getLabel();
                    }
                }
            }
            foreach ($data['availableMenu'] as $menuLabel)
            {
                // If it s a new page, or if it a page which we had a new menu
                if (!isset($alreadyInMenu) || !in_array($menuLabel, $alreadyInMenu))
                {
                    $menu = new PageMenu();
                    $menu->setPosition($pageMenuRepository->getNextMenuPosition($menuLabel));
                    $menu->setLabel($menuLabel);
                    $menu->setPage($page);
                    $em->persist($menu);
                }
            }
        }
        else if (!is_null($page->getId()))
        {
            $menus = $page->getMenu();
            foreach ($menus as $menu)
            {
                $pageMenuRepository->upMenuPagesPosition($menu->getLabel(), $menu->getPosition() + 1);
                $em->remove($menu);
            }
        }
    }
1072811
public function index($page = null)
    {
        $url = sprintf('buckets/%d/questions/%d/answers.json', $this->bucket, $this->parent);

        $answers = $this->client->get($url, [
            'query' => [
                'page' => $page,
            ],
        ]);

        return $this->indexResponse($answers, QuestionAnswer::class);
    }
628926
public function index($page = null)
    {
        $url = sprintf('buckets/%d/questionnaires/%d/questions.json', $this->bucket, $this->parent);

        $questions = $this->client->get($url, [
            'query' => [
                'page' => $page,
            ],
        ]);

        return $this->indexResponse($questions, Question::class);
    }
1009231
public function print_comments($page = 0) {
        global $OUTPUT, $CFG, $OUTPUT, $DB;

        $count = $DB->count_records('comments');
        $comments = $this->get_comments($page);
        if (count($comments) == 0) {
            echo $OUTPUT->notification(get_string('nocomments', 'moodle'));
            return false;
        }

        $table = new html_table();
        $table->head = array (
            html_writer::checkbox('selectall', '', false, get_string('selectall'), array('id' => 'comment_select_all',
                'class' => 'mr-1')),
            get_string('author', 'search'),
            get_string('content'),
            get_string('action')
        );
        $table->colclasses = array ('leftalign', 'leftalign', 'leftalign', 'leftalign');
        $table->attributes = array('class'=>'admintable generaltable');
        $table->id = 'commentstable';
        $table->data = array();

        $link = new moodle_url('/comment/index.php', array('action' => 'delete', 'sesskey' => sesskey()));
        foreach ($comments as $c) {
            $userdata = html_writer::link(new moodle_url('/user/profile.php', ['id' => $c->userid]), $c->fullname);
            $this->setup_plugin($c);
            if (!empty($this->plugintype)) {
                $context_url = plugin_callback($this->plugintype, $this->pluginname, 'comment', 'url', array($c));
            }
            $checkbox = html_writer::checkbox('comments', $c->id, false);
            $action = html_writer::link(new moodle_url($link, array('commentid' => $c->id)), get_string('delete'));
            if (!empty($context_url)) {
                $action .= html_writer::empty_tag('br');
                $action .= html_writer::link($context_url, get_string('commentincontext'), array('target'=>'_blank'));
            }
            $table->data[] = array($checkbox, $userdata, $c->content, $action);
        }
        echo html_writer::table($table);
        echo $OUTPUT->paging_bar($count, $page, $this->perpage, $CFG->wwwroot.'/comment/index.php');
        return true;
    }
228778
public function resetChildrenUri(Page $page)
    {
        foreach ($page->subpages as $subpage) {
            $uris = $subpage->getTranslations('uri');
            foreach ($uris as $locale => $uri) {
                $subpage->forgetTranslation('uri', $locale);
            }
            $subpage->save();
            $this->resetChildrenUri($subpage);
        }
    }
132172
public function postAdd(Page $page)
    {
        $this->authorize('add', $page);

        $parent = $page->getAddPageParent();
        $newPage = $this->dispatch(new CreatePage($parent));

        return PageFacade::find($newPage->getId());
    }
820712
public static function view_page($pageid) {

        $params = self::validate_parameters(self::view_page_parameters(),
                                            array(
                                                'pageid' => $pageid
                                            ));
        $warnings = array();

        // Get wiki page.
        if (!$page = wiki_get_page($params['pageid'])) {
            throw new moodle_exception('incorrectpageid', 'wiki');
        }

        // Get wiki instance.
        if (!$wiki = wiki_get_wiki_from_pageid($params['pageid'])) {
            throw new moodle_exception('incorrectwikiid', 'wiki');
        }

        // Permission validation.
        list($course, $cm) = get_course_and_cm_from_instance($wiki, 'wiki');
        $context = context_module::instance($cm->id);
        self::validate_context($context);

        // Check if user can view this wiki.
        if (!$subwiki = wiki_get_subwiki($page->subwikiid)) {
            throw new moodle_exception('incorrectsubwikiid', 'wiki');
        }
        if (!wiki_user_can_view($subwiki, $wiki)) {
            throw new moodle_exception('cannotviewpage', 'wiki');
        }

        // Trigger page_viewed event and completion.
        wiki_page_view($wiki, $page, $course, $cm, $context);

        $result = array();
        $result['status'] = true;
        $result['warnings'] = $warnings;
        return $result;
    }
1133848
public function render_preview(moodle_page $page) {

        if (!$this->is_form_defined()) {
            throw new coding_exception('It is the caller\'s responsibility to make sure that the form is actually defined');
        }

        // Check if current user is able to see preview
        $options = $this->get_options();
        if (empty($options['alwaysshowdefinition']) && !has_capability('moodle/grade:managegradingforms', $page->context))  {
            return '';
        }

        $criteria = $this->definition->guide_criteria;
        $comments = $this->definition->guide_comments;
        $output = $this->get_renderer($page);

        $guide = '';
        $guide .= $output->box($this->get_formatted_description(), 'gradingform_guide-description');
        if (has_capability('moodle/grade:managegradingforms', $page->context)) {
            $guide .= $output->display_guide_mapping_explained($this->get_min_max_score());
            $guide .= $output->display_guide($criteria, $comments, $options, self::DISPLAY_PREVIEW, 'guide');
        } else {
            $guide .= $output->display_guide($criteria, $comments, $options, self::DISPLAY_PREVIEW_GRADED, 'guide');
        }

        return $guide;
    }
1238799
public function initialise_js(moodle_page $page) {
        foreach ($this->jsyuimodules as $js) {
            $page->requires->yui_module($js->modules, $js->function, $js->arguments, null, $js->ondomready);
        }
        foreach ($this->jsinitcalls as $js) {
            $page->requires->js_init_call($js->function, $js->extraarguments, $js->ondomready, $js->module);
        }
        foreach ($this->jsstrings as $string) {
            $page->requires->strings_for_js($string->identifiers, $string->component, $string->a);
        }
    }
1139436
public function render_langimport_page(langimport_page $page) {
        $data = $page->export_for_template($this);
        return parent::render_from_template('tool_langimport/langimport', $data);
    }
528666
public function Index($DiscussionID = '', $DiscussionStub = '', $Page = '') {
      // Setup head
      $Session = Gdn::Session();
      $this->AddJsFile('jquery.autogrow.js');
      $this->AddJsFile('discussion.js');
      $this->AddJsFile('autosave.js');
      Gdn_Theme::Section('Discussion');
      
      // Load the discussion record
      $DiscussionID = (is_numeric($DiscussionID) && $DiscussionID > 0) ? $DiscussionID : 0;
      if (!array_key_exists('Discussion', $this->Data))
         $this->SetData('Discussion', $this->DiscussionModel->GetID($DiscussionID), TRUE);
         
      if(!is_object($this->Discussion)) {
         throw new Exception(sprintf(T('%s Not Found'), T('Discussion')), 404);
      }
      
      // Define the query offset & limit.
      $Limit = C('Vanilla.Comments.PerPage', 30);

      $OffsetProvided = $Page != '';
      list($Offset, $Limit) = OffsetLimit($Page, $Limit);
      
      // Check permissions
      $this->Permission('Vanilla.Discussions.View', TRUE, 'Category', $this->Discussion->PermissionCategoryID);
      $this->SetData('CategoryID', $this->CategoryID = $this->Discussion->CategoryID, TRUE);
      
      if (strcasecmp(GetValue('Type', $this->Discussion), 'redirect') === 0) {
         $this->RedirectDiscussion($this->Discussion);
      }
      
      $Category = CategoryModel::Categories($this->Discussion->CategoryID);
      $this->SetData('Category', $Category);
      
      if ($CategoryCssClass = GetValue('CssClass', $Category))
         Gdn_Theme::Section($CategoryCssClass);
      
      $this->SetData('Breadcrumbs', CategoryModel::GetAncestors($this->CategoryID));
      
      // Setup
      $this->Title($this->Discussion->Name);

      // Actual number of comments, excluding the discussion itself.
      $ActualResponses = $this->Discussion->CountComments;

      $this->Offset = $Offset;
      if (C('Vanilla.Comments.AutoOffset')) {
//         if ($this->Discussion->CountCommentWatch > 1 && $OffsetProvided == '')
//            $this->AddDefinition('ScrollTo', 'a[name=Item_'.$this->Discussion->CountCommentWatch.']');
         if (!is_numeric($this->Offset) || $this->Offset < 0 || !$OffsetProvided) {
            // Round down to the appropriate offset based on the user's read comments & comments per page
            $CountCommentWatch = $this->Discussion->CountCommentWatch > 0 ? $this->Discussion->CountCommentWatch : 0;
            if ($CountCommentWatch > $ActualResponses)
               $CountCommentWatch = $ActualResponses;

            // (((67 comments / 10 perpage) = 6.7) rounded down = 6) * 10 perpage = offset 60;
            $this->Offset = floor($CountCommentWatch / $Limit) * $Limit;
         }
         if ($ActualResponses <= $Limit)
            $this->Offset = 0;

         if ($this->Offset == $ActualResponses)
            $this->Offset -= $Limit;
      } else {
         if ($this->Offset == '')
            $this->Offset = 0;
      }

      if ($this->Offset < 0)
         $this->Offset = 0;
      
      
      $LatestItem = $this->Discussion->CountCommentWatch;
      if ($LatestItem === NULL) {
         $LatestItem = 0;
      } elseif ($LatestItem < $this->Discussion->CountComments) {
         $LatestItem += 1;
      }
      
      $this->SetData('_LatestItem', $LatestItem);
      
      // Set the canonical url to have the proper page title.
      $this->CanonicalUrl(DiscussionUrl($this->Discussion, PageNumber($this->Offset, $Limit, 0, FALSE)));
      
//      Url(ConcatSep('/', 'discussion/'.$this->Discussion->DiscussionID.'/'. Gdn_Format::Url($this->Discussion->Name), PageNumber($this->Offset, $Limit, TRUE, Gdn::Session()->UserID != 0)), TRUE), Gdn::Session()->UserID == 0);
      
      // Load the comments
      $this->SetData('Comments', $this->CommentModel->Get($DiscussionID, $Limit, $this->Offset));
      
      $PageNumber = PageNumber($this->Offset, $Limit);
      $this->SetData('Page', $PageNumber);
      $this->_SetOpenGraph();
      
      
      include_once(PATH_LIBRARY.'/vendors/simplehtmldom/simple_html_dom.php');
      if ($PageNumber == 1) {
         $this->Description(SliceParagraph(Gdn_Format::PlainText($this->Discussion->Body, $this->Discussion->Format), 160));
         // Add images to head for open graph
         $Dom = str_get_html(Gdn_Format::To($this->Discussion->Body, $this->Discussion->Format));
      } else {
         $this->Data['Title'] .= sprintf(T(' - Page %s'), PageNumber($this->Offset, $Limit));
         
         $FirstComment = $this->Data('Comments')->FirstRow();
         $FirstBody = GetValue('Body', $FirstComment);
         $FirstFormat = GetValue('Format', $FirstComment);
         $this->Description(SliceParagraph(Gdn_Format::PlainText($FirstBody, $FirstFormat), 160));
         // Add images to head for open graph
         $Dom = str_get_html(Gdn_Format::To($FirstBody, $FirstFormat));
      }

      if ($Dom) {
         foreach($Dom->find('img') as $img) {
            if (isset($img->src))
               $this->Image($img->src);
         }
      }
      
      // Queue notification.
      if ($this->Request->Get('new') && C('Vanilla.QueueNotifications')) {
         $this->AddDefinition('NotifyNewDiscussion', 1);
      }
         
      // Make sure to set the user's discussion watch records
      $this->CommentModel->SetWatch($this->Discussion, $Limit, $this->Offset, $this->Discussion->CountComments);

      // Build a pager
      $PagerFactory = new Gdn_PagerFactory();
		$this->EventArguments['PagerType'] = 'Pager';
		$this->FireEvent('BeforeBuildPager');
      $this->Pager = $PagerFactory->GetPager($this->EventArguments['PagerType'], $this);
      $this->Pager->ClientID = 'Pager';
         
      $this->Pager->Configure(
         $this->Offset,
         $Limit,
         $ActualResponses,
         array('DiscussionUrl')
      );
      $this->Pager->Record = $this->Discussion;
      PagerModule::Current($this->Pager);
      $this->FireEvent('AfterBuildPager');
      
      // Define the form for the comment input
      $this->Form = Gdn::Factory('Form', 'Comment');
      $this->Form->Action = Url('/vanilla/post/comment/');
      $this->DiscussionID = $this->Discussion->DiscussionID;
      $this->Form->AddHidden('DiscussionID', $this->DiscussionID);
      $this->Form->AddHidden('CommentID', '');

      // Look in the session stash for a comment
      $StashComment = $Session->Stash('CommentForDiscussionID_'.$this->Discussion->DiscussionID, '', FALSE);
      if ($StashComment)
         $this->Form->SetFormValue('Body', $StashComment);
         
      // Retrieve & apply the draft if there is one:
      if (Gdn::Session()->UserID) {
         $DraftModel = new DraftModel();
         $Draft = $DraftModel->Get($Session->UserID, 0, 1, $this->Discussion->DiscussionID)->FirstRow();
         $this->Form->AddHidden('DraftID', $Draft ? $Draft->DraftID : '');
         if ($Draft && !$this->Form->IsPostBack()) {
            $this->Form->SetValue('Body', $Draft->Body);
            $this->Form->SetValue('Format', $Draft->Format);
         }
      }
      
      // Deliver JSON data if necessary
      if ($this->_DeliveryType != DELIVERY_TYPE_ALL) {
         $this->SetJson('LessRow', $this->Pager->ToString('less'));
         $this->SetJson('MoreRow', $this->Pager->ToString('more'));
         $this->View = 'comments';
      }
      
		// Inform moderator of checked comments in this discussion
		$CheckedComments = $Session->GetAttribute('CheckedComments', array());
		if (count($CheckedComments) > 0)
			ModerationController::InformCheckedComments($this);

      // Add modules
      $this->AddModule('DiscussionFilterModule');
      $this->AddModule('NewDiscussionModule');
      $this->AddModule('CategoriesModule');
      $this->AddModule('BookmarkedModule');
      
		$this->CanEditComments = Gdn::Session()->CheckPermission('Vanilla.Comments.Edit', TRUE, 'Category', 'any') && C('Vanilla.AdminCheckboxes.Use');

      // Report the discussion id so js can use it.      
      $this->AddDefinition('DiscussionID', $DiscussionID);
      
      $this->FireEvent('BeforeDiscussionRender');
      $this->Render();
   }
1348525
public function handleRequest(Request $request, Page &$page)
    {
        $page->setData([
            "link" => $request->request->get("vfou_cmsbundle_page")["link"],
            "code" => $request->request->get("vfou_cmsbundle_page")["code"]
        ]);
    }
1199030
protected function grabArticle(\DOMElement $page = null)
    {
        if (!$page) {
            $page = $this->dom;
        }

        $xpath = null;
        $nodesToScore = [];

        if ($page instanceof \DOMDocument && isset($page->documentElement)) {
            $xpath = new \DOMXPath($page);
        }

        $allElements = $page->getElementsByTagName('*');

        for ($nodeIndex = 0; ($node = $allElements->item($nodeIndex)); ++$nodeIndex) {
            $tagName = $node->tagName;

            // Some well known site uses sections as paragraphs.
            if (0 === strcasecmp($tagName, 'p') || 0 === strcasecmp($tagName, 'td') || 0 === strcasecmp($tagName, 'pre') || 0 === strcasecmp($tagName, 'section')) {
                $nodesToScore[] = $node;
            }

            // Turn divs into P tags where they have been used inappropriately
            //  (as in, where they contain no other block level elements).
            if (0 === strcasecmp($tagName, 'div') || 0 === strcasecmp($tagName, 'article') || 0 === strcasecmp($tagName, 'section')) {
                if (!preg_match($this->regexps['divToPElements'], $node->getInnerHTML())) {
                    $newNode = $this->dom->createElement('p');

                    try {
                        $newNode->setInnerHtml($node->getInnerHTML());

                        $node->parentNode->replaceChild($newNode, $node);
                        --$nodeIndex;
                        $nodesToScore[] = $newNode;
                    } catch (\Exception $e) {
                        $this->logger->error('Could not alter div/article to p, reverting back to div: ' . $e->getMessage());
                    }
                } else {
                    // Will change these P elements back to text nodes after processing.
                    for ($i = 0, $il = $node->childNodes->length; $i < $il; ++$i) {
                        $childNode = $node->childNodes->item($i);

                        // it looks like sometimes the loop is going too far and we are retrieving a non-existant child
                        if (null === $childNode) {
                            continue;
                        }

                        // executable tags (<?php or <?xml) warning
                        if (\is_object($childNode) && 'DOMProcessingInstruction' === \get_class($childNode)) {
                            $childNode->parentNode->removeChild($childNode);

                            continue;
                        }

                        if (XML_TEXT_NODE === $childNode->nodeType) {
                            $p = $this->dom->createElement('p');
                            $p->setInnerHtml($childNode->nodeValue);
                            $p->setAttribute('data-readability-styled', 'true');
                            $childNode->parentNode->replaceChild($p, $childNode);
                        }
                    }
                }
            }
        }

        /*
         * Loop through all paragraphs, and assign a score to them based on how content-y they look.
         * Then add their score to their parent node.
         *
         * A score is determined by things like number of commas, class names, etc.
         * Maybe eventually link density.
         */
        for ($pt = 0, $scored = \count($nodesToScore); $pt < $scored; ++$pt) {
            $parentNode = $nodesToScore[$pt]->parentNode;

            // No parent node? Move on...
            if (!$parentNode) {
                continue;
            }

            $grandParentNode = $parentNode->parentNode instanceof \DOMElement ? $parentNode->parentNode : null;
            $innerText = $this->getInnerText($nodesToScore[$pt]);

            // If this paragraph is less than MIN_PARAGRAPH_LENGTH (default:20) characters, don't even count it.
            if (mb_strlen($innerText) < self::MIN_PARAGRAPH_LENGTH) {
                continue;
            }

            // Initialize readability data for the parent.
            if (!$parentNode->hasAttribute('readability')) {
                $this->initializeNode($parentNode);
                $parentNode->setAttribute('data-candidate', 'true');
            }

            // Initialize readability data for the grandparent.
            if ($grandParentNode && !$grandParentNode->hasAttribute('readability') && isset($grandParentNode->tagName)) {
                $this->initializeNode($grandParentNode);
                $grandParentNode->setAttribute('data-candidate', 'true');
            }
            // Add a point for the paragraph itself as a base.
            $contentScore = 1;
            // Add points for any commas within this paragraph.
            $contentScore += $this->getCommaCount($innerText);
            // For every SCORE_CHARS_IN_PARAGRAPH (default:100) characters in this paragraph, add another point. Up to 3 points.
            $contentScore += min(floor(mb_strlen($innerText) / self::SCORE_CHARS_IN_PARAGRAPH), 3);
            // For every SCORE_WORDS_IN_PARAGRAPH (default:20) words in this paragraph, add another point. Up to 3 points.
            $contentScore += min(floor($this->getWordCount($innerText) / self::SCORE_WORDS_IN_PARAGRAPH), 3);
            /* TEST: For every positive/negative parent tag, add/substract half point. Up to 3 points. *\/
            $up = $nodesToScore[$pt];
            $score = 0;
            while ($up->parentNode instanceof \DOMElement) {
                $up = $up->parentNode;
                if (preg_match($this->regexps['positive'], $up->getAttribute('class') . ' ' . $up->getAttribute('id'))) {
                    $score += 0.5;
                } elseif (preg_match($this->regexps['negative'], $up->getAttribute('class') . ' ' . $up->getAttribute('id'))) {
                    $score -= 0.5;
                }
            }
            $score = floor($score);
            $contentScore += max(min($score, 3), -3);/**/

            // Add the score to the parent. The grandparent gets half.
            $parentNode->getAttributeNode('readability')->value += $contentScore;
            if ($grandParentNode) {
                $grandParentNode->getAttributeNode('readability')->value += $contentScore / self::GRANDPARENT_SCORE_DIVISOR;
            }
        }

        /*
         * Node prepping: trash nodes that look cruddy (like ones with the class name "comment", etc).
         * This is faster to do before scoring but safer after.
         */
        if ($this->flagIsActive(self::FLAG_STRIP_UNLIKELYS) && $xpath) {
            $candidates = $xpath->query('.//*[(self::footer and count(//footer)<2) or (self::aside and count(//aside)<2)]', $page->documentElement);
            $node = null;

            for ($c = $candidates->length - 1; $c >= 0; --$c) {
                $node = $candidates->item($c);
                // node should be readable but not inside of an article otherwise it's probably non-readable block
                if ($node->hasAttribute('readability') && (int) $node->getAttributeNode('readability')->value < 40 && ($node->parentNode ? 0 !== strcasecmp($node->parentNode->tagName, 'article') : true)) {
                    $this->logger->debug('Removing unlikely candidate (using note) ' . $node->getNodePath() . ' by "' . $node->tagName . '" with readability ' . ($node->hasAttribute('readability') ? (int) $node->getAttributeNode('readability')->value : 0));
                    $node->parentNode->removeChild($node);
                }
            }

            $candidates = $xpath->query('.//*[not(self::body) and (@class or @id or @style) and ((number(@readability) < 40) or not(@readability))]', $page->documentElement);
            $node = null;

            for ($c = $candidates->length - 1; $c >= 0; --$c) {
                $node = $candidates->item($c);

                // Remove unlikely candidates
                $unlikelyMatchString = $node->getAttribute('class') . ' ' . $node->getAttribute('id') . ' ' . $node->getAttribute('style');

                if (mb_strlen($unlikelyMatchString) > 3 && // don't process "empty" strings
                    preg_match($this->regexps['unlikelyCandidates'], $unlikelyMatchString) &&
                    !preg_match($this->regexps['okMaybeItsACandidate'], $unlikelyMatchString)
                ) {
                    $this->logger->debug('Removing unlikely candidate (using conf) ' . $node->getNodePath() . ' by "' . $unlikelyMatchString . '" with readability ' . ($node->hasAttribute('readability') ? (int) $node->getAttributeNode('readability')->value : 0));
                    $node->parentNode->removeChild($node);
                    --$nodeIndex;
                }
            }
            unset($candidates);
        }

        /*
         * After we've calculated scores, loop through all of the possible candidate nodes we found
         * and find the one with the highest score.
         */
        $topCandidate = null;
        if ($xpath) {
            // Using array of DOMElements after deletion is a path to DOOMElement.
            $candidates = $xpath->query('.//*[@data-candidate]', $page->documentElement);

            for ($c = $candidates->length - 1; $c >= 0; --$c) {
                $item = $candidates->item($c);

                // Scale the final candidates score based on link density. Good content should have a
                // relatively small link density (5% or less) and be mostly unaffected by this operation.
                // If not for this we would have used XPath to find maximum @readability.
                $readability = $item->getAttributeNode('readability');
                $readability->value = round($readability->value * (1 - $this->getLinkDensity($item)), 0, PHP_ROUND_HALF_UP);

                if (!$topCandidate || $readability->value > (int) $topCandidate->getAttribute('readability')) {
                    $this->logger->debug('Candidate: ' . $item->getNodePath() . ' (' . $item->getAttribute('class') . ':' . $item->getAttribute('id') . ') with score ' . $readability->value);
                    $topCandidate = $item;
                }
            }

            unset($candidates);
        }

        /*
         * If we still have no top candidate, just use the body as a last resort.
         * We also have to copy the body node so it is something we can modify.
         */
        if (null === $topCandidate || 0 === strcasecmp($topCandidate->tagName, 'body')) {
            $topCandidate = $this->dom->createElement('div');

            if ($page instanceof \DOMDocument) {
                if (!isset($page->documentElement)) {
                    // we don't have a body either? what a mess! :)
                    $this->logger->debug('The page has no body!');
                } else {
                    $this->logger->debug('Setting body to a raw HTML of original page!');
                    $topCandidate->setInnerHtml($page->documentElement->getInnerHTML());
                    $page->documentElement->setInnerHtml('');
                    $this->reinitBody();
                    $page->documentElement->appendChild($topCandidate);
                }
            } else {
                $topCandidate->setInnerHtml($page->getInnerHTML());
                $page->setInnerHtml('');
                $page->appendChild($topCandidate);
            }

            $this->initializeNode($topCandidate);
        }

        // Set table as the main node if resulted data is table element.
        $tagName = $topCandidate->tagName;
        if (0 === strcasecmp($tagName, 'td') || 0 === strcasecmp($tagName, 'tr')) {
            $up = $topCandidate;

            if ($up->parentNode instanceof \DOMElement) {
                $up = $up->parentNode;

                if (0 === strcasecmp($up->tagName, 'table')) {
                    $topCandidate = $up;
                }
            }
        }

        $this->logger->debug('Top candidate: ' . $topCandidate->getNodePath());

        /*
         * Now that we have the top candidate, look through its siblings for content that might also be related.
         * Things like preambles, content split by ads that we removed, etc.
         */
        $articleContent = $this->dom->createElement('div');
        $articleContent->setAttribute('class', 'readability-content');
        $siblingScoreThreshold = max(10, ((int) $topCandidate->getAttribute('readability')) * 0.2);
        $siblingNodes = $topCandidate->parentNode->childNodes;

        if (null === $siblingNodes) {
            $siblingNodes = new \stdClass();
            $siblingNodes->length = 0;
        }

        for ($s = 0, $sl = $siblingNodes->length; $s < $sl; ++$s) {
            $siblingNode = $siblingNodes->item($s);
            $siblingNodeName = $siblingNode->nodeName;
            $append = false;
            $this->logger->debug('Looking at sibling node: ' . $siblingNode->getNodePath() . ((XML_ELEMENT_NODE === $siblingNode->nodeType && $siblingNode->hasAttribute('readability')) ? (' with score ' . $siblingNode->getAttribute('readability')) : ''));

            if ($siblingNode->isSameNode($topCandidate)) {
                $append = true;
            }

            $contentBonus = 0;

            // Give a bonus if sibling nodes and top candidates have the same classname.
            if (XML_ELEMENT_NODE === $siblingNode->nodeType && $siblingNode->getAttribute('class') === $topCandidate->getAttribute('class') && '' !== $topCandidate->getAttribute('class')) {
                $contentBonus += ((int) $topCandidate->getAttribute('readability')) * 0.2;
            }

            if (XML_ELEMENT_NODE === $siblingNode->nodeType && $siblingNode->hasAttribute('readability') && (((int) $siblingNode->getAttribute('readability')) + $contentBonus) >= $siblingScoreThreshold) {
                $append = true;
            }

            if (0 === strcasecmp($siblingNodeName, 'p')) {
                $linkDensity = $this->getLinkDensity($siblingNode);
                $nodeContent = $this->getInnerText($siblingNode, true, true);
                $nodeLength = mb_strlen($nodeContent);

                if (($nodeLength > self::MIN_NODE_LENGTH && $linkDensity < self::MAX_LINK_DENSITY)
                    || ($nodeLength < self::MIN_NODE_LENGTH && 0 === $linkDensity && preg_match('/\.( |$)/', $nodeContent))) {
                    $append = true;
                }
            }

            if ($append) {
                $this->logger->debug('Appending node: ' . $siblingNode->getNodePath());

                if (0 !== strcasecmp($siblingNodeName, 'div') && 0 !== strcasecmp($siblingNodeName, 'p')) {
                    // We have a node that isn't a common block level element, like a form or td tag. Turn it into a div so it doesn't get filtered out later by accident.
                    $this->logger->debug('Altering siblingNode "' . $siblingNodeName . '" to "div".');
                    $nodeToAppend = $this->dom->createElement('div');

                    try {
                        $nodeToAppend->setAttribute('alt', $siblingNodeName);
                        $nodeToAppend->setInnerHtml($siblingNode->getInnerHTML());
                    } catch (\Exception $e) {
                        $this->logger->debug('Could not alter siblingNode "' . $siblingNodeName . '" to "div", reverting to original.');
                        $nodeToAppend = $siblingNode;
                        --$s;
                        --$sl;
                    }
                } else {
                    $nodeToAppend = $siblingNode;
                    --$s;
                    --$sl;
                }

                // To ensure a node does not interfere with readability styles, remove its classnames & ids.
                // Now done via RegExp post_filter.
                //$nodeToAppend->removeAttribute('class');
                //$nodeToAppend->removeAttribute('id');
                // Append sibling and subtract from our list as appending removes a node.
                $articleContent->appendChild($nodeToAppend);
            }
        }

        unset($xpath);

        // So we have all of the content that we need. Now we clean it up for presentation.
        $this->prepArticle($articleContent);

        /*
         * Now that we've gone through the full algorithm, check to see if we got any meaningful content.
         * If we didn't, we may need to re-run grabArticle with different flags set. This gives us a higher
         * likelihood of finding the content, and the sieve approach gives us a higher likelihood of
         * finding the -right- content.
         */
        if (mb_strlen($this->getInnerText($articleContent, false)) < self::MIN_ARTICLE_LENGTH) {
            $this->reinitBody();

            if ($this->flagIsActive(self::FLAG_STRIP_UNLIKELYS)) {
                $this->removeFlag(self::FLAG_STRIP_UNLIKELYS);
                $this->logger->debug('...content is shorter than ' . self::MIN_ARTICLE_LENGTH . " letters, trying not to strip unlikely content.\n");

                return $this->grabArticle($this->body);
            } elseif ($this->flagIsActive(self::FLAG_WEIGHT_ATTRIBUTES)) {
                $this->removeFlag(self::FLAG_WEIGHT_ATTRIBUTES);
                $this->logger->debug('...content is shorter than ' . self::MIN_ARTICLE_LENGTH . " letters, trying not to weight attributes.\n");

                return $this->grabArticle($this->body);
            } elseif ($this->flagIsActive(self::FLAG_CLEAN_CONDITIONALLY)) {
                $this->removeFlag(self::FLAG_CLEAN_CONDITIONALLY);
                $this->logger->debug('...content is shorter than ' . self::MIN_ARTICLE_LENGTH . " letters, trying not to clean at all.\n");

                return $this->grabArticle($this->body);
            }

            return false;
        }

        return $articleContent;
    }
1143363
public function setPage(Page $page)
    {
        $this->page = $page;
        $revision = $page->getCurrentRevision();
        if (empty($revision)) {
            $revision = $page->getPublishedRevision();
        }
        $revisionId = null;
        if (!empty($revision)) {
            $revisionId = $revision->getRevisionId();
        }
        $this->setRevisionId($revisionId);
        $this->setTitle($page->getPageTitle());
        $this->setPageId($page->getPageId());
    }
211753
public function index($page = null)
    {
        $url = sprintf('buckets/%d/recordings/%d/comments.json', $this->bucket, $this->parent);

        $comments = $this->client->get($url, [
            'query' => [
                'page' => $page,
            ],
        ]);

        return $this->indexResponse($comments, Comment::class);
    }