Exemplo n.º 1
0
function add_definition($spart, $value)
{
    $w = $GLOBALS["word"];
    $d = DEFINITION(defaultDB(), NULL, $w);
    $d->set_lang("en");
    $d->set_value($value);
    $p = PATH($w, $spart);
    $d->set_path($p);
    $d = $w->add_definition($d);
}
Exemplo n.º 2
0
function run_template2($word, $t, $arg, $definition)
{
    if (!$ignore) {
        $ignore = [];
    }
    if ($word !== NULL and $definition) {
        $d = DEFINITION(defaultDB(), NULL, $word);
        $d->set_lang("en");
        $d->set_value($definition);
        $d = $word->add_definition($d);
    }
    if ($word !== NULL and $t !== NULL) {
        run_template($word, "", $t, $arg, [], [], FALSE);
    }
}
Exemplo n.º 3
0
function get_template($conj)
{
    return safe_get(0, defaultDB()->searcher()->spart("verb")->name($conj)->only_with_attr(ATTR("template", "true"))->all());
}
Exemplo n.º 4
0
<?php

require_once '/var/www/config.php';
sro('/Includes/mysql.php');
sro('/Includes/session.php');
sro('/Includes/functions.php');
sro('/PHP5/lib/PHPLang/db.php');
if (!requireRank(3, FALSE)) {
    echo "Insufficient permissions";
} else {
    if (array_key_exists("from", $_GET) and array_key_exists("to", $_GET) and array_key_exists("type", $_GET) and is_numeric($_GET["from"]) and is_numeric($_GET["to"])) {
        $cons = [[$_GET["from"], $_GET["to"]]];
        if (array_key_exists("mutual", $_GET) and $_GET["mutual"] === "true") {
            $cons = [$cons[0], [$_GET["to"], $_GET["from"]]];
        }
        foreach ($cons as list($ab, $ad)) {
            $w = WORD(defaultDB(), intval($ab));
            $t = WORD(defaultDB(), intval($ad));
            $c = CONNECTION($w, $t, $_GET["type"]);
            $w->add_connection($c);
        }
        exit("success");
    } else {
        exit("\$_GET was invalid");
    }
}
Exemplo n.º 5
0
<span data-i18n="word_formatting">Word formatting</span>:
<select id="la_ipa" style="width: 200px">
</select>
<br>

<label><span data-i18n="archaic_translations">Archai&#x308;c translations</span>:
<input id="archtrans" type="checkbox"></label>

<br><br>

<span data-i18n="order_cases">Order of cases</span>:
<div>
<ul id="cases">
<?php 
foreach (defaultDB()->get_mgr("la", "noun")->key2values["case"] as $case) {
    ?>
<li><span class="value"><?php 
    echo ucfirst($case);
    ?>
</span>
<?php 
}
?>
</ul>
</div>

<span id="word-format-ex" class="format-word-la">
Exemplum verbōrum: Salvē! Quid agis? Hoc verbum habet multās fōrmās: oppugnātus‣, et hoc īnflexum: aestⱶmāvissem. Jussa! Euge!
</span>
Exemplo n.º 6
0
        if ($reverse = substr($attr, 0, 1) === "!") {
            $attr = substr($attr, 1);
        }
        if (strpos($attr, "=") === FALSE) {
            $a = ATTR($attr);
        } else {
            list($name, $value) = explode("=", $attr, 2);
            $a = ATTR($name, $value);
        }
        if ($a !== NULL) {
            if (!$reverse) {
                $searcher = $searcher->only_with_attr($a);
            } else {
                $searcher = $searcher->only_without_attr($a);
            }
        }
    }
    $list = $searcher->all();
} else {
    $list = [];
    foreach ($ids as $id) {
        $list[] = WORD(defaultDB(), intval($id));
    }
}
$res = vec_norm(array_map(function ($e) {
    if (no_format($e)) {
        return ["data" => $e->name(), "value" => $e->id() . "", "display" => $e->info()];
    }
    return ["data" => $e->name(), "value" => $e->id() . "", "display" => format_word($e->info())];
}, $list));
echo json_encode($res);
Exemplo n.º 7
0
                     $w->add_path($p);
                 }
                 exit("success");
             } else {
                 $p = PATH($w);
                 $p->set($names[0]);
                 exit("success");
             }
         }
     }
 }
 $ignore = array_map(function ($a) {
     return explode("/", $a);
 }, $ignore);
 // Template: passed by name, spart from word, attr template=true
 $t = defaultDB()->searcher();
 $t = $t->spart($w->speechpart());
 $t = $t->name($template);
 $t = $t->only_with_attr(ATTR("template", "true"));
 $t = $t->all();
 //error_log(var_export(array_map(function($a){return$a->id();},$t),1));
 if (count($t) === 0) {
     exit("Could not find template with name: " . $template);
 } elseif (count($t) !== 1) {
     exit("Ambiguous template name (please remove duplicate template(s))");
 }
 if ($path === "common") {
     if (($s = run_template($w, PATH($w, "feminine"), $t[0], $forms, $ignore, $changes, FALSE)) === NULL) {
         if (($s = run_template($w, PATH($w, "masculine"), $t[0], $forms, $ignore, $changes, FALSE)) === NULL) {
             exit("success");
         } else {
Exemplo n.º 8
0
 private function _process_value($v)
 {
     return _process_value($v, $this->selections, defaultDB());
 }
Exemplo n.º 9
0
    }
    foreach ($res as &$r) {
        $r = ["correct" => $r->word()->id() === $pick_db["word"]->id(), "value" => ((string) $r->path() ? "(" . $r->path() . ") " : "") . str_replace("\n", ", ", $r->value())];
    }
    return $res;
}, "choices0-tooltip" => "Pick correct definition"]]], "random-definitions-stage28-29-fr" => ["name" => "Stage 28–29 Vocabulary (FR)", "category" => "Vocabulary", "lang" => "la", "options" => [["help" => "Choose a correct definition for the given word", "selections" => ["word" => function ($_, $db, $path) {
    $s = $db->searcher();
    $s->stmt .= "\n\t\t\t\t\t\tWHERE word_id IN (\n\t\t\t\t\t\t\tSELECT word_id FROM definitions\n\t\t\t\t\t\t\tWHERE def_lang = 'en'\n\t\t\t\t\t\t\tAND def_type IS NULL\n\t\t\t\t\t\t)\n\t\t\t\t\t\tAND word_lang = 'la'\n\t\t\t\t\t\tAND word_id NOT IN (\n\t\t\t\t\t\t\tSELECT word_id FROM attributes\n\t\t\t\t\t\t\tWHERE attr_tag = 'template' OR attr_tag = 'hidden'\n\t\t\t\t\t\t)\n\t\t\t\t\t\tAND (\n\t\t\t\t\t\t\tSELECT attr_value FROM attributes\n\t\t\t\t\t\t\tWHERE word_id = words.word_id\n\t\t\t\t\t\t\tAND attr_tag = 'clc-stage' \n\t\t\t\t\t\t) IN (28,29)";
    $s->args = [];
    return $s->rand();
}], "sentence" => [$OP_LQUOTE, function ($pick_db) {
    return format_word($pick_db["word"]->name());
}, $OP_RQUOTE, $OP_COLON, $OP_USER_INPUT], "answer0-language" => "en", "answer0" => function ($pick_db, $db) {
    global $mysqli;
    $query = $mysqli->prepare("\n\t\t\t\t\tSELECT DISTINCT def_id FROM definitions\n\t\t\t\t\tWHERE def_lang = 'en'\n\t\t\t\t\tAND def_type IS NULL\n\t\t\t\t\tAND word_id = (?)\n\t\t\t\t");
    $res = NULL;
    sql_getmany($query, $res, ["i", $pick_db["word"]->id()]);
    $query->close();
    if (!$res) {
        return NULL;
    }
    $ret = [];
    $ret2 = [];
    foreach ($res as $r) {
        $ret = array_merge($ret, explode("\n", definition(defaultDB(), $r)->value()));
    }
    foreach ($ret as $r) {
        $ret2 = array_merge($ret2, array_map("trim", explode(",", $r)));
    }
    return ["correct" => explode(",", $ret[0]), "acceptable" => $ret2];
}, "answer0-tooltip" => "Type correct definition"]]], "009" => ["name" => "Synonyms", "lang" => "la", "category" => "Vocabulary", "n_questions" => "auto", "options" => [make_matching(["cædō" => "interficiō", "exeō" => "discēdō", "pulsō" => "verberō", "volō" => "cupiō"]), make_matching(["turba" => "multitūdō", "mīles" => "arma", "imperātor" => "rēx"])]]]);
Exemplo n.º 10
0
<?php

require_once '/var/www/config.php';
sro('/Includes/mysql.php');
sro('/Includes/session.php');
sro('/Includes/functions.php');
sro('/PHP5/lib/PHPLang/db.php');
if (!requireRank(3, FALSE)) {
    echo "Insufficient permissions";
} else {
    if (array_key_exists("id", $_GET) and array_key_exists("path", $_GET) and is_numeric($_GET["id"])) {
        $w = WORD(defaultDB(), intval($_GET["id"]));
        $w->read_paths();
        $p = PATH($w, $_GET["path"]);
        foreach ($w->paths() as $_) {
            if ((string) $_ === (string) $p) {
                $p = $_;
            }
        }
        if ($p->id() === NULL) {
            exit("Path {$p} did not exist");
        }
        if (!$p->valid()) {
            exit("Path {$p} was invalid");
        }
        $p->remove();
        exit("success");
    } else {
        exit("\$_GET was invalid");
    }
}
Exemplo n.º 11
0
<?php

require_once '/var/www/config.php';
sro('/Includes/mysql.php');
sro('/Includes/session.php');
sro('/Includes/functions.php');
sro('/PHP5/lib/PHPLang/db.php');
if (!requireRank(3, FALSE)) {
    echo "Insufficient permissions";
} else {
    if (array_key_exists("from", $_GET) and array_key_exists("to", $_GET) and array_key_exists("type", $_GET) and is_numeric($_GET["from"]) and is_numeric($_GET["to"])) {
        $w = WORD(defaultDB(), intval($_GET["from"]));
        $t = WORD(defaultDB(), intval($_GET["to"]));
        $c = CONNECTION($w, $t, $_GET["type"]);
        $w->remove_connection($c);
        exit("success");
    } else {
        exit("\$_GET was invalid");
    }
}
Exemplo n.º 12
0
<?php

require_once '/var/www/config.php';
sro('/Includes/mysql.php');
sro('/Includes/session.php');
sro('/Includes/functions.php');
sro('/PHP5/lib/PHPLang/sql_stmts.php');
sro('/PHP5/lib/PHPLang/db.php');
sro('/PHP5/lib/PHPLang/display.php');
sro('/PHP5/lib/PHPLang/misc.php');
global $mysqli;
$w = defaultDB()->searcher()->lang('la')->only_without_attr(ATTR('template'));
$ws = $w->all();
?>
<table class="inflection"><?php 
foreach ($ws as $i => $word) {
    ?>
<tr><td><ol start="<?php 
    echo $i + 1;
    ?>
"><li><a class="word-ref format-word-<?php 
    echo $word->lang();
    ?>
" href="dictionary.php?id=<?php 
    echo $word->id();
    ?>
"><?php 
    echo $word->name();
    ?>
</ol></td><td style="border-spacing: 0px; padding: 0px;"><?php 
    display_definitions($word);
Exemplo n.º 13
0
function do_template($temp, $db = NULL, &$pick_db = NULL, &$reason = NULL)
{
    if ($db === NULL) {
        $db = defaultDB();
    }
    if (is_string($temp)) {
        return $temp;
    }
    $repeats = 0;
    $sentence = NULL;
    $reason = NULL;
    $ignore = NULL;
    $reset = [];
    if (is_array($pick_db)) {
        $reset = [];
        foreach ($pick_db as $k => $_) {
            $reset[$k] = _process_value($_, $reset, $db);
        }
    }
    while ($repeats < 1 and $sentence === NULL) {
        $repeats += 1;
        $sentence = [];
        $pick_db = $reset;
        foreach ($temp as $k => $t) {
            $res = do_pick($t, $db, $pick_db, $reason);
            if ($res === NULL) {
                $reason .= " on key {$k}";
                $reason .= " (picks were " . dump_pick_db($pick_db) . ")";
                $sentence = NULL;
                break;
            } elseif ($res !== FALSE) {
                $sentence[$k] = $res;
            }
        }
    }
    if ($sentence !== NULL) {
        return array_values($sentence);
    }
}
Exemplo n.º 14
0
function select2_getlangs()
{
    $langs = [];
    $db = defaultDB();
    foreach ($db->langs() as $l) {
        $langs[] = ["id" => $l, "text" => format_lang($l)];
    }
    return $langs;
}
Exemplo n.º 15
0
<?php

require_once '/var/www/config.php';
sro('/Includes/mysql.php');
sro('/Includes/session.php');
sro('/Includes/functions.php');
sro('/PHP5/lib/PHPLang/db.php');
if (!requireRank(3, FALSE)) {
    echo "Insufficient permissions";
} else {
    if (array_key_exists("id", $_GET) and array_key_exists("val", $_GET) and array_key_exists("path", $_GET) and is_numeric($_GET["id"])) {
        $w = WORD(defaultDB(), intval($_GET["id"]));
        $d = PRONUNCIATION(defaultDB(), NULL, $w);
        $d->set_type("IPA");
        $d->set_value($_GET["val"]);
        //error_log(var_export($d->value(),1)." should be ".var_export($_GET["val"],1));
        if ($_GET["path"]) {
            $p = PATH($w, $_GET["path"]);
            $d->set_path($p);
        }
        $d = $w->add_pronuncation($d);
        exit("success");
    } else {
        exit("\$_GET was invalid (" . var_export($_GET, 1) . ")");
    }
}
Exemplo n.º 16
0
<?php

require_once '/var/www/config.php';
sro('/Includes/mysql.php');
sro('/Includes/session.php');
sro('/Includes/functions.php');
sro('/PHP5/lib/PHPLang/db.php');
if (!requireRank(3, FALSE)) {
    echo "Insufficient permissions";
} else {
    if (array_key_exists("id", $_GET) and array_key_exists("val", $_GET) and array_key_exists("path", $_GET) and is_numeric($_GET["id"])) {
        $w = WORD(defaultDB(), intval($_GET["id"]));
        $d = DEFINITION(defaultDB(), NULL, $w);
        if (safe_get("lang", $_GET)) {
            $d->set_lang($_GET["lang"]);
        } else {
            $d->set_lang("en");
        }
        if (safe_get("type", $_GET)) {
            $d->set_type($_GET["type"]);
        }
        $d->set_value($_GET["val"]);
        if (safe_get("path", $_GET)) {
            $p = PATH($w, $_GET["path"]);
            $d->set_path($p);
        }
        $d = $w->add_definition($d);
        exit("success");
    } else {
        exit("\$_GET was invalid (" . var_export($_GET, 1) . ")");
    }
Exemplo n.º 17
0
<?php

require_once '/var/www/config.php';
sro('/Includes/mysql.php');
sro('/Includes/session.php');
sro('/Includes/functions.php');
sro('/PHP5/lib/PHPLang/make_example.php');
sro('/PHP5/lib/PHPLang/display.php');
$query = [];
parse_str($_SERVER["QUERY_STRING"], $query);
$f = function () {
    global $sql_stmts;
    $w = RWORD(defaultDB());
    ?>
	<sup>[<?php 
    echo $w->lang();
    ?>
]</sup>
	<b><?php 
    echo $w->name();
    ?>
</b>
	(<?php 
    echo $w->speechpart();
    ?>
)
	<br/>
	<?php 
};
if (!array_key_exists("n", $query)) {
    $query["n"] = 1;
Exemplo n.º 18
0
     if (count($answers) !== count(vec_norm(array_unique($answers)))) {
         $reason = "results were not unique (" . implode(",", $results) . ")";
         return $try();
     }
     foreach ($answers as &$r) {
         $r = format_word($r, $lang);
     }
     $result_json[] = ["matching", "answer{$n}", $quiz->get_other("matching{$n}-tooltip"), $left, $answers];
     $n += 1;
 } elseif ($word === $OP_USER_INPUT || $word === $OP_USER_PARAGRAPH) {
     $refresh(1);
     $stop = FALSE;
     $answers = $quiz->get_other("answer{$n}");
     $lang = safe_get("answer{$n}-language", $quiz->get_others());
     if (is_callable($answers)) {
         $answers = $answers($selections, defaultDB());
     }
     if (!is_array($answers)) {
         $reason = "answers were not in an array";
         return $try();
     }
     $process = function ($answer) use($dopick, &$stop, &$correct, $lang) {
         if ($stop) {
             return;
         }
         $ret = $dopick($answer, TRUE);
         if ($ret === NULL) {
             $stop = TRUE;
         } else {
             $ret = format_word($ret, $lang);
         }
Exemplo n.º 19
0
function RWORD2($lang, $spart, $name = null)
{
    $w = defaultDB()->searcher()->spart($spart)->lang($lang)->only_without_attr(ATTR("irregular"))->only_without_attr(ATTR("template"));
    if ($name !== null) {
        $w = $w->name($name);
    }
    $w->stmt .= " AND EXISTS (SELECT 1 FROM forms WHERE forms.word_id = words.word_id AND form_tag != '' AND form_value != '') AND NOT EXISTS (SELECT 1 FROM attributes WHERE attr_tag = 'conjugation' AND attr_value like '%deponent%' AND word_id = words.word_id)";
    return $w->rand();
}
Exemplo n.º 20
0
<?php

require_once '/var/www/config.php';
sro('/Includes/mysql.php');
sro('/Includes/session.php');
sro('/Includes/functions.php');
sro('/PHP5/lib/PHPLang/db.php');
if (!requireRank(3, FALSE)) {
    echo "Insufficient permissions";
} else {
    if (array_key_exists("id", $_GET) and is_numeric($_GET["id"])) {
        $d = DEFINITION(defaultDB(), intval($_GET["id"]));
        $d->remove();
        exit("success");
    } else {
        exit("\$_GET was invalid");
    }
}
Exemplo n.º 21
0
function search_GET($limit = 50, &$max_size = NULL)
{
    $db = defaultDB();
    if (!array_key_exists("lang", $_GET) or !($langs = vec_norm(explode(",", $_GET["lang"]), "trim"))) {
        $langs = ['la'];
    }
    if (!array_key_exists("name", $_GET) or !($names = vec_norm(explode(",", $_GET["name"]), "trim"))) {
        $names = NULL;
    }
    if (!array_key_exists("form", $_GET) or !($forms = vec_norm(explode(",", $_GET["form"]), "trim"))) {
        $forms = NULL;
    }
    if (!array_key_exists("spart", $_GET) or !($sparts = vec_norm(explode(",", $_GET["spart"]), "trim"))) {
        $sparts = NULL;
    }
    if (!array_key_exists("attr", $_GET) or !($attrs = vec_norm(explode(",", $_GET["attr"]), "trim"))) {
        $attrs = [];
    }
    if (!array_key_exists("def", $_GET) or !($defs = vec_norm(explode(";", $_GET["def"]), "trim"))) {
        $defs = [];
    }
    if (!array_key_exists("id", $_GET) or !($ids = vec_norm(explode(",", $_GET["id"]), "trim"))) {
        $ids = NULL;
    }
    $no_definitions = safe_get("no_definitions", $_GET) === "true";
    $no_templates = !(safe_get("show_templates", $_GET) === "true");
    $start = intval(safe_get("start", $_GET));
    $_ = $limit;
    $limit = intval(safe_get("limit", $_GET));
    if ($limit <= 0) {
        $limit = 5;
    }
    if ($limit > $_) {
        $limit = $_;
    }
    if ($ids === NULL) {
        $searcher = $db->searcher();
        if ($names) {
            $searcher = $searcher->name($names);
        }
        if ($forms) {
            $searcher = $searcher->form($forms);
        }
        if ($langs) {
            $searcher = $searcher->lang($langs);
        }
        if ($sparts) {
            $searcher = $searcher->spart($sparts);
        }
        if ($defs) {
            $searcher = $searcher->definition_parse($defs);
        } else {
            if ($no_definitions) {
                $searcher = $searcher->no_definitions();
            }
        }
        if ($no_templates) {
            $attrs[] = "!template";
        }
        foreach ($attrs as $attr) {
            if (!$attr) {
                continue;
            }
            $a = NULL;
            if ($reverse = substr($attr, 0, 1) === "!") {
                $attr = substr($attr, 1);
            }
            if (strpos($attr, "=") === FALSE) {
                $a = ATTR($attr);
            } else {
                list($name, $value) = explode("=", $attr, 2);
                $a = ATTR($name, $value);
            }
            if ($a !== NULL) {
                if (!$reverse) {
                    $searcher = $searcher->only_with_attr($a);
                } else {
                    $searcher = $searcher->only_without_attr($a);
                }
            }
        }
        $max_size = $searcher->max_size();
        $list = $searcher->limit($start, $limit)->all("name");
        if (count($list) === $max_size) {
            $max_size = NULL;
        }
    } else {
        $max_size = NULL;
        $list = [];
        foreach ($ids as $id) {
            $list[] = WORD(defaultDB(), intval($id));
        }
    }
    return $list;
}
Exemplo n.º 22
0
<?php

require_once '/var/www/config.php';
sro('/Includes/mysql.php');
sro('/Includes/session.php');
sro('/Includes/functions.php');
sro('/PHP5/lib/PHPLang/make_example.php');
sro('/PHP5/lib/PHPLang/display.php');
$db = defaultDB();
global $sql_stmts;
if (count($_GET)) {
    if (!array_key_exists("lang", $_GET)) {
        $_GET["lang"] = 'la';
    }
    if (!array_key_exists("name", $_GET)) {
        $_GET["name"] = NULL;
    }
    if (!array_key_exists("spart", $_GET)) {
        $_GET["spart"] = NULL;
    }
    foreach ($_GET as $k => $v) {
        if (!startswith($k, "delete_")) {
            continue;
        }
        if ($v != "true") {
            continue;
        }
        $id = explode("_", $k, 2)[1];
        $id = intval($id);
        sql_exec(sql_stmt("form_id->delete from forms"), ["i", $id]);
    }
Exemplo n.º 23
0
require_once '/var/www/config.php';
sro('/Includes/mysql.php');
sro('/Includes/session.php');
sro('/Includes/functions.php');
sro('/PHP5/lib/PHPLang/db.php');
sro('/PHP5/lib/PHPLang/display.php');
if (!hasACL('admin_panel', 'R', 'S')) {
    sro('/Pages/restricted/admin.php');
    die("");
}
if (!hasACL('add_words', 'R', 'S')) {
    sro('/Pages/restricted/adder.php');
    die("");
}
$uid = cleanInput('/[^0-9]/', $_GET['id']);
$word = WORD(defaultDB(), intval($uid));
?>
<h2><?php 
echo $word->name();
?>
</h2>
<div id="aswDetails">
    <p>
        Name: <?php 
echo $word->name();
?>
<br>
        Part of speech: <?php 
echo display_spart($word->spart());
?>
<br>
Exemplo n.º 24
0
sro('/Includes/functions.php');
sro('/PHP5/lib/PHPLang/make_example.php');
sro('/PHP5/lib/PHPLang/display.php');
sro('/PHP5/lib/PHPLang/db.php');
sro('/PHP5/lib/PHPLang/misc.php');
sro('/PHP5/lib/PHPLang/templates.php');
if (!array_key_exists("lang", $_GET) or !($langs = vec_norm(explode(",", $_GET["lang"]), "trim"))) {
    $langs = ['la'];
}
if (!array_key_exists("name", $_GET) or !($names = vec_norm(explode(",", $_GET["name"]), "trim"))) {
    $names = NULL;
}
if (!array_key_exists("spart", $_GET) or !($sparts = vec_norm(explode(",", $_GET["spart"]), "trim"))) {
    $sparts = NULL;
}
if (!array_key_exists("attr", $_GET) or !($attrs = vec_norm(explode(",", $_GET["attr"]), "trim"))) {
    $attrs = [];
}
$definitions = safe_get("definitions", $_GET);
$connections = safe_get("connections", $_GET);
$forms = safe_get("forms", $_GET);
if ($langs and count($langs) == 1 and $names and count($names) == 1 and $sparts and count($sparts) == 1) {
    $w = defaultDB()->searcher()->name($names[0])->spart($sparts[0])->lang($langs[0])->all();
    if (count($w)) {
        exit("present");
    } else {
        exit("absent");
    }
} else {
    exit("Bad \$_GET");
}
Exemplo n.º 25
0
function which3($lang, $spart, $key, $N = NULL, $given = NULL, $rand = NULL, $name = NULL)
{
    global $OP_MULTIPLE_CHOICE;
    global $OP_PARAGRAPH;
    global $OP_LPAREN;
    global $OP_RPAREN;
    global $OP_LQUOTE;
    global $OP_RQUOTE;
    $selections = [];
    $path = [];
    $mgr = defaultDB()->get_mgr($lang, $spart);
    $given = PATH($mgr, $given);
    $_gender = null;
    if ($N === NULL) {
        $N = count($mgr->key2values[$key]);
    }
    $selections["answers"] = PICK($N, $key, safe_get($key, $rand))->l($lang);
    $recurse = function ($mgr) use(&$_gender, $spart, $given, &$recurse, &$path, $rand, &$selections, $lang) {
        foreach ($mgr->simple_keys as $k) {
            if ($given->key_exists($k)) {
                $path[] = $given->key_value($k);
            } else {
                if ($k === "gender" and $spart === "verb") {
                    $_gender = make_pick(PICK($k, safe_get($k, $rand))->l($lang), $k);
                } else {
                    $path[] = make_pick(PICK($k, safe_get($k, $rand))->l($lang), $k);
                }
            }
        }
        foreach ($mgr->recursive_keys as $k) {
            if ($given->key_exists($k)) {
                $path[] = $given->key_value($k);
                $recurse($mgr->level[$k][$given->key_value($k)]);
            }
        }
    };
    $recurse($mgr);
    $answers = [];
    $selections[$key] = function ($pick_db) {
        error_log(var_export($pick_db, 1));
        return $pick_db["answers"][0];
    };
    for ($v = 0; $v < $N; $v++) {
        $answers[] = ["correct" => function ($pick_db) use($v) {
            return safe_get($pick_db["answers"][$v], $pick_db);
        }, "value" => function ($pick_db) use($v) {
            return $pick_db["answers"][$v];
        }];
    }
    $ret = ["help" => "What {$key} is this word?", "selections" => $selections, "sentence" => [["lang" => $lang, "speechpart" => $spart, "path" => $path, "attr" => ["!template" => NULL, "!hidden" => NULL], "store_word" => "word", "store" => "result"], function (&$pick_db) use($key) {
        global $mysqli;
        $query = $mysqli->prepare("\n\t\t\t\t\tSELECT form_tag FROM forms\n\t\t\t\t\tWHERE word_id = (?)\n\t\t\t\t\tAND form_value = (?)\n\t\t\t\t");
        $res = NULL;
        sql_getmany($query, $res, ["is", $pick_db["word"]->id(), $pick_db["result"]]);
        $query->close();
        foreach ($res as $tag) {
            $p = PATH($pick_db["word"], $tag);
            $v = $p->key_value($key);
            $pick_db[$v] = TRUE;
        }
        return FALSE;
        // No word
    }, $OP_PARAGRAPH, $OP_MULTIPLE_CHOICE], "choices0" => $answers, "choices0-tooltip" => "What {$key}?", "choices0-language" => "en"];
    if ($name !== null) {
        $ret["sentence"][0]["name"] = $name;
    }
    if ($_gender !== null) {
        $ret["sentence"][0]["verb-gender"] = $_gender;
    }
    return $ret;
}