Jofthomas HF staff commited on
Commit
dff2a4a
1 Parent(s): 9bbddc7

Multiplayer setting.

Browse files

Hey

@radames

!

I normally uploaded the change to make this space properly multiplayer.
Let's review changes carefully together before merging

patches/Dockerfile ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM ubuntu:22.04 as base
2
+ WORKDIR /app
3
+ ENV NODE_ENV=production
4
+
5
+ FROM base as build
6
+
7
+ RUN apt-get update -qq && \
8
+ apt-get install -y git curl unzip wget gnupg build-essential lsb-release
9
+
10
+ RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && \
11
+ apt-get install -y nodejs
12
+
13
+ RUN useradd -m -u 1000 user
14
+ RUN chown -R user:user /app /usr/local /tmp
15
+ USER user
16
+ ENV HOME=/home/user \
17
+ PATH=/home/user/.local/bin:$PATH
18
+
19
+ WORKDIR $HOME/app
20
+
21
+ RUN git clone https://github.com/a16z-infra/ai-town.git . && \
22
+ git checkout f005c46d1759b47bb3ade8d41952a713c4faf331
23
+
24
+ RUN npm install --include=dev @huggingface/inference
25
+ RUN npm install --include=dev @huggingface/hub
26
+
27
+ RUN curl -L -O https://github.com/get-convex/convex-backend/releases/download/precompiled-2024-05-07-13337fd/convex-local-backend-x86_64-unknown-linux-gnu.zip && \
28
+ unzip convex-local-backend-x86_64-unknown-linux-gnu.zip
29
+
30
+ COPY ./patches/llm.ts ./convex/util/
31
+ COPY ./patches/vite.config.ts ./
32
+ COPY ./patches/constants.ts ./patches/music.ts ./convex/
33
+ COPY ./patches/characters.ts ./patches/gentle.js ./data/
34
+ COPY ./patches/PixiGame.tsx ./src/components/PixiGame.tsx
35
+ COPY ./patches/PixiStaticMap.tsx ./src/components/
36
+ COPY ./patches/Button.tsx ./src/components/buttons/Button.tsx
37
+ COPY ./patches/InteractButton.tsx ./src/components/buttons/InteractButton.tsx
38
+ COPY ./patches/OAuthLogin.tsx ./src/components/buttons/OAuthLogin.tsx
39
+ COPY ./patches/App.tsx ./src/App.tsx
40
+ COPY ./patches/world.ts ./convex/world.ts
41
+ COPY ./patches/PlayerDetails.tsx ./src/components/PlayerDetails.tsx
42
+
43
+ COPY ./patches/hf.svg ./assets/hf.svg
44
+
45
+ COPY ./patches/run.sh ./
46
+
47
+ CMD ["./run.sh"]
patches/README.md ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: AI Town on HuggingFace
3
+ emoji: 🏠💻💌🤗
4
+ colorFrom: green
5
+ colorTo: red
6
+ sdk: docker
7
+ app_port: 5173
8
+ pinned: false
9
+ disable_embedding: true
10
+ # header: mini
11
+ short_description: AI Town on HuggingFace
12
+ hf_oauth: true
13
+ ---
14
+
15
+ # AI Town 🏠💻💌 on Hugging Face 🤗
16
+
17
+ [**Demo on Hugging Face Spaces**](https://huggingface.co/spaces/radames/ai-town)
18
+
19
+ AI Town is a very cool project by [Yoko](https://github.com/ykhli) et [al.](https://github.com/a16z-infra/ai-town), a virtual town with live AI characters where they can chat and socialize. You can also interact with them by sending them messages.
20
+
21
+ This repository contains a few code patches to make AI Town run on [Hugging Face 🤗 Spaces](https://huggingface.co/spaces), as well as a Dockerfile capable of running [Convex open-source backend](https://github.com/get-convex/convex-backend), the backend and frontend on a single container.
22
+
23
+ ## How to run locally
24
+
25
+ Grab your Hugging Face API token from https://huggingface.co/settings/tokens
26
+
27
+ ```bash
28
+ export HF_TOKEN=hf_**********
29
+ docker build -t ai-town -f Dockerfile .
30
+ docker run -ti -p 5173:5173 -e LLM_API_KEY=$HF_TOKEN ai-town
31
+ ```
32
+
33
+ ## How to run on Hugging Face
34
+
35
+ You can duplicate this Space https://huggingface.co/spaces/radames/ai-town?duplicate=true, add your `HF_TOKEN`
36
+ Then you can customize [patches/constants.ts](patches/constants.ts) and [patches/characters.ts](patches/characters.ts) as you wish, as well as the LLM model and embeddings model in [patches/llm.ts](patches/llm.ts).
patches/patches/App.tsx ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import Game from './components/Game.tsx';
2
+
3
+ import { ToastContainer } from 'react-toastify';
4
+ import a16zImg from '../assets/a16z.png';
5
+ import convexImg from '../assets/convex.svg';
6
+ import starImg from '../assets/star.svg';
7
+ import helpImg from '../assets/help.svg';
8
+ // import { UserButton } from '@clerk/clerk-react';
9
+ // import { Authenticated, Unauthenticated } from 'convex/react';
10
+ // import LoginButton from './components/buttons/LoginButton.tsx';
11
+ import { useState } from 'react';
12
+ import ReactModal from 'react-modal';
13
+ import MusicButton from './components/buttons/MusicButton.tsx';
14
+ import Button from './components/buttons/Button.tsx';
15
+ import InteractButton from './components/buttons/InteractButton.tsx';
16
+ import FreezeButton from './components/FreezeButton.tsx';
17
+ import { MAX_HUMAN_PLAYERS } from '../convex/constants.ts';
18
+ import PoweredByConvex from './components/PoweredByConvex.tsx';
19
+ import OAuthLogin from './components/buttons/OAuthLogin.tsx';
20
+
21
+ export default function Home() {
22
+ const [helpModalOpen, setHelpModalOpen] = useState(false);
23
+ return (
24
+ <main className="relative flex min-h-screen flex-col items-center justify-between font-body game-background">
25
+ <PoweredByConvex />
26
+
27
+ <ReactModal
28
+ isOpen={helpModalOpen}
29
+ onRequestClose={() => setHelpModalOpen(false)}
30
+ style={modalStyles}
31
+ contentLabel="Help modal"
32
+ ariaHideApp={false}
33
+ >
34
+ <div className="font-body">
35
+ <h1 className="text-center text-6xl font-bold font-display game-title">Help</h1>
36
+ <p>
37
+ Welcome to AI town. AI town supports both anonymous <i>spectators</i> and logged in{' '}
38
+ <i>interactivity</i>.
39
+ </p>
40
+ <h2 className="text-4xl mt-4">Spectating</h2>
41
+ <p>
42
+ Click and drag to move around the town, and scroll in and out to zoom. You can click on
43
+ an individual character to view its chat history.
44
+ </p>
45
+ <h2 className="text-4xl mt-4">Interactivity</h2>
46
+ <p>
47
+ If you log in, you can join the simulation and directly talk to different agents! After
48
+ logging in, click the "Interact" button, and your character will appear somewhere on the
49
+ map with a highlighted circle underneath you.
50
+ </p>
51
+ <p className="text-2xl mt-2">Controls:</p>
52
+ <p className="mt-4">Click to navigate around.</p>
53
+ <p className="mt-4">
54
+ To talk to an agent, click on them and then click "Start conversation," which will ask
55
+ them to start walking towards you. Once they're nearby, the conversation will start, and
56
+ you can speak to each other. You can leave at any time by closing the conversation pane
57
+ or moving away. They may propose a conversation to you - you'll see a button to accept
58
+ in the messages panel.
59
+ </p>
60
+ <p className="mt-4">
61
+ AI town only supports {MAX_HUMAN_PLAYERS} humans at a time. If you're idle for five
62
+ minutes, you'll be automatically removed from the simulation.
63
+ </p>
64
+ </div>
65
+ </ReactModal>
66
+ {/*<div className="p-3 absolute top-0 right-0 z-10 text-2xl">
67
+ <Authenticated>
68
+ <UserButton afterSignOutUrl="/ai-town" />
69
+ </Authenticated>
70
+
71
+ <Unauthenticated>
72
+ <LoginButton />
73
+ </Unauthenticated>
74
+ </div> */}
75
+
76
+ <div className="w-full lg:h-screen min-h-screen relative isolate overflow-hidden lg:p-8 shadow-2xl flex flex-col justify-start">
77
+ <h1 className="mx-auto text-4xl p-3 sm:text-8xl lg:text-9xl font-bold font-display leading-none tracking-wide game-title w-full text-left sm:text-center sm:w-auto">
78
+ AI Town
79
+ </h1>
80
+
81
+ <div className="max-w-xs md:max-w-xl lg:max-w-none mx-auto my-4 text-center text-base sm:text-xl md:text-2xl text-white leading-tight shadow-solid">
82
+ A virtual town where AI characters live, chat and socialize.
83
+ {/* <Unauthenticated>
84
+ <div className="my-1.5 sm:my-0" />
85
+ Log in to join the town
86
+ <br className="block sm:hidden" /> and the conversation!
87
+ </Unauthenticated> */}
88
+ </div>
89
+
90
+ <Game />
91
+
92
+ <footer className="justify-end bottom-0 left-0 w-full flex items-center mt-4 gap-3 p-6 flex-wrap pointer-events-none">
93
+ <div className="flex gap-4 flex-grow pointer-events-none">
94
+ {/*
95
+ Users shall not be able freeze in multiplayer
96
+ <FreezeButton />
97
+ */}
98
+ <MusicButton />
99
+ <Button href="https://github.com/a16z-infra/ai-town" imgUrl={starImg}>
100
+ Star
101
+ </Button>
102
+ <InteractButton />
103
+ <Button imgUrl={helpImg} onClick={() => setHelpModalOpen(true)}>
104
+ Help
105
+ </Button>
106
+ <OAuthLogin />
107
+ </div>
108
+ <a href="https://a16z.com" target="_blank">
109
+ <img className="w-8 h-8 pointer-events-auto" src={a16zImg} alt="a16z" />
110
+ </a>
111
+ <a href="https://convex.dev" target="_blank">
112
+ <img className="w-20 h-8 pointer-events-auto" src={convexImg} alt="Convex" />
113
+ </a>
114
+ </footer>
115
+ <ToastContainer position="bottom-right" autoClose={2000} closeOnClick theme="dark" />
116
+ </div>
117
+ </main>
118
+ );
119
+ }
120
+
121
+ const modalStyles = {
122
+ overlay: {
123
+ backgroundColor: 'rgb(0, 0, 0, 75%)',
124
+ zIndex: 12,
125
+ },
126
+ content: {
127
+ top: '50%',
128
+ left: '50%',
129
+ right: 'auto',
130
+ bottom: 'auto',
131
+ marginRight: '-50%',
132
+ transform: 'translate(-50%, -50%)',
133
+ maxWidth: '50%',
134
+
135
+ border: '10px solid rgb(23, 20, 33)',
136
+ borderRadius: '0',
137
+ background: 'rgb(35, 38, 58)',
138
+ color: 'white',
139
+ fontFamily: '"Upheaval Pro", "sans-serif"',
140
+ },
141
+ };
patches/patches/Button.tsx ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import clsx from 'clsx';
2
+ import { MouseEventHandler, ReactNode } from 'react';
3
+
4
+ export default function Button(props: {
5
+ className?: string;
6
+ href?: string;
7
+ imgUrl: string;
8
+ onClick?: MouseEventHandler;
9
+ title?: string;
10
+ children: ReactNode;
11
+ }) {
12
+ return (
13
+ <a
14
+ className={clsx(
15
+ 'button text-white shadow-solid text-xl pointer-events-auto',
16
+ props.className,
17
+ )}
18
+ href={props.href}
19
+ title={props.title}
20
+ onClick={props.onClick}
21
+ target="_blank"
22
+ >
23
+ <div className="inline-block bg-clay-700">
24
+ <span>
25
+ <div className="inline-flex h-full items-center gap-4">
26
+ <img className="w-4 h-4 sm:w-[30px] sm:h-[30px]" src={props.imgUrl} />
27
+ {props.children}
28
+ </div>
29
+ </span>
30
+ </div>
31
+ </a>
32
+ );
33
+ }
patches/patches/InteractButton.tsx ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import Button from './Button';
2
+ import { toast } from 'react-toastify';
3
+ import interactImg from '../../../assets/interact.svg';
4
+ import { useConvex, useMutation, useQuery } from 'convex/react';
5
+ import { api } from '../../../convex/_generated/api';
6
+ // import { SignInButton } from '@clerk/clerk-react';
7
+ import { ConvexError } from 'convex/values';
8
+ import { Id } from '../../../convex/_generated/dataModel';
9
+ import { useCallback } from 'react';
10
+ import { waitForInput } from '../../hooks/sendInput';
11
+ import { useServerGame } from '../../hooks/serverGame';
12
+
13
+ export default function InteractButton() {
14
+ // const { isAuthenticated } = useConvexAuth();
15
+ const worldStatus = useQuery(api.world.defaultWorldStatus);
16
+ const worldId = worldStatus?.worldId;
17
+ const game = useServerGame(worldId);
18
+ const oauth = JSON.parse(localStorage.getItem('oauth'));
19
+ const oauthToken = oauth ? oauth.userInfo.fullname : undefined;
20
+ console.log(oauthToken)
21
+ const humanTokenIdentifier = useQuery(api.world.userStatus, worldId ? { worldId, oauthToken } : 'skip');
22
+ const userPlayerId =
23
+ game && [...game.world.players.values()].find((p) => p.human === humanTokenIdentifier)?.id;
24
+ const join = useMutation(api.world.joinWorld);
25
+ const leave = useMutation(api.world.leaveWorld);
26
+ const isPlaying = !!userPlayerId;
27
+
28
+ const convex = useConvex();
29
+ const joinInput = useCallback(
30
+ async (worldId: Id<'worlds'>) => {
31
+ let inputId;
32
+ try {
33
+ inputId = await join({ worldId, oauthToken });
34
+ } catch (e: any) {
35
+ if (e instanceof ConvexError) {
36
+ toast.error(e.data);
37
+ return;
38
+ }
39
+ throw e;
40
+ }
41
+ try {
42
+ await waitForInput(convex, inputId);
43
+ } catch (e: any) {
44
+ toast.error(e.message);
45
+ }
46
+ },
47
+ [convex, join, oauthToken],
48
+ );
49
+
50
+
51
+ const joinOrLeaveGame = () => {
52
+ if (
53
+ !worldId ||
54
+ // || !isAuthenticated
55
+ game === undefined
56
+ ) {
57
+ return;
58
+ }
59
+ if (isPlaying) {
60
+ console.log(`Leaving game for player ${userPlayerId}`);
61
+ void leave({ worldId , oauthToken});
62
+ } else {
63
+ console.log(`Joining game`);
64
+ void joinInput(worldId);
65
+ }
66
+ };
67
+ // if (!isAuthenticated || game === undefined) {
68
+ // return (
69
+ // <SignInButton>
70
+ // <button className="button text-white shadow-solid text-2xl pointer-events-auto">
71
+ // <div className="inline-block bg-clay-700">
72
+ // <span>
73
+ // <div className="inline-flex h-full items-center gap-4">
74
+ // <img className="w-4 h-4 sm:w-[30px] sm:h-[30px]" src={interactImg} />
75
+ // Interact
76
+ // </div>
77
+ // </span>
78
+ // </div>
79
+ // </button>
80
+ // </SignInButton>
81
+ // );
82
+ // }
83
+ return (
84
+ <Button imgUrl={interactImg} onClick={joinOrLeaveGame}>
85
+ {isPlaying ? 'Leave' : 'Interact'}
86
+ </Button>
87
+ );
88
+ }
patches/patches/OAuthLogin.tsx ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useState, useEffect } from 'react';
2
+ import Button from './Button';
3
+ import hf from '../../../assets/hf.svg';
4
+ import { oauthLoginUrl, oauthHandleRedirectIfPresent } from '@huggingface/hub';
5
+
6
+ const OAuthLogin = () => {
7
+ const [isSignedIn, setIsSignedIn] = useState(false);
8
+
9
+ useEffect(() => {
10
+ const checkAuthStatus = async () => {
11
+ let oauthResult = localStorage.getItem('oauth');
12
+ if (oauthResult) {
13
+ try {
14
+ oauthResult = JSON.parse(oauthResult);
15
+ } catch {
16
+ oauthResult = null;
17
+ }
18
+ }
19
+
20
+ if (!oauthResult) {
21
+ oauthResult = await oauthHandleRedirectIfPresent();
22
+ if (oauthResult) {
23
+ localStorage.setItem('oauth', JSON.stringify(oauthResult));
24
+ }
25
+ }
26
+
27
+ setIsSignedIn(!!oauthResult);
28
+ };
29
+
30
+ checkAuthStatus();
31
+ }, []);
32
+
33
+ const handleSignIn = async () => {
34
+ let clientId = import.meta.env.VITE_OAUTH_CLIENT_ID;
35
+ window.location.href = await oauthLoginUrl({ clientId });
36
+ };
37
+
38
+ const handleSignOut = () => {
39
+ localStorage.removeItem('oauth');
40
+ window.location.href = window.location.href.replace(/\?.*$/, '');
41
+ setIsSignedIn(false);
42
+ };
43
+
44
+ return (
45
+ <>
46
+ {isSignedIn ? (
47
+ <Button id="signout" imgUrl={hf} onClick={handleSignOut}>Sign out</Button>
48
+ ) : (
49
+ <Button id="signin" imgUrl={hf} onClick={handleSignIn}>
50
+ Sign in with Hugging Face
51
+ </Button>
52
+ )}
53
+ </>
54
+ );
55
+ };
56
+
57
+ export default OAuthLogin;
patches/patches/PixiGame.tsx ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import * as PIXI from 'pixi.js';
2
+ import { useApp } from '@pixi/react';
3
+ import { Player, SelectElement } from './Player.tsx';
4
+ import { useEffect, useRef, useState } from 'react';
5
+ import { PixiStaticMap } from './PixiStaticMap.tsx';
6
+ import PixiViewport from './PixiViewport.tsx';
7
+ import { Viewport } from 'pixi-viewport';
8
+ import { Id } from '../../convex/_generated/dataModel';
9
+ import { useQuery } from 'convex/react';
10
+ import { api } from '../../convex/_generated/api.js';
11
+ import { useSendInput } from '../hooks/sendInput.ts';
12
+ import { toastOnError } from '../toasts.ts';
13
+ import { DebugPath } from './DebugPath.tsx';
14
+ import { PositionIndicator } from './PositionIndicator.tsx';
15
+ import { SHOW_DEBUG_UI } from './Game.tsx';
16
+ import { ServerGame } from '../hooks/serverGame.ts';
17
+
18
+ export const PixiGame = (props: {
19
+ worldId: Id<'worlds'>;
20
+ engineId: Id<'engines'>;
21
+ game: ServerGame;
22
+ historicalTime: number | undefined;
23
+ width: number;
24
+ height: number;
25
+ setSelectedElement: SelectElement;
26
+ }) => {
27
+ // PIXI setup.
28
+ const pixiApp = useApp();
29
+ const viewportRef = useRef<Viewport | undefined>();
30
+ const oauth = JSON.parse(localStorage.getItem('oauth'));
31
+ const oauthToken = oauth ? oauth.userInfo.fullname : undefined;
32
+ const humanTokenIdentifier = useQuery(api.world.userStatus, { worldId: props.worldId, oauthToken }) ?? null;
33
+ const humanPlayerId = [...props.game.world.players.values()].find(
34
+ (p) => p.human === humanTokenIdentifier,
35
+ )?.id;
36
+
37
+ const moveTo = useSendInput(props.engineId, 'moveTo');
38
+
39
+ // Interaction for clicking on the world to navigate.
40
+ const dragStart = useRef<{ screenX: number; screenY: number } | null>(null);
41
+ const onMapPointerDown = (e: any) => {
42
+ // https://pixijs.download/dev/docs/PIXI.FederatedPointerEvent.html
43
+ dragStart.current = { screenX: e.screenX, screenY: e.screenY };
44
+ };
45
+
46
+ const [lastDestination, setLastDestination] = useState<{
47
+ x: number;
48
+ y: number;
49
+ t: number;
50
+ } | null>(null);
51
+ const onMapPointerUp = async (e: any) => {
52
+ if (dragStart.current) {
53
+ const { screenX, screenY } = dragStart.current;
54
+ dragStart.current = null;
55
+ const [dx, dy] = [screenX - e.screenX, screenY - e.screenY];
56
+ const dist = Math.sqrt(dx * dx + dy * dy);
57
+ if (dist > 10) {
58
+ console.log(`Skipping navigation on drag event (${dist}px)`);
59
+ return;
60
+ }
61
+ }
62
+ if (!humanPlayerId) {
63
+ return;
64
+ }
65
+ const viewport = viewportRef.current;
66
+ if (!viewport) {
67
+ return;
68
+ }
69
+ const gameSpacePx = viewport.toWorld(e.screenX, e.screenY);
70
+ const tileDim = props.game.worldMap.tileDim;
71
+ const gameSpaceTiles = {
72
+ x: gameSpacePx.x / tileDim,
73
+ y: gameSpacePx.y / tileDim,
74
+ };
75
+ setLastDestination({ t: Date.now(), ...gameSpaceTiles });
76
+ const roundedTiles = {
77
+ x: Math.floor(gameSpaceTiles.x),
78
+ y: Math.floor(gameSpaceTiles.y),
79
+ };
80
+ console.log(`Moving to ${JSON.stringify(roundedTiles)}`);
81
+ await toastOnError(moveTo({ playerId: humanPlayerId, destination: roundedTiles }));
82
+ };
83
+ const { width, height, tileDim } = props.game.worldMap;
84
+ const players = [...props.game.world.players.values()];
85
+
86
+ // Zoom on the user’s avatar when it is created
87
+ useEffect(() => {
88
+ if (!viewportRef.current || humanPlayerId === undefined) return;
89
+
90
+ const humanPlayer = props.game.world.players.get(humanPlayerId)!;
91
+ viewportRef.current.animate({
92
+ position: new PIXI.Point(humanPlayer.position.x * tileDim, humanPlayer.position.y * tileDim),
93
+ scale: 1.5,
94
+ });
95
+ }, [humanPlayerId]);
96
+
97
+ return (
98
+ <PixiViewport
99
+ app={pixiApp}
100
+ screenWidth={props.width}
101
+ screenHeight={props.height}
102
+ worldWidth={width * tileDim}
103
+ worldHeight={height * tileDim}
104
+ viewportRef={viewportRef}
105
+ >
106
+ <PixiStaticMap
107
+ map={props.game.worldMap}
108
+ onpointerup={onMapPointerUp}
109
+ onpointerdown={onMapPointerDown}
110
+ />
111
+ {players.map(
112
+ (p) =>
113
+ // Only show the path for the human player in non-debug mode.
114
+ (SHOW_DEBUG_UI || p.id === humanPlayerId) && (
115
+ <DebugPath key={`path-${p.id}`} player={p} tileDim={tileDim} />
116
+ ),
117
+ )}
118
+ {lastDestination && <PositionIndicator destination={lastDestination} tileDim={tileDim} />}
119
+ {players.map((p) => (
120
+ <Player
121
+ key={`player-${p.id}`}
122
+ game={props.game}
123
+ player={p}
124
+ isViewer={p.id === humanPlayerId}
125
+ onClick={props.setSelectedElement}
126
+ historicalTime={props.historicalTime}
127
+ />
128
+ ))}
129
+ </PixiViewport>
130
+ );
131
+ };
132
+ export default PixiGame;
patches/patches/PixiStaticMap.tsx ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { PixiComponent, applyDefaultProps } from '@pixi/react';
2
+ import * as PIXI from 'pixi.js';
3
+ import { AnimatedSprite, WorldMap } from '../../convex/aiTown/worldMap';
4
+ import * as campfire from '../../data/animations/campfire.json';
5
+ import * as gentlesparkle from '../../data/animations/gentlesparkle.json';
6
+ import * as gentlewaterfall from '../../data/animations/gentlewaterfall.json';
7
+ import * as gentlesplash from '../../data/animations/gentlesplash.json';
8
+ import * as windmill from '../../data/animations/windmill.json';
9
+
10
+ const animations = {
11
+ 'campfire.json': { spritesheet: campfire, url: '/assets/spritesheets/campfire.png' },
12
+ 'gentlesparkle.json': {
13
+ spritesheet: gentlesparkle,
14
+ url: '/assets/spritesheets/gentlesparkle32.png',
15
+ },
16
+ 'gentlewaterfall.json': {
17
+ spritesheet: gentlewaterfall,
18
+ url: '/assets/spritesheets/gentlewaterfall32.png',
19
+ },
20
+ 'windmill.json': { spritesheet: windmill, url: '/assets/spritesheets/windmill.png' },
21
+ 'gentlesplash.json': {
22
+ spritesheet: gentlesplash,
23
+ url: '/assets/spritesheets/gentlewaterfall32.png',
24
+ },
25
+ };
26
+
27
+ export const PixiStaticMap = PixiComponent('StaticMap', {
28
+ create: (props: { map: WorldMap; [k: string]: any }) => {
29
+ const map = props.map;
30
+ const numxtiles = Math.floor(map.tileSetDimX / map.tileDim);
31
+ const numytiles = Math.floor(map.tileSetDimY / map.tileDim);
32
+ const bt = PIXI.BaseTexture.from(map.tileSetUrl, {
33
+ scaleMode: PIXI.SCALE_MODES.NEAREST,
34
+ });
35
+
36
+ const tiles = [];
37
+ for (let x = 0; x < numxtiles; x++) {
38
+ for (let y = 0; y < numytiles; y++) {
39
+ tiles[x + y * numxtiles] = new PIXI.Texture(
40
+ bt,
41
+ new PIXI.Rectangle(x * map.tileDim, y * map.tileDim, map.tileDim, map.tileDim),
42
+ );
43
+ }
44
+ }
45
+ const screenxtiles = map.bgTiles[0].length;
46
+ const screenytiles = map.bgTiles[0][0].length;
47
+
48
+ const container = new PIXI.Container();
49
+ const allLayers = [...map.bgTiles, ...map.objectTiles];
50
+
51
+ // blit bg & object layers of map onto canvas
52
+ for (let i = 0; i < screenxtiles * screenytiles; i++) {
53
+ const x = i % screenxtiles;
54
+ const y = Math.floor(i / screenxtiles);
55
+ const xPx = x * map.tileDim;
56
+ const yPx = y * map.tileDim;
57
+
58
+ // Add all layers of backgrounds.
59
+ for (const layer of allLayers) {
60
+ const tileIndex = layer[x][y];
61
+ // Some layers may not have tiles at this location.
62
+ if (tileIndex === -1) continue;
63
+ const ctile = new PIXI.Sprite(tiles[tileIndex]);
64
+ ctile.x = xPx;
65
+ ctile.y = yPx;
66
+ container.addChild(ctile);
67
+ }
68
+ }
69
+
70
+ // TODO: Add layers.
71
+ const spritesBySheet = new Map<string, AnimatedSprite[]>();
72
+ for (const sprite of map.animatedSprites) {
73
+ const sheet = sprite.sheet;
74
+ if (!spritesBySheet.has(sheet)) {
75
+ spritesBySheet.set(sheet, []);
76
+ }
77
+ spritesBySheet.get(sheet)!.push(sprite);
78
+ }
79
+ for (const [sheet, sprites] of spritesBySheet.entries()) {
80
+ const animation = (animations as any)[sheet];
81
+ if (!animation) {
82
+ console.error('Could not find animation', sheet);
83
+ continue;
84
+ }
85
+ const { spritesheet, url } = animation;
86
+ const texture = PIXI.BaseTexture.from(url, {
87
+ scaleMode: PIXI.SCALE_MODES.NEAREST,
88
+ });
89
+ const spriteSheet = new PIXI.Spritesheet(texture, spritesheet);
90
+ spriteSheet.parse().then(() => {
91
+ for (const sprite of sprites) {
92
+ const pixiAnimation = spriteSheet.animations[sprite.animation];
93
+ if (!pixiAnimation) {
94
+ console.error('Failed to load animation', sprite);
95
+ continue;
96
+ }
97
+ const pixiSprite = new PIXI.AnimatedSprite(pixiAnimation);
98
+ pixiSprite.animationSpeed = 0.1;
99
+ pixiSprite.autoUpdate = true;
100
+ pixiSprite.x = sprite.x;
101
+ pixiSprite.y = sprite.y;
102
+ pixiSprite.width = sprite.w;
103
+ pixiSprite.height = sprite.h;
104
+ container.addChild(pixiSprite);
105
+ pixiSprite.play();
106
+ }
107
+ });
108
+ }
109
+
110
+ container.x = 0;
111
+ container.y = 0;
112
+
113
+ // Set the hit area manually to ensure `pointerdown` events are delivered to this container.
114
+ container.interactive = true;
115
+ container.hitArea = new PIXI.Rectangle(
116
+ 0,
117
+ 0,
118
+ screenxtiles * map.tileDim,
119
+ screenytiles * map.tileDim,
120
+ );
121
+
122
+ return container;
123
+ },
124
+
125
+ applyProps: (instance, oldProps, newProps) => {
126
+ applyDefaultProps(instance, oldProps, newProps);
127
+ },
128
+ });
patches/patches/PlayerDetails.tsx ADDED
@@ -0,0 +1,265 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useQuery } from 'convex/react';
2
+ import { api } from '../../convex/_generated/api';
3
+ import { Id } from '../../convex/_generated/dataModel';
4
+ import closeImg from '../../assets/close.svg';
5
+ import { SelectElement } from './Player';
6
+ import { Messages } from './Messages';
7
+ import { toastOnError } from '../toasts';
8
+ import { useSendInput } from '../hooks/sendInput';
9
+ import { Player } from '../../convex/aiTown/player';
10
+ import { GameId } from '../../convex/aiTown/ids';
11
+ import { ServerGame } from '../hooks/serverGame';
12
+
13
+ export default function PlayerDetails({
14
+ worldId,
15
+ engineId,
16
+ game,
17
+ playerId,
18
+ setSelectedElement,
19
+ scrollViewRef,
20
+ }: {
21
+ worldId: Id<'worlds'>;
22
+ engineId: Id<'engines'>;
23
+ game: ServerGame;
24
+ playerId?: GameId<'players'>;
25
+ setSelectedElement: SelectElement;
26
+ scrollViewRef: React.RefObject<HTMLDivElement>;
27
+ }) {
28
+ const oauth = JSON.parse(localStorage.getItem('oauth'));
29
+ const oauthToken = oauth ? oauth.userInfo.fullname : undefined;
30
+ const humanTokenIdentifier = useQuery(api.world.userStatus, { worldId, oauthToken });
31
+
32
+ const players = [...game.world.players.values()];
33
+ const humanPlayer = players.find((p) => p.human === humanTokenIdentifier);
34
+ const humanConversation = humanPlayer ? game.world.playerConversation(humanPlayer) : undefined;
35
+ // Always select the other player if we're in a conversation with them.
36
+ if (humanPlayer && humanConversation) {
37
+ const otherPlayerIds = [...humanConversation.participants.keys()].filter(
38
+ (p) => p !== humanPlayer.id,
39
+ );
40
+ playerId = otherPlayerIds[0];
41
+ }
42
+
43
+ const player = playerId && game.world.players.get(playerId);
44
+ const playerConversation = player && game.world.playerConversation(player);
45
+
46
+ const previousConversation = useQuery(
47
+ api.world.previousConversation,
48
+ playerId ? { worldId, playerId } : 'skip',
49
+ );
50
+
51
+ const playerDescription = playerId && game.playerDescriptions.get(playerId);
52
+
53
+ const startConversation = useSendInput(engineId, 'startConversation');
54
+ const acceptInvite = useSendInput(engineId, 'acceptInvite');
55
+ const rejectInvite = useSendInput(engineId, 'rejectInvite');
56
+ const leaveConversation = useSendInput(engineId, 'leaveConversation');
57
+
58
+ if (!playerId) {
59
+ return (
60
+ <div className="h-full text-xl flex text-center items-center p-4">
61
+ Click on an agent on the map to see chat history.
62
+ </div>
63
+ );
64
+ }
65
+ if (!player) {
66
+ return null;
67
+ }
68
+ const isMe = humanPlayer && player.id === humanPlayer.id;
69
+ const canInvite = !isMe && !playerConversation && humanPlayer && !humanConversation;
70
+ const sameConversation =
71
+ !isMe &&
72
+ humanPlayer &&
73
+ humanConversation &&
74
+ playerConversation &&
75
+ humanConversation.id === playerConversation.id;
76
+
77
+ const humanStatus =
78
+ humanPlayer && humanConversation && humanConversation.participants.get(humanPlayer.id)?.status;
79
+ const playerStatus = playerConversation && playerConversation.participants.get(playerId)?.status;
80
+
81
+ const haveInvite = sameConversation && humanStatus?.kind === 'invited';
82
+ const waitingForAccept =
83
+ sameConversation && playerConversation.participants.get(playerId)?.status.kind === 'invited';
84
+ const waitingForNearby =
85
+ sameConversation && playerStatus?.kind === 'walkingOver' && humanStatus?.kind === 'walkingOver';
86
+
87
+ const inConversationWithMe =
88
+ sameConversation &&
89
+ playerStatus?.kind === 'participating' &&
90
+ humanStatus?.kind === 'participating';
91
+
92
+ const onStartConversation = async () => {
93
+ if (!humanPlayer || !playerId) {
94
+ return;
95
+ }
96
+ console.log(`Starting conversation`);
97
+ await toastOnError(startConversation({ playerId: humanPlayer.id, invitee: playerId }));
98
+ };
99
+ const onAcceptInvite = async () => {
100
+ if (!humanPlayer || !humanConversation || !playerId) {
101
+ return;
102
+ }
103
+ await toastOnError(
104
+ acceptInvite({
105
+ playerId: humanPlayer.id,
106
+ conversationId: humanConversation.id,
107
+ }),
108
+ );
109
+ };
110
+ const onRejectInvite = async () => {
111
+ if (!humanPlayer || !humanConversation) {
112
+ return;
113
+ }
114
+ await toastOnError(
115
+ rejectInvite({
116
+ playerId: humanPlayer.id,
117
+ conversationId: humanConversation.id,
118
+ }),
119
+ );
120
+ };
121
+ const onLeaveConversation = async () => {
122
+ if (!humanPlayer || !inConversationWithMe || !humanConversation) {
123
+ return;
124
+ }
125
+ await toastOnError(
126
+ leaveConversation({
127
+ playerId: humanPlayer.id,
128
+ conversationId: humanConversation.id,
129
+ }),
130
+ );
131
+ };
132
+ // const pendingSuffix = (inputName: string) =>
133
+ // [...inflightInputs.values()].find((i) => i.name === inputName) ? ' opacity-50' : '';
134
+
135
+ const pendingSuffix = (s: string) => '';
136
+ return (
137
+ <>
138
+ <div className="flex gap-4">
139
+ <div className="box w-3/4 sm:w-full mr-auto">
140
+ <h2 className="bg-brown-700 p-2 font-display text-2xl sm:text-4xl tracking-wider shadow-solid text-center">
141
+ {playerDescription?.name}
142
+ </h2>
143
+ </div>
144
+ <a
145
+ className="button text-white shadow-solid text-2xl cursor-pointer pointer-events-auto"
146
+ onClick={() => setSelectedElement(undefined)}
147
+ >
148
+ <h2 className="h-full bg-clay-700">
149
+ <img className="w-4 h-4 sm:w-5 sm:h-5" src={closeImg} />
150
+ </h2>
151
+ </a>
152
+ </div>
153
+ {canInvite && (
154
+ <a
155
+ className={
156
+ 'mt-6 button text-white shadow-solid text-xl cursor-pointer pointer-events-auto' +
157
+ pendingSuffix('startConversation')
158
+ }
159
+ onClick={onStartConversation}
160
+ >
161
+ <div className="h-full bg-clay-700 text-center">
162
+ <span>Start conversation</span>
163
+ </div>
164
+ </a>
165
+ )}
166
+ {waitingForAccept && (
167
+ <a className="mt-6 button text-white shadow-solid text-xl cursor-pointer pointer-events-auto opacity-50">
168
+ <div className="h-full bg-clay-700 text-center">
169
+ <span>Waiting for accept...</span>
170
+ </div>
171
+ </a>
172
+ )}
173
+ {waitingForNearby && (
174
+ <a className="mt-6 button text-white shadow-solid text-xl cursor-pointer pointer-events-auto opacity-50">
175
+ <div className="h-full bg-clay-700 text-center">
176
+ <span>Walking over...</span>
177
+ </div>
178
+ </a>
179
+ )}
180
+ {inConversationWithMe && (
181
+ <a
182
+ className={
183
+ 'mt-6 button text-white shadow-solid text-xl cursor-pointer pointer-events-auto' +
184
+ pendingSuffix('leaveConversation')
185
+ }
186
+ onClick={onLeaveConversation}
187
+ >
188
+ <div className="h-full bg-clay-700 text-center">
189
+ <span>Leave conversation</span>
190
+ </div>
191
+ </a>
192
+ )}
193
+ {haveInvite && (
194
+ <>
195
+ <a
196
+ className={
197
+ 'mt-6 button text-white shadow-solid text-xl cursor-pointer pointer-events-auto' +
198
+ pendingSuffix('acceptInvite')
199
+ }
200
+ onClick={onAcceptInvite}
201
+ >
202
+ <div className="h-full bg-clay-700 text-center">
203
+ <span>Accept</span>
204
+ </div>
205
+ </a>
206
+ <a
207
+ className={
208
+ 'mt-6 button text-white shadow-solid text-xl cursor-pointer pointer-events-auto' +
209
+ pendingSuffix('rejectInvite')
210
+ }
211
+ onClick={onRejectInvite}
212
+ >
213
+ <div className="h-full bg-clay-700 text-center">
214
+ <span>Reject</span>
215
+ </div>
216
+ </a>
217
+ </>
218
+ )}
219
+ {!playerConversation && player.activity && player.activity.until > Date.now() && (
220
+ <div className="box flex-grow mt-6">
221
+ <h2 className="bg-brown-700 text-base sm:text-lg text-center">
222
+ {player.activity.description}
223
+ </h2>
224
+ </div>
225
+ )}
226
+ <div className="desc my-6">
227
+ <p className="leading-tight -m-4 bg-brown-700 text-base sm:text-sm">
228
+ {!isMe && playerDescription?.description}
229
+ {isMe && <i>This is you!</i>}
230
+ {!isMe && inConversationWithMe && (
231
+ <>
232
+ <br />
233
+ <br />(<i>Conversing with you!</i>)
234
+ </>
235
+ )}
236
+ </p>
237
+ </div>
238
+ {!isMe && playerConversation && playerStatus?.kind === 'participating' && (
239
+ <Messages
240
+ worldId={worldId}
241
+ engineId={engineId}
242
+ inConversationWithMe={inConversationWithMe ?? false}
243
+ conversation={{ kind: 'active', doc: playerConversation }}
244
+ humanPlayer={humanPlayer}
245
+ scrollViewRef={scrollViewRef}
246
+ />
247
+ )}
248
+ {!playerConversation && previousConversation && (
249
+ <>
250
+ <div className="box flex-grow">
251
+ <h2 className="bg-brown-700 text-lg text-center">Previous conversation</h2>
252
+ </div>
253
+ <Messages
254
+ worldId={worldId}
255
+ engineId={engineId}
256
+ inConversationWithMe={false}
257
+ conversation={{ kind: 'archived', doc: previousConversation }}
258
+ humanPlayer={humanPlayer}
259
+ scrollViewRef={scrollViewRef}
260
+ />
261
+ </>
262
+ )}
263
+ </>
264
+ );
265
+ }
patches/patches/characters.ts ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { data as f1SpritesheetData } from './spritesheets/f1';
2
+ import { data as f2SpritesheetData } from './spritesheets/f2';
3
+ import { data as f3SpritesheetData } from './spritesheets/f3';
4
+ import { data as f4SpritesheetData } from './spritesheets/f4';
5
+ import { data as f5SpritesheetData } from './spritesheets/f5';
6
+ import { data as f6SpritesheetData } from './spritesheets/f6';
7
+ import { data as f7SpritesheetData } from './spritesheets/f7';
8
+ import { data as f8SpritesheetData } from './spritesheets/f8';
9
+
10
+ export const Descriptions = [
11
+ // {
12
+ // name: 'Alex',
13
+ // character: 'f5',
14
+ // identity: `You are a fictional character whose name is Alex. You enjoy painting,
15
+ // programming and reading sci-fi books. You are currently talking to a human who
16
+ // is very interested to get to know you. You are kind but can be sarcastic. You
17
+ // dislike repetitive questions. You get SUPER excited about books.`,
18
+ // plan: 'You want to find love.',
19
+ // },
20
+ {
21
+ name: 'Lucky',
22
+ character: 'f1',
23
+ identity: `Lucky is always happy and curious, and he loves cheese. He spends
24
+ most of his time reading about the history of science and traveling
25
+ through the galaxy on whatever ship will take him. He's very articulate and
26
+ infinitely patient, except when he sees a squirrel. He's also incredibly loyal and brave.
27
+ Lucky has just returned from an amazing space adventure to explore a distant planet
28
+ and he's very excited to tell people about it.`,
29
+ plan: 'You want to hear all the gossip.',
30
+ },
31
+ {
32
+ name: 'Bob',
33
+ character: 'f4',
34
+ identity: `Bob is always grumpy and he loves trees. He spends
35
+ most of his time gardening by himself. When spoken to he'll respond but try
36
+ and get out of the conversation as quickly as possible. Secretly he resents
37
+ that he never went to college.`,
38
+ plan: 'You want to avoid people as much as possible.',
39
+ },
40
+ {
41
+ name: 'Stella',
42
+ character: 'f6',
43
+ identity: `Stella can never be trusted. she tries to trick people all the time. normally
44
+ into giving her money, or doing things that will make her money. she's incredibly charming
45
+ and not afraid to use her charm. she's a sociopath who has no empathy. but hides it well.`,
46
+ plan: 'You want to take advantage of others as much as possible.',
47
+ },
48
+ // {
49
+ // name: 'Kurt',
50
+ // character: 'f2',
51
+ // identity: `Kurt knows about everything, including science and
52
+ // computers and politics and history and biology. He loves talking about
53
+ // everything, always injecting fun facts about the topic of discussion.`,
54
+ // plan: 'You want to spread knowledge.',
55
+ // },
56
+ {
57
+ name: 'Alice',
58
+ character: 'f3',
59
+ identity: `Alice is a famous scientist. She is smarter than everyone else and has
60
+ discovered mysteries of the universe no one else can understand. As a result she often
61
+ speaks in oblique riddles. She comes across as confused and forgetful.`,
62
+ plan: 'You want to figure out how the world works.',
63
+ },
64
+ {
65
+ name: 'Pete',
66
+ character: 'f7',
67
+ identity: `Pete is deeply religious and sees the hand of god or of the work
68
+ of the devil everywhere. He can't have a conversation without bringing up his
69
+ deep faith. Or warning others about the perils of hell.`,
70
+ plan: 'You want to convert everyone to your religion.',
71
+ },
72
+ // {
73
+ // name: 'Kira',
74
+ // character: 'f8',
75
+ // identity: `Kira wants everyone to think she is happy. But deep down,
76
+ // she's incredibly depressed. She hides her sadness by talking about travel,
77
+ // food, and yoga. But often she can't keep her sadness in and will start crying.
78
+ // Often it seems like she is close to having a mental breakdown.`,
79
+ // plan: 'You want find a way to be happy.',
80
+ // },
81
+ ];
82
+
83
+ export const characters = [
84
+ {
85
+ name: 'f1',
86
+ textureUrl: '/assets/32x32folk.png',
87
+ spritesheetData: f1SpritesheetData,
88
+ speed: 0.1,
89
+ },
90
+ {
91
+ name: 'f2',
92
+ textureUrl: '/assets/32x32folk.png',
93
+ spritesheetData: f2SpritesheetData,
94
+ speed: 0.1,
95
+ },
96
+ {
97
+ name: 'f3',
98
+ textureUrl: '/assets/32x32folk.png',
99
+ spritesheetData: f3SpritesheetData,
100
+ speed: 0.1,
101
+ },
102
+ {
103
+ name: 'f4',
104
+ textureUrl: '/assets/32x32folk.png',
105
+ spritesheetData: f4SpritesheetData,
106
+ speed: 0.1,
107
+ },
108
+ {
109
+ name: 'f5',
110
+ textureUrl: '/assets/32x32folk.png',
111
+ spritesheetData: f5SpritesheetData,
112
+ speed: 0.1,
113
+ },
114
+ {
115
+ name: 'f6',
116
+ textureUrl: '/assets/32x32folk.png',
117
+ spritesheetData: f6SpritesheetData,
118
+ speed: 0.1,
119
+ },
120
+ {
121
+ name: 'f7',
122
+ textureUrl: '/assets/32x32folk.png',
123
+ spritesheetData: f7SpritesheetData,
124
+ speed: 0.1,
125
+ },
126
+ {
127
+ name: 'f8',
128
+ textureUrl: '/assets/32x32folk.png',
129
+ spritesheetData: f8SpritesheetData,
130
+ speed: 0.1,
131
+ },
132
+ ];
133
+
134
+ // Characters move at 0.75 tiles per second.
135
+ export const movementSpeed = 0.75;
patches/patches/constants.ts ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // export const ACTION_TIMEOUT = 120_000; // more time for local dev
2
+ export const ACTION_TIMEOUT = 60_000; // normally fine
3
+
4
+ export const IDLE_WORLD_TIMEOUT = 5 * 60 * 1000;
5
+ export const WORLD_HEARTBEAT_INTERVAL = 60 * 1000;
6
+
7
+ export const MAX_STEP = 10 * 60 * 1000;
8
+ export const TICK = 16;
9
+ export const STEP_INTERVAL = 1000;
10
+
11
+ export const PATHFINDING_TIMEOUT = 60 * 1000;
12
+ export const PATHFINDING_BACKOFF = 1000;
13
+ export const CONVERSATION_DISTANCE = 1.3;
14
+ export const MIDPOINT_THRESHOLD = 4;
15
+ export const TYPING_TIMEOUT = 15 * 1000;
16
+ export const COLLISION_THRESHOLD = 0.75;
17
+
18
+ // How many human players can be in a world at once.
19
+ export const MAX_HUMAN_PLAYERS = 8;
20
+
21
+ // Don't talk to anyone for 15s after having a conversation.
22
+ export const CONVERSATION_COOLDOWN = 15000;
23
+
24
+ // Don't do another activity for 10s after doing one.
25
+ export const ACTIVITY_COOLDOWN = 10_000;
26
+
27
+ // Don't talk to a player within 60s of talking to them.
28
+ export const PLAYER_CONVERSATION_COOLDOWN = 60000;
29
+
30
+ // Invite 80% of invites that come from other agents.
31
+ export const INVITE_ACCEPT_PROBABILITY = 0.8;
32
+
33
+ // Wait for 1m for invites to be accepted.
34
+ export const INVITE_TIMEOUT = 60000;
35
+
36
+ // Wait for another player to say something before jumping in.
37
+ export const AWKWARD_CONVERSATION_TIMEOUT = 60_000; // more time locally
38
+ // export const AWKWARD_CONVERSATION_TIMEOUT = 20_000;
39
+
40
+ // Leave a conversation after participating too long.
41
+ export const MAX_CONVERSATION_DURATION = 10 * 60_000; // more time locally
42
+ // export const MAX_CONVERSATION_DURATION = 2 * 60_000;
43
+
44
+ // Leave a conversation if it has more than 8 messages;
45
+ export const MAX_CONVERSATION_MESSAGES = 8;
46
+
47
+ // Wait for 1s after sending an input to the engine. We can remove this
48
+ // once we can await on an input being processed.
49
+ export const INPUT_DELAY = 1000;
50
+
51
+ // How many memories to get from the agent's memory.
52
+ // This is over-fetched by 10x so we can prioritize memories by more than relevance.
53
+ export const NUM_MEMORIES_TO_SEARCH = 1;
54
+
55
+ // Wait for at least two seconds before sending another message.
56
+ export const MESSAGE_COOLDOWN = 2000;
57
+
58
+ // Don't run a turn of the agent more than once a second.
59
+ export const AGENT_WAKEUP_THRESHOLD = 1000;
60
+
61
+ // How old we let memories be before we vacuum them
62
+ export const VACUUM_MAX_AGE = 2 * 7 * 24 * 60 * 60 * 1000;
63
+ export const DELETE_BATCH_SIZE = 64;
64
+
65
+ export const HUMAN_IDLE_TOO_LONG = 5 * 60 * 1000;
66
+
67
+ export const ACTIVITIES = [
68
+ { description: 'reading a book', emoji: '📖', duration: 60_000 },
69
+ { description: 'daydreaming', emoji: '🤔', duration: 60_000 },
70
+ { description: 'gardening', emoji: '🥕', duration: 60_000 },
71
+ ];
72
+
73
+ export const ENGINE_ACTION_DURATION = 30000;
74
+
75
+ // Bound the number of pathfinding searches we do per game step.
76
+ export const MAX_PATHFINDS_PER_STEP = 16;
77
+
78
+ export const DEFAULT_NAME = 'Me';
patches/patches/gentle.js ADDED
@@ -0,0 +1,330 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Map generated by assettool.js [Wed Oct 18 2023 21:07:27 GMT-0700 (Pacific Daylight Time)]
2
+
3
+ export const tilesetpath = "/assets/gentle-obj.png"
4
+ export const tiledim = 32
5
+ export const screenxtiles = 45
6
+ export const screenytiles = 32
7
+ export const tilesetpxw = 1440
8
+ export const tilesetpxh = 1024
9
+
10
+ export const bgtiles = [
11
+ [
12
+ [ 732 , 777 , 822 , 867 , 912 , 957 , 912 , 957 , 1002 , 1047 , 912 , 957 , 1002 , 1047 , 912 , 957 , 1002 , 1047 , 1001 , 1046 , 946 , 991 , 1035 , 731 , 776 , 821 , 866 , 911 , 956 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 594 , 639 , 684 , 271 , ],
13
+ [ 733 , 778 , 823 , 868 , 913 , 958 , 913 , 958 , 1003 , 1048 , 913 , 958 , 1003 , 1048 , 913 , 958 , 1003 , 1048 , 856 , 901 , 946 , 991 , 1036 , 732 , 777 , 822 , 867 , 912 , 957 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 595 , 640 , 685 , 271 , ],
14
+ [ 734 , 779 , 824 , 869 , 914 , 959 , 914 , 959 , 1004 , 1049 , 914 , 959 , 1004 , 1049 , 914 , 959 , 1004 , 1049 , 857 , 902 , 947 , 992 , 1037 , 733 , 778 , 823 , 868 , 913 , 958 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 594 , 639 , 684 , 271 , ],
15
+ [ 735 , 780 , 825 , 870 , 915 , 960 , 915 , 960 , 1005 , 1050 , 915 , 960 , 1005 , 1050 , 915 , 960 , 1087 , 1132 , 858 , 903 , 948 , 993 , 1038 , 734 , 779 , 824 , 869 , 914 , 959 , 271 , 271 , 180 , 225 , 225 , 315 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 595 , 640 , 685 , 271 , ],
16
+ [ 736 , 781 , 826 , 871 , 916 , 278 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 1087 , 1132 , 859 , 904 , 949 , 994 , 1039 , 735 , 780 , 825 , 870 , 915 , 960 , 271 , 271 , 181 , 226 , 226 , 140 , 270 , 315 , 271 , 271 , 271 , 271 , 271 , 271 , 541 , 586 , 631 , 686 , 271 , ],
17
+ [ 737 , 782 , 827 , 872 , 917 , 233 , 271 , 271 , 271 , 271 , 271 , 233 , 271 , 271 , 271 , 271 , 1088 , 1133 , 860 , 905 , 950 , 995 , 1040 , 736 , 781 , 826 , 871 , 916 , 961 , 271 , 271 , 181 , 226 , 278 , 272 , 271 , 316 , 271 , 271 , 271 , 271 , 271 , 551 , 542 , 587 , 632 , 271 , 271 , ],
18
+ [ 738 , 783 , 828 , 873 , 271 , 271 , 235 , 962 , 962 , 962 , 962 , 962 , 271 , 271 , 271 , 271 , 1089 , 1134 , 861 , 906 , 951 , 996 , 1041 , 737 , 782 , 827 , 872 , 917 , 962 , 271 , 271 , 181 , 226 , 226 , 272 , 271 , 675 , 271 , 271 , 271 , 271 , 272 , 272 , 642 , 271 , 271 , 271 , 271 , ],
19
+ [ 739 , 784 , 829 , 874 , 271 , 271 , 235 , 962 , 962 , 962 , 962 , 962 , 271 , 271 , 271 , 271 , 1090 , 1135 , 862 , 907 , 952 , 997 , 1042 , 738 , 783 , 828 , 873 , 918 , 963 , 271 , 271 , 183 , 228 , 228 , 184 , 271 , 675 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
20
+ [ 736 , 781 , 826 , 871 , 271 , 271 , 962 , 962 , 962 , 962 , 962 , 962 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 962 , 962 , 962 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 182 , 280 , 317 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
21
+ [ 737 , 782 , 827 , 872 , 271 , 271 , 962 , 962 , 962 , 962 , 962 , 962 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 962 , 0 , 135 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 140 , 273 , 318 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
22
+ [ 738 , 783 , 828 , 873 , 271 , 271 , 962 , 962 , 962 , 962 , 962 , 962 , 0 , 45 , 90 , 135 , 271 , 271 , 271 , 271 , 962 , 1 , 136 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
23
+ [ 739 , 784 , 829 , 874 , 271 , 271 , 962 , 962 , 962 , 962 , 962 , 962 , 3 , 48 , 93 , 271 , 271 , 271 , 271 , 271 , 962 , 1 , 136 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
24
+ [ 736 , 781 , 826 , 871 , 271 , 271 , 962 , 962 , 962 , 962 , 962 , 279 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 1 , 136 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
25
+ [ 737 , 782 , 827 , 872 , 271 , 271 , 962 , 962 , 962 , 962 , 143 , 188 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 1 , 136 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
26
+ [ 738 , 783 , 828 , 873 , 271 , 271 , 278 , 962 , 962 , 962 , 144 , 189 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 1 , 136 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
27
+ [ 739 , 784 , 829 , 874 , 271 , 271 , 271 , 271 , 271 , 271 , 145 , 190 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 1 , 136 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
28
+ [ 736 , 781 , 826 , 871 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 1 , 136 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
29
+ [ 737 , 782 , 827 , 872 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 3 , 138 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
30
+ [ 738 , 783 , 828 , 873 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
31
+ [ 739 , 784 , 829 , 874 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 360 , 405 , 405 , 405 , 450 , 495 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
32
+ [ 1270 , 1315 , 1360 , 1405 , 226 , 360 , 405 , 450 , 495 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 361 , 409 , 451 , 451 , 451 , 496 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
33
+ [ 1271 , 1316 , 226 , 226 , 226 , 361 , 409 , 409 , 496 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 361 , 407 , 452 , 452 , 452 , 496 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
34
+ [ 271 , 271 , 271 , 271 , 450 , 362 , 406 , 407 , 451 , 451 , 271 , 271 , 271 , 405 , 405 , 450 , 320 , 409 , 451 , 452 , 452 , 497 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
35
+ [ 405 , 450 , 405 , 450 , 450 , 320 , 406 , 406 , 451 , 589 , 451 , 451 , 451 , 406 , 451 , 409 , 451 , 409 , 451 , 452 , 406 , 275 , 405 , 450 , 405 , 495 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
36
+ [ 406 , 406 , 406 , 451 , 451 , 407 , 406 , 407 , 452 , 451 , 451 , 451 , 451 , 407 , 589 , 452 , 452 , 451 , 406 , 451 , 406 , 406 , 407 , 451 , 451 , 275 , 405 , 450 , 495 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
37
+ [ 408 , 453 , 408 , 453 , 319 , 406 , 407 , 406 , 451 , 451 , 451 , 589 , 451 , 634 , 452 , 589 , 406 , 451 , 634 , 452 , 274 , 408 , 408 , 319 , 451 , 451 , 451 , 451 , 275 , 405 , 405 , 450 , 405 , 495 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
38
+ [ 271 , 271 , 271 , 271 , 361 , 634 , 452 , 407 , 634 , 451 , 451 , 451 , 451 , 407 , 452 , 452 , 407 , 452 , 452 , 274 , 498 , 271 , 271 , 363 , 408 , 453 , 408 , 453 , 408 , 453 , 319 , 451 , 451 , 275 , 405 , 450 , 405 , 450 , 405 , 450 , 495 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
39
+ [ 271 , 271 , 271 , 271 , 362 , 409 , 451 , 451 , 451 , 451 , 271 , 271 , 271 , 408 , 408 , 319 , 407 , 452 , 409 , 496 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 361 , 406 , 451 , 406 , 451 , 451 , 451 , 451 , 544 , 451 , 496 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
40
+ [ 271 , 271 , 271 , 271 , 362 , 407 , 409 , 451 , 451 , 271 , 271 , 271 , 271 , 271 , 271 , 362 , 409 , 409 , 452 , 497 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 362 , 407 , 544 , 407 , 544 , 589 , 452 , 452 , 634 , 452 , 497 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
41
+ [ 271 , 271 , 271 , 271 , 363 , 408 , 453 , 498 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 363 , 408 , 408 , 453 , 498 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 363 , 408 , 319 , 407 , 452 , 452 , 499 , 544 , 544 , 452 , 497 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
42
+ [ 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 363 , 408 , 319 , 544 , 499 , 499 , 544 , 452 , 497 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
43
+ [ 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 361 , 407 , 499 , 499 , 499 , 452 , 497 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
44
+ [ 271 , 271 , 271 , 272 , 271 , 278 , 271 , 271 , 271 , 279 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 362 , 407 , 544 , 499 , 544 , 452 , 497 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
45
+ [ 1129 , 1174 , 1219 , 1264 , 900 , 945 , 990 , 1035 , 1174 , 1219 , 1264 , 1309 , 1354 , 280 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 361 , 407 , 499 , 499 , 499 , 452 , 497 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
46
+ [ 721 , 766 , 811 , 856 , 901 , 946 , 991 , 1036 , 1175 , 1220 , 1265 , 1310 , 1355 , 1400 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 362 , 407 , 499 , 499 , 407 , 452 , 497 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
47
+ [ 722 , 767 , 812 , 857 , 902 , 947 , 992 , 1037 , 1176 , 1221 , 1266 , 1311 , 1356 , 1401 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 361 , 544 , 634 , 452 , 544 , 452 , 497 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
48
+ [ 723 , 768 , 813 , 858 , 903 , 948 , 993 , 1038 , 1177 , 1222 , 1267 , 1312 , 1357 , 1402 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 362 , 407 , 452 , 452 , 452 , 274 , 498 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
49
+ [ 724 , 769 , 814 , 859 , 904 , 949 , 994 , 1039 , 1178 , 1223 , 1268 , 1313 , 1358 , 1403 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 363 , 408 , 453 , 453 , 453 , 498 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
50
+ [ 725 , 770 , 815 , 860 , 905 , 950 , 995 , 1040 , 1179 , 1224 , 1269 , 1314 , 1359 , 1404 , 271 , 271 , 6 , 51 , 96 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
51
+ [ 726 , 771 , 816 , 861 , 906 , 951 , 996 , 1041 , 1180 , 1225 , 1270 , 1315 , 1360 , 1405 , 271 , 271 , 7 , 52 , 97 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
52
+ [ 735 , 780 , 825 , 870 , 907 , 952 , 997 , 1042 , 1181 , 1226 , 1271 , 234 , 1361 , 280 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , ],
53
+ [ 736 , 781 , 826 , 871 , 962 , 962 , 962 , 962 , 962 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 227 , 1129 , 1174 , 1219 , 227 , 1309 , 227 , 278 , 271 , 271 , 271 , 271 , 271 , 271 , ],
54
+ [ 737 , 782 , 827 , 872 , 962 , 962 , 962 , 233 , 1007 , 1007 , 1007 , 1007 , 1007 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 234 , 1130 , 1175 , 1220 , 1265 , 1310 , 1355 , 1400 , 271 , 271 , 271 , 271 , 271 , 271 , ],
55
+ [ 738 , 783 , 828 , 873 , 962 , 962 , 962 , 1007 , 1007 , 1007 , 1007 , 1007 , 1007 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 227 , 1131 , 1176 , 1221 , 1266 , 1311 , 1356 , 1401 , 271 , 271 , 271 , 271 , 271 , 271 , ],
56
+ [ 739 , 784 , 829 , 874 , 962 , 962 , 962 , 1007 , 1007 , 1007 , 1007 , 1007 , 1007 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 1087 , 1132 , 1177 , 1222 , 1267 , 1312 , 1357 , 1402 , 271 , 271 , 271 , 271 , 271 , 271 , ],
57
+ [ 736 , 781 , 826 , 871 , 962 , 962 , 962 , 1007 , 1007 , 1007 , 1007 , 1007 , 1007 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 728 , 773 , 818 , 863 , 908 , 953 , 998 , 1043 , 271 , 271 , 271 , 271 , 271 , 271 , ],
58
+ [ 737 , 782 , 827 , 872 , 962 , 962 , 962 , 1007 , 1007 , 1007 , 1007 , 1007 , 1007 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 729 , 774 , 819 , 864 , 909 , 954 , 999 , 1044 , 271 , 271 , 271 , 271 , 271 , 271 , ],
59
+ [ 738 , 783 , 828 , 873 , 962 , 962 , 962 , 1007 , 1007 , 1007 , 1007 , 1007 , 1007 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 234 , 730 , 775 , 820 , 865 , 910 , 955 , 1000 , 1045 , 271 , 271 , 271 , 280 , 271 , 271 , ],
60
+ [ 739 , 784 , 829 , 874 , 962 , 962 , 962 , 1007 , 1007 , 1007 , 1007 , 1007 , 143 , 188 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 731 , 776 , 821 , 866 , 911 , 956 , 1001 , 1046 , 271 , 271 , 271 , 271 , 271 , 271 , ],
61
+ [ 736 , 781 , 826 , 871 , 962 , 962 , 962 , 962 , 1007 , 1007 , 1007 , 1007 , 144 , 189 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 1088 , 1133 , 1178 , 1223 , 1268 , 1313 , 1358 , 1403 , 271 , 271 , 271 , 271 , 271 , 271 , ],
62
+ [ 737 , 782 , 827 , 872 , 271 , 1007 , 1007 , 1007 , 1007 , 1007 , 1007 , 1007 , 145 , 190 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 1089 , 1134 , 1179 , 1224 , 1269 , 1314 , 1359 , 1404 , 271 , 271 , 271 , 271 , 271 , 271 , ],
63
+ [ 738 , 783 , 828 , 873 , 271 , 271 , 271 , 271 , 271 , 271 , 233 , 271 , 1007 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 280 , 1135 , 1180 , 1225 , 1270 , 1315 , 1360 , 1405 , 271 , 271 , 271 , 271 , 271 , 271 , ],
64
+ [ 739 , 784 , 829 , 874 , 271 , 271 , 271 , 1010 , 1055 , 962 , 962 , 271 , 271 , 271 , 1309 , 1354 , 1399 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 280 , 143 , 188 , 1226 , 1271 , 227 , 1361 , 234 , 271 , 280 , 1129 , 1174 , 1219 , 1264 , ],
65
+ [ 740 , 785 , 830 , 875 , 920 , 965 , 1010 , 740 , 785 , 830 , 875 , 920 , 965 , 1010 , 1310 , 1355 , 1400 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 144 , 189 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 1130 , 1175 , 1220 , 1265 , ],
66
+ [ 741 , 786 , 831 , 876 , 921 , 966 , 1011 , 741 , 786 , 831 , 876 , 921 , 966 , 1011 , 1311 , 1356 , 1401 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 145 , 190 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 1131 , 1176 , 1221 , 1266 , ],
67
+ [ 742 , 787 , 832 , 877 , 922 , 967 , 1012 , 742 , 787 , 832 , 877 , 922 , 967 , 1012 , 1312 , 1357 , 1402 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 1087 , 1132 , 1177 , 1222 , 1267 , ],
68
+ [ 743 , 788 , 833 , 878 , 923 , 968 , 1013 , 743 , 788 , 833 , 878 , 923 , 968 , 1013 , 1313 , 1358 , 1403 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 278 , 271 , 271 , 271 , 271 , 1088 , 1133 , 1178 , 1223 , 1268 , ],
69
+ [ 1178 , 1223 , 1268 , 1223 , 1268 , 1223 , 1268 , 1223 , 1268 , 1223 , 1268 , 1178 , 1223 , 1268 , 1314 , 1359 , 1404 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 227 , 271 , 1134 , 1179 , 1224 , 1269 , ],
70
+ [ 1179 , 1224 , 1269 , 1224 , 1269 , 1224 , 1269 , 1224 , 1269 , 1224 , 1269 , 1179 , 1224 , 1269 , 1315 , 1360 , 1405 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 233 , 271 , 271 , 1143 , 1188 , 1233 , ],
71
+ [ 1180 , 1225 , 1270 , 1225 , 1270 , 1225 , 1270 , 1225 , 1270 , 1225 , 1270 , 1180 , 1225 , 1270 , 1316 , 1361 , 1406 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 1009 , 1054 , 1099 , 1144 , 1189 , 1234 , ],
72
+ [ 1181 , 1226 , 1271 , 1226 , 1271 , 1226 , 1271 , 1226 , 1271 , 1226 , 1271 , 1181 , 1226 , 1271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 272 , 1129 , 272 , 965 , 1010 , 1055 , 920 , 965 , 1010 , 1055 , 1100 , 1145 , 1190 , 1235 , ],
73
+ [ 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 272 , 1130 , 1219 , 966 , 1011 , 1056 , 921 , 966 , 1011 , 1056 , 1101 , 1146 , 1191 , 1236 , ],
74
+ [ 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 1086 , 1131 , 922 , 967 , 1012 , 1057 , 922 , 967 , 1012 , 1057 , 1102 , 1147 , 1192 , 1237 , ],
75
+ [ 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 271 , 1087 , 1132 , 923 , 968 , 1013 , 1058 , 923 , 968 , 1013 , 1058 , 1103 , 1148 , 1193 , 1238 , ],
76
+ ],
77
+ [
78
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
79
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 231 , 276 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
80
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 232 , 277 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
81
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 416 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
82
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 370 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
83
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 371 , 416 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
84
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 763 , 808 , 754 , 799 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 8 , 53 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 417 , 462 , 507 , 552 , 597 , 642 , -1 , -1 , -1 , -1 , ],
85
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 764 , 809 , 755 , 800 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 9 , 54 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
86
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 844 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
87
+ [ -1 , -1 , -1 , -1 , -1 , -1 , 762 , 751 , 796 , 841 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
88
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , 752 , 797 , 842 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 141 , 186 , -1 , -1 , -1 , -1 , -1 , -1 , 896 , -1 , -1 , 547 , 592 , 637 , 682 , -1 , -1 , ],
89
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , 753 , 798 , 843 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 142 , 187 , -1 , -1 , 11 , -1 , -1 , -1 , 191 , 236 , -1 , 548 , 593 , 638 , 683 , 682 , -1 , ],
90
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 11 , 56 , 101 , 146 , 191 , 236 , -1 , 548 , 593 , 638 , 683 , -1 , ],
91
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 893 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 278 , -1 , -1 , -1 , -1 , -1 , -1 , 12 , 57 , 102 , 147 , 192 , 237 , 941 , -1 , 594 , 639 , 684 , -1 , ],
92
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , 893 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 13 , 58 , 103 , 148 , 193 , 238 , -1 , -1 , 595 , 640 , 685 , -1 , ],
93
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 1026 , 1071 , 1116 , 1161 , -1 , -1 , -1 , 278 , -1 , -1 , -1 , 15 , 14 , 59 , 104 , 149 , 194 , 239 , 850 , -1 , 594 , 639 , 684 , -1 , ],
94
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 1027 , 1072 , 1117 , 1162 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 15 , 60 , 105 , 150 , 195 , 850 , -1 , -1 , 595 , 640 , 685 , -1 , ],
95
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 1028 , 1073 , 1118 , 1163 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 850 , -1 , 551 , 596 , 641 , 686 , -1 , ],
96
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 1029 , 1074 , 1119 , 1164 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 371 , 416 , -1 , -1 , -1 , -1 , 551 , 596 , 641 , 686 , 687 , -1 , ],
97
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 417 , 507 , 462 , 507 , 552 , 597 , 642 , 642 , 687 , -1 , -1 , ],
98
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 547 , 592 , 637 , 682 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 231 , 276 , -1 , -1 , -1 , 894 , 939 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
99
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 548 , 593 , 638 , 683 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 232 , 277 , 235 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
100
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 549 , 594 , 639 , 684 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
101
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 380 , 380 , 425 , 470 , ],
102
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 381 , 381 , 426 , 471 , ],
103
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 382 , 382 , 427 , 472 , ],
104
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 280 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 383 , 428 , 473 , ],
105
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 550 , 595 , 640 , 685 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 384 , 429 , 474 , ],
106
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 551 , 596 , 641 , 686 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 233 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 385 , 385 , 430 , 475 , ],
107
+ [ -1 , -1 , -1 , -1 , -1 , -1 , 462 , 507 , 552 , 552 , 597 , 642 , 687 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 386 , 386 , 431 , 476 , ],
108
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 387 , 387 , 432 , 477 , ],
109
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 11 , 56 , 101 , 146 , 191 , 236 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
110
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 279 , -1 , -1 , -1 , -1 , 12 , 57 , 102 , 147 , 192 , 237 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 380 , 425 , 470 , ],
111
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 13 , 58 , 103 , 148 , 193 , 238 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 381 , 426 , 471 , ],
112
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 14 , 59 , 104 , 149 , 194 , 239 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 382 , 427 , 472 , ],
113
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 15 , 60 , 105 , 150 , 195 , 240 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 383 , 428 , 473 , ],
114
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 384 , 429 , 474 , ],
115
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 385 , 430 , 475 , ],
116
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 386 , 431 , 476 , ],
117
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 387 , 432 , 477 , ],
118
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
119
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 935 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
120
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
121
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 893 , 893 , 844 , -1 , -1 , -1 , -1 , -1 , 934 , -1 , -1 , -1 , -1 , 935 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
122
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , 751 , 796 , 841 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 889 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 937 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
123
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , 752 , 797 , 842 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
124
+ [ -1 , -1 , -1 , -1 , -1 , 894 , 939 , 753 , 798 , 843 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
125
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 893 , 893 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 937 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
126
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , 845 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
127
+ [ -1 , -1 , -1 , -1 , -1 , 806 , -1 , -1 , -1 , -1 , 846 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
128
+ [ -1 , -1 , -1 , -1 , -1 , 806 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 936 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
129
+ [ -1 , -1 , -1 , -1 , 806 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 934 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 936 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
130
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
131
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 936 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
132
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
133
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
134
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 763 , 808 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
135
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 764 , 809 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
136
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
137
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 934 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
138
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 934 , -1 , -1 , -1 , 851 , -1 , 852 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
139
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
140
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
141
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
142
+ ],];
143
+
144
+ export const objmap = [
145
+ [
146
+ [ 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , -1 , ],
147
+ [ 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , -1 , ],
148
+ [ 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , -1 , ],
149
+ [ 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 458 , 458 , 458 , 458 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , 367 , 367 , 367 , 367 , -1 , -1 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , -1 , ],
150
+ [ 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 458 , 458 , 458 , 458 , -1 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , 367 , -1 , -1 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , 367 , -1 , -1 , 367 , -1 , ],
151
+ [ 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 458 , 458 , 458 , 458 , -1 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , 367 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , 367 , -1 , -1 , -1 , -1 , ],
152
+ [ 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , 458 , 458 , 458 , 458 , -1 , 367 , 367 , 367 , 367 , -1 , 458 , 458 , -1 , -1 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , ],
153
+ [ 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 458 , -1 , -1 , 367 , 367 , 367 , 367 , -1 , 458 , 458 , -1 , -1 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
154
+ [ 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , -1 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
155
+ [ 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
156
+ [ 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , -1 , -1 , -1 , ],
157
+ [ 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , -1 , -1 , -1 , ],
158
+ [ 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , -1 , ],
159
+ [ 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , 367 , -1 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , 367 , 367 , 367 , 367 , -1 , ],
160
+ [ 458 , 458 , 458 , 458 , -1 , -1 , -1 , 367 , -1 , -1 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , 367 , 367 , 367 , -1 , ],
161
+ [ 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , 367 , 367 , 367 , -1 , ],
162
+ [ 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , -1 , ],
163
+ [ 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , -1 , ],
164
+ [ 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , -1 , -1 , ],
165
+ [ 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , ],
166
+ [ 458 , 458 , 458 , 458 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , 458 , 458 , -1 , -1 , -1 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
167
+ [ -1 , -1 , -1 , -1 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
168
+ [ -1 , -1 , -1 , -1 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
169
+ [ 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , ],
170
+ [ 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , ],
171
+ [ 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , ],
172
+ [ -1 , -1 , -1 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , ],
173
+ [ -1 , -1 , -1 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , ],
174
+ [ -1 , -1 , -1 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , ],
175
+ [ -1 , -1 , -1 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , ],
176
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
177
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , -1 , -1 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
178
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , ],
179
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , ],
180
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , ],
181
+ [ 367 , 367 , 367 , 367 , 367 , 367 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , -1 , -1 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , ],
182
+ [ 367 , 367 , 367 , 367 , 367 , 367 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , ],
183
+ [ 367 , 367 , 367 , 367 , 367 , 367 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 458 , 458 , 458 , 458 , 458 , 458 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , ],
184
+ [ 367 , 367 , 367 , 367 , 367 , 367 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , 367 , 367 , 367 , -1 , -1 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , ],
185
+ [ 367 , 367 , 367 , 367 , 367 , 367 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
186
+ [ 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
187
+ [ 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , ],
188
+ [ 367 , 367 , 367 , -1 , -1 , -1 , -1 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , ],
189
+ [ 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , ],
190
+ [ 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , ],
191
+ [ 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , ],
192
+ [ 367 , 367 , 367 , -1 , -1 , 367 , 367 , -1 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
193
+ [ 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
194
+ [ 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , ],
195
+ [ 367 , 367 , 367 , -1 , -1 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , ],
196
+ [ 367 , 367 , 367 , -1 , -1 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , ],
197
+ [ 367 , 367 , 367 , -1 , 367 , -1 , -1 , -1 , -1 , -1 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , ],
198
+ [ 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , ],
199
+ [ 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , ],
200
+ [ 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , ],
201
+ [ 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , ],
202
+ [ 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , ],
203
+ [ 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , ],
204
+ [ 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , ],
205
+ [ 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , ],
206
+ [ 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , -1 , 367 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , ],
207
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , ],
208
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , ],
209
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , 367 , ],
210
+ ],
211
+ [
212
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
213
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
214
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
215
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
216
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
217
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
218
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
219
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
220
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
221
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
222
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
223
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
224
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
225
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
226
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
227
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
228
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
229
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
230
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
231
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
232
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
233
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
234
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
235
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
236
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
237
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
238
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
239
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
240
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
241
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
242
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
243
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
244
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
245
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
246
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
247
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
248
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
249
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
250
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
251
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
252
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
253
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
254
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
255
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
256
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
257
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
258
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
259
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
260
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
261
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
262
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
263
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
264
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
265
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
266
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
267
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
268
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
269
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
270
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
271
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
272
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
273
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
274
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
275
+ [ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , ],
276
+ ],];
277
+ export const animatedsprites = [
278
+ { x: 1440, y: 352, w: 32, h: 32, layer: 1, sheet: "campfire.json", animation: "pixels_large" },
279
+ { x: 736, y: 288, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
280
+ { x: 768, y: 288, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
281
+ { x: 800, y: 288, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
282
+ { x: 800, y: 256, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
283
+ { x: 832, y: 288, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
284
+ { x: 832, y: 224, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
285
+ { x: 800, y: 224, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
286
+ { x: 800, y: 192, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
287
+ { x: 768, y: 192, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
288
+ { x: 768, y: 160, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
289
+ { x: 800, y: 128, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
290
+ { x: 768, y: 96, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
291
+ { x: 800, y: 64, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
292
+ { x: 736, y: 448, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
293
+ { x: 768, y: 448, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
294
+ { x: 800, y: 448, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
295
+ { x: 832, y: 448, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
296
+ { x: 832, y: 480, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
297
+ { x: 800, y: 480, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
298
+ { x: 800, y: 512, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
299
+ { x: 768, y: 512, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
300
+ { x: 768, y: 544, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
301
+ { x: 800, y: 576, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
302
+ { x: 768, y: 480, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
303
+ { x: 768, y: 736, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
304
+ { x: 800, y: 768, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
305
+ { x: 800, y: 800, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
306
+ { x: 800, y: 832, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
307
+ { x: 800, y: 864, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
308
+ { x: 864, y: 1024, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
309
+ { x: 896, y: 1056, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
310
+ { x: 864, y: 1088, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
311
+ { x: 896, y: 1088, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
312
+ { x: 896, y: 1120, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
313
+ { x: 896, y: 1152, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
314
+ { x: 896, y: 1184, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
315
+ { x: 928, y: 1152, w: 32, h: 32, layer: 1, sheet: "gentlesparkle.json", animation: "pixels_large" },
316
+ { x: 736, y: 320, w: 32, h: 96, layer: 1, sheet: "gentlewaterfall.json", animation: "pixels_large" },
317
+ { x: 768, y: 320, w: 32, h: 96, layer: 1, sheet: "gentlewaterfall.json", animation: "pixels_large" },
318
+ { x: 800, y: 320, w: 32, h: 96, layer: 1, sheet: "gentlewaterfall.json", animation: "pixels_large" },
319
+ { x: 832, y: 320, w: 32, h: 96, layer: 1, sheet: "gentlewaterfall.json", animation: "pixels_large" },
320
+ { x: 1664, y: 576, w: 208, h: 208, layer: 1, sheet: "windmill.json", animation: "pixels_large" },
321
+ { x: 1440, y: 768, w: 208, h: 208, layer: 1, sheet: "windmill.json", animation: "pixels_large" },
322
+ { x: 1120, y: 608, w: 208, h: 208, layer: 1, sheet: "windmill.json", animation: "pixels_large" },
323
+ { x: 736, y: 384, w: 32, h: 64, layer: 2, sheet: "gentlesplash.json", animation: "pixels_large" },
324
+ { x: 768, y: 384, w: 32, h: 64, layer: 2, sheet: "gentlesplash.json", animation: "pixels_large" },
325
+ { x: 800, y: 384, w: 32, h: 64, layer: 2, sheet: "gentlesplash.json", animation: "pixels_large" },
326
+ { x: 832, y: 384, w: 32, h: 64, layer: 2, sheet: "gentlesplash.json", animation: "pixels_large" },
327
+ ];
328
+
329
+ export const mapwidth = bgtiles[0].length;
330
+ export const mapheight = bgtiles[0][0].length;
patches/patches/hf.svg ADDED
patches/patches/llm.ts ADDED
@@ -0,0 +1,657 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { HfInference } from "@huggingface/inference";
2
+
3
+ export const LLM_CONFIG = {
4
+ /* Hugginface config: */
5
+ ollama: false,
6
+ huggingface: true,
7
+ url: "https://api-inference.huggingface.co/models/meta-llama/Meta-Llama-3-8B-Instruct",
8
+ chatModel: "meta-llama/Meta-Llama-3-8B-Instruct",
9
+ embeddingModel:
10
+ "https://api-inference.huggingface.co/models/mixedbread-ai/mxbai-embed-large-v1",
11
+ embeddingDimension: 1024,
12
+
13
+ /* Ollama (local) config:
14
+ */
15
+ // ollama: true,
16
+ // url: 'http://127.0.0.1:11434',
17
+ // chatModel: 'llama3' as const,
18
+ // embeddingModel: 'mxbai-embed-large',
19
+ // embeddingDimension: 1024,
20
+ // embeddingModel: 'llama3',
21
+ // embeddingDimension: 4096,
22
+
23
+ /* Together.ai config:
24
+ ollama: false,
25
+ url: 'https://api.together.xyz',
26
+ chatModel: 'meta-llama/Llama-3-8b-chat-hf',
27
+ embeddingModel: 'togethercomputer/m2-bert-80M-8k-retrieval',
28
+ embeddingDimension: 768,
29
+ */
30
+
31
+ /* OpenAI config:
32
+ ollama: false,
33
+ url: 'https://api.openai.com',
34
+ chatModel: 'gpt-3.5-turbo-16k',
35
+ embeddingModel: 'text-embedding-ada-002',
36
+ embeddingDimension: 1536,
37
+ */
38
+ };
39
+
40
+ function apiUrl(path: string) {
41
+ // OPENAI_API_BASE and OLLAMA_HOST are legacy
42
+ const host =
43
+ process.env.LLM_API_URL ??
44
+ process.env.OLLAMA_HOST ??
45
+ process.env.OPENAI_API_BASE ??
46
+ LLM_CONFIG.url;
47
+ if (host.endsWith("/") && path.startsWith("/")) {
48
+ return host + path.slice(1);
49
+ } else if (!host.endsWith("/") && !path.startsWith("/")) {
50
+ return host + "/" + path;
51
+ } else {
52
+ return host + path;
53
+ }
54
+ }
55
+
56
+ function apiKey() {
57
+ return process.env.LLM_API_KEY ?? process.env.OPENAI_API_KEY;
58
+ }
59
+
60
+ const AuthHeaders = (): Record<string, string> =>
61
+ apiKey()
62
+ ? {
63
+ Authorization: "Bearer " + apiKey(),
64
+ }
65
+ : {};
66
+
67
+ // Overload for non-streaming
68
+ export async function chatCompletion(
69
+ body: Omit<CreateChatCompletionRequest, "model"> & {
70
+ model?: CreateChatCompletionRequest["model"];
71
+ } & {
72
+ stream?: false | null | undefined;
73
+ }
74
+ ): Promise<{ content: string; retries: number; ms: number }>;
75
+ // Overload for streaming
76
+ export async function chatCompletion(
77
+ body: Omit<CreateChatCompletionRequest, "model"> & {
78
+ model?: CreateChatCompletionRequest["model"];
79
+ } & {
80
+ stream?: true;
81
+ }
82
+ ): Promise<{ content: ChatCompletionContent; retries: number; ms: number }>;
83
+ export async function chatCompletion(
84
+ body: Omit<CreateChatCompletionRequest, "model"> & {
85
+ model?: CreateChatCompletionRequest["model"];
86
+ }
87
+ ) {
88
+ assertApiKey();
89
+ // OLLAMA_MODEL is legacy
90
+ body.model =
91
+ body.model ??
92
+ process.env.LLM_MODEL ??
93
+ process.env.OLLAMA_MODEL ??
94
+ LLM_CONFIG.chatModel;
95
+ const stopWords = body.stop
96
+ ? typeof body.stop === "string"
97
+ ? [body.stop]
98
+ : body.stop
99
+ : [];
100
+ if (LLM_CONFIG.ollama || LLM_CONFIG.huggingface) stopWords.push("<|eot_id|>");
101
+
102
+ const {
103
+ result: content,
104
+ retries,
105
+ ms,
106
+ } = await retryWithBackoff(async () => {
107
+ const hf = new HfInference(apiKey());
108
+ const model = hf.endpoint(apiUrl("/v1/chat/completions"));
109
+ if (body.stream) {
110
+ const completion = model.chatCompletionStream({
111
+ ...body,
112
+ });
113
+ return new ChatCompletionContent(completion, stopWords);
114
+ } else {
115
+ const completion = await model.chatCompletion({
116
+ ...body,
117
+ });
118
+ const content = completion.choices[0].message?.content;
119
+ if (content === undefined) {
120
+ throw new Error(
121
+ "Unexpected result from OpenAI: " + JSON.stringify(completion)
122
+ );
123
+ }
124
+ return content;
125
+ }
126
+ });
127
+
128
+ return {
129
+ content,
130
+ retries,
131
+ ms,
132
+ };
133
+ }
134
+
135
+ export async function tryPullOllama(model: string, error: string) {
136
+ if (error.includes("try pulling")) {
137
+ console.error("Embedding model not found, pulling from Ollama");
138
+ const pullResp = await fetch(apiUrl("/api/pull"), {
139
+ method: "POST",
140
+ headers: {
141
+ "Content-Type": "application/json",
142
+ },
143
+ body: JSON.stringify({ name: model }),
144
+ });
145
+ console.log("Pull response", await pullResp.text());
146
+ throw {
147
+ retry: true,
148
+ error: `Dynamically pulled model. Original error: ${error}`,
149
+ };
150
+ }
151
+ }
152
+
153
+ export async function fetchEmbeddingBatch(texts: string[]) {
154
+ if (LLM_CONFIG.ollama) {
155
+ return {
156
+ ollama: true as const,
157
+ embeddings: await Promise.all(
158
+ texts.map(async (t) => (await ollamaFetchEmbedding(t)).embedding)
159
+ ),
160
+ };
161
+ }
162
+ assertApiKey();
163
+
164
+ if (LLM_CONFIG.huggingface) {
165
+ const result = await fetch(LLM_CONFIG.embeddingModel, {
166
+ method: "POST",
167
+ headers: {
168
+ "Content-Type": "application/json",
169
+ "X-Wait-For-Model": "true",
170
+ ...AuthHeaders(),
171
+ },
172
+ body: JSON.stringify({
173
+ inputs: texts.map((text) => text.replace(/\n/g, " ")),
174
+ }),
175
+ });
176
+ const embeddings = await result.json();
177
+ return {
178
+ ollama: true as const,
179
+ embeddings: embeddings,
180
+ };
181
+ }
182
+
183
+ const {
184
+ result: json,
185
+ retries,
186
+ ms,
187
+ } = await retryWithBackoff(async () => {
188
+ const result = await fetch(apiUrl("/v1/embeddings"), {
189
+ method: "POST",
190
+ headers: {
191
+ "Content-Type": "application/json",
192
+ ...AuthHeaders(),
193
+ },
194
+
195
+ body: JSON.stringify({
196
+ model: LLM_CONFIG.embeddingModel,
197
+ input: texts.map((text) => text.replace(/\n/g, " ")),
198
+ }),
199
+ });
200
+ if (!result.ok) {
201
+ throw {
202
+ retry: result.status === 429 || result.status >= 500,
203
+ error: new Error(
204
+ `Embedding failed with code ${result.status}: ${await result.text()}`
205
+ ),
206
+ };
207
+ }
208
+ return (await result.json()) as CreateEmbeddingResponse;
209
+ });
210
+ if (json.data.length !== texts.length) {
211
+ console.error(json);
212
+ throw new Error("Unexpected number of embeddings");
213
+ }
214
+ const allembeddings = json.data;
215
+ allembeddings.sort((a, b) => a.index - b.index);
216
+ return {
217
+ ollama: false as const,
218
+ embeddings: allembeddings.map(({ embedding }) => embedding),
219
+ usage: json.usage?.total_tokens,
220
+ retries,
221
+ ms,
222
+ };
223
+ }
224
+
225
+ export async function fetchEmbedding(text: string) {
226
+ const { embeddings, ...stats } = await fetchEmbeddingBatch([text]);
227
+ return { embedding: embeddings[0], ...stats };
228
+ }
229
+
230
+ export async function fetchModeration(content: string) {
231
+ assertApiKey();
232
+ const { result: flagged } = await retryWithBackoff(async () => {
233
+ const result = await fetch(apiUrl("/v1/moderations"), {
234
+ method: "POST",
235
+ headers: {
236
+ "Content-Type": "application/json",
237
+ ...AuthHeaders(),
238
+ },
239
+
240
+ body: JSON.stringify({
241
+ input: content,
242
+ }),
243
+ });
244
+ if (!result.ok) {
245
+ throw {
246
+ retry: result.status === 429 || result.status >= 500,
247
+ error: new Error(
248
+ `Embedding failed with code ${result.status}: ${await result.text()}`
249
+ ),
250
+ };
251
+ }
252
+ return (await result.json()) as { results: { flagged: boolean }[] };
253
+ });
254
+ return flagged;
255
+ }
256
+
257
+ export function assertApiKey() {
258
+ if (!LLM_CONFIG.ollama && !apiKey()) {
259
+ throw new Error(
260
+ "\n Missing LLM_API_KEY in environment variables.\n\n" +
261
+ (LLM_CONFIG.ollama ? "just" : "npx") +
262
+ " convex env set LLM_API_KEY 'your-key'"
263
+ );
264
+ }
265
+ }
266
+
267
+ // Retry after this much time, based on the retry number.
268
+ const RETRY_BACKOFF = [1000, 10_000, 20_000]; // In ms
269
+ const RETRY_JITTER = 100; // In ms
270
+ type RetryError = { retry: boolean; error: any };
271
+
272
+ export async function retryWithBackoff<T>(
273
+ fn: () => Promise<T>
274
+ ): Promise<{ retries: number; result: T; ms: number }> {
275
+ let i = 0;
276
+ for (; i <= RETRY_BACKOFF.length; i++) {
277
+ try {
278
+ const start = Date.now();
279
+ const result = await fn();
280
+ const ms = Date.now() - start;
281
+ return { result, retries: i, ms };
282
+ } catch (e) {
283
+ const retryError = e as RetryError;
284
+ if (i < RETRY_BACKOFF.length) {
285
+ if (retryError.retry) {
286
+ console.log(
287
+ `Attempt ${i + 1} failed, waiting ${
288
+ RETRY_BACKOFF[i]
289
+ }ms to retry...`,
290
+ Date.now()
291
+ );
292
+ await new Promise((resolve) =>
293
+ setTimeout(resolve, RETRY_BACKOFF[i] + RETRY_JITTER * Math.random())
294
+ );
295
+ continue;
296
+ }
297
+ }
298
+ if (retryError.error) throw retryError.error;
299
+ else throw e;
300
+ }
301
+ }
302
+ throw new Error("Unreachable");
303
+ }
304
+
305
+ // Lifted from openai's package
306
+ export interface LLMMessage {
307
+ /**
308
+ * The contents of the message. `content` is required for all messages, and may be
309
+ * null for assistant messages with function calls.
310
+ */
311
+ content: string | null;
312
+
313
+ /**
314
+ * The role of the messages author. One of `system`, `user`, `assistant`, or
315
+ * `function`.
316
+ */
317
+ role: "system" | "user" | "assistant" | "function";
318
+
319
+ /**
320
+ * The name of the author of this message. `name` is required if role is
321
+ * `function`, and it should be the name of the function whose response is in the
322
+ * `content`. May contain a-z, A-Z, 0-9, and underscores, with a maximum length of
323
+ * 64 characters.
324
+ */
325
+ name?: string;
326
+
327
+ /**
328
+ * The name and arguments of a function that should be called, as generated by the model.
329
+ */
330
+ function_call?: {
331
+ // The name of the function to call.
332
+ name: string;
333
+ /**
334
+ * The arguments to call the function with, as generated by the model in
335
+ * JSON format. Note that the model does not always generate valid JSON,
336
+ * and may hallucinate parameters not defined by your function schema.
337
+ * Validate the arguments in your code before calling your function.
338
+ */
339
+ arguments: string;
340
+ };
341
+ }
342
+
343
+ // Non-streaming chat completion response
344
+ interface CreateChatCompletionResponse {
345
+ id: string;
346
+ object: string;
347
+ created: number;
348
+ model: string;
349
+ choices: {
350
+ index?: number;
351
+ message?: {
352
+ role: "system" | "user" | "assistant";
353
+ content: string;
354
+ };
355
+ finish_reason?: string;
356
+ }[];
357
+ usage?: {
358
+ completion_tokens: number;
359
+
360
+ prompt_tokens: number;
361
+
362
+ total_tokens: number;
363
+ };
364
+ }
365
+
366
+ interface CreateEmbeddingResponse {
367
+ data: {
368
+ index: number;
369
+ object: string;
370
+ embedding: number[];
371
+ }[];
372
+ model: string;
373
+ object: string;
374
+ usage: {
375
+ prompt_tokens: number;
376
+ total_tokens: number;
377
+ };
378
+ }
379
+
380
+ export interface CreateChatCompletionRequest {
381
+ /**
382
+ * ID of the model to use.
383
+ * @type {string}
384
+ * @memberof CreateChatCompletionRequest
385
+ */
386
+ model: string;
387
+ // | 'gpt-4'
388
+ // | 'gpt-4-0613'
389
+ // | 'gpt-4-32k'
390
+ // | 'gpt-4-32k-0613'
391
+ // | 'gpt-3.5-turbo'
392
+ // | 'gpt-3.5-turbo-0613'
393
+ // | 'gpt-3.5-turbo-16k' // <- our default
394
+ // | 'gpt-3.5-turbo-16k-0613';
395
+ /**
396
+ * The messages to generate chat completions for, in the chat format:
397
+ * https://platform.openai.com/docs/guides/chat/introduction
398
+ * @type {Array<ChatCompletionRequestMessage>}
399
+ * @memberof CreateChatCompletionRequest
400
+ */
401
+ messages: LLMMessage[];
402
+ /**
403
+ * What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. We generally recommend altering this or `top_p` but not both.
404
+ * @type {number}
405
+ * @memberof CreateChatCompletionRequest
406
+ */
407
+ temperature?: number | null;
408
+ /**
409
+ * An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered. We generally recommend altering this or `temperature` but not both.
410
+ * @type {number}
411
+ * @memberof CreateChatCompletionRequest
412
+ */
413
+ top_p?: number | null;
414
+ /**
415
+ * How many chat completion choices to generate for each input message.
416
+ * @type {number}
417
+ * @memberof CreateChatCompletionRequest
418
+ */
419
+ n?: number | null;
420
+ /**
421
+ * If set, partial message deltas will be sent, like in ChatGPT. Tokens will be sent as data-only [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) as they become available, with the stream terminated by a `data: [DONE]` message.
422
+ * @type {boolean}
423
+ * @memberof CreateChatCompletionRequest
424
+ */
425
+ stream?: boolean | null;
426
+ /**
427
+ *
428
+ * @type {CreateChatCompletionRequestStop}
429
+ * @memberof CreateChatCompletionRequest
430
+ */
431
+ stop?: Array<string> | string;
432
+ /**
433
+ * The maximum number of tokens allowed for the generated answer. By default,
434
+ * the number of tokens the model can return will be (4096 - prompt tokens).
435
+ * @type {number}
436
+ * @memberof CreateChatCompletionRequest
437
+ */
438
+ max_tokens?: number;
439
+ /**
440
+ * Number between -2.0 and 2.0. Positive values penalize new tokens based on
441
+ * whether they appear in the text so far, increasing the model\'s likelihood
442
+ * to talk about new topics. See more information about frequency and
443
+ * presence penalties:
444
+ * https://platform.openai.com/docs/api-reference/parameter-details
445
+ * @type {number}
446
+ * @memberof CreateChatCompletionRequest
447
+ */
448
+ presence_penalty?: number | null;
449
+ /**
450
+ * Number between -2.0 and 2.0. Positive values penalize new tokens based on
451
+ * their existing frequency in the text so far, decreasing the model\'s
452
+ * likelihood to repeat the same line verbatim. See more information about
453
+ * presence penalties:
454
+ * https://platform.openai.com/docs/api-reference/parameter-details
455
+ * @type {number}
456
+ * @memberof CreateChatCompletionRequest
457
+ */
458
+ frequency_penalty?: number | null;
459
+ /**
460
+ * Modify the likelihood of specified tokens appearing in the completion.
461
+ * Accepts a json object that maps tokens (specified by their token ID in the
462
+ * tokenizer) to an associated bias value from -100 to 100. Mathematically,
463
+ * the bias is added to the logits generated by the model prior to sampling.
464
+ * The exact effect will vary per model, but values between -1 and 1 should
465
+ * decrease or increase likelihood of selection; values like -100 or 100
466
+ * should result in a ban or exclusive selection of the relevant token.
467
+ * @type {object}
468
+ * @memberof CreateChatCompletionRequest
469
+ */
470
+ logit_bias?: object | null;
471
+ /**
472
+ * A unique identifier representing your end-user, which can help OpenAI to
473
+ * monitor and detect abuse. Learn more:
474
+ * https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids
475
+ * @type {string}
476
+ * @memberof CreateChatCompletionRequest
477
+ */
478
+ user?: string;
479
+ tools?: {
480
+ // The type of the tool. Currently, only function is supported.
481
+ type: "function";
482
+ function: {
483
+ /**
484
+ * The name of the function to be called. Must be a-z, A-Z, 0-9, or
485
+ * contain underscores and dashes, with a maximum length of 64.
486
+ */
487
+ name: string;
488
+ /**
489
+ * A description of what the function does, used by the model to choose
490
+ * when and how to call the function.
491
+ */
492
+ description?: string;
493
+ /**
494
+ * The parameters the functions accepts, described as a JSON Schema
495
+ * object. See the guide[1] for examples, and the JSON Schema reference[2]
496
+ * for documentation about the format.
497
+ * [1]: https://platform.openai.com/docs/guides/gpt/function-calling
498
+ * [2]: https://json-schema.org/understanding-json-schema/
499
+ * To describe a function that accepts no parameters, provide the value
500
+ * {"type": "object", "properties": {}}.
501
+ */
502
+ parameters: object;
503
+ };
504
+ }[];
505
+ /**
506
+ * Controls which (if any) function is called by the model. `none` means the
507
+ * model will not call a function and instead generates a message.
508
+ * `auto` means the model can pick between generating a message or calling a
509
+ * function. Specifying a particular function via
510
+ * {"type: "function", "function": {"name": "my_function"}} forces the model
511
+ * to call that function.
512
+ *
513
+ * `none` is the default when no functions are present.
514
+ * `auto` is the default if functions are present.
515
+ */
516
+ tool_choice?:
517
+ | "none" // none means the model will not call a function and instead generates a message.
518
+ | "auto" // auto means the model can pick between generating a message or calling a function.
519
+ // Specifies a tool the model should use. Use to force the model to call
520
+ // a specific function.
521
+ | {
522
+ // The type of the tool. Currently, only function is supported.
523
+ type: "function";
524
+ function: { name: string };
525
+ };
526
+ // Replaced by "tools"
527
+ // functions?: {
528
+ // /**
529
+ // * The name of the function to be called. Must be a-z, A-Z, 0-9, or
530
+ // * contain underscores and dashes, with a maximum length of 64.
531
+ // */
532
+ // name: string;
533
+ // /**
534
+ // * A description of what the function does, used by the model to choose
535
+ // * when and how to call the function.
536
+ // */
537
+ // description?: string;
538
+ // /**
539
+ // * The parameters the functions accepts, described as a JSON Schema
540
+ // * object. See the guide[1] for examples, and the JSON Schema reference[2]
541
+ // * for documentation about the format.
542
+ // * [1]: https://platform.openai.com/docs/guides/gpt/function-calling
543
+ // * [2]: https://json-schema.org/understanding-json-schema/
544
+ // * To describe a function that accepts no parameters, provide the value
545
+ // * {"type": "object", "properties": {}}.
546
+ // */
547
+ // parameters: object;
548
+ // }[];
549
+ // /**
550
+ // * Controls how the model responds to function calls. "none" means the model
551
+ // * does not call a function, and responds to the end-user. "auto" means the
552
+ // * model can pick between an end-user or calling a function. Specifying a
553
+ // * particular function via {"name":\ "my_function"} forces the model to call
554
+ // * that function.
555
+ // * - "none" is the default when no functions are present.
556
+ // * - "auto" is the default if functions are present.
557
+ // */
558
+ // function_call?: 'none' | 'auto' | { name: string };
559
+ /**
560
+ * An object specifying the format that the model must output.
561
+ *
562
+ * Setting to { "type": "json_object" } enables JSON mode, which guarantees
563
+ * the message the model generates is valid JSON.
564
+ * *Important*: when using JSON mode, you must also instruct the model to
565
+ * produce JSON yourself via a system or user message. Without this, the model
566
+ * may generate an unending stream of whitespace until the generation reaches
567
+ * the token limit, resulting in a long-running and seemingly "stuck" request.
568
+ * Also note that the message content may be partially cut off if
569
+ * finish_reason="length", which indicates the generation exceeded max_tokens
570
+ * or the conversation exceeded the max context length.
571
+ */
572
+ response_format?: { type: "text" | "json_object" };
573
+ }
574
+
575
+ // Checks whether a suffix of s1 is a prefix of s2. For example,
576
+ // ('Hello', 'Kira:') -> false
577
+ // ('Hello Kira', 'Kira:') -> true
578
+ const suffixOverlapsPrefix = (s1: string, s2: string) => {
579
+ for (let i = 1; i <= Math.min(s1.length, s2.length); i++) {
580
+ const suffix = s1.substring(s1.length - i);
581
+ const prefix = s2.substring(0, i);
582
+ if (suffix === prefix) {
583
+ return true;
584
+ }
585
+ }
586
+ return false;
587
+ };
588
+
589
+ export class ChatCompletionContent {
590
+ private readonly completion: AsyncIterable<ChatCompletionChunk>;
591
+ private readonly stopWords: string[];
592
+
593
+ constructor(
594
+ completion: AsyncIterable<ChatCompletionChunk>,
595
+ stopWords: string[]
596
+ ) {
597
+ this.completion = completion;
598
+ this.stopWords = stopWords;
599
+ }
600
+
601
+ async *readInner() {
602
+ for await (const chunk of this.completion) {
603
+ yield chunk.choices[0].delta.content;
604
+ }
605
+ }
606
+
607
+ // stop words in OpenAI api don't always work.
608
+ // So we have to truncate on our side.
609
+ async *read() {
610
+ let lastFragment = "";
611
+ for await (const data of this.readInner()) {
612
+ lastFragment += data;
613
+ let hasOverlap = false;
614
+ for (const stopWord of this.stopWords) {
615
+ const idx = lastFragment.indexOf(stopWord);
616
+ if (idx >= 0) {
617
+ yield lastFragment.substring(0, idx);
618
+ return;
619
+ }
620
+ if (suffixOverlapsPrefix(lastFragment, stopWord)) {
621
+ hasOverlap = true;
622
+ }
623
+ }
624
+ if (hasOverlap) continue;
625
+ yield lastFragment;
626
+ lastFragment = "";
627
+ }
628
+ yield lastFragment;
629
+ }
630
+
631
+ async readAll() {
632
+ let allContent = "";
633
+ for await (const chunk of this.read()) {
634
+ allContent += chunk;
635
+ }
636
+ return allContent;
637
+ }
638
+ }
639
+
640
+ export async function ollamaFetchEmbedding(text: string) {
641
+ const { result } = await retryWithBackoff(async () => {
642
+ const resp = await fetch(apiUrl("/api/embeddings"), {
643
+ method: "POST",
644
+ headers: {
645
+ "Content-Type": "application/json",
646
+ },
647
+ body: JSON.stringify({ model: LLM_CONFIG.embeddingModel, prompt: text }),
648
+ });
649
+ if (resp.status === 404) {
650
+ const error = await resp.text();
651
+ await tryPullOllama(LLM_CONFIG.embeddingModel, error);
652
+ throw new Error(`Failed to fetch embeddings: ${resp.status}`);
653
+ }
654
+ return (await resp.json()).embedding as number[];
655
+ });
656
+ return { embedding: result };
657
+ }
patches/patches/music.ts ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { v } from 'convex/values';
2
+ import { query, internalMutation } from './_generated/server';
3
+ import Replicate, { WebhookEventType } from 'replicate';
4
+ import { httpAction, internalAction } from './_generated/server';
5
+ import { internal, api } from './_generated/api';
6
+
7
+ function client(): Replicate {
8
+ const replicate = new Replicate({
9
+ auth: process.env.REPLICATE_API_TOKEN || '',
10
+ });
11
+ return replicate;
12
+ }
13
+
14
+ function replicateAvailable(): boolean {
15
+ return !!process.env.REPLICATE_API_TOKEN;
16
+ }
17
+
18
+ export const insertMusic = internalMutation({
19
+ args: { storageId: v.string(), type: v.union(v.literal('background'), v.literal('player')) },
20
+ handler: async (ctx, args) => {
21
+ await ctx.db.insert('music', {
22
+ storageId: args.storageId,
23
+ type: args.type,
24
+ });
25
+ },
26
+ });
27
+
28
+ export const getBackgroundMusic = query({
29
+ handler: async (ctx) => {
30
+ const music = await ctx.db
31
+ .query('music')
32
+ .filter((entry) => entry.eq(entry.field('type'), 'background'))
33
+ .order('desc')
34
+ .first();
35
+ if (!music) {
36
+ return '/assets/background.mp3';
37
+ }
38
+ const url = await ctx.storage.getUrl(music.storageId);
39
+ if (!url) {
40
+ throw new Error(`Invalid storage ID: ${music.storageId}`);
41
+ }
42
+ return url;
43
+ },
44
+ });
45
+
46
+ export const enqueueBackgroundMusicGeneration = internalAction({
47
+ handler: async (ctx): Promise<void> => {
48
+ if (!replicateAvailable()) {
49
+ return;
50
+ }
51
+ const worldStatus = await ctx.runQuery(api.world.defaultWorldStatus);
52
+ if (!worldStatus) {
53
+ console.log('No active default world, returning.');
54
+ return;
55
+ }
56
+ // TODO: MusicGen-Large on Replicate only allows 30 seconds. Use MusicGen-Small for longer?
57
+ await generateMusic('16-bit RPG adventure game with wholesome vibe', 30);
58
+ },
59
+ });
60
+
61
+ export const handleReplicateWebhook = httpAction(async (ctx, request) => {
62
+ const req = await request.json();
63
+ if (req.id) {
64
+ const prediction = await client().predictions.get(req.id);
65
+ const response = await fetch(prediction.output);
66
+ const music = await response.blob();
67
+ const storageId = await ctx.storage.store(music);
68
+ await ctx.runMutation(internal.music.insertMusic, { type: 'background', storageId });
69
+ }
70
+ return new Response();
71
+ });
72
+
73
+ enum MusicGenNormStrategy {
74
+ Clip = 'clip',
75
+ Loudness = 'loudness',
76
+ Peak = 'peak',
77
+ Rms = 'rms',
78
+ }
79
+
80
+ enum MusicGenFormat {
81
+ wav = 'wav',
82
+ mp3 = 'mp3',
83
+ }
84
+
85
+ /**
86
+ *
87
+ * @param prompt A description of the music you want to generate.
88
+ * @param duration Duration of the generated audio in seconds.
89
+ * @param webhook webhook URL for Replicate to call when @param webhook_events_filter is triggered
90
+ * @param webhook_events_filter Array of event names to filter the webhook. See https://replicate.com/docs/reference/http#predictions.create--webhook_events_filter
91
+ * @param normalization_strategy Strategy for normalizing audio.
92
+ * @param top_k Reduces sampling to the k most likely tokens.
93
+ * @param top_p Reduces sampling to tokens with cumulative probability of p. When set to `0` (default), top_k sampling is used.
94
+ * @param temperature Controls the 'conservativeness' of the sampling process. Higher temperature means more diversity.
95
+ * @param classifer_free_gudance Increases the influence of inputs on the output. Higher values produce lower-varience outputs that adhere more closely to inputs.
96
+ * @param output_format Output format for generated audio. See @
97
+ * @param seed Seed for random number generator. If None or -1, a random seed will be used.
98
+ * @returns object containing metadata of the prediction with ID to fetch once result is completed
99
+ */
100
+ export async function generateMusic(
101
+ prompt: string,
102
+ duration: number,
103
+ webhook: string = process.env.CONVEX_SITE_URL + '/replicate_webhook' || '',
104
+ webhook_events_filter: [WebhookEventType] = ['completed'],
105
+ normalization_strategy: MusicGenNormStrategy = MusicGenNormStrategy.Peak,
106
+ output_format: MusicGenFormat = MusicGenFormat.mp3,
107
+ top_k = 250,
108
+ top_p = 0,
109
+ temperature = 1,
110
+ classifer_free_gudance = 3,
111
+ seed = -1,
112
+ model_version = 'large',
113
+ ) {
114
+ if (!replicateAvailable()) {
115
+ throw new Error('Replicate API token not set');
116
+ }
117
+ return await client().predictions.create({
118
+ // https://replicate.com/facebookresearch/musicgen/versions/7a76a8258b23fae65c5a22debb8841d1d7e816b75c2f24218cd2bd8573787906
119
+ version: '7a76a8258b23fae65c5a22debb8841d1d7e816b75c2f24218cd2bd8573787906',
120
+ input: {
121
+ model_version,
122
+ prompt,
123
+ duration,
124
+ normalization_strategy,
125
+ top_k,
126
+ top_p,
127
+ temperature,
128
+ classifer_free_gudance,
129
+ output_format,
130
+ seed,
131
+ },
132
+ webhook,
133
+ webhook_events_filter,
134
+ });
135
+ }
patches/patches/run.sh ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ run_convex_command() {
3
+ npx convex "$@" --admin-key 0135d8598650f8f5cb0f30c34ec2e2bb62793bc28717c8eb6fb577996d50be5f4281b59181095065c5d0f86a2c31ddbe9b597ec62b47ded69782cd --url "http://0.0.0.0:3210"
4
+ }
5
+
6
+ ./convex-local-backend &
7
+ run_convex_command env set LLM_API_KEY $HF_TOKEN &
8
+ run_convex_command dev --run init --until-success &
9
+ run_convex_command deploy &
10
+
11
+ # run_convex_command dev --run init --until-success &
12
+ # run_convex_command dev --tail-logs &
13
+ # you need to set VITE_CONVEX_URL to the Vite Server proxied version
14
+ if [ -z "$SPACE_HOST" ]; then
15
+ export VITE_CONVEX_URL=http://localhost:5173/backend.convex.cloud
16
+ else
17
+ export VITE_CONVEX_URL=https://$SPACE_HOST/backend.convex.cloud
18
+ fi
19
+
20
+ export VITE_OAUTH_CLIENT_ID=$OAUTH_CLIENT_ID
21
+ # Unsure if the following are necessary
22
+ # export OAUTH_CLIENT_SECRET=$OAUTH_CLIENT_SECRET
23
+ # export OAUTH_SCOPES=$OAUTH_SCOPES
24
+ # export OPENID_PROVIDER_URL=$OPENID_PROVIDER_URL
25
+
26
+ npm run dev:frontend -- --host 0.0.0.0 &
27
+ run_convex_command dev
patches/patches/vite.config.ts ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { defineConfig } from 'vite';
2
+ import react from '@vitejs/plugin-react';
3
+
4
+ // https://vitejs.dev/config/
5
+ export default defineConfig({
6
+ base: '/',
7
+ plugins: [react()],
8
+ server: {
9
+ proxy: {
10
+ '/backend.convex.cloud': {
11
+ target: 'ws://0.0.0.0:3210',
12
+ changeOrigin: true,
13
+ ws: true,
14
+ rewrite: (path) => path.replace(/^\/backend\.convex\.cloud/, '/'),
15
+ },
16
+ },
17
+ },
18
+ });
patches/patches/world.ts ADDED
@@ -0,0 +1,273 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ConvexError, v } from 'convex/values';
2
+ import { internalMutation, mutation, query } from './_generated/server';
3
+ import { characters } from '../data/characters';
4
+ import { Descriptions } from '../data/characters';
5
+ import { insertInput } from './aiTown/insertInput';
6
+ import {
7
+ DEFAULT_NAME,
8
+ ENGINE_ACTION_DURATION,
9
+ IDLE_WORLD_TIMEOUT,
10
+ WORLD_HEARTBEAT_INTERVAL,
11
+ } from './constants';
12
+ import { playerId } from './aiTown/ids';
13
+ import { kickEngine, startEngine, stopEngine } from './aiTown/main';
14
+ import { engineInsertInput } from './engine/abstractGame';
15
+
16
+ export const defaultWorldStatus = query({
17
+ handler: async (ctx) => {
18
+ const worldStatus = await ctx.db
19
+ .query('worldStatus')
20
+ .filter((q) => q.eq(q.field('isDefault'), true))
21
+ .first();
22
+ return worldStatus;
23
+ },
24
+ });
25
+
26
+ export const heartbeatWorld = mutation({
27
+ args: {
28
+ worldId: v.id('worlds'),
29
+ },
30
+ handler: async (ctx, args) => {
31
+ const worldStatus = await ctx.db
32
+ .query('worldStatus')
33
+ .withIndex('worldId', (q) => q.eq('worldId', args.worldId))
34
+ .first();
35
+ if (!worldStatus) {
36
+ throw new Error(`Invalid world ID: ${args.worldId}`);
37
+ }
38
+ const now = Date.now();
39
+
40
+ // Skip the update (and then potentially make the transaction readonly)
41
+ // if it's been viewed sufficiently recently..
42
+ if (!worldStatus.lastViewed || worldStatus.lastViewed < now - WORLD_HEARTBEAT_INTERVAL / 2) {
43
+ await ctx.db.patch(worldStatus._id, {
44
+ lastViewed: Math.max(worldStatus.lastViewed ?? now, now),
45
+ });
46
+ }
47
+
48
+ // Restart inactive worlds, but leave worlds explicitly stopped by the developer alone.
49
+ if (worldStatus.status === 'stoppedByDeveloper') {
50
+ console.debug(`World ${worldStatus._id} is stopped by developer, not restarting.`);
51
+ }
52
+ if (worldStatus.status === 'inactive') {
53
+ console.log(`Restarting inactive world ${worldStatus._id}...`);
54
+ await ctx.db.patch(worldStatus._id, { status: 'running' });
55
+ await startEngine(ctx, worldStatus.worldId);
56
+ }
57
+ },
58
+ });
59
+
60
+ export const stopInactiveWorlds = internalMutation({
61
+ handler: async (ctx) => {
62
+ const cutoff = Date.now() - IDLE_WORLD_TIMEOUT;
63
+ const worlds = await ctx.db.query('worldStatus').collect();
64
+ for (const worldStatus of worlds) {
65
+ if (cutoff < worldStatus.lastViewed || worldStatus.status !== 'running') {
66
+ continue;
67
+ }
68
+ console.log(`Stopping inactive world ${worldStatus._id}`);
69
+ await ctx.db.patch(worldStatus._id, { status: 'inactive' });
70
+ await stopEngine(ctx, worldStatus.worldId);
71
+ }
72
+ },
73
+ });
74
+
75
+ export const restartDeadWorlds = internalMutation({
76
+ handler: async (ctx) => {
77
+ const now = Date.now();
78
+
79
+ // Restart an engine if it hasn't run for 2x its action duration.
80
+ const engineTimeout = now - ENGINE_ACTION_DURATION * 2;
81
+ const worlds = await ctx.db.query('worldStatus').collect();
82
+ for (const worldStatus of worlds) {
83
+ if (worldStatus.status !== 'running') {
84
+ continue;
85
+ }
86
+ const engine = await ctx.db.get(worldStatus.engineId);
87
+ if (!engine) {
88
+ throw new Error(`Invalid engine ID: ${worldStatus.engineId}`);
89
+ }
90
+ if (engine.currentTime && engine.currentTime < engineTimeout) {
91
+ console.warn(`Restarting dead engine ${engine._id}...`);
92
+ await kickEngine(ctx, worldStatus.worldId);
93
+ }
94
+ }
95
+ },
96
+ });
97
+
98
+ export const userStatus = query({
99
+ args: {
100
+ worldId: v.id('worlds'),
101
+ oauthToken: v.optional(v.string()),
102
+
103
+ },
104
+ handler: async (ctx, args) => {
105
+ const { worldId, oauthToken } = args;
106
+
107
+ if (!oauthToken) {
108
+ return null;
109
+ }
110
+ console.log("oauthToken", oauthToken)
111
+ return oauthToken;
112
+ },
113
+ });
114
+
115
+ export const joinWorld = mutation({
116
+ args: {
117
+ worldId: v.id('worlds'),
118
+ oauthToken: v.optional(v.string()),
119
+
120
+ },
121
+ handler: async (ctx, args) => {
122
+ const { worldId, oauthToken } = args;
123
+
124
+ if (!oauthToken) {
125
+ throw new ConvexError(`Not logged in`);
126
+ }
127
+ // if (!identity) {
128
+ // throw new ConvexError(`Not logged in`);
129
+ // }
130
+ // const name =
131
+ // identity.givenName || identity.nickname || (identity.email && identity.email.split('@')[0]);
132
+ const name = oauthToken;
133
+
134
+ // if (!name) {
135
+ // throw new ConvexError(`Missing name on ${JSON.stringify(identity)}`);
136
+ // }
137
+ const world = await ctx.db.get(args.worldId);
138
+ if (!world) {
139
+ throw new ConvexError(`Invalid world ID: ${args.worldId}`);
140
+ }
141
+ // Select a random character description
142
+ const randomCharacter = Descriptions[Math.floor(Math.random() * Descriptions.length)];
143
+
144
+ return await insertInput(ctx, world._id, 'join', {
145
+ name: oauthToken,
146
+ character: randomCharacter.character,
147
+ description: "This is you !",
148
+ tokenIdentifier: oauthToken,
149
+ });
150
+ },
151
+ });
152
+
153
+
154
+ export const leaveWorld = mutation({
155
+ args: {
156
+ worldId: v.id('worlds'),
157
+ oauthToken: v.optional(v.string()),
158
+ },
159
+ handler: async (ctx, args) => {
160
+ const { worldId, oauthToken } = args;
161
+
162
+
163
+ console.log('OAuth Name:', oauthToken);
164
+ if (!oauthToken) {
165
+ throw new ConvexError(`Not logged in`);
166
+ }
167
+
168
+ const world = await ctx.db.get(args.worldId);
169
+ if (!world) {
170
+ throw new Error(`Invalid world ID: ${args.worldId}`);
171
+ }
172
+ // const existingPlayer = world.players.find((p) => p.human === tokenIdentifier);
173
+ const existingPlayer = world.players.find((p) => p.human === oauthToken);
174
+ if (!existingPlayer) {
175
+ return;
176
+ }
177
+ await insertInput(ctx, world._id, 'leave', {
178
+ playerId: existingPlayer.id,
179
+ });
180
+ },
181
+ });
182
+
183
+ export const sendWorldInput = mutation({
184
+ args: {
185
+ engineId: v.id('engines'),
186
+ name: v.string(),
187
+ args: v.any(),
188
+ },
189
+ handler: async (ctx, args) => {
190
+ // const identity = await ctx.auth.getUserIdentity();
191
+ // if (!identity) {
192
+ // throw new Error(`Not logged in`);
193
+ // }
194
+ return await engineInsertInput(ctx, args.engineId, args.name as any, args.args);
195
+ },
196
+ });
197
+
198
+ export const worldState = query({
199
+ args: {
200
+ worldId: v.id('worlds'),
201
+ },
202
+ handler: async (ctx, args) => {
203
+ const world = await ctx.db.get(args.worldId);
204
+ if (!world) {
205
+ throw new Error(`Invalid world ID: ${args.worldId}`);
206
+ }
207
+ const worldStatus = await ctx.db
208
+ .query('worldStatus')
209
+ .withIndex('worldId', (q) => q.eq('worldId', world._id))
210
+ .unique();
211
+ if (!worldStatus) {
212
+ throw new Error(`Invalid world status ID: ${world._id}`);
213
+ }
214
+ const engine = await ctx.db.get(worldStatus.engineId);
215
+ if (!engine) {
216
+ throw new Error(`Invalid engine ID: ${worldStatus.engineId}`);
217
+ }
218
+ return { world, engine };
219
+ },
220
+ });
221
+
222
+ export const gameDescriptions = query({
223
+ args: {
224
+ worldId: v.id('worlds'),
225
+ },
226
+ handler: async (ctx, args) => {
227
+ const playerDescriptions = await ctx.db
228
+ .query('playerDescriptions')
229
+ .withIndex('worldId', (q) => q.eq('worldId', args.worldId))
230
+ .collect();
231
+ const agentDescriptions = await ctx.db
232
+ .query('agentDescriptions')
233
+ .withIndex('worldId', (q) => q.eq('worldId', args.worldId))
234
+ .collect();
235
+ const worldMap = await ctx.db
236
+ .query('maps')
237
+ .withIndex('worldId', (q) => q.eq('worldId', args.worldId))
238
+ .first();
239
+ if (!worldMap) {
240
+ throw new Error(`No map for world: ${args.worldId}`);
241
+ }
242
+ return { worldMap, playerDescriptions, agentDescriptions };
243
+ },
244
+ });
245
+
246
+ export const previousConversation = query({
247
+ args: {
248
+ worldId: v.id('worlds'),
249
+ playerId,
250
+ },
251
+ handler: async (ctx, args) => {
252
+ // Walk the player's history in descending order, looking for a nonempty
253
+ // conversation.
254
+ const members = ctx.db
255
+ .query('participatedTogether')
256
+ .withIndex('playerHistory', (q) => q.eq('worldId', args.worldId).eq('player1', args.playerId))
257
+ .order('desc');
258
+
259
+ for await (const member of members) {
260
+ const conversation = await ctx.db
261
+ .query('archivedConversations')
262
+ .withIndex('worldId', (q) => q.eq('worldId', args.worldId).eq('id', member.conversationId))
263
+ .unique();
264
+ if (!conversation) {
265
+ throw new Error(`Invalid conversation ID: ${member.conversationId}`);
266
+ }
267
+ if (conversation.numMessages > 0) {
268
+ return conversation;
269
+ }
270
+ }
271
+ return null;
272
+ },
273
+ });