From e79483e11bcb6473ba17689cf0a28c0aafb78d16 Mon Sep 17 00:00:00 2001 From: Tilman Crosetti Date: Tue, 13 May 2025 14:50:21 +0200 Subject: [PATCH 01/12] King rules --- OOP_2B1_Project/src/backend/King.java | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 OOP_2B1_Project/src/backend/King.java diff --git a/OOP_2B1_Project/src/backend/King.java b/OOP_2B1_Project/src/backend/King.java new file mode 100644 index 0000000..487c574 --- /dev/null +++ b/OOP_2B1_Project/src/backend/King.java @@ -0,0 +1,5 @@ +package backend; + +public class King { + +} From bad9ff9dc30f16ffb540c1a25a6e95139c1dae5d Mon Sep 17 00:00:00 2001 From: Tilman Crosetti Date: Tue, 13 May 2025 14:50:58 +0200 Subject: [PATCH 02/12] Bishop rules --- OOP_2B1_Project/src/backend/Bishop.java | 47 +++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 OOP_2B1_Project/src/backend/Bishop.java diff --git a/OOP_2B1_Project/src/backend/Bishop.java b/OOP_2B1_Project/src/backend/Bishop.java new file mode 100644 index 0000000..1218be0 --- /dev/null +++ b/OOP_2B1_Project/src/backend/Bishop.java @@ -0,0 +1,47 @@ +package backend; + +import java.util.ArrayList; +import java.util.List; + +public class Bishop extends Piece { + public Bishop(boolean isWhite, int x, int y) { + super(isWhite, PieceType.Bishop, x, y); + } + + @Override + public PieceType getType() { + return PieceType.Bishop; + } + + @Override + public List getLegalMoves(Board board, int row, int col) { + List moves = new ArrayList<>(); + int[][] directions = { + {-1, -1}, {-1, 1}, {1, -1}, {1, 1} + }; + + for (int[] dir : directions) { + int r = row + dir[0]; + int c = col + dir[1]; + while (board.isInBounds(r, c)) { + Piece target = board.getPieceAt(r, c); + if (target == null) { + moves.add(new Move(this, row, col, r, c)); + } else { + if (target.isWhite() != this.isWhite) + moves.add(new Move(this, row, col, r, c)); + break; + } + r += dir[0]; + c += dir[1]; + } + } + + return moves; + } + + @Override + public Piece clone() { + return new Bishop(this.isWhite, this.x, this.y); + } +} \ No newline at end of file From 076adb02918524d19e99b77b22728e980cc313d4 Mon Sep 17 00:00:00 2001 From: Tilman Crosetti Date: Tue, 13 May 2025 14:51:11 +0200 Subject: [PATCH 03/12] King --- OOP_2B1_Project/src/backend/King.java | 40 +++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/OOP_2B1_Project/src/backend/King.java b/OOP_2B1_Project/src/backend/King.java index 487c574..3d31626 100644 --- a/OOP_2B1_Project/src/backend/King.java +++ b/OOP_2B1_Project/src/backend/King.java @@ -1,5 +1,41 @@ package backend; -public class King { +import java.util.ArrayList; +import java.util.List; -} +public class King extends Piece { + public King(boolean isWhite, int x, int y) { + super(isWhite, PieceType.King, x, y); + } + + @Override + public PieceType getType() { + return PieceType.King; + } + + @Override + public List getLegalMoves(Board board, int row, int col) { + List moves = new ArrayList<>(); + int[] d = {-1, 0, 1}; + + for (int dr : d) { + for (int dc : d) { + if (dr == 0 && dc == 0) continue; + int r = row + dr; + int c = col + dc; + if (board.isInBounds(r, c)) { + Piece p = board.getPieceAt(r, c); + if (p == null || p.isWhite() != this.isWhite) + moves.add(new Move(this, row, col, r, c)); + } + } + } + + return moves; + } + + @Override + public Piece clone() { + return new King(this.isWhite, this.x, this.y); + } +} \ No newline at end of file From 9db0c04eeec3c191226cfba4c57218217cf1cf13 Mon Sep 17 00:00:00 2001 From: Tilman Crosetti Date: Tue, 13 May 2025 14:51:28 +0200 Subject: [PATCH 04/12] Knight rules --- OOP_2B1_Project/src/backend/Knight.java | 41 +++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 OOP_2B1_Project/src/backend/Knight.java diff --git a/OOP_2B1_Project/src/backend/Knight.java b/OOP_2B1_Project/src/backend/Knight.java new file mode 100644 index 0000000..1a43c34 --- /dev/null +++ b/OOP_2B1_Project/src/backend/Knight.java @@ -0,0 +1,41 @@ +package backend; + +import java.util.ArrayList; +import java.util.List; + +public class Knight extends Piece { + public Knight(boolean isWhite, int x, int y) { + super(isWhite, PieceType.Knight, x, y); + } + + @Override + public PieceType getType() { + return PieceType.Knight; + } + + @Override + public List getLegalMoves(Board board, int row, int col) { + List moves = new ArrayList<>(); + int[][] offsets = { + {-2, -1}, {-2, 1}, {-1, -2}, {-1, 2}, + {1, -2}, {1, 2}, {2, -1}, {2, 1} + }; + + for (int[] offset : offsets) { + int r = row + offset[0]; + int c = col + offset[1]; + if (board.isInBounds(r, c)) { + Piece p = board.getPieceAt(r, c); + if (p == null || p.isWhite() != this.isWhite) + moves.add(new Move(this, row, col, r, c)); + } + } + + return moves; + } + + @Override + public Piece clone() { + return new Knight(this.isWhite, this.x, this.y); + } +} From a3c3c9385835ca6a27bdc9b133967b3bbe762c10 Mon Sep 17 00:00:00 2001 From: Tilman Crosetti Date: Tue, 13 May 2025 14:51:39 +0200 Subject: [PATCH 05/12] Pawn rules --- OOP_2B1_Project/src/backend/Pawn.java | 51 +++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 OOP_2B1_Project/src/backend/Pawn.java diff --git a/OOP_2B1_Project/src/backend/Pawn.java b/OOP_2B1_Project/src/backend/Pawn.java new file mode 100644 index 0000000..156291d --- /dev/null +++ b/OOP_2B1_Project/src/backend/Pawn.java @@ -0,0 +1,51 @@ +package backend; + +import java.util.ArrayList; +import java.util.List; + +public class Pawn extends Piece { + public Pawn(boolean isWhite, int x, int y) { + super(isWhite, PieceType.Pawn, x, y); + } + + @Override + public PieceType getType() { + return PieceType.Pawn; + } + + @Override + public List getLegalMoves(Board board, int row, int col) { + List moves = new ArrayList<>(); + int direction = isWhite ? -1 : 1; + int startRow = isWhite ? 6 : 1; + + // Forward 1 square + int forwardRow = row + direction; + if (board.isInBounds(forwardRow, col) && board.getPieceAt(forwardRow, col) == null) { + moves.add(new Move(this, row, col, forwardRow, col)); + + // Forward 2 squares from starting position + int doubleForwardRow = row + 2 * direction; + if (row == startRow && board.getPieceAt(doubleForwardRow, col) == null) { + moves.add(new Move(this, row, col, doubleForwardRow, col)); + } + } + + // Diagonal captures + for (int dc = -1; dc <= 1; dc += 2) { + int c = col + dc; + if (board.isInBounds(forwardRow, c)) { + Piece target = board.getPieceAt(forwardRow, c); + if (target != null && target.isWhite() != this.isWhite) + moves.add(new Move(this, row, col, forwardRow, c)); + } + } + + return moves; + } + + @Override + public Piece clone() { + return new Pawn(this.isWhite, this.x, this.y); + } +} From 6fb087cbc00f99c0b73652153210a387566b1715 Mon Sep 17 00:00:00 2001 From: Tilman Crosetti Date: Tue, 13 May 2025 14:51:57 +0200 Subject: [PATCH 06/12] Move modification --- OOP_2B1_Project/src/backend/Move.java | 57 +++++++++++++++++++++------ 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/OOP_2B1_Project/src/backend/Move.java b/OOP_2B1_Project/src/backend/Move.java index 38328d3..73c867b 100644 --- a/OOP_2B1_Project/src/backend/Move.java +++ b/OOP_2B1_Project/src/backend/Move.java @@ -1,20 +1,51 @@ package backend; public class Move { - private final Piece piece; - private final int fromX, fromY, toX, toY; + private final Piece movedPiece; + private final int fromRow, fromCol; + private final int toRow, toCol; + private final Piece capturedPiece; // Optional, can be null - public Move(Piece piece, int fromX, int fromY, int toX, int toY) { - this.piece = piece; - this.fromX = fromX; - this.fromY = fromY; - this.toX = toX; - this.toY = toY; + public Move(Piece movedPiece, int fromRow, int fromCol, int toRow, int toCol) { + this(movedPiece, fromRow, fromCol, toRow, toCol, null); } - public Piece getPiece() { return piece; } - public int getFromX() { return fromX; } - public int getFromY() { return fromY; } - public int getToX() { return toX; } - public int getToY() { return toY; } + public Move(Piece movedPiece, int fromRow, int fromCol, int toRow, int toCol, Piece capturedPiece) { + this.movedPiece = movedPiece; + this.fromRow = fromRow; + this.fromCol = fromCol; + this.toRow = toRow; + this.toCol = toCol; + this.capturedPiece = capturedPiece; + } + + public Piece getMovedPiece() { + return movedPiece; + } + + public int getFromRow() { + return fromRow; + } + + public int getFromCol() { + return fromCol; + } + + public int getToRow() { + return toRow; + } + + public int getToCol() { + return toCol; + } + + public Piece getCapturedPiece() { + return capturedPiece; + } + + @Override + public String toString() { + return movedPiece.getType() + " from (" + fromRow + "," + fromCol + ") to (" + toRow + "," + toCol + ")" + + (capturedPiece != null ? " capturing " + capturedPiece.getType() : ""); + } } From 8e3c7d9adac64b22c4edc4bd12a85f99cf973723 Mon Sep 17 00:00:00 2001 From: Tilman Crosetti Date: Tue, 13 May 2025 14:52:08 +0200 Subject: [PATCH 07/12] Rook rules --- OOP_2B1_Project/src/backend/Rook.java | 44 +++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 OOP_2B1_Project/src/backend/Rook.java diff --git a/OOP_2B1_Project/src/backend/Rook.java b/OOP_2B1_Project/src/backend/Rook.java new file mode 100644 index 0000000..d5202f0 --- /dev/null +++ b/OOP_2B1_Project/src/backend/Rook.java @@ -0,0 +1,44 @@ +package backend; + +import java.util.ArrayList; +import java.util.List; + +public class Rook extends Piece { + public Rook(boolean isWhite, int x, int y) { + super(isWhite, PieceType.Rook, x, y); + } + + @Override + public PieceType getType() { + return PieceType.Rook; + } + + @Override + public List getLegalMoves(Board board, int row, int col) { + List moves = new ArrayList<>(); + int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; + + for (int[] dir : directions) { + int r = row + dir[0], c = col + dir[1]; + while (board.isInBounds(r, c)) { + Piece target = board.getPieceAt(r, c); + if (target == null) { + moves.add(new Move(this, row, col, r, c)); + } else { + if (target.isWhite() != this.isWhite) + moves.add(new Move(this, row, col, r, c)); + break; + } + r += dir[0]; + c += dir[1]; + } + } + + return moves; + } + + @Override + public Piece clone() { + return new Rook(this.isWhite, this.x, this.y); + } +} \ No newline at end of file From 902442c1e68f8dcaa04115a1a4bff484e9c85e63 Mon Sep 17 00:00:00 2001 From: Tilman Crosetti Date: Tue, 13 May 2025 14:52:21 +0200 Subject: [PATCH 08/12] Piece modification --- OOP_2B1_Project/src/backend/Piece.java | 62 ++++++++++++++------------ 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/OOP_2B1_Project/src/backend/Piece.java b/OOP_2B1_Project/src/backend/Piece.java index 618c43c..b856535 100644 --- a/OOP_2B1_Project/src/backend/Piece.java +++ b/OOP_2B1_Project/src/backend/Piece.java @@ -1,35 +1,39 @@ package backend; -public class Piece { - - private int x; - private int y; - private PieceType type; - private boolean isWhite; - +import java.util.List; - public int getX() { - return x; - } +public abstract class Piece { + protected int x; + protected int y; + protected PieceType type; + protected boolean isWhite; - public int getY() { - return y; - } - - public PieceType getType() { - return type; - } - - public boolean isWhite() { - return isWhite; - } - - public Piece(boolean isWhite, PieceType type, int x, int y){ - this.x=x; - this.y=y; - this.isWhite=isWhite; - this.type=type; - - } + public Piece(boolean isWhite, PieceType type, int x, int y) { + this.x = x; + this.y = y; + this.type = type; + this.isWhite = isWhite; + } + + public int getX() { return x; } + + public int getY() { return y; } + + public PieceType getType() { return type; } + + public boolean isWhite() { return isWhite; } + + public abstract List getLegalMoves(Board board, int row, int col); + + public abstract Piece clone(); } + + + + + + + + + From 5822222afd046594c47e40d4e6cc353b221688d0 Mon Sep 17 00:00:00 2001 From: Tilman Crosetti Date: Tue, 13 May 2025 14:52:31 +0200 Subject: [PATCH 09/12] Queen rules --- OOP_2B1_Project/src/backend/Queen.java | 49 ++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 OOP_2B1_Project/src/backend/Queen.java diff --git a/OOP_2B1_Project/src/backend/Queen.java b/OOP_2B1_Project/src/backend/Queen.java new file mode 100644 index 0000000..8b8692d --- /dev/null +++ b/OOP_2B1_Project/src/backend/Queen.java @@ -0,0 +1,49 @@ +package backend; + +import java.util.ArrayList; +import java.util.List; + +public class Queen extends Piece { + public Queen(boolean isWhite, int x, int y) { + super(isWhite, PieceType.Queen, x, y); + } + + @Override + public PieceType getType() { + return PieceType.Queen; + } + + @Override + public List getLegalMoves(Board board, int row, int col) { + List moves = new ArrayList<>(); + int[][] directions = { + {-1, 0}, {1, 0}, {0, -1}, {0, 1}, // Rook-like + {-1, -1}, {-1, 1}, {1, -1}, {1, 1} // Bishop-like + }; + + for (int[] dir : directions) { + int r = row + dir[0]; + int c = col + dir[1]; + while (board.isInBounds(r, c)) { + Piece target = board.getPieceAt(r, c); + if (target == null) { + moves.add(new Move(this, row, col, r, c)); + } else { + if (target.isWhite() != this.isWhite) { + moves.add(new Move(this, row, col, r, c)); + } + break; + } + r += dir[0]; + c += dir[1]; + } + } + + return moves; + } + + @Override + public Piece clone() { + return new Queen(this.isWhite, this.x, this.y); + } +} From c6669780583e6e59e1090e31ffaf1f4d4e270d65 Mon Sep 17 00:00:00 2001 From: Tilman Crosetti Date: Tue, 13 May 2025 15:12:55 +0200 Subject: [PATCH 10/12] Board modification (Set Piece,User touch) --- OOP_2B1_Project/src/backend/Board.java | 94 ++++++++++++++++---------- 1 file changed, 59 insertions(+), 35 deletions(-) diff --git a/OOP_2B1_Project/src/backend/Board.java b/OOP_2B1_Project/src/backend/Board.java index 010791f..72f0298 100644 --- a/OOP_2B1_Project/src/backend/Board.java +++ b/OOP_2B1_Project/src/backend/Board.java @@ -52,11 +52,31 @@ private ArrayList highlightedPositions = new ArrayList<>(); } public void setPiece(boolean isWhite, PieceType type, int x, int y) { - - pieces.add(new Piece(isWhite, type, x, y)); - - - + // Create a new instance of the specific piece type + Piece newPiece; + switch (type) { + case Pawn: + newPiece = new Pawn(isWhite, x, y); + break; + case King: + newPiece = new King(isWhite, x, y); + break; + case Queen: + newPiece = new Queen(isWhite, x, y); + break; + case Rook: + newPiece = new Rook(isWhite, x, y); + break; + case Bishop: + newPiece = new Bishop(isWhite, x, y); + break; + case Knight: + newPiece = new Knight(isWhite, x, y); + break; + default: + throw new IllegalArgumentException("Unknown piece type"); + } + pieces.add(newPiece); } public void populateBoard() { @@ -134,63 +154,65 @@ private ArrayList highlightedPositions = new ArrayList<>(); } public void userTouch(int x, int y) { - if (selectedX == null && selectedY == null) { - Piece pieceAtPos = getPieceAt(x, y); - if (pieceAtPos != null) { - selectedX = x; selectedY = y; } } else { - if (selectedX == x && selectedY == y) { - selectedX = null; selectedY = null; } else { - Piece pieceToMove = getPieceAt(selectedX, selectedY); - if (pieceToMove != null) { - Piece pieceAtDestination = getPieceAt(x, y); - - - if (pieceAtDestination == null || - pieceAtDestination.isWhite() != pieceToMove.isWhite()) { - - + if (pieceAtDestination == null || pieceAtDestination.isWhite() != pieceToMove.isWhite()) { if (pieceAtDestination != null) { pieces.remove(pieceAtDestination); } - - pieces.remove(pieceToMove); - pieces.add(new Piece(pieceToMove.isWhite(), pieceToMove.getType(), x, y)); - - + + // Create a new instance of the specific piece type + Piece newPiece; + switch (pieceToMove.getType()) { + case Pawn: + newPiece = new Pawn(pieceToMove.isWhite(), x, y); + break; + case King: + newPiece = new King(pieceToMove.isWhite(), x, y); + break; + case Queen: + newPiece = new Queen(pieceToMove.isWhite(), x, y); + break; + case Rook: + newPiece = new Rook(pieceToMove.isWhite(), x, y); + break; + case Bishop: + newPiece = new Bishop(pieceToMove.isWhite(), x, y); + break; + case Knight: + newPiece = new Knight(pieceToMove.isWhite(), x, y); + break; + default: + throw new IllegalArgumentException("Unknown piece type"); + } + pieces.add(newPiece); + turnNumber++; turnIsWhite = !turnIsWhite; } - - - + } selectedX = null; selectedY = null; - } } } - - - } - + } - private Piece getPieceAt(int x, int y) { + public Piece getPieceAt(int x, int y) { for (Piece piece : pieces) { if (piece.getX() == x && piece.getY() == y) { return piece; @@ -304,5 +326,7 @@ public ArrayList getAllPieces() { return pieces; } - +public boolean isInBounds(int row, int col) { + return row >= 0 && row < 8 && col >= 0 && col < 8; +} } From 1aaf4cd6d555f2ad08c7699f47489b201a5c6e2b Mon Sep 17 00:00:00 2001 From: "charles.duteil" Date: Tue, 13 May 2025 15:27:12 +0200 Subject: [PATCH 11/12] playMoveSound added --- OOP_2B1_Project/src/backend/Board.java | 41 ++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/OOP_2B1_Project/src/backend/Board.java b/OOP_2B1_Project/src/backend/Board.java index 72f0298..d06f986 100644 --- a/OOP_2B1_Project/src/backend/Board.java +++ b/OOP_2B1_Project/src/backend/Board.java @@ -1,4 +1,8 @@ package backend; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; + import java.util.ArrayList; @@ -22,12 +26,17 @@ private Integer selectedY = null; private ArrayList highlightedPositions = new ArrayList<>(); +/* ====== AUDIO STATE ====== */ +private Clip moveClip; +private boolean soundEnabled = false; public Board(int colNum, int lineNum) { this.Width=colNum; this.Height=lineNum; this.pieces= new ArrayList <> (); + initMoveSound(); + @@ -199,6 +208,8 @@ private ArrayList highlightedPositions = new ArrayList<>(); throw new IllegalArgumentException("Unknown piece type"); } pieces.add(newPiece); + + playMoveSound(); turnNumber++; turnIsWhite = !turnIsWhite; @@ -329,4 +340,34 @@ public ArrayList getAllPieces() { public boolean isInBounds(int row, int col) { return row >= 0 && row < 8 && col >= 0 && col < 8; } +private void initMoveSound() { + try { + AudioInputStream ais = AudioSystem.getAudioInputStream( + Board.class.getResource("/sounds/move.wav")); + + if (ais == null) { // resource not found + System.err.println("move.wav not on class-path!"); + return; + } + + moveClip = AudioSystem.getClip(); + moveClip.open(ais); + + soundEnabled = true; // <<< MISSING LINE + System.out.println("Move-sound loaded OK"); + } catch (Exception e) { + e.printStackTrace(); + soundEnabled = false; + } +} + +private void playMoveSound() { + if (!soundEnabled || moveClip == null) return; + + if (moveClip.isRunning()) { + moveClip.stop(); + } + moveClip.setFramePosition(0); + moveClip.start(); +} } From 66710ec364bbdda1417c631cab1cd731df65562a Mon Sep 17 00:00:00 2001 From: "charles.duteil" Date: Tue, 13 May 2025 15:27:36 +0200 Subject: [PATCH 12/12] move sound (to be updated later) --- OOP_2B1_Project/src/sounds/move.wav | Bin 0 -> 1660 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 OOP_2B1_Project/src/sounds/move.wav diff --git a/OOP_2B1_Project/src/sounds/move.wav b/OOP_2B1_Project/src/sounds/move.wav new file mode 100644 index 0000000000000000000000000000000000000000..1e6615e7c80840172c55eadff50264d86edfc154 GIT binary patch literal 1660 zcmW+%J&znk5M3vT5Hd1|NXQXLBna6O5yF9y5C|VaHnzO?u{*mn-PK)HUEMu5ySFyy z^V!%K3>FDF{0x2o5jmv%faCS;YInP5s$Rc(^=kI|$JefPugqqjeR$*Qt$Fv>YqQzx z3f`~3GrRm;nY}vuX0O}(1TjgISTs>K=JuOJB}LXqE(W3yLu66q5QU;@^f5Cwmet}o zP#HriJ_Ms=+r%n8S2J@OoDJ%%Tlbchs|S(8{blfBH5vJ-_*>EM+*vn!`(ie`z~`fj z+22oQ?_T`7_s{$9-R=L-7xczo*RTF^^UwcgZ(fuS9v{W0CqLZz;`e)BTDk4$+oMN6 ze}4P%v%?$D&+XT(=H1Qhy_c&+clOirz(0J}A1`%L{oMzN4#M`dmUQ$eOm4Y+xgf%seA6l^3&g*9?-$&+2U}TbD8tW{Pv2p>v#T$whP;> z)w$Ew{B#Cm3~;Sss$qzu^yb&KcuvDw zWEI7UbW1kveF}lRL?4pZgjh2Yt9}YSY$2L6jXCI)V^%S-#6a^bHFA_-zxXO~4h$CC%q{5`C zFf~VX*vEjeNX%@`rIJF7G*KvJP#C`Spy_>$Dqb-wEJ0FI>eDD-q#>x#So*}09p@-u zEMSOHLpC!ok`S08xE-EI3rJ?mrC3ucf)OhE{1bir~&f~r@6 zFdCy+fRP2d0GL}7pkq4(FThx66{0{!5S}tAT^?fr&mOFBvq=CTL^UQ@w66f^7~%m6 zOM~wK-5}u|hz2jU9YEU?3u+<>X$-Q^wP4j$0IQTy3EqtqdI&>7h5!H%OipTEQiU!^ z;M&n-184O#jf1aspxiPw!(LK6oK?wl!8w;D00)2)S~FVbGC6Fqk2nNYM12sU83(&& z4Ty+b6o)k=X{Lfza19zlC)Cl{;SNGk4f@eaYo~#sp(NO|RRRaJFu)+76_1iz+nNkm zA$yFl$)tTak*>f*n1Kp)6Zat-tOSalN$}Xq5wn!gWQRWjgrOtZ5NM2XM;oYhg)8Tr YK^4P`Lz^X`q^5$yakfEZXdct-f7wGNzyJUM literal 0 HcmV?d00001