Ejemplo n.º 1
0
 public function content($pl, $row)
 {
     global $Conf;
     $prow = edb_rows($Conf->qe("select * from PaperOption where paperId={$row->paperId}"));
     $options = PaperOption::option_list();
     $content = "";
     $q = explode(" ", $pl->search->q);
     foreach ($q as $word) {
         if (strpos($word, ':') === false) {
             continue;
         }
         $keyword = substr($word, 0, strpos($word, ':'));
         $matchingKw = reset(array_filter($options, function ($o) use($keyword) {
             return $this->option_search_term($o->abbr) == $keyword;
         }));
         if (empty($matchingKw)) {
             continue;
         }
         $keywordId = $matchingKw->id;
         $keywordTitle = !empty($matchingKw->description) ? $matchingKw->description : $matchingKw->name;
         $keywordRow = reset(array_filter($prow, function ($k) use($keywordId) {
             return $k[1] == $keywordId;
         }));
         if ($matchingKw->type == "checkbox") {
             if (empty($keywordRow) || !$keywordRow[3] && !$keywordRow[2]) {
                 $value = "no";
             } else {
                 $value = "yes";
             }
         } else {
             if (empty($keywordRow)) {
                 continue;
             }
             $value = !empty($keywordRow[3]) ? $keywordRow[3] : $keywordRow[2];
         }
         $content .= "<br><strong>{$keywordTitle}</strong>: {$value}";
     }
     return $content;
 }
Ejemplo n.º 2
0
 static function user_option_list(Contact $user)
 {
     global $Conf;
     if ($Conf->has_any_accepts() && $user->can_view_some_decision()) {
         return PaperOption::option_list();
     } else {
         return PaperOption::nonfinal_option_list();
     }
 }
Ejemplo n.º 3
0
 function paper_json($prow, $args = array())
 {
     global $Conf;
     if (is_int($prow)) {
         $prow = $Conf->paperRow(["paperId" => $prow, "topics" => true, "options" => true], $this->contact);
     }
     $contact = $this->contact;
     if (get($args, "forceShow")) {
         $contact = null;
     }
     if (!$prow || $contact && !$contact->can_view_paper($prow)) {
         return null;
     }
     $this->prow = $prow;
     $this->paperid = $prow->paperId;
     $pj = (object) array();
     $pj->pid = (int) $prow->paperId;
     $pj->title = $prow->title;
     if ($prow->timeWithdrawn > 0) {
         $pj->status = "withdrawn";
         $pj->withdrawn = true;
         $pj->withdrawn_at = (int) $prow->timeWithdrawn;
         if (get($prow, "withdrawReason")) {
             $pj->withdrawn_reason = $prow->withdrawReason;
         }
     } else {
         if ($prow->timeSubmitted > 0) {
             $pj->status = "submitted";
             $pj->submitted = true;
         } else {
             $pj->status = "inprogress";
             $pj->draft = true;
         }
     }
     if ($prow->timeSubmitted > 0) {
         $pj->submitted_at = (int) $prow->timeSubmitted;
     } else {
         if ($prow->timeSubmitted == -100 && $prow->timeWithdrawn > 0) {
             $pj->submitted_at = 1000000000;
         }
     }
     $can_view_authors = !$contact || $contact->can_view_authors($prow, $this->forceShow);
     if ($can_view_authors) {
         $contacts = array();
         foreach ($prow->named_contacts() as $conf) {
             $contacts[strtolower($conf->email)] = $conf;
         }
         $pj->authors = array();
         foreach ($prow->author_list() as $au) {
             $aux = (object) array();
             if ($au->email) {
                 $aux->email = $au->email;
             }
             if ($au->firstName) {
                 $aux->first = $au->firstName;
             }
             if ($au->lastName) {
                 $aux->last = $au->lastName;
             }
             if ($au->affiliation) {
                 $aux->affiliation = $au->affiliation;
             }
             $lemail = strtolower((string) $au->email);
             if ($lemail && ($conf = get($contacts, $lemail)) && $conf->conflictType >= CONFLICT_AUTHOR) {
                 $aux->contact = true;
                 unset($contacts[$lemail]);
             }
             $pj->authors[] = $aux;
         }
         $other_contacts = array();
         foreach ($contacts as $conf) {
             if ($conf->conflictType >= CONFLICT_AUTHOR) {
                 $aux = (object) array("email" => $conf->email);
                 if ($conf->firstName) {
                     $aux->first = $conf->firstName;
                 }
                 if ($conf->lastName) {
                     $aux->last = $conf->lastName;
                 }
                 if ($conf->affiliation) {
                     $aux->affiliation = $conf->affiliation;
                 }
                 $other_contacts[] = $aux;
             }
         }
         if (!empty($other_contacts)) {
             $pj->contacts = $other_contacts;
         }
     }
     if ($Conf->submission_blindness() == Conf::BLIND_OPTIONAL) {
         $pj->nonblind = !(isset($pj->paperBlind) ? $prow->paperBlind : $prow->blind);
     }
     $pj->abstract = $prow->abstract;
     $topics = array();
     foreach (array_intersect_key($Conf->topic_map(), array_flip($prow->topics())) as $tid => $tname) {
         $topics[$this->export_ids ? $tid : $tname] = true;
     }
     if (!empty($topics)) {
         $pj->topics = (object) $topics;
     }
     if ($prow->paperStorageId > 1 && (!$contact || $contact->can_view_pdf($prow)) && ($doc = $this->document_to_json(DTYPE_SUBMISSION, (int) $prow->paperStorageId))) {
         $pj->submission = $doc;
     }
     if ($prow->finalPaperStorageId > 1 && (!$contact || $contact->can_view_pdf($prow)) && ($doc = $this->document_to_json(DTYPE_FINAL, (int) $prow->finalPaperStorageId))) {
         $pj->final = $doc;
     }
     if ($prow->timeFinalSubmitted > 0) {
         $pj->final_submitted = true;
         $pj->final_submitted_at = (int) $prow->timeFinalSubmitted;
     }
     if (count($prow->options())) {
         $options = array();
         foreach (PaperOption::option_list() as $o) {
             if ($contact && !$contact->can_view_paper_option($prow, $o, $this->forceShow)) {
                 continue;
             }
             $ov = $prow->option($o->id) ?: new PaperOptionValue($o->id, $o);
             $options[$this->export_ids ? $o->id : $o->abbr] = $o->unparse_json($ov, $this, $contact);
         }
         if (!empty($options)) {
             $pj->options = (object) $options;
         }
     }
     if ($can_view_authors) {
         $pcconflicts = array();
         foreach ($prow->pc_conflicts(true) as $id => $conf) {
             if ($ctname = get(Conflict::$type_names, $conf->conflictType)) {
                 $pcconflicts[$conf->email] = $ctname;
             }
         }
         if (!empty($pcconflicts)) {
             $pj->pc_conflicts = (object) $pcconflicts;
         }
     }
     if ($prow->collaborators && $can_view_authors) {
         $pj->collaborators = $prow->collaborators;
     }
     return $pj;
 }
Ejemplo n.º 4
0
 public function diffs(&$diffs, $pj, $opj)
 {
     global $Conf;
     if (!$opj) {
         $diffs["new"] = true;
         return;
     }
     foreach (array("title", "abstract", "collaborators") as $k) {
         if (get_s($pj, $k) !== get_s($opj, $k)) {
             $diffs[$k] = true;
         }
     }
     if (!$this->same_authors($pj, $opj)) {
         $diffs["authors"] = true;
     }
     if (json_encode(get($pj, "topics") ?: (object) array()) !== json_encode(get($opj, "topics") ?: (object) array())) {
         $diffs["topics"] = true;
     }
     $pjopt = get($pj, "options", (object) []);
     $opjopt = get($opj, "options", (object) []);
     foreach (PaperOption::option_list() as $o) {
         $oabbr = $o->abbr;
         if (!get($pjopt, $oabbr) != !get($opjopt, $oabbr) || get($pjopt, $oabbr) && json_encode($pjopt->{$oabbr}) !== json_encode($opjopt->{$oabbr})) {
             $diffs["options"] = true;
             break;
         }
     }
     if ($Conf->subBlindOptional() && !get($pj, "nonblind") !== !get($opj, "nonblind")) {
         $diffs["anonymity"] = true;
     }
     if (json_encode(get($pj, "pc_conflicts")) !== json_encode(get($opj, "pc_conflicts"))) {
         $diffs["PC conflicts"] = true;
     }
     if (json_encode(get($pj, "submission")) !== json_encode(get($opj, "submission"))) {
         $diffs["submission"] = true;
     }
     if (json_encode(get($pj, "final")) !== json_encode(get($opj, "final"))) {
         $diffs["final copy"] = true;
     }
 }
Ejemplo n.º 5
0
 function active_document_ids()
 {
     $q = array("select paperStorageId from Paper where paperStorageId>1", "select finalPaperStorageId from Paper where finalPaperStorageId>1", "select paperStorageId from PaperComment where paperStorageId>1");
     $document_option_ids = array();
     foreach (PaperOption::option_list() as $id => $o) {
         if ($o->has_document()) {
             $document_option_ids[] = $id;
         }
     }
     if (count($document_option_ids)) {
         $q[] = "select value from PaperOption where optionId in (" . join(",", $document_option_ids) . ") and value>1";
     }
     $result = $this->qe(join(" UNION ", $q));
     $ids = array();
     while ($row = edb_row($result)) {
         $ids[(int) $row[0]] = true;
     }
     ksort($ids);
     return array_keys($ids);
 }
Ejemplo n.º 6
0
 public static function analyze_option_search($word)
 {
     if (preg_match('/\\A(.*?)([:#](?:[=!<>]=?|≠|≤|≥|)|[=!<>]=?|≠|≤|≥)(.*)\\z/', $word, $m)) {
         $oname = $m[1];
         if ($m[2][0] === ":" || $m[2][0] === "#") {
             $m[2] = substr($m[2], 1);
         }
         $ocompar = CountMatcher::canonical_comparator($m[2]);
         $oval = strtolower(simplify_whitespace($m[3]));
     } else {
         $oname = $word;
         $ocompar = "=";
         $oval = "";
     }
     $oname = strtolower(simplify_whitespace($oname));
     // match all options
     $qo = $warn = array();
     $option_failure = false;
     if ($oname === "none" || $oname === "any") {
         $omatches = PaperOption::option_list();
     } else {
         $omatches = PaperOption::search($oname);
     }
     // Conf::msg_info(Ht::pre_text(var_export($omatches, true)));
     if (count($omatches)) {
         foreach ($omatches as $oid => $o) {
             // selectors handle “yes”, “”, and “no” specially
             if ($o->has_selector()) {
                 $xval = array();
                 if ($oval === "") {
                     foreach ($o->selector as $k => $v) {
                         if (strcasecmp($v, "yes") == 0) {
                             $xval[$k] = $v;
                         }
                     }
                     if (count($xval) == 0) {
                         $xval = $o->selector;
                     }
                 } else {
                     $xval = Text::simple_search($oval, $o->selector);
                 }
                 if (count($xval) == 0) {
                     $warn[] = "“" . htmlspecialchars($oval) . "” doesn’t match any " . htmlspecialchars($oname) . " values.";
                 } else {
                     if (count($xval) == 1) {
                         reset($xval);
                         $qo[] = new OptionMatcher($o, $ocompar, key($xval), $oval);
                     } else {
                         if ($ocompar !== "=" && $ocompar !== "!=") {
                             $warn[] = "Submission option “" . htmlspecialchars("{$oname}:{$oval}") . "” matches multiple values, can’t use " . htmlspecialchars($ocompar) . ".";
                         } else {
                             $qo[] = new OptionMatcher($o, $ocompar, array_keys($xval), $oval);
                         }
                     }
                 }
                 continue;
             }
             if ($oval === "" || $oval === "yes" || $oval === "'yes'") {
                 $qo[] = new OptionMatcher($o, "!=", 0, $oval);
             } else {
                 if ($oval === "no" || $oval === "'no'") {
                     $qo[] = new OptionMatcher($o, "=", 0, $oval);
                 } else {
                     if ($o->type == "text") {
                         if (!empty($oval)) {
                             $qo[] = new OptionMatcher($o, ' like ', str_replace("+", " ", $oval), $oval);
                         }
                     } else {
                         if ($o->type === "numeric") {
                             if (preg_match('/\\A\\s*([-+]?\\d+)\\s*\\z/', $oval, $m)) {
                                 $qo[] = new OptionMatcher($o, $ocompar, $m[1], $oval);
                             } else {
                                 $warn[] = "Submission option “" . htmlspecialchars($o->name) . "” takes integer values.";
                             }
                         } else {
                             if ($o->type === "attachments") {
                                 if ($oval === "any") {
                                     $qo[] = new OptionMatcher($o, "!=", 0, $oval);
                                 } else {
                                     if (preg_match('/\\A\\s*([-+]?\\d+)\\s*\\z/', $oval, $m)) {
                                         if (CountMatcher::compare(0, $ocompar, $m[1])) {
                                             $qo[] = new OptionMatcher($o, "=", 0, $oval);
                                         }
                                         $qo[] = new OptionMatcher($o, $ocompar, $m[1], $oval, "attachment-count");
                                     } else {
                                         $qo[] = new OptionMatcher($o, "~=", $oval, $oval, "attachment-name", $oval);
                                     }
                                 }
                             } else {
                                 continue;
                             }
                         }
                     }
                 }
             }
         }
     } else {
         if (($ocompar === "=" || $ocompar === "!=") && $oval === "") {
             foreach (PaperOption::option_list() as $oid => $o) {
                 if ($o->has_selector()) {
                     foreach (Text::simple_search($oname, $o->selector) as $xval => $text) {
                         $qo[] = new OptionMatcher($o, $ocompar, $xval, "~val~");
                     }
                 }
             }
         }
     }
     return (object) array("os" => $qo, "warn" => $warn, "negate" => $oname === "none");
 }
Ejemplo n.º 7
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)");
}