Пример #1
0
// Formula experiment
function formulas_qrow($i, $q, $s, $errf)
{
    if ($q === "all") {
        $q = "";
    }
    $klass = ($errf ? "setting_error " : "") . "hotcrp_searchbox";
    $t = '<tr><td class="lentry">' . Ht::entry("q{$i}", $q, array("size" => 40, "placeholder" => "(All)", "class" => $klass));
    $t .= " <span style=\"padding-left:1em\">Style:</span> &nbsp;" . Ht::select("s{$i}", array("plain" => "plain", "by-tag" => "by tag", "redtag" => "red", "orangetag" => "orange", "yellowtag" => "yellow", "greentag" => "green", "bluetag" => "blue", "purpletag" => "purple", "graytag" => "gray"), $s !== "" ? $s : "by-tag");
    $t .= '</td><td class="nw"><a href="#" class="qx row_up" onclick="return author_change(this,-1)" tabindex="-1">&#x25b2;</a><a href="#" class="qx row_down" onclick="return author_change(this,1)" tabindex="-1">&#x25bc;</a><a href="#" class="qx row_kill" onclick="return author_change(this,Infinity)" tabindex="-1">x</a></td></tr>';
    return $t;
}
if ($Graph == "formula") {
    // derive a sample graph
    if (!isset($_REQUEST["fx"]) || !isset($_REQUEST["fy"])) {
        $all_review_fields = ReviewForm::all_fields();
        $field1 = @$all_review_fields["overAllMerit"];
        $field2 = null;
        foreach ($all_review_fields as $f) {
            if ($f->has_options && !$field1) {
                $field1 = $f;
            } else {
                if ($f->has_options && !$field2 && $field1 != $f) {
                    $field2 = $f;
                }
            }
        }
        unset($_REQUEST["fx"], $_REQUEST["fy"]);
        if ($field1) {
            $_REQUEST["fy"] = "avg(" . $field1->analyze()->abbreviation . ")";
        }
 public static function lookup_all()
 {
     $reg = array();
     foreach (ReviewForm::all_fields() as $f) {
         if ($c = self::_make_column($f->id)) {
             $reg[$f->display_order] = $c;
         }
     }
     ksort($reg);
     return $reg;
 }
Пример #3
0
     if (isset($_REQUEST[$x])) {
         echo Ht::hidden($x, $_REQUEST[$x]);
     }
 }
 echo "<table><tr><td><strong>Show:</strong> &nbsp;</td>\n  <td class='pad'>";
 $Conf->footerScript('foldmap.ul={"aff":2,"tags":3,"topics":1};');
 foreach (array("aff" => "Affiliations", "collab" => "Collaborators", "tags" => "Tags", "topics" => "Topics") as $fold => $text) {
     if (@$pl->have_folds[$fold] !== null) {
         echo Ht::checkbox("show{$fold}", 1, $pl->have_folds[$fold], array("onchange" => "fold('ul',!this.checked,'{$fold}')")), "&nbsp;", Ht::label($text), "<br />\n";
     }
 }
 echo "</td>";
 if (isset($pl->scoreMax)) {
     echo "<td class='pad'>";
     $revViewScore = $Me->aggregated_view_score_bound();
     foreach (ReviewForm::all_fields() as $f) {
         if ($f->view_score > $revViewScore && $f->has_options) {
             $checked = strpos(displayOptionsSet("uldisplay"), $f->id) !== false;
             echo Ht::checkbox("show{$f->id}", 1, $checked), "&nbsp;", Ht::label($f->name_html), "<br />";
         }
     }
     echo "</td>";
 }
 echo "<td>", Ht::submit("redisplay", "Redisplay"), "</td></tr>\n";
 if (isset($pl->scoreMax)) {
     $ss = array();
     foreach (array("A", "V", "D") as $k) {
         /* ghetto array_intersect_key */
         if (isset(ListSorter::$score_sorts[$k])) {
             $ss[$k] = ListSorter::$score_sorts[$k];
         }
Пример #4
0
 function paperQuery($contact, $options = array())
 {
     // Options:
     //   "paperId" => $pid  Only paperId $pid (if array, any of those)
     //   "reviewId" => $rid Only paper reviewed by $rid
     //   "commentId" => $c  Only paper where comment is $c
     //   "finalized"        Only submitted papers
     //   "unsub"            Only unsubmitted papers
     //   "accepted"         Only accepted papers
     //   "active"           Only nonwithdrawn papers
     //   "author"           Only papers authored by $contactId
     //   "myReviewRequests" Only reviews requested by $contactId
     //   "myReviews"        All reviews authored by $contactId
     //   "myOutstandingReviews" All unsubmitted reviews auth by $contactId
     //   "myReviewsOpt"     myReviews, + include papers not yet reviewed
     //   "allReviews"       All reviews (multiple rows per paper)
     //   "allReviewScores"  All review scores (multiple rows per paper)
     //   "allComments"      All comments (multiple rows per paper)
     //   "reviewerName"     Include reviewer names
     //   "commenterName"    Include commenter names
     //   "reviewer" => $cid Include reviewerConflictType/reviewerReviewType
     //   "tags"             Include paperTags
     //   "tagIndex" => $tag Include tagIndex of named tag
     //   "tagIndex" => tag array -- include tagIndex, tagIndex1, ...
     //   "topics"
     //   "options"
     //   "scores" => array(fields to score)
     //   "assignments"
     //   "order" => $sql    $sql is SQL 'order by' clause (or empty)
     global $Opt;
     $reviewerQuery = isset($options["myReviews"]) || isset($options["allReviews"]) || isset($options["myReviewRequests"]) || isset($options["myReviewsOpt"]) || isset($options["myOutstandingReviews"]);
     $allReviewerQuery = isset($options["allReviews"]) || isset($options["allReviewScores"]);
     $scoresQuery = !$reviewerQuery && isset($options["allReviewScores"]);
     if (is_object($contact)) {
         $contactId = $contact->contactId;
     } else {
         $contactId = (int) $contact;
         $contact = null;
     }
     if (isset($options["reviewer"]) && is_object($options["reviewer"])) {
         $reviewerContactId = $options["reviewer"]->contactId;
     } else {
         if (isset($options["reviewer"])) {
             $reviewerContactId = $options["reviewer"];
         } else {
             $reviewerContactId = $contactId;
         }
     }
     if (get($options, "author")) {
         $myPaperReview = null;
     } else {
         if ($allReviewerQuery) {
             $myPaperReview = "MyPaperReview";
         } else {
             $myPaperReview = "PaperReview";
         }
     }
     // paper selection
     $paperset = array();
     if (isset($options["paperId"])) {
         $paperset[] = self::_cvt_numeric_set($options["paperId"]);
     }
     if (isset($options["reviewId"])) {
         if (is_numeric($options["reviewId"])) {
             $result = Dbl::qe("select paperId from PaperReview where reviewId=" . $options["reviewId"]);
             $paperset[] = self::_cvt_numeric_set(edb_first_columns($result));
         } else {
             if (preg_match('/^(\\d+)([A-Z][A-Z]?)$/i', $options["reviewId"], $m)) {
                 $result = Dbl::qe("select paperId from PaperReview where paperId={$m['1']} and reviewOrdinal=" . parseReviewOrdinal($m[2]));
                 $paperset[] = self::_cvt_numeric_set(edb_first_columns($result));
             } else {
                 $paperset[] = array();
             }
         }
     }
     if (isset($options["commentId"])) {
         $result = Dbl::qe("select paperId from PaperComment where commentId" . sql_in_numeric_set(self::_cvt_numeric_set($options["commentId"])));
         $paperset[] = self::_cvt_numeric_set(edb_first_columns($result));
     }
     if (count($paperset) > 1) {
         $paperset = array(call_user_func_array("array_intersect", $paperset));
     }
     $papersel = "";
     if (count($paperset)) {
         $papersel = "paperId" . sql_in_numeric_set($paperset[0]) . " and ";
     }
     // prepare query: basic tables
     $where = array();
     $joins = array("Paper");
     $cols = array("Paper.*, PaperConflict.conflictType");
     $aujoinwhere = null;
     if (get($options, "author") && $contact && ($aujoinwhere = $contact->actAuthorSql("PaperConflict", true))) {
         $where[] = $aujoinwhere;
     }
     if (get($options, "author") && !$aujoinwhere) {
         $joins[] = "join PaperConflict on (PaperConflict.paperId=Paper.paperId and PaperConflict.contactId={$contactId} and PaperConflict.conflictType>=" . CONFLICT_AUTHOR . ")";
     } else {
         $joins[] = "left join PaperConflict on (PaperConflict.paperId=Paper.paperId and PaperConflict.contactId={$contactId})";
     }
     // my review
     $qr = "";
     if ($contact && ($tokens = $contact->review_tokens())) {
         $qr = " or PaperReview.reviewToken in (" . join(", ", $tokens) . ")";
     }
     if (get($options, "myReviewRequests")) {
         $joins[] = "join PaperReview on (PaperReview.paperId=Paper.paperId and PaperReview.requestedBy={$contactId} and PaperReview.reviewType=" . REVIEW_EXTERNAL . ")";
     } else {
         if (get($options, "myReviews")) {
             $joins[] = "join PaperReview on (PaperReview.paperId=Paper.paperId and (PaperReview.contactId={$contactId}{$qr}))";
         } else {
             if (get($options, "myOutstandingReviews")) {
                 $joins[] = "join PaperReview on (PaperReview.paperId=Paper.paperId and (PaperReview.contactId={$contactId}{$qr}) and PaperReview.reviewNeedsSubmit!=0)";
             } else {
                 if (get($options, "myReviewsOpt")) {
                     $joins[] = "left join PaperReview on (PaperReview.paperId=Paper.paperId and (PaperReview.contactId={$contactId}{$qr}))";
                 } else {
                     if (get($options, "allReviews") || get($options, "allReviewScores")) {
                         $x = get($options, "reviewLimitSql") ? " and (" . $options["reviewLimitSql"] . ")" : "";
                         $joins[] = "join PaperReview on (PaperReview.paperId=Paper.paperId{$x})";
                     } else {
                         if (!get($options, "author")) {
                             $joins[] = "left join PaperReview on (PaperReview.paperId=Paper.paperId and (PaperReview.contactId={$contactId}{$qr}))";
                         }
                     }
                 }
             }
         }
     }
     // started reviews
     if (get($options, "startedReviewCount")) {
         $joins[] = "left join (select paperId, count(*) count from PaperReview where {$papersel}(reviewSubmitted or reviewNeedsSubmit>0) group by paperId) R_started on (R_started.paperId=Paper.paperId)";
         $cols[] = "coalesce(R_started.count,0) startedReviewCount";
     }
     // submitted reviews
     $j = "select paperId, count(*) count";
     $before_ncols = count($cols);
     if (get($options, "startedReviewCount")) {
         $cols[] = "coalesce(R_submitted.count,0) reviewCount";
     }
     if (get($options, "scores")) {
         foreach ($options["scores"] as $fid) {
             $cols[] = "R_submitted.{$fid}Scores";
             if ($myPaperReview) {
                 $cols[] = "{$myPaperReview}.{$fid}";
             }
             $j .= ", group_concat({$fid} order by reviewId) {$fid}Scores";
         }
     }
     if (get($options, "reviewTypes") || get($options, "reviewIdentities")) {
         $cols[] = "R_submitted.reviewTypes";
         $j .= ", group_concat(reviewType order by reviewId) reviewTypes";
     }
     if (get($options, "reviewIdentities")) {
         $cols[] = "R_submitted.reviewRequestedBys";
         $j .= ", group_concat(requestedBy order by reviewId) reviewRequestedBys";
         if ($this->review_blindness() == self::BLIND_OPTIONAL) {
             $cols[] = "R_submitted.reviewBlinds";
             $j .= ", group_concat(reviewBlind order by reviewId) reviewBlinds";
         }
         if ($contact && $contact->review_tokens()) {
             $cols[] = "R_submitted.reviewTokens";
             $j .= ", group_concat(reviewToken order by reviewId) reviewTokens";
         }
     }
     if (get($options, "reviewRounds")) {
         $cols[] = "R_submitted.reviewRounds";
         $j .= ", group_concat(reviewRound order by reviewId) reviewRounds";
     }
     if (get($options, "reviewWordCounts") && $this->sversion >= 99) {
         $cols[] = "R_submitted.reviewWordCounts";
         $j .= ", group_concat(reviewWordCount order by reviewId) reviewWordCounts";
     }
     if (get($options, "reviewOrdinals")) {
         $cols[] = "R_submitted.reviewOrdinals";
         $j .= ", group_concat(reviewOrdinal order by reviewId) reviewOrdinals";
     }
     if (get($options, "reviewTypes") || get($options, "scores") || get($options, "reviewContactIds") || get($options, "reviewOrdinals") || get($options, "reviewIdentities")) {
         $cols[] = "R_submitted.reviewContactIds";
         $j .= ", group_concat(contactId order by reviewId) reviewContactIds";
     }
     if (count($cols) != $before_ncols) {
         $joins[] = "left join ({$j} from PaperReview where {$papersel}reviewSubmitted>0 group by paperId) R_submitted on (R_submitted.paperId=Paper.paperId)";
     }
     // assignments
     if (get($options, "assignments")) {
         $j = "select paperId, group_concat(contactId order by reviewId) allReviewContactIds, group_concat(reviewType order by reviewId) allReviewTypes, group_concat(reviewRound order by reviewId) allReviewRounds";
         $cols[] = "R_all.allReviewContactIds, R_all.allReviewTypes, R_all.allReviewRounds";
         $joins[] = "left join ({$j} from PaperReview where {$papersel}true group by paperId) R_all on (R_all.paperId=Paper.paperId)";
     }
     // fields
     if (get($options, "author")) {
         $cols[] = "null reviewType, null reviewId, null myReviewType";
     } else {
         // see also papercolumn.php
         array_push($cols, "PaperReview.reviewType, PaperReview.reviewId", "PaperReview.reviewModified, PaperReview.reviewSubmitted", "PaperReview.reviewNeedsSubmit, PaperReview.reviewOrdinal", "PaperReview.reviewBlind, PaperReview.reviewToken", "PaperReview.contactId as reviewContactId, PaperReview.requestedBy", "max({$myPaperReview}.reviewType) as myReviewType", "max({$myPaperReview}.reviewSubmitted) as myReviewSubmitted", "min({$myPaperReview}.reviewNeedsSubmit) as myReviewNeedsSubmit", "{$myPaperReview}.contactId as myReviewContactId", "PaperReview.reviewRound");
     }
     if ($reviewerQuery || $scoresQuery) {
         $cols[] = "PaperReview.reviewEditVersion as reviewEditVersion";
         $cols[] = ($this->sversion >= 105 ? "PaperReview.reviewFormat" : "null") . " as reviewFormat";
         foreach (ReviewForm::all_fields() as $f) {
             if ($reviewerQuery || $f->has_options) {
                 $cols[] = "PaperReview.{$f->id} as {$f->id}";
             }
         }
     }
     if ($myPaperReview == "MyPaperReview") {
         $joins[] = "left join PaperReview as MyPaperReview on (MyPaperReview.paperId=Paper.paperId and MyPaperReview.contactId={$contactId})";
     }
     if (get($options, "topics")) {
         $cols[] = "(select group_concat(topicId) from PaperTopic where PaperTopic.paperId=Paper.paperId) topicIds";
     }
     if (get($options, "options") && (isset($this->settingTexts["options"]) || isset($Opt["optionsInclude"])) && PaperOption::count_option_list()) {
         $cols[] = "(select group_concat(PaperOption.optionId, '#', value) from PaperOption where paperId=Paper.paperId) optionIds";
     } else {
         if (get($options, "options")) {
             $cols[] = "'' as optionIds";
         }
     }
     if (get($options, "tags")) {
         $cols[] = "(select group_concat(' ', tag, '#', tagIndex order by tag separator '') from PaperTag where PaperTag.paperId=Paper.paperId) paperTags";
     }
     if (get($options, "tagIndex") && !is_array($options["tagIndex"])) {
         $options["tagIndex"] = array($options["tagIndex"]);
     }
     if (get($options, "tagIndex")) {
         foreach ($options["tagIndex"] as $i => $tag) {
             $cols[] = "(select tagIndex from PaperTag where PaperTag.paperId=Paper.paperId and PaperTag.tag='" . sqlq($tag) . "') tagIndex" . ($i ?: "");
         }
     }
     if (get($options, "reviewerPreference")) {
         $joins[] = "left join PaperReviewPreference on (PaperReviewPreference.paperId=Paper.paperId and PaperReviewPreference.contactId={$reviewerContactId})";
         $cols[] = "coalesce(PaperReviewPreference.preference, 0) as reviewerPreference";
         $cols[] = "PaperReviewPreference.expertise as reviewerExpertise";
     }
     if (get($options, "allReviewerPreference") || get($options, "desirability")) {
         $subq = "select paperId";
         if (get($options, "allReviewerPreference")) {
             $subq .= ", " . $this->query_all_reviewer_preference() . " as allReviewerPreference";
             $cols[] = "APRP.allReviewerPreference";
         }
         if (get($options, "desirability")) {
             $subq .= ", sum(if(preference<=-100,0,greatest(least(preference,1),-1))) as desirability";
             $cols[] = "coalesce(APRP.desirability,0) as desirability";
         }
         $subq .= " from PaperReviewPreference where {$papersel}true group by paperId";
         $joins[] = "left join ({$subq}) as APRP on (APRP.paperId=Paper.paperId)";
     }
     if (get($options, "allConflictType")) {
         $joins[] = "left join (select paperId, group_concat(concat(contactId,' ',conflictType) separator ',') as allConflictType from PaperConflict where {$papersel}conflictType>0 group by paperId) as AllConflict on (AllConflict.paperId=Paper.paperId)";
         $cols[] = "AllConflict.allConflictType";
     }
     if (get($options, "reviewer")) {
         $joins[] = "left join PaperConflict RPC on (RPC.paperId=Paper.paperId and RPC.contactId={$reviewerContactId})";
         $joins[] = "left join PaperReview RPR on (RPR.paperId=Paper.paperId and RPR.contactId={$reviewerContactId})";
         $cols[] = "RPC.conflictType reviewerConflictType, RPR.reviewType reviewerReviewType";
     }
     if (get($options, "allComments")) {
         $joins[] = "join PaperComment on (PaperComment.paperId=Paper.paperId)";
         $joins[] = "left join PaperConflict as CommentConflict on (CommentConflict.paperId=PaperComment.paperId and CommentConflict.contactId=PaperComment.contactId)";
         array_push($cols, "PaperComment.commentId, PaperComment.contactId as commentContactId", "CommentConflict.conflictType as commentConflictType", "PaperComment.timeModified, PaperComment.comment", "PaperComment.replyTo, PaperComment.commentType");
     }
     if (get($options, "reviewerName")) {
         if ($options["reviewerName"] === "lead" || $options["reviewerName"] === "shepherd") {
             $joins[] = "left join ContactInfo as ReviewerContactInfo on (ReviewerContactInfo.contactId=Paper." . $options['reviewerName'] . "ContactId)";
         } else {
             if (get($options, "allComments")) {
                 $joins[] = "left join ContactInfo as ReviewerContactInfo on (ReviewerContactInfo.contactId=PaperComment.contactId)";
             } else {
                 if (get($options, "reviewerName")) {
                     $joins[] = "left join ContactInfo as ReviewerContactInfo on (ReviewerContactInfo.contactId=PaperReview.contactId)";
                 }
             }
         }
         array_push($cols, "ReviewerContactInfo.firstName as reviewFirstName", "ReviewerContactInfo.lastName as reviewLastName", "ReviewerContactInfo.email as reviewEmail", "ReviewerContactInfo.lastLogin as reviewLastLogin");
     }
     if (get($options, "foldall")) {
         $cols[] = "1 as folded";
     }
     // conditions
     if (count($paperset)) {
         $where[] = "Paper.paperId" . sql_in_numeric_set($paperset[0]);
     }
     if (get($options, "finalized")) {
         $where[] = "timeSubmitted>0";
     } else {
         if (get($options, "unsub")) {
             $where[] = "timeSubmitted<=0";
         }
     }
     if (get($options, "accepted")) {
         $where[] = "outcome>0";
     }
     if (get($options, "undecided")) {
         $where[] = "outcome=0";
     }
     if (get($options, "active") || get($options, "myReviews") || get($options, "myReviewRequests")) {
         $where[] = "timeWithdrawn<=0";
     }
     if (get($options, "myLead")) {
         $where[] = "leadContactId={$contactId}";
     }
     if (get($options, "unmanaged")) {
         $where[] = "managerContactId=0";
     }
     $pq = "select " . join(",\n    ", $cols) . "\nfrom " . join("\n    ", $joins);
     if (count($where)) {
         $pq .= "\nwhere " . join("\n    and ", $where);
     }
     // grouping and ordering
     if (get($options, "allComments")) {
         $pq .= "\ngroup by Paper.paperId, PaperComment.commentId";
     } else {
         if ($reviewerQuery || $scoresQuery) {
             $pq .= "\ngroup by Paper.paperId, PaperReview.reviewId";
         } else {
             $pq .= "\ngroup by Paper.paperId";
         }
     }
     if (get($options, "order") && $options["order"] != "order by Paper.paperId") {
         $pq .= "\n" . $options["order"];
     } else {
         $pq .= "\norder by Paper.paperId";
         if ($reviewerQuery || $scoresQuery) {
             $pq .= ", PaperReview.reviewOrdinal";
         }
         if (isset($options["allComments"])) {
             $pq .= ", PaperComment.commentId";
         }
     }
     //Conf::msg_debugt($pq);
     return $pq . "\n";
 }
Пример #5
0
function searchQuickref()
{
    global $rowidx, $Conf, $Opt, $Me;
    // how to report author searches?
    if ($Conf->subBlindNever()) {
        $aunote = "";
    } else {
        if (!$Conf->subBlindAlways()) {
            $aunote = "<br /><span class='hint'>Search uses fields visible to the searcher. For example, PC member searches do not examine anonymous authors.</span>";
        } else {
            $aunote = "<br /><span class='hint'>Search uses fields visible to the searcher. For example, PC member searches do not examine authors.</span>";
        }
    }
    // does a reviewer tag exist?
    $retag = meaningful_pc_tag() ?: "";
    _searchQuickrefRow("Basics", "", "all papers in the search category");
    _searchQuickrefRow("", "story", "“story” in title, abstract, authors{$aunote}");
    _searchQuickrefRow("", "119", "paper #119");
    _searchQuickrefRow("", "1 2 5 12-24 kernel", "papers in the numbered set with “kernel” in title, abstract, authors");
    _searchQuickrefRow("", "\"802\"", "“802” in title, abstract, authors (not paper #802)");
    _searchQuickrefRow("", "very new", "“very” <em>and</em> “new” in title, abstract, authors");
    _searchQuickrefRow("", "very AND new", "the same");
    _searchQuickrefRow("", "\"very new\"", "the phrase “very new” in title, abstract, authors");
    _searchQuickrefRow("", "very OR new", "<em>either</em> “very” <em>or</em> “new” in title, abstract, authors");
    _searchQuickrefRow("", "(very AND new) OR newest", "use parentheses to group");
    _searchQuickrefRow("", "very -new", "“very” <em>but not</em> “new” in title, abstract, authors");
    _searchQuickrefRow("", "very NOT new", "the same");
    _searchQuickrefRow("", "ve*", "words that <em>start with</em> “ve” in title, abstract, authors");
    _searchQuickrefRow("", "*me*", "words that <em>contain</em> “me” in title, abstract, authors");
    _searchQuickrefRow("Title", "ti:flexible", "title contains “flexible”");
    _searchQuickrefRow("Abstract", "ab:\"very novel\"", "abstract contains “very novel”");
    _searchQuickrefRow("Authors", "au:poletto", "author list contains “poletto”");
    if ($Me->isPC) {
        _searchQuickrefRow("", "au:pc", "one or more authors are PC members (author email matches PC email)");
    }
    _searchQuickrefRow("Collaborators", "co:liskov", "collaborators contains “liskov”");
    _searchQuickrefRow("Topics", "topic:link", "selected topics match “link”");
    $oex = array();
    foreach (PaperOption::option_list() as $o) {
        $oex = array_merge($oex, $o->example_searches());
    }
    if (count($oex)) {
        $section = "Options";
        foreach ($oex as $extype => $oex) {
            if ($extype === "has") {
                $desc = "paper has “" . htmlspecialchars($oex[1]->name) . "” submission option";
                $oabbr = array();
                foreach (PaperOption::option_list() as $ox) {
                    if ($ox !== $oex[1]) {
                        $oabbr[] = "“has:" . htmlspecialchars($ox->abbr) . "”";
                    }
                }
                if (count($oabbr)) {
                    $desc .= '<div class="hint">Other option ' . pluralx(count($oabbr), "search") . ': ' . commajoin($oabbr) . '</div>';
                }
            } else {
                if ($extype === "yes") {
                    $desc = "same meaning; abbreviations also accepted";
                } else {
                    if ($extype === "numeric") {
                        $desc = "paper’s “" . htmlspecialchars($oex[1]->name) . "” option has value &gt; 100";
                    } else {
                        if ($extype === "selector") {
                            $desc = "paper’s “" . htmlspecialchars($oex[1]->name) . "” option has value “" . htmlspecialchars($oex[1]->selector[1]) . "”";
                        } else {
                            if ($extype === "attachment-count") {
                                $desc = "paper has more than 2 “" . htmlspecialchars($oex[1]->name) . "” attachments";
                            } else {
                                if ($extype === "attachment-filename") {
                                    $desc = "paper has an “" . htmlspecialchars($oex[1]->name) . "” attachment with a .gif extension";
                                } else {
                                    continue;
                                }
                            }
                        }
                    }
                }
            }
            _searchQuickrefRow($section, $oex[0], $desc);
            $section = "";
        }
    }
    _searchQuickrefRow("<a href='" . hoturl("help", "t=tags") . "'>Tags</a>", "#discuss", "tagged “discuss” (“tag:discuss” also works)");
    _searchQuickrefRow("", "-#discuss", "not tagged “discuss”");
    _searchQuickrefRow("", "order:discuss", "tagged “discuss”, sort by tag order (“rorder:” for reverse order)");
    _searchQuickrefRow("", "#disc*", "matches any tag that <em>starts with</em> “disc”");
    $cx = null;
    $cm = array();
    foreach (TagInfo::defined_tags() as $t) {
        foreach ($t->colors ?: array() as $c) {
            $cx = $cx ?: $c;
            if ($cx === $c) {
                $cm[] = "“{$t->tag}”";
            }
        }
    }
    if (count($cm)) {
        array_unshift($cm, "“{$cx}”");
        _searchQuickrefRow("", "style:{$cx}", "tagged to appear {$cx} (tagged " . commajoin($cm, "or") . ")");
    }
    _searchQuickrefRow("Reviews", "re:me", "you are a reviewer");
    _searchQuickrefRow("", "re:fdabek", "“fdabek” in reviewer name/email");
    if ($retag) {
        _searchQuickrefRow("", "re:#{$retag}", "has a reviewer tagged “#" . $retag . "”");
    }
    _searchQuickrefRow("", "re:4", "four reviewers (assigned and/or completed)");
    if ($retag) {
        _searchQuickrefRow("", "re:#{$retag}>1", "at least two reviewers (assigned and/or completed) tagged “#" . $retag . "”");
    }
    _searchQuickrefRow("", "re:complete<3", "less than three completed reviews<br /><span class=\"hint\">Use “cre:<3” for short.</span>");
    _searchQuickrefRow("", "re:incomplete>0", "at least one incomplete review");
    _searchQuickrefRow("", "re:inprogress", "at least one in-progress review (started, but not completed)");
    _searchQuickrefRow("", "re:primary>=2", "at least two primary reviewers");
    _searchQuickrefRow("", "re:secondary", "at least one secondary reviewer");
    _searchQuickrefRow("", "re:external", "at least one external reviewer");
    _searchQuickrefRow("", "re:primary:fdabek:complete", "“fdabek” has completed a primary review");
    if ($r = meaningful_round_name()) {
        _searchQuickrefRow("", "re:{$r}", "review in round “" . htmlspecialchars($r) . "”");
    }
    _searchQuickrefRow("", "re:auwords<100", "has a review with less than 100 words in author-visible fields");
    if ($Conf->setting("rev_ratings") != REV_RATINGS_NONE) {
        _searchQuickrefRow("", "rate:+", "review was rated positively (“rate:-” and “rate:+>2” also work; can combine with “re:”)");
    }
    _searchQuickrefRow("Comments", "has:cmt", "at least one visible reviewer comment (not including authors’ response)");
    _searchQuickrefRow("", "cmt:>=3", "at least <em>three</em> visible reviewer comments");
    _searchQuickrefRow("", "has:aucmt", "at least one reviewer comment visible to authors");
    _searchQuickrefRow("", "cmt:sylvia", "“sylvia” (in name/email) wrote at least one visible comment; can combine with counts, use reviewer tags");
    $rnames = $Conf->resp_round_list();
    if (count($rnames) > 1) {
        _searchQuickrefRow("", "has:response", "has an author’s response");
        _searchQuickrefRow("", "has:{$rnames[1]}response", "has {$rnames['1']} response");
    } else {
        _searchQuickrefRow("", "has:response", "has author’s response");
    }
    _searchQuickrefRow("", "anycmt:>1", "at least two visible comments, possibly <em>including</em> author’s response");
    _searchQuickrefRow("Leads", "lead:fdabek", "“fdabek” (in name/email) is discussion lead");
    _searchQuickrefRow("", "lead:none", "no assigned discussion lead");
    _searchQuickrefRow("", "lead:any", "some assigned discussion lead");
    _searchQuickrefRow("Shepherds", "shep:fdabek", "“fdabek” (in name/email) is shepherd (“none” and “any” also work)");
    _searchQuickrefRow("Conflicts", "conflict:me", "you have a conflict with the paper");
    _searchQuickrefRow("", "conflict:fdabek", "“fdabek” (in name/email) has a conflict with the paper<br /><span class='hint'>This search is only available to chairs and to PC members who can see the paper’s author list.</span>");
    _searchQuickrefRow("", "conflict:pc", "some PC member has a conflict with the paper");
    _searchQuickrefRow("", "conflict:pc>2", "at least three PC members have conflicts with the paper");
    _searchQuickrefRow("", "reconflict:\"1 2 3\"", "a reviewer of paper 1, 2, or 3 has a conflict with the paper");
    _searchQuickrefRow("Preferences", "pref:fdabek>0", "“fdabek” (in name/email) has review preference &gt;&nbsp;0<br /><span class='hint'>PC members can search their own preferences; chairs can search anyone’s preferences.</span>");
    _searchQuickrefRow("", "pref:X", "some PC member has a preference expertise of “X” (expert)");
    _searchQuickrefRow("Status", "status:sub", "paper is submitted for review", "t=all");
    _searchQuickrefRow("", "status:unsub", "paper is neither submitted nor withdrawn", "t=all");
    _searchQuickrefRow("", "status:withdrawn", "paper has been withdrawn", "t=all");
    _searchQuickrefRow("", "has:final", "final copy uploaded");
    foreach ($Conf->decision_map() as $dnum => $dname) {
        if ($dnum) {
            break;
        }
    }
    $qdname = strtolower($dname);
    if (strpos($qdname, " ") !== false) {
        $qdname = "\"{$qdname}\"";
    }
    _searchQuickrefRow("Decision", "dec:{$qdname}", "decision is “" . htmlspecialchars($dname) . "” (partial matches OK)");
    _searchQuickrefRow("", "dec:yes", "one of the accept decisions");
    _searchQuickrefRow("", "dec:no", "one of the reject decisions");
    _searchQuickrefRow("", "dec:any", "decision specified");
    _searchQuickrefRow("", "dec:none", "decision unspecified");
    // find names of review fields to demonstrate syntax
    $farr = array(array(), array());
    foreach (ReviewForm::all_fields() as $f) {
        $fx = $f->has_options ? 0 : 1;
        $farr[$fx][] = $f->analyze();
    }
    $t = "Review&nbsp;fields";
    if (count($farr[0])) {
        $r = $farr[0][0];
        _searchQuickrefRow($t, $r->abbreviation1() . ":{$r->typical_score}", "at least one completed review has {$r->name_html} score {$r->typical_score}");
        _searchQuickrefRow("", "{$r->abbreviation}:{$r->typical_score}", "other abbreviations accepted");
        if (count($farr[0]) > 1) {
            $r2 = $farr[0][1];
            _searchQuickrefRow("", strtolower($r2->abbreviation) . ":{$r2->typical_score}", "other fields accepted (here, {$r2->name_html})");
        }
        if (isset($r->typical_score_range)) {
            _searchQuickrefRow("", "{$r->abbreviation}:{$r->typical_score0}..{$r->typical_score}", "completed reviews’ {$r->name_html} scores are in the {$r->typical_score0}&ndash;{$r->typical_score} range<br /><small>(all scores between {$r->typical_score0} and {$r->typical_score})</small>");
            _searchQuickrefRow("", "{$r->abbreviation}:{$r->typical_score_range}", "completed reviews’ {$r->name_html} scores <em>fill</em> the {$r->typical_score0}&ndash;{$r->typical_score} range<br /><small>(all scores between {$r->typical_score0} and {$r->typical_score}, with at least one {$r->typical_score0} and at least one {$r->typical_score})</small>");
        }
        if (!$r->option_letter) {
            list($greater, $less, $hint) = array("greater", "less", "");
        } else {
            $hint = "<br /><small>(better scores are closer to A than Z)</small>";
            if (defval($Opt, "smartScoreCompare")) {
                list($greater, $less) = array("better", "worse");
            } else {
                list($greater, $less) = array("worse", "better");
            }
        }
        _searchQuickrefRow("", "{$r->abbreviation}:>{$r->typical_score}", "at least one completed review has {$r->name_html} score {$greater} than {$r->typical_score}" . $hint);
        _searchQuickrefRow("", "{$r->abbreviation}:2<={$r->typical_score}", "at least two completed reviews have {$r->name_html} score {$less} than or equal to {$r->typical_score}");
        _searchQuickrefRow("", "{$r->abbreviation}:pc>{$r->typical_score}", "at least one completed PC review has {$r->name_html} score {$greater} than {$r->typical_score}");
        _searchQuickrefRow("", "{$r->abbreviation}:pc:2>{$r->typical_score}", "at least two completed PC reviews have {$r->name_html} score {$greater} than {$r->typical_score}");
        _searchQuickrefRow("", "{$r->abbreviation}:sylvia={$r->typical_score}", "“sylvia” (reviewer name/email) gave {$r->name_html} score {$r->typical_score}");
        $t = "";
    }
    if (count($farr[1])) {
        $r = $farr[1][0];
        _searchQuickrefRow($t, $r->abbreviation1() . ":finger", "at least one completed review has “finger” in the {$r->name_html} field");
        _searchQuickrefRow($t, "{$r->abbreviation}:finger", "other abbreviations accepted");
        _searchQuickrefRow($t, "{$r->abbreviation}:any", "at least one completed review has text in the {$r->name_html} field");
    }
    if (count($farr[0])) {
        $r = $farr[0][0];
        _searchQuickrefRow("<a href=\"" . hoturl("help", "t=formulas") . "\">Formulas</a>", "formula:all({$r->abbreviation}={$r->typical_score})", "all reviews have {$r->name_html} score {$r->typical_score}<br />" . "<span class='hint'><a href=\"" . hoturl("help", "t=formulas") . "\">Formulas</a> can express complex numerical queries across review scores and preferences.</span>");
        _searchQuickrefRow("", "f:all({$r->abbreviation}={$r->typical_score})", "“f” is shorthand for “formula”");
        _searchQuickrefRow("", "formula:var({$r->abbreviation})>0.5", "variance in {$r->abbreviation} is above 0.5");
        _searchQuickrefRow("", "formula:any({$r->abbreviation}={$r->typical_score} && pref<0)", "at least one reviewer had {$r->name_html} score {$r->typical_score} and review preference &lt; 0");
    }
    _searchQuickrefRow("Display", "show:tags show:conflicts", "show tags and PC conflicts in the results");
    _searchQuickrefRow("", "hide:title", "hide title in the results");
    if (count($farr[0])) {
        $r = $farr[0][0];
        _searchQuickrefRow("", "show:max({$r->abbreviation})", "show a <a href=\"" . hoturl("help", "t=formulas") . "\">formula</a>");
        _searchQuickrefRow("", "show:statistics", "show summary statistics for formulas");
        _searchQuickrefRow("", "sort:{$r->abbreviation}", "sort by score");
        _searchQuickrefRow("", "sort:\"{$r->abbreviation} variance\"", "sort by score variance");
    }
    _searchQuickrefRow("", "sort:-status", "sort by reverse status");
    _searchQuickrefRow("", "edit:#discuss", "edit the values for tag “#discuss”");
    _searchQuickrefRow("", "search1 THEN search2", "like “search1 OR search2”, but papers matching “search1” are grouped together and appear earlier in the sorting order");
    _searchQuickrefRow("", "1-5 THEN 6-10 show:compact", "display searches in compact columns");
    _searchQuickrefRow("", "search1 HIGHLIGHT search2", "search for “search1”, but <span class=\"taghl highlightmark\">highlight</span> papers in that list that match “search2” (also try HIGHLIGHT:pink, HIGHLIGHT:green, HIGHLIGHT:blue)");
}
 private function preferences_paperpc($scoreinfo)
 {
     global $Conf;
     $time = microtime(true);
     $this->prefs = array();
     foreach ($this->pcm as $cid => $p) {
         $this->prefs[$cid] = array();
     }
     $all_fields = ReviewForm::all_fields();
     $scoredir = 1;
     if ($scoreinfo === "x") {
         $score = "1";
     } else {
         if ((substr($scoreinfo, 0, 1) === "-" || substr($scoreinfo, 0, 1) === "+") && isset($all_fields[substr($scoreinfo, 1)])) {
             $score = "PaperReview." . substr($scoreinfo, 1);
             $scoredir = substr($scoreinfo, 0, 1) === "-" ? -1 : 1;
         } else {
             $score = "PaperReview.overAllMerit";
         }
     }
     $query = "select Paper.paperId, ? contactId,\n            coalesce(PaperConflict.conflictType, 0) as conflictType,\n            coalesce(PaperReview.reviewType, 0) as myReviewType,\n            coalesce(PaperReview.reviewSubmitted, 0) as myReviewSubmitted,\n            coalesce({$score}, 0) as reviewScore,\n            Paper.outcome,\n            Paper.managerContactId\n        from Paper\n        left join PaperConflict on (PaperConflict.paperId=Paper.paperId and PaperConflict.contactId=?)\n        left join PaperReview on (PaperReview.paperId=Paper.paperId and PaperReview.contactId=?)\n        where Paper.paperId ?a\n        group by Paper.paperId";
     $nmade = 0;
     foreach ($this->pcm as $cid => $p) {
         $result = Dbl::qe($query, $cid, $cid, $cid, $this->papersel);
         // First, collect score extremes
         $scoreextreme = array();
         $rows = array();
         while ($row = edb_orow($result)) {
             if ($row->conflictType > 0 || $row->myReviewType == 0 || $row->myReviewSubmitted == 0 || $row->reviewScore == 0) {
                 $this->prefs[$row->contactId][$row->paperId] = self::PNOASSIGN;
             } else {
                 if (!isset($scoreextreme[$row->paperId]) || $scoredir * $row->reviewScore > $scoredir * $scoreextreme[$row->paperId]) {
                     $scoreextreme[$row->paperId] = $row->reviewScore;
                 }
                 $rows[] = $row;
             }
         }
         // Then, collect preferences; ignore score differences farther
         // than 1 score away from the relevant extreme
         foreach ($rows as $row) {
             $scoredifference = $scoredir * ($row->reviewScore - $scoreextreme[$row->paperId]);
             if ($scoredifference >= -1) {
                 $this->prefs[$row->contactId][$row->paperId] = $scoredifference;
             }
         }
         unset($rows);
         // don't need the memory any more
         Dbl::free($result);
         ++$nmade;
         if ($nmade % 4 == 0) {
             $this->set_progress(sprintf("Loading reviewer preferences (%d%% done)", (int) ($nmade * 100 / count($this->pcm) + 0.5)));
         }
     }
     $this->make_pref_groups();
     $this->profile["preferences"] = microtime(true) - $time;
 }
 function addScores($a)
 {
     global $Conf;
     if ($this->contact->isPC) {
         foreach (ReviewForm::all_fields() as $f) {
             if ($f->has_options && strpos(displayOptionsSet("uldisplay"), " {$f->id} ") !== false) {
                 array_push($a, $f->id);
             }
         }
         $this->scoreMax = array();
     }
     return $a;
 }