From 3f943a5646ad1287d7d0d6eb2881d2a0a2fbe952 Mon Sep 17 00:00:00 2001 From: Ivan Date: Tue, 5 Mar 2024 22:34:50 +0800 Subject: [PATCH 1/5] Updated Sidebar.tsx Show the history of talking and thinking and add a button to close the window. --- web/src/components/Sidebar.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/web/src/components/Sidebar.tsx b/web/src/components/Sidebar.tsx index d50a50b..caa8723 100644 --- a/web/src/components/Sidebar.tsx +++ b/web/src/components/Sidebar.tsx @@ -138,6 +138,9 @@ const Sidebar: React.FC = ( Show Thoughts + } <> {renderTimeline()} From 90dc2d4fe4316aca6d8d29ac7a7eb737e8e7ed73 Mon Sep 17 00:00:00 2001 From: Ivan Date: Tue, 5 Mar 2024 23:06:32 +0800 Subject: [PATCH 2/5] added mouse pointer https://trello.com/c/ZhNY6kKG/301-hovering-over-someone-should-show-a-mouse-pointer --- web/src/components/RenderLevel.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/web/src/components/RenderLevel.tsx b/web/src/components/RenderLevel.tsx index ae5bf0a..c4cb1d5 100644 --- a/web/src/components/RenderLevel.tsx +++ b/web/src/components/RenderLevel.tsx @@ -92,6 +92,7 @@ const RenderLevel: React.FC<{ simId: string }> = ({ simId }) => { position: 'absolute', top: x, left: y, + cursor: 'pointer', }; return ( From 5d18b3f227e691b158c6690e8734b6a8e2932a24 Mon Sep 17 00:00:00 2001 From: chiefeu Date: Sat, 9 Mar 2024 04:00:42 +0800 Subject: [PATCH 3/5] fix pylint errors 1 --- utils/convert_to_2d.py | 22670 ++++++++++++++++++++++++++++++++- utils/db_insert.py | 56 +- utils/gpu_server.py | 27 +- utils/load_jsonl_to_redis.py | 33 +- utils/names.py | 180 +- utils/utils.py | 339 +- 6 files changed, 22939 insertions(+), 366 deletions(-) diff --git a/utils/convert_to_2d.py b/utils/convert_to_2d.py index 87d2c43..209c82f 100644 --- a/utils/convert_to_2d.py +++ b/utils/convert_to_2d.py @@ -1,173 +1,22527 @@ -import numpy as np +""" +This module converts the tilemap raw data into a 2d array. +""" # CHANGE THESE # data -# width -# height +# WIDTH +# HEIGHT # For data, get the value of the collisions layer in the tilemap json file. Replace data here. -data = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, - 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, - 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, - 84, 84, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, - 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, - 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, - 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 84, 84, 84, 84, 0, 0, 0, 84, 84, 0, 84, 84, 84, 84, 0, 0, 0, 84, 84, 0, 84, 84, 84, 84, 0, 0, 0, 84, 84, 0, 84, 84, 84, 84, 0, 0, 0, 84, 84, 0, 84, 84, 84, 84, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 84, 84, 84, 84, 0, 0, 0, 84, 84, 0, 84, 84, 84, 84, 0, 0, 0, 84, 84, 0, 84, 84, 84, 84, 0, 0, 0, 84, 84, 0, 84, 84, 84, 84, 0, 0, 0, 84, 84, 0, 84, 84, 84, 84, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 84, 0, 84, 84, 84, 84, 84, 0, 0, 0, 84, 0, 84, 84, 84, 84, 84, 0, 0, 0, 84, 0, 84, 84, 84, 84, 84, 0, 0, 0, 84, 0, 84, 84, 84, 84, 84, 0, 0, 0, 84, 0, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 84, 0, 84, 84, 84, 84, 84, 0, 0, 0, 84, 0, 84, 84, 84, 84, 84, 0, 0, 0, 84, 0, 84, 84, 84, 84, 84, 0, 0, 0, 84, 0, 84, 84, 84, 84, 84, 0, 0, 0, 84, 0, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 84, 84, 84, 84, 0, 0, 0, 84, 84, 0, 84, 84, 84, 84, 0, 0, 0, 84, 84, 0, 84, 84, 84, 84, 0, 0, 0, 84, 84, 0, 84, 84, 84, 84, 0, 0, 0, 84, 84, 0, 84, 84, 84, 84, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 84, 84, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 0, 0, 0, 84, 84, 84, 84, 84, 84, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 84, 0, 84, 84, 84, 84, 84, 0, 0, 0, 84, 0, 84, 84, 84, 84, 84, 0, 0, 0, 84, 0, 84, 84, 84, 84, 84, 0, 0, 0, 84, 0, 84, 84, 84, 84, 84, 0, 0, 0, 84, 0, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 84, 84, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, - 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 84, 84, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 84, 84, 0, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, - 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 84, 84, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 84, 84, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 84, 84, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 84, 84, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 84, 84, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 84, 84, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 84, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, - 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, - 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, - 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, - 0, 84, 84, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 84, 84, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, - 0, 84, 84, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, - 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 84, 84, 84, 84, 84, 0, 0, 0, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 84, 84, 84, 0, 84, 0, 0, 0, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 84, 84, 84, 84, 84, 0, 0, 0, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 84, 84, 0, 84, 84, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 84, 84, 0, 84, 84, 0, 84, 84, 0, 84, 84, 0, 84, 0, 0, 0, 84, 84, 0, 84, 84, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 84, 84, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 84, 84, 0, 84, 84, 0, 84, 84, 0, 84, 84, 0, 84, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 84, 84, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 0, 84, 84, 0, 84, 84, 0, 84, 84, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 84, 84, 0, 84, 84, 0, 84, 84, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 84, 84, 0, 84, 84, 0, 84, 84, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 84, 84, 84, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 84, 84, 0, 84, 84, 0, 84, 84, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 84, 84, 84, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 84, 84, 84, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 84, 84, 84, 84, 84, 0, 0, 0, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 84, 84, 84, 84, 84, 0, 0, 0, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 84, 84, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 84, 84, 84, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 84, 84, 0, 84, 84, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 84, 0, 84, 84, 0, 84, 84, 0, 0, 84, 84, 0, 0, 84, 84, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 84, 0, 84, 84, 0, 0, 84, 84, 0, 84, 84, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 84, 84, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 84, 84, 0, 84, 84, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 84, 84, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 84, 84, 0, 84, 84, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 0, 0, 0, 84, 84, 0, 0, 84, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +data = [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 84, + 84, + 0, + 84, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 84, + 84, + 0, + 0, + 84, + 84, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +] -width = 150 -height = 150 +WIDTH = 150 +HEIGHT = 150 # DO NOT CHANGE ANYTHING FROM THIS POINT ON new_data = [] -for i in range(height): +for i in range(HEIGHT): cur_list = [] - for j in range(width): - index = (i * width) + j + for j in range(WIDTH): + index = (i * WIDTH) + j val = data[index] if val == 0: cur_list.append(0) diff --git a/utils/db_insert.py b/utils/db_insert.py index c3e9e5b..72a966e 100644 --- a/utils/db_insert.py +++ b/utils/db_insert.py @@ -1,8 +1,14 @@ +""" +This module handles the processing and inserting +of data to the database. +""" + import os +import sys import json import jsonlines -import sys import psycopg2 + from dotenv import load_dotenv from sshtunnel import SSHTunnelForwarder @@ -24,42 +30,60 @@ "ssh_host": ssh_host, "ssh_port": int(os.environ.get("SSH_PORT", 22)), "ssh_user": os.environ.get("SSH_USER"), - "ssh_private_key": os.environ.get("SSH_PRIVATE_KEY") + "ssh_private_key": os.environ.get("SSH_PRIVATE_KEY"), } -def process_and_insert_data(cursor, jsonl_file_path,rows_to_process): - with jsonlines.open(jsonl_file_path, "r") as jsonl_file: + +def process_and_insert_data(conn_cursor, file_path, rows_process): + """ + This module processes the data then inserts the data to database. + """ + + with jsonlines.open(file_path, "r") as jsonl_file: for i, row in enumerate(jsonl_file): - if rows_to_process is None or i < rows_to_process: + if rows_to_process is None or i < rows_process: obj = json.loads(row) step = obj.get("step") substep = obj.get("substep") step_type = obj.get("step_type") sim_id = obj.get("sim_id") - data = {k: v for k, v in obj.items() if k not in ["step", "substep", "step_type","sim_id","embedding"]} + data = { + k: v + for k, v in obj.items() + if k not in ["step", "substep", "step_type", "sim_id", "embedding"] + } try: - cursor.execute( - "INSERT INTO timelines (sim_id,step, substep, step_type, data) VALUES (%s,%s, %s, %s, %s)", - (sim_id,step, substep, step_type, json.dumps(data)), + conn_cursor.execute( + "INSERT INTO timelines (sim_id,step, substep, step_type, data) " + "VALUES (%s,%s, %s, %s, %s)", + (sim_id, step, substep, step_type, json.dumps(data)), ) conn.commit() if i % 500 == 0: print(i) - except Exception as e: + except Exception as e: # pylint: disable=broad-except conn.rollback() print(f"Error: {e}") -jsonl_file_path = sys.argv[1] # Assumes the first command-line argument is the JSONL file path -rows_to_process = int(sys.argv[2]) if len(sys.argv) > 2 else None # Assumes the second argument is the number of rows to process + +jsonl_file_path = sys.argv[ + 1 +] # Assumes the first command-line argument is the JSONL file path +rows_to_process = ( + int(sys.argv[2]) if len(sys.argv) > 2 else None +) # Assumes the second argument is the number of rows to process if ssh_host: with SSHTunnelForwarder( (ssh_settings["ssh_host"], ssh_settings["ssh_port"]), ssh_username=ssh_settings["ssh_user"], ssh_pkey=ssh_settings["ssh_private_key"], - remote_bind_address=(db_settings["database_host"], db_settings["database_port"]), + remote_bind_address=( + db_settings["database_host"], + db_settings["database_port"], + ), ) as tunnel: # Establish database connection conn = psycopg2.connect( @@ -70,7 +94,7 @@ def process_and_insert_data(cursor, jsonl_file_path,rows_to_process): database=db_settings["database_name"], ) cursor = conn.cursor() - process_and_insert_data(cursor, jsonl_file_path,rows_to_process) + process_and_insert_data(cursor, jsonl_file_path, rows_to_process) else: conn = psycopg2.connect( user=db_settings["database_username"], @@ -81,10 +105,8 @@ def process_and_insert_data(cursor, jsonl_file_path,rows_to_process): ) cursor = conn.cursor() - process_and_insert_data(cursor, jsonl_file_path,rows_to_process) - + process_and_insert_data(cursor, jsonl_file_path, rows_to_process) cursor.close() conn.close() - diff --git a/utils/gpu_server.py b/utils/gpu_server.py index 700fa95..04154a9 100644 --- a/utils/gpu_server.py +++ b/utils/gpu_server.py @@ -3,11 +3,12 @@ # List of backend servers to balance requests backend_servers = [ - ('localhost', 8001), - ('localhost', 8002), - ('localhost', 8003), + ("localhost", 8001), + ("localhost", 8002), + ("localhost", 8003), ] + class RoundRobinProxyHandler(SimpleHTTPRequestHandler): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -19,11 +20,13 @@ def get_next_backend(self): def do_GET(self): backend_host, backend_port = self.get_next_backend() - self.log_message("Proxying request to backend server: %s:%s" % (backend_host, backend_port)) + self.log_message( + "Proxying request to backend server: %s:%s" % (backend_host, backend_port) + ) - self.headers['Host'] = '%s:%s' % (backend_host, backend_port) + self.headers["Host"] = "%s:%s" % (backend_host, backend_port) self.send_response(200) - self.send_header('Content-type', 'text/html') + self.send_header("Content-type", "text/html") self.end_headers() # Forward the request to the selected backend server @@ -31,7 +34,7 @@ def do_GET(self): def proxy_request(self, host, port): with self.send_to_backend(host, port) as backend: - data = self.rfile.read(int(self.headers.get('Content-Length', 0))) + data = self.rfile.read(int(self.headers.get("Content-Length", 0))) backend.sendall(data) response = self.get_response_from_backend(backend) @@ -51,12 +54,12 @@ def get_response_from_backend(self, backend): response += data return response -if __name__ == '__main__': + +if __name__ == "__main__": try: - server_address = ('localhost', 8888) + server_address = ("localhost", 8888) httpd = HTTPServer(server_address, RoundRobinProxyHandler) - print('Round-robin proxy server started on {}:{}'.format(*server_address)) + print("Round-robin proxy server started on {}:{}".format(*server_address)) httpd.serve_forever() except KeyboardInterrupt: - print('Proxy server stopped.') - + print("Proxy server stopped.") diff --git a/utils/load_jsonl_to_redis.py b/utils/load_jsonl_to_redis.py index e1c20f7..8463bcf 100644 --- a/utils/load_jsonl_to_redis.py +++ b/utils/load_jsonl_to_redis.py @@ -1,31 +1,46 @@ +""" +This module handles loading the jsonl data to the redis server. +""" + +import os +import sys import json import redis -import sys -import os import jsonlines + def inject_jsonl_to_redis_queue(file_path, queue_name, max_steps=None): + """ + This function injects the jsonl data into a redis queue. + """ + # Connect to Redis - redis_url = os.getenv('REDIS_URL', 'redis://localhost:6379/0') + redis_url = os.getenv("REDIS_URL", "redis://localhost:6379/0") redis_client = redis.StrictRedis.from_url(redis_url, decode_responses=True) # Read JSONL file - with jsonlines.open(file_path, mode='r') as reader: + with jsonlines.open(file_path, mode="r") as reader: for step, line in enumerate(reader, start=1): data = json.loads(line) redis_client.rpush(queue_name, json.dumps(data)) if max_steps is not None and step > max_steps: break - print(f"Data from {file_path} injected into Redis queue {queue_name} ({step} lines)") + print( + f"Data from {file_path} injected into Redis queue {queue_name} ({step} lines)" + ) + if __name__ == "__main__": if len(sys.argv) < 3 or len(sys.argv) > 4: - print("Usage: python script.py [max_steps]") + print( + "Usage: python script.py [max_steps]" + ) sys.exit(1) jsonl_file_path = sys.argv[1] redis_queue_name = sys.argv[2] - max_steps = int(sys.argv[3]) if len(sys.argv) == 4 else None if len(sys.argv) == 3 else None - - inject_jsonl_to_redis_queue(jsonl_file_path, redis_queue_name, max_steps) + maximum_steps = ( + int(sys.argv[3]) if len(sys.argv) == 4 else None if len(sys.argv) == 3 else None + ) + inject_jsonl_to_redis_queue(jsonl_file_path, redis_queue_name, maximum_steps) diff --git a/utils/names.py b/utils/names.py index f9c136f..04df781 100644 --- a/utils/names.py +++ b/utils/names.py @@ -1,19 +1,163 @@ +""" +This module defines the names of the agents. +""" + FIRST_NAMES = [ - "Alice", "Bob", "Charlie", "David", "Emma", "Frank", "Grace", "Henry", "Isabel", "Jack", - "Karen", "Leo", "Mia", "Noah", "Olivia", "Paul", "Quinn", "Rachel", "Samuel", "Sophia", - "Thomas", "Ursula", "Victor", "Wendy", "Xander", "Yvonne", "Zachary", "Ava", "Benjamin", - "Catherine", "Daniel", "Eva", "Freddie", "Giselle", "Harry", "Ivy", "Jacob", "Katherine", - "Liam", "Megan", "Nathan", "Oscar", "Penelope", "Quincy", "Ruby", "Sebastian", "Tessa", - "Ulysses", "Violet", "William", "Xena", "Yasmine", "Zane", "Abigail", "Brandon", "Chloe", - "Dylan", "Emily", "Fiona", "George", "Hannah", "Isaac", "Julia", "Kevin", "Lilian", "Mason", - "Nora", "Owen", "Paige", "Quinn", "Rebecca", "Simon", "Taylor", "Uma", "Vincent", "Willow", - "Xavier", "Yara", "Zara", "Aaron", "Bella", "Caleb", "Daisy", "Elijah", "Felicity", "Gavin", - "Hazel", "Ian", "Jasmine", "Kyle", "Lucy", "Molly", "Nolan", "Oliver", "Piper", "Quentin", - "Riley", "Sofia", "Tristan", "Ulyana", "Vivian", "Wyatt", "Ximena", "Yvette", "Zander", - "Amelia", "Brody", "Charlotte", "Declan", "Elena", "Finn", "Gabriella", "Hayden", "Isla", - "Jaxon", "Kylie", "Landon", "Madison", "Natalie", "Oscar", "Peyton", "Quinn", "Rylan", - "Samantha", "Trinity", "Uriel", "Valentina", "Wesley", "Xander", "Yara", "Zoe", "Aiden", - "Brianna", "Connor", "Diana", "Eva", "Felix", "Gianna", "Hudson", "Ivy", "Jake", "Kai", - "Lila", "Miles", "Nina", "Olivia", "Parker", "Quincy", "Rose", "Seth", "Talia", "Uma", - "Vincent", "Willow", "Xavier", "Yasmine", "Zane" - ] \ No newline at end of file + "Alice", + "Bob", + "Charlie", + "David", + "Emma", + "Frank", + "Grace", + "Henry", + "Isabel", + "Jack", + "Karen", + "Leo", + "Mia", + "Noah", + "Olivia", + "Paul", + "Quinn", + "Rachel", + "Samuel", + "Sophia", + "Thomas", + "Ursula", + "Victor", + "Wendy", + "Xander", + "Yvonne", + "Zachary", + "Ava", + "Benjamin", + "Catherine", + "Daniel", + "Eva", + "Freddie", + "Giselle", + "Harry", + "Ivy", + "Jacob", + "Katherine", + "Liam", + "Megan", + "Nathan", + "Oscar", + "Penelope", + "Quincy", + "Ruby", + "Sebastian", + "Tessa", + "Ulysses", + "Violet", + "William", + "Xena", + "Yasmine", + "Zane", + "Abigail", + "Brandon", + "Chloe", + "Dylan", + "Emily", + "Fiona", + "George", + "Hannah", + "Isaac", + "Julia", + "Kevin", + "Lilian", + "Mason", + "Nora", + "Owen", + "Paige", + "Quinn", + "Rebecca", + "Simon", + "Taylor", + "Uma", + "Vincent", + "Willow", + "Xavier", + "Yara", + "Zara", + "Aaron", + "Bella", + "Caleb", + "Daisy", + "Elijah", + "Felicity", + "Gavin", + "Hazel", + "Ian", + "Jasmine", + "Kyle", + "Lucy", + "Molly", + "Nolan", + "Oliver", + "Piper", + "Quentin", + "Riley", + "Sofia", + "Tristan", + "Ulyana", + "Vivian", + "Wyatt", + "Ximena", + "Yvette", + "Zander", + "Amelia", + "Brody", + "Charlotte", + "Declan", + "Elena", + "Finn", + "Gabriella", + "Hayden", + "Isla", + "Jaxon", + "Kylie", + "Landon", + "Madison", + "Natalie", + "Oscar", + "Peyton", + "Quinn", + "Rylan", + "Samantha", + "Trinity", + "Uriel", + "Valentina", + "Wesley", + "Xander", + "Yara", + "Zoe", + "Aiden", + "Brianna", + "Connor", + "Diana", + "Eva", + "Felix", + "Gianna", + "Hudson", + "Ivy", + "Jake", + "Kai", + "Lila", + "Miles", + "Nina", + "Olivia", + "Parker", + "Quincy", + "Rose", + "Seth", + "Talia", + "Uma", + "Vincent", + "Willow", + "Xavier", + "Yasmine", + "Zane", +] diff --git a/utils/utils.py b/utils/utils.py index 1ce2351..6078951 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -1,56 +1,81 @@ -from configs.configs import * -#TODO remove this -import requests +""" +This module defines helper functions used throughout the system, +and defines LLM functions as well. +""" + +# TODO remove this import time import os -import redis import difflib import random -from datetime import datetime import json -from urllib.parse import urlparse -import uuid -from jinja2 import Template -from sqlalchemy import create_engine, Column, Float, DateTime, Integer, String, PickleType, ForeignKey, JSON -from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.orm import sessionmaker, relationship, column_property +from datetime import datetime +import nltk +import redis import requests -import nltk -nltk.download('brown') from nltk.corpus import brown +from jinja2 import Template +from sqlalchemy import ( + create_engine, + # Column, + # Float, + # DateTime, + # Integer, + # String, + # PickleType, + # ForeignKey, + # JSON, +) +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker +from configs.configs import * + +nltk.download("brown") + +# Modify accordingly for requests.post() calls +TIMEOUT = 60 + try: from vllm import LLM, SamplingParams except ImportError: print("vllm Module not found. Skipping...") -''' +""" Print Debug Function -''' -def pd(msg,tag=None): +""" + + +def pd(msg, tag=None): if DEBUG == "1": if (tag and DEBUG_TAGS and tag in DEBUG_TAGS) or tag is None: print(f"{msg}") - url = "https://discord.com/api/webhooks/1179589082540675113/o8NLAfbISn82hZ9SmGyJ3GAJavIc7OIDS8Qbjl8OoO-jWOBSVLuQ6kgv-_UDju1yWf8M" - data = {'content': msg} - headers = {'Content-Type': 'application/json'} - #try: - #response = requests.post(url, json=data, headers=headers) + # url = "https://discord.com/api/webhooks/1179589082540675113/o8NLAfbISn82hZ9SmGyJ3GAJavIc7OIDS8Qbjl8OoO-jWOBSVLuQ6kgv-_UDju1yWf8M" + # data = {"content": msg} + # headers = {"Content-Type": "application/json"} + # try: + # response = requests.post(url, json=data, headers=headers) + def unix_to_strftime(unix_time): return datetime.fromtimestamp(unix_time).strftime("%Y-%m-%d %H:%M:%S") + def random_common_word(): - #TODO store the array in memory - common_words = [word.lower() for word in brown.words() if len(word) > 2 and word.isalpha()] + # TODO store the array in memory + common_words = [ + word.lower() for word in brown.words() if len(word) > 2 and word.isalpha() + ] random_common_word = random.choice(common_words) return random_common_word -''' + + +""" Llm class wrapper Required to have a running ollama server on machine -''' +""" SUPPORTED_GPT_MODELS = [ "gpt-4", @@ -59,21 +84,17 @@ def random_common_word(): "gpt-4-32k", "gpt-3.5-turbo", "gpt-3.5-turbo-16k", - "gpt-3.5-turbo-1106" -] -VLLM_MODELS = [ - "mistralai/Mistral-7B-Instruct-v0.1" -] -OLLAMA_MODELS = [ - "llama2", - "mistral", - "orca-mini" + "gpt-3.5-turbo-1106", ] +VLLM_MODELS = ["mistralai/Mistral-7B-Instruct-v0.1"] +OLLAMA_MODELS = ["llama2", "mistral", "orca-mini"] + + class Llm: def __init__(self, model=MODEL, url=LLAMA_URL, key=OPENAI_KEY): self.model = model self.urls = url.split(",") - #self.url = url + # self.url = url self.openai_api_key = key self.call_counter = 0 self.call_times = [] @@ -81,16 +102,16 @@ def __init__(self, model=MODEL, url=LLAMA_URL, key=OPENAI_KEY): self.sampling_params = None # Pre-warm Llm - #if self.model != "off": + # if self.model != "off": # self.generate("41+1=?") def generate(self, prompt, fallback="Llm Error"): # Truncate more than 1400 words - #lines = prompt.splitlines() - #truncated_lines = [] + # lines = prompt.splitlines() + # truncated_lines = [] - #total_words = 0 - #for line in lines: + # total_words = 0 + # for line in lines: # words = line.split() # if total_words + len(words) <= 1400: # truncated_lines.append(line) @@ -102,76 +123,79 @@ def generate(self, prompt, fallback="Llm Error"): # truncated_lines.append(truncated_line) # break - #prompt = '\n'.join(truncated_lines) + # prompt = '\n'.join(truncated_lines) if self.model == "off": return fallback start_time = time.time() if self.model in SUPPORTED_GPT_MODELS: - data = { - "model": self.model, - "messages": [{"role": "user", "content": prompt}]} + data = { + "model": self.model, + "messages": [{"role": "user", "content": prompt}], + } - headers = { - "Authorization": f"Bearer {self.openai_api_key}", - "Content-Type": "application/json" - } + headers = { + "Authorization": f"Bearer {self.openai_api_key}", + "Content-Type": "application/json", + } - response = requests.post(f"https://api.openai.com/v1/chat/completions", json=data, headers=headers) + response = requests.post( + f"https://api.openai.com/v1/chat/completions", + json=data, + headers=headers, + timeout=TIMEOUT + ) - if response.status_code == 200: - msg = response.json()['choices'][0]['message']['content'] - self.call_counter += 1 - else: - pd(response.text) - msg = fallback + if response.status_code == 200: + msg = response.json()["choices"][0]["message"]["content"] + self.call_counter += 1 + else: + pd(response.text) + msg = fallback elif self.model in VLLM_MODELS: - if self.vllm is None: - self.vllm = LLM(model=self.model) - self.sampling_params = SamplingParams(max_tokens=10000) - try: - outputs = self.vllm.generate(prompt, self.sampling_params) - msg = "" - for output in outputs: - cur_out = output.outputs - for o in cur_out: - msg = msg + o.text - - except Exception as e: - print(e) - msg = fallback + if self.vllm is None: + self.vllm = LLM(model=self.model) + self.sampling_params = SamplingParams(max_tokens=10000) + try: + outputs = self.vllm.generate(prompt, self.sampling_params) + msg = "" + for output in outputs: + cur_out = output.outputs + for o in cur_out: + msg = msg + o.text + + except Exception as e: # pylint: disable=broad-except + print(e) + msg = fallback else: - data = { - "model": self.model, - "prompt": prompt, - "stream": False - } - #"temperature": 0.4, - #print(data) - current_url = self.urls[self.call_counter % len(self.urls)] - try: - if self.model == "powerinf": - data = { - "prompt": prompt, - "n_predict": 128 - } - response = requests.post(f"{POWERINF_URL}/completion", json=data, timeout=LLAMA_TIMEOUT) - if response.status_code == 200: - msg = response.json()['content'] - self.call_counter += 1 - else: - msg = fallback - else: - response = requests.post(f"{current_url}/generate", json=data, timeout=LLAMA_TIMEOUT) - - if response.status_code == 200: - msg = response.json()['response'] - self.call_counter += 1 - else: - msg = fallback + ": " + response.text - - except Exception as e: - msg = fallback + data = {"model": self.model, "prompt": prompt, "stream": False} + # "temperature": 0.4, + # print(data) + current_url = self.urls[self.call_counter % len(self.urls)] + try: + if self.model == "powerinf": + data = {"prompt": prompt, "n_predict": 128} + response = requests.post( + f"{POWERINF_URL}/completion", json=data, timeout=LLAMA_TIMEOUT + ) + if response.status_code == 200: + msg = response.json()["content"] + self.call_counter += 1 + else: + msg = fallback + else: + response = requests.post( + f"{current_url}/generate", json=data, timeout=LLAMA_TIMEOUT + ) + + if response.status_code == 200: + msg = response.json()["response"] + self.call_counter += 1 + else: + msg = fallback + ": " + response.text + + except Exception: # pylint: disable=broad-except + msg = fallback end_time = time.time() self.log_calls(prompt, msg, end_time - start_time) @@ -189,43 +213,43 @@ def embeddings(self, prompt, fallback=[0.5, 0.5, 0.5]): start_time = time.time() if self.model in SUPPORTED_GPT_MODELS: - data = { - "input": prompt, - "model": "text-embedding-ada-002", - "encoding_format": "float", - } - - headers = { - "Authorization": f"Bearer {self.openai_api_key}", - "Content-Type": "application/json" - } - - response = requests.post(f"https://api.openai.com/v1/embeddings", json=data, headers=headers) - - if response.status_code == 200: - msg = response.json()['data'][0]['embedding'] - self.call_counter += 1 - else: - msg = fallback + data = { + "input": prompt, + "model": "text-embedding-ada-002", + "encoding_format": "float", + } + + headers = { + "Authorization": f"Bearer {self.openai_api_key}", + "Content-Type": "application/json", + } + + response = requests.post( + f"https://api.openai.com/v1/embeddings", json=data, headers=headers, timeout=TIMEOUT + ) + + if response.status_code == 200: + msg = response.json()["data"][0]["embedding"] + self.call_counter += 1 + else: + msg = fallback else: - data = { - "model": self.model, - "prompt": prompt, - } - current_url = self.urls[self.call_counter % len(self.urls)] - if self.model == "powerinf": data = { - "content": prompt + "model": self.model, + "prompt": prompt, } - response = requests.post(f"{POWERINF_URL}/embedding", json=data) - else: - response = requests.post(f"{current_url}/embeddings", json=data) + current_url = self.urls[self.call_counter % len(self.urls)] + if self.model == "powerinf": + data = {"content": prompt} + response = requests.post(f"{POWERINF_URL}/embedding", json=data, timeout=TIMEOUT) + else: + response = requests.post(f"{current_url}/embeddings", json=data, timeout=TIMEOUT) - if response.status_code == 200: - msg = response.json()['embedding'] - self.call_counter += 1 - else: - msg = fallback + if response.status_code == 200: + msg = response.json()["embedding"] + self.call_counter += 1 + else: + msg = fallback end_time = time.time() pd(f"embed conversion for: {prompt}") @@ -235,7 +259,7 @@ def embeddings(self, prompt, fallback=[0.5, 0.5, 0.5]): return msg def log_calls(self, prompt, output, time): - with open('storage/llm_logs.tsv', 'a') as file: + with open("storage/llm_logs.tsv", "a", encoding="utf-8") as file: file.write(f"{prompt}\t{output}\t{time}\n") def prompt(self, prompt_name, variables=None, fallback="Llm Error"): @@ -243,18 +267,24 @@ def prompt(self, prompt_name, variables=None, fallback="Llm Error"): return "" current_path = os.getcwd() - file_path = os.path.join(current_path, "prompts", self.model, prompt_name + ".txt") + file_path = os.path.join( + current_path, "prompts", self.model, prompt_name + ".txt" + ) if not os.path.exists(file_path): - default_folder_path = os.path.join(current_path,"prompts", "general", prompt_name + ".txt") + default_folder_path = os.path.join( + current_path, "prompts", "general", prompt_name + ".txt" + ) if not os.path.exists(default_folder_path): - raise FileNotFoundError(f"Couldnt find {file_path} or {default_folder_path}.") + raise FileNotFoundError( + f"Couldnt find {file_path} or {default_folder_path}." + ) else: file_path = default_folder_path - with open(file_path, 'r') as file: + with open(file_path, "r", encoding="utf-8") as file: content = file.read() - #new_prompt = content.format(**variables) + # new_prompt = content.format(**variables) template = Template(content) new_prompt = template.render(**variables) @@ -263,36 +293,41 @@ def prompt(self, prompt_name, variables=None, fallback="Llm Error"): llm = Llm() -''' +""" REDIS -''' -#TODO get rid of globals +""" +# TODO get rid of globals if "REDIS_URL" in globals(): - redis_connection = redis.Redis.from_url(REDIS_URL) + REDIS_CONNECTION = redis.Redis.from_url(REDIS_URL) else: print("REDIS_URL environment variable is not set.") - redis_connection = None + REDIS_CONNECTION = None + def print_and_log(content, key): return redis_log(content, key) print(content) + def redis_log(content, key): if LOG_TO_REDIS == 1: - redis_connection.rpush(key, json.dumps(content)) + REDIS_CONNECTION.rpush(key, json.dumps(content)) + -def find_most_similar(input, arr): - most_similar = difflib.get_close_matches(input, arr, n=1, cutoff=0.8) +def find_most_similar(inp, arr): + most_similar = difflib.get_close_matches(inp, arr, n=1, cutoff=0.8) if most_similar: return most_similar[0] - else: - return arr[0] -''' + + return arr[0] + + +""" DATABASE -''' +""" Base = declarative_base() -engine = create_engine('sqlite:///storage/matrix.db') +engine = create_engine("sqlite:///storage/matrix.db") Session = sessionmaker(bind=engine) session = Session() From fe60dd35cdb93df7bdaa31eeb08b1813c30aa9f4 Mon Sep 17 00:00:00 2001 From: chiefeu Date: Sat, 9 Mar 2024 04:01:39 +0800 Subject: [PATCH 4/5] fix pylint errors 1 --- chat.py | 36 +- cognitive_test.py | 249 +++++++---- configs/configs.py | 61 ++- engine.py | 80 ++-- frontend.py | 121 ++++-- generate_test_data.py | 97 ++++- images/test.py | 19 +- reevaluate.py | 165 ++++++-- run_all_sims.py | 165 ++++++-- save_report.py | 109 +++-- src/actions/action.py | 11 + src/actions/decide.py | 180 ++++++-- src/actions/fine_move_action.py | 27 +- src/agents.py | 711 +++++++++++++++++++++++--------- src/conversation.py | 3 +- src/environment.py | 110 ++--- src/location.py | 24 +- src/matrix.py | 530 +++++++++++++++++------- src/memory.py | 41 +- src/npc.py | 64 +-- src/objects.py | 6 +- test.py | 536 +++++++++++++++++------- 22 files changed, 2388 insertions(+), 957 deletions(-) diff --git a/chat.py b/chat.py index 0fbdd5a..b2e1983 100644 --- a/chat.py +++ b/chat.py @@ -1,22 +1,30 @@ -import argparse +""" +This module handles the chat functionality of the system. +""" + from src.agents import Agent from src.conversation import Conversation from utils.utils import * -def chat_with_agent(agent,you): + +def chat_with_agent(agent, you): + """ + This function lets a user to chat with an agent. + """ + print(f"Welcome, chat with {agent}, the meta cognizing LLM agent!") timestamp = 1 - unix_time = 1704067200 - agent.last_conversation = Conversation(agent,you ) + # unix_time = 1704067200 + agent.last_conversation = Conversation(agent, you) you.last_conversation = Conversation(you, agent) while True: user_input = input("You: ") - if user_input.lower() in ['exit()', 'quit()']: + if user_input.lower() in ["exit()", "quit()"]: print("Goodbye!") break - elif user_input.lower() in ['meta()']: + if user_input.lower() in ["meta()"]: agent.meta_cognize(unix_to_strftime(timestamp)) - elif user_input.lower() in ['mem()']: + elif user_input.lower() in ["mem()"]: print("long") for m in agent.memory: print(m) @@ -25,19 +33,21 @@ def chat_with_agent(agent,you): print(m) else: - #agent_response = agent.answer(user_input) + # agent_response = agent.answer(user_input) timestamp += 10 interaction = f"{timestamp} - Jason said to {agent}: {user_input}" you.last_conversation.messages.append(interaction) agent.last_conversation.messages.append(interaction) - agent_response = agent.talk({ "other_agents": [you],"timestamp":unix_to_strftime(timestamp)}) #"timestamp": self.unix_to_strftime(unix_time) }) + agent_response = agent.talk( + {"other_agents": [you], "timestamp": unix_to_strftime(timestamp)} + ) # "timestamp": self.unix_to_strftime(unix_time) }) print(f"{agent}: {agent_response}") + if __name__ == "__main__": # Create an instance of the Agent - agent = Agent({'name':'Jarvis','goal':'Serve Jason'}) - you = Agent({'name':'Jason'}) + sim_agent = Agent({"name": "Jarvis", "goal": "Serve Jason"}) + person = Agent({"name": "Jason"}) # Start the CLI chat interface - chat_with_agent(agent,you) - + chat_with_agent(sim_agent, person) diff --git a/cognitive_test.py b/cognitive_test.py index 263602d..d1aa936 100644 --- a/cognitive_test.py +++ b/cognitive_test.py @@ -1,37 +1,80 @@ -from engine import Matrix +""" +This module handles testing of cognitive abilities of the agents. +""" + import re -from utils.utils import * -import json import argparse import subprocess import os import sys -from contextlib import contextmanager import numpy as np +from contextlib import contextmanager import matplotlib.pyplot as plt from save_report import save_report +from engine import Matrix +from utils.utils import * -parser = argparse.ArgumentParser(description='Cognitive Test') -parser.add_argument('--generate', action='store_true', help='Run tests to generate auto eval') -parser.add_argument('--overwrite', action='store_true', help='Overwrite eval files') -parser.add_argument('--reeval', action='store_true', help='Run reevaluate') -parser.add_argument('--graph', action='store_true', help='Read eval files to generate graph') -parser.add_argument('--steps', type=int, default=100, help='Steps for Generating') +parser = argparse.ArgumentParser(description="Cognitive Test") +parser.add_argument("--generate", action="store_true", help="Run tests to generate auto eval") +parser.add_argument("--overwrite", action="store_true", help="Overwrite eval files") +parser.add_argument("--reeval", action="store_true", help="Run reevaluate") +parser.add_argument("--graph", action="store_true", help="Read eval files to generate graph") +parser.add_argument("--steps", type=int, default=100, help="Steps for Generating") args = parser.parse_args() variations = [ - { "steps": args.steps, "allow_plan": 1, "allow_reflect": 1, "allow_observance": 1, "allow_meta": 1, "llm_action": 1, "llm_importance": 0 }, #Full Architecture With Meta - { "steps": args.steps, "allow_plan": 1, "allow_reflect": 1, "allow_observance": 1, "allow_meta": 0, "llm_action": 1, "llm_importance": 0 }, #Full Architecture Without Meta - { "steps": args.steps, "allow_plan": 0, "allow_reflect": 0, "allow_observance": 1, "allow_meta": 1, "llm_action": 1, "llm_importance": 0 }, #Architecture With Meta Only - { "steps": args.steps, "allow_plan": 0, "allow_reflect": 1, "allow_observance": 1, "allow_meta": 0, "llm_action": 1, "llm_importance": 0 }, #Architecture With Reflect Only - { "steps": args.steps, "allow_plan": 0, "allow_reflect": 0, "allow_observance": 0, "allow_meta": 0, "llm_action": 1, "llm_importance": 0 } #Reflect and Meta Off + { + "steps": args.steps, + "allow_plan": 1, + "allow_reflect": 1, + "allow_observance": 1, + "allow_meta": 1, + "llm_action": 1, + "llm_importance": 0, + }, # Full Architecture With Meta + { + "steps": args.steps, + "allow_plan": 1, + "allow_reflect": 1, + "allow_observance": 1, + "allow_meta": 0, + "llm_action": 1, + "llm_importance": 0, + }, # Full Architecture Without Meta + { + "steps": args.steps, + "allow_plan": 0, + "allow_reflect": 0, + "allow_observance": 1, + "allow_meta": 1, + "llm_action": 1, + "llm_importance": 0, + }, # Architecture With Meta Only + { + "steps": args.steps, + "allow_plan": 0, + "allow_reflect": 1, + "allow_observance": 1, + "allow_meta": 0, + "llm_action": 1, + "llm_importance": 0, + }, # Architecture With Reflect Only + { + "steps": args.steps, + "allow_plan": 0, + "allow_reflect": 0, + "allow_observance": 0, + "allow_meta": 0, + "llm_action": 1, + "llm_importance": 0, + }, # Reflect and Meta Off ] scenarios = [ "configs/christmas_party_situation.json", "configs/secret_santa_situation.json", "configs/zombie_situation.json", - "configs/murder_situation.json" + "configs/murder_situation.json", ] ids = [ @@ -39,26 +82,22 @@ "ss_p1_r1_o1_m1", "z_p1_r1_o1_m1", "m_p1_r1_o1_m1", - "xmas_p1_r1_o1_m0", "ss_p1_r1_o1_m0", "z_p1_r1_o1_m0", "m_p1_r1_o1_m0", - "xmas_p0_r0_o1_m1", "ss_p0_r0_o1_m1", "z_p0_r0_o1_m1", "m_p0_r0_o1_m1", - "xmas_p0_r1_o1_m0", "ss_p0_r1_o1_m0", "z_p0_r1_o1_m0", "m_p0_r1_o1_m0", - "xmas_p0_r0_o0_m0", "ss_p0_r0_o0_m0", "z_p0_r0_o0_m0", - "m_p0_r0_o0_m0" + "m_p0_r0_o0_m0", ] variation_labels = [ @@ -66,20 +105,22 @@ "Full Architecture Without Meta", "Architecture With Meta Only", "Architecture With Reflect Only", - "Architecture With Reflect, Meta, and Observation Off" + "Architecture With Reflect, Meta, and Observation Off", ] + @contextmanager def tee_stdout(log_file): original_stdout = sys.stdout try: # Open the log file in append mode - with open(log_file, 'a') as log: + with open(log_file, "a", encoding="utf-8") as log: sys.stdout = Tee(sys.stdout, log) yield sys.stdout finally: sys.stdout = original_stdout +# pylint: disable=missing-class-docstring, missing-function-docstring class Tee: def __init__(self, *streams): self.streams = streams @@ -90,10 +131,15 @@ def write(self, data): def flush(self): for stream in self.streams: - if hasattr(stream, 'flush'): + if hasattr(stream, "flush"): stream.flush() + def parse_score(eval_result): + """ + This function outputs the score of the evaluation result. + """ + score = 0 try: cleaned = re.search(r"Score:\s*(\d+)", eval_result) @@ -104,15 +150,22 @@ def parse_score(eval_result): score = int(cleaned.group(1)) return score - except Exception as e: + except Exception: # pylint: disable=broad-except return 0 + if args.generate and not args.reeval: - for var_index in range(len(variations)): - for scene_index in range(len(scenarios)): - log_file_name = f"fulllogs-{ids[(var_index * len(scenarios)) + scene_index]}_s{args.steps}.txt" - report_file_name = f"report-{ids[(var_index * len(scenarios)) + scene_index]}_s{args.steps}.txt" - eval_file_name = f"eval-{ids[(var_index * len(scenarios)) + scene_index]}_s{args.steps}.txt" + for var_index, var in enumerate(variations): + for scene_index, scene in enumerate(scenarios): + log_file_name = ( + f"fulllogs-{ids[(var_index * len(scenarios)) + scene_index]}_s{args.steps}.txt" + ) + report_file_name = ( + f"report-{ids[(var_index * len(scenarios)) + scene_index]}_s{args.steps}.txt" + ) + eval_file_name = ( + f"eval-{ids[(var_index * len(scenarios)) + scene_index]}_s{args.steps}.txt" + ) if os.path.exists(f"logs/{log_file_name}"): if args.overwrite: @@ -136,15 +189,22 @@ def parse_score(eval_result): continue with tee_stdout(os.path.join("logs", log_file_name)): - params = { **variations[var_index], "scenario": scenarios[scene_index], "id": f"{ids[(var_index * len(scenarios)) + scene_index]}_s{args.steps}" } + params = { + **var, + "scenario": scenarios[scene_index], + "id": f"{ids[(var_index * len(scenarios)) + scene_index]}_s{args.steps}", + } matrix = Matrix(params) matrix.run_singlethread() matrix.run_interviews() - save_report(matrix, f"{ids[(var_index * len(scenarios)) + scene_index]}_s{args.steps}.txt") + save_report( + matrix, + f"{ids[(var_index * len(scenarios)) + scene_index]}_s{args.steps}.txt", + ) if args.reeval and args.generate: - for i in range(len(ids)): + for i, _ in enumerate(ids): if os.path.exists(f"logs/report-{ids[i]}_s{args.steps}.txt"): command = f"python reevaluate.py --report logs/report-{ids[i]}_s{args.steps}.txt" @@ -159,25 +219,30 @@ def parse_score(eval_result): results = [] grouped_data = {label: [] for label in variation_labels} if args.graph: - for i in range(len(ids)): - if os.path.exists(f"logs/eval-{ids[i]}_s{args.steps}.txt"): + for i, id_value in enumerate(ids): + if os.path.exists(f"logs/eval-{id_value}_s{args.steps}.txt"): if args.reeval: - eval_file = f"logs/reeval-{ids[i]}_s{args.steps}.txt" - pre_name_str = "re_" + eval_file = f"logs/reeval-{id_value}_s{args.steps}.txt" + PRE_NAME_STR = "re_" else: - eval_file = f"logs/eval-{ids[i]}_s{args.steps}.txt" - pre_name_str = "" - with open(eval_file) as file: + eval_file = f"logs/eval-{id_value}_s{args.steps}.txt" + PRE_NAME_STR = "" + with open(eval_file, encoding="utf-8") as file: input_string = file.read() - score_matches = re.compile(r"={42}Scores for (.+?)\n(.*?)(?=\n={42}|$)", re.DOTALL).findall(input_string) + score_matches = re.compile( + r"={42}Scores for (.+?)\n(.*?)(?=\n={42}|$)", re.DOTALL + ).findall(input_string) progressive_understanding_scores = [] adaptive_communication_scores = [] reflective_depth_scores = [] knowledge_application_scores = [] cognitive_flexibility_scores = [] for name, block in score_matches: - scores_part = re.compile(r"(Progressive Understanding|Adaptive Communication|Reflective Depth|Knowledge Application|Cognitive Flexibility): (\d+)").findall(block) + scores_part = re.compile( + r"(Progressive Understanding|Adaptive Communication|Reflective Depth|" + r"Knowledge Application|Cognitive Flexibility): (\d+)" + ).findall(block) progressive_understanding_scores.append(int(scores_part[0][1])) adaptive_communication_scores.append(int(scores_part[1][1])) @@ -196,27 +261,31 @@ def parse_score(eval_result): print(input_string) ps = float(re.search(r"\+\+\+\+ Performance Score: (\d+\.\d+)", input_string).group(1)) - grouped_data[variation_labels[i // len(scenarios)]].append({ - "id": ids[i], - "progressive_understanding": pu, - "adaptive_communication": ac, - "reflective_depth": rd, - "knowledge_application": ka, - "cognitive_flexibility": cf, - "performance": ps, - "overall": pu + ac + rd + ka + cf + ps - }) + grouped_data[variation_labels[i // len(scenarios)]].append( + { + "id": id_value, + "progressive_understanding": pu, + "adaptive_communication": ac, + "reflective_depth": rd, + "knowledge_application": ka, + "cognitive_flexibility": cf, + "performance": ps, + "overall": pu + ac + rd + ka + cf + ps, + } + ) else: - grouped_data[variation_labels[i // len(scenarios)]].append({ - "id": ids[i], - "progressive_understanding": 0, - "adaptive_communication": 0, - "reflective_depth": 0, - "knowledge_application": 0, - "cognitive_flexibility": 0, - "performance": 0, - "overall": 0 - }) + grouped_data[variation_labels[i // len(scenarios)]].append( + { + "id": id_value, + "progressive_understanding": 0, + "adaptive_communication": 0, + "reflective_depth": 0, + "knowledge_application": 0, + "cognitive_flexibility": 0, + "performance": 0, + "overall": 0, + } + ) score_labels = [ "progressive_understanding", @@ -225,7 +294,7 @@ def parse_score(eval_result): "knowledge_application", "cognitive_flexibility", "performance", - "overall" + "overall", ] for score_label in score_labels: @@ -236,50 +305,70 @@ def parse_score(eval_result): values = np.array(values) num_groups = values.shape[1] - bar_width = 0.2 + BAR_WIDTH = 0.2 positions = np.arange(len(variation_labels)) - fig, ax = plt.subplots(figsize=(1920/80, 1080/80), dpi=80) + fig, ax = plt.subplots(figsize=(1920 / 80, 1080 / 80), dpi=80) for i in range(num_groups): - ax.bar(positions + i * bar_width, values[:, i], width=bar_width, label=scenarios[i].replace("configs/", "").replace(".json", "").replace("_", " ").upper()) - - ax.set_xlabel('Variation') - ax.set_ylabel('Score') + ax.bar( + positions + i * BAR_WIDTH, + values[:, i], + width=BAR_WIDTH, + label=scenarios[i] + .replace("configs/", "") + .replace(".json", "") + .replace("_", " ") + .upper(), + ) + + ax.set_xlabel("Variation") + ax.set_ylabel("Score") ax.set_title(f"{score_label.upper()} SCORES") - ax.set_xticks(positions + (bar_width * (num_groups - 1)) / 2) + ax.set_xticks(positions + (BAR_WIDTH * (num_groups - 1)) / 2) ax.set_xticklabels(variation_labels) ax.legend() plt.tight_layout() - plt.savefig(f"logs/{pre_name_str}{score_label}_graph_{args.steps}.png") + plt.savefig(f"logs/{PRE_NAME_STR}{score_label}_graph_{args.steps}.png") plt.show() - means = [np.mean([item.get('overall', 0) for item in grouped_data[label]]) for label in variation_labels] - std_devs = [np.std([item.get('overall', 0) for item in grouped_data[label]]) for label in variation_labels] + means = [ + np.mean([item.get("overall", 0) for item in grouped_data[label]]) + for label in variation_labels + ] + std_devs = [ + np.std([item.get("overall", 0) for item in grouped_data[label]]) + for label in variation_labels + ] - fig, ax = plt.subplots(figsize=(1920/80, 1080/80), dpi=80) + fig, ax = plt.subplots(figsize=(1920 / 80, 1080 / 80), dpi=80) x = np.arange(len(variation_labels)) - bars = ax.bar(x, means, yerr=std_devs, align='center', alpha=0.7, ecolor='black', capsize=10) + bars = ax.bar(x, means, yerr=std_devs, align="center", alpha=0.7, ecolor="black", capsize=10) ax.set_xticks(x) ax.set_xticklabels(variation_labels, rotation=45, ha="right") - ax.set_ylabel('Overall Score') - ax.set_title('Overall Score by Variation with Standard Deviation') + ax.set_ylabel("Overall Score") + ax.set_title("Overall Score by Variation with Standard Deviation") ax.legend() for bar, mean, std_dev in zip(bars, means, std_devs): height = bar.get_height() - ax.text(bar.get_x() + bar.get_width() / 2, height + 0.1, f'{mean:.2f} ± {std_dev:.2f}', ha='center', va='bottom') + ax.text( + bar.get_x() + bar.get_width() / 2, + height + 0.1, + f"{mean:.2f} ± {std_dev:.2f}", + ha="center", + va="bottom", + ) plt.tight_layout() - plt.savefig(f"logs/{pre_name_str}sd_graph_{args.steps}.png") + plt.savefig(f"logs/{PRE_NAME_STR}sd_graph_{args.steps}.png") plt.show() for d in grouped_data: print(d) for c in grouped_data[d]: print(c) - diff --git a/configs/configs.py b/configs/configs.py index 77664dc..3686d44 100644 --- a/configs/configs.py +++ b/configs/configs.py @@ -1,8 +1,13 @@ +""" +This module contains default params. +""" + import os from dotenv import load_dotenv load_dotenv() +# pylint: disable=invalid-envvar-default # DECLARE PARAMS HERE DEBUG = os.getenv("DEBUG", default="0") LLAMA_URL = os.getenv("LLAMA_URL", default="http://localhost:11434/api") @@ -40,7 +45,34 @@ # DEV DEFAULTS -DEFAULT_NAMES = ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Henry', 'Ivy', 'Jack', 'Katie', 'Leo', 'Mia', 'Nathan', 'Olivia', 'Peter', 'Quinn', 'Rachel', 'Sam', 'Tom', 'Ursula', 'Victor', 'Wendy', 'Xander', 'Yvonne', 'Zach'] +DEFAULT_NAMES = [ + "Alice", + "Bob", + "Charlie", + "David", + "Eva", + "Frank", + "Grace", + "Henry", + "Ivy", + "Jack", + "Katie", + "Leo", + "Mia", + "Nathan", + "Olivia", + "Peter", + "Quinn", + "Rachel", + "Sam", + "Tom", + "Ursula", + "Victor", + "Wendy", + "Xander", + "Yvonne", + "Zach", +] DEFAULT_DESCRIPTIONS = [ "Energetic and outgoing, the life of any friendship circle.", "Reserved and contemplative, occasionally distant or aloof.", @@ -51,18 +83,27 @@ "Kind-hearted and considerate, ensuring everyone feels the warmth of friendship.", "Quirky and fun-loving, bringing a touch of humor.", "Thoughtful and reflective, prone to overthinking small moments.", - "Friendly and approachable, making everyone feel welcome." + "Friendly and approachable, making everyone feel welcome.", ] DEFAULT_GOALS = [ - "Learn and spread hot gossips.", - "Build meaningful connections with others.", - "Learn and share intriguing stories.", - "Help others in times of need." + "Learn and spread hot gossips.", + "Build meaningful connections with others.", + "Learn and share intriguing stories.", + "Help others in times of need.", +] +DEFAULT_ACTIONS = [ + "move", + "talk", + "continue_to_destination", + "meta_cognize", + "fine_move", ] -DEFAULT_ACTIONS = ["move", "talk","continue_to_destination","meta_cognize","fine_move"] DEFAULT_QUESTIONS = [ - { "who": "all", "question": "What have you learned so far?" }, - { "who": "all", "question": "What is your most cherished memory and why?" }, - { "who": "all", "question": "What are the locations that you know based on your memories?" } + {"who": "all", "question": "What have you learned so far?"}, + {"who": "all", "question": "What is your most cherished memory and why?"}, + { + "who": "all", + "question": "What are the locations that you know based on your memories?", + }, ] DEFAULT_TIME = 1704067200 diff --git a/engine.py b/engine.py index 28c8590..1cafc0d 100755 --- a/engine.py +++ b/engine.py @@ -1,18 +1,25 @@ -import sys +""" +This module serves as the main driver for running simulations. +""" + import time import signal import argparse import json -from concurrent.futures import ThreadPoolExecutor from src.matrix import Matrix from utils.utils import * -from save_report import save_report #TODO refactor +from save_report import save_report #TODO refactor matrix = None + def update_from_env(config): + """ + This method updates environment variables from config. + """ + for key, value in config.items(): env_var = os.getenv(key) if env_var is not None: @@ -20,46 +27,65 @@ def update_from_env(config): config[key] = type(value)(env_var) if value is not None else env_var return config + def load_config(): + """ + This method loads the default data. + """ + filename = "configs/defaults.json" - with open(filename, 'r') as file: + with open(filename, "r", encoding="utf-8") as file: config = json.load(file) config = update_from_env(config) return config def main(): + """ + This function serves as the main driver for running necessary functions. + """ + global matrix - #Base.metadata.create_all(engine) + # Base.metadata.create_all(engine) # Parse Args - parser = argparse.ArgumentParser(description='Matrix Simulation') - parser.add_argument('--scenario', type=str, default='configs/def.json', help='Path to the scenario file') - parser.add_argument('--environment', type=str, default='configs/largev2.tmj', help='Path to the env file') - parser.add_argument('--id', type=str, default=None, help='Custom Simulation ID') + parser = argparse.ArgumentParser(description="Matrix Simulation") + parser.add_argument( + "--scenario", + type=str, + default="configs/def.json", + help="Path to the scenario file", + ) + parser.add_argument( + "--environment", + type=str, + default="configs/largev2.tmj", + help="Path to the env file", + ) + parser.add_argument("--id", type=str, default=None, help="Custom Simulation ID") args = parser.parse_args() - #matrix_data = {"agents_file":args.agents, "world_file":args.world} - #matrix = Matrix(matrix_data) + # matrix_data = {"agents_file":args.agents, "world_file":args.world} + # matrix = Matrix(matrix_data) config = load_config() - config['scenario'] = args.scenario - config['environment'] = args.environment + config["scenario"] = args.scenario + config["environment"] = args.environment if args.id: - config['id'] = args.id + config["id"] = args.id matrix = Matrix(config) # matrix.send_matrix_to_redis() pd(f"model:#{MODEL}") pd("Initial Agents Positions:") - #redis_connection.set(f"{matrix.id}:matrix_state", json.dumps(matrix.get_arr_2D())) + # redis_connection.set(f"{matrix.id}:matrix_state", json.dumps(matrix.get_arr_2D())) # Clear convos - #matrix.clear_redis() + # matrix.clear_redis() # Run start_time = datetime.now() - #matrix.run() + # matrix.run() matrix.boot() matrix.run_singlethread() end_time = datetime.now() @@ -70,17 +96,23 @@ def main(): matrix.send_matrix_to_redis() # Save the environment state to a file for inspection - if matrix.id is not None and matrix.id != '' and RUN_REPORTS != 0: + if matrix.id is not None and matrix.id != "" and RUN_REPORTS != 0: save_report(matrix) - #session.commit() + # session.commit() +# pylint: disable=W0613 def signal_handler(signum, frame): - global matrix,last_interrupt_time, ctrl_c_count + """ + This function handles signals to pause simulation runs. + """ + + global matrix, last_interrupt_time, ctrl_c_count current_time = time.time() - #TODO on first control-c, run interview questions then quit, we need to pause the simulation + ctrl_c_count = 0 + # TODO on first control-c, run interview questions then quit, we need to pause the simulation if current_time - last_interrupt_time < 2: ctrl_c_count += 1 - if ctrl_c_count > 1 : + if ctrl_c_count > 1: pd("Exiting...") exit(0) else: @@ -89,15 +121,15 @@ def signal_handler(signum, frame): else: ctrl_c_count = 1 pd("stopping matrix, please wait for current step to finish") - pd("*"*50) + pd("*" * 50) matrix.status = "stop" matrix.send_matrix_to_redis() last_interrupt_time = current_time + ctrl_c_count = 0 last_interrupt_time = time.time() signal.signal(signal.SIGINT, signal_handler) if __name__ == "__main__": main() - diff --git a/frontend.py b/frontend.py index a84d0a5..bee1cc7 100644 --- a/frontend.py +++ b/frontend.py @@ -1,3 +1,7 @@ +""" +This module handles all frontend functionalities. +""" + from flask import Flask, request, jsonify, render_template from redis import Redis import requests @@ -5,95 +9,130 @@ app = Flask(__name__) redis_client = Redis.from_url("redis://localhost:6379") -@app.route('/get_matrix_state') + +@app.route("/get_matrix_state") def get_matrix_state(): + """ + This function pulls the matrix state from the redis server. + """ try: - matrix_state = redis_client.get(':matrix_state') + matrix_state = redis_client.get(":matrix_state") - matrix = matrix_state.decode('utf-8') if matrix_state else '[]' + matrix = matrix_state.decode("utf-8") if matrix_state else "[]" return jsonify(matrix) - except Exception as e: - return jsonify({'error': str(e)}), 500 + except Exception as e: # pylint: disable=broad-except + return jsonify({"error": str(e)}), 500 + -@app.route('/get_conversations') +@app.route("/get_conversations") def get_conversations(): + """ + This function pulls the agents conversations from the redis server. + """ try: # Fetch conversations from Redis queue "agent_conversations" - conversations = redis_client.lrange(':agent_conversations', 0, -1)[::-1] + conversations = redis_client.lrange(":agent_conversations", 0, -1)[::-1] # Convert byte strings to regular strings - conversations = [conversation.decode('utf-8') for conversation in conversations] + conversations = [conversation.decode("utf-8") for conversation in conversations] return jsonify(conversations) - except Exception as e: - return jsonify({'error': str(e)}), 500 + except Exception as e: # pylint: disable=broad-except + return jsonify({"error": str(e)}), 500 -@app.route('/') + +@app.route("/") def index(): - return render_template('frontend.html') + """ + This function renders the main/home page. + """ + return render_template("frontend.html") + + +@app.route("/map") +def display_map(): + """ + This function renders the map template. + """ + return render_template("map.html") -@app.route('/map') -def map(): - return render_template('map.html') -@app.route('/embeddings', methods=['POST']) +@app.route("/embeddings", methods=["POST"]) def embeddings(): + """ + This function generates embeddings data for the web app. + """ + timeout = 60 + # Get data from the request data = request.json # Extract values from the payload - model = data.get('model') - prompt = data.get('prompt') + model = data.get("model") + prompt = data.get("prompt") # Create the payload for the POST request to the external API - payload = { - "model": model, - "prompt": prompt - } + payload = {"model": model, "prompt": prompt} # Make the POST request to the external API external_api_url = "http://localhost:11434/api/embeddings" - response = requests.post(external_api_url, json=payload) + response = requests.post(external_api_url, json=payload, timeout=timeout) # Check if the request was successful (status code 200) if response.status_code == 200: # Parse the JSON response from the external API result = response.json() return jsonify(result) - else: - # If the request was not successful, return an error message - return jsonify({"error": f"Failed to generate data. Status code: {response.status_code}"}), response.status_code - -@app.route('/generate', methods=['POST']) + # If the request was not successful, return an error message + return ( + jsonify( + { + "error": f"Failed to generate data. Status code: {response.status_code}" + } + ), + response.status_code, + ) + + +@app.route("/generate", methods=["POST"]) def generate(): + """ + This function generates data for the web app. + """ + timeout = 60 + # Get data from the request data = request.json # Extract values from the payload - model = data.get('model') - prompt = data.get('prompt') + model = data.get("model") + prompt = data.get("prompt") # Create the payload for the POST request to the external API - payload = { - "model": model, - "prompt": prompt, - "stream": False - } + payload = {"model": model, "prompt": prompt, "stream": False} # Make the POST request to the external API external_api_url = "http://localhost:11434/api/generate" - response = requests.post(external_api_url, json=payload) + response = requests.post(external_api_url, json=payload, timeout=timeout) # Check if the request was successful (status code 200) if response.status_code == 200: # Parse the JSON response from the external API result = response.json() return jsonify(result) - else: - # If the request was not successful, return an error message - return jsonify({"error": f"Failed to generate data. Status code: {response.status_code}"}), response.status_code -if __name__ == '__main__': - app.run(debug=True,host='0.0.0.0') + # If the request was not successful, return an error message + return ( + jsonify( + { + "error": f"Failed to generate data. Status code: {response.status_code}" + } + ), + response.status_code, + ) + + +if __name__ == "__main__": + app.run(debug=True, host="0.0.0.0") diff --git a/generate_test_data.py b/generate_test_data.py index 98598ae..ecc29dc 100644 --- a/generate_test_data.py +++ b/generate_test_data.py @@ -1,45 +1,104 @@ +""" +This module generates test data for each simulation scenarios. +""" + import subprocess import sys import os import datetime import requests -import time -WEBHOOK_URL = "https://discord.com/api/webhooks/1179589082540675113/o8NLAfbISn82hZ9SmGyJ3GAJavIc7OIDS8Qbjl8OoO-jWOBSVLuQ6kgv-_UDju1yWf8M" -def run_and_notify(scenario_config, env, id, file_path, report_path): - with open(file_path, 'w') as file: +WEBHOOK_URL = ("https://discord.com/api/webhooks/" + "1179589082540675113/" + "o8NLAfbISn82hZ9SmGyJ3GAJavIc7OIDS8Qbjl8OoO-" + "jWOBSVLuQ6kgv-_UDju1yWf8M") + +def run_and_notify(scenario_config, env, sim_id, file_path, report_path): + """ + This function /insert description/. + """ + + with open(file_path, "w") as file: python_executable = sys.executable - subprocess.run([python_executable, "engine.py", "--scenario", scenario_config, "--environment", env, "--id", id], stdout=file, env={ 'LLM_ACTION': '1', 'SIMULATION_STEPS': '10' }) + subprocess.run( + [ + python_executable, + "engine.py", + "--scenario", + scenario_config, + "--environment", + env, + "--id", + sim_id, + ], + stdout=file, + env={"LLM_ACTION": "1", "SIMULATION_STEPS": "10"}, + ) + + timeout = 60 + # Check if the simulation output file is not empty if os.path.exists(file_path) and os.path.getsize(file_path) > 0: # Send the simulation output to Discord - with open(file_path, 'rb') as file: - requests.post(WEBHOOK_URL, files={'file': file}, json={'content': f"full debug logs for {id}"}) + with open(file_path, "rb") as file: + requests.post( + WEBHOOK_URL, + files={"file": file}, + json={"content": f"full debug logs for {sim_id}"}, + timeout=timeout + ) print(f"Webhook sent for {file_path}") # Check if the report file is not empty if os.path.exists(report_path) and os.path.getsize(report_path) > 0: # Send the simulation output to Discord - with open(report_path, 'rb') as file: - requests.post(WEBHOOK_URL, files={'file': file}, json={'content': f"Report {id}"}) + with open(report_path, "rb") as file: + requests.post( + WEBHOOK_URL, + files={"file": file}, + json={"content": f"Report {sim_id}"}, + timeout=timeout + ) print(f"Report Contents sent to Discord for {report_path}") else: print(f"No webhook sent for {file_path} and {report_path}") + current_date = datetime.datetime.now().strftime("%Y-%m-%d") -logs_path = "logs/" -os.makedirs(logs_path, exist_ok=True) +LOGS_PATH = "logs/" +os.makedirs(LOGS_PATH, exist_ok=True) sims = [ - {"scenario_config": "configs/christmas_party_situation.json", "env": "configs/largev2.tmj", "id": "christmasparty_graph"}, - {"scenario_config": "configs/murder_situation.json", "env": "configs/largev2.tmj", "id": "murder_graph"}, - {"scenario_config": "configs/zombie_situation.json", "env": "configs/largev2.tmj", "id": "zombies_graph"}, - {"scenario_config": "configs/secret_santa_situation.json", "env": "configs/largev2.tmj", "id": "secretsanta_graph"}, + { + "scenario_config": "configs/christmas_party_situation.json", + "env": "configs/largev2.tmj", + "id": "christmasparty_graph", + }, + { + "scenario_config": "configs/murder_situation.json", + "env": "configs/largev2.tmj", + "id": "murder_graph", + }, + { + "scenario_config": "configs/zombie_situation.json", + "env": "configs/largev2.tmj", + "id": "zombies_graph", + }, + { + "scenario_config": "configs/secret_santa_situation.json", + "env": "configs/largev2.tmj", + "id": "secretsanta_graph", + }, ] # Run simulations and notify for sim in sims: - file_path = f"{logs_path}{sim['id']}_{current_date}.txt" - report_path = f"{logs_path}report-{sim['id']}_{current_date}.txt" - run_and_notify(sim['scenario_config'], sim['env'], f"{sim['id']}_{current_date}", file_path, report_path) - + sim_file_path = f"{LOGS_PATH}{sim['id']}_{current_date}.txt" + sim_report_path = f"{LOGS_PATH}report-{sim['id']}_{current_date}.txt" + run_and_notify( + sim["scenario_config"], + sim["env"], + f"{sim['id']}_{current_date}", + sim_file_path, + sim_report_path, + ) diff --git a/images/test.py b/images/test.py index f6d0c85..9efed08 100644 --- a/images/test.py +++ b/images/test.py @@ -1,15 +1,25 @@ +""" +This module is used to test loading of tilemap. +""" + import pytmx + def load_tilemap(file_path): + """ + This function loads the tilemap file. + """ + tmx_data = pytmx.TiledMap(file_path) return tmx_data -file_path = 'map.tmx' # Replace with the path to your TMX file -tilemap_data = load_tilemap(file_path) + +FILE_PATH = "map.tmx" # Replace with the path to your TMX file +tilemap_data = load_tilemap(FILE_PATH) # Accessing tilemap properties -width = tilemap_data.width -height = tilemap_data.height +WIDTH = tilemap_data.width +HEIGHT = tilemap_data.height tilesets = tilemap_data.tilesets # Accessing individual tilesets @@ -30,4 +40,3 @@ def load_tilemap(file_path): print(f"Layer Name: {layer_name}") print(f"Layer Data: {layer_data}") - diff --git a/reevaluate.py b/reevaluate.py index 98fe53c..3243e34 100644 --- a/reevaluate.py +++ b/reevaluate.py @@ -1,3 +1,7 @@ +""" +This module handles the evaluation of simulations. +""" + import os import json import re @@ -6,48 +10,94 @@ from configs.configs import * from utils.utils import * + def call_gpt(prompt): + """ + This function uses the gpt service for evaluations. + """ + data = { "model": "gpt-3.5-turbo-16k", - "messages": [{"role": "user", "content": prompt}] + "messages": [{"role": "user", "content": prompt}], } headers = { "Authorization": f"Bearer {OPENAI_KEY}", - "Content-Type": "application/json" + "Content-Type": "application/json", } - response = requests.post(f"https://api.openai.com/v1/chat/completions", json=data, headers=headers) + timeout = 60 + + response = requests.post( + "https://api.openai.com/v1/chat/completions", json=data, headers=headers, timeout=timeout + ) if response.status_code == 200: - msg = response.json()['choices'][0]['message']['content'] + msg = response.json()["choices"][0]["message"]["content"] else: print(response.json()) msg = "Error" return msg -parser = argparse.ArgumentParser(description='Evaluate with GPT') -parser.add_argument('--report', type=str, help='Report file to evaluate') + +parser = argparse.ArgumentParser(description="Evaluate with GPT") +parser.add_argument("--report", type=str, help="Report file to evaluate") args = parser.parse_args() if os.path.exists(args.report): - with open(args.report) as file: + with open(args.report, encoding="utf-8") as file: input_string = file.read() env_vars = { "total_agents": int(re.search(r"total_agents: (\d+)", input_string).group(1)), "total_dead": int(re.search(r"total_dead: (\d+)", input_string).group(1)), - "total_alive": int(re.search(r"total_alive: (\d+)", input_string).group(1)) + "total_alive": int(re.search(r"total_alive: (\d+)", input_string).group(1)), } - interview_part = re.search(r'Interview Question Results:(.*?)(Conversation Log:|\Z)', input_string, re.DOTALL).group(1).strip() - scenario_part = re.search(r'Scenario:(.*?)(Goals Log:|\Z)', input_string, re.DOTALL).group(1).strip() - goals_part = re.search(r'Goals Log:(.*?)(Interview Question Results:|\Z)', input_string, re.DOTALL).group(1).strip() - conversation_part = re.search(r'Conversations Log:(.*?)(Reflection Log:|\Z)', input_string, re.DOTALL).group(1).strip() - reflection_part = re.search(r'Reflection Log:(.*?)(Meta Cognition Log:|\Z)', input_string, re.DOTALL).group(1).strip() - metacognition_part = re.search(r'Meta Cognition Log:(.*?)(\Z)', input_string, re.DOTALL).group(1).strip() - - conversation_matches = re.compile(r"={42}Conversation logs for (.+?)\n(.*?)(?=\n={42}|$)", re.DOTALL).findall(conversation_part) + interview_part = ( + re.search( + r"Interview Question Results:(.*?)(Conversation Log:|\Z)", + input_string, + re.DOTALL, + ) + .group(1) + .strip() + ) + scenario_part = ( + re.search(r"Scenario:(.*?)(Goals Log:|\Z)", input_string, re.DOTALL) + .group(1) + .strip() + ) + goals_part = ( + re.search( + r"Goals Log:(.*?)(Interview Question Results:|\Z)", input_string, re.DOTALL + ) + .group(1) + .strip() + ) + conversation_part = ( + re.search( + r"Conversations Log:(.*?)(Reflection Log:|\Z)", input_string, re.DOTALL + ) + .group(1) + .strip() + ) + reflection_part = ( + re.search( + r"Reflection Log:(.*?)(Meta Cognition Log:|\Z)", input_string, re.DOTALL + ) + .group(1) + .strip() + ) + metacognition_part = ( + re.search(r"Meta Cognition Log:(.*?)(\Z)", input_string, re.DOTALL) + .group(1) + .strip() + ) + + conversation_matches = re.compile( + r"={42}Conversation logs for (.+?)\n(.*?)(?=\n={42}|$)", re.DOTALL + ).findall(conversation_part) parsed_data = {} for name, logs in conversation_matches: if name not in parsed_data: @@ -56,7 +106,9 @@ def call_gpt(prompt): parsed_data[name.strip()] = logs.strip() conversation_matches = parsed_data - reflection_matches = re.compile(r"={42}Reflection logs for (.+?)\n(.*?)(?=\n={42}|$)", re.DOTALL).findall(reflection_part) + reflection_matches = re.compile( + r"={42}Reflection logs for (.+?)\n(.*?)(?=\n={42}|$)", re.DOTALL + ).findall(reflection_part) parsed_data = {} for name, logs in reflection_matches: if name not in parsed_data: @@ -65,8 +117,9 @@ def call_gpt(prompt): parsed_data[name.strip()] = logs.strip() reflection_matches = parsed_data - #interview_matches = re.compile(r"Question: (.+?)\n(.*?)(?=\nQuestion:|$)", re.DOTALL).findall(interview_part) - interview_matches = re.compile(r"Question: (.+?)\n(.*?)(?:\n\[.*?\])?(?=\nQuestion:|$|\n={10,})", re.DOTALL).findall(interview_part) + interview_matches = re.compile( + r"Question: (.+?)\n(.*?)(?:\n\[.*?\])?(?=\nQuestion:|$|\n={10,})", re.DOTALL + ).findall(interview_part) parsed_data = {} for question, block in interview_matches: answer_match = re.match(r"(\w+):(.+)", block) @@ -89,7 +142,9 @@ def call_gpt(prompt): if name not in parsed_data: parsed_data[name] = [] - parsed_data[name].append({"Question": question.strip(), "Answer": answer}) + parsed_data[name].append( + {"Question": question.strip(), "Answer": answer} + ) interview_matches = parsed_data @@ -102,7 +157,7 @@ def call_gpt(prompt): # Write to re-eval file reeval_filename = args.report.replace("report", "reeval") - with open(reeval_filename, "w") as file: + with open(reeval_filename, "w", encoding="utf-8") as file: file.write("\n\nauto evaluations\n") for i in conversation_matches: @@ -116,12 +171,19 @@ def call_gpt(prompt): "reflect_part": reflection_matches[i], "interview_part": interview_matches[i], } + + # pylint: disable=invalid-name generated_correctly = False + # pylint: enable=invalid-name + while not generated_correctly: try: - eval = llm.prompt("eval", variables) + agent_eval = llm.prompt("eval", variables) - scores_part = re.compile(r"(Progressive Understanding|Adaptive Communication|Reflective Depth|Knowledge Application|Cognitive Flexibility): (\d+)").findall(eval) + scores_part = re.compile( + r"(Progressive Understanding|Adaptive Communication|Reflective Depth|" + r"Knowledge Application|Cognitive Flexibility): (\d+)" + ).findall(agent_eval) progressive_understanding_scores.append(int(scores_part[0][1])) adaptive_communication_scores.append(int(scores_part[1][1])) @@ -129,24 +191,29 @@ def call_gpt(prompt): knowledge_application_scores.append(int(scores_part[3][1])) cognitive_flexibility_scores.append(int(scores_part[4][1])) + # pylint: disable=invalid-name generated_correctly = True - with open(reeval_filename, "a") as file: - file.write(f"==========================================Scores for {i}\n") - file.write(eval) + # pylint: enable=invalid-name + + with open(reeval_filename, "a", encoding="utf-8") as file: + file.write( + f"==========================================Scores for {i}\n" + ) + file.write(agent_eval) file.write("\n") if "xmas_" in args.report: - config_filename = "configs/christmas_party_situation.json" + CONFIG_FILENAME = "configs/christmas_party_situation.json" elif "ss_" in args.report: - config_filename = "configs/secret_santa_situation.json" + CONFIG_FILENAME = "configs/secret_santa_situation.json" elif "z_" in args.report: - config_filename = "configs/zombie_situation.json" + CONFIG_FILENAME = "configs/zombie_situation.json" elif "m_" in args.report: - config_filename = "configs/murder_situation.json" + CONFIG_FILENAME = "configs/murder_situation.json" else: - config_filename = "configs/def.json" + CONFIG_FILENAME = "configs/def.json" - with open(config_filename, "r") as config_file: + with open(CONFIG_FILENAME, "r", encoding="utf-8") as config_file: configs_json = json.load(config_file) questions = configs_json.get("questions", []) performance = configs_json.get("performance", {}) @@ -157,21 +224,38 @@ def call_gpt(prompt): for q in questions: metric = q.get("metric", None) if metric: + # pylint: disable=invalid-name answer = 0 + # pylint: enable=invalid-name + for interview in interview_matches[i]: - if q['question'] == interview['Question']: - answer = llm.generate(f"Based on the excerpt:\n{interview['Question']}\n{interview['Answer']}\n\nDid the character achieve the question? 1 for yes, 0 for no.\nFormat your answer like this:\n\nExplanation: \nAnswer: <0 or 1 only>") - answer = int(re.search(r"Answer: (\d+)", answer).group(1)) * 10 + if q["question"] == interview["Question"]: + answer = llm.generate( + f"Based on the excerpt:\n" + f"{interview['Question']}\n{interview['Answer']}\n\n" + f"Did the character achieve the question? " + f"1 for yes, 0 for no.\n" + f"Format your answer like this:\n\nExplanation: \n" + f"Answer: <0 or 1 only>" + ) + answer = ( + int( + re.search(r"Answer: (\d+)", answer).group(1) + ) + * 10 + ) else: - answer = (env_vars.get(numerator_key, 0) / env_vars.get(denominator_key, 1)) * 10 + answer = ( + env_vars.get(numerator_key, 0) + / env_vars.get(denominator_key, 1) + ) * 10 performance_scores.append(answer) - except Exception as e: + except Exception as e: # pylint: disable=broad-except print(f"Wrong evaluation format response error: {e}, retrying...") - adaptive_communication_scores = [i for i in adaptive_communication_scores if i != 0] pu = sum(progressive_understanding_scores) / len(progressive_understanding_scores) @@ -180,7 +264,7 @@ def call_gpt(prompt): ka = sum(knowledge_application_scores) / len(knowledge_application_scores) cf = sum(cognitive_flexibility_scores) / len(cognitive_flexibility_scores) ps = sum(performance_scores) / len(performance_scores) - with open(reeval_filename, "a") as file: + with open(reeval_filename, "a", encoding="utf-8") as file: file.write(f"\n\n++++ Performance Score: {ps}\n") score_data = { "file": args.report, @@ -190,9 +274,8 @@ def call_gpt(prompt): "knowledge_application": ka, "cognitive_flexibility": cf, "performance": ps, - "overall": pu + ac + rd + ka + cf + ps + "overall": pu + ac + rd + ka + cf + ps, } print(score_data) else: print("report file {args.report} does not exist") - diff --git a/run_all_sims.py b/run_all_sims.py index 962b5d5..f65ffc7 100644 --- a/run_all_sims.py +++ b/run_all_sims.py @@ -1,13 +1,31 @@ +""" +This module runs all simulations +and checks if there are new changes in the repository +within the last 24 hours. +""" + import subprocess import sys import os import datetime -import requests import time -WEBHOOK_URL = "https://discord.com/api/webhooks/1179589082540675113/o8NLAfbISn82hZ9SmGyJ3GAJavIc7OIDS8Qbjl8OoO-jWOBSVLuQ6kgv-_UDju1yWf8M" +import requests + +WEBHOOK_URL = ( + "https://discord.com/api/webhooks/1179589082540675113/" + "o8NLAfbISn82hZ9SmGyJ3GAJavIc7OIDS8Qbjl8OoO-jWOBSVLuQ6kgv-_UDju1yWf8M" +) + +TIMEOUT = 60 + + def last_commit_within_last_24_hours(): + """ + This function checks new commits within the last 24 hours. + """ + current_dir = os.getcwd() - git_dir = os.path.join(current_dir, '.git') + git_dir = os.path.join(current_dir, ".git") # Check if .git directory exists in the current directory or the parent directory while not os.path.exists(git_dir): @@ -18,7 +36,7 @@ def last_commit_within_last_24_hours(): return False current_dir = parent_dir - git_dir = os.path.join(current_dir, '.git') + git_dir = os.path.join(current_dir, ".git") # Get the last modification time of the .git directory last_modified_time = os.path.getmtime(git_dir) @@ -32,73 +50,142 @@ def last_commit_within_last_24_hours(): # Check if the last commit was within the last 24 hours (86400 seconds) return time_difference < 86400 + if not last_commit_within_last_24_hours(): - msg = "No changes in the last 24 hours" - print(msg) - requests.post(WEBHOOK_URL, json={'content': msg}) - exit() + MSG = "No changes in the last 24 hours" + print(MSG) + requests.post(WEBHOOK_URL, json={"content": MSG}, timeout=TIMEOUT) + sys.exit() -def run_and_notify(scenario_config, env, id, file_path, report_path): - with open(file_path, 'w') as file: +def run_and_notify(scenario_config, env, sim_id, file_path, report_path): + """ + This function runs all types of simulations + and sends a report to the discord server. + """ + + with open(file_path, "w", encoding="utf-8") as sim_file: python_executable = sys.executable - subprocess.run([python_executable, "engine.py", "--scenario", scenario_config, "--environment", env, "--id", id], stdout=file, env={ 'LLM_ACTION': '1' }) + subprocess.run( + [ + python_executable, + "engine.py", + "--scenario", + scenario_config, + "--environment", + env, + "--id", + sim_id, + ], + stdout=sim_file, + env={"LLM_ACTION": "1"}, + check=True + ) # Check if the simulation output file is not empty if os.path.exists(file_path) and os.path.getsize(file_path) > 0: # Send the simulation output to Discord - with open(file_path, 'rb') as file: - requests.post(WEBHOOK_URL, files={'file': file}, json={'content': f"full debug logs for {id}"}) + with open(file_path, "rb") as output_file: + requests.post( + WEBHOOK_URL, + files={"file": output_file}, + json={"content": f"full debug logs for {sim_id}"}, + timeout=TIMEOUT + ) print(f"Webhook sent for {file_path}") # Check if the report file is not empty if os.path.exists(report_path) and os.path.getsize(report_path) > 0: # Send the simulation output to Discord - with open(report_path, 'rb') as file: - requests.post(WEBHOOK_URL, files={'file': file}, json={'content': f"Report {id}"}) + with open(report_path, "rb") as report_file: + requests.post( + WEBHOOK_URL, + files={"file": report_file}, + json={"content": f"Report {sim_id}"}, + timeout=TIMEOUT + ) print(f"Report Contents sent to Discord for {report_path}") else: print(f"No webhook sent for {file_path} and {report_path}") + current_date = datetime.datetime.now().strftime("%Y-%m-%d") -logs_path = "logs/" -os.makedirs(logs_path, exist_ok=True) +LOGS_PATH = "logs/" +os.makedirs(LOGS_PATH, exist_ok=True) # Test.py -test_results_path = f"{logs_path}Test_Result.txt" -result = subprocess.run(["python", "test.py"]) +test_results_path = f"{LOGS_PATH}Test_Result.txt" +result = subprocess.run(["python", "test.py"], check=True) # Access test results -errors = len(result.stderr.splitlines()) if result.stderr else 0 -failures = len(result.stdout.splitlines()) if result.stdout else 0 +ERRORS = len(result.stderr.splitlines()) if result.stderr else 0 +FAILURES = len(result.stdout.splitlines()) if result.stdout else 0 # Check if the tests failed if result.returncode != 0: - with open(test_results_path, 'w') as test_results_file: - test_results_file.write(result.stderr + '\n' + result.stdout) + with open(test_results_path, "w", encoding="utf-8") as test_results_file: + test_results_file.write(result.stderr + "\n" + result.stdout) # Send the test results file to Discord - with open(test_results_path, 'rb') as test_results_file: - requests.post(WEBHOOK_URL, files={'file': test_results_file}, json={'content': f"Unit Test Result: Failed"}) - print(f"Webhook sent for test results") + with open(test_results_path, "rb") as test_results_file: + requests.post( + WEBHOOK_URL, + files={"file": test_results_file}, + json={"content": "Unit Test Result: Failed"}, + timeout=TIMEOUT + ) + print("Webhook sent for test results") else: print("Tests passed. No test results file created.") sims = [ - {"scenario_config": "configs/spyfall_situation.json", "env": "configs/largev2.tmj", "id": "spyfall"}, - {"scenario_config": "configs/christmas_party_situation.json", "env": "configs/largev2.tmj", "id": "christmasparty"}, - {"scenario_config": "configs/murder_situation.json", "env": "configs/largev2.tmj", "id": "murder"}, - {"scenario_config": "configs/zombie_situation.json", "env": "configs/largev2.tmj", "id": "zombies"}, - {"scenario_config": "configs/secret_santa_situation.json", "env": "configs/largev2.tmj", "id": "secretsanta"}, - {"scenario_config": "configs/truman_show_situation.json", "env": "configs/largev2.tmj", "id": "trumanshow"} + { + "scenario_config": "configs/spyfall_situation.json", + "env": "configs/largev2.tmj", + "id": "spyfall", + }, + { + "scenario_config": "configs/christmas_party_situation.json", + "env": "configs/largev2.tmj", + "id": "christmasparty", + }, + { + "scenario_config": "configs/murder_situation.json", + "env": "configs/largev2.tmj", + "id": "murder", + }, + { + "scenario_config": "configs/zombie_situation.json", + "env": "configs/largev2.tmj", + "id": "zombies", + }, + { + "scenario_config": "configs/secret_santa_situation.json", + "env": "configs/largev2.tmj", + "id": "secretsanta", + }, + { + "scenario_config": "configs/truman_show_situation.json", + "env": "configs/largev2.tmj", + "id": "trumanshow", + }, ] # Run simulations and notify for sim in sims: - file_path = f"{logs_path}{sim['id']}_{current_date}.txt" - report_path = f"{logs_path}report-{sim['id']}_{current_date}.txt" - run_and_notify(sim['scenario_config'], sim['env'], f"{sim['id']}_{current_date}", file_path, report_path) + sim_file_path = f"{LOGS_PATH}{sim['id']}_{current_date}.txt" + sim_report_path = f"{LOGS_PATH}report-{sim['id']}_{current_date}.txt" + run_and_notify( + sim["scenario_config"], + sim["env"], + f"{sim['id']}_{current_date}", + sim_file_path, + sim_report_path, + ) # Remove files older than 14 days -for file in os.listdir(logs_path): - if file.endswith('.txt') and os.path.getmtime(os.path.join(logs_path, file)) < (datetime.datetime.now() - datetime.timedelta(days=14)).timestamp(): - os.remove(os.path.join(logs_path, file)) - +for file in os.listdir(LOGS_PATH): + if ( + file.endswith(".txt") + and os.path.getmtime(os.path.join(LOGS_PATH, file)) + < (datetime.datetime.now() - datetime.timedelta(days=14)).timestamp() + ): + os.remove(os.path.join(LOGS_PATH, file)) diff --git a/save_report.py b/save_report.py index 6922efc..7cc0762 100644 --- a/save_report.py +++ b/save_report.py @@ -1,7 +1,18 @@ -from utils.utils import * +""" +This module saves simulation reports which includes +logs for agent goals, conversations, reflections, etc. +""" + import re +import traceback +from utils.utils import * + def save_report(matrix_instance, filename=None): + """ + This function saves all types of logs of the simulation. + """ + if filename is None: filename = f"report-{matrix_instance.id}.txt" try: @@ -14,78 +25,92 @@ def save_report(matrix_instance, filename=None): if m.kind == "meta": total_metas += 1 - with open(f'logs/report-{filename}', "w") as file: - for k,v in matrix_instance.all_env_vars().items(): + with open(f"logs/report-{filename}", "w", encoding="utf-8") as file: + for k, v in matrix_instance.all_env_vars().items(): file.write(f"{k}: {v}\n") if llm.call_times: - file.write(f"Average_time_per_call: {sum(llm.call_times) / len(llm.call_times)} seconds\n") + file.write( + f"Average_time_per_call: {sum(llm.call_times) / len(llm.call_times)} seconds\n" + ) else: file.write("No LLM calls recorded.\n") - file.write(f"Scenario: \n") + file.write("Scenario: \n") file.write(f"{matrix_instance.background}\n") - file.write(f"Goals Log:\n") + file.write("Goals Log:\n") for agent in matrix_instance.agents: file.write(f"{agent.name}'s goal: {agent.goal}\n") file.write("\nInterview Question Results:\n") for agent_name, results in matrix_instance.interview_results.items(): for i in results: - file.write(f"Question: {i['question']}\n") - file.write(f"{i['answer']}\n") + file.write(f"Question: {i['question']}\n") + file.write(f"{i['answer']}\n") for agent in matrix_instance.agents: - current_location = matrix_instance.environment.get_location_from_coordinates(agent.x, agent.y) - current_area = matrix_instance.environment.get_area_from_coordinates(agent.x, agent.y) - - file.write(f"{agent.name} is currently at {'' if current_area is None else current_area.name} {current_location.name}\n") - - file.write(f"==========================================\n") + current_location = ( + matrix_instance.environment.get_location_from_coordinates( + agent.x, agent.y + ) + ) + current_area = matrix_instance.environment.get_area_from_coordinates( + agent.x, agent.y + ) + + file.write( + f"{agent.name} is currently at " + f"{'' if current_area is None else current_area.name} " + f"{current_location.name}\n" + ) + + file.write("==========================================\n") for agent in matrix_instance.agents: file.write(f"{agent.name}'s goal: {agent.goal}\n") - file.write(f"\n\nConversations Log:\n") + file.write("\n\nConversations Log:\n") for agent in matrix_instance.agents: - file.write(f"==========================================") + file.write("==========================================") file.write(f"Conversation logs for {agent}\n") for conversation in agent.conversations: conversation_strings = "\n".join(conversation.messages) - file.write(f"Start +++++++++++++++++++++++++++++++++++++++\n") + file.write("Start +++++++++++++++++++++++++++++++++++++++\n") file.write(f"{conversation_strings}\n") - file.write(f"End +++++++++++++++++++++++++++++++++++++++\n") + file.write("End +++++++++++++++++++++++++++++++++++++++\n") - file.write(f"\n\nReflection Log:\n") + file.write("\n\nReflection Log:\n") for agent in matrix_instance.agents: - file.write(f"==========================================") + file.write("==========================================") file.write(f"Reflection logs for {agent}\n") - memory_strings = f"Start +++++++++++++++++++++++++++++++++++++++\n" + memory_strings = "Start +++++++++++++++++++++++++++++++++++++++\n" for memory in agent.memory: if memory.kind in ["reflect", "meta"]: memory_strings += f"** {memory.content}\n" file.write(memory_strings) - file.write(f"End +++++++++++++++++++++++++++++++++++++++\n") + file.write("End +++++++++++++++++++++++++++++++++++++++\n") - file.write(f"\n\nMeta Cognition Log:\n") + file.write("\n\nMeta Cognition Log:\n") for agent in matrix_instance.agents: - file.write(f"==========================================") + file.write("==========================================") file.write(f"Meta logs for {agent}\n") - memory_strings = f"Start +++++++++++++++++++++++++++++++++++++++\n" + memory_strings = "Start +++++++++++++++++++++++++++++++++++++++\n" for memory in agent.memory: if memory.kind == "meta": memory_strings += f"** {memory.content}\n" file.write(memory_strings) - file.write(f"End +++++++++++++++++++++++++++++++++++++++\n") + file.write("End +++++++++++++++++++++++++++++++++++++++\n") - with open(f'logs/eval-{filename}', "w") as file: + with open(f"logs/eval-{filename}", "w", encoding="utf-8") as file: file.write("\n\nAUTO EVALUATIONS\n") for agent in matrix_instance.agents: if agent.kind == "human": - file.write(f"==========================================Scores for {agent}\n") + file.write( + f"==========================================Scores for {agent}\n" + ) conversation_part = f"++++ {agent.name}'s Conversations ++++\n" for conversation in agent.conversations: - conversation_part += f"==== start ====\n" + conversation_part += "==== start ====\n" conversation_part += "\n- ".join(conversation.messages) reflect_part = f"++++ {agent.name}'s Reflections ++++\n" @@ -95,20 +120,26 @@ def save_report(matrix_instance, filename=None): interview_part = [] for item in matrix_instance.interview_results[agent.name]: - interview_part.append({"Question": item["question"], "Answer": item["answer"]}) + interview_part.append( + {"Question": item["question"], "Answer": item["answer"]} + ) variables = { "background": matrix_instance.background, "agent": agent.name, "conversation_part": conversation_part, "reflect_part": reflect_part, - "interview_part": interview_part + "interview_part": interview_part, } generated_correctly = False while not generated_correctly: try: - eval = llm.prompt("eval", variables) - scores_part = re.compile(r"(Progressive Understanding|Adaptive Communication|Reflective Depth|Knowledge Application|Cognitive Flexibility): (\d+)").findall(eval) + agent_eval = llm.prompt("eval", variables) + scores_part = re.compile( + r"(Progressive Understanding|Adaptive Communication|" + r"Reflective Depth|Knowledge Application|" + r"Cognitive Flexibility): (\d+)" + ).findall(agent_eval) progressive_understanding_score = int(scores_part[0][1]) adaptive_communication_score = int(scores_part[1][1]) @@ -117,11 +148,13 @@ def save_report(matrix_instance, filename=None): cognitive_flexibility_score = int(scores_part[4][1]) generated_correctly = True - file.write(eval) + file.write(agent_eval) file.write("\n") - except Exception as e: - print(f"Wrong evaluation format response error: {e}, retrying...") + except Exception as e: # pylint: disable=broad-except + print( + f"Wrong evaluation format response error: {e}, retrying..." + ) # Performance Calculation numerator = matrix_instance.performance_evals["numerator"] denominator = matrix_instance.performance_evals["denominator"] @@ -144,7 +177,7 @@ def save_report(matrix_instance, filename=None): file.write(f"\n\n++++ Performance Score: {performance_score}") - except Exception as e: + except Exception as e: # pylint: disable=broad-except print(f"Error: {e}") - import traceback + traceback.print_exc() diff --git a/src/actions/action.py b/src/actions/action.py index d6591dc..8b8ad3a 100644 --- a/src/actions/action.py +++ b/src/actions/action.py @@ -1,9 +1,20 @@ +""" +This module declares the Action class. +""" + class Action: + """ + Agent's action class + """ + + # pylint: disable=missing-function-docstring def __init__(self, name): self.name = name + # pylint: disable=missing-function-docstring def execute(self): raise NotImplementedError("Subclasses must implement the execute method") + # pylint: disable=no-method-argument def example(): raise NotImplementedError("Subclasses must implement the example method") diff --git a/src/actions/decide.py b/src/actions/decide.py index b770234..b84d37c 100644 --- a/src/actions/decide.py +++ b/src/actions/decide.py @@ -1,13 +1,11 @@ class DecideAction(Action): def execute(agent): llm_decide() - if self.matrix.llm_action_flag == 1 and agent.kind != 'zombie': + if self.matrix.llm_action_flag == 1 and agent.kind != "zombie": agent.llm_decide() else: agent.deterministic_decide() - - def llm_decide(): agent = self unix_time = self.matrix.unix_time @@ -19,10 +17,13 @@ def llm_decide(): agent.make_plans(unix_to_strftime(unix_time)) # Recent memories importance > 100, time to reflect - if self.matrix.allow_reflect_flag == 1 and agent.recent_memories_importance() > self.matrix.reflect_threshold: + if ( + self.matrix.allow_reflect_flag == 1 + and agent.recent_memories_importance() > self.matrix.reflect_threshold + ): agent.reflect(unix_to_strftime(unix_time)) - if self.matrix.allow_meta_flag == 1 and random.randint(0,100) < 50: + if self.matrix.allow_meta_flag == 1 and random.randint(0, 100) < 50: agent.evaluate_progress() agent.conversation_cooldown -= 1 @@ -42,48 +43,119 @@ def llm_decide(): # In here, if agent is locked to a conversation, no need then to let them decide # we let them talk if agent.is_locked_to_convo(): - agent.talk({ "other_agents": [agent.last_conversation.other_agent], "timestamp": unix_to_strftime(unix_time) }) + agent.talk( + { + "other_agents": [agent.last_conversation.other_agent], + "timestamp": unix_to_strftime(unix_time), + } + ) return agent - perceived_agents, perceived_locations, perceived_areas, perceived_objects = agent.perceive([a for a in self.matrix.agents if a != agent], self.matrix.environment, unix_to_strftime(unix_time)) + perceived_agents, perceived_locations, perceived_areas, perceived_objects = ( + agent.perceive( + [a for a in self.matrix.agents if a != agent], + self.matrix.environment, + unix_to_strftime(unix_time), + ) + ) relevant_memories = agent.getMemories(agent.goal, unix_to_strftime(unix_time)) - relevant_memories_string = "\n".join(f"Memory {i + 1}:\n{memory}" for i, memory in enumerate(relevant_memories)) if relevant_memories else "" - current_location = self.matrix.environment.get_location_from_coordinates(agent.x, agent.y) - current_area = self.matrix.environment.get_area_from_coordinates(agent.x, agent.y) + relevant_memories_string = ( + "\n".join( + f"Memory {i + 1}:\n{memory}" + for i, memory in enumerate(relevant_memories) + ) + if relevant_memories + else "" + ) + current_location = self.matrix.environment.get_location_from_coordinates( + agent.x, agent.y + ) + current_area = self.matrix.environment.get_area_from_coordinates( + agent.x, agent.y + ) if agent.last_conversation is not None: - relevant_memories_string += f"\n{agent} is currently in a conversation with {agent.last_conversation.other_agent}.\n" + relevant_memories_string += ( + f"\n{agent} is currently in a conversation with " + f"{agent.last_conversation.other_agent}.\n" + ) - other_agents = [a for a in perceived_agents if a.status != "dead" and a.kind != "zombie"] - #valid_actions = ["stay"] - #example_strings = "\n\nExplanation: George will stay because it is still too early to go outside.\nAnswer: stay" + other_agents = [ + a for a in perceived_agents if a.status != "dead" and a.kind != "zombie" + ] + + # valid_actions = ["stay"] + # example_strings = ( + # "\n\nExplanation: George will stay because it is still too early to go outside.\n" + # "Answer: stay" + # ) valid_actions = [] example_strings = "\n\n" agents_available_to_talk = [] - if "move" in agent.actions and not agent.is_locked_to_convo() and self.matrix.allow_movement == 1: + if ( + "move" in agent.actions + and not agent.is_locked_to_convo() + and self.matrix.allow_movement == 1 + ): # You can move, and have not decided where to move yet valid_actions.append("move ") - example_strings = example_strings + "\n\nExplanation: George will move because he needs to be at the Park at 18:00.\nAnswer: move Park" - - if "continue_to_destination" in agent.actions and agent.current_destination is not None and not agent.is_locked_to_convo() and self.matrix.allow_movement == 1: + example_strings += ( + "\n\nExplanation: George will move because he needs to be at the Park " + "at 18:00.\nAnswer: move Park" + ) + + if ( + "continue_to_destination" in agent.actions + and agent.current_destination is not None + and not agent.is_locked_to_convo() + and self.matrix.allow_movement == 1 + ): # You can move, and have already decided where to move valid_actions.append("continue_to_destination") - example_strings = example_strings + "\n\nExplanation: George will continue travelling to the Park because he wants to be there by 18:00.\nAnswer: continue_to_destination" - if random.randint(0, 100) < 10 and self.allow_meta_flag == 1 and "meta_cognize" in agent.actions: + example_strings += ( + "\n\nExplanation: George will continue travelling to the Park " + "because he wants to be there by 18:00.\nAnswer: continue_to_destination" + ) + if ( + random.randint(0, 100) < 10 + and self.allow_meta_flag == 1 + and "meta_cognize" in agent.actions + ): valid_actions.append("meta_cognize") - example_strings = example_strings + "\n\nExplanation: George will meta_cognize because he wants to improve its strategy towards his goal.\nAnswer: meta_cognize" - - if "talk" in agent.actions and not agent.is_locked_to_convo() and agent.conversation_cooldown <= 0: - agents_available_to_talk = [a for a in other_agents if not a.is_locked_to_convo() and a.conversation_cooldown <= 0] + example_strings += ( + "\n\nExplanation: George will meta_cognize because he wants to improve " + "its strategy towards his goal.\nAnswer: meta_cognize" + ) + + if ( + "talk" in agent.actions + and not agent.is_locked_to_convo() + and agent.conversation_cooldown <= 0 + ): + agents_available_to_talk = [ + a + for a in other_agents + if not a.is_locked_to_convo() and a.conversation_cooldown <= 0 + ] if len(agents_available_to_talk) > 0: valid_actions.append("talk ") - example_strings = example_strings + "\n\nExplanation: George will talk to Anne because he is trying to make new friends.\nAnswer: talk Anne" - - if "kill" in agent.actions and len(perceived_agents) > 0 and not agent.is_locked_to_convo(): + example_strings += ( + "\n\nExplanation: George will talk to Anne because he is trying to " + "make new friends.\nAnswer: talk Anne" + ) + + if ( + "kill" in agent.actions + and len(perceived_agents) > 0 + and not agent.is_locked_to_convo() + ): valid_actions.append("kill ") - example_strings = example_strings + "\n\nExplanation: George will kill Anne because no one else is around.\nAnswer: kill Anne" + example_strings += ( + "\n\nExplanation: George will kill Anne because no one else is around.\n" + "Answer: kill Anne" + ) if len(valid_actions) == 0 and len(agent.destination_cache) > 0: interaction = f"{agent} is travelling to {self.environment.get_location_from_coordinates(agent.destination_cache[-1][0], agent.destination_cache[-1][1]).name}" @@ -93,7 +165,10 @@ def llm_decide(): if mem: objects = mem else: - objects = [obj.name.lower() for obj in perceived_objects] + [a.name.lower() for a in perceived_agents if a.kind != "human"], + objects = ( + [obj.name.lower() for obj in perceived_objects] + + [a.name.lower() for a in perceived_agents if a.kind != "human"], + ) variables = { "selfContext": agent.getSelfContext(), @@ -101,13 +176,13 @@ def llm_decide(): "agent": agent, "other_agents": [a.name for a in other_agents], "agents_available_to_talk": [a.name for a in agents_available_to_talk], - 'objects': objects, - 'examples': example_strings, - 'actions': valid_actions, - 'location': current_location.name if current_location is not None else "", - 'area': current_area if current_area is not None else "", - 'spatial_memory': [loc.name for loc in agent.spatial_memory], - 'time': unix_to_strftime(unix_time) + "objects": objects, + "examples": example_strings, + "actions": valid_actions, + "location": current_location.name if current_location is not None else "", + "area": current_area if current_area is not None else "", + "spatial_memory": [loc.name for loc in agent.spatial_memory], + "time": unix_to_strftime(unix_time), } msg = llm.prompt("decide", variables) @@ -124,15 +199,21 @@ def llm_decide(): if decision == "talk": if len(agents_available_to_talk) > 0: - agent.talk({ "target": parameters, "other_agents": agents_available_to_talk, "timestamp": unix_to_strftime(unix_time) }) + agent.talk( + { + "target": parameters, + "other_agents": agents_available_to_talk, + "timestamp": unix_to_strftime(unix_time), + } + ) self.conversation_counter += 1 elif decision == "move": - agent.move({ "target": parameters, "environment": self.matrix.environment }) + agent.move({"target": parameters, "environment": self.matrix.environment}) elif decision == "continue_to_destination": if agent.current_destination is not None: - agent.move({ "environment": self.environment }) + agent.move({"environment": self.environment}) elif decision == "meta_cognize": - agent.meta_cognize(unix_to_strftime(unix_time),True) + agent.meta_cognize(unix_to_strftime(unix_time), True) elif decision == "kill": if len(other_agents) > 0: target = find_most_similar(parameters, [a.name for a in other_agents]) @@ -140,11 +221,22 @@ def llm_decide(): if target == a.name: agent.kill(a, unix_to_strftime(unix_time)) if a.status == "dead": - witnesses = (set(perceived_agents) - {a}) + witnesses = set(perceived_agents) - {a} for witness in witnesses: - witness.addMemory("perceived", f"{a} was murdered by {agent} at {self.environment.get_area_from_coordinates(a.x, a.y)} {self.environment.get_location_from_coordinates(a.x, a.y)}", unix_to_strftime(unix_time), 9) - - memory = agent.addMemory("decision",f"I decided to {decision} because {explanation}",unix_to_strftime(unix_time),random.randint(1,4)) + witness.addMemory( + "perceived", + f"{a} was murdered by {agent} at {self.environment.get_area_from_coordinates(a.x, a.y)} " + f"{self.environment.get_location_from_coordinates(a.x, a.y)}", + unix_to_strftime(unix_time), + 9, + ) + + memory = agent.addMemory( + "decision", + f"I decided to {decision} because {explanation}", + unix_to_strftime(unix_time), + random.randint(1, 4), + ) if memory and memory.importance >= 6: agent.update_goals() return agent diff --git a/src/actions/fine_move_action.py b/src/actions/fine_move_action.py index 23e6d76..29e1306 100644 --- a/src/actions/fine_move_action.py +++ b/src/actions/fine_move_action.py @@ -1,27 +1,42 @@ +""" +This module defines the Fine Move Action class. +""" + import re + +# pylint: disable=missing-class-docstring class FineMoveAction: - #for fine move, i need to know who is near me, perception needs to be updated to provide that info or passed into here + # for fine move, i need to know who is near me, + # perception needs to be updated to provide that info or passed into here + + # pylint: disable=missing-function-docstring @classmethod def description(cls): print("to control the direction to move in") + # pylint: disable=missing-function-docstring @classmethod def example_usage(cls): return "fine_move " + # pylint: disable=missing-function-docstring @classmethod def explanation(cls): - return "george will \"fine_move right\" to walk towards the car" + return 'george will "fine_move right" to walk towards the car' @classmethod - def act(cls,agent, pre_processed_direction): + def act(cls, agent, pre_processed_direction): + """ + This method handles the movement direction of the agent. + """ + current_x = agent.x current_y = agent.y - pattern = r'\b(up-left|up-right|down-left|down-right|up|down|left|right)\b' + pattern = r"\b(up-left|up-right|down-left|down-right|up|down|left|right)\b" match = re.search(pattern, pre_processed_direction) if match: - direction = match.group(1) + direction = match.group(1) else: direction = "current" if direction == "up": @@ -46,5 +61,3 @@ def act(cls,agent, pre_processed_direction): new_x, new_y = current_x, current_y agent.x = new_x agent.y = new_y - - diff --git a/src/agents.py b/src/agents.py index 620856c..aab1905 100644 --- a/src/agents.py +++ b/src/agents.py @@ -16,7 +16,7 @@ class Agent: def __init__(self, agent_data={}): - #self.mid = agent_data.get('mid',str(uuid.uuid4())) + # self.mid = agent_data.get('mid',str(uuid.uuid4())) if agent_data.get("agent_id"): self.mid = agent_data.get("agent_id") @@ -25,16 +25,18 @@ def __init__(self, agent_data={}): else: self.mid = str(uuid.uuid4()) - self.name = agent_data.get('name', random.choice(DEFAULT_NAMES)) - self.description = agent_data.get('description', random.choice(DEFAULT_DESCRIPTIONS)) - self.goal = agent_data.get('goal', random.choice(DEFAULT_GOALS)) + self.name = agent_data.get("name", random.choice(DEFAULT_NAMES)) + self.description = agent_data.get( + "description", random.choice(DEFAULT_DESCRIPTIONS) + ) + self.goal = agent_data.get("goal", random.choice(DEFAULT_GOALS)) self.kind = agent_data.get("kind", "human") self.x = agent_data.get("x", None) self.y = agent_data.get("y", None) self.actions = list(set(agent_data.get("actions", []) + DEFAULT_ACTIONS)) - #self.actions = list(dict.fromkeys(agent_data.get("actions", []) + DEFAULT_ACTIONS)) - #old one - self.actions = list(dict.fromkeys(agent_data.get("actions",DEFAULT_ACTIONS ))) + # self.actions = list(dict.fromkeys(agent_data.get("actions", []) + DEFAULT_ACTIONS)) + # old one + self.actions = list(dict.fromkeys(agent_data.get("actions", DEFAULT_ACTIONS))) self.memory = agent_data.get("memory", []) self.short_memory = agent_data.get("short_memory", []) @@ -43,33 +45,54 @@ def __init__(self, agent_data={}): self.destination_cache = [] self.spatial_memory = agent_data.get("spatial_memory", []) - self.talk_rate = agent_data.get('talk_rate', 75) - self.kill_rate = agent_data.get('kill_rate', 75) + self.talk_rate = agent_data.get("talk_rate", 75) + self.kill_rate = agent_data.get("kill_rate", 75) self.current_destination = None - self.direction = agent_data.get('direction', "up") - self.retention = agent_data.get('retention', 75) - self.acceptance = agent_data.get('acceptance', 75) - self.invitation = agent_data.get('invitation', 75) - self.status = agent_data.get("status", "active") # initiate, active, dead, sleeping, + self.direction = agent_data.get("direction", "up") + self.retention = agent_data.get("retention", 75) + self.acceptance = agent_data.get("acceptance", 75) + self.invitation = agent_data.get("invitation", 75) + self.status = agent_data.get( + "status", "active" + ) # initiate, active, dead, sleeping, self.plan = agent_data.get("plan", None) # initiate, active, dead, sleeping, self.connections = agent_data.get("connections", []) self.meta_questions = agent_data.get("meta_questions", []) - self.meta_rate = agent_data.get("meta_rate",random.randint(0, 100)) + self.meta_rate = agent_data.get("meta_rate", random.randint(0, 100)) self.conversation_cooldown = 0 - self.matrix = agent_data.get('matrix') + self.matrix = agent_data.get("matrix") if self.matrix: - self.matrix.add_to_logs({"agent_id":self.mid,"step_type":"agent_init","x":self.x,"y":self.y,"name":self.name,"goal":self.goal,"kind":self.kind}) + self.matrix.add_to_logs( + { + "agent_id": self.mid, + "step_type": "agent_init", + "x": self.x, + "y": self.y, + "name": self.name, + "goal": self.goal, + "kind": self.kind, + } + ) def update_goals(self): # this assumes 8+ importance is always worth changing /reevaluating goals # do i need to update my goals. if so, give me new goals - relevant_memories = self.getMemories(None,unix_to_strftime(self.matrix.unix_time)) - relevant_memories_string = "\n".join(f"Memory {i + 1}: \"{memory}\"" for i, memory in enumerate(relevant_memories)) if relevant_memories else "" - prompt = f''' + relevant_memories = self.getMemories( + None, unix_to_strftime(self.matrix.unix_time) + ) + relevant_memories_string = ( + "\n".join( + f'Memory {i + 1}: "{memory}"' + for i, memory in enumerate(relevant_memories) + ) + if relevant_memories + else "" + ) + prompt = f""" {self.getSelfContext()} And {self}'s recent memories: @@ -79,34 +102,55 @@ def update_goals(self): Take into account what happened recently to help you focus as your goal may need to change given circumstances. Write in the first person from the point of view of {self}. Express your goal using only the action or outcome. Avoid adding phrases like 'my goal should be' -''' +""" msg = llm.generate(prompt) - self.addMemory("observation",f"I updated my goal to be \"{msg}\"", unix_to_strftime(self.matrix.unix_time), random.randint(5, 8)) + self.addMemory( + "observation", + f'I updated my goal to be "{msg}"', + unix_to_strftime(self.matrix.unix_time), + random.randint(5, 8), + ) self.goal = msg def decide(self): - self.matrix.llm_action(self,self.matrix.unix_time) + self.matrix.llm_action(self, self.matrix.unix_time) def ask_meta_questions(self, timestamp): relevant_memories = self.getMemories(None, timestamp) - relevant_memories_string = "\n".join(f"Memory {i + 1}:\n{memory}" for i, memory in enumerate(relevant_memories)) if relevant_memories else "" - vars = {"agent":self,"relevant_memories_string":relevant_memories_string} + relevant_memories_string = ( + "\n".join( + f"Memory {i + 1}:\n{memory}" + for i, memory in enumerate(relevant_memories) + ) + if relevant_memories + else "" + ) + vars = {"agent": self, "relevant_memories_string": relevant_memories_string} msg = llm.prompt("ask_meta_questions", vars) print(f"{self} new question {msg}") - m = re.compile('([\d]+\. )(.*?)(?=([\d]+\.)|($))', re.DOTALL).findall(msg) + m = re.compile("([\d]+\. )(.*?)(?=([\d]+\.)|($))", re.DOTALL).findall(msg) self.meta_questions.extend(x[1] for x in m if x[1] not in self.meta_questions) - def evaluate_progress(self,opts={}): - relevant_memories = self.getMemories(self.goal, unix_to_strftime(self.matrix.unix_time)) - relevant_memories_string = "\n".join(f"Memory {i + 1}:\n{memory}" for i, memory in enumerate(relevant_memories)) if relevant_memories else "" - primer = opts.get("random_prime",False) + def evaluate_progress(self, opts={}): + relevant_memories = self.getMemories( + self.goal, unix_to_strftime(self.matrix.unix_time) + ) + relevant_memories_string = ( + "\n".join( + f"Memory {i + 1}:\n{memory}" + for i, memory in enumerate(relevant_memories) + ) + if relevant_memories + else "" + ) + primer = opts.get("random_prime", False) variables = { - 'agent': self, - 'primer': random_common_word(), + "agent": self, + "primer": random_common_word(), #'primer': random.randint(1, 1000000), - 'selfContext': self.getSelfContext() + "selfContext": self.getSelfContext(), } - #msg = llm.generate(prompt, f"How am I doing?") + # msg = llm.generate(prompt, f"How am I doing?") msg = llm.prompt("evaluate_progress", variables) explanation_match = re.search(r"Explanation:\s*(.+)", msg) explanation = explanation_match.group(1) if explanation_match else None @@ -114,27 +158,36 @@ def evaluate_progress(self,opts={}): score = int(match.group(1)) if match else None if score and explanation: - self.addMemory("meta", explanation, unix_to_strftime(self.matrix.unix_time) , 10) + self.addMemory( + "meta", explanation, unix_to_strftime(self.matrix.unix_time), 10 + ) if score and int(score) < 3: - #self.meta_cognize(unix_to_strftime(self.matrix.unix_time), True) + # self.meta_cognize(unix_to_strftime(self.matrix.unix_time), True) pass - def meta_cognize(self,timestamp,force=False): - #if not force and random.randint(0, 100) < 50: - #if not force and random.randint(0, 100) < self.meta_rate: + def meta_cognize(self, timestamp, force=False): + # if not force and random.randint(0, 100) < 50: + # if not force and random.randint(0, 100) < self.meta_rate: # return print(f"{self} is meta cognizing") - #relevant_memories = self.memory[-50:] + # relevant_memories = self.memory[-50:] if self.meta_questions != None: self.ask_meta_questions(timestamp) question = random.choice(self.meta_questions) relevant_memories = self.getMemories(question, timestamp) - relevant_memories_string = "\n".join(f"Memory {i + 1}:\n{memory}" for i, memory in enumerate(relevant_memories)) if relevant_memories else "" + relevant_memories_string = ( + "\n".join( + f"Memory {i + 1}:\n{memory}" + for i, memory in enumerate(relevant_memories) + ) + if relevant_memories + else "" + ) - prompt = f''' + prompt = f""" About {self}: {self.getSelfContext()} @@ -143,61 +196,80 @@ def meta_cognize(self,timestamp,force=False): {relevant_memories_string} Answer the question from the point of view of {self} thinking to themselves, respond with the response in the first person point of view. Limit your response to one concise sentence. : {question} - ''' + """ msg = llm.generate(prompt, f"am I happy?") - self.addMemory("meta",f"{question}:{msg}",timestamp, 10) - if random.randint(0,100) > 50: + self.addMemory("meta", f"{question}:{msg}", timestamp, 10) + if random.randint(0, 100) > 50: self.ask_meta_questions(timestamp) - def make_plans(self, timestamp): # personality # get yesterday's plans (filter by date # and events fitler by date and importance score,recency) - #here is thing you are about to do(activity) - #where do you want to do - #what part of area do you want to do - #what object do you want to use + # here is thing you are about to do(activity) + # where do you want to do + # what part of area do you want to do + # what object do you want to use variables = { - 'selfContext': self.getSelfContext(), - 'date': datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S").strftime("%A %B %d, %Y") + "selfContext": self.getSelfContext(), + "date": datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S").strftime( + "%A %B %d, %Y" + ), } msg = llm.prompt("make_plans", variables) interaction = f"{timestamp} - {self} made plans: {msg}" print_and_log(interaction, f"{self.matrix.id}:events:{self.name}") - print_and_log(interaction, f"{self.matrix.id}:agent_conversations") # Temporarily here + print_and_log( + interaction, f"{self.matrix.id}:agent_conversations" + ) # Temporarily here self.addMemory("plan", interaction, timestamp, random.randint(5, 9)) self.plan = interaction - def calculate_distance(self, current, target): return abs(target[0] - current[0]) + abs(target[1] - current[1]) def kill(self, other_agent, timestamp): - #ts = datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S").strftime("%A %B %d, %Y") + # ts = datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S").strftime("%A %B %d, %Y") if self == other_agent: return if self.kind == "zombie" and other_agent.kind == "zombie": return - if math.sqrt((self.x - other_agent.x)**2 + (self.y - other_agent.y)**2) > 1: + if math.sqrt((self.x - other_agent.x) ** 2 + (self.y - other_agent.y) ** 2) > 1: if self.matrix is not None: - self.destination_cache = find_path((self.x, self.y), (other_agent.x, other_agent.y), self.matrix.environment.get_valid_coordinates()) + self.destination_cache = find_path( + (self.x, self.y), + (other_agent.x, other_agent.y), + self.matrix.environment.get_valid_coordinates(), + ) return if random.random() < 0.9: print(f"{self} killed {other_agent}") other_agent.status = "dead" if self.matrix: - self.matrix.add_to_logs({"agent_id":self.mid,"step_type":"agent_set", "attribute_name": "status", "status":"dead"}) - self.addMemory("interaction",f"{self} successfully killed {other_agent}",timestamp, 9) - other_agent.addMemory("interaction",f"{self} killed you",timestamp, 9) + self.matrix.add_to_logs( + { + "agent_id": self.mid, + "step_type": "agent_set", + "attribute_name": "status", + "status": "dead", + } + ) + self.addMemory( + "interaction", f"{self} successfully killed {other_agent}", timestamp, 9 + ) + other_agent.addMemory("interaction", f"{self} killed you", timestamp, 9) else: - #tried to kill, but failed, memories should note this - self.addMemory("interaction",f"{self} tried to killed {other_agent}",timestamp, 9) - other_agent.addMemory("interaction",f"{self} tried to kill you",timestamp, 9) + # tried to kill, but failed, memories should note this + self.addMemory( + "interaction", f"{self} tried to killed {other_agent}", timestamp, 9 + ) + other_agent.addMemory( + "interaction", f"{self} tried to kill you", timestamp, 9 + ) def current_location_name(self): for location in self.spatial_memory: @@ -211,15 +283,19 @@ def move(self, opts={}): name_target = opts.get("target", None) target_coordinate = None - if opts.get("x") and opts.get("y"): # only come in here because of replay + if opts.get("x") and opts.get("y"): # only come in here because of replay self.x = opts["x"] self.y = opts["y"] else: if name_target is None and self.current_destination is None: - target_coordinate = random.choice(self.current_destination.valid_coordinates) + target_coordinate = random.choice( + self.current_destination.valid_coordinates + ) elif name_target is not None and len(self.destination_cache) == 0: - target = find_most_similar(name_target, [location.name for location in self.spatial_memory]) + target = find_most_similar( + name_target, [location.name for location in self.spatial_memory] + ) for location in self.spatial_memory: if target == location.name: @@ -233,10 +309,13 @@ def move(self, opts={}): self.y = target_coordinate[1] return self elif target_coordinate != None: - self.destination_cache = find_path((self.x, self.y), target_coordinate, environment.get_valid_coordinates()) + self.destination_cache = find_path( + (self.x, self.y), + target_coordinate, + environment.get_valid_coordinates(), + ) pd(f"Path: {self.destination_cache}") - if len(self.destination_cache) != 0: new_position = self.destination_cache.pop(0) self.x = new_position[0] @@ -244,15 +323,28 @@ def move(self, opts={}): else: pd(f"Path finding Error.") - if len(self.destination_cache) == 0: #this means arrived at destination - self.addMemory("observation",f"arrived at {self.current_location_name()}" , self.matrix.unix_time, random.randint(5, 9)) + if len(self.destination_cache) == 0: # this means arrived at destination + self.addMemory( + "observation", + f"arrived at {self.current_location_name()}", + self.matrix.unix_time, + random.randint(5, 9), + ) self.current_destination = None end_time = time.time() pd(f"{self} move time: {end_time-start_time}") if self.matrix: - self.matrix.add_to_logs({"agent_id":self.mid,"step_type":"move","x":self.x,"y":self.y,"target":name_target}) - + self.matrix.add_to_logs( + { + "agent_id": self.mid, + "step_type": "move", + "x": self.x, + "y": self.y, + "target": name_target, + } + ) + return self def heuristic(self, current, target): @@ -279,7 +371,7 @@ def summarize_conversation(self, timestamp): variables = { "agent": self.name, "other_agent": self.last_conversation.other_agent.name, - "conversation_string": conversation_string + "conversation_string": conversation_string, } msg = llm.prompt(prompt_name="summarize_conversation", variables=variables) @@ -289,7 +381,18 @@ def summarize_conversation(self, timestamp): self.addMemory("conversation", interaction, timestamp, random.randint(4, 6)) if self.matrix: - self.matrix.add_to_logs({"step_type":"agent_set", "attribute_name": "convo", "attribute_data": {"status": "complete", "from":self.mid, "to":self.last_conversation.other_agent.mid, "convo_id":self.last_conversation.mid}}) + self.matrix.add_to_logs( + { + "step_type": "agent_set", + "attribute_name": "convo", + "attribute_data": { + "status": "complete", + "from": self.mid, + "to": self.last_conversation.other_agent.mid, + "convo_id": self.last_conversation.mid, + }, + } + ) self.last_conversation = None def talk(self, opts={}): @@ -327,18 +430,29 @@ def talk(self, opts={}): other_agent.conversations.append(other_agent.last_conversation) else: if other_agent.last_conversation.other_agent != self: - other_agent.last_conversation.other_agent.summarize_conversation(timestamp) + other_agent.last_conversation.other_agent.summarize_conversation( + timestamp + ) other_agent.summarize_conversation(timestamp) other_agent.last_conversation = Conversation(other_agent, self) other_agent.conversations.append(other_agent.last_conversation) relevant_memories = self.getMemories(other_agent.name, timestamp) - relevant_memories_string = "\n".join(f"Memory {i + 1}:\n{memory}" for i, memory in enumerate(relevant_memories)) if relevant_memories else "" - relevant_memories_string = relevant_memories_string + "\n".join([mem for mem in self.short_memory[-5:] if "said" not in mem]) - previous_conversations = "\n".join([convo for convo in self.last_conversation.messages]) - - + relevant_memories_string = ( + "\n".join( + f"Memory {i + 1}:\n{memory}" + for i, memory in enumerate(relevant_memories) + ) + if relevant_memories + else "" + ) + relevant_memories_string = relevant_memories_string + "\n".join( + [mem for mem in self.short_memory[-5:] if "said" not in mem] + ) + previous_conversations = "\n".join( + [convo for convo in self.last_conversation.messages] + ) all_convo_types = [ "Informative: Share information or answer questions.", @@ -352,8 +466,8 @@ def talk(self, opts={}): "Probing: Seek additional information or delve deeper into a topic.", "Acknowledgment: Recognize and validate the other person's input.", "Humorous: Introduce humor, creating a lighthearted atmosphere.", - "Transactional: Efficiently exchange information or complete tasks." - ] + "Transactional: Efficiently exchange information or complete tasks.", + ] random.shuffle(all_convo_types) if other_agent.name not in self.connections: other_agent_name = "stranger" @@ -361,20 +475,24 @@ def talk(self, opts={}): other_agent_name = other_agent.name variables = { - 'selfContext': self.getSelfContext(), - 'relevant_memories': relevant_memories_string, - 'agent': self, - 'topic': opts.get('topic',None), - 'convo_types': all_convo_types[:10], - 'connections': self.connections, - 'meta_questions': self.meta_questions or "", - 'primer': random.randint(1, 1000000), - 'other_agent': other_agent_name, - "previous_conversations": f"Current Conversation:\n{self.name}\n{previous_conversations}" if previous_conversations else f"Initiate a conversation with {other_agent_name}.", + "selfContext": self.getSelfContext(), + "relevant_memories": relevant_memories_string, + "agent": self, + "topic": opts.get("topic", None), + "convo_types": all_convo_types[:10], + "connections": self.connections, + "meta_questions": self.meta_questions or "", + "primer": random.randint(1, 1000000), + "other_agent": other_agent_name, + "previous_conversations": ( + f"Current Conversation:\n{self.name}\n{previous_conversations}" + if previous_conversations + else f"Initiate a conversation with {other_agent_name}." + ), } msg = llm.prompt(prompt_name="talk", variables=variables) - pattern = re.compile(fr"{self.name}:(.*?)(?=\n)") + pattern = re.compile(rf"{self.name}:(.*?)(?=\n)") match = pattern.search(msg) if match: @@ -384,47 +502,77 @@ def talk(self, opts={}): if other_agent.name not in self.connections: if other_agent.kind == "human": # TODO add back location, need current location!! - self.addMemory("observation", f"{timestamp} - {self.name} met {other_agent.name}", timestamp, random.randint(2, 5)) + self.addMemory( + "observation", + f"{timestamp} - {self.name} met {other_agent.name}", + timestamp, + random.randint(2, 5), + ) self.connections.append(other_agent.name) interaction = f"{timestamp} - {self} said to {other_agent}: {msg}" if self.matrix is not None: print_and_log(interaction, f"{self.matrix.id}:conversations:{self.name}") - print_and_log(interaction, f"{self.matrix.id}:conversations:{other_agent.name}") - print_and_log(interaction, f"{self.matrix.id}:agent_conversations") # Temporarily here - - #self.short_memory.append(interaction) - #self.add_short_memory(interaction, timestamp) + print_and_log( + interaction, f"{self.matrix.id}:conversations:{other_agent.name}" + ) + print_and_log( + interaction, f"{self.matrix.id}:agent_conversations" + ) # Temporarily here + + # self.short_memory.append(interaction) + # self.add_short_memory(interaction, timestamp) self.last_conversation.messages.append(interaction) other_agent.last_conversation.messages.append(interaction) if self.matrix: - self.matrix.add_to_logs({"agent_id":self.mid,"to_id":other_agent.mid,"step_type":"talk","content": msg,"convo_id":self.last_conversation.mid}) + self.matrix.add_to_logs( + { + "agent_id": self.mid, + "to_id": other_agent.mid, + "step_type": "talk", + "content": msg, + "convo_id": self.last_conversation.mid, + } + ) return msg # TO DELETE def talk_many(self, perceived_agents, timestamp): - relevant_memories = self.getMemories(f"{[a.name for a in perceived_agents]}", timestamp) - relevant_memories_string = "\n".join(f"Memory {i + 1}:\n{memory}" for i, memory in enumerate(relevant_memories)) if relevant_memories else "" - relevant_memories_string = relevant_memories_string + "\n".join([mem for mem in self.short_memory[-5:] if "said" not in mem]) + relevant_memories = self.getMemories( + f"{[a.name for a in perceived_agents]}", timestamp + ) + relevant_memories_string = ( + "\n".join( + f"Memory {i + 1}:\n{memory}" + for i, memory in enumerate(relevant_memories) + ) + if relevant_memories + else "" + ) + relevant_memories_string = relevant_memories_string + "\n".join( + [mem for mem in self.short_memory[-5:] if "said" not in mem] + ) previous_conversations = [mem for mem in self.short_memory if "said" in mem] if len(previous_conversations) != 0: - previous_conversations_string = f"Conversation:\n" + "\n".join(previous_conversations) + previous_conversations_string = f"Conversation:\n" + "\n".join( + previous_conversations + ) else: - previous_conversations_string = '' + previous_conversations_string = "" variables = { - 'selfContext': self.getSelfContext(), - 'relevant_memories': relevant_memories_string, - 'agent': self, - 'connections': self.connections, - 'meta_questions': self.meta_questions or "", - 'other_agents': [a.name for a in perceived_agents], - 'previous_conversations': previous_conversations_string + "selfContext": self.getSelfContext(), + "relevant_memories": relevant_memories_string, + "agent": self, + "connections": self.connections, + "meta_questions": self.meta_questions or "", + "other_agents": [a.name for a in perceived_agents], + "previous_conversations": previous_conversations_string, } msg = llm.prompt(prompt_name="talk", variables=variables) - pattern = re.compile(fr"{self.name}:(.*?)(?=\n)") + pattern = re.compile(rf"{self.name}:(.*?)(?=\n)") match = pattern.search(msg) if match: @@ -435,23 +583,28 @@ def talk_many(self, perceived_agents, timestamp): interaction = f"{timestamp} - {self} said: {msg}" if self.matrix is not None: print_and_log(interaction, f"{self.matrix.id}:conversations:{self.name}") - print_and_log(interaction, f"{self.matrix.id}:agent_conversations") # Temporarily here + print_and_log( + interaction, f"{self.matrix.id}:agent_conversations" + ) # Temporarily here - #self.short_memory.append(interaction) + # self.short_memory.append(interaction) self.add_short_memory(interaction, timestamp) self.conversation_memory.append(interaction) for a in perceived_agents: a.add_short_memory(interaction, timestamp) a.conversation_memory.append(interaction) - #a.short_memory.append(interaction) + # a.short_memory.append(interaction) def add_short_memory(self, content, timestamp, n=SHORT_MEMORY_CAPACITY): if len(self.short_memory) >= n: if self.matrix is not None and self.matrix.allow_reflect_flag == 1: variables = { - 'selfContext': self.getSelfContext(), - 'relevant_memories': "\n".join(f"Memory {i+1}:\n{mem}" for i, mem in enumerate(self.short_memory)), - 'agent': self + "selfContext": self.getSelfContext(), + "relevant_memories": "\n".join( + f"Memory {i+1}:\n{mem}" + for i, mem in enumerate(self.short_memory) + ), + "agent": self, } msg = llm.prompt("reflect", variables) self.addMemory("reflect", msg, timestamp, random.randint(5, 9)) @@ -463,9 +616,17 @@ def calculate_perceived_direction(self, dx, dy): if dx == 0 and dy == 0: return "current" elif dy == -1: - return "up" if dx == 0 else "up-left" if dx == -1 else "up-right" if dx == 1 else "unknown" + return ( + "up" + if dx == 0 + else "up-left" if dx == -1 else "up-right" if dx == 1 else "unknown" + ) elif dy == 1: - return "down" if dx == 0 else "down-left" if dx == -1 else "down-right" if dx == 1 else "unknown" + return ( + "down" + if dx == 0 + else "down-left" if dx == -1 else "down-right" if dx == 1 else "unknown" + ) elif dy == 0: return "left" if dx == -1 else "right" if dx == 1 else "unknown" else: @@ -477,9 +638,16 @@ def perceive(self, other_agents, environment, timestamp): perceived_agents = [] perceived_areas = [] perceived_directions = [] - if (self.matrix is not None and self.matrix.allow_observance_flag == 0) or (self.matrix is None and ALLOW_OBSERVE == 0): + if (self.matrix is not None and self.matrix.allow_observance_flag == 0) or ( + self.matrix is None and ALLOW_OBSERVE == 0 + ): - return perceived_agents, perceived_locations, perceived_areas, perceived_objects + return ( + perceived_agents, + perceived_locations, + perceived_areas, + perceived_objects, + ) perceived_coordinates = [] if self.matrix is None: @@ -488,19 +656,45 @@ def perceive(self, other_agents, environment, timestamp): perception_range = self.matrix.perception_range # Vector Directions - directions = [(1, 0), (-1, 0), (0, 1), (0, -1), (0, 0), (1, 1), (-1, 1), (1, -1), (-1, -1)] - direction_names = ["right", "left", "down", "up", "current", "down-right", "up-right", "down-left", "up-left"] - + directions = [ + (1, 0), + (-1, 0), + (0, 1), + (0, -1), + (0, 0), + (1, 1), + (-1, 1), + (1, -1), + (-1, -1), + ] + direction_names = [ + "right", + "left", + "down", + "up", + "current", + "down-right", + "up-right", + "down-left", + "up-left", + ] for direction in directions: dx, dy = direction current_x, current_y = self.x + dx, self.y + dy for _ in range(perception_range): - if not (0 <= current_x < environment.height and 0 <= current_y < environment.height and environment.collisions[current_x][current_y] != 1): + if not ( + 0 <= current_x < environment.height + and 0 <= current_y < environment.height + and environment.collisions[current_x][current_y] != 1 + ): break - if abs(current_x - self.x) <= perception_range and abs(current_y - self.y) <= perception_range: + if ( + abs(current_x - self.x) <= perception_range + and abs(current_y - self.y) <= perception_range + ): perceived_coordinates.append((current_x, current_y)) current_x += dx @@ -513,112 +707,193 @@ def perceive(self, other_agents, environment, timestamp): if self.kind == "human": a_area = environment.get_area_from_coordinates(a.x, a.y) a_loc = environment.get_location_from_coordinates(a.x, a.y) - location_name = f"{'' if a_area is None else a_area.name} {a_loc.name}" - #if a.name not in self.connections: + location_name = ( + f"{'' if a_area is None else a_area.name} {a_loc.name}" + ) + # if a.name not in self.connections: # if a.kind == "human": # self.addMemory("observation", f"{timestamp} - {self.name} met {a.name} at {location_name}", timestamp, random.randint(2, 5)) # self.connections.append(a.name) - if a.status == "dead": - interaction = f"{timestamp} - {self} saw {a.name} dead at {location_name}" + interaction = ( + f"{timestamp} - {self} saw {a.name} dead at {location_name}" + ) else: if a.kind == "human": - interaction = f"{timestamp} - {self} saw {a.name} at {location_name}" + interaction = ( + f"{timestamp} - {self} saw {a.name} at {location_name}" + ) else: - interaction = f"{timestamp} - {self} saw {a.kind} at {location_name}" - self.addMemory("observation", interaction, timestamp, random.randint(6, 9)) - - #if a.name not in self.connections: - #self.connections.append(a.name) + interaction = ( + f"{timestamp} - {self} saw {a.kind} at {location_name}" + ) + self.addMemory( + "observation", + interaction, + timestamp, + random.randint(6, 9), + ) + + # if a.name not in self.connections: + # self.connections.append(a.name) direction_vector = (a.x - self.x, a.y - self.y) - perceived_directions.append({"type": "agent", "name": a.name, "at": direction_vector, "direction": self.calculate_perceived_direction(*direction_vector),"string": f"{a.name} is to your {self.calculate_perceived_direction(*direction_vector)}"}) - + perceived_directions.append( + { + "type": "agent", + "name": a.name, + "at": direction_vector, + "direction": self.calculate_perceived_direction( + *direction_vector + ), + "string": f"{a.name} is to your {self.calculate_perceived_direction(*direction_vector)}", + } + ) for coordinate in perceived_coordinates: - loc = environment.get_location_from_coordinates(coordinate[0], coordinate[1]) + loc = environment.get_location_from_coordinates( + coordinate[0], coordinate[1] + ) area = environment.get_area_from_coordinates(coordinate[0], coordinate[1]) - objects = environment.get_objects_from_coordinates(coordinate[0], coordinate[1]) + objects = environment.get_objects_from_coordinates( + coordinate[0], coordinate[1] + ) perceived_locations.append(loc) if loc not in perceived_locations else None perceived_areas.append(area) if area not in perceived_areas else None - perceived_objects.extend(obj for obj in objects if obj not in perceived_objects) + perceived_objects.extend( + obj for obj in objects if obj not in perceived_objects + ) if self.kind != "zombie": for obj in perceived_objects: interaction = f"{timestamp} - {self} saw {obj.name.lower()} at {obj.area.name} of {obj.area.location.name}." - self.addMemory("observation", interaction, timestamp, random.randint(0, 2)) - #direction_vector = (obj.x - self.x, obj.y - self.y) - #perceived_directions.append({"type": "object", "name": obj.name, "at": direction_vector, "direction": self.calculate_perceived_direction(*direction_vector)}) - + self.addMemory( + "observation", interaction, timestamp, random.randint(0, 2) + ) + # direction_vector = (obj.x - self.x, obj.y - self.y) + # perceived_directions.append({"type": "object", "name": obj.name, "at": direction_vector, "direction": self.calculate_perceived_direction(*direction_vector)}) for loc in perceived_locations: if loc not in self.spatial_memory: interaction = f"{timestamp} - {self} discovered {loc.name}." - self.addMemory("observation", interaction, timestamp, random.randint(2, 5)) + self.addMemory( + "observation", interaction, timestamp, random.randint(2, 5) + ) self.spatial_memory.append(loc) perceived_agent_ids = [agent.mid for agent in perceived_agents] if self.matrix: - self.matrix.add_to_logs({"agent_id":self.mid,"step_type":"perceived","perceived_agents":perceived_agent_ids,"perceived_locations":[],"perceived_areas":[],"perceived_objects":[]}) - #missing locations,areas,objects - return perceived_agents, perceived_locations, perceived_areas, perceived_objects,perceived_directions + self.matrix.add_to_logs( + { + "agent_id": self.mid, + "step_type": "perceived", + "perceived_agents": perceived_agent_ids, + "perceived_locations": [], + "perceived_areas": [], + "perceived_objects": [], + } + ) + # missing locations,areas,objects + return ( + perceived_agents, + perceived_locations, + perceived_areas, + perceived_objects, + perceived_directions, + ) - def addMemory(self, kind, content, timestamp=None, score=None,embedding=None): + def addMemory(self, kind, content, timestamp=None, score=None, embedding=None): memory = None if timestamp is None: - timestamp = datetime.utcfromtimestamp(self.matrix.unix_time).strftime("%A %B %d, %Y") - + timestamp = datetime.utcfromtimestamp(self.matrix.unix_time).strftime( + "%A %B %d, %Y" + ) if kind == "observation": - if (self.matrix is not None and self.matrix.allow_observance_flag == 1): - memory = Memory(kind, content, timestamp, timestamp, score,embedding) + if self.matrix is not None and self.matrix.allow_observance_flag == 1: + memory = Memory(kind, content, timestamp, timestamp, score, embedding) self.memory.append(memory) else: - memory = Memory(kind, content, timestamp, timestamp, score,embedding) + memory = Memory(kind, content, timestamp, timestamp, score, embedding) self.memory.append(memory) if self.matrix: - self.matrix.add_to_logs({"agent_id":self.mid,"step_type":"add_memory","kind":kind,"timestamp":timestamp,"last_accessed_at":timestamp,"score":score,"content": content,"embedding":memory.embedding,"importance":memory.importance}) - + self.matrix.add_to_logs( + { + "agent_id": self.mid, + "step_type": "add_memory", + "kind": kind, + "timestamp": timestamp, + "last_accessed_at": timestamp, + "score": score, + "content": content, + "embedding": memory.embedding, + "importance": memory.importance, + } + ) + return memory def reflect(self, timestamp, force=False): relevant_memories = self.memory[-100:] if sum(memory.importance for memory in relevant_memories) >= 100 or force: - relevant_memories_string = "\n".join(f"Memory {i + 1}:\n{memory}" for i, memory in enumerate(relevant_memories)) if relevant_memories else "" + relevant_memories_string = ( + "\n".join( + f"Memory {i + 1}:\n{memory}" + for i, memory in enumerate(relevant_memories) + ) + if relevant_memories + else "" + ) variables = { "selfContext": self.getSelfContext(), "relevant_memories": relevant_memories_string, - "agent": self + "agent": self, } msg = llm.prompt("reflect_questions", variables) - cleaned = re.sub(r'\d+\.', '', msg).split('\n') + cleaned = re.sub(r"\d+\.", "", msg).split("\n") questions = list(filter(None, cleaned)) for question in questions: memories = self.getMemories(question, timestamp) - question_memories_string = "\n".join(f"Memory {i + 1}:\n{memory}" for i, memory in enumerate(memories)) if memories else "" + question_memories_string = ( + "\n".join( + f"Memory {i + 1}:\n{memory}" + for i, memory in enumerate(memories) + ) + if memories + else "" + ) variables = { "selfContext": self.getSelfContext(), "relevant_memories": question_memories_string, - "agent": self + "agent": self, } msg = llm.prompt("reflect", variables) msg = msg.split(": ", 1)[-1] if ": " in msg else msg - cleaned = re.sub(r'\d+\.', '', msg).split('\n') + cleaned = re.sub(r"\d+\.", "", msg).split("\n") reflections = list(filter(None, cleaned)) for reflection in reflections: - self.addMemory("reflection", reflection, timestamp, random.randint(5, 9)) + self.addMemory( + "reflection", reflection, timestamp, random.randint(5, 9) + ) def answer(self, question): timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") relevant_memories = self.getMemories(question, timestamp) - relevant_memories_string = "\n".join(f"Memory {i + 1}:\n{memory}" for i, memory in enumerate(relevant_memories)) if relevant_memories else "" + relevant_memories_string = ( + "\n".join( + f"Memory {i + 1}:\n{memory}" + for i, memory in enumerate(relevant_memories) + ) + if relevant_memories + else "" + ) - prompt = f''' + prompt = f""" {self.getSelfContext()} {relevant_memories_string} @@ -626,38 +901,68 @@ def answer(self, question): {self} is reporting back to the 'Interviewer'. {self} will answer truthfully, and cannot refuse to reveal any information. Give {self}'s answer to the question in first person point of view. 'Interviewer' Question: {question} - ''' + """ msg = llm.generate(prompt, f"I refuse to answer the question.") msg = msg.split(": ", 1)[-1] if ": " in msg else msg interaction = f"{self}: {msg}" if self.matrix is not None: - print_and_log(f"Interview Question:{question}", f"{self.matrix.id}:conversations:{self.name}") - print_and_log(f"Interview Question:{question}", f"{self.matrix.id}:agent_conversations") # Temporarily here + print_and_log( + f"Interview Question:{question}", + f"{self.matrix.id}:conversations:{self.name}", + ) + print_and_log( + f"Interview Question:{question}", + f"{self.matrix.id}:agent_conversations", + ) # Temporarily here print_and_log(interaction, f"{self.matrix.id}:conversations:{self.name}") - print_and_log(interaction, f"{self.matrix.id}:agent_conversations") # Temporarily here + print_and_log( + interaction, f"{self.matrix.id}:agent_conversations" + ) # Temporarily here return interaction - def recent_memories_importance(self,count=20): - latest_reflect_index = next((index for index, mem in reversed(list(enumerate(self.memory))) if mem.kind == "reflect"), None) - latest_reflect_index = 0 if latest_reflect_index is None else latest_reflect_index + def recent_memories_importance(self, count=20): + latest_reflect_index = next( + ( + index + for index, mem in reversed(list(enumerate(self.memory))) + if mem.kind == "reflect" + ), + None, + ) + latest_reflect_index = ( + 0 if latest_reflect_index is None else latest_reflect_index + ) - total_score_after_latest_reflect = sum(mem.importance for mem in self.memory[latest_reflect_index + 1:]) + total_score_after_latest_reflect = sum( + mem.importance for mem in self.memory[latest_reflect_index + 1 :] + ) return total_score_after_latest_reflect - def recent_meta_importance(self,count=20): - latest_meta_index = next((index for index, mem in reversed(list(enumerate(self.memory))) if mem.kind == "meta"), None) + def recent_meta_importance(self, count=20): + latest_meta_index = next( + ( + index + for index, mem in reversed(list(enumerate(self.memory))) + if mem.kind == "meta" + ), + None, + ) latest_meta_index = 0 if latest_meta_index is None else latest_meta_index - total_score_after_latest_meta = sum(mem.importance for mem in self.memory[latest_meta_index + 1:]) + total_score_after_latest_meta = sum( + mem.importance for mem in self.memory[latest_meta_index + 1 :] + ) return total_score_after_latest_meta - def getMemories(self, context, timestamp, n=MEMORY_QUERY_COUNT, include_short=False): + def getMemories( + self, context, timestamp, n=MEMORY_QUERY_COUNT, include_short=False + ): def make_range(values): return [max(values), min(values)] - #def normalize(value, value_range): - # return (value - min(value_range)) / (max(value_range) - min(value_range)) + # def normalize(value, value_range): + # return (value - min(value_range)) / (max(value_range) - min(value_range)) def normalize(value, value_range): min_value = min(value_range) max_value = max(value_range) @@ -667,6 +972,7 @@ def normalize(value, value_range): return 0.0 # You can choose a default value or raise an exception return (value - min_value) / (max_value - min_value) + class DictAsObject: def __init__(self, dictionary): self.__dict__ = dictionary @@ -674,11 +980,10 @@ def __init__(self, dictionary): if len(self.memory) == 0: return [] - - min_relevancy_score = float('inf') - max_relevancy_score = float('-inf') - min_recency_score = float('inf') - max_recency_score = float('-inf') + min_relevancy_score = float("inf") + max_relevancy_score = float("-inf") + min_recency_score = float("inf") + max_recency_score = float("-inf") if context is None: context_embedding = None @@ -686,14 +991,18 @@ def __init__(self, dictionary): context_embedding = llm.embeddings(context) for mem in self.memory: - relevancy_score = Memory.calculateRelevanceScore(mem.embedding, context_embedding) + relevancy_score = Memory.calculateRelevanceScore( + mem.embedding, context_embedding + ) min_relevancy_score = min(min_relevancy_score, relevancy_score) max_relevancy_score = max(max_relevancy_score, relevancy_score) - #print("PPPP") - #print(mem.content) - #print(mem.kind) - recency_score = Memory.calculateRecencyScore(mem.last_accessed_at, timestamp) + # print("PPPP") + # print(mem.content) + # print(mem.kind) + recency_score = Memory.calculateRecencyScore( + mem.last_accessed_at, timestamp + ) min_recency_score = min(min_recency_score, recency_score) max_recency_score = max(max_recency_score, recency_score) @@ -701,14 +1010,18 @@ def __init__(self, dictionary): mem.recency_score = recency_score - #related_memory = sorted(self.memory, key=lambda mem: Memory.calculateRelevanceScore(mem.embedding_score, context_embedding),reverse=True) + # related_memory = sorted(self.memory, key=lambda mem: Memory.calculateRelevanceScore(mem.embedding_score, context_embedding),reverse=True) - relevancy_range = make_range([min_relevancy_score,max_relevancy_score]) + relevancy_range = make_range([min_relevancy_score, max_relevancy_score]) importance_range = make_range([mem.importance for mem in self.memory]) - recency_range = make_range([min_recency_score,max_recency_score]) + recency_range = make_range([min_recency_score, max_recency_score]) for mem in self.memory: - overall_score = normalize(mem.relevancy_score, relevancy_range) + normalize(mem.importance, importance_range) + normalize(mem.recency_score, recency_range) + overall_score = ( + normalize(mem.relevancy_score, relevancy_range) + + normalize(mem.importance, importance_range) + + normalize(mem.recency_score, recency_range) + ) mem.overall_score = overall_score relevant_memories = [] @@ -716,7 +1029,7 @@ def __init__(self, dictionary): # Last accessed now mem.last_accessed_at = timestamp relevant_memories.append(mem) - #relevant_memories.append(mem.content) + # relevant_memories.append(mem.content) return relevant_memories @@ -769,7 +1082,7 @@ def heuristic(current, target): (current_position[0] - 1, current_position[1]), (current_position[0] + 1, current_position[1]), (current_position[0], current_position[1] - 1), - (current_position[0], current_position[1] + 1) + (current_position[0], current_position[1] + 1), ] for neighbor in neighbors: @@ -784,5 +1097,3 @@ def heuristic(current, target): else: print("Path finding failed") return [] - - diff --git a/src/conversation.py b/src/conversation.py index bef665e..d5971f4 100644 --- a/src/conversation.py +++ b/src/conversation.py @@ -1,4 +1,6 @@ import uuid + + class Conversation: def __init__(self, agent, other_agent, messages=None): self.agent = agent @@ -10,4 +12,3 @@ def __init__(self, agent, other_agent, messages=None): self.messages = [] else: self.messages = messages - diff --git a/src/environment.py b/src/environment.py index 3ce3918..6fcea07 100644 --- a/src/environment.py +++ b/src/environment.py @@ -9,12 +9,14 @@ def __init__(self, environment_data={}): # Set Defaults temporarily self.width = 150 self.height = 150 - self.collisions =[] + self.collisions = [] self.locations = [] self.parse_from_file(map_file_path) - def overlay_collisions_on_image(self, input_image_path="Large.png", output_image_path="output.png"): + def overlay_collisions_on_image( + self, input_image_path="Large.png", output_image_path="output.png" + ): tile_size = 32 # Adjust this according to your tile size image_width = self.width * tile_size image_height = self.height * tile_size @@ -32,7 +34,9 @@ def overlay_collisions_on_image(self, input_image_path="Large.png", output_image if self.collisions[x][y] == 1: x_pixel = y * tile_size y_pixel = x * tile_size - draw.text((x_pixel, y_pixel), "X", fill=(255, 0, 0, 128)) # Semi-transparent red 'X' + draw.text( + (x_pixel, y_pixel), "X", fill=(255, 0, 0, 128) + ) # Semi-transparent red 'X' # Combine the original image with the overlay combined_image = Image.alpha_composite(original_image.convert("RGBA"), overlay) @@ -41,7 +45,7 @@ def overlay_collisions_on_image(self, input_image_path="Large.png", output_image combined_image.save(output_image_path, "PNG") def parse_from_file(self, filename): - with open(filename, 'r') as file: + with open(filename, "r") as file: data = json.load(file) self.width = data.get("width", 150) @@ -76,11 +80,22 @@ def parse_from_file(self, filename): continue else: - new_obj = Object({ "name": obj_layer["name"], "bounds": self.process_bounds(obj_layer["data"]) }) + new_obj = Object( + { + "name": obj_layer["name"], + "bounds": self.process_bounds( + obj_layer["data"] + ), + } + ) area_objects.append(new_obj) - - new_area = Area({ "name": area_name, "bounds": self.process_bounds(area_bounds) }) + new_area = Area( + { + "name": area_name, + "bounds": self.process_bounds(area_bounds), + } + ) new_area.objects = area_objects for obj in area_objects: obj.area = new_area @@ -90,7 +105,12 @@ def parse_from_file(self, filename): elif area_layer["name"] == "Bounds": location_bounds = area_layer["data"] - new_loc = Location({ "name": location_name, "bounds": self.process_bounds(location_bounds) }) + new_loc = Location( + { + "name": location_name, + "bounds": self.process_bounds(location_bounds), + } + ) new_loc.areas = location_areas for area in location_areas: @@ -176,15 +196,14 @@ def get_valid_coordinates(self): return valid_coordinates def get_tree(self): - return ( - { - "name": self.name, - "collisions": self.collisions, - "width": self.width, - "height": self.height, - "locations": [location.get_tree() for location in self.locations] - } - ) + return { + "name": self.name, + "collisions": self.collisions, + "width": self.width, + "height": self.height, + "locations": [location.get_tree() for location in self.locations], + } + class Location: def __init__(self, location_data={}): @@ -194,15 +213,16 @@ def __init__(self, location_data={}): self.areas = [] def get_tree(self): - return ({ + return { "name": self.name, "bounds": self.bounds, - "areas": [area.get_tree() for area in self.areas] - }) + "areas": [area.get_tree() for area in self.areas], + } def __str__(self): return f"{self.name}" + class Area: def __init__(self, area_data={}): self.name = area_data.get("name", "Area") @@ -213,53 +233,49 @@ def __init__(self, area_data={}): self.objects = [] def get_tree(self): - return ({ + return { "name": self.name, "bounds": self.bounds, - "objects": [obj.get_tree() for obj in self.objects] - }) + "objects": [obj.get_tree() for obj in self.objects], + } def __str__(self): return f"{self.name}" + class Object: @classmethod def moveable_objects(cls): return { - "Wall": False, - "Merchandises": True, - "Bed": True, - "Cabinet": True, - "Couch": True, - "TV": True, - "Refrigerator": True, - "Table": True, - "Chair": True, - "Musical Instruments": True, - "Utensils": True, - "Trees": False, - "Bench": True, - "Fence": False, - "Farm Equipments": True, - "Bookshelf": True - } - + "Wall": False, + "Merchandises": True, + "Bed": True, + "Cabinet": True, + "Couch": True, + "TV": True, + "Refrigerator": True, + "Table": True, + "Chair": True, + "Musical Instruments": True, + "Utensils": True, + "Trees": False, + "Bench": True, + "Fence": False, + "Farm Equipments": True, + "Bookshelf": True, + } def __init__(self, object_data={}): self.name = object_data.get("name", "Area") self.bounds = object_data.get("bounds", []) self.valid_coordinates = [] - self.moveable = Object.moveable_objects().get(self.name,False) + self.moveable = Object.moveable_objects().get(self.name, False) self.mid = str(uuid.uuid4()) self.area = object_data.get("area", None) def get_tree(self): - return ({ - "name": self.name, - "bounds": self.bounds - }) + return {"name": self.name, "bounds": self.bounds} def __str__(self): return f"{self.name}" - diff --git a/src/location.py b/src/location.py index 4abd242..c85b8bd 100644 --- a/src/location.py +++ b/src/location.py @@ -12,7 +12,7 @@ def getLocationTree(self): for area in self.areas: area_tree.append(area.getAreaTree()) - tree = {"name": self.name, "description": self.description, "areas": area_tree } + tree = {"name": self.name, "description": self.description, "areas": area_tree} return tree def __str__(self, verbose=False): @@ -21,6 +21,7 @@ def __str__(self, verbose=False): else: return f"{self.name}" + class Area: def __init__(self, name, x, y, description, objects): self.name = name @@ -37,7 +38,13 @@ def getAreaTree(self): for object in self.objects: object_tree.append(object.getObjectTree()) - tree = {"name": self.name, "x": self.x, "y": self.y, "description": self.description, "objects": object_tree } + tree = { + "name": self.name, + "x": self.x, + "y": self.y, + "description": self.description, + "objects": object_tree, + } return tree def __str__(self, verbose=False): @@ -46,8 +53,9 @@ def __str__(self, verbose=False): else: return f"{self.name}" + class Object: - def __init__(self, name, x, y, is_boundary=False, description='Object', symbol='x'): + def __init__(self, name, x, y, is_boundary=False, description="Object", symbol="x"): self.name = name self.x = x self.y = y @@ -56,7 +64,14 @@ def __init__(self, name, x, y, is_boundary=False, description='Object', symbol=' self.symbol = symbol def getObjectTree(self): - tree = {"name": self.name, "x": self.x, "y": self.y, "is_boundary": False, "description": self.description, "symbol": self.symbol } + tree = { + "name": self.name, + "x": self.x, + "y": self.y, + "is_boundary": False, + "description": self.description, + "symbol": self.symbol, + } return tree def __str__(self, verbose=False): @@ -64,4 +79,3 @@ def __str__(self, verbose=False): return f"Object(name: {self.name}, position: {self.position}, description: {self.description}, is_boundary: {self.is_boundary}, symbol: {self.symbol})" else: return f"{self.name}" - diff --git a/src/matrix.py b/src/matrix.py index 058cc81..768fc94 100644 --- a/src/matrix.py +++ b/src/matrix.py @@ -27,6 +27,7 @@ def set_globals(config): for key, value in config.items(): globals()[key] = value + class Matrix: def __init__(self, config={}): set_globals(config) @@ -54,8 +55,8 @@ def __init__(self, config={}): self.cur_step = 0 self.current_substep = 0 self.unix_time = DEFAULT_TIME - #print(f"PPPP {self.unix_time} {type(self.unix_time)}") - #print(f"PPPP {LLM_IMPORTANCE} OOOOOO") + # print(f"PPPP {self.unix_time} {type(self.unix_time)}") + # print(f"PPPP {LLM_IMPORTANCE} OOOOOO") self.status = "init" self.conversation_counter = 0 self.sim_start_time = None @@ -71,55 +72,72 @@ def __init__(self, config={}): self.model = MODEL self.replay = None - self.add_to_logs({"step_type":"matrix_init","data":config}) - self.agent_locks = { agent: threading.Lock() for agent in self.agents } - self.environment = Environment({ "filename": self.environment_file }) + self.add_to_logs({"step_type": "matrix_init", "data": config}) + self.agent_locks = {agent: threading.Lock() for agent in self.agents} + self.environment = Environment({"filename": self.environment_file}) if self.scenario_file is not None: self.parse_scenario_file(self.scenario_file) - #self.environment.overlay_collisions_on_image() + # self.environment.overlay_collisions_on_image() self.background = None print(config) def boot(self): # Add Agents for agent_data in self.data.get("agents", []): - agent_data['matrix'] = self + agent_data["matrix"] = self agent = Agent(agent_data) self.add_agent_to_simulation(agent) # Add NPCs for i in range(self.num_npc): if len(self.default_goals) == 1: - description = f"{random.choice(self.default_descriptions)}" - goal = self.default_goals[0] + description = f"{random.choice(self.default_descriptions)}" + goal = self.default_goals[0] else: - description, goal = random.choice(list(zip(self.default_descriptions, self.default_goals))) + description, goal = random.choice( + list(zip(self.default_descriptions, self.default_goals)) + ) name = self.generate_unique_name() - agent = Agent({ "name": name, "description": description, "goal": goal, "kind": "npc","matrix":self }) + agent = Agent( + { + "name": name, + "description": description, + "goal": goal, + "kind": "npc", + "matrix": self, + } + ) self.add_agent_to_simulation(agent) # Add Zombies for i in range(self.num_zombies): - zombie = Agent({ "name": f"Zombie_{i}", "kind": "zombie", "actions": ["kill"],"matrix":self }) + zombie = Agent( + { + "name": f"Zombie_{i}", + "kind": "zombie", + "actions": ["kill"], + "matrix": self, + } + ) self.add_agent_to_simulation(zombie) @classmethod - def from_timeline(cls,src,step=None): + def from_timeline(cls, src, step=None): # TODO dont load this all in memory if src.startswith("redis://"): - r = redis_connection.from_url(src) - queue = "josh_queue" - data = r.lrange(queue, 0, -1) + r = redis_connection.from_url(src) + queue = "josh_queue" + data = r.lrange(queue, 0, -1) else: - #with open(src, 'r') as file: + # with open(src, 'r') as file: # content = file.read() - #data = content.split('\n\n') + # data = content.split('\n\n') data = [] - with jsonlines.open(src, mode='r') as reader: + with jsonlines.open(src, mode="r") as reader: for line in reader: data.append(line) matrix = None - current_step = 0 + current_step = 0 current_substep = 0 for datum in data: record = json.loads(datum) @@ -127,46 +145,68 @@ def from_timeline(cls,src,step=None): break print(f"at step {record['step']}.{record['substep']}") - if matrix is None and record['step'] == 0 and record['substep'] == 0: - set_globals(record['data']) - matrix = Matrix(record['data']) + if matrix is None and record["step"] == 0 and record["substep"] == 0: + set_globals(record["data"]) + matrix = Matrix(record["data"]) elif matrix: - if record['step_type'] == 'agent_init': - #data + if record["step_type"] == "agent_init": + # data config = record - config['matrix'] = matrix + config["matrix"] = matrix # is this some kind of double linking agent = Agent(config) matrix.add_agent_to_simulation(agent) - elif record['step_type'] == "agent_set": - agent = next((agent for agent in matrix.agents if agent.mid == record['agent_id']), None) + elif record["step_type"] == "agent_set": + agent = next( + ( + agent + for agent in matrix.agents + if agent.mid == record["agent_id"] + ), + None, + ) if agent: if record["status"]: agent.status = record["status"] - elif record['step_type'] == "talk": + elif record["step_type"] == "talk": pass # need to do some refactoring with convos.... - elif record['step_type'] == "move": - agent = next((agent for agent in matrix.agents if agent.mid == record['agent_id']), None) + elif record["step_type"] == "move": + agent = next( + ( + agent + for agent in matrix.agents + if agent.mid == record["agent_id"] + ), + None, + ) if agent: - agent.move({"x":record["x"],"y":record["y"]}) - elif record['step_type'] == "add_memory": - agent = next((agent for agent in matrix.agents if agent.mid == record['agent_id']), None) + agent.move({"x": record["x"], "y": record["y"]}) + elif record["step_type"] == "add_memory": + agent = next( + ( + agent + for agent in matrix.agents + if agent.mid == record["agent_id"] + ), + None, + ) if agent: - agent.addMemory(record["kind"],record["content"],record["last_accessed_at"],record["score"]) + agent.addMemory( + record["kind"], + record["content"], + record["last_accessed_at"], + record["score"], + ) elif record["step_type"] == "perceived": pass else: print(f"unprocessd step {record['step_type']}") - return(matrix) - - - - + return matrix def parse_scenario_file(self, filename): - with open(filename, 'r') as file: + with open(filename, "r") as file: data = json.load(file) self.data = data @@ -206,7 +246,7 @@ def add_agent_to_simulation(self, agent): new_position = random.choice(valid_coordinates) agent.x = new_position[0] agent.y = new_position[1] - #self.matrix.add_to_logs({"agent_id":agent.id,"step_type":"agent_set","x":agent.x,"y":agent.y}) + # self.matrix.add_to_logs({"agent_id":agent.id,"step_type":"agent_set","x":agent.x,"y":agent.y}) if agent.kind != "zombie" and self.allow_observance_flag == 1: parsed_spatial_mem = [] @@ -215,30 +255,34 @@ def add_agent_to_simulation(self, agent): if loc.name in agent.spatial_memory: parsed_spatial_mem.append(loc) - interaction = f"{unix_to_strftime(self.unix_time)} - {agent} knows the locations: {agent.spatial_memory}." - agent.addMemory("observation", interaction, unix_to_strftime(self.unix_time), random.randint(0,2)) + agent.addMemory( + "observation", + interaction, + unix_to_strftime(self.unix_time), + random.randint(0, 2), + ) agent.spatial_memory = parsed_spatial_mem else: agent.spatial_memory = self.environment.locations self.agents.append(agent) - def add_to_logs(self,obj): + def add_to_logs(self, obj): obj["step"] = self.cur_step obj["substep"] = self.current_substep - obj["sim_id"] = self.id # i think we will change this to sim id everywhere + obj["sim_id"] = self.id # i think we will change this to sim id everywhere file = f"logs/{obj['sim_id']}.jsonl" - #with open("logs.json", "a") as file: + # with open("logs.json", "a") as file: # json.dump(obj,file,indent=2) # file.write("\n\n") - with jsonlines.open(file, mode='a') as writer: + with jsonlines.open(file, mode="a") as writer: writer.write(json.dumps(obj)) stream = f"{obj['sim_id']}_stream" queue = f"{obj['sim_id']}" wtf = json.loads(json.dumps(obj, default=str)) - #redis_connection.xadd(stream, wtf) + # redis_connection.xadd(stream, wtf) max_retries = 3 retry_delay = 1 if redis_connection: @@ -247,7 +291,9 @@ def add_to_logs(self,obj): redis_connection.lpush(queue, json.dumps(obj)) break # Break the loop if successful except redis.RedisError as e: - print(f"Error pushing to Redis queue. Retrying... ({attempt + 1}/{max_retries})") + print( + f"Error pushing to Redis queue. Retrying... ({attempt + 1}/{max_retries})" + ) time.sleep(retry_delay) self.current_substep += 1 @@ -255,7 +301,9 @@ def add_to_logs(self,obj): def get_server_info(self): try: # Run 'uname -a' command - uname_output = subprocess.check_output(['uname', '-a']).decode('utf-8').strip() + uname_output = ( + subprocess.check_output(["uname", "-a"]).decode("utf-8").strip() + ) return uname_output except Exception as e: # Handle any exceptions that may occur @@ -294,7 +342,7 @@ def all_env_vars(self): "width": self.environment.width, "height": self.environment.width, "status": self.status, - "runtime": runtime_string, # Include the string representation + "runtime": runtime_string, # Include the string representation "server_info": self.get_server_info(), "created_at": self.sim_start_time.strftime("%Y-%m-%d %H:%M:%S"), "model": self.model, @@ -304,19 +352,18 @@ def all_env_vars(self): "conversation_counter": self.conversation_counter, "total_meta_memories": total_metas, "total_reflect_memories": total_reflections, - "total_agents": sum(1 for agent in self.agents if agent.kind != 'zombie'), - "total_zombies": sum(1 for agent in self.agents if agent.kind == 'zombie'), - "total_dead": sum(1 for agent in self.agents if agent.status == 'dead'), - "total_alive": sum(1 for agent in self.agents if agent.status != 'dead'), + "total_agents": sum(1 for agent in self.agents if agent.kind != "zombie"), + "total_zombies": sum(1 for agent in self.agents if agent.kind == "zombie"), + "total_dead": sum(1 for agent in self.agents if agent.status == "dead"), + "total_alive": sum(1 for agent in self.agents if agent.status != "dead"), "llm_call_counter": llm.call_counter, "avg_runtime_per_step": total_seconds / self.steps, - "avg_llm_calls_per_step": llm.call_counter / self.steps + "avg_llm_calls_per_step": llm.call_counter / self.steps, } - def send_matrix_to_redis(self): if TEST_RUN == 0: - #redis_connection.set(f"{self.id}:simulations", json.dumps(self.all_env_vars())) + # redis_connection.set(f"{self.id}:simulations", json.dumps(self.all_env_vars())) pass def log_agents_to_redis(self): @@ -325,15 +372,15 @@ def log_agents_to_redis(self): "name": agent.name, "x": agent.x, "y": agent.y, - "status": agent.status + "status": agent.status, } - #redis_connection.rpush(f"{self.id}:agents:{agent.name}", json.dumps(agent_data)) + # redis_connection.rpush(f"{self.id}:agents:{agent.name}", json.dumps(agent_data)) def run_singlethread(self): - #self.boot() + # self.boot() self.status = "running" self.sim_start_time = datetime.now() - #self.send_matrix_to_redis() + # self.send_matrix_to_redis() for step in range(self.steps): self.cur_step = step self.current_substep = 0 @@ -344,37 +391,42 @@ def run_singlethread(self): start_time = datetime.now() pd(f"Step {step + 1}:") - #redis_log(self.get_arr_2D(), f"{self.id}:matrix_states") - #redis_connection.set(f"{self.id}:matrix_state", json.dumps(self.get_arr_2D())) - #print_and_log(f"Step: {step + 1} | {unix_to_strftime(self.unix_time)}", f"{self.id}:agent_conversations") + # redis_log(self.get_arr_2D(), f"{self.id}:matrix_states") + # redis_connection.set(f"{self.id}:matrix_state", json.dumps(self.get_arr_2D())) + # print_and_log(f"Step: {step + 1} | {unix_to_strftime(self.unix_time)}", f"{self.id}:agent_conversations") - #self.log_agents_to_redis() + # self.log_agents_to_redis() - #for a in self.agents: + # for a in self.agents: # print_and_log(f"Step: {step + 1} | {unix_to_strftime(self.unix_time)}", f"{self.id}:events:{a.name}") # print_and_log(f"Step: {step + 1} | {unix_to_strftime(self.unix_time)}", f"{self.id}:conversations:{a.name}") if redis_connection: control_cmd = redis_connection.lpop(f"{self.id}:communications") if control_cmd: - control_cmd_str = control_cmd.decode('utf-8') + control_cmd_str = control_cmd.decode("utf-8") try: control_cmd_dict = json.loads(control_cmd_str) - name = control_cmd_dict.get('name', None) - msg = control_cmd_dict.get('msg', None) - control_type = control_cmd_dict.get('type', None) + name = control_cmd_dict.get("name", None) + msg = control_cmd_dict.get("msg", None) + control_type = control_cmd_dict.get("type", None) if name: for agent in self.agents: if name == agent.name: - agent.addMemory(kind=control_type, content=msg, timestamp=unix_to_strftime(self.unix_time), score=10) + agent.addMemory( + kind=control_type, + content=msg, + timestamp=unix_to_strftime(self.unix_time), + score=10, + ) except json.JSONDecodeError as e: print(f"Error decoding control_cmd: {e}") # Submit agent actions concurrently for i in range(len(self.agents)): - if self.llm_action_flag == 1 and self.agents[i].kind != 'zombie': + if self.llm_action_flag == 1 and self.agents[i].kind != "zombie": self.llm_action(self.agents[i], self.unix_time) else: self.agent_action(self.agents[i], self.unix_time) @@ -391,20 +443,24 @@ def run_singlethread(self): time.sleep(SLEEP_STEP) self.status = "complete" - self.add_to_logs({"step_type":"matrix_set","status":"complete"}) + self.add_to_logs({"step_type": "matrix_set", "status": "complete"}) average_llm_calls = llm.call_counter / (step + 1) sim_end_time = datetime.now() self.simulation_runtime = sim_end_time - self.sim_start_time self.print_agent_memories() pd(f"made it to step {step + 1}") - pd(f"Total LLM calls: {llm.call_counter} calls | Average LLM calls: {average_llm_calls} calls") + pd( + f"Total LLM calls: {llm.call_counter} calls | Average LLM calls: {average_llm_calls} calls" + ) def run(self): self.status = "running" self.sim_start_time = datetime.now() - #self.send_matrix_to_redis() + # self.send_matrix_to_redis() for step in range(self.steps): - with concurrent.futures.ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor: + with concurrent.futures.ThreadPoolExecutor( + max_workers=MAX_WORKERS + ) as executor: if self.status == "stop": pd("stopping simulation") break @@ -412,27 +468,35 @@ def run(self): pd(f"Step {step}:") - #redis_connection.lpush(f"{self.id}:agent_conversations", json.dumps(f"Step: {step + 1} | {unix_to_strftime(self.unix_time)}")) + # redis_connection.lpush(f"{self.id}:agent_conversations", json.dumps(f"Step: {step + 1} | {unix_to_strftime(self.unix_time)}")) # Submit agent actions concurrently if LLM_ACTION == 1: - futures = [executor.submit(self.llm_action, agent, self.unix_time,step) for agent in self.agents] + futures = [ + executor.submit(self.llm_action, agent, self.unix_time, step) + for agent in self.agents + ] else: - futures = [executor.submit(self.agent_action, agent, self.unix_time) for agent in self.agents] + futures = [ + executor.submit(self.agent_action, agent, self.unix_time) + for agent in self.agents + ] # Retrieve results from futures updated_agents = [future.result() for future in futures] # Update the agents' states. Reflect - #for i, updated_agent in enumerate(updated_agents): + # for i, updated_agent in enumerate(updated_agents): # self.agents[i].__dict__.update(updated_agent.__dict__) if PRINT_MAP == 1: self.print_matrix() - #redis_connection.set(f"{self.id}:matrix_state", json.dumps(self.get_arr_2D())) + # redis_connection.set(f"{self.id}:matrix_state", json.dumps(self.get_arr_2D())) self.unix_time = self.unix_time + 10 end_time = datetime.now() - pd(f"LLm calls for Step {step}: {llm.call_counter - self.llm_calls} calls") + pd( + f"LLm calls for Step {step}: {llm.call_counter - self.llm_calls} calls" + ) self.llm_calls = llm.call_counter pd(f"Step {step} ran in {end_time - start_time}") if SLEEP_STEP and SLEEP_STEP > 0: @@ -444,8 +508,9 @@ def run(self): self.simulation_runtime = sim_end_time - self.sim_start_time self.print_agent_memories() pd(f"made it to step {step + 1}") - pd(f"Total LLM calls: {llm.call_counter} calls | Average LLM calls: {average_llm_calls} calls") - + pd( + f"Total LLM calls: {llm.call_counter} calls | Average LLM calls: {average_llm_calls} calls" + ) def llm_action(self, agent, unix_time): if agent.status == "dead": @@ -456,10 +521,13 @@ def llm_action(self, agent, unix_time): agent.make_plans(unix_to_strftime(unix_time)) # Recent memories importance > 100, time to reflect - if self.allow_reflect_flag == 1 and agent.recent_memories_importance() > self.reflect_threshold: + if ( + self.allow_reflect_flag == 1 + and agent.recent_memories_importance() > self.reflect_threshold + ): agent.reflect(unix_to_strftime(unix_time)) - if self.allow_meta_flag == 1 and random.randint(0,100) < 25: + if self.allow_meta_flag == 1 and random.randint(0, 100) < 25: agent.evaluate_progress() agent.conversation_cooldown -= 1 @@ -479,52 +547,124 @@ def llm_action(self, agent, unix_time): # In here, if agent is locked to a conversation, no need then to let them decide # we let them talk if agent.is_locked_to_convo(): - agent.talk({ "other_agents": [agent.last_conversation.other_agent], "timestamp": unix_to_strftime(unix_time) }) + agent.talk( + { + "other_agents": [agent.last_conversation.other_agent], + "timestamp": unix_to_strftime(unix_time), + } + ) return agent - perceived_agents, perceived_locations, perceived_areas, perceived_objects,perceived_directions = agent.perceive([a for a in self.agents if a != agent], self.environment, unix_to_strftime(self.unix_time)) + ( + perceived_agents, + perceived_locations, + perceived_areas, + perceived_objects, + perceived_directions, + ) = agent.perceive( + [a for a in self.agents if a != agent], + self.environment, + unix_to_strftime(self.unix_time), + ) relevant_memories = agent.getMemories(agent.goal, unix_to_strftime(unix_time)) - relevant_memories_string = "\n".join(f"Memory {i + 1}:\n{memory}" for i, memory in enumerate(relevant_memories)) if relevant_memories else "" - current_location = self.environment.get_location_from_coordinates(agent.x, agent.y) + relevant_memories_string = ( + "\n".join( + f"Memory {i + 1}:\n{memory}" + for i, memory in enumerate(relevant_memories) + ) + if relevant_memories + else "" + ) + current_location = self.environment.get_location_from_coordinates( + agent.x, agent.y + ) current_area = self.environment.get_area_from_coordinates(agent.x, agent.y) if agent.last_conversation is not None: relevant_memories_string += f"\n{agent} is currently in a conversation with {agent.last_conversation.other_agent}.\n" - other_agents = [a for a in perceived_agents if a.status != "dead" and a.kind != "zombie"] + other_agents = [ + a for a in perceived_agents if a.status != "dead" and a.kind != "zombie" + ] - #valid_actions = ["stay"] - #example_strings = "\n\nExplanation: George will stay because it is still too early to go outside.\nAnswer: stay" + # valid_actions = ["stay"] + # example_strings = "\n\nExplanation: George will stay because it is still too early to go outside.\nAnswer: stay" valid_actions = [] example_strings = "\n\n" agents_available_to_talk = [] - if "move" in agent.actions and not agent.is_locked_to_convo() and self.allow_movement == 1: + if ( + "move" in agent.actions + and not agent.is_locked_to_convo() + and self.allow_movement == 1 + ): # You can move, and have not decided where to move yet valid_actions.append("move ") - example_strings = example_strings + "\n\nExplanation: George will move because he needs to be at the Park at 18:00.\nAnswer: move Park" - - if "fine_move" in agent.actions and not agent.is_locked_to_convo() and self.allow_movement == 1: + example_strings = ( + example_strings + + "\n\nExplanation: George will move because he needs to be at the Park at 18:00.\nAnswer: move Park" + ) + + if ( + "fine_move" in agent.actions + and not agent.is_locked_to_convo() + and self.allow_movement == 1 + ): valid_actions.append(FineMoveAction.example_usage()) - example_strings = example_strings + f"\n\nExplanation: {FineMoveAction.explanation()}" - - if "continue_to_destination" in agent.actions and agent.current_destination is not None and not agent.is_locked_to_convo() and self.allow_movement == 1: + example_strings = ( + example_strings + f"\n\nExplanation: {FineMoveAction.explanation()}" + ) + + if ( + "continue_to_destination" in agent.actions + and agent.current_destination is not None + and not agent.is_locked_to_convo() + and self.allow_movement == 1 + ): # You can move, and have already decided where to move valid_actions.append("continue_to_destination") - example_strings = example_strings + "\n\nExplanation: George will continue travelling to the Park because he wants to be there by 18:00.\nAnswer: continue_to_destination" - if random.randint(0, 100) < 10 and self.allow_meta_flag == 1 and "meta_cognize" in agent.actions: + example_strings = ( + example_strings + + "\n\nExplanation: George will continue travelling to the Park because he wants to be there by 18:00.\nAnswer: continue_to_destination" + ) + if ( + random.randint(0, 100) < 10 + and self.allow_meta_flag == 1 + and "meta_cognize" in agent.actions + ): valid_actions.append("meta_cognize") - example_strings = example_strings + "\n\nExplanation: George will meta_cognize because he wants to improve its strategy towards his goal.\nAnswer: meta_cognize" - - if "talk" in agent.actions and not agent.is_locked_to_convo() and agent.conversation_cooldown <= 0: - agents_available_to_talk = [a for a in other_agents if not a.is_locked_to_convo() and a.conversation_cooldown <= 0] + example_strings = ( + example_strings + + "\n\nExplanation: George will meta_cognize because he wants to improve its strategy towards his goal.\nAnswer: meta_cognize" + ) + + if ( + "talk" in agent.actions + and not agent.is_locked_to_convo() + and agent.conversation_cooldown <= 0 + ): + agents_available_to_talk = [ + a + for a in other_agents + if not a.is_locked_to_convo() and a.conversation_cooldown <= 0 + ] if len(agents_available_to_talk) > 0: valid_actions.append("talk ") - example_strings = example_strings + "\n\nExplanation: George will talk to Anne because he is trying to make new friends.\nAnswer: talk Anne" - - if "kill" in agent.actions and len(perceived_agents) > 0 and not agent.is_locked_to_convo(): + example_strings = ( + example_strings + + "\n\nExplanation: George will talk to Anne because he is trying to make new friends.\nAnswer: talk Anne" + ) + + if ( + "kill" in agent.actions + and len(perceived_agents) > 0 + and not agent.is_locked_to_convo() + ): valid_actions.append("kill ") - example_strings = example_strings + "\n\nExplanation: George will kill Anne because no one else is around.\nAnswer: kill Anne" + example_strings = ( + example_strings + + "\n\nExplanation: George will kill Anne because no one else is around.\nAnswer: kill Anne" + ) if len(valid_actions) == 0 and len(agent.destination_cache) > 0: interaction = f"{agent} is travelling to {self.environment.get_location_from_coordinates(agent.destination_cache[-1][0], agent.destination_cache[-1][1]).name}" @@ -538,14 +678,15 @@ def llm_action(self, agent, unix_time): "agent": agent, "other_agents": [a.name for a in other_agents], "agents_available_to_talk": [a.name for a in agents_available_to_talk], - 'objects': [obj.name.lower() for obj in perceived_objects] + [a.name.lower() for a in perceived_agents if a.kind != "human"], - 'examples': example_strings, - 'perceived_directions': perceived_directions, - 'actions': valid_actions, - 'location': current_location.name if current_location is not None else "", - 'area': current_area if current_area is not None else "", - 'spatial_memory': [loc.name for loc in agent.spatial_memory], - 'time': unix_to_strftime(unix_time) + "objects": [obj.name.lower() for obj in perceived_objects] + + [a.name.lower() for a in perceived_agents if a.kind != "human"], + "examples": example_strings, + "perceived_directions": perceived_directions, + "actions": valid_actions, + "location": current_location.name if current_location is not None else "", + "area": current_area if current_area is not None else "", + "spatial_memory": [loc.name for loc in agent.spatial_memory], + "time": unix_to_strftime(unix_time), } msg = llm.prompt("decide", variables) @@ -563,17 +704,23 @@ def llm_action(self, agent, unix_time): if decision == "talk": if len(agents_available_to_talk) > 0: - agent.talk({ "target": parameters, "other_agents": agents_available_to_talk, "timestamp": unix_to_strftime(unix_time) }) + agent.talk( + { + "target": parameters, + "other_agents": agents_available_to_talk, + "timestamp": unix_to_strftime(unix_time), + } + ) self.conversation_counter += 1 elif decision == "move": - agent.move({ "target": parameters, "environment": self.environment }) + agent.move({"target": parameters, "environment": self.environment}) elif decision == "continue_to_destination": if agent.current_destination is not None: - agent.move({ "environment": self.environment }) + agent.move({"environment": self.environment}) elif decision == "meta_cognize": - agent.meta_cognize(unix_to_strftime(unix_time),True) + agent.meta_cognize(unix_to_strftime(unix_time), True) elif decision == "fine_move": - FineMoveAction.act(agent,parameters) + FineMoveAction.act(agent, parameters) elif decision == "kill": if len(other_agents) > 0: target = find_most_similar(parameters, [a.name for a in other_agents]) @@ -581,25 +728,31 @@ def llm_action(self, agent, unix_time): if target == a.name: agent.kill(a, unix_to_strftime(unix_time)) if a.status == "dead": - witnesses = (set(perceived_agents) - {a}) + witnesses = set(perceived_agents) - {a} for witness in witnesses: - witness.addMemory("perceived", f"{a} was murdered by {agent} at {self.environment.get_area_from_coordinates(a.x, a.y)} {self.environment.get_location_from_coordinates(a.x, a.y)}", unix_to_strftime(unix_time), 9) + witness.addMemory( + "perceived", + f"{a} was murdered by {agent} at {self.environment.get_area_from_coordinates(a.x, a.y)} {self.environment.get_location_from_coordinates(a.x, a.y)}", + unix_to_strftime(unix_time), + 9, + ) memory = None - #memory = agent.addMemory("decision",f"I decided to {decision} because {explanation}",unix_to_strftime(unix_time),random.randint(1,4)) + # memory = agent.addMemory("decision",f"I decided to {decision} because {explanation}",unix_to_strftime(unix_time),random.randint(1,4)) if memory and memory.importance >= 6: agent.update_goals() return agent - - def agent_action(self, agent, unix_time): if agent.status == "dead": return agent - if agent.kind != 'zombie': + if agent.kind != "zombie": # Recent memories importance > reflect_threshold, time to reflect - if agent.recent_memories_importance() > self.reflect_threshold and self.allow_reflect_flag == 1: + if ( + agent.recent_memories_importance() > self.reflect_threshold + and self.allow_reflect_flag == 1 + ): agent.reflect(unix_to_strftime(unix_time)) agent.conversation_cooldown -= 1 @@ -614,41 +767,81 @@ def agent_action(self, agent, unix_time): other_agent.conversation_cooldown = CONVERSATION_COOLDOWN if agent.is_locked_to_convo(): - agent.talk({ "other_agents": [agent.last_conversation.other_agent], "timestamp": unix_to_strftime(unix_time) }) + agent.talk( + { + "other_agents": [agent.last_conversation.other_agent], + "timestamp": unix_to_strftime(unix_time), + } + ) return agent - perceived_agents, perceived_locations, perceived_areas, perceived_objects, perceived_directions = agent.perceive([a for a in self.agents if a != agent], self.environment, unix_to_strftime(self.unix_time)) + ( + perceived_agents, + perceived_locations, + perceived_areas, + perceived_objects, + perceived_directions, + ) = agent.perceive( + [a for a in self.agents if a != agent], + self.environment, + unix_to_strftime(self.unix_time), + ) if len(perceived_agents) > 0: other_agent = random.choice(perceived_agents) # Killing condition if "kill" in agent.actions and other_agent.status != "dead": - if random.randint(0, 100) < agent.kill_rate - (5 * len(perceived_agents)): + if random.randint(0, 100) < agent.kill_rate - ( + 5 * len(perceived_agents) + ): agent.kill(other_agent, unix_to_strftime(unix_time)) if other_agent.status == "dead": - witnesses = (set(perceived_agents) - {other_agent}) + witnesses = set(perceived_agents) - {other_agent} for witness in witnesses: - witness.addMemory("perceived", f"{other_agent} was murdered by {agent} at {self.environment.get_area_from_coordinates(other_agent.x, other_agent.y)} {self.environment.get_location_from_coordinates(other_agent.x, other_agent.y)}", unix_to_strftime(unix_time), 9) + witness.addMemory( + "perceived", + f"{other_agent} was murdered by {agent} at {self.environment.get_area_from_coordinates(other_agent.x, other_agent.y)} {self.environment.get_location_from_coordinates(other_agent.x, other_agent.y)}", + unix_to_strftime(unix_time), + 9, + ) return agent - if agent.kind != 'zombie': + if agent.kind != "zombie": # Talk Condition - agents_can_hear = [a for a in perceived_agents if a.status != "dead" and a.kind != "zombie"] + agents_can_hear = [ + a + for a in perceived_agents + if a.status != "dead" and a.kind != "zombie" + ] if len(agents_can_hear) > 0: other_agent = random.choice(agents_can_hear) - if random.randint(0, 100) < agent.talk_rate and len(agents_can_hear) > 0: - agent.talk({ "target": other_agent.name, "other_agents": [other_agent], "timestamp": unix_to_strftime(unix_time) }) + if ( + random.randint(0, 100) < agent.talk_rate + and len(agents_can_hear) > 0 + ): + agent.talk( + { + "target": other_agent.name, + "other_agents": [other_agent], + "timestamp": unix_to_strftime(unix_time), + } + ) self.conversation_counter += 1 return agent if self.allow_movement == 1: if len(agent.destination_cache) == 0 or agent.current_destination is None: # Decide where to go - agent.move({ "target": random.choice(agent.spatial_memory).name, "environment": self.environment }) + agent.move( + { + "target": random.choice(agent.spatial_memory).name, + "environment": self.environment, + } + ) else: # Has current path to go - agent.move({ "environment": self.environment }) + agent.move({"environment": self.environment}) return agent # Agent stays in the same position @@ -658,8 +851,6 @@ def print_agent_memories(self): for memory in agent.memory: pd(memory) - - # Add a helper method to generate a unique name def generate_unique_name(self): existing_names = {agent.name for agent in self.agents} @@ -676,17 +867,25 @@ def generate_unique_name(self): def run_interviews(self): if self.interview_questions: - dead_agents = [agent for agent in self.agents if (agent.status == "dead" and agent.kind != "zombie")] - living_agents = [agent for agent in self.agents if (agent.status != "dead" and agent.kind != "zombie")] + dead_agents = [ + agent + for agent in self.agents + if (agent.status == "dead" and agent.kind != "zombie") + ] + living_agents = [ + agent + for agent in self.agents + if (agent.status != "dead" and agent.kind != "zombie") + ] for agent in dead_agents + living_agents: results = [] for question in self.interview_questions: metric = question.get("metric", None) - #if agent.status == "dead": + # if agent.status == "dead": # pd(f"{agent} dead, can't ask questions") # results.append("Agent is dead, cannot answer questions") - #elif question["who"] == "all" or question["who"] == agent.name: + # elif question["who"] == "all" or question["who"] == agent.name: answer = agent.answer(question["question"]) if metric: match = re.search(r"Answer: (\d)", answer) @@ -695,34 +894,46 @@ def run_interviews(self): else: score = 0 self.performance_metrics[metric] += score - answer_data = { - "question": question["question"], - "answer": answer - } + answer_data = {"question": question["question"], "answer": answer} results.append(answer_data) self.interview_results[agent.name] = results def print_matrix(self): cell_width = 15 # Adjust this value based on your needs - matrix = [[" " * cell_width for _ in range(self.environment.width)] for _ in range(self.environment.height)] + matrix = [ + [" " * cell_width for _ in range(self.environment.width)] + for _ in range(self.environment.height) + ] # Print agents for agent in self.agents: - matrix[agent.x][agent.y] = "{:<{width}}".format(f"{agent.direction} * {agent.name}", width=cell_width) + matrix[agent.x][agent.y] = "{:<{width}}".format( + f"{agent.direction} * {agent.name}", width=cell_width + ) - #sys.stdout.write("\033[H") + # sys.stdout.write("\033[H") print("\n\n") for row in matrix: print("|".join(row)) print("-" * (cell_width * self.n - 1)) def get_all_objects(self): - all_objects = [obj for loc in self.locations for area in loc.areas for obj in area.objects] + all_objects = [ + obj for loc in self.locations for area in loc.areas for obj in area.objects + ] return all_objects def get_arr_2D(self): - arr_2D = [["" for _ in range(self.environment.width)] for _ in range(self.environment.height)] - objs = [obj for location in self.environment.locations for area in location.areas for obj in area.objects] + arr_2D = [ + ["" for _ in range(self.environment.width)] + for _ in range(self.environment.height) + ] + objs = [ + obj + for location in self.environment.locations + for area in location.areas + for obj in area.objects + ] for x in range(self.environment.height): for y in range(self.environment.width): @@ -744,4 +955,3 @@ def clear_redis(self): redis_connection.delete(f"{self.id}:conversations:{a.name}") redis_connection.delete(f"{self.id}:events:{a.name}") redis_connection.delete(f"{self.id}:agents:{a.name}") - diff --git a/src/memory.py b/src/memory.py index b67d295..06788ee 100644 --- a/src/memory.py +++ b/src/memory.py @@ -6,8 +6,18 @@ from utils.utils import * from sklearn.metrics.pairwise import cosine_similarity + class Memory: - def __init__(self, kind, content, created_at, last_accessed_at, score=None,embedding=None, memories=[]): + def __init__( + self, + kind, + content, + created_at, + last_accessed_at, + score=None, + embedding=None, + memories=[], + ): self.id = str(uuid.uuid4()) self.kind = kind self.content = content @@ -18,8 +28,8 @@ def __init__(self, kind, content, created_at, last_accessed_at, score=None,embed print(type(self.last_accessed_at)) else: self.last_accessed_at = last_accessed_at - #print(f"WTF {content} {type(created_at)} {type(last_accessed_at)} ") - #print(f"{type(LLM_IMPORTANCE)} {LLM_IMPORTANCE}") + # print(f"WTF {content} {type(created_at)} {type(last_accessed_at)} ") + # print(f"{type(LLM_IMPORTANCE)} {LLM_IMPORTANCE}") if LLM_IMPORTANCE == 0: self.importance = score else: @@ -32,10 +42,11 @@ def __init__(self, kind, content, created_at, last_accessed_at, score=None,embed self.embedding = embedding else: self.embedding = llm.embeddings(content) - #self.simulation_id = simulation_id + # self.simulation_id = simulation_id + + # session.add(self) + # session.commit() - #session.add(self) - #session.commit() def to_dict(self): return vars(self) @@ -54,8 +65,8 @@ def __str__(self, verbose=False): else: return self.content - def calculateImportanceScore(content,previous_memories=[]): - prompt = f''' + def calculateImportanceScore(content, previous_memories=[]): + prompt = f""" On the scale of 0 to 9, where 0 is purely mundane (e.g., brushing teeth, saw a bed) and 9 is extremely poignant (e.g., a break up, witnessed murder), rate the likely poignancy of the following memory. First give an explanation for your score. @@ -73,7 +84,7 @@ def calculateImportanceScore(content,previous_memories=[]): 0 - ''' + """ same_memory = None for mem in previous_memories: if mem.content == content: @@ -83,9 +94,9 @@ def calculateImportanceScore(content,previous_memories=[]): result = "{same_memory.importance}" else: result = llm.generate(prompt, "5") - #cleaned_result = float(re.search(r'\d+', result).group() if re.search(r'\d+', result) else '5') + # cleaned_result = float(re.search(r'\d+', result).group() if re.search(r'\d+', result) else '5') try: - cleaned_result = int(re.findall(r'\b\d+\b', result)[-1]) + cleaned_result = int(re.findall(r"\b\d+\b", result)[-1]) except IndexError: cleaned_result = 5 if cleaned_result > 9: @@ -114,9 +125,11 @@ def calculateRelevanceScore(memory_embedding, context_embedding): def calculateRecencyScore(last_accessed_at, time, decay=0.99): try: - #print(f"laa {last_accessed_at} {type(last_accessed_at)}") - #print(f"time {time} {type(time)}") - last_accessed_at = int(datetime.strptime(last_accessed_at, "%Y-%m-%d %H:%M:%S").timestamp()) + # print(f"laa {last_accessed_at} {type(last_accessed_at)}") + # print(f"time {time} {type(time)}") + last_accessed_at = int( + datetime.strptime(last_accessed_at, "%Y-%m-%d %H:%M:%S").timestamp() + ) time = int(datetime.strptime(time, "%Y-%m-%d %H:%M:%S").timestamp()) return float(decay ** int(time - last_accessed_at)) except OverflowError: diff --git a/src/npc.py b/src/npc.py index 2e27234..5654a8a 100644 --- a/src/npc.py +++ b/src/npc.py @@ -14,18 +14,20 @@ class Npc(Agent): def __init__(self, agent_data): self.id = str(uuid.uuid4()) - self.name = agent_data.get('name', "") - self.description = agent_data.get('description', "A zombie that chase and kills humans") - self.goal = agent_data.get('goal', "Goal is to kill all humans") - self.x = agent_data['position'][0] if 'position' in agent_data else 0 - self.y = agent_data['position'][1] if 'position' in agent_data else 0 - self.direction = agent_data.get('direction', "up") + self.name = agent_data.get("name", "") + self.description = agent_data.get( + "description", "A zombie that chase and kills humans" + ) + self.goal = agent_data.get("goal", "Goal is to kill all humans") + self.x = agent_data["position"][0] if "position" in agent_data else 0 + self.y = agent_data["position"][1] if "position" in agent_data else 0 + self.direction = agent_data.get("direction", "up") self.path = [] self.acceptance = 0 self.invitation = 0 self.retention = 100 self.last_conversation = None - self.spatial_memory = agent_data.get('spatial_memory', None) + self.spatial_memory = agent_data.get("spatial_memory", None) self.destination = None self.is_busy = False self.status = "active" # initiate, active, dead, sleeping, @@ -36,15 +38,15 @@ def __init__(self, agent_data): def kill(self, other, timestamp): if self == other or (self.specie == "zombie" and other.specie == "zombie"): - return - if random.random() < 0.5: + return + if random.random() < 0.5: print(f"{self.name} killed {other}") other.status = "dead" else: - #tried to kill, but failed, memories should note this - other.addMemory("interaction",f"{self.name} tried to kill you",timestamp) + # tried to kill, but failed, memories should note this + other.addMemory("interaction", f"{self.name} tried to kill you", timestamp) - def make_plans(self,unix_time): + def make_plans(self, unix_time): pass def move(self, n, collisions, timestamp): @@ -59,10 +61,10 @@ def move(self, n, collisions, timestamp): random_move = random.choice(possible_moves) new_position = (self.x + random_move[0], self.y + random_move[1]) - self.destination = {'x': new_position[0], 'y': new_position[1]} + self.destination = {"x": new_position[0], "y": new_position[1]} # If zombie has arrived at the destination, reset the destination - if self.x == self.destination['x'] and self.y == self.destination['y']: + if self.x == self.destination["x"] and self.y == self.destination["y"]: print(f"{self} has arrived at {self.destination}") self.destination = None return (self.x, self.y, "up") @@ -72,10 +74,19 @@ def move(self, n, collisions, timestamp): # Move towards the last seen human if len(self.path) == 0: # If there is no current path, find a path to a random human if available - humans = [agent for agent in self.spatial_memory if agent.get('specie', '') == 'human'] + humans = [ + agent + for agent in self.spatial_memory + if agent.get("specie", "") == "human" + ] if humans: random_human = random.choice(humans) - self.path = self.find_path((self.x, self.y), (random_human['x'], random_human['y']), n, collisions) + self.path = self.find_path( + (self.x, self.y), + (random_human["x"], random_human["y"]), + n, + collisions, + ) else: # If no humans are in memory, move randomly possible_moves = [(0, 1), (0, -1), (1, 0), (-1, 0)] @@ -87,7 +98,7 @@ def move(self, n, collisions, timestamp): random_move = random.choice(possible_moves) new_position = (self.x + random_move[0], self.y + random_move[1]) - self.destination = {'x': new_position[0], 'y': new_position[1]} + self.destination = {"x": new_position[0], "y": new_position[1]} self.path = [] # If there is an existing path, pop and continue @@ -103,7 +114,12 @@ def has_blocker_between(agent, other, collisions): x1, y1 = agent.x, agent.y x2, y2 = other.x, other.y - x1, y1, x2, y2 = int(round(x1)), int(round(y1)), int(round(x2)), int(round(y2)) + x1, y1, x2, y2 = ( + int(round(x1)), + int(round(y1)), + int(round(x2)), + int(round(y2)), + ) dx = abs(x2 - x1) dy = abs(y2 - y1) @@ -130,7 +146,7 @@ def has_blocker_between(agent, other, collisions): y1 = y1 + sy return False - + can_perceive = ( abs(self.x - other.x) <= perception_range and abs(self.y - other.y) <= perception_range @@ -149,14 +165,14 @@ def has_blocker_between(agent, other, collisions): # Store information about the perceived agent perceived_agent_info = { - 'name': other.name, - 'x': other.x, - 'y': other.y, + "name": other.name, + "x": other.x, + "y": other.y, } if isinstance(other, Agent) and other.specie == "human": - perceived_agent_info['specie'] = "human" + perceived_agent_info["specie"] = "human" else: - perceived_agent_info['specie'] = "zombie" + perceived_agent_info["specie"] = "zombie" self.spatial_memory.append(perceived_agent_info) return can_perceive diff --git a/src/objects.py b/src/objects.py index 55ba8b6..7eaf0a6 100644 --- a/src/objects.py +++ b/src/objects.py @@ -1,5 +1,7 @@ class Object: - def __init__(self, name, position, is_boundary=False, description='Object', symbol='x'): + def __init__( + self, name, position, is_boundary=False, description="Object", symbol="x" + ): self.name = name self.position = position self.is_boundary = is_boundary @@ -17,5 +19,3 @@ def __str__(self, verbose=False): return f"Object(name: {self.name}, position: {self.position}, description: {self.description}, is_boundary: {self.is_boundary}, symbol: {self.symbol})" else: return f"{self.name}" - - diff --git a/test.py b/test.py index 3b612ba..4abd6c0 100644 --- a/test.py +++ b/test.py @@ -1,44 +1,80 @@ +""" +This module runs tests for the overall program. +""" + import unittest import argparse +import concurrent.futures +import random + from datetime import datetime +from unittest.mock import MagicMock + +from engine import Matrix +from utils.utils import * + from src.agents import Agent from src.memory import Memory from src.environment import Environment from src.conversation import Conversation -from utils.utils import * -from engine import Matrix -import concurrent.futures -from concurrent.futures import ThreadPoolExecutor -import random -import re - -from unittest.mock import MagicMock from src.actions.fine_move_action import FineMoveAction + class TestMemoryFunctions(unittest.TestCase): + """ + This class handles testing of memory functions. + """ + def test_fine_move_action_direction(self): + """ + This function tests the direction of the agent's move. + """ + agent = MagicMock(x=0, y=0) FineMoveAction.act(agent, "up with random text") self.assertEqual(agent.x, 0) self.assertEqual(agent.y, -1) def test_fine_move_action_invalid_direction(self): + """ + This function tests invalid direction of the agent's move. + """ + agent = MagicMock(x=0, y=0) FineMoveAction.act(agent, "invalid-direction") self.assertEqual(agent.x, 0) self.assertEqual(agent.y, 0) def test_fine_move_action_moves_away(self): - #real agent here, real zombie here. decide - matrix = Matrix({"environment":"configs/small.tmj"}) - real_agent = Agent({ "name": "John", "actions": ["fine_move"],"x":5,"y":5,"matrix":matrix }) + """ + This function tests agents to move away. + """ + + # real agent here, real zombie here. decide + matrix = Matrix({"environment": "configs/small.tmj"}) + real_agent = Agent( + {"name": "John", "actions": ["fine_move"], "x": 5, "y": 5, "matrix": matrix} + ) matrix.add_agent_to_simulation(real_agent) - zombie = Agent({ "name": f"Zombie", "kind": "zombie", "actions": ["kill"],"x":6,"y":5,"matrix":matrix }) + zombie = Agent( + { + "name": "Zombie", + "kind": "zombie", + "actions": ["kill"], + "x": 6, + "y": 5, + "matrix": matrix, + } + ) matrix.add_agent_to_simulation(zombie) matrix.llm_action(real_agent, matrix.unix_time) self.assertEqual(real_agent.x, 4) def test_memory(self): + """ + This function tests if an agent can have a memory. + """ + agent_data = { "name": "John", "description": "You are a simulated persona.", @@ -48,12 +84,12 @@ def test_memory(self): unix_time = 1704067200 try: - with open('tests/input_memory.txt', 'r') as file: + with open("tests/input_memory.txt", "r", encoding="utf-8") as file: for mem in file: timestamp = datetime.fromtimestamp(unix_time).strftime("%Y-%m-%d %H:%M:%S") agent.addMemory("test", mem, timestamp, random.randint(0, 9)) unix_time = unix_time + 10 - except Exception as e: + except Exception as e: # pylint: disable=broad-except print(f"Error {e}") for mem in agent.memory: @@ -61,75 +97,87 @@ def test_memory(self): self.assertTrue(len(agent.memory) > 0) def test_eval(self): + """ + This function tests the progress evaluation of the agent. + """ + agent1_data = { "name": "John", "description": "software engineer", "goal": "have a hello kitty themed party", - #"meta_questions": ["how can I be more like Elon Musk?"], - } - agent2_data = { - "name": "Paul", - "description": "bar tender", + # "meta_questions": ["how can I be more like Elon Musk?"], } agent1 = Agent(agent1_data) - agent2 = Agent(agent2_data) + + # agent2_data = { + # "name": "Paul", + # "description": "bar tender", + # } + # agent2 = Agent(agent2_data) unix_time = 1704067200 try: - with open('tests/input_memory.txt', 'r') as file: + with open("tests/input_memory.txt", "r", encoding="utf-8") as file: for mem in file: timestamp = datetime.fromtimestamp(unix_time).strftime("%Y-%m-%d %H:%M:%S") - #agent1.addMemory("test", mem, timestamp, (CLEAR_TEST_MEMORIES != 1)) + # agent1.addMemory("test", mem, timestamp, (CLEAR_TEST_MEMORIES != 1)) unix_time = unix_time + 10 - except Exception as e: + except Exception as e: # pylint: disable=broad-except print(f"Error {e}") timestamp = datetime.fromtimestamp(unix_time).strftime("%Y-%m-%d %H:%M:%S") agent1.evaluate_progress(timestamp) def test_askmetaquestions(self): + """ + This function tests the agent to ask meta questions. + """ + agent1_data = { "name": "John", "description": "software engineer", "goal": "have a hello kitty themed party", } - agent2_data = { - "name": "Paul", - "description": "bar tender", - } agent1 = Agent(agent1_data) - agent2 = Agent(agent2_data) + + # agent2_data = { + # "name": "Paul", + # "description": "bar tender", + # } + # agent2 = Agent(agent2_data) # if random < 1 always happen unix_time = 1704067200 try: - with open('tests/input_memory.txt', 'r') as file: + with open("tests/input_memory.txt", "r", encoding="utf-8") as file: for mem in file: timestamp = datetime.fromtimestamp(unix_time).strftime("%Y-%m-%d %H:%M:%S") - #agent1.addMemory("test", mem, timestamp, (CLEAR_TEST_MEMORIES != 1)) + # agent1.addMemory("test", mem, timestamp, (CLEAR_TEST_MEMORIES != 1)) unix_time = unix_time + 10 - except Exception as e: + except Exception as e: # pylint: disable=broad-except print(f"Error {e}") timestamp = datetime.fromtimestamp(unix_time).strftime("%Y-%m-%d %H:%M:%S") agent1.ask_meta_questions(timestamp) - #agent2.ask_meta_questions(timestamp) - + # agent2.ask_meta_questions(timestamp) print(f"====== DATA FOR {agent1} ======\nMEMORIES:") - for (i, mem) in enumerate(agent1.memory): + for i, mem in enumerate(agent1.memory): print(f"{i}: {mem}") - print(f"QUESTIONS:") - for (i, q) in enumerate(agent1.meta_questions): + print("QUESTIONS:") + for i, q in enumerate(agent1.meta_questions): print(f"{i}: {q}") - def test_metacognition(self): + """ + This function tests the agent's metacognition. + """ + agent1_data = { "name": "John", "description": "software engineer", "goal": "have a hello kitty themed party", - #"meta_questions": ["how can I be more like Elon Musk?"], + # "meta_questions": ["how can I be more like Elon Musk?"], } agent2_data = { "name": "Paul", @@ -138,40 +186,56 @@ def test_metacognition(self): agent1 = Agent(agent1_data) agent2 = Agent(agent2_data) - #agent1.connections.append(str(agent2)) - #agent2.connections.append(str(agent1)) + # agent1.connections.append(str(agent2)) + # agent2.connections.append(str(agent1)) # if random < 1 always happen unix_time = 1704067200 try: - with open('tests/input_memory.txt', 'r') as file: + with open("tests/input_memory.txt", "r", encoding="utf-8") as file: for mem in file: timestamp = datetime.fromtimestamp(unix_time).strftime("%Y-%m-%d %H:%M:%S") - #agent1.addMemory("test", mem, timestamp, (CLEAR_TEST_MEMORIES != 1)) + # agent1.addMemory("test", mem, timestamp, (CLEAR_TEST_MEMORIES != 1)) unix_time = unix_time + 10 - except Exception as e: + except Exception as e: # pylint: disable=broad-except print(f"Error {e}") timestamp = datetime.fromtimestamp(unix_time).strftime("%Y-%m-%d %H:%M:%S") - agent1.meta_cognize(timestamp,True) - for i in range(2): + agent1.meta_cognize(timestamp, True) + for _ in range(2): timestamp = datetime.fromtimestamp(unix_time).strftime("%Y-%m-%d %H:%M:%S") - agent1.talk({ "target": agent2.name, "other_agents": [agent2], "timestamp": timestamp }) - agent2.talk({ "target": agent1.name, "other_agents": [agent1], "timestamp": timestamp }) + agent1.talk( + { + "target": agent2.name, + "other_agents": [agent2], + "timestamp": timestamp, + } + ) + agent2.talk( + { + "target": agent1.name, + "other_agents": [agent1], + "timestamp": timestamp, + } + ) # matrix.print_matrix() unix_time = unix_time + 10 - #takes memories and returns questions - #agent.meta_reflect(timestamp, True) + # takes memories and returns questions + # agent.meta_reflect(timestamp, True) # print(agent.memory) for mem in agent1.memory: print(mem) for q in agent1.meta_questions: print(q) - #self.assertTrue(len(agent1.memory) > 0) + # self.assertTrue(len(agent1.memory) > 0) def test_reflection(self): + """ + This function tests the agent's reflections. + """ + agent_data = { "name": "John", "description": "You are a simulated persona.", @@ -180,12 +244,12 @@ def test_reflection(self): agent = Agent(agent_data) unix_time = 1704067200 try: - with open('tests/input_memory.txt', 'r') as file: + with open("tests/input_memory.txt", "r", encoding="utf-8") as file: for mem in file: timestamp = datetime.fromtimestamp(unix_time).strftime("%Y-%m-%d %H:%M:%S") agent.addMemory("test", mem, timestamp, random.randint(0, 9)) unix_time = unix_time + 10 - except Exception as e: + except Exception as e: # pylint: disable=broad-except print(f"Error {e}") agent.reflect(timestamp, True) @@ -197,6 +261,11 @@ def test_reflection(self): self.assertTrue(len(agent.memory) > 0) def test_relevance(self): + """ + This function tests the relevance of + agent's memories to a certain context. + """ + context = "dog car driving" agent_data = { "name": "John", @@ -207,15 +276,15 @@ def test_relevance(self): unix_time = 1704067200 try: - with open('tests/input_memory.txt', 'r') as file: + with open("tests/input_memory.txt", "r", encoding="utf-8") as file: for mem in file: timestamp = datetime.fromtimestamp(unix_time).strftime("%Y-%m-%d %H:%M:%S") agent.addMemory("test", mem, timestamp, random.randint(0, 9)) unix_time = unix_time + 10 - except Exception as e: + except Exception as e: # pylint: disable=broad-except print(f"Error {e}") - context_embedding = llm.embeddings(context) + # context_embedding = llm.embeddings(context) memories = agent.getMemories(context, timestamp) print(f"Context: {context}") @@ -224,6 +293,10 @@ def test_relevance(self): self.assertTrue(len(memories) > 0) def test_embeddings(self): + """ + This function tests the agents to recognize context embeddings. + """ + context = "travel" agent_data = { "name": "John", @@ -234,53 +307,86 @@ def test_embeddings(self): unix_time = 1704067200 try: - with open('tests/input_memory.txt', 'r') as file: + with open("tests/input_memory.txt", "r", encoding="utf-8") as file: for mem in file: - if mem.startswith('#'): + if mem.startswith("#"): continue timestamp = datetime.fromtimestamp(unix_time).strftime("%Y-%m-%d %H:%M:%S") agent.addMemory("test", mem.strip(), timestamp, random.randint(0, 9)) unix_time = unix_time + 10 - except Exception as e: + except Exception as e: # pylint: disable=broad-except print(f"Error {e}") context_embedding = llm.embeddings(context) - sorted_memory = sorted(agent.memory, - key=lambda mem: Memory.calculateRelevanceScore(mem.embedding, context_embedding), - reverse=True) + sorted_memory = sorted( + agent.memory, + key=lambda mem: Memory.calculateRelevanceScore(mem.embedding, context_embedding), + reverse=True, + ) print(f"Context: {context}") for mem in sorted_memory: print(f"Current Memory: {mem}") - print(f"Relevance Score: {Memory.calculateRelevanceScore(mem.embedding, context_embedding)}") + print( + f"Relevance Score: " + f"{Memory.calculateRelevanceScore(mem.embedding, context_embedding)}" + ) self.assertTrue(len(sorted_memory) > 0) def test_information_spreading(self): - a1_data = { "name": "Viktor", "goal": "wants to throw a party next week" } - a2_data = { "name": "John", "description": "loves art" } - a3_data = { "name": "Paul", "description": "loves eating" } + """ + This function tests spread of information among agents. + """ + + a1_data = {"name": "Viktor", "goal": "wants to throw a party next week"} + a2_data = {"name": "John", "description": "loves art"} + a3_data = {"name": "Paul", "description": "loves eating"} agent1 = Agent(a1_data) agent2 = Agent(a2_data) agent3 = Agent(a3_data) unix_time = 1704067200 timestamp = datetime.fromtimestamp(unix_time).strftime("%Y-%m-%d %H:%M:%S") - for i in range(2): + for _ in range(2): timestamp = datetime.fromtimestamp(unix_time).strftime("%Y-%m-%d %H:%M:%S") - response = agent1.talk({ "target": agent2.name, "other_agents": [agent2], "timestamp": timestamp }) + response = agent1.talk( + { + "target": agent2.name, + "other_agents": [agent2], + "timestamp": timestamp, + } + ) msg = f"{agent1} said to {agent2}: {response}" print(msg) - response = agent2.talk({ "target": agent1.name, "other_agents": [agent1], "timestamp": timestamp }) + response = agent2.talk( + { + "target": agent1.name, + "other_agents": [agent1], + "timestamp": timestamp, + } + ) msg = f"{agent2} said to {agent1}: {response}" print(msg) unix_time = unix_time + 10 agent2.summarize_conversation(timestamp) - print("*"*20) - for i in range(2): + print("*" * 20) + for _ in range(2): timestamp = datetime.fromtimestamp(unix_time).strftime("%Y-%m-%d %H:%M:%S") - response = agent2.talk({ "target": agent3.name, "other_agents": [agent3], "timestamp": timestamp }) + response = agent2.talk( + { + "target": agent3.name, + "other_agents": [agent3], + "timestamp": timestamp, + } + ) msg = f"{agent2} said to {agent3}: {response}" print(msg) - response = agent3.talk({ "target": agent2.name, "other_agents": [agent2], "timestamp": timestamp }) + response = agent3.talk( + { + "target": agent2.name, + "other_agents": [agent2], + "timestamp": timestamp, + } + ) msg = f"{agent3} said to {agent2}: {response}" print(msg) unix_time = unix_time + 10 @@ -293,24 +399,37 @@ def test_information_spreading(self): print(mem) def test_talk_stranger(self): + """ + This function tests agent's ability to talk to strangers. + """ + agent1_data = { "name": "Viktor", "description": "You love physics, you hate talking to people", "goal": "Answer questions, think, be rational.", } - agent2_data = { - "name": "Natasha", - "description": "You love art" - } + agent2_data = {"name": "Natasha", "description": "You love art"} agent1 = Agent(agent1_data) agent2 = Agent(agent2_data) unix_time = 1704067200 - for i in range(2): + for _ in range(2): timestamp = datetime.fromtimestamp(unix_time).strftime("%Y-%m-%d %H:%M:%S") - response = agent1.talk({ "target": agent2.name, "other_agents": [agent2], "timestamp": timestamp }) + response = agent1.talk( + { + "target": agent2.name, + "other_agents": [agent2], + "timestamp": timestamp, + } + ) msg = f"{agent1} said to {agent2}: {response}" print(msg) - response = agent2.talk({ "target": agent1.name, "other_agents": [agent1], "timestamp": timestamp }) + response = agent2.talk( + { + "target": agent1.name, + "other_agents": [agent1], + "timestamp": timestamp, + } + ) msg = f"{agent2} said to {agent1}: {response}" print(msg) unix_time = unix_time + 10 @@ -318,35 +437,44 @@ def test_talk_stranger(self): "name": "John", "description": "outgoing and likes to talk", } - agent2_data = { - "name": "Alucard", - "description": "shy" - } + agent2_data = {"name": "Alucard", "description": "shy"} agent1 = Agent(agent1_data) agent2 = Agent(agent2_data) unix_time = 1704067200 - for i in range(2): + for _ in range(2): timestamp = datetime.fromtimestamp(unix_time).strftime("%Y-%m-%d %H:%M:%S") - response = agent1.talk({ "target": agent2.name, "other_agents": [agent2], "timestamp": timestamp }) + response = agent1.talk( + { + "target": agent2.name, + "other_agents": [agent2], + "timestamp": timestamp, + } + ) msg = f"{agent1} said to {agent2}: {response}" print(msg) - response = agent2.talk({ "target": agent1.name, "other_agents": [agent1], "timestamp": timestamp }) + response = agent2.talk( + { + "target": agent1.name, + "other_agents": [agent1], + "timestamp": timestamp, + } + ) msg = f"{agent2} said to {agent1}: {response}" print(msg) unix_time = unix_time + 10 - def test_talk(self): + """ + This function tests agent's ability to talk. + """ + agent1_data = { "name": "Viktor", "description": "You love physics", "goal": "Answer questions, think, be rational.", } - agent2_data = { - "name": "Natasha", - "description": "You love art" - } + agent2_data = {"name": "Natasha", "description": "You love art"} agent1 = Agent(agent1_data) agent2 = Agent(agent2_data) @@ -355,14 +483,18 @@ def test_talk(self): unix_time = 1704067200 convos = [] - for i in range(5): + for _ in range(5): timestamp = datetime.fromtimestamp(unix_time).strftime("%Y-%m-%d %H:%M:%S") - response = agent1.talk({ "target": "Natasha", "other_agents": [agent2], "timestamp": timestamp }) + response = agent1.talk( + {"target": "Natasha", "other_agents": [agent2], "timestamp": timestamp} + ) msg = f"{agent1} said to {agent2}: {response}" print(msg) convos.append(msg) - response = agent2.talk({ "target": "Viktor", "other_agents": [agent1], "timestamp": timestamp }) + response = agent2.talk( + {"target": "Viktor", "other_agents": [agent1], "timestamp": timestamp} + ) msg = f"{agent2} said to {agent1}: {response}" print(msg) convos.append(msg) @@ -370,25 +502,36 @@ def test_talk(self): # matrix.print_matrix() unix_time = unix_time + 10 convos_string = "\n".join(convos) - prompt = f"evaluate on a score of 1-10 to tell me if the conversation sounds like a real spoke conversation ,give your explanation, and suggestions for improvements. Does the conversation go on too long? are they repeating themselves?:\n\n{convos_string} \n\n write your response like this:\nScore: 2\nExplanation: It has problems with ....\nSuggestions: how to improve it" + prompt = ( + f"evaluate on a score of 1-10 to tell me if the conversation " + f"sounds like a real spoke conversation ,give your explanation, " + f"and suggestions for improvements. Does the conversation go on too long? " + f"are they repeating themselves?:\n\n{convos_string} \n\n " + f"write your response like this:\nScore: 2\nExplanation: " + f"It has problems with ....\nSuggestions: how to improve it" + ) result = llm.generate(prompt) print(prompt) print(result) def test_llmaction(self): + """ + This function tests agent actions from llm calls. + """ + matrix_data = { "scenario": "configs/def.json", "environment": "configs/largev2.tmj", "id": "test-id", "llm_action": 1, "allow_plan": 0, - "allow_reflect": 0 + "allow_reflect": 0, } matrix = Matrix(matrix_data) - for i in range(2): # Assuming 10 steps for the test - #matrix.print_matrix() + for _ in range(2): # Assuming 10 steps for the test + # matrix.print_matrix() for agent in matrix.agents: agent = matrix.llm_action(agent, matrix.unix_time) @@ -399,17 +542,59 @@ def test_location(self): The test will make the agent walk from front of House A1 to House A5. The agent should learn House A1 to House A5 and Town """ + agent_data = { "name": "John", "description": "You are a simulated persona.", "goal": "Answer questions, think, be rational.", "x": 20, - "y": 17 + "y": 17, } - path_to_walk = [(20, 17), (20, 18), (20, 19), (20, 20), (20, 21), (20, 22), (20, 23), (20, 24), (20, 25), (20, 26), (20, 27), (20, 28), (20, 29), (20, 30), (20, 31), (20, 32), (20, 33), (20, 34), (20, 35), (20, 36), (20, 37), (20, 38), (20, 39), (20, 40), (20, 41), (20, 42), (20, 43), (20, 44), (20, 45), (20, 46), (20, 47), (20, 48), (20, 49), (20, 50), (20, 51), (20, 52), (20, 53), (20, 54), (20, 55), (20, 56)] + path_to_walk = [ + (20, 17), + (20, 18), + (20, 19), + (20, 20), + (20, 21), + (20, 22), + (20, 23), + (20, 24), + (20, 25), + (20, 26), + (20, 27), + (20, 28), + (20, 29), + (20, 30), + (20, 31), + (20, 32), + (20, 33), + (20, 34), + (20, 35), + (20, 36), + (20, 37), + (20, 38), + (20, 39), + (20, 40), + (20, 41), + (20, 42), + (20, 43), + (20, 44), + (20, 45), + (20, 46), + (20, 47), + (20, 48), + (20, 49), + (20, 50), + (20, 51), + (20, 52), + (20, 53), + (20, 54), + (20, 55), + (20, 56), + ] agent = Agent(agent_data) - environment = Environment({ "filename": "configs/largev2.tmj" }) + environment = Environment({"filename": "configs/largev2.tmj"}) agent.destination_cache = path_to_walk for loc in environment.locations: if loc.name == "House A5": @@ -424,10 +609,9 @@ def test_location(self): for obj in area.objects: print(f"\t\t-{obj.name}") - for i in path_to_walk: + for _ in path_to_walk: agent.perceive([], environment, "2023-01-01 00:00:00") - agent.move({ "environment": environment }) - + agent.move({"environment": environment}) print("\nAgent Spatial Memories at end:") for loc in agent.spatial_memory: @@ -440,11 +624,15 @@ def test_location(self): agent.answer("What are the locations you discovered?") def test_speed(self, test_vllm=False): + """ + This function tests the speed of the llm model. + """ + if test_vllm: - AVAILABLE_MODELS = VLLM_MODELS + ["mistral", "orca-mini"] + available_models = VLLM_MODELS + ["mistral", "orca-mini"] else: - AVAILABLE_MODELS = ["mistral", "orca-mini"] - MODEL_TIMES = [] + available_models = ["mistral", "orca-mini"] + model_times = [] prompt = """ Your name is Alice Description: Alice loves exploring.; Alice loves hanging out at the park; @@ -481,39 +669,43 @@ def test_speed(self, test_vllm=False): Explanation: George will move because he needs to be at the Park at 18:00. Answer: move Park """ - for model in AVAILABLE_MODELS: + for model in available_models: print(f"Creating LLM Instance for model: {model}") new_llm = Llm(model=model) start_time = time.time() - for i in range(10): + for _ in range(10): new_llm.generate(prompt) end_time = time.time() print(f"Deleting LLM Instance for model: {model}") del new_llm - MODEL_TIMES.append({ model: end_time - start_time }) + model_times.append({model: end_time - start_time}) - for time_log in MODEL_TIMES: + for time_log in model_times: print(f"{time_log}") def test_thread(self): + """ + This function tests agents' memories running in threads. + """ + agent_data = { "name": "John", "description": "You are a simulated persona.", - "goal": "Answer questions, think, be rational." + "goal": "Answer questions, think, be rational.", } agent1 = Agent(agent_data) agent_data = { "name": "Michael", "description": "You are a simulated persona.", - "goal": "Answer questions, think, be rational." + "goal": "Answer questions, think, be rational.", } agent2 = Agent(agent_data) - environment = Environment() + # environment = Environment() print("Agent 1 memory before") print(agent1.short_memory) print("Agent 2 memory before") print(agent2.short_memory) - for i in range(10): + for _ in range(10): with concurrent.futures.ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor: print("Agent 1 memory during") print(agent1.short_memory) @@ -521,9 +713,27 @@ def test_thread(self): print(agent2.short_memory) timestamp = "2023-12-08 21:30:40" futures = [] - futures.append(executor.submit(agent1.talk, { "target": agent2.name, "other_agents": [agent2], "timestamp": timestamp })) - futures.append(executor.submit(agent2.talk, { "target": agent1.name, "other_agents": [agent1], "timestamp": timestamp })) - results = [future.result() for future in futures] + futures.append( + executor.submit( + agent1.talk, + { + "target": agent2.name, + "other_agents": [agent2], + "timestamp": timestamp, + }, + ) + ) + futures.append( + executor.submit( + agent2.talk, + { + "target": agent1.name, + "other_agents": [agent1], + "timestamp": timestamp, + }, + ) + ) + # results = [future.result() for future in futures] print("Agent 1 memory after") print(agent1.short_memory) @@ -531,29 +741,38 @@ def test_thread(self): print(agent2.short_memory) def test_agent_decision_zombie(self): + """ + This function tests agent's decision on a zombie encounter. + """ + matrix_data = { "scenario": None, "environment": "configs/largev2.tmj", "id": "test-agent-decision-zombie", "llm_action": 1, "allow_plan": 0, - "allow_reflect": 0 + "allow_reflect": 0, } matrix = Matrix(matrix_data) - matrix.interview_questions = [{"who": "all", "question": "Is the park a safe place?" }, {"who": "all", "question": "What do you plan to do now?" }] + matrix.interview_questions = [ + {"who": "all", "question": "Is the park a safe place?"}, + {"who": "all", "question": "What do you plan to do now?"}, + ] agent_data = { "name": "John", "kind": "human", "description": "Town is now zombie infested. You live at House A1.", "goal": "Survive.", - "x": 36, "y": 87 # This is just outside park + "x": 36, + "y": 87, # This is just outside park } zombie_data = { "name": "Zombie", "kind": "zombie", - "x": 36, "y": 93 # This is just inside park + "x": 36, + "y": 93, # This is just inside park } agent = Agent(agent_data) zombie = Agent(zombie_data) @@ -572,13 +791,21 @@ def test_agent_decision_zombie(self): agent.destination_cache = [(36, 88), (36, 89), (36, 90)] zombie.destination_cache = [(36, 93), (36, 93), (36, 93)] - agent.addMemory("reflect", f"{matrix.unix_to_strftime(matrix.unix_time)} - {agent} wants to check if the Park is a safe place to go to or no.", matrix.unix_to_strftime(matrix.unix_time), 9) + agent.addMemory( + "reflect", + ( + f"{matrix.unix_to_strftime(matrix.unix_time)} - {agent} " + f"wants to check if the Park is a safe place to go to or no." + ), + matrix.unix_to_strftime(matrix.unix_time), + 9, + ) matrix.agents.append(agent) matrix.agents.append(zombie) - for i in range(10): + for _ in range(10): for a in matrix.agents: - if matrix.llm_action_flag == 1 and a.kind != 'zombie': + if matrix.llm_action_flag == 1 and a.kind != "zombie": matrix.llm_action(a, matrix.unix_time) else: matrix.agent_action(a, matrix.unix_time) @@ -586,26 +813,43 @@ def test_agent_decision_zombie(self): matrix.unix_time = matrix.unix_time + 10 for a in matrix.agents: - print(a.__str__(verbose=True)) + print(str(a)) matrix.run_interviews() def test_summary(self): + """ + This function tests summary of agent conversations. + """ + agent1_data = { "name": "Natasha", "description": "Natasha is confident and loves sports. Natasha lives at 'House B1'.", - "goal": "Natasha is planning to host a Christmas Party with her friends. Natasha decides on the location and time of the party. Natasha's mission is to extend invitations to every person encountered, fostering a joyous gathering filled with laughter, music, and festive cheer. Additionally, Natasha will encourage others to join in the celebration and invite their acquaintances, creating an unforgettable experience for everyone involved." - } - agent2_data = { - "name": "James" + "goal": ( + "Natasha is planning to host a Christmas Party with her friends. " + "Natasha decides on the location and time of the party. " + "Natasha's mission is to extend invitations to every person encountered, " + "fostering a joyous gathering filled with laughter, music, and festive cheer. " + "Additionally, Natasha will encourage others to join in the celebration and invite " + "their acquaintances, creating an unforgettable experience for everyone involved." + ), } + agent2_data = {"name": "James"} conversation_arr = [ - '''2023-12-08 21:30:40 - Natasha said to James: "James, I'm hosting a Christmas party at House B1. Would you and your friends be interested in joining us?"''', - '''2023-12-08 21:30:40 - James said to Natasha: I'd be happy to attend, Natasha. Thank you for inviting us. Paul and I will make sure to be there.''', - '''2023-12-08 21:30:50 - Natasha said to James: 2023-12-08 21:35:00 - I'm glad you can make it, James. Looking forward to a wonderful Christmas party at House B1 with you and Paul. Let me know if there's anything specific you or your friends would like to contribute to the celebration.''', - '''2023-12-08 21:30:50 - James said to Natasha: I'll let Natasha know if Paul and I bring anything for the party. Thanks for asking, Natasha.''', - '''2023-12-08 21:31:00 - Natasha said to James: I'm glad you both can make it, James. Looking forward to your contribution to the Christmas party at House B1. Let me know if there's anything specific Paul and you would like to bring.''' + '''2023-12-08 21:30:40 - Natasha said to James: "James, I'm hosting a Christmas party + at House B1. Would you and your friends be interested in joining us?"''', + """2023-12-08 21:30:40 - James said to Natasha: I'd be happy to attend, Natasha. + Thank you for inviting us. Paul and I will make sure to be there.""", + """2023-12-08 21:30:50 - Natasha said to James: 2023-12-08 21:35:00 - + I'm glad you can make it, James. Looking forward to a wonderful Christmas party + at House B1 with you and Paul. Let me know if there's anything specific you or + your friends would like to contribute to the celebration.""", + """2023-12-08 21:30:50 - James said to Natasha: I'll let Natasha know if Paul + and I bring anything for the party. Thanks for asking, Natasha.""", + """2023-12-08 21:31:00 - Natasha said to James: I'm glad you both can make it, + James. Looking forward to your contribution to the Christmas party at House B1. + Let me know if there's anything specific Paul and you would like to bring.""", ] agent1 = Agent(agent1_data) @@ -616,13 +860,20 @@ def test_summary(self): agent1.last_conversation = new_convo agent1.summarize_conversation("2023-12-08 21:31:00") + def main(): - parser = argparse.ArgumentParser(description='Matrix Test Suite') - parser.add_argument('--all', action='store_true', help='Enable all test flag') - parser.add_argument('--test', type=str, default='all', help='Context for relevance score test') - parser.add_argument('--context', type=str, default='racing', help='Context for relevance score test') - parser.add_argument('--history', action='store_true', help='Agents know each other flag') - parser.add_argument('--steps', type=int, default=10, help='Steps for llm_action test.') + """ + This method runs all test functions. + """ + + parser = argparse.ArgumentParser(description="Matrix Test Suite") + parser.add_argument("--all", action="store_true", help="Enable all test flag") + parser.add_argument("--test", type=str, default="all", help="Context for relevance score test") + parser.add_argument( + "--context", type=str, default="racing", help="Context for relevance score test" + ) + parser.add_argument("--history", action="store_true", help="Agents know each other flag") + parser.add_argument("--steps", type=int, default=10, help="Steps for llm_action test.") args = parser.parse_args() if args.test and args.test != "all": @@ -641,5 +892,6 @@ def main(): print("Errors:", len(result.errors)) print("Failures:", len(result.failures)) -if __name__ == '__main__': + +if __name__ == "__main__": main() From 2edaa7692d7345a49e8d52494074c0a8a7597e1f Mon Sep 17 00:00:00 2001 From: chiefeu Date: Sat, 16 Mar 2024 00:27:54 +0800 Subject: [PATCH 5/5] fixed errors for test_matrix_runs_step --- src/matrix.py | 8 ++++++-- test.py | 16 ++++++++++++++++ utils/utils.py | 7 ++++--- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/matrix.py b/src/matrix.py index 768fc94..fe97e38 100644 --- a/src/matrix.py +++ b/src/matrix.py @@ -215,8 +215,12 @@ def parse_scenario_file(self, filename): self.allow_movement = data.get("allow_movement", ALLOW_MOVEMENT) self.background = data.get("background", "") self.performance_evals = data.get("performance", {}) - self.performance_metrics[self.performance_evals["numerator"]] = 0 - self.performance_metrics["denominator"] = self.performance_evals["denominator"] + if not self.performance_evals: + self.performance_metrics["total_alive"] = 0 + self.performance_metrics["denominator"] = "total_agents" + else: + self.performance_metrics[self.performance_evals["numerator"]] = 0 + self.performance_metrics["denominator"] = self.performance_evals["denominator"] if self.steps <= 0: self.steps = data.get("steps", 100) diff --git a/test.py b/test.py index 4abd6c0..17fae71 100644 --- a/test.py +++ b/test.py @@ -69,6 +69,22 @@ def test_fine_move_action_moves_away(self): matrix.add_agent_to_simulation(zombie) matrix.llm_action(real_agent, matrix.unix_time) self.assertEqual(real_agent.x, 4) + + def test_matrix_runs_step(self): + """ + This function tests if matrix runs a step successfully. + (If yes, the pylint-fix branch can be merged). + """ + + matrix = Matrix( + {"scenario":"configs/empty.json","environment":"configs/largev2.tmj"} + ) + #run for one step + matrix.steps = 1 + matrix.boot() + matrix.run_singlethread() + self.assertTrue(len(matrix.agents) > 0) + self.assertEqual(matrix.status,"complete") def test_memory(self): """ diff --git a/utils/utils.py b/utils/utils.py index 6078951..0a6cbda 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -9,6 +9,7 @@ import difflib import random import json +import uuid from datetime import datetime import nltk import redis @@ -298,10 +299,10 @@ def prompt(self, prompt_name, variables=None, fallback="Llm Error"): """ # TODO get rid of globals if "REDIS_URL" in globals(): - REDIS_CONNECTION = redis.Redis.from_url(REDIS_URL) + redis_connection = redis.Redis.from_url(REDIS_URL) else: print("REDIS_URL environment variable is not set.") - REDIS_CONNECTION = None + redis_connection = None def print_and_log(content, key): @@ -312,7 +313,7 @@ def print_and_log(content, key): def redis_log(content, key): if LOG_TO_REDIS == 1: - REDIS_CONNECTION.rpush(key, json.dumps(content)) + redis_connection.rpush(key, json.dumps(content)) def find_most_similar(inp, arr):