$t = $Conf->parse_time("1 Sep 2010 23:59:59");
$t0 = $Conf->obscure_time($t);
xassert_eqq($Conf->unparse_time_obscure($t0), "1 Sep 2010");
xassert_eqq($Conf->printableTime($t0), "1 Sep 2010 12pm EDT");
// review ordinal tests
foreach ([1 => "A", 26 => "Z", 27 => "AA", 28 => "AB", 51 => "AY", 52 => "AZ", 53 => "BA", 54 => "BB", 702 => "ZZ"] as $n => $t) {
    xassert_eqq(unparseReviewOrdinal($n), $t);
    xassert_eqq(parseReviewOrdinal($t), $n);
}
// ReviewField::make_abbreviation tests
xassert_eqq(ReviewField::make_abbreviation("novelty", 0, 0), "Nov");
xassert_eqq(ReviewField::make_abbreviation("novelty is an amazing", 0, 0), "NovIsAma");
xassert_eqq(ReviewField::make_abbreviation("novelty is an AWESOME", 0, 0), "NovIsAWESOME");
xassert_eqq(ReviewField::make_abbreviation("novelty isn't an AWESOME", 0, 0), "NovIsnAWESOME");
xassert_eqq(ReviewField::make_abbreviation("novelty isn't an AWESOME", 0, 1), "novelty-isnt-awesome");
xassert_eqq(ReviewField::make_abbreviation("_format", 0, 1), "format");
// utf8_word_prefix, etc. tests
xassert_eqq(UnicodeHelper::utf8_prefix("aaaaaaaa", 7), "aaaaaaa");
xassert_eqq(UnicodeHelper::utf8_prefix("aaaaaaaa", 8), "aaaaaaaa");
xassert_eqq(UnicodeHelper::utf8_prefix("aaaaaaaa", 9), "aaaaaaaa");
xassert_eqq(UnicodeHelper::utf8_prefix("áááááááá", 7), "ááááááá");
xassert_eqq(UnicodeHelper::utf8_prefix("áááááááá", 8), "áááááááá");
xassert_eqq(UnicodeHelper::utf8_prefix("áááááááá", 9), "áááááááá");
xassert_eqq(UnicodeHelper::utf8_prefix("a̓a̓a̓a̓a̓a̓a̓a̓", 7), "a̓a̓a̓a̓a̓a̓a̓");
xassert_eqq(UnicodeHelper::utf8_prefix("a̓a̓a̓a̓a̓a̓a̓a̓", 8), "a̓a̓a̓a̓a̓a̓a̓a̓");
xassert_eqq(UnicodeHelper::utf8_prefix("a̓a̓a̓a̓a̓a̓a̓a̓", 9), "a̓a̓a̓a̓a̓a̓a̓a̓");
xassert_eqq(UnicodeHelper::utf8_word_prefix("aaaaaaaa bbb", 7), "aaaaaaaa");
xassert_eqq(UnicodeHelper::utf8_word_prefix("aaaaaaaa bbb", 8), "aaaaaaaa");
xassert_eqq(UnicodeHelper::utf8_word_prefix("aaaaaaaa bbb", 9), "aaaaaaaa");
xassert_eqq(UnicodeHelper::utf8_word_prefix("aaaaaaaa bbb", 10), "aaaaaaaa");
xassert_eqq(UnicodeHelper::utf8_glyphlen("aaaaaaaa"), 8);
    public function __construct($rfj)
    {
        // prototype fields
        foreach (array("paperSummary", "commentsToAuthor", "commentsToPC", "commentsToAddress", "weaknessOfPaper", "strengthOfPaper", "textField7", "textField8") as $fid) {
            $this->fmap[$fid] = new ReviewField($fid, false);
        }
        foreach (array("potential", "fixability", "overAllMerit", "reviewerQualification", "novelty", "technicalMerit", "interestToCommunity", "longevity", "grammar", "likelyPresentation", "suitableForShort") as $fid) {
            $this->fmap[$fid] = new ReviewField($fid, true);
        }
        // parse JSON
        if (!$rfj) {
            $rfj = json_decode('{
"overAllMerit":{"name":"Overall merit","position":1,"visibility":"au",
  "options":["Reject","Weak reject","Weak accept","Accept","Strong accept"]},
"reviewerQualification":{"name":"Reviewer expertise","position":2,"visibility":"au",
  "options":["No familiarity","Some familiarity","Knowledgeable","Expert"]},
"paperSummary":{"name":"Paper summary","position":3,"display_space":5,"visibility":"au"},
"commentsToAuthor":{"name":"Comments to authors","position":4,"visibility":"au"},
"commentsToPC":{"name":"Comments to PC","position":5,"visibility":"pc"}}');
        }
        foreach ($rfj as $fname => $j) {
            if ($f = get($this->fmap, $fname)) {
                $f->assign($j);
            }
        }
        // assign field order
        $forder = array();
        $this->fieldName = array();
        foreach ($this->fmap as $fid => $f) {
            $this->fieldName[strtolower($f->name)] = $fid;
            if ($f->displayed) {
                $forder[sprintf("%03d.%s", $f->display_order, $fid)] = $f;
            }
        }
        ksort($forder);
        $n = 0;
        foreach ($forder as $f) {
            $f->display_order = ++$n;
        }
        uasort($this->fmap, "ReviewForm::fmap_compare");
        $this->forder = array();
        foreach ($this->fmap as $f) {
            if ($f->displayed) {
                $this->forder[$f->id] = $f;
            }
        }
        // set field abbreviations; try to ensure uniqueness
        for ($detail = 0; $detail < 5; ++$detail) {
            $fmap = array();
            foreach ($this->forder as $f) {
                $f->abbreviation = ReviewField::make_abbreviation($f->name, $detail, 0);
                $fmap[$f->abbreviation] = true;
            }
            if (count($fmap) == count($this->forder)) {
                break;
            }
        }
        foreach ($this->forder as $f) {
            $f->uid = $detail < 5 ? $f->abbreviation : $f->id;
        }
    }
 public function unparse_html($x, $contact)
 {
     if ($x === null || $x === false) {
         return "";
     } else {
         if ($x === true) {
             return "✓";
         } else {
             if ($this->_format === Fexpr::FPREFEXPERTISE) {
                 return ReviewField::unparse_letter(91, $x + 2);
             } else {
                 if ($this->_format === Fexpr::FREVIEWER) {
                     return $contact->reviewer_html_for($x);
                 } else {
                     if ($this->_format instanceof ReviewField && $this->_format->option_letter) {
                         return ReviewField::unparse_letter($this->_format->option_letter, $x);
                     } else {
                         if (is_numeric($x)) {
                             return round($x * 100) / 100;
                         } else {
                             return "{$x}";
                         }
                     }
                 }
             }
         }
     }
 }