├── dial.jpg ├── mapped2.png ├── README.md ├── clock_test.py ├── clock.py └── clock.ipynb /dial.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Concept-Bytes/MC_Clock/main/dial.jpg -------------------------------------------------------------------------------- /mapped2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Concept-Bytes/MC_Clock/main/mapped2.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MC_Clock 2 | This project turns your Raspberry Pi 5 into a functional Minecraft-themed clock. It utilizes a 5-inch round display, Pygame, and Python libraries to create a visual clock that rotates the iconic Minecraft clock image based on the current time of day. 3 | 4 | # Features 5 | 6 | * Real-Time Clock: The clock displays the current time in a 12-hour format, where noon (12:00 PM) corresponds to 0 degrees, and midnight (12:00 AM) corresponds to 180 degrees. 7 | 8 | * Custom Image Mapping: Uses the Minecraft clock image (mapped2.png), which rotates smoothly to reflect the current time. 9 | 10 | * Grid-Based Resampling: The image is divided into a 10x10 grid, and each grid cell's color is resampled based on the most common color in that region. 11 | 12 | * Debug Mode: Allows for easy development and testing by setting custom time values. 13 | 14 | # Hardware Requirements 15 | 16 | * Raspberry Pi 5 17 | 18 | * 5-inch Round Display (linked in the build guide) 19 | 20 | # Software Requirements 21 | 22 | * Raspberry Pi OS (or a compatible Linux distribution) 23 | 24 | * python 3.x 25 | 26 | * Required Libraries: 27 | * pygame 28 | * Pillow 29 | * numpy 30 | 31 | # Installation 32 | 33 | Clone the Repository: 34 | 35 | ``` git clone https://github.com/Concept-Bytes/MC_Clock ``` 36 | 37 | 38 | # Controls 39 | 40 | ESC or Q: Exit the application 41 | 42 | # License 43 | Distributed under the MIT License. See LICENSE for more information. 44 | 45 | # Contact 46 | Reach out with any feedback or support needs via GitHub or email. 47 | -------------------------------------------------------------------------------- /clock_test.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | import sys 3 | import numpy as np 4 | from PIL import Image 5 | from collections import Counter 6 | 7 | # Configuration 8 | IMAGE_PATH = 'mapped2.png' 9 | WINDOW_SIZE = 1080 10 | GRID_SIZE = 10 11 | SCALING_FACTOR = 2.5 12 | ANGLE_INCREMENT = 2 # Faster rotation 13 | 14 | # Initialize pygame 15 | pygame.init() 16 | 17 | screen = pygame.display.set_mode((WINDOW_SIZE, WINDOW_SIZE), pygame.FULLSCREEN) 18 | pygame.display.set_caption("Minecraft Clock Rotation - Time of Day Based") 19 | 20 | 21 | # Load image with PIL 22 | image = Image.open(IMAGE_PATH) 23 | 24 | # Precompute parameters 25 | cell_size = WINDOW_SIZE // GRID_SIZE 26 | new_size = int(WINDOW_SIZE * SCALING_FACTOR) 27 | angle = 0 28 | 29 | # Scale the image once outside the main loop 30 | scaled_image_bigger = image.resize((new_size, new_size), Image.NEAREST) 31 | 32 | clock = pygame.time.Clock() 33 | running = True 34 | 35 | while running: 36 | # Event handling 37 | for event in pygame.event.get(): 38 | if event.type == pygame.QUIT: 39 | running = False 40 | elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: 41 | running = False 42 | 43 | # Create a black canvas 44 | canvas = np.zeros((WINDOW_SIZE, WINDOW_SIZE, 3), dtype=np.uint8) 45 | 46 | # Rotate the pre-scaled image 47 | rotated_image_bigger = scaled_image_bigger.rotate(angle) 48 | 49 | # Crop to 1080x1080 50 | left = (rotated_image_bigger.width - WINDOW_SIZE) / 2 51 | top = (rotated_image_bigger.height - WINDOW_SIZE) / 2 52 | right = (rotated_image_bigger.width + WINDOW_SIZE) / 2 53 | bottom = (rotated_image_bigger.height + WINDOW_SIZE) / 2 54 | cropped_image = rotated_image_bigger.crop((left, top, right, bottom)) 55 | 56 | # Convert to numpy 57 | cropped_image_np = np.array(cropped_image) 58 | 59 | # Place the cropped image onto the canvas 60 | canvas[:cropped_image_np.shape[0], :cropped_image_np.shape[1]] = cropped_image_np 61 | 62 | # Resample by the most common color in each cell 63 | resampled_canvas = np.zeros_like(canvas) 64 | for row in range(GRID_SIZE): 65 | for col in range(GRID_SIZE): 66 | # Get cell boundaries 67 | start_row = row * cell_size 68 | end_row = start_row + cell_size 69 | start_col = col * cell_size 70 | end_col = start_col + cell_size 71 | 72 | # Extract the cell 73 | cell = canvas[start_row:end_row, start_col:end_col] 74 | 75 | # Find the most frequent color 76 | cell_flat = cell.reshape(-1, cell.shape[-1]) 77 | most_common_color = Counter(map(tuple, cell_flat)).most_common(1)[0][0] 78 | 79 | # Fill the resampled canvas cell 80 | resampled_canvas[start_row:end_row, start_col:end_col] = most_common_color 81 | 82 | # Convert the resampled numpy array to a pygame surface 83 | surface = pygame.surfarray.make_surface(np.transpose(resampled_canvas, (1, 0, 2))) 84 | 85 | # Draw the image to the screen 86 | screen.blit(surface, (0,0)) 87 | pygame.display.flip() 88 | 89 | # Update the angle (negative to reverse direction if needed) 90 | angle = (angle - ANGLE_INCREMENT) % 360 91 | 92 | # Attempt to run at ~60 FPS 93 | clock.tick(60) 94 | 95 | pygame.quit() 96 | sys.exit() 97 | 98 | -------------------------------------------------------------------------------- /clock.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | import sys 3 | import numpy as np 4 | from PIL import Image 5 | from collections import Counter 6 | from datetime import datetime 7 | 8 | # Configuration 9 | IMAGE_PATH = 'mapped2.png' 10 | WINDOW_SIZE = 1080 11 | GRID_SIZE = 10 12 | SCALING_FACTOR = 2.5 13 | DEBUG = True # Set this to True to enable debug mode 14 | 15 | # Debug configuration 16 | debug_hours = 6 # Set this to the desired debug hour (0-23) 17 | debug_minutes = 0 # Set this to the desired debug minute (0-59) 18 | 19 | # Initialize pygame 20 | pygame.init() 21 | 22 | screen = pygame.display.set_mode((WINDOW_SIZE, WINDOW_SIZE), pygame.FULLSCREEN) 23 | pygame.display.set_caption("Minecraft Clock Rotation - Time of Day Based") 24 | 25 | # Load image with PIL 26 | image = Image.open(IMAGE_PATH) 27 | 28 | # Precompute parameters 29 | cell_size = WINDOW_SIZE // GRID_SIZE 30 | new_size = int(WINDOW_SIZE * SCALING_FACTOR) 31 | 32 | # Scale the image once outside the main loop 33 | scaled_image_bigger = image.resize((new_size, new_size), Image.NEAREST) 34 | 35 | clock = pygame.time.Clock() 36 | running = True 37 | 38 | while running: 39 | # Event handling 40 | for event in pygame.event.get(): 41 | if event.type == pygame.QUIT: 42 | running = False 43 | elif event.type == pygame.KEYDOWN: 44 | if event.key == pygame.K_ESCAPE or event.key == pygame.K_q: 45 | running = False 46 | 47 | # Get current time or debug time 48 | if DEBUG: 49 | hours = debug_hours + debug_minutes / 60 # Use debug time if debug mode is enabled 50 | else: 51 | now = datetime.now() 52 | hours = now.hour + now.minute / 60 # Include minutes as a fraction of an hour 53 | 54 | # Calculate angle where 12:00 PM (noon) = 0 degrees and 12:00 AM (midnight) = 180 degrees 55 | if hours >= 12: 56 | hours -= 12 # Convert 24-hour format to 12-hour format 57 | 58 | angle = (hours / 24) * 360 # Map 0-12 hours to 0-360 degrees 59 | angle = 360 - angle # Reverse direction to match the desired rotation (noon = 0, midnight = 180) 60 | 61 | # Create a black canvas 62 | canvas = np.zeros((WINDOW_SIZE, WINDOW_SIZE, 3), dtype=np.uint8) 63 | 64 | # Rotate the pre-scaled image 65 | rotated_image_bigger = scaled_image_bigger.rotate(angle) 66 | 67 | # Crop to 1080x1080 68 | left = (rotated_image_bigger.width - WINDOW_SIZE) / 2 69 | top = (rotated_image_bigger.height - WINDOW_SIZE) / 2 70 | right = (rotated_image_bigger.width + WINDOW_SIZE) / 2 71 | bottom = (rotated_image_bigger.height + WINDOW_SIZE) / 2 72 | cropped_image = rotated_image_bigger.crop((left, top, right, bottom)) 73 | 74 | # Convert to numpy 75 | cropped_image_np = np.array(cropped_image) 76 | 77 | # Place the cropped image onto the canvas 78 | canvas[:cropped_image_np.shape[0], :cropped_image_np.shape[1]] = cropped_image_np 79 | 80 | # Resample by the most common color in each cell 81 | resampled_canvas = np.zeros_like(canvas) 82 | for row in range(GRID_SIZE): 83 | for col in range(GRID_SIZE): 84 | # Get cell boundaries 85 | start_row = row * cell_size 86 | end_row = start_row + cell_size 87 | start_col = col * cell_size 88 | end_col = start_col + cell_size 89 | 90 | # Extract the cell 91 | cell = canvas[start_row:end_row, start_col:end_col] 92 | 93 | # Find the most frequent color 94 | cell_flat = cell.reshape(-1, cell.shape[-1]) 95 | most_common_color = Counter(map(tuple, cell_flat)).most_common(1)[0][0] 96 | 97 | # Fill the resampled canvas cell 98 | resampled_canvas[start_row:end_row, start_col:end_col] = most_common_color 99 | 100 | # Convert the resampled numpy array to a pygame surface 101 | surface = pygame.surfarray.make_surface(np.transpose(resampled_canvas, (1, 0, 2))) 102 | 103 | # Draw the image to the screen 104 | screen.blit(surface, (0, 0)) 105 | pygame.display.flip() 106 | 107 | # Attempt to run at ~60 FPS 108 | clock.tick(60) 109 | 110 | pygame.quit() 111 | sys.exit() 112 | -------------------------------------------------------------------------------- /clock.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 3, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "name": "stdout", 10 | "output_type": "stream", 11 | "text": [ 12 | "(26, 26)\n" 13 | ] 14 | } 15 | ], 16 | "source": [ 17 | "from PIL import Image\n", 18 | "\n", 19 | "# Read in the image\n", 20 | "image = Image.open('mapped2.png')\n", 21 | "\n", 22 | "# Print out the dimensions\n", 23 | "print(image.size)" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": 4, 29 | "metadata": {}, 30 | "outputs": [ 31 | { 32 | "data": { 33 | "image/png": "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", 34 | "text/plain": [ 35 | "
" 36 | ] 37 | }, 38 | "metadata": {}, 39 | "output_type": "display_data" 40 | } 41 | ], 42 | "source": [ 43 | "import numpy as np\n", 44 | "\n", 45 | "import matplotlib.pyplot as plt\n", 46 | "\n", 47 | "# Create a black canvas\n", 48 | "canvas = np.zeros((1080, 1080, 3), dtype=np.uint8)\n", 49 | "\n", 50 | "# Define the grid size\n", 51 | "grid_size = 10\n", 52 | "cell_size = 1080 // grid_size\n", 53 | "\n", 54 | "# Draw the grid lines\n", 55 | "for i in range(1, grid_size):\n", 56 | " # Horizontal lines\n", 57 | " canvas[i * cell_size, :] = 255\n", 58 | " # Vertical lines\n", 59 | " canvas[:, i * cell_size] = 255\n", 60 | "\n", 61 | "# Display the canvas\n", 62 | "plt.imshow(canvas)\n", 63 | "plt.axis('off')\n", 64 | "plt.show()" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": 5, 70 | "metadata": { 71 | "vscode": { 72 | "languageId": "ruby" 73 | } 74 | }, 75 | "outputs": [ 76 | { 77 | "data": { 78 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYUAAAGFCAYAAAASI+9IAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAdYElEQVR4nO3dXYxc5X3H8d85s7ZTdrNASEECgm0CbYJJUqnmIoW0cNUQAjg1Uq8wSHATNRKoICWlUugVL3dBNUkv7Ea9CanaQHNhQEpapbJJaGI1Ci/CKGn8gk2CG8dmwTR4d+b0YvycmV3vzpyZ8/Y8/+f7uYuyeI89Zr885zzP/yRZlmUCAEBS2vYFAAD8QRQAADmiAADIEQUAQI4oAAByRAEAkCMKAIAcUQAA5GaKfuHNXzxQ53UAAGrSXXpPv3rpCb38X/809mtZKQCAYd2l9/TrV57Uwps/KPT1RAEAjHJBePvo9yUVm2hU+PYRACAc/SDs1NtH/11FgyCxUgAAc6YNgkQUAMCUMkGQiAIAmFE2CBJRAAATqgiCxINmAAhed+k9/frlnXr7WLkgSKwUACBo+bbTCoIgEQUACNY05xDGIQoAEKA6giARBQAITl1BkIgCAASlziBI7D4CgGBUte10FFYKABCAwQqhviBIrBQAwHtNrBAcVgoA4LEmgyARBQDwVtNBkIgCAHipjSBIRAEAvNNWECSiAABeaWqX0VrYfQQAnmhzheCwUgAAD7S9QnCIAgC0rO7RFZMgCgDQIp+CIBEFAGiNb0GQiAIAtMLHIEjsPgKAxlX5TuWqsVIAgAbl2049DIJEFACgMT6cQxiHKABAA0IIgkQUAKB2oQRB4kFzS4b/UiStXUU13O8l9N8HUI+QgiCxUmhBpvnZU/qrv3xMmy/7uUL4S7KWNOnq1j/7Z918w9NKkm7blwN4x5fRFZNgpdCw+blTeuDOh3Xdlhf0R3/4Yz2y+3EdPHa1Qvsv7TTp6vabntLdtz2pLEvUSbvas3e7sqzT9qUBXvD1HMI4rBQaND97Ug+eDUKSSJdfckR/c89XtPnSXyiovzRDQVi/7ow2rH9f937ha7rlhu+wYgAUbhAkotCY8+d+qwfv+qq2ng2C85FLDuuhe78czK2kNO1q21AQnA3r39e9f/E13fIZwoC4hRwEiSg04vy5k3pgx8Paes0PlwXBueziw3ronq94H4Y07er2G5/SXSuC4OQrBsKASIUeBIko1O78ud/qgR1fXTMIkpQkLgz+rhjSdEm333juCmGl4TCkhAERsRAEiSjUqh+EtVcIw/phOOJlGNJ0Sdtu/Lbuvm3nyCA4gzD8K2FAFAbbTsMOgkQUajNJEBwfw+CCcNdtO7V+3WLhf27D+vd1zxeeIAwwL7RzCOMQhRqMe4Ywik9hmDYIDmGAddaCIBGFyhV5hjCOD2Fwu4ymDYJDGGCVxSBIRKFS87PTrxBWWhaGS5sNQ77L6NavlwqC48LwOXYlwQirQZCIQkUyzc+d1IMVBcHJw9DgOYY06WpbgV1Gkxp++EwYELL8BTkGgyARhQr0Zxk9cOfD5xxMq8JgxVD/OQZ3Unmtcwhl9cPwBOcYEKx826mnL8ipAlEoaX72lB7YMRhdUYcmzjGsHF1RF0ZiIFRWziGMQxRKmJ/t3zKqMwiOm5VUx4qhqSA4jMRAaGIJgkQUpjY/d1IP3lXPLaNRLr+k2pEYa80yqhsjMRCKmIIgEYWpnD93Ug/u+Kq2XtNsEJx+GMrfSho3y6huPHyG72ILgkQUJlbFOYQqlD3HkKZL2nbTtxpfIaw0ePjMOQb4xdLoikkQhQlMM7qiLmXOMeQnlW9tNwiOC8PnGKIHT4T4xrSqEIWCfAqCM805hrKjK+ribiURBrQt1hWCQxQK8DEIziQjMXwNgsN0VbTN8knloojCGGWG2zWlSBj6D5X9DYIzPBKDMKBJBKGPKIwwP3fSi4fKRYwKg9tl1H+o7G8QnMGtJFYMaAZBGCAKq8ryg2khBMFZLQx1zTKq2+DhM9tVUS+CsBxROEd/llE/CO2cQyhjOAwfvfz1WmcZ1Y1ZSahbzLuM1pJkWVboT+LmLx6o+1o8cDYId4Vxy2iULJNOLlykufPeCTIIw94/s0G7nrlfe/ZuV5Z12r4cGBHjCuHwG0fGfs1MA9cRjMEKIewgSP0Vw4fOP9H2ZVTCPWNQJu3Zd4eyjAUuymGFsDaicNbgfQjh3TKKgRuiJ0l79rFiwPRiHF0xCaIgt+00/FtG1uVhSMStJEyFIIwX/Trcl1lGKIYDbpgWQSgm6ij4fFIZaxverkoYUARBKC7a20cEIWwuDImkPXvvUI9bSVhD/k5lw6/QrFKUKwWCYIMbicGtJKwl33ZKEAqLLgohzDJCccxKwlpiPIdQhaiiENIsIxTH2G2sRBCmF00UQpxlhOKGw8BIjLgRhHIiiMLwcDsOplnGO59BEMozHoX+LKMHdjysrVsIQgwYohcvRldUw/SW1Pm5U3rgzod1HUGISj4rSZx8jgXnEKpjdqUwP3tSDxKEaOW3km5gxWAdQaiWyZUC5xAgMSspBgSheuZWCpxDwLDBw2dWDNYQhHqYigLD7bCa4TBwjsEGglAfM1HglhFGYbqqHYNtpwShDiaiQBBQBLOSwsc5hPoFHwWeIWAShCFcBKEZQUeBZwiYBmEID0FoTrBRmJ9lhYDpDU9XZVeS3whCswI8p5Bpfu6UHryTIKCcwcnnTHv23sE5Bg/xgpzmBbZSODvL6E5mGaEay2cl9dq+HAzJt50ShEYFFgXpzs//A6MrUKl1M4u67OIjSomCNziH0J7govDsvu06dvyKti8DRvR6qfbs3a5vfvdL6vYCvJtqEEFoV2BRSHTw2NV6ZPfjeuOtjW1fDALngrDrmft1ZvEDbV8ORBB8EFgUJBeGR3c9rqNvbVTG3xtMoR+EOwiCRwiCHwKMgiQlOvjmVXpk92M6dpwwYDLdPAj3EQRPMLrCH4FGQRrcSnpMx45fQRhQSLeX6tm92wmCR3hjml8CjoI0/IyBMGCcQRC4ZeQLVgj+CTwKEmFAEV2eIXiHk8p+MhAFiTBgFBeE3dwy8gZB8JeRKEiEAavp3zIiCD4hCH4zFAWJMGBY72wQeKjsD4LgP2NRkPIw7CIMMRscTCMIvmCXURgMRkHqn2NwKwbOMcSGk8r+YZdROIxGQVp5jgFx6PVS7dlHEHzCCiEshqMgDT9jOMqsJPPyFcLTBMEXjK4Ij/EoSMMrBsJgF7eM/EMQwhRBFKTlYeDhszUcTPMPQQhXJFGQ2K5qU5dtp94hCGGLKAoSYbCFaaf+yd+pTBCCFVkUJM4x2MDoCv/k2055p3LQIoyCtPwcA2EIjZt2ShD8wUllOyKNgsStpDAx/to/BMGWiKMgEYawDGYZEQRfEAR7Io+CRBjC0OOhsncIgk1EQRJh8FuvlzDczjOMrrCLKOT6YXjsHx/VyYWL2r4YDPndmd/Tf/z4czqzuKHtS4E4h2AdURiSJj198g/2a+68d9q+FAw57wPv6a93/J02X/oL8UOoXQTBPqJwVpp2te2mp3T3bU9q/bozbV8OVvjIJYf10L1f1ubLfi5+GLWDIMSBKKgfhNtvfEp3EQSvXXbxYT10z1cIQwsIQjyij0KaLun2G1khhCBJXBhYMTSJIMQl6iik6ZK23fht3X3bToIQiH4YjhCGhvDGtPhEGwUXhLtu26n16xbbvhxMgDA0g3MIcYoyCgQhfIShXgQhXtFFwe0yIgjhIwz1IAhxiyoK+S6jW79OEIxYFoZLCUNZBAHRRCFNutrGLiOT8jBwjqGUwQtyCELMoohCmnR1+02cQ7BssGLgHMM08m2nvCAneuaj4ILACsE+zjFMh3MIGGY6CgQhPkkiXX4JK4aiCAJWMhsFZhnF7fJLGIkxDkHAakxGgVlGkFwYuJW0GoKAtZiLQpouadtN32KFAEmcY1gNoyswiqko5CeVbyUI6OMcw3K8MQ3jmIkCoyuwFs4x9LFCQBEmokAQME7sIzE4qYyigo9C/6EyQcB4sYaBIGASQUfB7TLqP1QmCBgvtjAQBEwq2CgwywjTiiUMBAHTCDIKzDJCWdbDwC4jTCu4KDC6AlWxGgZ2GaGMwKKQ6ZY//ReCgMq4MOz4/De0bib851KsEFBWYFGQlrrrlGVJ25cBI7JMOnjsau1+5j4tLq1v+3JKYXQFqhBYFBI9/8I27Xrmfr1/ZkPbF4PAuSA8svtxHT2+qe3LKYUgoCqBRUHKso727N2uXU8TBkxvOAjHjl/R9uWUQhBQpeCiIJ0Nw77trBgwlXODEO7tSIKAqs20fQHTcisGSbr3C1/ThvXvt3xFCIG5ILy8k1doolJBrhSc/FYSKwYUYC4IrxAEVC/oKEj9MDy7d7t2P3MfYcCaTAaBbaeoQfBRkKRe1tGevXcQBqyKIADFmYiCRBiwOoIATMZMFCTCgOUIAjA5U1GQBmHg4XPc7AWB0RVohrkoSC4M27WLFUOUbAaBcwhohskoSG67KiuG2GSZdPDNq/To7sd07PhGEQRgMmajIDESIzb5CmEXs4yAaZmOgsRIjFgsv2W0se3LKYUgoE3moyBx8tk6niEA1YkiCtJwGHj4bIm9IPDGNLQrmihIww+fCYMFNoPAtlO0K6ooSG5WEruSQkcQgHpEFwWpf47hWZ4xBIsgAPWJMgrSIAyMxAhL/xwCQQDqEm0UJEZihGb4HIKJILxMEOCfqKMgDd9KYsXgM3u3jJ7kBTnwUvRRkFwY2JXkK5NBYNspPEUUzrJ2K6nXS/Te785r+zJKGwSBWUZAE4jCECsnn3u9VHv23qG//fsn9cZb4Y58WB6ETW1fTikEAaEgCiuEPkTPBWHXM/frwKFP6NFdj+voWxuVBfZzaPkto01tX04pBAEhIQqr6A/RuyO4MHTzINynM4sfkJTo4JtX5bdeQgnDuc8QwsXoCoSGKKwhy9Kgpqt2e2m+i6ofBCcZugVzhfdhsHcOgTemISxEYYRQhugNgnD/iiA4ybL/8vY1DObOIbBCQICIwhiZ59tVu0PPEFYPguN3GOxtO+VgGsJEFApw5xh8G4nhgrD7nFtGa/EzDAQB8AdRKMidY/AlDP1bRpMEwfErDAQB8AtRmIAvB9x6Z4Nw7kPlovwIA0EA/EMUJtT22O3+OYTVdhlNKln2ULfpMNgLAruMYANRmEJbYRgEYdxD5aKSoe2fzZ1jsBcEdhnBDqIwpV7D21V7vcG5iWqC4Cw/x1C3/jmEq4a+X+hBYIUAW4hCCVlDzxjyFcLTVQfBGTxjOFrjrCS3Qnh0lxtdYSEIrBBgC1Eoqe4hetXfMlrLYMVQRxiGbxkdZZYR4C2iUIG6hugVP5hWleEwVPfw2d4sI4IAu4hCRfpD9KpbMXRLbzudVrXbVe09VCYIsI0oVKiqW0nnTjttWjVhMBeEl9llBPuIQsXKhmHy0RV1KXeOwVwQXtnJO5URBaJQg+zsOYZJR2K4aaftB8FJlo2xLhoGk0Fg2ykiQRRqMumspPHjr9sy2a0kggCEjSjUqGgYBrOMfAuCUywMBAEIH1Go2bgw9Fp/qFzU6DAQBMAGotCAtaarVjfcrimrh8FeEBhdgXgRhYasnJXU3Enlqp0bBntBYNsp4pVkWbE9JTd/8UDd1xKFJOnqls98R5ddfETf/O6XAgvCsEybL/u5dnz+G9r9zH2MrvBImnbU63XbvozSkiRV/8dT2J+HTw6/cWTs1xCFFiRJT2nSU7c30/allJRp3cyiFpfWt30hpVgKwuzcBdqy5XodeO1FLSycaPtyppZ2ZnTNxz+td0+f0qGDryj0z8UXRaIQ+k+lIGVZqm5m4c5dQhA8Mjt7gbZuvVnz8xdpbvZC7d//XJBhSNMZbbnmem3afG1/xZNJhw4RhqZY+MkETMVcEK7rByFJEs3ODf53SNK0oy1b+kFIklSdzjptufYGbdp0rUJ+XhUSooAoWXpj2sogSOqHYTasMPSDcEMeBKfTmemHYTNhaAJRQHQsnUNYLQhOSGFI007+g384CE6nM5MHgzDUiyggKrEEwQkhDPkKYdPqQXAIQzOIAqIRWxAcn8Ow1i2jtRCG+hEFRCHWIDg+hmHSIDh5GHj4XAuiAPMGL8iJMwiOT2GYNggOD5/rQxRgWr7t1MALcsoEwfEhDGWD4PRXDNcThooRBZhl+RxCGW2GoaogOJ3Oun4YuJVUGaIAkwjCaEmSaG7uwkbDkKYzlQbBycPAiqESRAHmmArCXPVBGNZUGNLOjLZce33lQXA6M4ShKkQBppgKwtAsozqC4NQdhtTd+x9zDqEsVgzVIAoww9ToippXCOd8v5qeMfRvGdUfBKcfBnYllUEUYIKlN6Y1tUIYVsfD53y4XUNBcDjgVg5RQPBMrRBqeKhcVJVhqHqX0aQIw/SIAoIW+0nlqlURhraD4BCG6RAFBIsg1KNMGHwJgkMYJtf+pwZMgSDUa5ow+BYEhzBMxp9PDiiIIDRjkjD4GgSHMBTn36cHjGBul5GnQXCKhMH3IDiEoRh/P0FgBXYZtWN5GD687P8b98Y03zBEbzz/P0VArBDaNgjDZ/MVQ9E3pvmm01mnLdcwRG8t4XySiJa50RWBBcHJh+htvVkXXnhJELeM1pLPSiIM55hp+wKAUQiCf+Y+eKE+/Sfb1OnMBBkEpzOzTluuvV5KpEMHX1Hof7+qQhTgLYLgr5mZ9W1fQiXcrCSJMDjhZh6mEQQ0hV1Jy7FSgHfydyrzCk00xIVBYsXASgFeybedEgQ0jBVDH1GANzipjLYRBqIATxAE+CL2MBAFtI4gwDd5GCI8x0AU0CqCAF91OjP5CI+YwkAU0BpGV8B3Md5KYksqWmHqHMJc8+9URnPcED0pju2qrBTQOFNBmCUIMYhpiB5RQKNMBWGOW0YxcbOSrN9KIgpojKkgsEKIUn9Wku0VA1FAI8wFgRVCtDqddf1dSUbDQBRQO96YBmssb1clCqgV5xBgldXtqkQBtSEIsM5iGIgCakEQEAtrYSAKqBxBQGwszUoiCqhU/oIcgoDIWHn4TBRQmXzbKS/IQaTcSIyQw0AUUAnOIQB9oR9wIwoojSAAy+VhCHDFQBRQiqkgMMsIFerM9MOwceM1bV/KRIgCpmYpCGna0ZYt1wcfhO7Sok6dfEtZFvbnYUeiNO20fRETIQqYiqXRFZLU63V14LUXdfrdU8H+QO12F/Xqqy/ohz/8Nx1940Cwvw8rut0lvfbaj3Tw4MttX8pEiAImZumNacMWFk5o//7ndPp0eGHodpf06qsv6NChV7S0dEYvvfSfhKFFLgi//OXPFNq/I0QBE7G2QlhpYeGE9v8krDD0g7Bv2VvBut1FwtCSbndJB177kQ7+8mdSgH/2RAGFWTqpPEpIYVgtCIP/jzA0bXiFEOqfOVFAIbEEwQkhDKOCMPgawtCU/BlCwEGQiAIKiC0Ijs9hKBKEwdcShrpZCYJEFDBGrEFwfAzDJEEY/DOEoS6WgiARBYxgdZfRpHwKwzRBGPyzhKFq1oIgEQWswfouo0n5EIZud0mvvjJdEAa/BmGoisUgSEQBq2CFsLrhMDQtXyEcmj4Ig1+LMJRlNQgSUcAKlkZX1MGF4d13Tzb2PfsnlcutEFb7NQnDdCwHQSIKGEIQimkyDN2l/uiKKoOQ/9qEYWIWziGMQxQgiSBMajgMdf1wcLOM6gjC8PcgDMXkQfifME8qF0UUQBCmVOfD5zwIFTxDKPK9CMNoy4Jg/N8RohC5wTuVCcI06ghDf5dRvSuEc78nYVhLyMPtpkEUIpZvOzXwTuU2VRmGfNtpAyuEc783YVhp+KGy5VtGw4hCpGI/qVy1KsJQ5bbTaRGGAeu7jNZCFCJEEOpRJgxlTipXjTDEGwSJKESHINRrmjD4FAQn5jDEHASJKESFIDRjkjD4GAQnxjDEHgSJKESD0RXNKhKGKmYZ1S2mMBCEPqIQAc4htGNUGLrdxdZ2GU0qhjAQhAGiYBxBaFc/DM8vG6LX5MG0qlgOw/A7la393qZBFAwjCH5YWPhNfyTGOyf7s4waPphWFYthiGGW0aRm2r4A1IMg+GVh4YT2739O8+f/vo6+8bpC/UxcGCTp8o98TEmStHxF5Swuvq8TvzlGEIawUjCIIPhpYeGEjr5xQKF/JpZWDBs2nKc/3vrnmp+/qO1L8QZRMIY3pqEJVsKQJIlmZy/Q1utuJgxnEQVDOIeAJhEGm4iCEQQBbSAM9hAFAwgC2kQYbCEKgSMI8AFhsIMoBGzwghyCgPYRBhuIQqDybae8IAceIQzhIwoB4hwCfEYYwkYUAkMQEAJLYZibuzCqMBCFgBAEhMRKGCRFFQaiEAiCgBARhvAQhQAwugIhsxSGGJ4xEAXP8cY0WGAlDDE8fCYKHmOFAEsIQxiIgqc4qQyLCIP/iIKHCAIsIwx+IwqeIQiIAWHwF1HwCEFATAiDn4iCJ9hlhBgRBv8QBQ+wywgxsxmGD7d9OVMjCi1jhQBYDMNng10xEIUWMboCGLAUhrm5C7V1a5i3kohCSwgCcC4rYZCkuQ+GOSuJKLSAIABr63YX9eqr+/TOwom2L6W02dkLtHHTJ9q+jIkQhYYRBGC0NO3o6qu36oPzH2r7UkrJskzHjx/W6wdebPtSJjLT9gXEJH+nMq/QBFaVph19/OOf1pVXfkpJEu5/s2ZZpuNvHdZPf/o9nTnzu7YvZyLh/qkHJt92ShCAVbkgbL7yU0rScH80uRVCiEGQiEIjOKkMjDYchNRCEP77+0EGQSIKtSMIwGg2g/B/bV/O1ML9BAJAEIDRbAXhSPBBkIhCbQgCMJq9IHwv+CBI7D6qBaMrgNFsBSH8W0bDwv00PMU5BGA0guC3cD8RDxEEYLQ07ehjBMFr3D6qCEEARjO1Qgj0YFoRRKECBAEYbdlJ5dCDEPDBtCKIQkkEARgtD8JHDYyuOH747C4jm0GQiEIpbDsFRiMI4Qn3U2oZQQBGWzbLiCAEI9xPqkUEARjN1EPliIIgEYWJEQRgNIIQtnA/sRYQBGA0W0E4EvS002nxoLkgXpADjGYrCPGtEJxwP7kG5dtOCQKwKntBiG+F4IT76TWEcwjAaDaDYGt0xSS4fTQCQQBGsxeEOG8ZDQv3U6wZQQBGIwg2sVJYBUEARuOksl1EYQW2nQLjbb7ykzaCYHja6bTC/URrwBvTgGL+9/gRnT79trIszH9PYph2Oi2icNZghcAtI2CchYUT2v+T53T69KngwsAto9GIgrhlBEwjxDAQhPGijwJBAKYXUhgIQjFRR4EgAOWFEAZOKhcXbRQIAlAdn8PASeXJRBkFdhkB1fMxDINpp98jCAVFFwV2GQH18SkMPEOYTlRRYIUA1G84DG1ZHgRWCJOIJgqMrgCa48Lw7rsnG//erBDKiSIKBAFoXhthIAjlmY8CQQDaMxyGup8xEIRqmI4CQQDa18TDZ4JQHbNRyN+pTBCA1tUZhnzaKUGohMko5NtOeacy4I06wsC00+qZiwInlQF/VRkGRlfUw1QUCALgvyrCwOiK+piJAkEAwlEmDIPRFQShDiaiQBCA8EwTBmYZ1S/4KDC6AgjXJGFgdEUzgo4C5xCA8BUJA88QmhNsFAgCYEc/DM+vOkSPIDQryCgQBMCehYXf9EdivDOYlbT8YBpBaEJwUSAIgF0LCye0f/9gVhIH05o30/YFTIIgAPa5ZwwbN31Crx94kSA0LJgosO0UiMfCwgm9/NIP2r6MKAVx+4ggAEAzvI8CQQCA5ngdBYIAAM3yNgoEAQCa5+WD5vwFObwPAQAa5d1KId92ShAAoHFeRYFzCADQLm+iQBAAoH1eRIEgAIAfWo8CQQAAf7S6+4htpwDgl9ZWCrwxDQD808pKgRUCAPip8ZUCQQAAfzUaBYIAAH5rLAoEAQD810gUCAIAhKH2KLDLCADCUevuI1YIABCW2lYKrBAAIDy1RIHRFQAQpsqjQBAAIFyVRoEgAEDYKosCQQCA8FWy+4h3KgOADaVXCvm2U4IAAMErFQXOIQCALVNHgSAAgD1TRYEgAIBNE0eBIACAXRNFgdEVAGBb4ShwDgEA7Ct8TuFXLz2hhTd/IIIAAHYlWZbxUx4AIKnhdzQDAPxGFAAAOaIAAMgRBQBAjigAAHJEAQCQIwoAgBxRAADkiAIAIPf/YcYUte/k0uIAAAAASUVORK5CYII=", 79 | "text/plain": [ 80 | "
" 81 | ] 82 | }, 83 | "metadata": {}, 84 | "output_type": "display_data" 85 | } 86 | ], 87 | "source": [ 88 | "# Scale the image to be bigger than the canvas\n", 89 | "new_size = int(1080 * 2.5) # Increase the size by 50%\n", 90 | "scaled_image_bigger = image.resize((new_size, new_size), Image.NEAREST)\n", 91 | "\n", 92 | "angle = 45\n", 93 | "# Rotate the scaled image\n", 94 | "rotated_image_bigger = scaled_image_bigger.rotate(angle)\n", 95 | "\n", 96 | "# Crop the rotated image to 1080x1080\n", 97 | "left = (rotated_image_bigger.width - 1080) / 2\n", 98 | "top = (rotated_image_bigger.height - 1080) / 2\n", 99 | "right = (rotated_image_bigger.width + 1080) / 2\n", 100 | "bottom = (rotated_image_bigger.height + 1080) / 2\n", 101 | "cropped_image = rotated_image_bigger.crop((left, top, right, bottom))\n", 102 | "\n", 103 | "# Convert the cropped image to a numpy array\n", 104 | "cropped_image_np = np.array(cropped_image)\n", 105 | "\n", 106 | "# Place the cropped image on the canvas\n", 107 | "canvas[:cropped_image_np.shape[0], :cropped_image_np.shape[1]] = cropped_image_np\n", 108 | "\n", 109 | "# Display the canvas with the cropped image\n", 110 | "plt.imshow(canvas)\n", 111 | "plt.axis('off')\n", 112 | "plt.show()" 113 | ] 114 | }, 115 | { 116 | "cell_type": "code", 117 | "execution_count": 6, 118 | "metadata": {}, 119 | "outputs": [ 120 | { 121 | "data": { 122 | "image/png": "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", 123 | "text/plain": [ 124 | "
" 125 | ] 126 | }, 127 | "metadata": {}, 128 | "output_type": "display_data" 129 | } 130 | ], 131 | "source": [ 132 | "# Draw the grid lines over the canvas with the cropped image\n", 133 | "for i in range(1, grid_size):\n", 134 | " # Horizontal lines\n", 135 | " canvas[i * cell_size, :] = 255\n", 136 | " # Vertical lines\n", 137 | " canvas[:, i * cell_size] = 255\n", 138 | "\n", 139 | "# Display the canvas with the grid lines\n", 140 | "plt.imshow(canvas)\n", 141 | "plt.axis('off')\n", 142 | "plt.show()" 143 | ] 144 | }, 145 | { 146 | "cell_type": "code", 147 | "execution_count": 7, 148 | "metadata": {}, 149 | "outputs": [ 150 | { 151 | "data": { 152 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYUAAAGFCAYAAAASI+9IAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAJmklEQVR4nO3ZT04dVxrG4a8swLYgxL2F7nHvIFmAx1lC1AMPnSwgK0h2kCV4BRm1bK8gE09a8p8NwOUimyrqnh4QXstKy2A35BT4ecY1eHUvnN89qqG11goAqupO7wEALIcoABCiAECIAgAhCgCEKAAQogBAiAIAsXXZBx8+enGdOwBujdOTg/rPv/9V83jYe8oHXr15feEzbgoAhCgAEKIAQIgCACEKAIQoABCiAECIAgAhCgCEKAAQogBAiAIAIQoAhCgAEKIAQIgCACEKAIQoABCiAECIAgAhCgCEKAAQogBAiAIAIQoAhCgAEKIAQIgCACEKAIQoABCiAECIAgAhCgCEKAAQogBAbPUecJsMtam93VUNQ+s9ZdFaG2p9vF/NbxKuQGubmqd1Vdv0nhLztFrUnk8hCldob3dVP//wfe3vHvSesmir4wf14y+/1tHxg95TuAXmaV0vnz8+O4iX4jxUN5AoXKFhaLW/e1Bff3XQe8riuU1xZdqm5mlV83jYe8mt4P4OQIgCACEKAIQoABCiAECIAgAhCgCEKAAQogBAiAIAIQoAhCgAEKIAQIgCACEKAIQoABCiAECIAgAhCgCEKAAQogBAiAIAIQoAhCgAEKIAQIgCACEKAIQoABCiAECIAgAhCgCEKAAQogBAiAIAsdV7wOcaalN7u6sahtZ7SuzvHixqz1INQ6v93YPeMz7Q2lDr4/1qfid9VGubmqd1Vdv0nhLztFrUnptuaK1d6hR7+OjFdW/5JF/tHtTPP3y/qMNlGFrt7a7qjjB81Ob8AG5D7ymxOn5QP/7yax0dP+g9ZdFOx1W9fP747CBeivNQlf+7i7x68/rCZ27uTeGPX5tff3XQewqf6M7Qan/vsPeMP3HLu4S2qXla1Twu7/vjargrAxCiAECIAgAhCgCEKAAQogBAiAIAIQoAhCgAEKIAQIgCACEKAIQoABCiAECIAgAhCgCEKAAQogBAiAIAIQoAhCgAEKIAQIgCACEKAIQoABCiAECIAgAhCgCEKAAQogBAiAIAIQoAhCgAEKIAQGz1HgD8b61tap7WVW3Te0rM02pRe7h6ogALNU/revn88dlBvBTnoeLWEgVYqrapeVrVPB72XsIXxDsFAEIUAAhRACBEAYAQBQBCFAAIUQAgRAGAEAUAQhQACFEAIEQBgBAFAEIUAAhRACBEAYAQBQBCFAAIUQAgRAGAEAUAQhQACFEAIEQBgBAFAEIUAAhRACBEAYAQBQBCFAAIUQAgRAGAEAUAQhQAiK3eAz5Xa0Otjh/0nvGBYWi1t7uqO0PrPWXRNm2o9fF+tTb0nhKr4/06PTmq05PlbJqnVVXb9J7BF2ZorV3qBHv46MV1b/kkQ21qb3dVw4IO4P3dg/r5h+9rf++w95RFW62/rh9/+XVRUT89Oarff/upTsd17ynvtU3N07qqlvM3zs326s3rC5+5uTeFulNHCzpUzi3p1+9Snd/yVuu/9Z4SpydDnY7rmkdB58vmnQIAIQoAhCgAEKIAQIgCACEKAIQoABCiAECIAgAhCgCEKAAQogBAiAIAIQoAhCgAEKIAQIgCACEKAIQoABCiAECIAgAhCgCEKAAQogBAiAIAIQoAhCgAEKIAQIgCACEKAIQoABCiAECIAgAhCgDEVu8Bt0lrQ62OH/SesXir4/06PTmq05Oh95SYp1VV2/Se8Sfb2/dqWM7HtEitVU3Tu94zbo2htdYu8+DDRy+ue8uNN9Sm9nZXNQyX+ki/WKcnR/X7bz/V6bjuPeW9tql5WlfVcr677e179c2339XOzv3eUxZtHN/Ws6dPhOESXr15feEzbgpXqNWdOnJTuNDpyVCn47rm8bD3lEUbhqqdnft1964oXMRt6up4pwBAiAIAIQoAhCgAEKIAQIgCACEKAIQoABCiAECIAgAhCgCEKAAQogBAiAIAIQoAhCgAEKIAQIgCACEKAIQoABCiAECIAgAhCgCEKAAQogBAiAIAIQoAhCgAEKIAQIgCACEKAIQoABCiAECIAgCx1XsA16u1Tc3Tuqptek+JeVotas+57e17NQy9V7y3s3N/UXuWahjOPqslaa1qmt71nvFZROGWm6d1vXz++OwgXorzUC3I9va9+ubb7xZ1uAzD2S4+7vy7a633kvfG8W09e/rkRoZBFG67tql5WtU8HvZesmjnvzbv3l1OFLicYRgWFfNzN/WW550CACEKAIQoABCiAECIAgAhCgCEKAAQogBAiAIAIQoAhCgAEKIAQIgCACEKAIQoABCiAECIAgAhCgCEKAAQogBAiAIAIQoAhCgAEKIAQIgCACEKAIQoABCiAECIAgAhCgCEKAAQogBAiAIAIQoAxFbvAbdJa5uap3VV2/SeEvO0WtSepWqtahzf9p6xeMNQtb19r4Zh6D2FayIKV2ie1vXy+eOzg3gpzkPFR03Tu3r29Ek56z5uZ+d+ffPtd7Wzc7/3FK6JKFyltql5WtU8HvZewmeYpne9J9wIrfVewHXyTgGAEAUAQhQACFEAIEQBgBAFAEIUAAhRACBEAYAQBQBCFAAIUQAgRAGAEAUAQhQACFEAIEQBgBAFAEIUAAhRACBEAYAQBQBCFAAIUQAgRAGAEAUAQhQACFEAIEQBgBAFAEIUAAhRACBEAYAQBQBiq/eAz9XapuZpXdU2vafEPK0WtQe+BK21mqZ31VrvJe+N49tF7fkUNzYK87Sul88fnx3ES3EeKuAvM03v6tnTJzWOb3tPidbOdt1ENzYKZwfwqubxsPcSoKPWzn6Zj+PNPISXxjsFAEIUAAhRACBEAYAQBQBCFAAIUQAgRAGAEAUAQhQACFEAIEQBgBAFAEIUAAhRACBEAYAQBQBCFAAIUQAgRAGAEAUAQhQACFEAIEQBgBAFAEIUAAhRACBEAYAQBQBCFAAIUQAgRAGAEAUAQhQAiK3LPnh6cnCNMz7dPK2q2qb3DPiitFY1jm97z/jAOL6t1nqvuD2G1i73cf79H/+87i2fpm1qntZV5a8B/krb2/dqGHqveK+1qml613vGjfDqzesLn7n0TWEeD/+vMcDt4AC+3bxTACBEAYAQBQBCFAAIUQAgRAGAEAUAQhQACFEAIEQBgBAFAEIUAAhRACBEAYAQBQBCFAAIUQAgRAGAEAUAQhQACFEAIEQBgBAFAEIUAAhRACBEAYAQBQBCFAAIUQAgRAGAEAUAQhQACFEAIEQBgBAFAGJorbXeIwBYBjcFAEIUAAhRACBEAYAQBQBCFAAIUQAgRAGAEAUA4r9P5h3UUhbnFQAAAABJRU5ErkJggg==", 153 | "text/plain": [ 154 | "
" 155 | ] 156 | }, 157 | "metadata": {}, 158 | "output_type": "display_data" 159 | } 160 | ], 161 | "source": [ 162 | "from collections import Counter\n", 163 | "\n", 164 | "# Create a new canvas for the resampled image\n", 165 | "resampled_canvas = np.zeros_like(canvas)\n", 166 | "\n", 167 | "# Iterate through each cell in the grid\n", 168 | "for row in range(grid_size):\n", 169 | " for col in range(grid_size):\n", 170 | " # Get the coordinates of the current cell\n", 171 | " start_row = row * cell_size\n", 172 | " end_row = start_row + cell_size\n", 173 | " start_col = col * cell_size\n", 174 | " end_col = start_col + cell_size\n", 175 | " \n", 176 | " # Extract the cell from the canvas\n", 177 | " cell = canvas[start_row:end_row, start_col:end_col]\n", 178 | " \n", 179 | " # Find the most frequent color in the cell\n", 180 | " cell_flat = cell.reshape(-1, cell.shape[-1])\n", 181 | " most_common_color = Counter(map(tuple, cell_flat)).most_common(1)[0][0]\n", 182 | " \n", 183 | " # Fill the resampled canvas with the most common color\n", 184 | " resampled_canvas[start_row:end_row, start_col:end_col] = most_common_color\n", 185 | "\n", 186 | "# Display the resampled canvas\n", 187 | "plt.imshow(resampled_canvas)\n", 188 | "plt.axis('off')\n", 189 | "plt.show()" 190 | ] 191 | } 192 | ], 193 | "metadata": { 194 | "kernelspec": { 195 | "display_name": "home", 196 | "language": "python", 197 | "name": "python3" 198 | }, 199 | "language_info": { 200 | "codemirror_mode": { 201 | "name": "ipython", 202 | "version": 3 203 | }, 204 | "file_extension": ".py", 205 | "mimetype": "text/x-python", 206 | "name": "python", 207 | "nbconvert_exporter": "python", 208 | "pygments_lexer": "ipython3", 209 | "version": "3.10.13" 210 | } 211 | }, 212 | "nbformat": 4, 213 | "nbformat_minor": 2 214 | } 215 | --------------------------------------------------------------------------------