diff --git a/src/main/java/cz/vsb/fei/java2/lab03/AppController.java b/src/main/java/cz/vsb/fei/java2/lab03/AppController.java
index 3b613391501a607dc2cbb64f3a24e0062fc16137..0436edfdafa2f7e5d368b1cfd5121debaa823a79 100644
--- a/src/main/java/cz/vsb/fei/java2/lab03/AppController.java
+++ b/src/main/java/cz/vsb/fei/java2/lab03/AppController.java
@@ -1,20 +1,104 @@
 package cz.vsb.fei.java2.lab03;
 
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+import java.util.stream.Stream;
+
+import javafx.beans.binding.ObjectBinding;
+import javafx.beans.value.ObservableValue;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
 import javafx.event.ActionEvent;
 import javafx.fxml.FXML;
-import javafx.scene.control.Label;
-import javafx.scene.control.MenuItem;
+import javafx.scene.control.SelectionMode;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.TableView;
+import javafx.scene.control.cell.PropertyValueFactory;
+import javafx.scene.paint.Color;
 
 public class AppController {
 
+	private static final Random RANDOM = new Random();
+	private static final List<Color> COLORS = Arrays.asList(Color.RED, Color.BLUE);
+
+	@FXML
+	private TableView<Point> table1;
+
+	@FXML
+	private TableView<Point> table2;
+
+	private ObservableList<Point> points1 = FXCollections.observableArrayList();
+
+	private ObservableList<Point> points2 = FXCollections.observableArrayList();
+
 	@FXML
-	private Label infoLabel;
+	public void initialize() {
+		table1.setItems(points1);
+		table2.setItems(points2);
+		initColumns(table1);
+		initColumns(table2);
+		table1.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
+		table2.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
+		table1.getSelectionModel().selectedItemProperty()
+				.addListener((ObservableValue<? extends Point> observable, Point oldValue, Point newValue) -> {
+					table2.getSelectionModel().clearSelection();
+					for (int i = 0; i < points2.size(); i++) {
+						if (newValue != null && newValue.equals(points2.get(i))) {
+							table2.getSelectionModel().select(i);
+						}
+					}
+				});
+	}
+
+	private void initColumns(TableView<Point> tab) {
+		((TableColumn<Point, Double>) tab.getColumns().get(0)).setCellValueFactory(new PropertyValueFactory<>("x"));
+		((TableColumn<Point, Double>) tab.getColumns().get(1)).setCellValueFactory(new PropertyValueFactory<>("y"));
+		((TableColumn<Point, Color>) tab.getColumns().get(2)).setCellValueFactory(param -> {
+			if (param.getValue() instanceof ColorPoint p) {
+				return new MyObservableValue<>(p.getColor());
+			}
+			return null;
+		});
+		((TableColumn<Point, Integer>) tab.getColumns().get(3))
+				.setCellValueFactory(param -> new MyObservableValue<>(System.identityHashCode(param.getValue())));
+	}
 
 	@FXML
-	private void menuPressed(ActionEvent event) {
-		if(event.getSource() instanceof MenuItem menuItem) {
-			infoLabel.setText("Selected menu: " + menuItem.getText());
+	private void generatePressed(ActionEvent event) {
+		Stream.generate(this::generate).limit(10).forEach(points1::add);
+		Stream.generate(this::generate).limit(6).forEach(points2::add);
+		Stream.generate(() -> RANDOM.nextInt(points1.size())).limit(4).map(points1::get).forEach(points2::add);
+	}
+
+	@FXML
+	private void clearPressed(ActionEvent event) {
+		table2.getSelectionModel().clearSelection();
+		table1.getSelectionModel().clearSelection();
+		points1.clear();
+		points2.clear();
+	}
+
+	private Point generate() {
+		if (RANDOM.nextBoolean()) {
+			return new Point(RANDOM.nextInt(2), RANDOM.nextInt(2));
+		} else {
+			return new ColorPoint(RANDOM.nextInt(2), RANDOM.nextInt(2), COLORS.get(RANDOM.nextInt(COLORS.size())));
 		}
 	}
 
+	public static class MyObservableValue<T> extends ObjectBinding<T> {
+
+		private T value;
+
+		public MyObservableValue(T color) {
+			this.value = color;
+		}
+
+		@Override
+		public T computeValue() {
+			return value;
+		}
+
+	}
 }
diff --git a/src/main/java/cz/vsb/fei/java2/lab03/ColorPoint.java b/src/main/java/cz/vsb/fei/java2/lab03/ColorPoint.java
index 16722be7c127a830ba28d9e80be9ad1a13a2ec1d..9b30cbf540d75a920c54721550e8df6ed1e01248 100644
--- a/src/main/java/cz/vsb/fei/java2/lab03/ColorPoint.java
+++ b/src/main/java/cz/vsb/fei/java2/lab03/ColorPoint.java
@@ -11,4 +11,8 @@ public class ColorPoint extends Point {
 		this.color = color;
 	}
 
+	public Color getColor() {
+		return color;
+	}
+
 }
diff --git a/src/main/java/cz/vsb/fei/java2/lab03/Point.java b/src/main/java/cz/vsb/fei/java2/lab03/Point.java
index cc34fbc39a6d8595ffac0dd749a78ab7ecb26c44..6e67b01bc25a38937c377cff0edf9e3f1d56254f 100644
--- a/src/main/java/cz/vsb/fei/java2/lab03/Point.java
+++ b/src/main/java/cz/vsb/fei/java2/lab03/Point.java
@@ -11,4 +11,12 @@ public class Point {
 		this.y = y;
 	}
 
+	public double getX() {
+		return x;
+	}
+
+	public double getY() {
+		return y;
+	}
+
 }
\ No newline at end of file
diff --git a/src/main/resources/cz/vsb/fei/java2/lab03/AppWindow.fxml b/src/main/resources/cz/vsb/fei/java2/lab03/AppWindow.fxml
index 6a81cb714392da4f95140ab76f55e0edcfc5e83c..5b0577ff75c941de01c3af5bba4bda9c018a17de 100644
--- a/src/main/resources/cz/vsb/fei/java2/lab03/AppWindow.fxml
+++ b/src/main/resources/cz/vsb/fei/java2/lab03/AppWindow.fxml
@@ -32,62 +32,66 @@
   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 -->
 
+<?import javafx.geometry.Insets?>
+<?import javafx.scene.control.Button?>
 <?import javafx.scene.control.Label?>
-<?import javafx.scene.control.Menu?>
-<?import javafx.scene.control.MenuBar?>
-<?import javafx.scene.control.MenuItem?>
-<?import javafx.scene.control.SeparatorMenuItem?>
+<?import javafx.scene.control.TableColumn?>
+<?import javafx.scene.control.TableView?>
 <?import javafx.scene.layout.BorderPane?>
-<?import javafx.scene.text.Font?>
+<?import javafx.scene.layout.HBox?>
 
-
-<BorderPane minHeight="400.0" minWidth="640.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="cz.vsb.fei.java2.lab03.AppController">
-   <top>
-    <MenuBar BorderPane.alignment="CENTER">
-      <menus>
-        <Menu mnemonicParsing="false" text="File">
-          <items>
-            <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="New" />
-            <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Open…" />
-            <Menu mnemonicParsing="false" text="Open Recent" />
-            <SeparatorMenuItem mnemonicParsing="false" />
-            <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Close" />
-            <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Save" />
-            <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Save As…" />
-            <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Revert" />
-            <SeparatorMenuItem mnemonicParsing="false" onAction="#menuPressed" />
-            <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Preferences…" />
-            <SeparatorMenuItem mnemonicParsing="false" />
-            <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Quit" />
-          </items>
-        </Menu>
-        <Menu mnemonicParsing="false" text="Edit">
-          <items>
-            <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Undo" />
-            <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Redo" />
-            <SeparatorMenuItem mnemonicParsing="false" />
-            <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Cut" />
-            <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Copy" />
-            <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Paste" />
-            <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Delete" />
-            <SeparatorMenuItem mnemonicParsing="false" />
-            <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Select All" />
-            <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="Unselect All" />
-          </items>
-        </Menu>
-        <Menu mnemonicParsing="false" text="Help">
-          <items>
-            <MenuItem mnemonicParsing="false" onAction="#menuPressed" text="About MyHelloApp" />
-          </items>
-        </Menu>
-      </menus>
-    </MenuBar>
-   </top>
+<BorderPane minHeight="400.0" minWidth="640.0" prefHeight="400.0" prefWidth="715.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="cz.vsb.fei.java2.lab03.AppController">
    <center>
-  <Label fx:id="infoLabel" alignment="CENTER" style="&#10;" text="Drag components from Library here…" textAlignment="CENTER" textFill="#9f9f9f" wrapText="false" BorderPane.alignment="CENTER">
-    <font>
-      <Font size="18.0" />
-    </font>
-  </Label>
+      <HBox prefHeight="100.0" prefWidth="200.0" BorderPane.alignment="CENTER">
+         <children>
+            <TableView fx:id="table1" prefHeight="200.0" prefWidth="200.0" HBox.hgrow="ALWAYS">
+              <columns>
+                <TableColumn prefWidth="46.0" text="X" />
+                <TableColumn prefWidth="52.0" text="Y" />
+                  <TableColumn prefWidth="75.0" text="Color" />
+                  <TableColumn prefWidth="163.0" text="System identity&#10;HashCode" />
+              </columns>
+            </TableView>
+            <BorderPane HBox.hgrow="NEVER">
+               <HBox.margin>
+                  <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
+               </HBox.margin>
+               <center>
+                  <Label text="==" />
+               </center>
+            </BorderPane>
+            <TableView fx:id="table2" prefHeight="200.0" prefWidth="200.0" HBox.hgrow="ALWAYS">
+              <columns>
+                <TableColumn prefWidth="38.0" text="X" />
+                <TableColumn prefWidth="35.0" text="Y" />
+                  <TableColumn prefWidth="70.0" text="Color" />
+                  <TableColumn prefWidth="186.0" text="System identity&#10;HashCode" />
+              </columns>
+               <columnResizePolicy>
+                  <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
+               </columnResizePolicy>
+            </TableView>
+         </children>
+      </HBox>
    </center>
+   <top>
+      <BorderPane BorderPane.alignment="CENTER">
+         <center>
+            <HBox alignment="CENTER" BorderPane.alignment="CENTER">
+               <children>
+                  <Button mnemonicParsing="false" onAction="#generatePressed" text="Generate">
+                     <HBox.margin>
+                        <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
+                     </HBox.margin>
+                  </Button>
+                  <Button mnemonicParsing="false" onAction="#clearPressed" text="Clear">
+                     <HBox.margin>
+                        <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
+                     </HBox.margin>
+                  </Button>
+               </children>
+            </HBox>
+         </center>
+      </BorderPane>
+   </top>
 </BorderPane>
diff --git a/src/test/java/cz/vsb/fei/java2/lab03/EquivalenceRoutines.java b/src/test/java/cz/vsb/fei/java2/lab03/EquivalenceRoutines.java
new file mode 100644
index 0000000000000000000000000000000000000000..159555fb4cec2342670b591e0ef0fcf77b79504f
--- /dev/null
+++ b/src/test/java/cz/vsb/fei/java2/lab03/EquivalenceRoutines.java
@@ -0,0 +1,25 @@
+package cz.vsb.fei.java2.lab03;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+
+class EquivalenceRoutines {
+	static void assertReflexivity(Object obj) {
+		assertTrue(obj.equals(obj));
+	}
+	
+	static void assertSymmetry(Object obj1, Object obj2) {
+		if(obj1.equals(obj2)) {
+			assertTrue(obj2.equals(obj1));
+		} else {
+	
+			assertTrue(!obj2.equals(obj1));
+		}
+	}
+	
+	static void assertTransitivity(Object obj1, Object obj2, Object obj3) {
+		if(obj1.equals(obj2) && obj2.equals(obj3)) {
+			assertTrue(obj1.equals(obj3));
+		} 
+	}
+}
diff --git a/src/test/java/cz/vsb/fei/java2/lab03/TestEquals.java b/src/test/java/cz/vsb/fei/java2/lab03/TestEquals.java
new file mode 100644
index 0000000000000000000000000000000000000000..d14a7499ba4c3e76b2f8a3239ff9a074b1f07889
--- /dev/null
+++ b/src/test/java/cz/vsb/fei/java2/lab03/TestEquals.java
@@ -0,0 +1,95 @@
+package cz.vsb.fei.java2.lab03;
+
+import static cz.vsb.fei.java2.lab03.EquivalenceRoutines.assertReflexivity;
+import static cz.vsb.fei.java2.lab03.EquivalenceRoutines.assertSymmetry;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+
+import javafx.scene.paint.Color;
+
+/**
+ * Unit test for simple App.
+ */
+@TestMethodOrder(OrderAnnotation.class)
+class TestEquals {
+
+	@Test
+	@Order(1)
+	void testLogicEquality() {
+		Point p1 = new Point(1, 2);
+		Point p2 = new Point(1, 2);
+		assertTrue(p1.equals(p2));
+
+		Point p3 = new Point(1, 1);
+		assertTrue(!p1.equals(p3));
+
+		Point cp1 = new ColorPoint(1, 2, Color.BLACK);
+		Point cp2 = new ColorPoint(1, 2, Color.BLACK);
+		assertTrue(cp1.equals(cp2));
+
+		Point cp3 = new ColorPoint(1, 1, Color.BLACK);
+		assertTrue(!cp1.equals(cp3));
+
+		Point cp4 = new ColorPoint(1, 2, Color.WHITE);
+		assertTrue(!cp1.equals(cp4));
+	}
+
+	@Test
+	@Order(2)
+	void testRelfexity() {
+		Point p1 = new Point(1, 2);
+		assertReflexivity(p1);
+	}
+
+	@Test
+	@Order(3)
+	void testSymmetry() {
+		Point p1 = new Point(1, 2);
+		Point p2 = new Point(1, 2);
+		assertSymmetry(p1, p2);
+
+		Point p3 = new Point(1, 1);
+		assertSymmetry(p1, p3);
+
+		Point cp1 = new ColorPoint(1, 2, Color.BLACK);
+		Point cp2 = new ColorPoint(1, 2, Color.BLACK);
+		assertSymmetry(p1, cp2);
+		assertSymmetry(cp1, cp2);
+
+		Point cp3 = new ColorPoint(1, 1, Color.BLACK);
+		assertSymmetry(p1, cp3);
+		assertSymmetry(cp1, cp3);
+
+		Point cp4 = new ColorPoint(1, 2, Color.WHITE);
+		assertSymmetry(p1, cp4);
+		assertSymmetry(cp1, cp4);
+	}
+
+	@Test
+	@Order(4)
+	void testTransitivity() {
+
+		Point p1 = new ColorPoint(1, 2, Color.WHITE);
+		Point p2 = new Point(1, 2);
+		Point p3 = new ColorPoint(1, 2, Color.BLACK);
+		EquivalenceRoutines.assertTransitivity(p1, p2, p3);
+	}
+
+	@Test
+	@Order(5)
+	void testLiskovPrinciple() {
+		Point p1 = new ColorPoint(1, 2, Color.CYAN);
+		Point p2 = new ColorPoint(1, 2, Color.CYAN) {
+
+			@Override
+			public String toString() {
+				return "Moje barva";
+			}
+		};
+		assertTrue(p1.equals(p2));
+	}
+}