DrawFiddle▶ RunEdit in Fiddle
// CHESS — full rules (castling, en passant, promotion), SVG pieces, two players on one board.
// Board index 0 = a8 … 63 = h1: exactly the order an 8x8 grid lays its cells out, so a square
// index IS its cell index — no mapping anywhere.

// ---- pieces ------------------------------------------------------------------------------
// One small SVG body per type in a 45x45 box; colours are injected, so 6 shapes serve both sides.
const string PawnSvg =
    "<circle cx='22.5' cy='13' r='6.2'/>" +
    "<path d='M16 34c0-7 5-8 5-13h3c0 5 5 6 5 13z'/>" +
    "<rect x='12' y='32.5' width='21' height='5.5' rx='2.6'/>";

const string RookSvg =
    "<path d='M11 12h5v4h4v-4h5v4h4v-4h5v10l-3 3v8l4 4v2h-25v-2l4-4v-8l-3-3z'/>" +
    "<rect x='9' y='34' width='27' height='5.5' rx='2.6'/>";

const string KnightSvg =
    "<path d='M11 39h24v-4c0-12-3-19-11-23l1-7-4 5c-5 1-9 5-12 9l-3 5 4 1 3-3c0 6 2 9 5 11-4 2-6 4-7 6z'/>" +
    "<circle cx='17' cy='16' r='1.4' stroke='none'/>";

const string BishopSvg =
    "<circle cx='22.5' cy='8' r='2.6'/>" +
    "<path d='M22.5 11c6 4 9 9 9 13 0 4-4 6-9 6s-9-2-9-6c0-4 3-9 9-13z'/>" +
    "<path d='M18.5 20h8M22.5 16v8' fill='none' stroke-width='1.4'/>" +
    "<rect x='13' y='29.5' width='19' height='4' rx='2'/>" +
    "<rect x='9' y='33.5' width='27' height='5.5' rx='2.6'/>";

const string QueenSvg =
    "<path d='M9 31 6 14l4 7 4-12 4 11 4.5-14 4.5 14 4-11 4 12 4-7-3 17z'/>" +
    "<circle cx='6' cy='13' r='2.2'/><circle cx='14' cy='8' r='2.2'/><circle cx='22.5' cy='5' r='2.4'/>" +
    "<circle cx='31' cy='8' r='2.2'/><circle cx='39' cy='13' r='2.2'/>" +
    "<rect x='9' y='30' width='27' height='4' rx='2'/>" +
    "<rect x='7' y='34' width='31' height='5.5' rx='2.6'/>";

const string KingSvg =
    "<path d='M20.8 3h3.4v4h4v3.4h-4v4h-3.4v-4h-4V7h4z'/>" +
    "<path d='M22.5 14c7 0 12 5 12 10l-2 6H12.5l-2-6c0-5 5-10 12-10z'/>" +
    "<rect x='10' y='29.5' width='25' height='4' rx='2'/>" +
    "<rect x='7' y='33.5' width='31' height='5.5' rx='2.6'/>";

var svgCache = new Dictionary<int, string>();

string SvgOf(int code)
{
    if (svgCache.TryGetValue(code, out var cached))
        return cached;

    var body = Math.Abs(code) switch
    {
        1 => PawnSvg, 2 => KnightSvg, 3 => BishopSvg,
        4 => RookSvg, 5 => QueenSvg, _ => KingSvg,
    };
    var fill = code > 0 ? "#FAF7F0" : "#25231E";
    var line = code > 0 ? "#23201C" : "#0B0A08";
    return svgCache[code] =
        "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 45 45'>" +
        $"<g fill='{fill}' stroke='{line}' stroke-width='1.6' stroke-linejoin='round'>{body}</g></svg>";
}

// ---- state -------------------------------------------------------------------------------
const double cell = 44;

var lightSquare = Color.Parse("#EDD7B5");
var darkSquare = Color.Parse("#B58863");
var lightMoved = Color.Parse("#DBD483");
var darkMoved = Color.Parse("#B0A254");
var selectedColor = Color.Parse("#F1E05A");
var checkColor = Color.Parse("#E2645C");

var game = ChessGame.New();
var history = new Stack<ChessGame>();
var cells = new SkiaShape[64];
var pieces = new SkiaSvg[64];
var marks = new SkiaShape[64];
var shown = new int[64];              // SVG currently on each square, so only changed squares re-parse
var targets = new List<ChessMove>();  // legal moves out of the selected square
var selected = -1;
var lastFrom = -1;
var lastTo = -1;
var aiDepth = 3;                      // 0 = two humans, otherwise how many plies black looks ahead
var thinking = false;
SkiaLabel status = null;
SkiaButton aiButton = null;

void Reset()
{
    selected = -1;
    lastFrom = lastTo = -1;
    targets.Clear();
    for (int i = 0; i < 64; i++)
        shown[i] = 99;                // impossible code: forces every square to reload its SVG
}

void Refresh()
{
    var legal = game.Moves();
    var check = game.KingAttacked(game.White);
    var kingSquare = Array.IndexOf(game.B, game.White ? 6 : -6);

    for (int i = 0; i < 64; i++)
    {
        var isDark = (i / 8 + i % 8) % 2 == 1;
        var color = isDark ? darkSquare : lightSquare;
        if (i == lastFrom || i == lastTo) color = isDark ? darkMoved : lightMoved;
        if (i == selected) color = selectedColor;
        if (check && i == kingSquare) color = checkColor;
        cells[i].BackgroundColor = color;

        var code = game.B[i];
        if (shown[i] != code)
        {
            shown[i] = code;
            pieces[i].IsVisible = code != 0;
            if (code != 0)
                pieces[i].SvgString = SvgOf(code);
        }

        var isTarget = targets.Any(m => m.To == i);
        marks[i].IsVisible = isTarget;
        if (isTarget)
        {
            var capture = game.B[i] != 0;   // a ring around the victim, a dot on an empty square
            marks[i].WidthRequest = marks[i].HeightRequest = capture ? cell - 5 : 14;
            marks[i].BackgroundColor = capture ? Colors.Transparent : Color.Parse("#40151210");
            marks[i].StrokeWidth = capture ? 3 : 0;
        }
    }

    var side = game.White ? "White" : "Black";
    status.Text = legal.Count == 0
        ? (check ? $"Checkmate — {(game.White ? "Black" : "White")} wins" : "Stalemate — draw")
        : (check ? $"{side} to move — CHECK" : $"{side} to move");
}

// Black's turn, driven by the engine. async so the canvas paints the human move BEFORE the
// search blocks the only thread this app has.
async void PlayAi()
{
    thinking = true;
    status.Text = "Black is thinking…";
    try
    {
        await System.Threading.Tasks.Task.Delay(40);
        var clock = System.Diagnostics.Stopwatch.StartNew();
        var move = ChessAi.Best(game, aiDepth);
        Console.WriteLine($"ai: depth {aiDepth}, {clock.ElapsedMilliseconds} ms");
        if (move != null)
        {
            history.Push(game.Clone());
            game.Apply(move.Value);
            lastFrom = move.Value.From;
            lastTo = move.Value.To;
        }
    }
    finally
    {
        thinking = false;
        Refresh();
    }
}

void Tap(int square)
{
    if (thinking) return;
    if (aiDepth > 0 && !game.White) return;   // black belongs to the engine

    if (selected >= 0 && targets.Any(m => m.To == square))
    {
        history.Push(game.Clone());
        game.Apply(targets.First(m => m.To == square));
        lastFrom = selected;
        lastTo = square;
        selected = -1;
        targets.Clear();
    }
    else if (game.Mine(square))
    {
        selected = square;
        targets = game.Moves().Where(m => m.From == square).ToList();
    }
    else
    {
        selected = -1;
        targets.Clear();
    }
    Refresh();

    if (aiDepth > 0 && !game.White && game.Moves().Count > 0)
        PlayAi();
}

// ---- board -------------------------------------------------------------------------------
return new SkiaLayer
{
    Padding = new Thickness(16),
    HorizontalOptions = LayoutOptions.Center,
    VerticalOptions = LayoutOptions.Center,
    Children = new List<SkiaControl>
    {
        new SkiaStack
        {
            Spacing = 10,
            UseCache = SkiaCacheType.ImageCompositeGPU,
            HorizontalOptions = LayoutOptions.Center,
            Children = new List<SkiaControl>
            {
                new SkiaLabel("CHESS")
                {
                    FontSize = 17,
                    FontWeight = 800,
                    TextColor = Color.Parse("#E8C87A"),
                }.CenterX(),

                new SkiaLabel("White to move")
                {
                    FontSize = 13,
                    TextColor = Color.Parse("#9FB0CC"),
                }.CenterX().Assign(out status),

                // frame around the board
                new SkiaShape
                {
                    CornerRadius = 6,
                    BackgroundColor = Color.Parse("#3A2A1C"),
                    Padding = new Thickness(6),
                    HorizontalOptions = LayoutOptions.Center,
                    Children = new List<SkiaControl>
                    {
                        // 64 squares placed absolutely: the square index already carries row and
                        // column, so Left/Top is cheaper and shorter than grid definitions.
                        new SkiaLayer
                        {
                            WidthRequest = cell * 8,
                            HeightRequest = cell * 8,
                            HorizontalOptions = LayoutOptions.Center,
                            VerticalOptions = LayoutOptions.Start,
                            Children = Enumerable.Range(0, 64).Select(i => (SkiaControl)new SkiaShape
                            {
                                WidthRequest = cell,
                                HeightRequest = cell,
                                Left = i % 8 * cell,
                                Top = i / 8 * cell,
                                HorizontalOptions = LayoutOptions.Start,
                                VerticalOptions = LayoutOptions.Start,
                                BackgroundColor = (i / 8 + i % 8) % 2 == 1 ? darkSquare : lightSquare,
                                Children = new List<SkiaControl>
                                {
                                    // coordinates: rank down the a-file, letter along rank 1
                                    new SkiaLabel(i % 8 == 0 ? $"{8 - i / 8}" : i / 8 == 7 ? $"{(char)('a' + i % 8)}" : "")
                                    {
                                        FontSize = 9,
                                        FontWeight = 700,
                                        TextColor = (i / 8 + i % 8) % 2 == 1 ? lightSquare : darkSquare,
                                        Margin = new Thickness(3, 2, 4, 2),
                                        HorizontalOptions = i % 8 == 0 ? LayoutOptions.Start : LayoutOptions.End,
                                        VerticalOptions = i % 8 == 0 ? LayoutOptions.Start : LayoutOptions.End,
                                    },

                                    new SkiaSvg
                                    {
                                        WidthRequest = cell - 6,
                                        HeightRequest = cell - 6,
                                        IsVisible = false,
                                    }.Center().Assign(out pieces[i]),

                                    new SkiaShape
                                    {
                                        Type = ShapeType.Circle,
                                        WidthRequest = 14,
                                        HeightRequest = 14,
                                        StrokeColor = Color.Parse("#55151210"),
                                        IsVisible = false,
                                    }.Center().Assign(out marks[i]),
                                }
                            }
                            .Assign(out cells[i])
                            .OnTapped(me => Tap(i))).ToList()
                        }
                    }
                },

                new SkiaRow
                {
                    Spacing = 8,
                    HorizontalOptions = LayoutOptions.Center,
                    UseCache = SkiaCacheType.Operations,
                    Children = new List<SkiaControl>
                    {
                        new SkiaButton("New game")
                        {
                            WidthRequest = 110,
                            HeightRequest = 34,
                            CornerRadius = 8,
                            FontSize = 13,
                            BackgroundColor = Color.Parse("#2C3342"),
                            TextColor = Color.Parse("#DCE4F2"),
                        }.OnTapped(me => { game = ChessGame.New(); history.Clear(); Reset(); Refresh(); }),

                        new SkiaButton("Undo")
                        {
                            WidthRequest = 90,
                            HeightRequest = 34,
                            CornerRadius = 8,
                            FontSize = 13,
                            BackgroundColor = Color.Parse("#2C3342"),
                            TextColor = Color.Parse("#DCE4F2"),
                        }.OnTapped(me =>
                        {
                            if (thinking || history.Count == 0) return;
                            game = history.Pop();
                            // against the engine one "move" is two plies, so rewind to a white turn
                            while (aiDepth > 0 && !game.White && history.Count > 0)
                                game = history.Pop();
                            Reset();
                            Refresh();
                        }),

                        new SkiaButton("Black: engine")
                        {
                            WidthRequest = 124,
                            HeightRequest = 34,
                            CornerRadius = 8,
                            FontSize = 13,
                            BackgroundColor = Color.Parse("#2C3342"),
                            TextColor = Color.Parse("#DCE4F2"),
                        }
                        .Assign(out aiButton)
                        .OnTapped(me =>
                        {
                            if (thinking) return;
                            // 3 plies answers in ~0.1s, 4 costs ~0.5s and freezes the canvas while it thinks
                            aiDepth = aiDepth == 3 ? 4 : aiDepth == 4 ? 2 : aiDepth == 2 ? 0 : 3;
                            me.Text = aiDepth == 0 ? "Black: human"
                                : aiDepth == 2 ? "Black: quick"
                                : aiDepth == 3 ? "Black: engine" : "Black: strong";
                            if (aiDepth > 0 && !game.White && game.Moves().Count > 0)
                                PlayAi();
                        }),
                    }
                },
            }
        }
    }
}
.Initialize(me => { Reset(); Refresh(); });

// ---- rules -------------------------------------------------------------------------------
// Piece codes: 1 pawn, 2 knight, 3 bishop, 4 rook, 5 queen, 6 king. Positive = white.

record struct ChessMove(int From, int To, int Promo);

class ChessGame
{
    public int[] B = new int[64];
    public bool White = true;
    public bool WK = true, WQ = true, BK = true, BQ = true;   // castling rights
    public int Ep = -1;                                       // en passant target square

    const string Layout = "rnbqkbnrpppppppp................................PPPPPPPPRNBQKBNR";
    const string Codes = ".pnbrqk";

    static readonly (int dr, int dc)[] Jumps =
        { (1, 2), (2, 1), (2, -1), (1, -2), (-1, -2), (-2, -1), (-2, 1), (-1, 2) };
    static readonly (int dr, int dc)[] Diagonal = { (1, 1), (1, -1), (-1, 1), (-1, -1) };
    static readonly (int dr, int dc)[] Straight = { (1, 0), (-1, 0), (0, 1), (0, -1) };
    static readonly (int dr, int dc)[] Around =
        { (1, 1), (1, -1), (-1, 1), (-1, -1), (1, 0), (-1, 0), (0, 1), (0, -1) };

    public static ChessGame New()
    {
        var g = new ChessGame();
        for (int i = 0; i < 64; i++)
        {
            var c = Layout[i];
            if (c == '.') continue;
            var type = Codes.IndexOf(char.ToLowerInvariant(c));
            g.B[i] = char.IsUpper(c) ? type : -type;
        }
        return g;
    }

    public ChessGame Clone() => new ChessGame
    {
        B = (int[])B.Clone(), White = White, WK = WK, WQ = WQ, BK = BK, BQ = BQ, Ep = Ep,
    };

    static int Row(int i) => i / 8;
    static int Col(int i) => i % 8;
    static bool In(int r, int c) => r >= 0 && r < 8 && c >= 0 && c < 8;
    static int Sq(int r, int c) => r * 8 + c;

    public bool Mine(int i) => B[i] != 0 && B[i] > 0 == White;

    /// Every pseudo-legal move, filtered by "does it leave my own king attacked".
    public List<ChessMove> Moves()
    {
        var legal = new List<ChessMove>();
        foreach (var move in Pseudo())
        {
            var after = Clone();
            after.Apply(move);
            if (!after.KingAttacked(White))
                legal.Add(move);
        }
        return legal;
    }

    public IEnumerable<ChessMove> Pseudo()
    {
        var sign = White ? 1 : -1;
        for (int i = 0; i < 64; i++)
        {
            if (!Mine(i)) continue;
            int r = Row(i), c = Col(i), piece = Math.Abs(B[i]);

            if (piece == 1)
            {
                var dir = White ? -1 : 1;
                var promo = White ? 0 : 7;
                var start = White ? 6 : 1;

                if (In(r + dir, c) && B[Sq(r + dir, c)] == 0)
                {
                    yield return new ChessMove(i, Sq(r + dir, c), r + dir == promo ? 5 : 0);
                    if (r == start && B[Sq(r + 2 * dir, c)] == 0)
                        yield return new ChessMove(i, Sq(r + 2 * dir, c), 0);
                }
                foreach (var dc in new[] { -1, 1 })
                {
                    if (!In(r + dir, c + dc)) continue;
                    var to = Sq(r + dir, c + dc);
                    if (B[to] * sign < 0 || to == Ep)
                        yield return new ChessMove(i, to, r + dir == promo ? 5 : 0);
                }
            }
            else if (piece == 2)
            {
                foreach (var (dr, dc) in Jumps)
                    if (In(r + dr, c + dc) && B[Sq(r + dr, c + dc)] * sign <= 0)
                        yield return new ChessMove(i, Sq(r + dr, c + dc), 0);
            }
            else if (piece == 6)
            {
                foreach (var (dr, dc) in Around)
                    if (In(r + dr, c + dc) && B[Sq(r + dr, c + dc)] * sign <= 0)
                        yield return new ChessMove(i, Sq(r + dr, c + dc), 0);

                // castling: rights, empty path, and the king neither in check nor crossing one
                var home = White ? 7 : 0;
                if (r == home && c == 4 && !KingAttacked(White))
                {
                    if ((White ? WK : BK) && B[Sq(home, 5)] == 0 && B[Sq(home, 6)] == 0
                        && !Attacked(Sq(home, 5), !White))
                        yield return new ChessMove(i, Sq(home, 6), 0);
                    if ((White ? WQ : BQ) && B[Sq(home, 1)] == 0 && B[Sq(home, 2)] == 0 && B[Sq(home, 3)] == 0
                        && !Attacked(Sq(home, 3), !White))
                        yield return new ChessMove(i, Sq(home, 2), 0);
                }
            }
            else
            {
                var rays = piece == 3 ? Diagonal : piece == 4 ? Straight : Around;
                foreach (var (dr, dc) in rays)
                {
                    for (int step = 1; step < 8; step++)
                    {
                        int rr = r + dr * step, cc = c + dc * step;
                        if (!In(rr, cc)) break;
                        var to = Sq(rr, cc);
                        if (B[to] * sign > 0) break;          // own piece blocks
                        yield return new ChessMove(i, to, 0);
                        if (B[to] != 0) break;                // a capture ends the ray
                    }
                }
            }
        }
    }

    public void Apply(ChessMove m)
    {
        int piece = B[m.From], type = Math.Abs(piece), row = Row(m.From), col = Col(m.To);
        var nextEp = -1;

        if (type == 1 && m.To == Ep && B[m.To] == 0)
            B[Sq(row, col)] = 0;                              // en passant: the victim is beside, not under
        if (type == 1 && Math.Abs(Row(m.To) - row) == 2)
            nextEp = Sq((row + Row(m.To)) / 2, col);
        if (type == 6 && Math.Abs(col - Col(m.From)) == 2)    // castling drags the rook across
        {
            if (col == 6) { B[Sq(row, 5)] = B[Sq(row, 7)]; B[Sq(row, 7)] = 0; }
            else { B[Sq(row, 3)] = B[Sq(row, 0)]; B[Sq(row, 0)] = 0; }
        }

        B[m.To] = m.Promo != 0 ? (piece > 0 ? m.Promo : -m.Promo) : piece;
        B[m.From] = 0;

        // rights die when the king moves, or when a rook leaves or is taken on its home square
        if (type == 6) { if (piece > 0) WK = WQ = false; else BK = BQ = false; }
        if (m.From == 56 || m.To == 56) WQ = false;
        if (m.From == 63 || m.To == 63) WK = false;
        if (m.From == 0 || m.To == 0) BQ = false;
        if (m.From == 7 || m.To == 7) BK = false;

        Ep = nextEp;
        White = !White;
    }

    public bool KingAttacked(bool white)
    {
        var king = Array.IndexOf(B, white ? 6 : -6);
        return king >= 0 && Attacked(king, !white);
    }

    /// Instead of generating every enemy move, look outward from the square for an attacker of each kind.
    public bool Attacked(int square, bool byWhite)
    {
        int sign = byWhite ? 1 : -1, r = Row(square), c = Col(square);

        var pawnRow = r + (byWhite ? 1 : -1);      // a white pawn attacks upward, so it stands below
        foreach (var dc in new[] { -1, 1 })
            if (In(pawnRow, c + dc) && B[Sq(pawnRow, c + dc)] == sign)
                return true;

        foreach (var (dr, dc) in Jumps)
            if (In(r + dr, c + dc) && B[Sq(r + dr, c + dc)] == sign * 2)
                return true;

        foreach (var (dr, dc) in Around)
            if (In(r + dr, c + dc) && B[Sq(r + dr, c + dc)] == sign * 6)
                return true;

        foreach (var (dr, dc) in Diagonal)
            if (Ray(r, c, dr, dc, sign * 3, sign * 5))
                return true;

        foreach (var (dr, dc) in Straight)
            if (Ray(r, c, dr, dc, sign * 4, sign * 5))
                return true;

        return false;
    }

    bool Ray(int r, int c, int dr, int dc, int a, int b)
    {
        for (int step = 1; step < 8; step++)
        {
            int rr = r + dr * step, cc = c + dc * step;
            if (!In(rr, cc)) return false;
            var piece = B[Sq(rr, cc)];
            if (piece != 0) return piece == a || piece == b;
        }
        return false;
    }
}

// ---- engine ------------------------------------------------------------------------------
// Plain 1980s recipe: score the position by material plus a nudge, look a few plies ahead with
// alpha-beta, and keep searching captures at the leaves so it stops hanging pieces.
static class ChessAi
{
    static readonly int[] Value = { 0, 100, 320, 330, 500, 900, 20000 };

    public static ChessMove? Best(ChessGame game, int depth)
    {
        var best = int.MinValue;
        ChessMove? pick = null;

        foreach (var move in Ordered(game))
        {
            var after = game.Clone();
            after.Apply(move);
            if (after.KingAttacked(!after.White)) continue;   // pseudo-legal: it left its own king en prise

            var score = -Search(after, depth - 1, int.MinValue + 1, int.MaxValue - 1);
            if (score > best)
            {
                best = score;
                pick = move;
            }
        }
        return pick;
    }

    static int Search(ChessGame game, int depth, int alpha, int beta)
    {
        if (depth == 0)
            return Quiesce(game, alpha, beta, 2);

        var moved = false;
        foreach (var move in Ordered(game))
        {
            var after = game.Clone();
            after.Apply(move);
            if (after.KingAttacked(!after.White)) continue;

            moved = true;
            var score = -Search(after, depth - 1, -beta, -alpha);
            if (score >= beta) return beta;
            if (score > alpha) alpha = score;
        }

        if (!moved)   // deeper mates score lower, so it takes the fastest one it sees
            return game.KingAttacked(game.White) ? -30000 - depth : 0;

        return alpha;
    }

    /// Leaf search over captures only: without it a 3-ply search happily grabs a pawn and loses a queen.
    static int Quiesce(ChessGame game, int alpha, int beta, int depth)
    {
        var stand = Eval(game);
        if (stand >= beta) return beta;
        if (stand > alpha) alpha = stand;
        if (depth == 0) return alpha;

        foreach (var move in Ordered(game))
        {
            if (game.B[move.To] == 0) continue;

            var after = game.Clone();
            after.Apply(move);
            if (after.KingAttacked(!after.White)) continue;

            var score = -Quiesce(after, -beta, -alpha, depth - 1);
            if (score >= beta) return beta;
            if (score > alpha) alpha = score;
        }
        return alpha;
    }

    /// Fat victim first, cheap attacker first — the single cheapest thing that makes alpha-beta pay off.
    static IEnumerable<ChessMove> Ordered(ChessGame game) =>
        game.Pseudo().OrderByDescending(m => game.B[m.To] == 0
            ? 0
            : Value[Math.Abs(game.B[m.To])] - Value[Math.Abs(game.B[m.From])] / 10);

    /// Material, plus knights/bishops liking the centre and pawns liking the centre and the far rank.
    /// Always from the side to move's point of view, which is what negamax expects.
    static int Eval(ChessGame game)
    {
        var score = 0;
        for (int i = 0; i < 64; i++)
        {
            var piece = game.B[i];
            if (piece == 0) continue;

            var type = Math.Abs(piece);
            var value = Value[type];
            int row = i / 8, col = i % 8;
            var centre = 3 - Math.Max(Math.Abs(row * 2 - 7), Math.Abs(col * 2 - 7)) / 2;

            if (type == 2 || type == 3) value += centre * 6;
            if (type == 1) value += centre * 3 + (piece > 0 ? 6 - row : row - 1) * 4;

            score += piece > 0 ? value : -value;
        }
        return game.White ? score : -score;
    }
}