public function restore($corpus)
 {
     if ($this->map) {
         $corpus = phutil_safe_html(str_replace(array_reverse(array_keys($this->map)), array_map('phutil_escape_html', array_reverse($this->map)), phutil_escape_html($corpus)));
     }
     return $corpus;
 }
 protected function renderInput()
 {
     self::requireLib();
     $uri = new PhutilURI(PhabricatorEnv::getEnvConfig('phabricator.base-uri'));
     $protocol = $uri->getProtocol();
     $use_ssl = $protocol == 'https';
     return phutil_safe_html(recaptcha_get_html(PhabricatorEnv::getEnvConfig('recaptcha.public-key'), $error = null, $use_ssl));
 }
 public function overwriteStoredText($token, $new_text)
 {
     if ($this->isTextMode()) {
         $new_text = phutil_safe_html($new_text);
     }
     $this->storage->overwrite($token, $new_text);
     return $this;
 }
 public function renderExample()
 {
     $out = '';
     $out .= $this->renderTestThings('AphrontProgressBarView', 13, 10);
     $out .= $this->renderTestThings('AphrontGlyphBarView', 13, 10);
     $out .= $this->renderWeirdOrderGlyphBars();
     $out .= $this->renderAsciiStarBar();
     return phutil_safe_html($out);
 }
 private function buildResources()
 {
     $css = array('application/config/config-template.css', 'application/config/setup-issue.css');
     $webroot = dirname(phutil_get_library_root('phabricator')) . '/webroot/';
     $resources = array();
     foreach ($css as $path) {
         $resources[] = phutil_tag('style', array('type' => 'text/css'), phutil_safe_html(Filesystem::readFile($webroot . '/rsrc/css/' . $path)));
     }
     return phutil_implode_html("\n", $resources);
 }
 private function buildResources()
 {
     $paths = $this->getResources();
     $webroot = dirname(phutil_get_library_root('phabricator')) . '/webroot/';
     $resources = array();
     foreach ($paths as $path) {
         $resources[] = phutil_tag('style', array('type' => 'text/css'), phutil_safe_html(Filesystem::readFile($webroot . '/rsrc/' . $path)));
     }
     return phutil_implode_html("\n", $resources);
 }
 public function restore($corpus, $text_mode = false)
 {
     if ($this->map) {
         if ($text_mode) {
             $corpus = str_replace(array_reverse(array_keys($this->map)), array_reverse($this->map), $corpus);
         } else {
             $corpus = phutil_safe_html(str_replace(array_reverse(array_keys($this->map)), array_map('phutil_escape_html', array_reverse($this->map)), phutil_escape_html($corpus)));
         }
     }
     return $corpus;
 }
 private function renderTemplate($__template__, array $__scope__)
 {
     chdir($this->getPath());
     ob_start();
     if (Filesystem::pathExists($this->getPath($__template__))) {
         // Fool lint.
         $__evil__ = 'extract';
         $__evil__($__scope__ + $this->getDefaultScope());
         require $this->getPath($__template__);
     }
     return phutil_safe_html(ob_get_clean());
 }
 protected function didReceiveResult($result)
 {
     list($err, $stdout, $stderr) = $result;
     if (!$err && strlen($stdout)) {
         // Strip off fluff Pygments adds.
         $stdout = preg_replace('@^<div class="highlight"><pre>(.*)</pre></div>\\s*$@s', '\\1', $stdout);
         if ($this->scrub) {
             $stdout = preg_replace('/^.*\\n/', '', $stdout);
         }
         return phutil_safe_html($stdout);
     }
     throw new PhutilSyntaxHighlighterException($stderr, $err);
 }
 public function getHighlightFuture($source)
 {
     $source = phutil_escape_html($source);
     // This highlighter isn't perfect but tries to do an okay job at getting
     // some of the basics at least. There's lots of room for improvement.
     $blocks = explode("\n\n", $source);
     foreach ($blocks as $key => $block) {
         if (preg_match('/^[^ ](?! )/m', $block)) {
             $blocks[$key] = $this->highlightBlock($block);
         }
     }
     $source = implode("\n\n", $blocks);
     $source = phutil_safe_html($source);
     return new ImmediateFuture($source);
 }
Пример #11
0
 public static function applyIntralineDiff($str, $intra_stack)
 {
     $buf = '';
     $p = $s = $e = 0;
     // position, start, end
     $highlight = $tag = $ent = false;
     $highlight_o = '<span class="bright">';
     $highlight_c = '</span>';
     $is_html = false;
     if ($str instanceof PhutilSafeHTML) {
         $is_html = true;
         $str = $str->getHTMLContent();
     }
     $n = strlen($str);
     for ($i = 0; $i < $n; $i++) {
         if ($p == $e) {
             do {
                 if (empty($intra_stack)) {
                     $buf .= substr($str, $i);
                     break 2;
                 }
                 $stack = array_shift($intra_stack);
                 $s = $e;
                 $e += $stack[1];
             } while ($stack[0] == 0);
         }
         if (!$highlight && !$tag && !$ent && $p == $s) {
             $buf .= $highlight_o;
             $highlight = true;
         }
         if ($str[$i] == '<') {
             $tag = true;
             if ($highlight) {
                 $buf .= $highlight_c;
             }
         }
         if (!$tag) {
             if ($str[$i] == '&') {
                 $ent = true;
             }
             if ($ent && $str[$i] == ';') {
                 $ent = false;
             }
             if (!$ent) {
                 $p++;
             }
         }
         $buf .= $str[$i];
         if ($tag && $str[$i] == '>') {
             $tag = false;
             if ($highlight) {
                 $buf .= $highlight_o;
             }
         }
         if ($highlight && ($p == $e || $i == $n - 1)) {
             $buf .= $highlight_c;
             $highlight = false;
         }
     }
     if ($is_html) {
         return phutil_safe_html($buf);
     }
     return $buf;
 }
 private function addTaskToTree($task)
 {
     $cdate = $this->getTaskCreatedDate($task);
     $date_created = phabricator_date($cdate, $this->viewer);
     $udate = $this->getTaskModifiedDate($task);
     $last_updated = phabricator_date($udate, $this->viewer);
     $status = $task->getStatus();
     $owner_link = $this->setOwnerLink($this->handles, $task);
     $priority = $this->getPriority($task);
     $priority_name = $this->getPriorityName($task);
     $is_open = ManiphestTaskStatus::isOpenStatus($task->getStatus());
     if ($this->blocker === true && $is_open === true) {
         $blockericon = $this->getIconforBlocker();
     } else {
         $blockericon = '';
     }
     if ($this->blocked === true && $is_open === true) {
         $blockedicon = $this->getIconforBlocked();
     } else {
         $blockedicon = '';
     }
     $output = array();
     $output[] = array(phutil_safe_html(phutil_tag('a', array('href' => '/' . $task->getMonogram(), 'class' => $status !== 'open' ? 'phui-tag-core-closed' : ''), array($this->buildTaskLink($task), $blockericon, $blockedicon))), $cdate, $date_created, $udate, $last_updated, $owner_link, $priority, $priority_name, $this->points, $status);
     return $output;
 }
 public final function renderChangesetTable($content)
 {
     $props = null;
     if ($this->shouldRenderPropertyChangeHeader()) {
         $props = $this->renderPropertyChangeHeader();
     }
     $notice = null;
     if ($this->getIsTopLevel()) {
         $force = !$content && !$props;
         $notice = $this->renderChangeTypeHeader($force);
     }
     $result = $notice . $props . $content;
     // TODO: Let the user customize their tab width / display style.
     // TODO: We should possibly post-process "\r" as well.
     // TODO: Both these steps should happen earlier.
     $result = str_replace("\t", '  ', $result);
     return phutil_safe_html($result);
 }
Пример #14
0
 private function loadContent(array $pastes)
 {
     $cache = new PhabricatorKeyValueDatabaseCache();
     $cache = new PhutilKeyValueCacheProfiler($cache);
     $cache->setProfiler(PhutilServiceProfiler::getInstance());
     $keys = array();
     foreach ($pastes as $paste) {
         $keys[] = $this->getContentCacheKey($paste);
     }
     $caches = $cache->getKeys($keys);
     $results = array();
     $need_raw = array();
     foreach ($pastes as $key => $paste) {
         $key = $this->getContentCacheKey($paste);
         if (isset($caches[$key])) {
             $paste->attachContent(phutil_safe_html($caches[$key]));
             $results[$paste->getID()] = $paste;
         } else {
             $need_raw[$key] = $paste;
         }
     }
     if (!$need_raw) {
         return $results;
     }
     $write_data = array();
     $need_raw = $this->loadRawContent($need_raw);
     foreach ($need_raw as $key => $paste) {
         $content = $this->buildContent($paste);
         $paste->attachContent($content);
         $write_data[$this->getContentCacheKey($paste)] = (string) $content;
         $results[$paste->getID()] = $paste;
     }
     $cache->setKeys($write_data);
     return $results;
 }
 public function renderTextChange($range_start, $range_len, $rows)
 {
     $hunk_starts = $this->getHunkStartLines();
     $context_not_available = null;
     if ($hunk_starts) {
         $context_not_available = javelin_tag('tr', array('sigil' => 'context-target'), phutil_tag('td', array('colspan' => 6, 'class' => 'show-more'), pht('Context not available.')));
     }
     $html = array();
     $old_lines = $this->getOldLines();
     $new_lines = $this->getNewLines();
     $gaps = $this->getGaps();
     $reference = $this->getRenderingReference();
     $left_id = $this->getOldChangesetID();
     $right_id = $this->getNewChangesetID();
     // "N" stands for 'new' and means the comment should attach to the new file
     // when stored, i.e. DifferentialInlineComment->setIsNewFile().
     // "O" stands for 'old' and means the comment should attach to the old file.
     $left_char = $this->getOldAttachesToNewFile() ? 'N' : 'O';
     $right_char = $this->getNewAttachesToNewFile() ? 'N' : 'O';
     $changeset = $this->getChangeset();
     $copy_lines = idx($changeset->getMetadata(), 'copy:lines', array());
     $highlight_old = $this->getHighlightOld();
     $highlight_new = $this->getHighlightNew();
     $old_render = $this->getOldRender();
     $new_render = $this->getNewRender();
     $original_left = $this->getOriginalOld();
     $original_right = $this->getOriginalNew();
     $depths = $this->getDepths();
     $mask = $this->getMask();
     for ($ii = $range_start; $ii < $range_start + $range_len; $ii++) {
         if (empty($mask[$ii])) {
             // If we aren't going to show this line, we've just entered a gap.
             // Pop information about the next gap off the $gaps stack and render
             // an appropriate "Show more context" element. This branch eventually
             // increments $ii by the entire size of the gap and then continues
             // the loop.
             $gap = array_pop($gaps);
             $top = $gap[0];
             $len = $gap[1];
             $end = $top + $len - 20;
             $contents = array();
             if ($len > 40) {
                 $is_first_block = false;
                 if ($ii == 0) {
                     $is_first_block = true;
                 }
                 $contents[] = javelin_tag('a', array('href' => '#', 'mustcapture' => true, 'sigil' => 'show-more', 'meta' => array('ref' => $reference, 'range' => "{$top}-{$len}/{$top}-20")), $is_first_block ? pht('Show First 20 Lines') : pht("▲ Show 20 Lines"));
             }
             $contents[] = javelin_tag('a', array('href' => '#', 'mustcapture' => true, 'sigil' => 'show-more', 'meta' => array('type' => 'all', 'ref' => $reference, 'range' => "{$top}-{$len}/{$top}-{$len}")), pht('Show All %d Lines', $len));
             $is_last_block = false;
             if ($ii + $len >= $rows) {
                 $is_last_block = true;
             }
             if ($len > 40) {
                 $contents[] = javelin_tag('a', array('href' => '#', 'mustcapture' => true, 'sigil' => 'show-more', 'meta' => array('ref' => $reference, 'range' => "{$top}-{$len}/{$end}-20")), $is_last_block ? pht('Show Last 20 Lines') : pht("▼ Show 20 Lines"));
             }
             $context = null;
             $context_line = null;
             if (!$is_last_block && $depths[$ii + $len]) {
                 for ($l = $ii + $len - 1; $l >= $ii; $l--) {
                     $line = $new_lines[$l]['text'];
                     if ($depths[$l] < $depths[$ii + $len] && trim($line) != '') {
                         $context = $new_render[$l];
                         $context_line = $new_lines[$l]['line'];
                         break;
                     }
                 }
             }
             $container = javelin_tag('tr', array('sigil' => 'context-target'), array(phutil_tag('td', array('colspan' => 2, 'class' => 'show-more'), phutil_implode_html(" • ", $contents)), phutil_tag('th', array('class' => 'show-context-line'), $context_line ? (int) $context_line : null), phutil_tag('td', array('colspan' => 3, 'class' => 'show-context'), phutil_safe_html($context))));
             $html[] = $container;
             $ii += $len - 1;
             continue;
         }
         $o_num = null;
         $o_classes = '';
         $o_text = null;
         if (isset($old_lines[$ii])) {
             $o_num = $old_lines[$ii]['line'];
             $o_text = isset($old_render[$ii]) ? $old_render[$ii] : null;
             if ($old_lines[$ii]['type']) {
                 if ($old_lines[$ii]['type'] == '\\') {
                     $o_text = $old_lines[$ii]['text'];
                     $o_class = 'comment';
                 } else {
                     if ($original_left && !isset($highlight_old[$o_num])) {
                         $o_class = 'old-rebase';
                     } else {
                         if (empty($new_lines[$ii])) {
                             $o_class = 'old old-full';
                         } else {
                             $o_class = 'old';
                         }
                     }
                 }
                 $o_classes = $o_class;
             }
         }
         $n_copy = hsprintf('<td class="copy" />');
         $n_cov = null;
         $n_colspan = 2;
         $n_classes = '';
         $n_num = null;
         $n_text = null;
         if (isset($new_lines[$ii])) {
             $n_num = $new_lines[$ii]['line'];
             $n_text = isset($new_render[$ii]) ? $new_render[$ii] : null;
             $coverage = $this->getCodeCoverage();
             if ($coverage !== null) {
                 if (empty($coverage[$n_num - 1])) {
                     $cov_class = 'N';
                 } else {
                     $cov_class = $coverage[$n_num - 1];
                 }
                 $cov_class = 'cov-' . $cov_class;
                 $n_cov = phutil_tag('td', array('class' => "cov {$cov_class}"));
                 $n_colspan--;
             }
             if ($new_lines[$ii]['type']) {
                 if ($new_lines[$ii]['type'] == '\\') {
                     $n_text = $new_lines[$ii]['text'];
                     $n_class = 'comment';
                 } else {
                     if ($original_right && !isset($highlight_new[$n_num])) {
                         $n_class = 'new-rebase';
                     } else {
                         if (empty($old_lines[$ii])) {
                             $n_class = 'new new-full';
                         } else {
                             $n_class = 'new';
                         }
                     }
                 }
                 $n_classes = $n_class;
                 if ($new_lines[$ii]['type'] == '\\' || !isset($copy_lines[$n_num])) {
                     $n_copy = phutil_tag('td', array('class' => "copy {$n_class}"));
                 } else {
                     list($orig_file, $orig_line, $orig_type) = $copy_lines[$n_num];
                     $title = ($orig_type == '-' ? 'Moved' : 'Copied') . ' from ';
                     if ($orig_file == '') {
                         $title .= "line {$orig_line}";
                     } else {
                         $title .= basename($orig_file) . ":{$orig_line} in dir " . dirname('/' . $orig_file);
                     }
                     $class = $orig_type == '-' ? 'new-move' : 'new-copy';
                     $n_copy = javelin_tag('td', array('meta' => array('msg' => $title), 'class' => 'copy ' . $class), '');
                 }
             }
         }
         if (isset($hunk_starts[$o_num])) {
             $html[] = $context_not_available;
         }
         if ($o_num && $left_id) {
             $o_id = 'C' . $left_id . $left_char . 'L' . $o_num;
         } else {
             $o_id = null;
         }
         if ($n_num && $right_id) {
             $n_id = 'C' . $right_id . $right_char . 'L' . $n_num;
         } else {
             $n_id = null;
         }
         // NOTE: This is a unicode zero-width space, which we use as a hint when
         // intercepting 'copy' events to make sure sensible text ends up on the
         // clipboard. See the 'phabricator-oncopy' behavior.
         $zero_space = "​";
         // NOTE: The Javascript is sensitive to whitespace changes in this
         // block!
         $html[] = phutil_tag('tr', array(), array(phutil_tag('th', array('id' => $o_id), $o_num), phutil_tag('td', array('class' => $o_classes), $o_text), phutil_tag('th', array('id' => $n_id), $n_num), $n_copy, phutil_tag('td', array('class' => $n_classes, 'colspan' => $n_colspan), array(phutil_tag('span', array('class' => 'zwsp'), $zero_space), $n_text)), $n_cov));
         if ($context_not_available && $ii == $rows - 1) {
             $html[] = $context_not_available;
         }
         $old_comments = $this->getOldComments();
         $new_comments = $this->getNewComments();
         if ($o_num && isset($old_comments[$o_num])) {
             foreach ($old_comments[$o_num] as $comment) {
                 $comment_html = $this->renderInlineComment($comment, $on_right = false);
                 $new = '';
                 if ($n_num && isset($new_comments[$n_num])) {
                     foreach ($new_comments[$n_num] as $key => $new_comment) {
                         if ($comment->isCompatible($new_comment)) {
                             $new = $this->renderInlineComment($new_comment, $on_right = true);
                             unset($new_comments[$n_num][$key]);
                         }
                     }
                 }
                 $html[] = phutil_tag('tr', array('class' => 'inline'), array(phutil_tag('th', array()), phutil_tag('td', array(), $comment_html), phutil_tag('th', array()), phutil_tag('td', array('colspan' => 3), $new)));
             }
         }
         if ($n_num && isset($new_comments[$n_num])) {
             foreach ($new_comments[$n_num] as $comment) {
                 $comment_html = $this->renderInlineComment($comment, $on_right = true);
                 $html[] = phutil_tag('tr', array('class' => 'inline'), array(phutil_tag('th', array()), phutil_tag('td', array()), phutil_tag('th', array()), phutil_tag('td', array('colspan' => 3), $comment_html)));
             }
         }
     }
     return $this->wrapChangeInTable(phutil_implode_html('', $html));
 }
 public function handleRequest(AphrontRequest $request)
 {
     $viewer = $request->getUser();
     if ($viewer->isLoggedIn()) {
         // Kick the user home if they are already logged in.
         return id(new AphrontRedirectResponse())->setURI('/');
     }
     if ($request->isAjax()) {
         return $this->processAjaxRequest();
     }
     if ($request->isConduit()) {
         return $this->processConduitRequest();
     }
     // If the user gets this far, they aren't logged in, so if they have a
     // user session token we can conclude that it's invalid: if it was valid,
     // they'd have been logged in above and never made it here. Try to clear
     // it and warn the user they may need to nuke their cookies.
     $session_token = $request->getCookie(PhabricatorCookies::COOKIE_SESSION);
     if (strlen($session_token)) {
         $kind = PhabricatorAuthSessionEngine::getSessionKindFromToken($session_token);
         switch ($kind) {
             case PhabricatorAuthSessionEngine::KIND_ANONYMOUS:
                 // If this is an anonymous session. It's expected that they won't
                 // be logged in, so we can just continue.
                 break;
             default:
                 // The session cookie is invalid, so clear it.
                 $request->clearCookie(PhabricatorCookies::COOKIE_USERNAME);
                 $request->clearCookie(PhabricatorCookies::COOKIE_SESSION);
                 return $this->renderError(pht('Your login session is invalid. Try reloading the page and ' . 'logging in again. If that does not work, clear your browser ' . 'cookies.'));
         }
     }
     $providers = PhabricatorAuthProvider::getAllEnabledProviders();
     foreach ($providers as $key => $provider) {
         if (!$provider->shouldAllowLogin()) {
             unset($providers[$key]);
         }
     }
     if (!$providers) {
         if ($this->isFirstTimeSetup()) {
             // If this is a fresh install, let the user register their admin
             // account.
             return id(new AphrontRedirectResponse())->setURI($this->getApplicationURI('/register/'));
         }
         return $this->renderError(pht('This Phabricator install is not configured with any enabled ' . 'authentication providers which can be used to log in. If you ' . 'have accidentally locked yourself out by disabling all providers, ' . 'you can use `%s` to recover access to an administrative account.', 'phabricator/bin/auth recover <username>'));
     }
     $next_uri = $request->getStr('next');
     if (!strlen($next_uri)) {
         if ($this->getDelegatingController()) {
             // Only set a next URI from the request path if this controller was
             // delegated to, which happens when a user tries to view a page which
             // requires them to login.
             // If this controller handled the request directly, we're on the main
             // login page, and never want to redirect the user back here after they
             // login.
             $next_uri = (string) $this->getRequest()->getRequestURI();
         }
     }
     if (!$request->isFormPost()) {
         if (strlen($next_uri)) {
             PhabricatorCookies::setNextURICookie($request, $next_uri);
         }
         PhabricatorCookies::setClientIDCookie($request);
     }
     if (!$request->getURIData('loggedout') && count($providers) == 1) {
         $auto_login_provider = head($providers);
         $auto_login_config = $auto_login_provider->getProviderConfig();
         if ($auto_login_provider instanceof PhabricatorPhabricatorAuthProvider && $auto_login_config->getShouldAutoLogin()) {
             $auto_login_adapter = $provider->getAdapter();
             $auto_login_adapter->setState($provider->getAuthCSRFCode($request));
             return id(new AphrontRedirectResponse())->setIsExternal(true)->setURI($provider->getAdapter()->getAuthenticateURI());
         }
     }
     $invite = $this->loadInvite();
     $not_buttons = array();
     $are_buttons = array();
     $providers = msort($providers, 'getLoginOrder');
     foreach ($providers as $provider) {
         if ($invite) {
             $form = $provider->buildInviteForm($this);
         } else {
             $form = $provider->buildLoginForm($this);
         }
         if ($provider->isLoginFormAButton()) {
             $are_buttons[] = $form;
         } else {
             $not_buttons[] = $form;
         }
     }
     $out = array();
     $out[] = $not_buttons;
     if ($are_buttons) {
         require_celerity_resource('auth-css');
         foreach ($are_buttons as $key => $button) {
             $are_buttons[$key] = phutil_tag('div', array('class' => 'phabricator-login-button mmb'), $button);
         }
         // If we only have one button, add a second pretend button so that we
         // always have two columns. This makes it easier to get the alignments
         // looking reasonable.
         if (count($are_buttons) == 1) {
             $are_buttons[] = null;
         }
         $button_columns = id(new AphrontMultiColumnView())->setFluidLayout(true);
         $are_buttons = array_chunk($are_buttons, ceil(count($are_buttons) / 2));
         foreach ($are_buttons as $column) {
             $button_columns->addColumn($column);
         }
         $out[] = phutil_tag('div', array('class' => 'phabricator-login-buttons'), $button_columns);
     }
     $login_message = PhabricatorEnv::getEnvConfig('auth.login-message');
     $login_message = phutil_safe_html($login_message);
     $invite_message = null;
     if ($invite) {
         $invite_message = $this->renderInviteHeader($invite);
     }
     $crumbs = $this->buildApplicationCrumbs();
     $crumbs->addTextCrumb(pht('Login'));
     $crumbs->setBorder(true);
     return $this->buildApplicationPage(array($crumbs, $login_message, $invite_message, $out), array('title' => pht('Login to Phabricator')));
 }
 public function addRawHTMLSection($html)
 {
     $this->htmlSections[] = phutil_safe_html($html);
     return $this;
 }
 private function loadContent(array $pastes)
 {
     $cache = new PhabricatorKeyValueDatabaseCache();
     $cache = new PhutilKeyValueCacheProfiler($cache);
     $cache->setProfiler(PhutilServiceProfiler::getInstance());
     $keys = array();
     foreach ($pastes as $paste) {
         $keys[] = $this->getContentCacheKey($paste);
     }
     $caches = $cache->getKeys($keys);
     $need_raw = array();
     $have_cache = array();
     foreach ($pastes as $paste) {
         $key = $this->getContentCacheKey($paste);
         if (isset($caches[$key])) {
             $paste->attachContent(phutil_safe_html($caches[$key]));
             $have_cache[$paste->getPHID()] = true;
         } else {
             $need_raw[$key] = $paste;
         }
     }
     if (!$need_raw) {
         return $pastes;
     }
     $write_data = array();
     $have_raw = $this->loadRawContent($need_raw);
     $have_raw = mpull($have_raw, null, 'getPHID');
     foreach ($pastes as $key => $paste) {
         $paste_phid = $paste->getPHID();
         if (isset($have_cache[$paste_phid])) {
             continue;
         }
         if (empty($have_raw[$paste_phid])) {
             unset($pastes[$key]);
             continue;
         }
         $content = $this->buildContent($paste);
         $paste->attachContent($content);
         $write_data[$this->getContentCacheKey($paste)] = (string) $content;
     }
     if ($write_data) {
         $cache->setKeys($write_data);
     }
     return $pastes;
 }
Пример #19
0
 public function translate($text)
 {
     if (isset($this->translations[$text])) {
         $translation = $this->translations[$text];
     } else {
         $translation = $text;
     }
     $args = func_get_args();
     while (is_array($translation)) {
         $arg = next($args);
         $translation = $this->chooseVariant($translation, $arg);
         if ($translation === null) {
             $pos = key($args);
             if (is_object($arg)) {
                 $kind = get_class($arg);
             } else {
                 $kind = gettype($arg);
             }
             return sprintf('[Invalid Translation!] The "%s" language data offers variant ' . 'translations for the plurality or gender of argument %s, but ' . 'the value for that argument is not an integer, PhutilNumber, or ' . 'PhutilPerson (it is a value of type "%s"). Raw input: <%s>.', $this->localeCode, $pos, $kind, $text);
         }
     }
     array_shift($args);
     foreach ($args as $k => $arg) {
         if ($arg instanceof PhutilNumber) {
             $args[$k] = $this->formatNumber($arg->getNumber(), $arg->getDecimals());
         }
     }
     // Check if any arguments are PhutilSafeHTML. If they are, we will apply
     // any escaping necessary and output HTML.
     $is_html = false;
     foreach ($args as $arg) {
         if ($arg instanceof PhutilSafeHTML || $arg instanceof PhutilSafeHTMLProducerInterface) {
             $is_html = true;
             break;
         }
     }
     if ($is_html) {
         foreach ($args as $k => $arg) {
             $args[$k] = (string) phutil_escape_html($arg);
         }
     }
     $result = vsprintf($translation, $args);
     if ($result === false) {
         // If vsprintf() fails (often because the translated string references
         // too many parameters), show the bad template with a note instead of
         // returning an empty string. This makes it easier to figure out what
         // went wrong and fix it.
         $result = pht('[Invalid Translation!] %s', $translation);
     }
     if ($this->shouldPostProcess) {
         $result = $this->locale->didTranslateString($text, $translation, $args, $result);
     }
     if ($is_html) {
         $result = phutil_safe_html($result);
     }
     return $result;
 }
 protected function replaceHTML($pattern, $callback, $text)
 {
     $this->replaceCallback = $callback;
     return phutil_safe_html(preg_replace_callback($pattern, array($this, 'replaceHTMLCallback'), phutil_escape_html($text)));
 }
 /**
  * Check whether text is flat (contains no replacement tokens) or not.
  *
  * @param   wild  Ostensibly flat text.
  * @return  bool  True if the text is flat.
  */
 protected function isFlatText($text)
 {
     $text = (string) hsprintf('%s', phutil_safe_html($text));
     return strpos($text, PhutilRemarkupBlockStorage::MAGIC_BYTE) === false;
 }
Пример #22
0
 private function addTaskToTree(&$output, $task, &$map, $handles, $depth = 0)
 {
     static $included = array();
     // Get the owner object so we can render the owner username/link
     $owner = $handles[$task->getOwnerPHID()];
     // If this task is already is this tree, this is a repeat.
     $repeat = isset($included[$task->getPHID()]);
     $depth_indent = '';
     for ($i = 0; $i < $depth; $i++) {
         $depth_indent .= '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
     }
     // Build the row
     $output[] = array(phutil_safe_html($depth_indent . phutil_tag('a', array('href' => '/' . $task->getMonogram(), 'class' => $task->getStatus() !== 'open' ? 'phui-tag-core-closed' : ''), $task->getMonogram() . ': ' . $task->getTitle()) . ($repeat ? '&nbsp;&nbsp;<em title="This task is a child of more than one task in this list. Children are only shown on ' . 'the first occurance">[Repeat]</em>' : '')), $task->getOwnerPHID() ? $owner->renderLink() : 'none assigned', $task->getStatus());
     $included[$task->getPHID()] = $task->getPHID();
     if (isset($map[$task->getPHID()]['children'])) {
         foreach ($map[$task->getPHID()]['children'] as $child) {
             $child = $this->tasks[$child];
             $this->addTaskToTree($output, $child, $map, $handles, $depth + 1);
         }
     }
 }
 public function renderTextChange($range_start, $range_len, $rows)
 {
     $hunk_starts = $this->getHunkStartLines();
     $context_not_available = null;
     if ($hunk_starts) {
         $context_not_available = javelin_tag('tr', array('sigil' => 'context-target'), phutil_tag('td', array('colspan' => 6, 'class' => 'show-more'), pht('Context not available.')));
     }
     $html = array();
     $old_lines = $this->getOldLines();
     $new_lines = $this->getNewLines();
     $gaps = $this->getGaps();
     $reference = $this->getRenderingReference();
     list($left_prefix, $right_prefix) = $this->getLineIDPrefixes();
     $changeset = $this->getChangeset();
     $copy_lines = idx($changeset->getMetadata(), 'copy:lines', array());
     $highlight_old = $this->getHighlightOld();
     $highlight_new = $this->getHighlightNew();
     $old_render = $this->getOldRender();
     $new_render = $this->getNewRender();
     $original_left = $this->getOriginalOld();
     $original_right = $this->getOriginalNew();
     $depths = $this->getDepths();
     $mask = $this->getMask();
     $hidden = new PHUIDiffRevealIconView();
     /* Init extension */
     $line_renderer = new DifferentialLineNumberRendered($changeset->getDisplayFilename(), $range_start, $range_len);
     for ($ii = $range_start; $ii < $range_start + $range_len; $ii++) {
         if (empty($mask[$ii])) {
             // If we aren't going to show this line, we've just entered a gap.
             // Pop information about the next gap off the $gaps stack and render
             // an appropriate "Show more context" element. This branch eventually
             // increments $ii by the entire size of the gap and then continues
             // the loop.
             $gap = array_pop($gaps);
             $top = $gap[0];
             $len = $gap[1];
             $contents = $this->renderShowContextLinks($top, $len, $rows);
             $is_last_block = false;
             if ($ii + $len >= $rows) {
                 $is_last_block = true;
             }
             $context = null;
             $context_line = null;
             if (!$is_last_block && $depths[$ii + $len]) {
                 for ($l = $ii + $len - 1; $l >= $ii; $l--) {
                     $line = $new_lines[$l]['text'];
                     if ($depths[$l] < $depths[$ii + $len] && trim($line) != '') {
                         $context = $new_render[$l];
                         $context_line = $new_lines[$l]['line'];
                         break;
                     }
                 }
             }
             $container = javelin_tag('tr', array('sigil' => 'context-target'), array(phutil_tag('td', array('colspan' => 2, 'class' => 'show-more'), $contents), phutil_tag('th', array('class' => 'show-context-line'), $context_line ? (int) $context_line : null), phutil_tag('td', array('colspan' => 3, 'class' => 'show-context'), phutil_safe_html($context))));
             $html[] = $container;
             $ii += $len - 1;
             continue;
         }
         $o_num = null;
         $o_classes = '';
         $o_text = null;
         if (isset($old_lines[$ii])) {
             $o_num = $old_lines[$ii]['line'];
             $o_text = isset($old_render[$ii]) ? $old_render[$ii] : null;
             if ($old_lines[$ii]['type']) {
                 if ($old_lines[$ii]['type'] == '\\') {
                     $o_text = $old_lines[$ii]['text'];
                     $o_class = 'comment';
                 } else {
                     if ($original_left && !isset($highlight_old[$o_num])) {
                         $o_class = 'old-rebase';
                     } else {
                         if (empty($new_lines[$ii])) {
                             $o_class = 'old old-full';
                         } else {
                             $o_class = 'old';
                         }
                     }
                 }
                 $o_classes = $o_class;
             }
         }
         $n_copy = hsprintf('<td class="copy" />');
         $n_cov = null;
         $n_colspan = 2;
         $n_classes = '';
         $n_num = null;
         $n_text = null;
         if (isset($new_lines[$ii])) {
             $n_num = $new_lines[$ii]['line'];
             $n_text = isset($new_render[$ii]) ? $new_render[$ii] : null;
             $coverage = $this->getCodeCoverage();
             if ($coverage !== null) {
                 if (empty($coverage[$n_num - 1])) {
                     $cov_class = 'N';
                 } else {
                     $cov_class = $coverage[$n_num - 1];
                 }
                 $cov_class = 'cov-' . $cov_class;
                 $n_cov = phutil_tag('td', array('class' => "cov {$cov_class}"));
                 $n_colspan--;
             }
             if ($new_lines[$ii]['type']) {
                 if ($new_lines[$ii]['type'] == '\\') {
                     $n_text = $new_lines[$ii]['text'];
                     $n_class = 'comment';
                 } else {
                     if ($original_right && !isset($highlight_new[$n_num])) {
                         $n_class = 'new-rebase';
                     } else {
                         if (empty($old_lines[$ii])) {
                             $n_class = 'new new-full';
                         } else {
                             $n_class = 'new';
                         }
                     }
                 }
                 $n_classes = $n_class;
                 if ($new_lines[$ii]['type'] == '\\' || !isset($copy_lines[$n_num])) {
                     $n_copy = phutil_tag('td', array('class' => "copy {$n_class}"));
                 } else {
                     list($orig_file, $orig_line, $orig_type) = $copy_lines[$n_num];
                     $title = ($orig_type == '-' ? 'Moved' : 'Copied') . ' from ';
                     if ($orig_file == '') {
                         $title .= "line {$orig_line}";
                     } else {
                         $title .= basename($orig_file) . ":{$orig_line} in dir " . dirname('/' . $orig_file);
                     }
                     $class = $orig_type == '-' ? 'new-move' : 'new-copy';
                     $n_copy = javelin_tag('td', array('meta' => array('msg' => $title), 'class' => 'copy ' . $class), '');
                 }
             }
         }
         if (isset($hunk_starts[$o_num])) {
             $html[] = $context_not_available;
         }
         if ($o_num && $left_prefix) {
             $o_id = $left_prefix . $o_num;
         } else {
             $o_id = null;
         }
         if ($n_num && $right_prefix) {
             $n_id = $right_prefix . $n_num;
         } else {
             $n_id = null;
         }
         $old_comments = $this->getOldComments();
         $new_comments = $this->getNewComments();
         $scaffolds = array();
         $o_hidden = array();
         $n_hidden = array();
         if ($o_num && isset($old_comments[$o_num])) {
             foreach ($old_comments[$o_num] as $comment) {
                 $inline = $this->buildInlineComment($comment, $on_right = false);
                 $scaffold = $this->getRowScaffoldForInline($inline);
                 if ($comment->isHidden()) {
                     $o_hidden[] = $comment;
                 }
                 if ($n_num && isset($new_comments[$n_num])) {
                     foreach ($new_comments[$n_num] as $key => $new_comment) {
                         if ($comment->isCompatible($new_comment)) {
                             $companion = $this->buildInlineComment($new_comment, $on_right = true);
                             if ($new_comment->isHidden()) {
                                 $n_hidden = $new_comment;
                             }
                             $scaffold->addInlineView($companion);
                             unset($new_comments[$n_num][$key]);
                             break;
                         }
                     }
                 }
                 $scaffolds[] = $scaffold;
             }
         }
         if ($n_num && isset($new_comments[$n_num])) {
             foreach ($new_comments[$n_num] as $comment) {
                 $inline = $this->buildInlineComment($comment, $on_right = true);
                 if ($comment->isHidden()) {
                     $n_hidden[] = $comment;
                 }
                 $scaffolds[] = $this->getRowScaffoldForInline($inline);
             }
         }
         if ($o_hidden) {
             $o_num = array($hidden, $o_num);
         }
         if ($n_hidden) {
             $n_num = array($hidden, $n_num);
         }
         // NOTE: This is a unicode zero-width space, which we use as a hint when
         // intercepting 'copy' events to make sure sensible text ends up on the
         // clipboard. See the 'phabricator-oncopy' behavior.
         $zero_space = "​";
         $line_num_rendered_o = $line_renderer->getLineTag($o_num);
         $line_num_rendered_n = $line_renderer->getLineTag($n_num);
         $html[] = phutil_tag('tr', array(), array(phutil_tag('th', array('id' => $o_id), $line_num_rendered_o), phutil_tag('td', array('class' => $o_classes), $o_text), phutil_tag('th', array('id' => $n_id), $line_num_rendered_n), $n_copy, phutil_tag('td', array('class' => $n_classes, 'colspan' => $n_colspan), array(phutil_tag('span', array('class' => 'zwsp'), $zero_space), $n_text)), $n_cov));
         if ($context_not_available && $ii == $rows - 1) {
             $html[] = $context_not_available;
         }
         foreach ($scaffolds as $scaffold) {
             $html[] = $scaffold;
         }
     }
     return $this->wrapChangeInTable(phutil_implode_html('', $html));
 }
 private function buildDisplayRows(array $lines, array $blame_list, array $blame_commits, $show_color, $show_blame)
 {
     $request = $this->getRequest();
     $viewer = $this->getViewer();
     $drequest = $this->getDiffusionRequest();
     $repository = $drequest->getRepository();
     $revision_map = array();
     $revisions = array();
     if ($blame_commits) {
         $commit_map = mpull($blame_commits, 'getCommitIdentifier', 'getPHID');
         $revision_ids = id(new DifferentialRevision())->loadIDsByCommitPHIDs(array_keys($commit_map));
         if ($revision_ids) {
             $revisions = id(new DifferentialRevisionQuery())->setViewer($viewer)->withIDs($revision_ids)->execute();
             $revisions = mpull($revisions, null, 'getID');
         }
         foreach ($revision_ids as $commit_phid => $revision_id) {
             $revision_map[$commit_map[$commit_phid]] = $revision_id;
         }
     }
     $phids = array();
     foreach ($blame_commits as $commit) {
         $author_phid = $commit->getAuthorPHID();
         if ($author_phid === null) {
             continue;
         }
         $phids[$author_phid] = $author_phid;
     }
     foreach ($revisions as $revision) {
         $author_phid = $revision->getAuthorPHID();
         if ($author_phid === null) {
             continue;
         }
         $phids[$author_phid] = $author_phid;
     }
     $handles = $viewer->loadHandles($phids);
     $colors = array();
     if ($blame_commits) {
         $epochs = array();
         foreach ($blame_commits as $identifier => $commit) {
             $epochs[$identifier] = $commit->getEpoch();
         }
         $epoch_list = array_filter($epochs);
         $epoch_list = array_unique($epoch_list);
         $epoch_list = array_values($epoch_list);
         $epoch_min = min($epoch_list);
         $epoch_max = max($epoch_list);
         $epoch_range = $epoch_max - $epoch_min + 1;
         foreach ($blame_commits as $identifier => $commit) {
             $epoch = $epochs[$identifier];
             if (!$epoch) {
                 $color = '#ffffdd';
                 // Warning color, missing data.
             } else {
                 $color_ratio = ($epoch - $epoch_min) / $epoch_range;
                 $color_value = 0xe6 * (1.0 - $color_ratio);
                 $color = sprintf('#%02x%02x%02x', $color_value, 0xf6, $color_value);
             }
             $colors[$identifier] = $color;
         }
     }
     $display = array();
     $last_identifier = null;
     $last_color = null;
     foreach ($lines as $line_index => $line) {
         $color = '#f6f6f6';
         $duplicate = false;
         if (isset($blame_list[$line_index])) {
             $identifier = $blame_list[$line_index];
             if (isset($colors[$identifier])) {
                 $color = $colors[$identifier];
             }
             if ($identifier === $last_identifier) {
                 $duplicate = true;
             } else {
                 $last_identifier = $identifier;
             }
         }
         $display[$line_index] = array('data' => $line, 'target' => false, 'highlighted' => false, 'color' => $color, 'duplicate' => $duplicate);
     }
     $line_arr = array();
     $line_str = $drequest->getLine();
     $ranges = explode(',', $line_str);
     foreach ($ranges as $range) {
         if (strpos($range, '-') !== false) {
             list($min, $max) = explode('-', $range, 2);
             $line_arr[] = array('min' => min($min, $max), 'max' => max($min, $max));
         } else {
             if (strlen($range)) {
                 $line_arr[] = array('min' => $range, 'max' => $range);
             }
         }
     }
     // Mark the first highlighted line as the target line.
     if ($line_arr) {
         $target_line = $line_arr[0]['min'];
         if (isset($display[$target_line - 1])) {
             $display[$target_line - 1]['target'] = true;
         }
     }
     // Mark all other highlighted lines as highlighted.
     foreach ($line_arr as $range) {
         for ($ii = $range['min']; $ii <= $range['max']; $ii++) {
             if (isset($display[$ii - 1])) {
                 $display[$ii - 1]['highlighted'] = true;
             }
         }
     }
     $engine = null;
     $inlines = array();
     if ($this->getRequest()->getStr('lint') !== null && $this->lintMessages) {
         $engine = new PhabricatorMarkupEngine();
         $engine->setViewer($viewer);
         foreach ($this->lintMessages as $message) {
             $inline = id(new PhabricatorAuditInlineComment())->setSyntheticAuthor(ArcanistLintSeverity::getStringForSeverity($message['severity']) . ' ' . $message['code'] . ' (' . $message['name'] . ')')->setLineNumber($message['line'])->setContent($message['description']);
             $inlines[$message['line']][] = $inline;
             $engine->addObject($inline, PhabricatorInlineCommentInterface::MARKUP_FIELD_BODY);
         }
         $engine->process();
         require_celerity_resource('differential-changeset-view-css');
     }
     $rows = $this->renderInlines(idx($inlines, 0, array()), $show_blame, (bool) $this->coverage, $engine);
     // NOTE: We're doing this manually because rendering is otherwise
     // dominated by URI generation for very large files.
     $line_base = (string) $drequest->generateURI(array('action' => 'browse', 'stable' => true));
     require_celerity_resource('aphront-tooltip-css');
     Javelin::initBehavior('phabricator-oncopy');
     Javelin::initBehavior('phabricator-tooltips');
     Javelin::initBehavior('phabricator-line-linker');
     // Render these once, since they tend to get repeated many times in large
     // blame outputs.
     $commit_links = $this->renderCommitLinks($blame_commits, $handles);
     $revision_links = $this->renderRevisionLinks($revisions, $handles);
     $skip_text = pht('Skip Past This Commit');
     foreach ($display as $line_index => $line) {
         $row = array();
         $line_number = $line_index + 1;
         $line_href = $line_base . '$' . $line_number;
         if (isset($blame_list[$line_index])) {
             $identifier = $blame_list[$line_index];
         } else {
             $identifier = null;
         }
         $revision_link = null;
         $commit_link = null;
         $before_link = null;
         $style = 'background: ' . $line['color'] . ';';
         if ($identifier && !$line['duplicate']) {
             if (isset($commit_links[$identifier])) {
                 $commit_link = $commit_links[$identifier];
             }
             if (isset($revision_map[$identifier])) {
                 $revision_id = $revision_map[$identifier];
                 if (isset($revision_links[$revision_id])) {
                     $revision_link = $revision_links[$revision_id];
                 }
             }
             $skip_href = $line_href . '?before=' . $identifier . '&view=blame';
             $before_link = javelin_tag('a', array('href' => $skip_href, 'sigil' => 'has-tooltip', 'meta' => array('tip' => $skip_text, 'align' => 'E', 'size' => 300)), "«");
         }
         $row[] = phutil_tag('th', array('class' => 'diffusion-blame-link'), $before_link);
         $object_links = array();
         $object_links[] = $commit_link;
         if ($revision_link) {
             $object_links[] = phutil_tag('span', array(), '/');
             $object_links[] = $revision_link;
         }
         $row[] = phutil_tag('th', array('class' => 'diffusion-rev-link'), $object_links);
         $line_link = phutil_tag('a', array('href' => $line_href, 'style' => $style), $line_number);
         $row[] = javelin_tag('th', array('class' => 'diffusion-line-link', 'sigil' => 'phabricator-source-line', 'style' => $style), $line_link);
         if ($line['target']) {
             Javelin::initBehavior('diffusion-jump-to', array('target' => 'scroll_target'));
             $anchor_text = phutil_tag('a', array('id' => 'scroll_target'), '');
         } else {
             $anchor_text = null;
         }
         $row[] = phutil_tag('td', array(), array($anchor_text, "​", phutil_safe_html(str_replace("\t", '  ', $line['data']))));
         if ($this->coverage) {
             require_celerity_resource('differential-changeset-view-css');
             $cov_index = $line_index;
             if (isset($this->coverage[$cov_index])) {
                 $cov_class = $this->coverage[$cov_index];
             } else {
                 $cov_class = 'N';
             }
             $row[] = phutil_tag('td', array('class' => 'cov cov-' . $cov_class), '');
         }
         $rows[] = phutil_tag('tr', array('class' => $line['highlighted'] ? 'phabricator-source-highlight' : null), $row);
         $cur_inlines = $this->renderInlines(idx($inlines, $line_number, array()), $show_blame, $this->coverage, $engine);
         foreach ($cur_inlines as $cur_inline) {
             $rows[] = $cur_inline;
         }
     }
     return $rows;
 }
 private function buildWelcomePanel()
 {
     $panel = new PHUIObjectBoxView();
     $panel->setHeaderText(pht('Welcome'));
     $panel->appendChild(phutil_safe_html(PhabricatorEnv::getEnvConfig('welcome.html')));
     return $panel;
 }
 public function translate($text)
 {
     $translation = idx($this->translations, $text, $text);
     $args = func_get_args();
     while (is_array($translation)) {
         $translation = $this->chooseVariant($translation, next($args));
     }
     array_shift($args);
     foreach ($args as $k => $arg) {
         if ($arg instanceof PhutilNumber) {
             $args[$k] = $this->formatNumber($arg->getNumber(), $arg->getDecimals());
         }
     }
     // Check if any arguments are PhutilSafeHTML. If they are, we will apply
     // any escaping necessary and output HTML.
     $is_html = false;
     foreach ($args as $arg) {
         if ($arg instanceof PhutilSafeHTML) {
             $is_html = true;
             break;
         }
     }
     if ($is_html) {
         foreach ($args as $k => $arg) {
             $args[$k] = (string) phutil_escape_html($arg);
         }
     }
     $result = vsprintf($translation, $args);
     if ($result === false) {
         // If vsprintf() fails (often because the translated string references
         // too many parameters), show the bad template with a note instead of
         // returning an empty string. This makes it easier to figure out what
         // went wrong and fix it.
         $result = pht('[Invalid Translation!] %s', $translation);
     }
     if ($this->shouldPostProcess) {
         $result = $this->locale->didTranslateString($text, $translation, $args, $result);
     }
     if ($is_html) {
         $result = phutil_safe_html($result);
     }
     return $result;
 }
 private function buildWelcomePanel()
 {
     $panel = new AphrontPanelView();
     $panel->appendChild(phutil_safe_html(PhabricatorEnv::getEnvConfig('welcome.html')));
     $panel->setNoBackground();
     return $panel;
 }
 public static function renderInlineScript($data)
 {
     if (stripos($data, '</script>') !== false) {
         throw new Exception(pht('Literal %s is not allowed inside inline script.', '</script>'));
     }
     if (strpos($data, '<!') !== false) {
         throw new Exception(pht('Literal %s is not allowed inside inline script.', '<!'));
     }
     // We don't use <![CDATA[ ]]> because it is ignored by HTML parsers. We
     // would need to send the document with XHTML content type.
     return phutil_tag('script', array('type' => 'text/javascript'), phutil_safe_html($data));
 }
 private function buildDisplayRows(array $text_list, array $rev_list, array $blame_dict, $needs_blame, DiffusionRequest $drequest, $show_blame, $show_color)
 {
     $handles = array();
     if ($blame_dict) {
         $epoch_list = ipull(ifilter($blame_dict, 'epoch'), 'epoch');
         $epoch_min = min($epoch_list);
         $epoch_max = max($epoch_list);
         $epoch_range = $epoch_max - $epoch_min + 1;
         $author_phids = ipull(ifilter($blame_dict, 'authorPHID'), 'authorPHID');
         $handles = $this->loadViewerHandles($author_phids);
     }
     $line_arr = array();
     $line_str = $drequest->getLine();
     $ranges = explode(',', $line_str);
     foreach ($ranges as $range) {
         if (strpos($range, '-') !== false) {
             list($min, $max) = explode('-', $range, 2);
             $line_arr[] = array('min' => min($min, $max), 'max' => max($min, $max));
         } else {
             if (strlen($range)) {
                 $line_arr[] = array('min' => $range, 'max' => $range);
             }
         }
     }
     $display = array();
     $line_number = 1;
     $last_rev = null;
     $color = null;
     foreach ($text_list as $k => $line) {
         $display_line = array('epoch' => null, 'commit' => null, 'author' => null, 'target' => null, 'highlighted' => null, 'line' => $line_number, 'data' => $line);
         if ($show_blame) {
             // If the line's rev is same as the line above, show empty content
             // with same color; otherwise generate blame info. The newer a change
             // is, the more saturated the color.
             $rev = idx($rev_list, $k, $last_rev);
             if ($last_rev == $rev) {
                 $display_line['color'] = $color;
             } else {
                 $blame = $blame_dict[$rev];
                 if (!isset($blame['epoch'])) {
                     $color = '#ffd';
                     // Render as warning.
                 } else {
                     $color_ratio = ($blame['epoch'] - $epoch_min) / $epoch_range;
                     $color_value = 0xe6 * (1.0 - $color_ratio);
                     $color = sprintf('#%02x%02x%02x', $color_value, 0xf6, $color_value);
                 }
                 $display_line['epoch'] = idx($blame, 'epoch');
                 $display_line['color'] = $color;
                 $display_line['commit'] = $rev;
                 $author_phid = idx($blame, 'authorPHID');
                 if ($author_phid && $handles[$author_phid]) {
                     $author_link = $handles[$author_phid]->renderLink();
                 } else {
                     $author_link = $blame['author'];
                 }
                 $display_line['author'] = $author_link;
                 $last_rev = $rev;
             }
         }
         if ($line_arr) {
             if ($line_number == $line_arr[0]['min']) {
                 $display_line['target'] = true;
             }
             foreach ($line_arr as $range) {
                 if ($line_number >= $range['min'] && $line_number <= $range['max']) {
                     $display_line['highlighted'] = true;
                 }
             }
         }
         $display[] = $display_line;
         ++$line_number;
     }
     $request = $this->getRequest();
     $viewer = $request->getUser();
     $commits = array_filter(ipull($display, 'commit'));
     if ($commits) {
         $commits = id(new DiffusionCommitQuery())->setViewer($viewer)->withRepository($drequest->getRepository())->withIdentifiers($commits)->execute();
         $commits = mpull($commits, null, 'getCommitIdentifier');
     }
     $revision_ids = id(new DifferentialRevision())->loadIDsByCommitPHIDs(mpull($commits, 'getPHID'));
     $revisions = array();
     if ($revision_ids) {
         $revisions = id(new DifferentialRevisionQuery())->setViewer($viewer)->withIDs($revision_ids)->execute();
     }
     $phids = array();
     foreach ($commits as $commit) {
         if ($commit->getAuthorPHID()) {
             $phids[] = $commit->getAuthorPHID();
         }
     }
     foreach ($revisions as $revision) {
         if ($revision->getAuthorPHID()) {
             $phids[] = $revision->getAuthorPHID();
         }
     }
     $handles = $this->loadViewerHandles($phids);
     Javelin::initBehavior('phabricator-oncopy', array());
     $engine = null;
     $inlines = array();
     if ($this->getRequest()->getStr('lint') !== null && $this->lintMessages) {
         $engine = new PhabricatorMarkupEngine();
         $engine->setViewer($viewer);
         foreach ($this->lintMessages as $message) {
             $inline = id(new PhabricatorAuditInlineComment())->setSyntheticAuthor(ArcanistLintSeverity::getStringForSeverity($message['severity']) . ' ' . $message['code'] . ' (' . $message['name'] . ')')->setLineNumber($message['line'])->setContent($message['description']);
             $inlines[$message['line']][] = $inline;
             $engine->addObject($inline, PhabricatorInlineCommentInterface::MARKUP_FIELD_BODY);
         }
         $engine->process();
         require_celerity_resource('differential-changeset-view-css');
     }
     $rows = $this->renderInlines(idx($inlines, 0, array()), $show_blame, (bool) $this->coverage, $engine);
     foreach ($display as $line) {
         $line_href = $drequest->generateURI(array('action' => 'browse', 'line' => $line['line'], 'stable' => true));
         $blame = array();
         $style = null;
         if (array_key_exists('color', $line)) {
             if ($line['color']) {
                 $style = 'background: ' . $line['color'] . ';';
             }
             $before_link = null;
             $commit_link = null;
             $revision_link = null;
             if (idx($line, 'commit')) {
                 $commit = $line['commit'];
                 if (idx($commits, $commit)) {
                     $tooltip = $this->renderCommitTooltip($commits[$commit], $handles, $line['author']);
                 } else {
                     $tooltip = null;
                 }
                 Javelin::initBehavior('phabricator-tooltips', array());
                 require_celerity_resource('aphront-tooltip-css');
                 $commit_link = javelin_tag('a', array('href' => $drequest->generateURI(array('action' => 'commit', 'commit' => $line['commit'])), 'sigil' => 'has-tooltip', 'meta' => array('tip' => $tooltip, 'align' => 'E', 'size' => 600)), id(new PhutilUTF8StringTruncator())->setMaximumGlyphs(9)->setTerminator('')->truncateString($line['commit']));
                 $revision_id = null;
                 if (idx($commits, $commit)) {
                     $revision_id = idx($revision_ids, $commits[$commit]->getPHID());
                 }
                 if ($revision_id) {
                     $revision = idx($revisions, $revision_id);
                     if ($revision) {
                         $tooltip = $this->renderRevisionTooltip($revision, $handles);
                         $revision_link = javelin_tag('a', array('href' => '/D' . $revision->getID(), 'sigil' => 'has-tooltip', 'meta' => array('tip' => $tooltip, 'align' => 'E', 'size' => 600)), 'D' . $revision->getID());
                     }
                 }
                 $uri = $line_href->alter('before', $commit);
                 $before_link = javelin_tag('a', array('href' => $uri->setQueryParam('view', 'blame'), 'sigil' => 'has-tooltip', 'meta' => array('tip' => pht('Skip Past This Commit'), 'align' => 'E', 'size' => 300)), "«");
             }
             $blame[] = phutil_tag('th', array('class' => 'diffusion-blame-link'), $before_link);
             $object_links = array();
             $object_links[] = $commit_link;
             if ($revision_link) {
                 $object_links[] = phutil_tag('span', array(), '/');
                 $object_links[] = $revision_link;
             }
             $blame[] = phutil_tag('th', array('class' => 'diffusion-rev-link'), $object_links);
         }
         $line_link = phutil_tag('a', array('href' => $line_href, 'style' => $style), $line['line']);
         $blame[] = javelin_tag('th', array('class' => 'diffusion-line-link', 'sigil' => 'phabricator-source-line', 'style' => $style), $line_link);
         Javelin::initBehavior('phabricator-line-linker');
         if ($line['target']) {
             Javelin::initBehavior('diffusion-jump-to', array('target' => 'scroll_target'));
             $anchor_text = phutil_tag('a', array('id' => 'scroll_target'), '');
         } else {
             $anchor_text = null;
         }
         $blame[] = phutil_tag('td', array(), array($anchor_text, "​", phutil_safe_html(str_replace("\t", '  ', $line['data']))));
         if ($this->coverage) {
             require_celerity_resource('differential-changeset-view-css');
             $cov_index = $line['line'] - 1;
             if (isset($this->coverage[$cov_index])) {
                 $cov_class = $this->coverage[$cov_index];
             } else {
                 $cov_class = 'N';
             }
             $blame[] = phutil_tag('td', array('class' => 'cov cov-' . $cov_class), '');
         }
         $rows[] = phutil_tag('tr', array('class' => $line['highlighted'] ? 'phabricator-source-highlight' : null), $blame);
         $cur_inlines = $this->renderInlines(idx($inlines, $line['line'], array()), $show_blame, $this->coverage, $engine);
         foreach ($cur_inlines as $cur_inline) {
             $rows[] = $cur_inline;
         }
     }
     return $rows;
 }
 protected function getHead()
 {
     $monospaced = PhabricatorEnv::getEnvConfig('style.monospace');
     $monospaced_win = PhabricatorEnv::getEnvConfig('style.monospace.windows');
     $request = $this->getRequest();
     if ($request) {
         $user = $request->getUser();
         if ($user) {
             $pref = $user->loadPreferences()->getPreference(PhabricatorUserPreferences::PREFERENCE_MONOSPACED);
             $monospaced = nonempty($pref, $monospaced);
             $monospaced_win = nonempty($pref, $monospaced_win);
         }
     }
     $response = CelerityAPI::getStaticResourceResponse();
     return hsprintf('%s<style type="text/css">' . '.PhabricatorMonospaced, ' . '.phabricator-remarkup .remarkup-code-block { font: %s; } ' . '.platform-windows .PhabricatorMonospaced, ' . '.platform-windows .phabricator-remarkup ' . '.remarkup-code-block { font: %s; }' . '</style>%s', parent::getHead(), phutil_safe_html($monospaced), phutil_safe_html($monospaced_win), $response->renderSingleResource('javelin-magical-init', 'phabricator'));
 }