mirror of
https://github.com/RGBCube/alejandra
synced 2025-07-30 12:07:46 +00:00
feat: support bin-op again
This commit is contained in:
parent
f9d2a27751
commit
4afecdb5df
10 changed files with 115 additions and 54 deletions
|
@ -144,63 +144,92 @@ fn format(
|
||||||
let rule = match kind {
|
let rule = match kind {
|
||||||
// a b
|
// a b
|
||||||
rnix::SyntaxKind::NODE_APPLY => crate::rules::apply::rule,
|
rnix::SyntaxKind::NODE_APPLY => crate::rules::apply::rule,
|
||||||
|
|
||||||
// assert a; b
|
// assert a; b
|
||||||
rnix::SyntaxKind::NODE_ASSERT => crate::rules::scoped::rule, /* a.b.c */
|
rnix::SyntaxKind::NODE_ASSERT => crate::rules::scoped::rule,
|
||||||
|
|
||||||
|
// a.b.c
|
||||||
rnix::SyntaxKind::NODE_ATTRPATH => crate::rules::default,
|
rnix::SyntaxKind::NODE_ATTRPATH => crate::rules::default,
|
||||||
|
|
||||||
// a = b;
|
// a = b;
|
||||||
rnix::SyntaxKind::NODE_ATTRPATH_VALUE => {
|
rnix::SyntaxKind::NODE_ATTRPATH_VALUE => {
|
||||||
crate::rules::key_value::rule
|
crate::rules::key_value::rule
|
||||||
}
|
}
|
||||||
|
|
||||||
// { }
|
// { }
|
||||||
rnix::SyntaxKind::NODE_ATTR_SET => crate::rules::attr_set::rule,
|
rnix::SyntaxKind::NODE_ATTR_SET => crate::rules::attr_set::rule,
|
||||||
|
|
||||||
// a $op b
|
// a $op b
|
||||||
rnix::SyntaxKind::NODE_BIN_OP => crate::rules::default,
|
rnix::SyntaxKind::NODE_BIN_OP => crate::rules::bin_op::rule,
|
||||||
|
|
||||||
// ${a} (interpolation but for NODE_SELECT)
|
// ${a} (interpolation but for NODE_SELECT)
|
||||||
rnix::SyntaxKind::NODE_DYNAMIC => crate::rules::dynamic::rule,
|
rnix::SyntaxKind::NODE_DYNAMIC => crate::rules::dynamic::rule,
|
||||||
|
|
||||||
//
|
//
|
||||||
rnix::SyntaxKind::NODE_HAS_ATTR => crate::rules::default,
|
rnix::SyntaxKind::NODE_HAS_ATTR => crate::rules::default,
|
||||||
|
|
||||||
// $identifier
|
// $identifier
|
||||||
rnix::SyntaxKind::NODE_IDENT => crate::rules::default,
|
rnix::SyntaxKind::NODE_IDENT => crate::rules::default,
|
||||||
rnix::SyntaxKind::NODE_IDENT_PARAM => crate::rules::default,
|
rnix::SyntaxKind::NODE_IDENT_PARAM => crate::rules::default,
|
||||||
|
|
||||||
// if a then b else c
|
// if a then b else c
|
||||||
rnix::SyntaxKind::NODE_IF_ELSE => crate::rules::if_else::rule,
|
rnix::SyntaxKind::NODE_IF_ELSE => crate::rules::if_else::rule,
|
||||||
|
|
||||||
// inherit NODE_INHERIT_FROM? b+ ;
|
// inherit NODE_INHERIT_FROM? b+ ;
|
||||||
rnix::SyntaxKind::NODE_INHERIT => crate::rules::inherit::rule,
|
rnix::SyntaxKind::NODE_INHERIT => crate::rules::inherit::rule,
|
||||||
|
|
||||||
// ( a )
|
// ( a )
|
||||||
rnix::SyntaxKind::NODE_INHERIT_FROM => {
|
rnix::SyntaxKind::NODE_INHERIT_FROM => {
|
||||||
crate::rules::paren::rule
|
crate::rules::paren::rule
|
||||||
}
|
}
|
||||||
|
|
||||||
// ${a}
|
// ${a}
|
||||||
rnix::SyntaxKind::NODE_INTERPOL => crate::rules::paren::rule,
|
rnix::SyntaxKind::NODE_INTERPOL => crate::rules::paren::rule,
|
||||||
|
|
||||||
// a: b
|
// a: b
|
||||||
rnix::SyntaxKind::NODE_LAMBDA => crate::rules::lambda::rule,
|
rnix::SyntaxKind::NODE_LAMBDA => crate::rules::lambda::rule,
|
||||||
|
|
||||||
// let { }
|
// let { }
|
||||||
rnix::SyntaxKind::NODE_LEGACY_LET => crate::rules::default,
|
rnix::SyntaxKind::NODE_LEGACY_LET => crate::rules::default,
|
||||||
|
|
||||||
// let NODE_KEY_VALUE* in b;
|
// let NODE_KEY_VALUE* in b;
|
||||||
rnix::SyntaxKind::NODE_LET_IN => crate::rules::let_in::rule,
|
rnix::SyntaxKind::NODE_LET_IN => crate::rules::let_in::rule,
|
||||||
|
|
||||||
// [ ... ]
|
// [ ... ]
|
||||||
rnix::SyntaxKind::NODE_LIST => crate::rules::list::rule,
|
rnix::SyntaxKind::NODE_LIST => crate::rules::list::rule,
|
||||||
|
|
||||||
// 1 | true | null
|
// 1 | true | null
|
||||||
rnix::SyntaxKind::NODE_LITERAL => crate::rules::default,
|
rnix::SyntaxKind::NODE_LITERAL => crate::rules::default,
|
||||||
|
|
||||||
// ( a )
|
// ( a )
|
||||||
rnix::SyntaxKind::NODE_PAREN => crate::rules::paren::rule,
|
rnix::SyntaxKind::NODE_PAREN => crate::rules::paren::rule,
|
||||||
|
|
||||||
// a | a ? b
|
// a | a ? b
|
||||||
rnix::SyntaxKind::NODE_PAT_BIND => crate::rules::pat_bind::rule,
|
rnix::SyntaxKind::NODE_PAT_BIND => crate::rules::pat_bind::rule,
|
||||||
|
|
||||||
// NODE_PAT_BIND | TOKEN_ELLIPSIS
|
// NODE_PAT_BIND | TOKEN_ELLIPSIS
|
||||||
rnix::SyntaxKind::NODE_PAT_ENTRY => {
|
rnix::SyntaxKind::NODE_PAT_ENTRY => {
|
||||||
crate::rules::pat_entry::rule
|
crate::rules::pat_entry::rule
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /path/to/${a}
|
||||||
rnix::SyntaxKind::NODE_PATH => crate::rules::default,
|
rnix::SyntaxKind::NODE_PATH => crate::rules::default,
|
||||||
|
|
||||||
// { NODE_PAT_ENTRY* }
|
// { NODE_PAT_ENTRY* }
|
||||||
rnix::SyntaxKind::NODE_PATTERN => crate::rules::pattern::rule,
|
rnix::SyntaxKind::NODE_PATTERN => crate::rules::pattern::rule,
|
||||||
|
|
||||||
// implementation detail of rowan
|
// implementation detail of rowan
|
||||||
rnix::SyntaxKind::NODE_ROOT => crate::rules::root::rule,
|
rnix::SyntaxKind::NODE_ROOT => crate::rules::root::rule,
|
||||||
|
|
||||||
// a.b | a.NODE_DYNAMIC
|
// a.b | a.NODE_DYNAMIC
|
||||||
rnix::SyntaxKind::NODE_SELECT => crate::rules::default,
|
rnix::SyntaxKind::NODE_SELECT => crate::rules::default,
|
||||||
|
|
||||||
// "..." || ''...''
|
// "..." || ''...''
|
||||||
rnix::SyntaxKind::NODE_STRING => crate::rules::string::rule,
|
rnix::SyntaxKind::NODE_STRING => crate::rules::string::rule,
|
||||||
|
|
||||||
// !a
|
// !a
|
||||||
rnix::SyntaxKind::NODE_UNARY_OP => crate::rules::default,
|
rnix::SyntaxKind::NODE_UNARY_OP => crate::rules::default,
|
||||||
|
|
||||||
// with a; b
|
// with a; b
|
||||||
rnix::SyntaxKind::NODE_WITH => crate::rules::scoped::rule,
|
rnix::SyntaxKind::NODE_WITH => crate::rules::scoped::rule,
|
||||||
kind => {
|
kind => {
|
||||||
|
|
|
@ -2,14 +2,7 @@ pub(crate) fn rule(
|
||||||
build_ctx: &crate::builder::BuildCtx,
|
build_ctx: &crate::builder::BuildCtx,
|
||||||
node: &rnix::SyntaxNode,
|
node: &rnix::SyntaxNode,
|
||||||
) -> std::collections::LinkedList<crate::builder::Step> {
|
) -> std::collections::LinkedList<crate::builder::Step> {
|
||||||
rule_with_configuration(build_ctx, node, "bin_op_and_or_default")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn rule_with_configuration(
|
|
||||||
build_ctx: &crate::builder::BuildCtx,
|
|
||||||
node: &rnix::SyntaxNode,
|
|
||||||
parent_kind: &str,
|
|
||||||
) -> std::collections::LinkedList<crate::builder::Step> {
|
|
||||||
let mut steps = std::collections::LinkedList::new();
|
let mut steps = std::collections::LinkedList::new();
|
||||||
|
|
||||||
let mut children = crate::children2::new(build_ctx, node);
|
let mut children = crate::children2::new(build_ctx, node);
|
||||||
|
@ -30,11 +23,7 @@ pub(crate) fn rule_with_configuration(
|
||||||
if vertical {
|
if vertical {
|
||||||
let kind = first.element.kind();
|
let kind = first.element.kind();
|
||||||
|
|
||||||
if (parent_kind == "bin_op_and_or_default"
|
if matches!(kind, rnix::SyntaxKind::NODE_BIN_OP) {
|
||||||
&& matches!(kind, rnix::SyntaxKind::NODE_BIN_OP))
|
|
||||||
|| (parent_kind == "select"
|
|
||||||
&& matches!(kind, rnix::SyntaxKind::NODE_SELECT))
|
|
||||||
{
|
|
||||||
steps.push_back(crate::builder::Step::Format(first.element));
|
steps.push_back(crate::builder::Step::Format(first.element));
|
||||||
} else {
|
} else {
|
||||||
steps.push_back(crate::builder::Step::FormatWider(first.element));
|
steps.push_back(crate::builder::Step::FormatWider(first.element));
|
||||||
|
@ -65,7 +54,7 @@ pub(crate) fn rule_with_configuration(
|
||||||
}
|
}
|
||||||
|
|
||||||
// second
|
// second
|
||||||
if !vertical && parent_kind == "bin_op_and_or_default" {
|
if !vertical {
|
||||||
steps.push_back(crate::builder::Step::Whitespace);
|
steps.push_back(crate::builder::Step::Whitespace);
|
||||||
}
|
}
|
||||||
steps.push_back(crate::builder::Step::Format(second.element));
|
steps.push_back(crate::builder::Step::Format(second.element));
|
||||||
|
@ -90,9 +79,7 @@ pub(crate) fn rule_with_configuration(
|
||||||
crate::children2::Trivia::Newlines => {}
|
crate::children2::Trivia::Newlines => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if !second.has_inline_comment
|
} else if !second.has_inline_comment {
|
||||||
&& parent_kind == "bin_op_and_or_default"
|
|
||||||
{
|
|
||||||
steps.push_back(crate::builder::Step::Whitespace);
|
steps.push_back(crate::builder::Step::Whitespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
pub(crate) mod apply;
|
pub(crate) mod apply;
|
||||||
pub(crate) mod attr_set;
|
pub(crate) mod attr_set;
|
||||||
// pub(crate) mod bin_op;
|
pub(crate) mod bin_op;
|
||||||
pub(crate) mod dynamic;
|
pub(crate) mod dynamic;
|
||||||
pub(crate) mod if_else;
|
pub(crate) mod if_else;
|
||||||
pub(crate) mod inherit;
|
pub(crate) mod inherit;
|
||||||
|
|
|
@ -1,10 +1,49 @@
|
||||||
[
|
[
|
||||||
(1 + 1)
|
(1 + 1)
|
||||||
(1 +/**/1)
|
(1
|
||||||
(1/**/+ 1)
|
+
|
||||||
(1/**/+/**/1)
|
/**/
|
||||||
(1/**/+/**/(1/**/+/**/(1/**/+/**/1)))
|
1)
|
||||||
|
(1
|
||||||
|
/**/
|
||||||
|
+ 1)
|
||||||
|
(1
|
||||||
|
/**/
|
||||||
|
+
|
||||||
|
/**/
|
||||||
|
1)
|
||||||
|
(1
|
||||||
|
/**/
|
||||||
|
+
|
||||||
|
/**/
|
||||||
|
(1
|
||||||
|
/**/
|
||||||
|
+
|
||||||
|
/**/
|
||||||
|
(1
|
||||||
|
/**/
|
||||||
|
+
|
||||||
|
/**/
|
||||||
|
1)))
|
||||||
(1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1)
|
(1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1)
|
||||||
(1
|
(1
|
||||||
+ 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1)
|
+ 1
|
||||||
|
+ 1
|
||||||
|
+ 1
|
||||||
|
+ 1
|
||||||
|
+ 1
|
||||||
|
+ 1
|
||||||
|
+ 1
|
||||||
|
+ 1
|
||||||
|
+ 1
|
||||||
|
+ 1
|
||||||
|
+ 1
|
||||||
|
+ 1
|
||||||
|
+ 1
|
||||||
|
+ 1
|
||||||
|
+ 1
|
||||||
|
+ 1
|
||||||
|
+ 1
|
||||||
|
+ 1
|
||||||
|
+ 1)
|
||||||
]
|
]
|
||||||
|
|
|
@ -98,7 +98,7 @@
|
||||||
builtins.bitAnd
|
builtins.bitAnd
|
||||||
or (import ./zip-int-bits.nix
|
or (import ./zip-int-bits.nix
|
||||||
(a: b:
|
(a: b:
|
||||||
if a==1 && b==1
|
if a == 1 && b == 1
|
||||||
then 1
|
then 1
|
||||||
else 0));
|
else 0));
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@
|
||||||
builtins.bitOr
|
builtins.bitOr
|
||||||
or (import ./zip-int-bits.nix
|
or (import ./zip-int-bits.nix
|
||||||
(a: b:
|
(a: b:
|
||||||
if a==1 || b==1
|
if a == 1 || b == 1
|
||||||
then 1
|
then 1
|
||||||
else 0));
|
else 0));
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@
|
||||||
builtins.bitXor
|
builtins.bitXor
|
||||||
or (import ./zip-int-bits.nix
|
or (import ./zip-int-bits.nix
|
||||||
(a: b:
|
(a: b:
|
||||||
if a!=b
|
if a != b
|
||||||
then 1
|
then 1
|
||||||
else 0));
|
else 0));
|
||||||
|
|
||||||
|
@ -482,8 +482,9 @@
|
||||||
Check whether something is a function or something
|
Check whether something is a function or something
|
||||||
annotated with function args.
|
annotated with function args.
|
||||||
*/
|
*/
|
||||||
isFunction = f: builtins.isFunction f ||
|
isFunction = f:
|
||||||
(f ? __functor && isFunction (f.__functor f));
|
builtins.isFunction f
|
||||||
|
|| (f ? __functor && isFunction (f.__functor f));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Convert the given positive integer to a string of its hexadecimal
|
Convert the given positive integer to a string of its hexadecimal
|
||||||
|
|
|
@ -81,10 +81,11 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
boot.kernelParams = mkOption {
|
boot.kernelParams = mkOption {
|
||||||
type = types.listOf (types.strMatching ''([^"[:space:]]|"[^"]*")+'' // {
|
type = types.listOf (types.strMatching ''([^"[:space:]]|"[^"]*")+''
|
||||||
name = "kernelParam";
|
// {
|
||||||
description = "string, with spaces inside double quotes";
|
name = "kernelParam";
|
||||||
});
|
description = "string, with spaces inside double quotes";
|
||||||
|
});
|
||||||
default = [];
|
default = [];
|
||||||
description = "Parameters added to the kernel command line.";
|
description = "Parameters added to the kernel command line.";
|
||||||
};
|
};
|
||||||
|
@ -244,7 +245,8 @@ in {
|
||||||
"hid_logitech_hidpp"
|
"hid_logitech_hidpp"
|
||||||
"hid_logitech_dj"
|
"hid_logitech_dj"
|
||||||
"hid_microsoft"
|
"hid_microsoft"
|
||||||
] ++ optionals pkgs.stdenv.hostPlatform.isx86 [
|
]
|
||||||
|
++ optionals pkgs.stdenv.hostPlatform.isx86 [
|
||||||
# Misc. x86 keyboard stuff.
|
# Misc. x86 keyboard stuff.
|
||||||
"pcips2"
|
"pcips2"
|
||||||
"atkbd"
|
"atkbd"
|
||||||
|
@ -268,8 +270,8 @@ in {
|
||||||
# Implement consoleLogLevel both in early boot and using sysctl
|
# Implement consoleLogLevel both in early boot and using sysctl
|
||||||
# (so you don't need to reboot to have changes take effect).
|
# (so you don't need to reboot to have changes take effect).
|
||||||
boot.kernelParams =
|
boot.kernelParams =
|
||||||
["loglevel=${toString config.boot.consoleLogLevel}"] ++
|
["loglevel=${toString config.boot.consoleLogLevel}"]
|
||||||
optionals config.boot.vesa ["vga=0x317" "nomodeset"];
|
++ optionals config.boot.vesa ["vga=0x317" "nomodeset"];
|
||||||
|
|
||||||
boot.kernel.sysctl."kernel.printk" = mkDefault config.boot.consoleLogLevel;
|
boot.kernel.sysctl."kernel.printk" = mkDefault config.boot.consoleLogLevel;
|
||||||
|
|
||||||
|
@ -337,7 +339,8 @@ in {
|
||||||
# !!! Should this really be needed?
|
# !!! Should this really be needed?
|
||||||
(isYes "MODULES")
|
(isYes "MODULES")
|
||||||
(isYes "BINFMT_ELF")
|
(isYes "BINFMT_ELF")
|
||||||
] ++ (optional (randstructSeed != "") (isYes "GCC_PLUGIN_RANDSTRUCT"));
|
]
|
||||||
|
++ (optional (randstructSeed != "") (isYes "GCC_PLUGIN_RANDSTRUCT"));
|
||||||
|
|
||||||
# nixpkgs kernels are assumed to have all required features
|
# nixpkgs kernels are assumed to have all required features
|
||||||
assertions =
|
assertions =
|
||||||
|
|
|
@ -81,10 +81,11 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
boot.kernelParams = mkOption {
|
boot.kernelParams = mkOption {
|
||||||
type = types.listOf (types.strMatching ''([^"[:space:]]|"[^"]*")+'' // {
|
type = types.listOf (types.strMatching ''([^"[:space:]]|"[^"]*")+''
|
||||||
name = "kernelParam";
|
// {
|
||||||
description = "string, with spaces inside double quotes";
|
name = "kernelParam";
|
||||||
});
|
description = "string, with spaces inside double quotes";
|
||||||
|
});
|
||||||
default = [];
|
default = [];
|
||||||
description = "Parameters added to the kernel command line.";
|
description = "Parameters added to the kernel command line.";
|
||||||
};
|
};
|
||||||
|
@ -244,7 +245,8 @@ in {
|
||||||
"hid_logitech_hidpp"
|
"hid_logitech_hidpp"
|
||||||
"hid_logitech_dj"
|
"hid_logitech_dj"
|
||||||
"hid_microsoft"
|
"hid_microsoft"
|
||||||
] ++ optionals pkgs.stdenv.hostPlatform.isx86 [
|
]
|
||||||
|
++ optionals pkgs.stdenv.hostPlatform.isx86 [
|
||||||
# Misc. x86 keyboard stuff.
|
# Misc. x86 keyboard stuff.
|
||||||
"pcips2"
|
"pcips2"
|
||||||
"atkbd"
|
"atkbd"
|
||||||
|
@ -268,8 +270,8 @@ in {
|
||||||
# Implement consoleLogLevel both in early boot and using sysctl
|
# Implement consoleLogLevel both in early boot and using sysctl
|
||||||
# (so you don't need to reboot to have changes take effect).
|
# (so you don't need to reboot to have changes take effect).
|
||||||
boot.kernelParams =
|
boot.kernelParams =
|
||||||
["loglevel=${toString config.boot.consoleLogLevel}"] ++
|
["loglevel=${toString config.boot.consoleLogLevel}"]
|
||||||
optionals config.boot.vesa ["vga=0x317" "nomodeset"];
|
++ optionals config.boot.vesa ["vga=0x317" "nomodeset"];
|
||||||
|
|
||||||
boot.kernel.sysctl."kernel.printk" = mkDefault config.boot.consoleLogLevel;
|
boot.kernel.sysctl."kernel.printk" = mkDefault config.boot.consoleLogLevel;
|
||||||
|
|
||||||
|
@ -337,7 +339,8 @@ in {
|
||||||
# !!! Should this really be needed?
|
# !!! Should this really be needed?
|
||||||
(isYes "MODULES")
|
(isYes "MODULES")
|
||||||
(isYes "BINFMT_ELF")
|
(isYes "BINFMT_ELF")
|
||||||
] ++ (optional (randstructSeed != "") (isYes "GCC_PLUGIN_RANDSTRUCT"));
|
]
|
||||||
|
++ (optional (randstructSeed != "") (isYes "GCC_PLUGIN_RANDSTRUCT"));
|
||||||
|
|
||||||
# nixpkgs kernels are assumed to have all required features
|
# nixpkgs kernels are assumed to have all required features
|
||||||
assertions =
|
assertions =
|
||||||
|
|
|
@ -60,10 +60,7 @@ in {
|
||||||
|
|
||||||
type =
|
type =
|
||||||
types.unspecified
|
types.unspecified
|
||||||
|
// {
|
||||||
//
|
|
||||||
|
|
||||||
{
|
|
||||||
merge =
|
merge =
|
||||||
mergeEqualOption;
|
mergeEqualOption;
|
||||||
};
|
};
|
||||||
|
@ -84,10 +81,7 @@ in {
|
||||||
or
|
or
|
||||||
|
|
||||||
[])
|
[])
|
||||||
|
++ kernelPatches;
|
||||||
++
|
|
||||||
|
|
||||||
kernelPatches;
|
|
||||||
|
|
||||||
features =
|
features =
|
||||||
lib.recursiveUpdate
|
lib.recursiveUpdate
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
[
|
[
|
||||||
(1 |> builtins.add 2 |> builtins.mul 3)
|
(1 |> builtins.add 2 |> builtins.mul 3)
|
||||||
(builtins.add 1 <| builtins.mul 2 <| 3)
|
(builtins.add 1 <| builtins.mul 2 <| 3)
|
||||||
|
(1 |> builtins.add 2 |>
|
||||||
|
builtins.mul 3)
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
[
|
[
|
||||||
(1 |> builtins.add 2 |> builtins.mul 3)
|
(1 |> builtins.add 2 |> builtins.mul 3)
|
||||||
(builtins.add 1 <| builtins.mul 2 <| 3)
|
(builtins.add 1 <| builtins.mul 2 <| 3)
|
||||||
|
(1
|
||||||
|
|> builtins.add 2
|
||||||
|
|> builtins.mul 3)
|
||||||
]
|
]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue