mirror of
https://github.com/sockspls/badfish
synced 2025-04-30 16:53:09 +00:00
Change pos.pieces() argument order
Let first argument to be the 'color'. This allows to align pos.pieces() signatures with piece_list(), piece_count() and all the other functions where 'color' argument is passed as first one. No functional change. Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This commit is contained in:
parent
5e90580088
commit
b9bc6e823f
8 changed files with 59 additions and 59 deletions
|
@ -406,7 +406,7 @@ ScaleFactor Endgame<KBPsK>::operator()(const Position& pos) const {
|
|||
// No assertions about the material of weakerSide, because we want draws to
|
||||
// be detected even when the weaker side has some pawns.
|
||||
|
||||
Bitboard pawns = pos.pieces(PAWN, strongerSide);
|
||||
Bitboard pawns = pos.pieces(strongerSide, PAWN);
|
||||
File pawnFile = file_of(pos.piece_list(strongerSide, PAWN)[0]);
|
||||
|
||||
// All pawns are on a single rook file ?
|
||||
|
@ -460,12 +460,12 @@ ScaleFactor Endgame<KQKRPs>::operator()(const Position& pos) const {
|
|||
Square kingSq = pos.king_square(weakerSide);
|
||||
if ( relative_rank(weakerSide, kingSq) <= RANK_2
|
||||
&& relative_rank(weakerSide, pos.king_square(strongerSide)) >= RANK_4
|
||||
&& (pos.pieces(ROOK, weakerSide) & rank_bb(relative_rank(weakerSide, RANK_3)))
|
||||
&& (pos.pieces(PAWN, weakerSide) & rank_bb(relative_rank(weakerSide, RANK_2)))
|
||||
&& (pos.attacks_from<KING>(kingSq) & pos.pieces(PAWN, weakerSide)))
|
||||
&& (pos.pieces(weakerSide, ROOK) & rank_bb(relative_rank(weakerSide, RANK_3)))
|
||||
&& (pos.pieces(weakerSide, PAWN) & rank_bb(relative_rank(weakerSide, RANK_2)))
|
||||
&& (pos.attacks_from<KING>(kingSq) & pos.pieces(weakerSide, PAWN)))
|
||||
{
|
||||
Square rsq = pos.piece_list(weakerSide, ROOK)[0];
|
||||
if (pos.attacks_from<PAWN>(rsq, strongerSide) & pos.pieces(PAWN, weakerSide))
|
||||
if (pos.attacks_from<PAWN>(rsq, strongerSide) & pos.pieces(weakerSide, PAWN))
|
||||
return SCALE_FACTOR_DRAW;
|
||||
}
|
||||
return SCALE_FACTOR_NONE;
|
||||
|
@ -643,7 +643,7 @@ ScaleFactor Endgame<KPsK>::operator()(const Position& pos) const {
|
|||
assert(pos.piece_count(weakerSide, PAWN) == 0);
|
||||
|
||||
Square ksq = pos.king_square(weakerSide);
|
||||
Bitboard pawns = pos.pieces(PAWN, strongerSide);
|
||||
Bitboard pawns = pos.pieces(strongerSide, PAWN);
|
||||
|
||||
// Are all pawns on the 'a' file?
|
||||
if (!(pawns & ~FileABB))
|
||||
|
@ -712,7 +712,7 @@ ScaleFactor Endgame<KBPKB>::operator()(const Position& pos) const {
|
|||
{
|
||||
Bitboard path = forward_bb(strongerSide, pawnSq);
|
||||
|
||||
if (path & pos.pieces(KING, weakerSide))
|
||||
if (path & pos.pieces(weakerSide, KING))
|
||||
return SCALE_FACTOR_DRAW;
|
||||
|
||||
if ( (pos.attacks_from<BISHOP>(weakerBishopSq) & path)
|
||||
|
@ -779,14 +779,14 @@ ScaleFactor Endgame<KBPPKB>::operator()(const Position& pos) const {
|
|||
if ( ksq == blockSq1
|
||||
&& opposite_colors(ksq, wbsq)
|
||||
&& ( bbsq == blockSq2
|
||||
|| (pos.attacks_from<BISHOP>(blockSq2) & pos.pieces(BISHOP, weakerSide))
|
||||
|| (pos.attacks_from<BISHOP>(blockSq2) & pos.pieces(weakerSide, BISHOP))
|
||||
|| abs(r1 - r2) >= 2))
|
||||
return SCALE_FACTOR_DRAW;
|
||||
|
||||
else if ( ksq == blockSq2
|
||||
&& opposite_colors(ksq, wbsq)
|
||||
&& ( bbsq == blockSq1
|
||||
|| (pos.attacks_from<BISHOP>(blockSq1) & pos.pieces(BISHOP, weakerSide))))
|
||||
|| (pos.attacks_from<BISHOP>(blockSq1) & pos.pieces(weakerSide, BISHOP))))
|
||||
return SCALE_FACTOR_DRAW;
|
||||
else
|
||||
return SCALE_FACTOR_NONE;
|
||||
|
|
|
@ -519,8 +519,8 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
// no minor piece which can exchange the outpost piece.
|
||||
if (bonus && (ei.attackedBy[Us][PAWN] & s))
|
||||
{
|
||||
if ( !pos.pieces(KNIGHT, Them)
|
||||
&& !(same_color_squares(s) & pos.pieces(BISHOP, Them)))
|
||||
if ( !pos.pieces(Them, KNIGHT)
|
||||
&& !(same_color_squares(s) & pos.pieces(Them, BISHOP)))
|
||||
bonus += bonus + bonus / 2;
|
||||
else
|
||||
bonus += bonus / 2;
|
||||
|
@ -551,9 +551,9 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
if (Piece == KNIGHT || Piece == QUEEN)
|
||||
b = pos.attacks_from<Piece>(s);
|
||||
else if (Piece == BISHOP)
|
||||
b = attacks_bb<BISHOP>(s, pos.pieces() ^ pos.pieces(QUEEN, Us));
|
||||
b = attacks_bb<BISHOP>(s, pos.pieces() ^ pos.pieces(Us, QUEEN));
|
||||
else if (Piece == ROOK)
|
||||
b = attacks_bb<ROOK>(s, pos.pieces() ^ pos.pieces(ROOK, QUEEN, Us));
|
||||
b = attacks_bb<ROOK>(s, pos.pieces() ^ pos.pieces(Us, ROOK, QUEEN));
|
||||
else
|
||||
assert(false);
|
||||
|
||||
|
@ -592,7 +592,7 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
|
||||
// Bishop and knight outposts squares
|
||||
if ( (Piece == BISHOP || Piece == KNIGHT)
|
||||
&& !(pos.pieces(PAWN, Them) & attack_span_mask(Us, s)))
|
||||
&& !(pos.pieces(Them, PAWN) & attack_span_mask(Us, s)))
|
||||
score += evaluate_outposts<Piece, Us>(pos, ei, s);
|
||||
|
||||
// Queen or rook on 7th rank
|
||||
|
@ -902,8 +902,8 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
// If there is an enemy rook or queen attacking the pawn from behind,
|
||||
// add all X-ray attacks by the rook or queen. Otherwise consider only
|
||||
// the squares in the pawn's path attacked or occupied by the enemy.
|
||||
if ( (forward_bb(Them, s) & pos.pieces(ROOK, QUEEN, Them))
|
||||
&& (forward_bb(Them, s) & pos.pieces(ROOK, QUEEN, Them) & pos.attacks_from<ROOK>(s)))
|
||||
if ( (forward_bb(Them, s) & pos.pieces(Them, ROOK, QUEEN))
|
||||
&& (forward_bb(Them, s) & pos.pieces(Them, ROOK, QUEEN) & pos.attacks_from<ROOK>(s)))
|
||||
unsafeSquares = squaresToQueen;
|
||||
else
|
||||
unsafeSquares = squaresToQueen & (ei.attackedBy[Them][0] | pos.pieces(Them));
|
||||
|
@ -923,7 +923,7 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
|
||||
// Increase the bonus if the passed pawn is supported by a friendly pawn
|
||||
// on the same rank and a bit smaller if it's on the previous rank.
|
||||
supportingPawns = pos.pieces(PAWN, Us) & adjacent_files_bb(file_of(s));
|
||||
supportingPawns = pos.pieces(Us, PAWN) & adjacent_files_bb(file_of(s));
|
||||
if (supportingPawns & rank_bb(s))
|
||||
ebonus += Value(r * 20);
|
||||
|
||||
|
@ -940,7 +940,7 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
{
|
||||
if (pos.non_pawn_material(Them) <= KnightValueMidgame)
|
||||
ebonus += ebonus / 4;
|
||||
else if (pos.pieces(ROOK, QUEEN, Them))
|
||||
else if (pos.pieces(Them, ROOK, QUEEN))
|
||||
ebonus -= ebonus / 4;
|
||||
}
|
||||
score += make_score(mbonus, ebonus);
|
||||
|
@ -1013,7 +1013,7 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
loserSide = ~winnerSide;
|
||||
|
||||
// Step 3. Can the losing side possibly create a new passed pawn and thus prevent the loss?
|
||||
b = candidates = pos.pieces(PAWN, loserSide);
|
||||
b = candidates = pos.pieces(loserSide, PAWN);
|
||||
|
||||
while (b)
|
||||
{
|
||||
|
@ -1026,7 +1026,7 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
|
||||
// Check if (without even considering any obstacles) we're too far away or doubled
|
||||
if ( pliesToQueen[winnerSide] + 3 <= pliesToGo
|
||||
|| (forward_bb(loserSide, s) & pos.pieces(PAWN, loserSide)))
|
||||
|| (forward_bb(loserSide, s) & pos.pieces(loserSide, PAWN)))
|
||||
candidates ^= s;
|
||||
}
|
||||
|
||||
|
@ -1050,8 +1050,8 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
|
||||
// Generate list of blocking pawns and supporters
|
||||
supporters = adjacent_files_bb(file_of(s)) & candidates;
|
||||
opposed = forward_bb(loserSide, s) & pos.pieces(PAWN, winnerSide);
|
||||
blockers = passed_pawn_mask(loserSide, s) & pos.pieces(PAWN, winnerSide);
|
||||
opposed = forward_bb(loserSide, s) & pos.pieces(winnerSide, PAWN);
|
||||
blockers = passed_pawn_mask(loserSide, s) & pos.pieces(winnerSide, PAWN);
|
||||
|
||||
assert(blockers);
|
||||
|
||||
|
@ -1128,12 +1128,12 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
|||
// SpaceMask[]. A square is unsafe if it is attacked by an enemy
|
||||
// pawn, or if it is undefended and attacked by an enemy piece.
|
||||
Bitboard safe = SpaceMask[Us]
|
||||
& ~pos.pieces(PAWN, Us)
|
||||
& ~pos.pieces(Us, PAWN)
|
||||
& ~ei.attackedBy[Them][PAWN]
|
||||
& (ei.attackedBy[Us][0] | ~ei.attackedBy[Them][0]);
|
||||
|
||||
// Find all squares which are at most three squares behind some friendly pawn
|
||||
Bitboard behind = pos.pieces(PAWN, Us);
|
||||
Bitboard behind = pos.pieces(Us, PAWN);
|
||||
behind |= (Us == WHITE ? behind >> 8 : behind << 8);
|
||||
behind |= (Us == WHITE ? behind >> 16 : behind << 16);
|
||||
|
||||
|
|
|
@ -127,8 +127,8 @@ MaterialEntry* MaterialTable::probe(const Position& pos) {
|
|||
{
|
||||
// Minor piece endgame with at least one minor piece per side and
|
||||
// no pawns. Note that the case KmmK is already handled by KXK.
|
||||
assert((pos.pieces(KNIGHT, WHITE) | pos.pieces(BISHOP, WHITE)));
|
||||
assert((pos.pieces(KNIGHT, BLACK) | pos.pieces(BISHOP, BLACK)));
|
||||
assert((pos.pieces(WHITE, KNIGHT) | pos.pieces(WHITE, BISHOP)));
|
||||
assert((pos.pieces(BLACK, KNIGHT) | pos.pieces(BLACK, BISHOP)));
|
||||
|
||||
if ( pos.piece_count(WHITE, BISHOP) + pos.piece_count(WHITE, KNIGHT) <= 2
|
||||
&& pos.piece_count(BLACK, BISHOP) + pos.piece_count(BLACK, KNIGHT) <= 2)
|
||||
|
|
|
@ -97,7 +97,7 @@ const string move_to_san(Position& pos, Move m) {
|
|||
|
||||
// Disambiguation if we have more then one piece with destination 'to'
|
||||
// note that for pawns is not needed because starting file is explicit.
|
||||
attackers = pos.attackers_to(to) & pos.pieces(pt, pos.side_to_move());
|
||||
attackers = pos.attackers_to(to) & pos.pieces(pos.side_to_move(), pt);
|
||||
attackers ^= from;
|
||||
ambiguousMove = ambiguousFile = ambiguousRank = false;
|
||||
|
||||
|
|
|
@ -126,8 +126,8 @@ namespace {
|
|||
|
||||
Bitboard b1, b2, dc1, dc2, emptySquares;
|
||||
|
||||
Bitboard pawnsOn7 = pos.pieces(PAWN, Us) & TRank7BB;
|
||||
Bitboard pawnsNotOn7 = pos.pieces(PAWN, Us) & ~TRank7BB;
|
||||
Bitboard pawnsOn7 = pos.pieces(Us, PAWN) & TRank7BB;
|
||||
Bitboard pawnsNotOn7 = pos.pieces(Us, PAWN) & ~TRank7BB;
|
||||
|
||||
Bitboard enemies = (Type == MV_EVASION ? pos.pieces(Them) & target:
|
||||
Type == MV_CAPTURE ? target : pos.pieces(Them));
|
||||
|
|
|
@ -104,8 +104,8 @@ PawnEntry* PawnTable::probe(const Position& pos) {
|
|||
e->kingSquares[WHITE] = e->kingSquares[BLACK] = SQ_NONE;
|
||||
e->halfOpenFiles[WHITE] = e->halfOpenFiles[BLACK] = 0xFF;
|
||||
|
||||
Bitboard wPawns = pos.pieces(PAWN, WHITE);
|
||||
Bitboard bPawns = pos.pieces(PAWN, BLACK);
|
||||
Bitboard wPawns = pos.pieces(WHITE, PAWN);
|
||||
Bitboard bPawns = pos.pieces(BLACK, PAWN);
|
||||
e->pawnAttacks[WHITE] = ((wPawns & ~FileHBB) << 9) | ((wPawns & ~FileABB) << 7);
|
||||
e->pawnAttacks[BLACK] = ((bPawns & ~FileHBB) >> 7) | ((bPawns & ~FileABB) >> 9);
|
||||
|
||||
|
|
|
@ -201,7 +201,7 @@ void Position::from_fen(const string& fenStr, bool isChess960, Thread* th) {
|
|||
{
|
||||
st->epSquare = make_square(File(col - 'a'), Rank(row - '1'));
|
||||
|
||||
if (!(attackers_to(st->epSquare) & pieces(PAWN, sideToMove)))
|
||||
if (!(attackers_to(st->epSquare) & pieces(sideToMove, PAWN)))
|
||||
st->epSquare = SQ_NONE;
|
||||
}
|
||||
|
||||
|
@ -382,8 +382,8 @@ template Bitboard Position::hidden_checkers<false>() const;
|
|||
|
||||
Bitboard Position::attackers_to(Square s, Bitboard occ) const {
|
||||
|
||||
return (attacks_from<PAWN>(s, BLACK) & pieces(PAWN, WHITE))
|
||||
| (attacks_from<PAWN>(s, WHITE) & pieces(PAWN, BLACK))
|
||||
return (attacks_from<PAWN>(s, BLACK) & pieces(WHITE, PAWN))
|
||||
| (attacks_from<PAWN>(s, WHITE) & pieces(BLACK, PAWN))
|
||||
| (attacks_from<KNIGHT>(s) & pieces(KNIGHT))
|
||||
| (attacks_bb<ROOK>(s, occ) & pieces(ROOK, QUEEN))
|
||||
| (attacks_bb<BISHOP>(s, occ) & pieces(BISHOP, QUEEN))
|
||||
|
@ -431,8 +431,8 @@ bool Position::move_attacks_square(Move m, Square s) const {
|
|||
return true;
|
||||
|
||||
// Scan for possible X-ray attackers behind the moved piece
|
||||
xray = (attacks_bb<ROOK>(s, occ) & pieces(ROOK, QUEEN, color_of(piece)))
|
||||
|(attacks_bb<BISHOP>(s, occ) & pieces(BISHOP, QUEEN, color_of(piece)));
|
||||
xray = (attacks_bb< ROOK>(s, occ) & pieces(color_of(piece), QUEEN, ROOK))
|
||||
| (attacks_bb<BISHOP>(s, occ) & pieces(color_of(piece), QUEEN, BISHOP));
|
||||
|
||||
// Verify attackers are triggered by our move and not already existing
|
||||
return xray && (xray ^ (xray & attacks_from<QUEEN>(s)));
|
||||
|
@ -468,8 +468,8 @@ bool Position::pl_move_is_legal(Move m, Bitboard pinned) const {
|
|||
assert(piece_on(capsq) == make_piece(them, PAWN));
|
||||
assert(piece_on(to) == NO_PIECE);
|
||||
|
||||
return !(attacks_bb<ROOK>(ksq, b) & pieces(ROOK, QUEEN, them))
|
||||
&& !(attacks_bb<BISHOP>(ksq, b) & pieces(BISHOP, QUEEN, them));
|
||||
return !(attacks_bb< ROOK>(ksq, b) & pieces(them, QUEEN, ROOK))
|
||||
&& !(attacks_bb<BISHOP>(ksq, b) & pieces(them, QUEEN, BISHOP));
|
||||
}
|
||||
|
||||
// If the moving piece is a king, check whether the destination
|
||||
|
@ -666,8 +666,8 @@ bool Position::move_gives_check(Move m, const CheckInfo& ci) const {
|
|||
Square capsq = make_square(file_of(to), rank_of(from));
|
||||
Bitboard b = (pieces() ^ from ^ capsq) | to;
|
||||
|
||||
return (attacks_bb< ROOK>(ksq, b) & pieces( ROOK, QUEEN, us))
|
||||
| (attacks_bb<BISHOP>(ksq, b) & pieces(BISHOP, QUEEN, us));
|
||||
return (attacks_bb< ROOK>(ksq, b) & pieces(us, QUEEN, ROOK))
|
||||
| (attacks_bb<BISHOP>(ksq, b) & pieces(us, QUEEN, BISHOP));
|
||||
}
|
||||
|
||||
// Castling with check ?
|
||||
|
@ -841,7 +841,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
|
|||
{
|
||||
// Set en-passant square, only if moved pawn can be captured
|
||||
if ( (int(to) ^ int(from)) == 16
|
||||
&& (attacks_from<PAWN>(from + pawn_push(us), us) & pieces(PAWN, them)))
|
||||
&& (attacks_from<PAWN>(from + pawn_push(us), us) & pieces(them, PAWN)))
|
||||
{
|
||||
st->epSquare = Square((from + to) / 2);
|
||||
k ^= zobEp[file_of(st->epSquare)];
|
||||
|
@ -919,10 +919,10 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
|
|||
if (ci.dcCandidates && (ci.dcCandidates & from))
|
||||
{
|
||||
if (pt != ROOK)
|
||||
st->checkersBB |= attacks_from<ROOK>(king_square(them)) & pieces(ROOK, QUEEN, us);
|
||||
st->checkersBB |= attacks_from<ROOK>(king_square(them)) & pieces(us, QUEEN, ROOK);
|
||||
|
||||
if (pt != BISHOP)
|
||||
st->checkersBB |= attacks_from<BISHOP>(king_square(them)) & pieces(BISHOP, QUEEN, us);
|
||||
st->checkersBB |= attacks_from<BISHOP>(king_square(them)) & pieces(us, QUEEN, BISHOP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1651,7 +1651,7 @@ bool Position::pos_is_ok(int* failedStep) const {
|
|||
if ((*step)++, debugPieceCounts)
|
||||
for (Color c = WHITE; c <= BLACK; c++)
|
||||
for (PieceType pt = PAWN; pt <= KING; pt++)
|
||||
if (pieceCount[c][pt] != popcount<Full>(pieces(pt, c)))
|
||||
if (pieceCount[c][pt] != popcount<Full>(pieces(c, pt)))
|
||||
return false;
|
||||
|
||||
if ((*step)++, debugPieceList)
|
||||
|
|
|
@ -98,11 +98,11 @@ public:
|
|||
|
||||
// Position representation
|
||||
Bitboard pieces() const;
|
||||
Bitboard pieces(Color c) const;
|
||||
Bitboard pieces(PieceType pt) const;
|
||||
Bitboard pieces(PieceType pt, Color c) const;
|
||||
Bitboard pieces(PieceType pt1, PieceType pt2) const;
|
||||
Bitboard pieces(PieceType pt1, PieceType pt2, Color c) const;
|
||||
Bitboard pieces(Color c) const;
|
||||
Bitboard pieces(Color c, PieceType pt) const;
|
||||
Bitboard pieces(Color c, PieceType pt1, PieceType pt2) const;
|
||||
Piece piece_on(Square s) const;
|
||||
Square king_square(Color c) const;
|
||||
Square ep_square() const;
|
||||
|
@ -261,24 +261,24 @@ inline Bitboard Position::pieces() const {
|
|||
return byTypeBB[ALL_PIECES];
|
||||
}
|
||||
|
||||
inline Bitboard Position::pieces(Color c) const {
|
||||
return byColorBB[c];
|
||||
}
|
||||
|
||||
inline Bitboard Position::pieces(PieceType pt) const {
|
||||
return byTypeBB[pt];
|
||||
}
|
||||
|
||||
inline Bitboard Position::pieces(PieceType pt, Color c) const {
|
||||
return byTypeBB[pt] & byColorBB[c];
|
||||
}
|
||||
|
||||
inline Bitboard Position::pieces(PieceType pt1, PieceType pt2) const {
|
||||
return byTypeBB[pt1] | byTypeBB[pt2];
|
||||
}
|
||||
|
||||
inline Bitboard Position::pieces(PieceType pt1, PieceType pt2, Color c) const {
|
||||
return (byTypeBB[pt1] | byTypeBB[pt2]) & byColorBB[c];
|
||||
inline Bitboard Position::pieces(Color c) const {
|
||||
return byColorBB[c];
|
||||
}
|
||||
|
||||
inline Bitboard Position::pieces(Color c, PieceType pt) const {
|
||||
return byColorBB[c] & byTypeBB[pt];
|
||||
}
|
||||
|
||||
inline Bitboard Position::pieces(Color c, PieceType pt1, PieceType pt2) const {
|
||||
return byColorBB[c] & (byTypeBB[pt1] | byTypeBB[pt2]);
|
||||
}
|
||||
|
||||
inline int Position::piece_count(Color c, PieceType pt) const {
|
||||
|
@ -351,7 +351,7 @@ inline Bitboard Position::pinned_pieces() const {
|
|||
}
|
||||
|
||||
inline bool Position::pawn_is_passed(Color c, Square s) const {
|
||||
return !(pieces(PAWN, ~c) & passed_pawn_mask(c, s));
|
||||
return !(pieces(~c, PAWN) & passed_pawn_mask(c, s));
|
||||
}
|
||||
|
||||
inline Key Position::key() const {
|
||||
|
@ -406,7 +406,7 @@ inline bool Position::bishop_pair(Color c) const {
|
|||
}
|
||||
|
||||
inline bool Position::pawn_on_7th(Color c) const {
|
||||
return pieces(PAWN, c) & rank_bb(relative_rank(c, RANK_7));
|
||||
return pieces(c, PAWN) & rank_bb(relative_rank(c, RANK_7));
|
||||
}
|
||||
|
||||
inline bool Position::is_chess960() const {
|
||||
|
|
Loading…
Add table
Reference in a new issue