@@ -426,6 +426,18 @@ do požadavků. Pak můžete postupně přepisovat/vyplňovat.
|
|||||||
|
|
||||||
Funkce `todo` vám zároveň zabrání v tom, aby se text Lorem Ipsum vyskytl ve výsledném dokumentu.
|
Funkce `todo` vám zároveň zabrání v tom, aby se text Lorem Ipsum vyskytl ve výsledném dokumentu.
|
||||||
|
|
||||||
|
#pagebreak(weak: true)
|
||||||
|
= Argumenty šablony
|
||||||
|
|
||||||
|
Následujících pár stránek je kompletní soupis argumentů, které tato šablona přijímá.
|
||||||
|
Pokud s šablonou nemáte rozsáhlé zkušenosti, doporučujeme raději využít generátoru
|
||||||
|
(https://tulsablona.zumepro.cz/generate/).
|
||||||
|
|
||||||
|
// Automaticky generovaný seznam argumentů
|
||||||
|
#import "template/arguments.typ": print_argument_docs
|
||||||
|
#print_argument_docs()
|
||||||
|
|
||||||
|
|
||||||
#attachments(
|
#attachments(
|
||||||
attach_link("Zdrojový kód této šablony", "https://git.zumepro.cz/tul/tultemplate2"),
|
attach_link("Zdrojový kód této šablony", "https://git.zumepro.cz/tul/tultemplate2"),
|
||||||
attach_content("Testovací obsah vygenerovaný Typstem", [Sem lze psát _stylovaný_ obsah.]),
|
attach_content("Testovací obsah vygenerovaný Typstem", [Sem lze psát _stylovaný_ obsah.]),
|
||||||
|
|||||||
@@ -1,4 +1,147 @@
|
|||||||
#import "utils.typ": assert_type_signature, is_none, map_none, deref, assert_dict_has
|
#import "utils.typ": assert_type_signature, is_none, map_none, deref, assert_dict_has
|
||||||
|
#import "type_signature.typ": *
|
||||||
|
|
||||||
|
#let lang_keys = variants(literal("cs"), literal("en"));
|
||||||
|
#let nonrec_str = doc(string, none, "Je doporučeno použít 'content', pokud je to možné");
|
||||||
|
#let cont_or_str = variants(cont, nonrec_str);
|
||||||
|
#let opt_cont_or_str = variants(cont, nonrec_str);
|
||||||
|
|
||||||
|
// "fs", "ft", "fp", "ef", "fua", "fm", "fzs", "cxi"
|
||||||
|
#let arguments_structure = struct(
|
||||||
|
keyval(literal("document"), struct( // document
|
||||||
|
doc(
|
||||||
|
keyval(literal("visual_style"), variants(literal("classic"))), // document.visual_style
|
||||||
|
"style", "Vizuální styl šablony"
|
||||||
|
),
|
||||||
|
|
||||||
|
doc(keyval(literal("faculty"), variants( // document.faculty
|
||||||
|
doc(literal("fs"), none, "Fakulta strojní"),
|
||||||
|
doc(literal("ft"), none, "Fakulta textilní"),
|
||||||
|
doc(literal("fp"), none, "Fakulta přírodovědně-humanitní a pedagogická"),
|
||||||
|
doc(literal("ef"), none, "Ekonomická fakulta"),
|
||||||
|
doc(literal("fua"), none, "Fakulta umění a architektury"),
|
||||||
|
doc(literal("fm"), none, "Fakulta mechatroniky, informatiky a mezioborových studií"),
|
||||||
|
doc(literal("fzs"), none, "Fakulta zdravotnických studií"),
|
||||||
|
doc(literal("cxi"), none, "Ústav pro nanomateriály, pokročilé technologie a inovace"),
|
||||||
|
)), "faculty", "Fakulta (na základě toho budou vybrány barvy, logotypy, ...)"),
|
||||||
|
|
||||||
|
doc(keyval(literal("language"), variants( // document.language
|
||||||
|
doc(literal("cs"), none, "Čeština"),
|
||||||
|
doc(literal("en"), none, "Angličtina"),
|
||||||
|
)), "lang", "Primární jazyk dokumentu"),
|
||||||
|
|
||||||
|
doc(keyval(literal("type"), variants( // document.type
|
||||||
|
doc(literal("bp"), none, "Bakalářská práce"),
|
||||||
|
doc(literal("dp"), none, "Diplomová práce"),
|
||||||
|
doc(literal("prj"), none, "Projekt (ročník před odevzdáním bakalářské práce)"),
|
||||||
|
)), "document", "Typ dokumentu"),
|
||||||
|
)),
|
||||||
|
|
||||||
|
doc(keyval(literal("title_pages"), variants( // title_pages
|
||||||
|
doc(string, none, "Cesta k souboru PDF, který má být vložen"),
|
||||||
|
doc(null, none, (
|
||||||
|
"Stránky jsou generovány pomocí šablony. Tohle u některých prací může vyžadovat doplnění" +
|
||||||
|
" informací (argumentů)."
|
||||||
|
)),
|
||||||
|
)), "title_pages", "Způsob generování stránek na začátku dokumentu"),
|
||||||
|
|
||||||
|
doc(keyval(literal("title"), dict(keyval(variants( // title
|
||||||
|
doc(literal("cs"), none, "Název práce v češtině"),
|
||||||
|
doc(literal("en"), none, "Název práce v angličtině"),
|
||||||
|
), cont_or_str))), "title", "Název práce"),
|
||||||
|
|
||||||
|
keyval(literal("author"), struct( // author
|
||||||
|
doc(keyval( // author.name
|
||||||
|
literal("name"), opt_cont_or_str
|
||||||
|
), "author", "Jméno autora včetně titulů"),
|
||||||
|
|
||||||
|
doc(keyval(literal("pronouns"), variants( // author.pronouns
|
||||||
|
doc(literal("masculine"), none, "Pro češtinu, oslovení v mužském rodě"),
|
||||||
|
doc(literal("feminine"), none, "Pro češtinu, oslovení v ženském rodě"),
|
||||||
|
doc(literal("we"), none, "Pro češtinu a angličtinu, oslovení v množném čísle"),
|
||||||
|
doc(literal("me"), none, "Pro angličtinu, oslovení v jednotném čísle"),
|
||||||
|
doc(null, none, "Pro angličtinu, oslovení v jednotném čísle"),
|
||||||
|
)), "author", "Jméno autora včetně titulů"),
|
||||||
|
|
||||||
|
doc(keyval( // author.programme
|
||||||
|
literal("programme"), dict(keyval(lang_keys, opt_cont_or_str))
|
||||||
|
), "programme", "Studijní program, pod kterým byl tento dokument vytvořen"),
|
||||||
|
|
||||||
|
doc(keyval( // author.specialization
|
||||||
|
literal("specialization"), dict(keyval(lang_keys, opt_cont_or_str))
|
||||||
|
), "specialization", "Specializace, pod kterou byl tento dokument vytvořen"),
|
||||||
|
|
||||||
|
doc(keyval( // author.year_of_study
|
||||||
|
literal("year_of_study"), dict(keyval(lang_keys, opt_cont_or_str))
|
||||||
|
), "year_of_study", "Specializace, pod kterou byl tento dokument vytvořen"),
|
||||||
|
)),
|
||||||
|
|
||||||
|
keyval(literal("project"), struct( // project
|
||||||
|
doc(keyval(literal("supervisor"), variants(cont, nonrec_str, struct( // project.supervisor
|
||||||
|
doc(keyval(literal("name"), cont_or_str), none, "Jméno vedoucího projektu"),
|
||||||
|
doc(keyval(literal("institute"), cont_or_str), none, "Ústav vedoucího projektu"),
|
||||||
|
), null)), "supervisor", "Vedoucí projektu"),
|
||||||
|
|
||||||
|
doc(keyval(literal("consultant"), variants(cont, nonrec_str, struct( // project.consultant
|
||||||
|
doc(keyval(literal("name"), cont_or_str), none, "Jméno konzultanta projektu"),
|
||||||
|
doc(keyval(literal("institute"), cont_or_str), none, "Ústav konzultanta projektu"),
|
||||||
|
), null)), "consultant", "Konzultant projektu"),
|
||||||
|
)),
|
||||||
|
|
||||||
|
keyval(literal("abstract"), struct( // abstract
|
||||||
|
doc(
|
||||||
|
keyval(literal("content"), struct(..lang_keys.variants.map((k) => { // abstract.content
|
||||||
|
keyval(k, variants(cont, nonrec_str, slice(string)))
|
||||||
|
}))),
|
||||||
|
"abstract", "Abstrakt projektu"
|
||||||
|
),
|
||||||
|
|
||||||
|
doc(
|
||||||
|
keyval(
|
||||||
|
literal("keywords"), // abstract.keywords
|
||||||
|
struct(..lang_keys.variants.map((k) => {
|
||||||
|
keyval(k, variants(cont, nonrec_str, slice(string)))
|
||||||
|
})),
|
||||||
|
),
|
||||||
|
"keywords", "Klíčová slova projektu"
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
|
||||||
|
doc( // acknowledgement
|
||||||
|
keyval(literal("acknowledgement"), dict(keyval(lang_keys, opt_cont_or_str))),
|
||||||
|
"acknowledgement", "Poděkování",
|
||||||
|
),
|
||||||
|
|
||||||
|
doc( // assignment
|
||||||
|
keyval(literal("assignment"), variants(
|
||||||
|
doc(string, none, "Zadání bude vloženo z PDF souboru s touto cestou"),
|
||||||
|
doc(
|
||||||
|
struct(
|
||||||
|
keyval(literal("personal_number"), cont_or_str),
|
||||||
|
keyval(literal("department"), cont_or_str),
|
||||||
|
keyval(literal("academical_year"), cont_or_str),
|
||||||
|
doc(keyval(literal("content"), cont), none, "Obsah zadání (zobrazen pod informacemi)"),
|
||||||
|
),
|
||||||
|
none, "Zadání bude vygenerováno šablonou"
|
||||||
|
),
|
||||||
|
doc(
|
||||||
|
null, none,
|
||||||
|
"Pokud je zadání vyžadováno typem dokumentu, bude vložena strana s upozorněním na vložení",
|
||||||
|
),
|
||||||
|
doc(cont, none, "Zdrojový kód se zadáním (tato možnost se nedoporučuje)"),
|
||||||
|
)),
|
||||||
|
"assignment", "Stránka / stránky se zadáním",
|
||||||
|
),
|
||||||
|
|
||||||
|
doc( // citations
|
||||||
|
keyval(literal("citations"), string),
|
||||||
|
"citations", "Cesta k souboru s citacemi",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
#let print_argument_docs() = {
|
||||||
|
signature_docs(arguments_structure);
|
||||||
|
}
|
||||||
|
|
||||||
#let arguments_structure = (
|
#let arguments_structure = (
|
||||||
document: (
|
document: (
|
||||||
|
|||||||
324
template/type_signature.typ
Normal file
324
template/type_signature.typ
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
#let doc(inner, argument_name, explanation) = {
|
||||||
|
inner.doc = (argname: argument_name, expl: explanation);
|
||||||
|
inner
|
||||||
|
}
|
||||||
|
|
||||||
|
#let type_primitive(id, name, cs_name) = {
|
||||||
|
(type: "primitive", type_id: id, type_name: name, type_name_cs: cs_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
#let int = type_primitive("integer", "an 'integer'", "celé číslo");
|
||||||
|
#let float = type_primitive("float", "a 'float'", "desetinné číslo");
|
||||||
|
#let bool = type_primitive("boolean", "a 'boolean'", "pravdivostní hodnota");
|
||||||
|
#let string = type_primitive("string", "a 'string'", "textový řetězec");
|
||||||
|
#let cont = type_primitive("content", "a 'content'", "obsah generovaný Typst syntaxí");
|
||||||
|
#let null = type_primitive("none", "a 'none'", "prázdná hodnota");
|
||||||
|
|
||||||
|
#let literal(value) = {
|
||||||
|
(type: "literal", value: value)
|
||||||
|
}
|
||||||
|
|
||||||
|
#let variants(..variants) = {
|
||||||
|
(type: "variants", variants: variants.pos())
|
||||||
|
}
|
||||||
|
|
||||||
|
#let slice(items) = {
|
||||||
|
(type: "slice", items: items)
|
||||||
|
}
|
||||||
|
|
||||||
|
#let tuple(..items) = {
|
||||||
|
(type: "tuple", items: items.pos())
|
||||||
|
}
|
||||||
|
|
||||||
|
#let keyval(key, val) = {
|
||||||
|
(type: "keyval", key: key, val: val)
|
||||||
|
}
|
||||||
|
|
||||||
|
#let dict(keyval) = {
|
||||||
|
(type: "dictionary", key: keyval.key, val: keyval.val)
|
||||||
|
}
|
||||||
|
|
||||||
|
#let struct(..keyvals) = {
|
||||||
|
let copy_doc(from, to) = {
|
||||||
|
if "doc" in from {
|
||||||
|
let to = to;
|
||||||
|
to.doc = from.doc;
|
||||||
|
to
|
||||||
|
} else {
|
||||||
|
to
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let keyvals = keyvals.pos();
|
||||||
|
let res = ().to-dict();
|
||||||
|
for keyval in keyvals {
|
||||||
|
if keyval.key.type != "literal" {
|
||||||
|
panic("invalid type signature, struct keys must be literals");
|
||||||
|
}
|
||||||
|
res.insert(keyval.key.value, copy_doc(keyval, keyval.val));
|
||||||
|
}
|
||||||
|
(type: "struct", pairs: res)
|
||||||
|
}
|
||||||
|
|
||||||
|
#let dbg_literal(literal, is_content: false) = {
|
||||||
|
let res = if type(literal) == str {
|
||||||
|
"\"" + literal + "\""
|
||||||
|
} else {
|
||||||
|
"'" + str(literal) + "'"
|
||||||
|
};
|
||||||
|
if is_content {
|
||||||
|
raw(res)
|
||||||
|
} else {
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#let signature_check(value, signature, name_prefix) = {
|
||||||
|
let error_target_name(target, name_prefix) = {
|
||||||
|
name_prefix + if "doc" in target { " ('" + target.doc.argname + "')" } else { "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
let error_value_name(value) = {
|
||||||
|
str(type(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
let error_expected_type(target) = {
|
||||||
|
if target.type == "variants" {
|
||||||
|
let variants = target.variants;
|
||||||
|
let last = variants.pop();
|
||||||
|
let res = (variants.map((v) => { error_expected_type(v) })).join(", ");
|
||||||
|
if type(last) != type(none) {
|
||||||
|
if type(res) != type(none) {
|
||||||
|
res + " or " + error_expected_type(last)
|
||||||
|
} else {
|
||||||
|
error_expected_type(last)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res
|
||||||
|
}
|
||||||
|
} else if target.type == "slice" or target.type == "tuple" {
|
||||||
|
"an array"
|
||||||
|
} else if target.type == "dictionary" or target.type == "struct" {
|
||||||
|
"a dictionary/hashmap"
|
||||||
|
} else if target.type == "primitive" {
|
||||||
|
target.type_name
|
||||||
|
} else if target.type == "literal" {
|
||||||
|
dbg_literal(target.value)
|
||||||
|
} else {
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let error(target, name_prefix, value, is_value: false, target_doc: none) = {
|
||||||
|
if type(target_doc) != type(none) {
|
||||||
|
error_target_name(target_doc)
|
||||||
|
} else {
|
||||||
|
error_target_name(target, name_prefix)
|
||||||
|
} + " " + if is_value {
|
||||||
|
"is unexpected"
|
||||||
|
} else {
|
||||||
|
"has an unexpected type '" + error_value_name(value) + "'"
|
||||||
|
} + ", expected " + error_expected_type(target)
|
||||||
|
}
|
||||||
|
|
||||||
|
let in_variants(value, variants, matcher) = {
|
||||||
|
for variant in variants {
|
||||||
|
if matcher(value, variant).at(0) == true {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
let matches_type(value, target, name_prefix: "") = {
|
||||||
|
if target.type == "variants" {
|
||||||
|
return if in_variants(value, target.variants, matches_type.with(name_prefix: name_prefix)) {
|
||||||
|
(true,)
|
||||||
|
} else {
|
||||||
|
(false, error(target, name_prefix, value, is_value: true))
|
||||||
|
}
|
||||||
|
} else if target.type == "literal" {
|
||||||
|
return if value != target.value {
|
||||||
|
(false, error(target, name_prefix, value, is_value: true))
|
||||||
|
} else {
|
||||||
|
(true,)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if type(value) == dictionary {
|
||||||
|
if target.type == "struct" {
|
||||||
|
for key in target.pairs.keys() {
|
||||||
|
if key not in value {
|
||||||
|
return (false, (
|
||||||
|
error_target_name(target, name_prefix) +
|
||||||
|
" is missing an entry for key " +
|
||||||
|
dbg_literal(key)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (key, val) in value.pairs() {
|
||||||
|
if key not in target.pairs {
|
||||||
|
return (
|
||||||
|
false, name_prefix + " contains an unexpected key " + dbg_literal(key)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
matches_type(
|
||||||
|
val, target.pairs.at(key), name_prefix: name_prefix + " " + str(key)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else if target.type == "dictionary" {
|
||||||
|
for (key, val) in value.pairs() {
|
||||||
|
let cur = matches_type(key, target.key, name_prefix: name_prefix + " key");
|
||||||
|
if not cur.at(0) {
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
let cur = matches_type(
|
||||||
|
val, target.val, name_prefix: name_prefix + " value"
|
||||||
|
);
|
||||||
|
if not cur.at(0) {
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(true,)
|
||||||
|
} else {
|
||||||
|
(false, error(target, name_prefix, value))
|
||||||
|
}
|
||||||
|
} else if type(value) == array {
|
||||||
|
if target.type == "slice" {
|
||||||
|
for (idx, val) in value.enumerate() {
|
||||||
|
let cur = matches_type(
|
||||||
|
val, target.items, name_prefix: name_prefix + " item at index " + str(idx)
|
||||||
|
);
|
||||||
|
if not cur.at(0) {
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(true,)
|
||||||
|
} else if target.type == "tuple" {
|
||||||
|
for (idx, target) in target.items.enumerate() {
|
||||||
|
if idx >= value.len() {
|
||||||
|
return (false, name_prefix + " is missing an item: " + error_expected_type(target))
|
||||||
|
}
|
||||||
|
let cur = matches_type(
|
||||||
|
value.at(idx), target, name_prefix: name_prefix + " item at index " + str(idx)
|
||||||
|
);
|
||||||
|
if not cur.at(0) {
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(true,)
|
||||||
|
} else {
|
||||||
|
(false, error(target, name_prefix, value))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if target.type != "primitive" or str(type(value)) != target.type_id {
|
||||||
|
(false, error(target, name_prefix, value))
|
||||||
|
} else {
|
||||||
|
(true,)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
matches_type(value, signature, name_prefix: name_prefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
#let signature_docs(target, is_nested: false) = {
|
||||||
|
let typeinfo(target, flatten: false, disable_doc: false) = {
|
||||||
|
let try_doc(target, mapper: (v) => { v }) = {
|
||||||
|
if "doc" in target and not disable_doc {
|
||||||
|
mapper(target.doc.expl);
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if target.type == "struct" {
|
||||||
|
if not flatten {
|
||||||
|
[slovník s přesnými atributy (_dictionary_)];
|
||||||
|
try_doc(target, mapper: (v) => { [ -- ]; v; });
|
||||||
|
":";
|
||||||
|
}
|
||||||
|
list(
|
||||||
|
..target.pairs.pairs().map(((key, val)) => {
|
||||||
|
raw(key);
|
||||||
|
try_doc(val, mapper: (v) => { [ -- ]; text(v); });
|
||||||
|
": "
|
||||||
|
typeinfo(val, disable_doc: true);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else if target.type == "dictionary" {
|
||||||
|
[slovník (_dictionary_)];
|
||||||
|
try_doc(target, mapper: (v) => { [ -- ]; v; });
|
||||||
|
":";
|
||||||
|
list(
|
||||||
|
{
|
||||||
|
"S klíči: ";
|
||||||
|
typeinfo(target.key);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"S hodnotami: ";
|
||||||
|
typeinfo(target.val);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else if target.type == "slice" {
|
||||||
|
try_doc(target, mapper: (v) => { v; ": "; });
|
||||||
|
[pole různé délky (_array_) s prvky: ];
|
||||||
|
typeinfo(target.items, disable_doc: true);
|
||||||
|
} else if target.type == "tuple" {
|
||||||
|
try_doc(target, mapper: (v) => { v; ": "; });
|
||||||
|
[pole (_array_) s upřesněnými prvky: ];
|
||||||
|
list(
|
||||||
|
..target.items.map((v) => {
|
||||||
|
list.item({
|
||||||
|
typeinfo(v);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else if target.type == "primitive" {
|
||||||
|
if target.type_id == "none" {
|
||||||
|
text("prázdné ('none')");
|
||||||
|
try_doc(target, mapper: (v) => { [ -- ]; text(v); });
|
||||||
|
} else {
|
||||||
|
text(target.type_name_cs + " (");
|
||||||
|
text(target.type_id, style: "italic");
|
||||||
|
text(")");
|
||||||
|
try_doc(target, mapper: (v) => { [ -- ]; text(v); });
|
||||||
|
}
|
||||||
|
} else if target.type == "variants" {
|
||||||
|
try_doc(target, mapper: (v) => { text(v); ":"; });
|
||||||
|
list(
|
||||||
|
..target.variants.map((v) => {
|
||||||
|
list.item({
|
||||||
|
typeinfo(v);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else if target.type == "literal" {
|
||||||
|
dbg_literal(target.value, is_content: true);
|
||||||
|
try_doc(target, mapper: (v) => { [ -- ]; text(v); });
|
||||||
|
} else {
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let args = ();
|
||||||
|
if target.type == "struct" {
|
||||||
|
for val in target.pairs.values() {
|
||||||
|
args.push(signature_docs(val, is_nested: true));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if "doc" in target and type(target.doc.argname) != type(none) {
|
||||||
|
args.push({
|
||||||
|
raw(target.doc.argname);
|
||||||
|
[ -- ]
|
||||||
|
typeinfo(target);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if not is_nested {
|
||||||
|
list(spacing: 2em, ..args.flatten());
|
||||||
|
} else {
|
||||||
|
args.flatten()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user