twa: add support for very-weak property
* spot/twa/twa.hh: Implement the property. * spot/parseaut/parseaut.yy, spot/twaalgos/hoa.cc: Add input and output for it. * spot/twaalgos/strength.cc, spot/twaalgos/strength.hh (is_very_weak_automaton): New function. * tests/core/alternating.test: Add a test for --check=strength on an alternating automaton. * tests/core/strength.test, tests/core/parseaut.test: Adjust expected output. * NEWS, doc/org/hoa.org, doc/org/concepts.org: Document it.
This commit is contained in:
parent
a4ce999402
commit
582d455c23
11 changed files with 146 additions and 33 deletions
4
NEWS
4
NEWS
|
|
@ -14,6 +14,10 @@ New in spot 2.2.2.dev (Not yet released)
|
||||||
* The new version of the Couvreur emptiness check is now the default
|
* The new version of the Couvreur emptiness check is now the default
|
||||||
one, used by is_empty() and accepting_run().
|
one, used by is_empty() and accepting_run().
|
||||||
|
|
||||||
|
* twa objects have a new property, very-weak, that can be set or
|
||||||
|
retrieved via twa::prop_very_weak(), and that can be tested by
|
||||||
|
is_very_weak_automaton().
|
||||||
|
|
||||||
Build:
|
Build:
|
||||||
|
|
||||||
* The configure script has a new option --enable-c++14, to compile in
|
* The configure script has a new option --enable-c++14, to compile in
|
||||||
|
|
|
||||||
|
|
@ -995,6 +995,7 @@ automaton, and that can be queried or set by algorithms:
|
||||||
| =state_acc= | automaton should be considered has having state-based acceptance |
|
| =state_acc= | automaton should be considered has having state-based acceptance |
|
||||||
| =inherently_weak= | accepting and rejecting cycles cannot be mixed in the same SCC |
|
| =inherently_weak= | accepting and rejecting cycles cannot be mixed in the same SCC |
|
||||||
| =weak= | transitions of an SCC all belong to the same acceptance sets |
|
| =weak= | transitions of an SCC all belong to the same acceptance sets |
|
||||||
|
| =very-weak= | weak automaton where all SCCs have size 1 |
|
||||||
| =terminal= | automaton is weak, accepting SCCs are complete, accepting edges may not go to rejecting SCCs |
|
| =terminal= | automaton is weak, accepting SCCs are complete, accepting edges may not go to rejecting SCCs |
|
||||||
| =deterministic= | there is at most one run *recognizing* a word, but not necessarily accepting it |
|
| =deterministic= | there is at most one run *recognizing* a word, but not necessarily accepting it |
|
||||||
| =unambiguous= | there is at most one run *accepting* a word (but it might be recognized several time) |
|
| =unambiguous= | there is at most one run *accepting* a word (but it might be recognized several time) |
|
||||||
|
|
|
||||||
|
|
@ -603,10 +603,10 @@ body of the file, and then return and error if what has been declared
|
||||||
does not correspond to the reality.
|
does not correspond to the reality.
|
||||||
|
|
||||||
Some supported properties (like =weak=, =inherently-weak=,
|
Some supported properties (like =weak=, =inherently-weak=,
|
||||||
=unambiguous=, or =stutter-invariant=) are not double-checked, because
|
=very-weak=, =terminal=, =unambiguous=, or =stutter-invariant=) are
|
||||||
that would require more operations. Command-line tools that
|
not double-checked, because that would require more operations.
|
||||||
read HOA files all take a =--trust-hoa=no= option to ignore properties
|
Command-line tools that read HOA files all take a =--trust-hoa=no=
|
||||||
that are not double-checked by the parser.
|
option to ignore properties that are not double-checked by the parser.
|
||||||
|
|
||||||
It should be noted that each property can take three values: true,
|
It should be noted that each property can take three values: true,
|
||||||
false, or maybe. So actually two bits are used per property. For
|
false, or maybe. So actually two bits are used per property. For
|
||||||
|
|
@ -653,7 +653,7 @@ particular:
|
||||||
that do not try to output deterministic automata.
|
that do not try to output deterministic automata.
|
||||||
|
|
||||||
| property | parser | stored | printer | notes |
|
| property | parser | stored | printer | notes |
|
||||||
|---------------------+---------+--------+---------------------------------------------+------------------------------------------------------------------|
|
|---------------------+---------+--------+---------------------------------------------------------+------------------------------------------------------------------|
|
||||||
| =state-labels= | checked | no | checked if =-Hk= | state labels are converted to transition labels when reading TωA |
|
| =state-labels= | checked | no | checked if =-Hk= | state labels are converted to transition labels when reading TωA |
|
||||||
| =trans-labels= | checked | no | always, unless =-Hi= or =-Hk= | |
|
| =trans-labels= | checked | no | always, unless =-Hi= or =-Hk= | |
|
||||||
| =implicit-labels= | checked | no | if =-Hi= | =-Hi= only works for deterministic automata |
|
| =implicit-labels= | checked | no | if =-Hi= | =-Hi= only works for deterministic automata |
|
||||||
|
|
@ -667,7 +667,8 @@ particular:
|
||||||
| =stutter-invariant= | trusted | yes | as stored | can be checked with =--check=stuttering= |
|
| =stutter-invariant= | trusted | yes | as stored | can be checked with =--check=stuttering= |
|
||||||
| =stutter-sensitive= | trusted | yes | as stored (opposite of =stutter-invariant=) | can be checked with =--check=stuttering= |
|
| =stutter-sensitive= | trusted | yes | as stored (opposite of =stutter-invariant=) | can be checked with =--check=stuttering= |
|
||||||
| =terminal= | trusted | yes | as stored | can be checked with =--check=strength= |
|
| =terminal= | trusted | yes | as stored | can be checked with =--check=strength= |
|
||||||
| =weak= | trusted | yes | as stored if (=-Hv= or not =terminal=) | can be checked with =--check=strength= |
|
| =very-weak= | trusted | yes | as stored if (=-Hv= or not =terminal=) | can be checked with =--check=strength= |
|
||||||
|
| =weak= | trusted | yes | as stored if (=-Hv= or not (=terminal= or =very-weak=)) | can be checked with =--check=strength= |
|
||||||
| =inherently-weak= | trusted | yes | as stored if (=-Hv= or not =weak=) | can be checked with =--check=strength= |
|
| =inherently-weak= | trusted | yes | as stored if (=-Hv= or not =weak=) | can be checked with =--check=strength= |
|
||||||
| =colored= | ignored | no | checked | |
|
| =colored= | ignored | no | checked | |
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -526,8 +526,27 @@ header: format-version header-items
|
||||||
a->prop_stutter_invariant(!ss->second.val);
|
a->prop_stutter_invariant(!ss->second.val);
|
||||||
}
|
}
|
||||||
auto iw = p.find("inherently-weak");
|
auto iw = p.find("inherently-weak");
|
||||||
|
auto vw = p.find("very-weak");
|
||||||
auto w = p.find("weak");
|
auto w = p.find("weak");
|
||||||
auto t = p.find("terminal");
|
auto t = p.find("terminal");
|
||||||
|
if (vw != e)
|
||||||
|
{
|
||||||
|
a->prop_very_weak(vw->second.val);
|
||||||
|
if (w != e && !w->second.val && vw->second.val)
|
||||||
|
{
|
||||||
|
error(w->second.loc,
|
||||||
|
"'properties: !weak' contradicts...");
|
||||||
|
error(vw->second.loc,
|
||||||
|
"... 'properties: very-weak' given here");
|
||||||
|
}
|
||||||
|
if (iw != e && !iw->second.val && vw->second.val)
|
||||||
|
{
|
||||||
|
error(iw->second.loc,
|
||||||
|
"'properties: !inherently-weak' contradicts...");
|
||||||
|
error(vw->second.loc,
|
||||||
|
"... 'properties: very-weak' given here");
|
||||||
|
}
|
||||||
|
}
|
||||||
if (iw != e)
|
if (iw != e)
|
||||||
{
|
{
|
||||||
a->prop_inherently_weak(iw->second.val);
|
a->prop_inherently_weak(iw->second.val);
|
||||||
|
|
|
||||||
|
|
@ -990,6 +990,7 @@ namespace spot
|
||||||
trival::repr_t deterministic:2; // Deterministic automaton.
|
trival::repr_t deterministic:2; // Deterministic automaton.
|
||||||
trival::repr_t unambiguous:2; // Unambiguous automaton.
|
trival::repr_t unambiguous:2; // Unambiguous automaton.
|
||||||
trival::repr_t stutter_invariant:2; // Stutter invariant language.
|
trival::repr_t stutter_invariant:2; // Stutter invariant language.
|
||||||
|
trival::repr_t very_weak:2; // very-weak, or 1-weak
|
||||||
};
|
};
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
|
|
@ -1167,7 +1168,7 @@ namespace spot
|
||||||
/// \brief Set the "inherently weak" proeprty.
|
/// \brief Set the "inherently weak" proeprty.
|
||||||
///
|
///
|
||||||
/// Setting "inherently weak" to false automatically
|
/// Setting "inherently weak" to false automatically
|
||||||
/// disables "terminal" and "weak".
|
/// disables "terminal", "very weak", and "weak".
|
||||||
///
|
///
|
||||||
/// \see prop_weak()
|
/// \see prop_weak()
|
||||||
/// \see prop_terminal()
|
/// \see prop_terminal()
|
||||||
|
|
@ -1175,7 +1176,7 @@ namespace spot
|
||||||
{
|
{
|
||||||
is.inherently_weak = val.val();
|
is.inherently_weak = val.val();
|
||||||
if (!val)
|
if (!val)
|
||||||
is.terminal = is.weak = val.val();
|
is.very_weak = is.terminal = is.weak = val.val();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Whether the automaton is terminal.
|
/// \brief Whether the automaton is terminal.
|
||||||
|
|
@ -1234,9 +1235,38 @@ namespace spot
|
||||||
if (val)
|
if (val)
|
||||||
is.inherently_weak = val.val();
|
is.inherently_weak = val.val();
|
||||||
if (!val)
|
if (!val)
|
||||||
is.terminal = val.val();
|
is.very_weak = is.terminal = val.val();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Whether the automaton is very-weak.
|
||||||
|
///
|
||||||
|
/// An automaton is very-weak if it is weak (inside each strongly connected
|
||||||
|
/// component, all transitions belong to the same acceptance sets)
|
||||||
|
/// and each SCC contains only one state.
|
||||||
|
///
|
||||||
|
/// \see prop_terminal()
|
||||||
|
/// \see prop_weak()
|
||||||
|
trival prop_very_weak() const
|
||||||
|
{
|
||||||
|
return is.very_weak;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Set the very-weak property.
|
||||||
|
///
|
||||||
|
/// Marking an automaton as "very-weak" automatically marks it as
|
||||||
|
/// "weak" and "inherently weak".
|
||||||
|
///
|
||||||
|
/// \see prop_terminal()
|
||||||
|
/// \see prop_weak()
|
||||||
|
void prop_very_weak(trival val)
|
||||||
|
{
|
||||||
|
is.very_weak = val.val();
|
||||||
|
if (val)
|
||||||
|
is.weak = is.inherently_weak = val.val();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// \brief Whether the automaton is deterministic.
|
/// \brief Whether the automaton is deterministic.
|
||||||
///
|
///
|
||||||
/// An automaton is deterministic if the conjunction between the
|
/// An automaton is deterministic if the conjunction between the
|
||||||
|
|
@ -1400,6 +1430,7 @@ namespace spot
|
||||||
{
|
{
|
||||||
prop_terminal(other->prop_terminal());
|
prop_terminal(other->prop_terminal());
|
||||||
prop_weak(other->prop_weak());
|
prop_weak(other->prop_weak());
|
||||||
|
prop_very_weak(other->prop_very_weak());
|
||||||
prop_inherently_weak(other->prop_inherently_weak());
|
prop_inherently_weak(other->prop_inherently_weak());
|
||||||
}
|
}
|
||||||
if (p.deterministic)
|
if (p.deterministic)
|
||||||
|
|
|
||||||
|
|
@ -500,12 +500,18 @@ namespace spot
|
||||||
}
|
}
|
||||||
if (aut->prop_terminal())
|
if (aut->prop_terminal())
|
||||||
prop(" terminal");
|
prop(" terminal");
|
||||||
if (aut->prop_weak() && (verbose || aut->prop_terminal() != true))
|
if (aut->prop_very_weak() && (verbose || aut->prop_terminal() != true))
|
||||||
|
prop(" very-weak");
|
||||||
|
if (aut->prop_weak() && (verbose || (aut->prop_terminal() != true &&
|
||||||
|
aut->prop_very_weak() != true)))
|
||||||
prop(" weak");
|
prop(" weak");
|
||||||
if (aut->prop_inherently_weak() && (verbose || aut->prop_weak() != true))
|
if (aut->prop_inherently_weak() && (verbose || aut->prop_weak() != true))
|
||||||
prop(" inherently-weak");
|
prop(" inherently-weak");
|
||||||
if (v1_1 && !aut->prop_terminal() && (verbose || aut->prop_weak() != false))
|
if (v1_1 && !aut->prop_terminal() && (verbose || aut->prop_weak() != false))
|
||||||
prop(" !terminal");
|
prop(" !terminal");
|
||||||
|
if (v1_1 && !aut->prop_very_weak() && (verbose
|
||||||
|
|| aut->prop_weak() != false))
|
||||||
|
prop(" !very-weak");
|
||||||
if (v1_1 && !aut->prop_weak() && (verbose ||
|
if (v1_1 && !aut->prop_weak() && (verbose ||
|
||||||
aut->prop_inherently_weak() != false))
|
aut->prop_inherently_weak() != false))
|
||||||
prop(" !weak");
|
prop(" !weak");
|
||||||
|
|
|
||||||
|
|
@ -34,22 +34,29 @@ namespace spot
|
||||||
bool need_si = !si;
|
bool need_si = !si;
|
||||||
if (need_si)
|
if (need_si)
|
||||||
si = new scc_info(aut);
|
si = new scc_info(aut);
|
||||||
|
if (inweak)
|
||||||
si->determine_unknown_acceptance();
|
si->determine_unknown_acceptance();
|
||||||
|
|
||||||
bool is_inweak = true;
|
bool is_inweak = true;
|
||||||
bool is_weak = true;
|
bool is_weak = true;
|
||||||
|
bool is_single_state_scc = true;
|
||||||
bool is_term = true;
|
bool is_term = true;
|
||||||
unsigned n = si->scc_count();
|
unsigned n = si->scc_count();
|
||||||
for (unsigned i = 0; i < n; ++i)
|
for (unsigned i = 0; i < n; ++i)
|
||||||
{
|
{
|
||||||
if (si->is_trivial(i))
|
if (si->is_trivial(i))
|
||||||
continue;
|
continue;
|
||||||
|
if (si->states_of(i).size() > 1)
|
||||||
|
is_single_state_scc = false;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
acc_cond::mark_t m = 0U;
|
acc_cond::mark_t m = 0U;
|
||||||
if (is_weak)
|
if (is_weak)
|
||||||
for (auto src: si->states_of(i))
|
for (auto src: si->states_of(i))
|
||||||
for (auto& t: aut->out(src))
|
for (auto& t: aut->out(src))
|
||||||
if (si->scc_of(t.dst) == i)
|
// In case of a universal edge we only need to check
|
||||||
|
// the first destination of an inside the SCC, because
|
||||||
|
// the other have the same t.acc.
|
||||||
|
if (si->scc_of(*aut->univ_dests(t.dst).begin()) == i)
|
||||||
{
|
{
|
||||||
if (first)
|
if (first)
|
||||||
{
|
{
|
||||||
|
|
@ -98,6 +105,7 @@ namespace spot
|
||||||
if (terminal)
|
if (terminal)
|
||||||
aut->prop_terminal(is_term && is_weak);
|
aut->prop_terminal(is_term && is_weak);
|
||||||
aut->prop_weak(is_weak);
|
aut->prop_weak(is_weak);
|
||||||
|
aut->prop_very_weak(is_single_state_scc && is_weak);
|
||||||
if (inweak)
|
if (inweak)
|
||||||
aut->prop_inherently_weak(is_inweak);
|
aut->prop_inherently_weak(is_inweak);
|
||||||
}
|
}
|
||||||
|
|
@ -131,6 +139,17 @@ namespace spot
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_very_weak_automaton(const const_twa_graph_ptr& aut, scc_info* si)
|
||||||
|
{
|
||||||
|
trival v = aut->prop_very_weak();
|
||||||
|
if (v.is_known())
|
||||||
|
return v.is_true();
|
||||||
|
is_type_automaton<false, false, true>
|
||||||
|
(std::const_pointer_cast<twa_graph>(aut), si);
|
||||||
|
return aut->prop_very_weak().is_true();
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
is_inherently_weak_automaton(const const_twa_graph_ptr& aut, scc_info* si)
|
is_inherently_weak_automaton(const const_twa_graph_ptr& aut, scc_info* si)
|
||||||
{
|
{
|
||||||
|
|
@ -145,6 +164,9 @@ namespace spot
|
||||||
|
|
||||||
void check_strength(const twa_graph_ptr& aut, scc_info* si)
|
void check_strength(const twa_graph_ptr& aut, scc_info* si)
|
||||||
{
|
{
|
||||||
|
if (aut->is_alternating())
|
||||||
|
is_type_automaton<false, false, true>(aut, si);
|
||||||
|
else
|
||||||
is_type_automaton<true, true, true>(aut, si);
|
is_type_automaton<true, true, true>(aut, si);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,24 @@ namespace spot
|
||||||
SPOT_API bool
|
SPOT_API bool
|
||||||
is_weak_automaton(const const_twa_graph_ptr& aut, scc_info* sm = nullptr);
|
is_weak_automaton(const const_twa_graph_ptr& aut, scc_info* sm = nullptr);
|
||||||
|
|
||||||
|
/// \brief Check whether an automaton is very-weak.
|
||||||
|
///
|
||||||
|
/// An automaton is very-weak if in any given SCC, all transitions
|
||||||
|
/// belong to the same acceptance sets, and the SCC has only one
|
||||||
|
/// state.
|
||||||
|
///
|
||||||
|
/// \param aut the automaton to check
|
||||||
|
///
|
||||||
|
/// \param sm an scc_info object for the automaton if available (it
|
||||||
|
/// will be built otherwise).
|
||||||
|
///
|
||||||
|
/// In addition to returning the result as a Boolean, this will set
|
||||||
|
/// the prop_very_weak() and prop_weak() properties of the automaton
|
||||||
|
/// as a side-effect, so further calls will return in constant-time.
|
||||||
|
SPOT_API bool
|
||||||
|
is_very_weak_automaton(const const_twa_graph_ptr& aut,
|
||||||
|
scc_info* sm = nullptr);
|
||||||
|
|
||||||
/// \brief Check whether an automaton is inherently weak.
|
/// \brief Check whether an automaton is inherently weak.
|
||||||
///
|
///
|
||||||
/// An automaton is inherently weak if in any given SCC, there
|
/// An automaton is inherently weak if in any given SCC, there
|
||||||
|
|
@ -90,7 +108,8 @@ namespace spot
|
||||||
|
|
||||||
/// \brief Check whether an automaton is weak or terminal.
|
/// \brief Check whether an automaton is weak or terminal.
|
||||||
///
|
///
|
||||||
/// This sets the "weak" and "terminal" property as appropriate.
|
/// This sets the "inherently weak", "weak", "very-weak" and
|
||||||
|
/// "terminal" properties as appropriate.
|
||||||
///
|
///
|
||||||
/// \param aut the automaton to check
|
/// \param aut the automaton to check
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -126,3 +126,10 @@ digraph G {
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
diff expect.dot alt.dot
|
diff expect.dot alt.dot
|
||||||
|
|
||||||
|
autfilt --trust=no --check=strength alt.hoa | grep properties: >output
|
||||||
|
cat >expected <<EOF
|
||||||
|
properties: univ-branch trans-labels explicit-labels state-acc
|
||||||
|
properties: very-weak
|
||||||
|
EOF
|
||||||
|
diff output expected
|
||||||
|
|
|
||||||
|
|
@ -1928,6 +1928,7 @@ AP: 4 "p2" "c1" "p1" "c2"
|
||||||
acc-name: co-Buchi
|
acc-name: co-Buchi
|
||||||
Acceptance: 1 Fin(0)
|
Acceptance: 1 Fin(0)
|
||||||
properties: univ-branch trans-labels explicit-labels state-acc
|
properties: univ-branch trans-labels explicit-labels state-acc
|
||||||
|
properties: very-weak
|
||||||
--BODY--
|
--BODY--
|
||||||
State: 0 "X (G(c2))"
|
State: 0 "X (G(c2))"
|
||||||
[t] 1
|
[t] 1
|
||||||
|
|
@ -2403,6 +2404,7 @@ AP: 2 "b" "a"
|
||||||
acc-name: co-Buchi
|
acc-name: co-Buchi
|
||||||
Acceptance: 1 Fin(0)
|
Acceptance: 1 Fin(0)
|
||||||
properties: univ-branch trans-labels explicit-labels state-acc
|
properties: univ-branch trans-labels explicit-labels state-acc
|
||||||
|
properties: very-weak
|
||||||
--BODY--
|
--BODY--
|
||||||
State: 0 "((((a) U (b)) && GF(b)) && FG(a))"
|
State: 0 "((((a) U (b)) && GF(b)) && FG(a))"
|
||||||
[0] 3&1
|
[0] 3&1
|
||||||
|
|
@ -2608,6 +2610,7 @@ AP: 2 "b" "a"
|
||||||
acc-name: Buchi
|
acc-name: Buchi
|
||||||
Acceptance: 1 Inf(0)
|
Acceptance: 1 Inf(0)
|
||||||
properties: univ-branch trans-labels explicit-labels state-acc
|
properties: univ-branch trans-labels explicit-labels state-acc
|
||||||
|
properties: very-weak
|
||||||
--BODY--
|
--BODY--
|
||||||
State: 0 "((((a) U (b)) && GF(b)) && FG(a))"
|
State: 0 "((((a) U (b)) && GF(b)) && FG(a))"
|
||||||
[0] 3&1
|
[0] 3&1
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,7 @@ AP: 1 "a"
|
||||||
acc-name: Buchi
|
acc-name: Buchi
|
||||||
Acceptance: 1 Inf(0)
|
Acceptance: 1 Inf(0)
|
||||||
properties: trans-labels explicit-labels state-acc colored
|
properties: trans-labels explicit-labels state-acc colored
|
||||||
properties: deterministic weak
|
properties: deterministic very-weak
|
||||||
--BODY--
|
--BODY--
|
||||||
State: 0 {0}
|
State: 0 {0}
|
||||||
[t] 1
|
[t] 1
|
||||||
|
|
@ -644,7 +644,7 @@ AP: 1 "a"
|
||||||
acc-name: Buchi
|
acc-name: Buchi
|
||||||
Acceptance: 1 Inf(0)
|
Acceptance: 1 Inf(0)
|
||||||
properties: trans-labels explicit-labels trans-acc complete
|
properties: trans-labels explicit-labels trans-acc complete
|
||||||
properties: deterministic weak
|
properties: deterministic very-weak
|
||||||
--BODY--
|
--BODY--
|
||||||
State: 0
|
State: 0
|
||||||
[t] 0
|
[t] 0
|
||||||
|
|
@ -659,7 +659,7 @@ AP: 1 "a"
|
||||||
acc-name: co-Buchi
|
acc-name: co-Buchi
|
||||||
Acceptance: 1 Fin(0)
|
Acceptance: 1 Fin(0)
|
||||||
properties: trans-labels explicit-labels trans-acc complete
|
properties: trans-labels explicit-labels trans-acc complete
|
||||||
properties: deterministic weak
|
properties: deterministic very-weak
|
||||||
--BODY--
|
--BODY--
|
||||||
State: 0
|
State: 0
|
||||||
[t] 0
|
[t] 0
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue