Merge remote-tracking branch 'misskey-original/develop' into develop

This commit is contained in:
mattyatea 2024-01-21 13:44:29 +09:00
commit 6390977653
29 changed files with 1057 additions and 560 deletions

View File

@ -38,6 +38,7 @@
- Enhance: 絵文字ピッカー・オートコンプリートで、完全一致した絵文字を優先的に表示するように
- Enhance: Playの説明欄にMFMを使えるように
- Enhance: チャンネルノートの場合は詳細ページからその前後のノートを見れるように
- Enhance: ノート作成画面のファイル添付メニューから直接ファイルを削除できるように
- Enhance: MFMの属性でオートコンプリートが使用できるように #12735
- Fix: ネイティブモードの絵文字がモノクロにならないように
- Fix: v2023.12.0で追加された「モデレーターがユーザーのアイコンもしくはバナー画像を未設定状態にできる機能」が管理画面上で正しく表示されていない問題を修正
@ -57,6 +58,9 @@
- Fix: ipv4とipv6の両方が利用可能な環境でallowedPrivateNetworksが設定されていた場合プライベートipの検証ができていなかった問題を修正
- Fix: properly handle cc followers
### Service Worker
- Enhance: オフライン表示のデザインを改善・多言語対応
## 2023.12.2
### General

View File

@ -24,6 +24,8 @@ COPY --link ["packages/backend/package.json", "./packages/backend/"]
COPY --link ["packages/frontend/package.json", "./packages/frontend/"]
COPY --link ["packages/sw/package.json", "./packages/sw/"]
COPY --link ["packages/misskey-js/package.json", "./packages/misskey-js/"]
COPY --link ["packages/misskey-reversi/package.json", "./packages/misskey-reversi/"]
COPY --link ["packages/misskey-bubble-game/package.json", "./packages/misskey-bubble-game/"]
RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \
pnpm i --frozen-lockfile --aggregate-output
@ -52,6 +54,8 @@ COPY --link ["pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "./"]
COPY --link ["scripts", "./scripts"]
COPY --link ["packages/backend/package.json", "./packages/backend/"]
COPY --link ["packages/misskey-js/package.json", "./packages/misskey-js/"]
COPY --link ["packages/misskey-reversi/package.json", "./packages/misskey-reversi/"]
COPY --link ["packages/misskey-bubble-game/package.json", "./packages/misskey-bubble-game/"]
RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \
pnpm i --frozen-lockfile --aggregate-output
@ -79,8 +83,12 @@ WORKDIR /misskey
COPY --chown=misskey:misskey --from=target-builder /misskey/node_modules ./node_modules
COPY --chown=misskey:misskey --from=target-builder /misskey/packages/backend/node_modules ./packages/backend/node_modules
COPY --chown=misskey:misskey --from=target-builder /misskey/packages/misskey-js/node_modules ./packages/misskey-js/node_modules
COPY --chown=misskey:misskey --from=target-builder /misskey/packages/misskey-reversi/node_modules ./packages/misskey-reversi/node_modules
COPY --chown=misskey:misskey --from=target-builder /misskey/packages/misskey-bubble-game/node_modules ./packages/misskey-bubble-game/node_modules
COPY --chown=misskey:misskey --from=native-builder /misskey/built ./built
COPY --chown=misskey:misskey --from=native-builder /misskey/packages/misskey-js/built ./packages/misskey-js/built
COPY --chown=misskey:misskey --from=native-builder /misskey/packages/misskey-reversi/built ./packages/misskey-reversi/built
COPY --chown=misskey:misskey --from=native-builder /misskey/packages/misskey-bubble-game/built ./packages/misskey-bubble-game/built
COPY --chown=misskey:misskey --from=native-builder /misskey/packages/backend/built ./packages/backend/built
COPY --chown=misskey:misskey --from=native-builder /misskey/fluent-emojis /misskey/fluent-emojis
COPY --chown=misskey:misskey . ./

26
locales/index.d.ts vendored
View File

@ -580,6 +580,10 @@ export interface Locale extends ILocale {
*
*/
"attachCancel": string;
/**
*
*/
"deleteFile": string;
/**
*
*/
@ -9777,6 +9781,10 @@ export interface Locale extends ILocale {
*
*/
"surrendered": string;
/**
*
*/
"timeout": string;
/**
*
*/
@ -9829,6 +9837,10 @@ export interface Locale extends ILocale {
*
*/
"canPutEverywhere": string;
/**
* 1
*/
"timeLimitForEachTurn": string;
/**
*
*/
@ -9837,6 +9849,20 @@ export interface Locale extends ILocale {
*
*/
"lookingForPlayer": string;
/**
*
*/
"gameCanceled": string;
};
"_offlineScreen": {
/**
* -
*/
"title": string;
/**
*
*/
"header": string;
};
}
declare const locales: {

View File

@ -141,6 +141,7 @@ overwriteFromPinnedEmojis: "全般設定から上書きする"
reactionSettingDescription2: "ドラッグして並び替え、クリックして削除、+を押して追加します。"
rememberNoteVisibility: "公開範囲を記憶する"
attachCancel: "添付取り消し"
deleteFile: "ファイルを削除"
markAsSensitive: "センシティブとして設定"
unmarkAsSensitive: "センシティブを解除する"
enterFileName: "ファイル名を入力"
@ -2603,6 +2604,7 @@ _reversi:
pastTurnOf: "{name}のターン"
surrender: "投了"
surrendered: "投了により"
timeout: "時間切れ"
drawn: "引き分け"
won: "{name}の勝ち"
black: "黒"
@ -2616,5 +2618,11 @@ _reversi:
isLlotheo: "石の少ない方が勝ち(ロセオ)"
loopedMap: "ループマップ"
canPutEverywhere: "どこでも置けるモード"
timeLimitForEachTurn: "1ターンの時間制限"
freeMatch: "フリーマッチ"
lookingForPlayer: "対戦相手を探しています"
gameCanceled: "対局がキャンセルされました"
_offlineScreen:
title: "オフライン - サーバーに接続できません"
header: "サーバーに接続できません"

View File

@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: syuilo and other misskey contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class Reversi31705793785675 {
name = 'Reversi31705793785675'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "reversi_game" RENAME COLUMN "surrendered" TO "surrenderedUserId"`);
await queryRunner.query(`ALTER TABLE "reversi_game" ADD "timeoutUserId" character varying(32)`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "reversi_game" DROP COLUMN "timeoutUserId"`);
await queryRunner.query(`ALTER TABLE "reversi_game" RENAME COLUMN "surrenderedUserId" TO "surrendered"`);
}
}

View File

@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: syuilo and other misskey contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class Reversi41705794768153 {
name = 'Reversi41705794768153'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "reversi_game" ADD "endedAt" TIMESTAMP WITH TIME ZONE`);
await queryRunner.query(`COMMENT ON COLUMN "reversi_game"."endedAt" IS 'The ended date of the ReversiGame.'`);
}
async down(queryRunner) {
await queryRunner.query(`COMMENT ON COLUMN "reversi_game"."endedAt" IS 'The ended date of the ReversiGame.'`);
await queryRunner.query(`ALTER TABLE "reversi_game" DROP COLUMN "endedAt"`);
}
}

View File

@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: syuilo and other misskey contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class Reversi51705798904141 {
name = 'Reversi51705798904141'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "reversi_game" ADD "timeLimitForEachTurn" smallint NOT NULL DEFAULT '90'`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "reversi_game" DROP COLUMN "timeLimitForEachTurn"`);
}
}

View File

@ -181,9 +181,6 @@ export interface ReversiGameEventTypes {
value: any;
};
log: Reversi.Serializer.Log & { id: string | null };
syncState: {
crc32: string;
};
started: {
game: Packed<'ReversiGameDetailed'>;
};
@ -191,6 +188,9 @@ export interface ReversiGameEventTypes {
winnerId: MiUser['id'] | null;
game: Packed<'ReversiGameDetailed'>;
};
canceled: {
userId: MiUser['id'];
};
}
//#endregion

View File

@ -25,6 +25,7 @@ import { GlobalEventService } from '@/core/GlobalEventService.js';
import { IdService } from '@/core/IdService.js';
import type { Packed } from '@/misc/json-schema.js';
import { NotificationService } from '@/core/NotificationService.js';
import { Serialized } from '@/types.js';
import { ReversiGameEntityService } from './entities/ReversiGameEntityService.js';
import type { OnApplicationShutdown, OnModuleInit } from '@nestjs/common';
@ -55,6 +56,16 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
this.notificationService = this.moduleRef.get(NotificationService.name);
}
@bindThis
private async cacheGame(game: MiReversiGame) {
await this.redisClient.setex(`reversi:game:cache:${game.id}`, 60 * 3, JSON.stringify(game));
}
@bindThis
private async deleteGameCache(gameId: MiReversiGame['id']) {
await this.redisClient.del(`reversi:game:cache:${gameId}`);
}
@bindThis
public async matchSpecificUser(me: MiUser, targetUser: MiUser): Promise<MiReversiGame | null> {
if (targetUser.id === me.id) {
@ -83,6 +94,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
bw: 'random',
isLlotheo: false,
}).then(x => this.reversiGamesRepository.findOneByOrFail(x.identifiers[0]));
this.cacheGame(game);
const packed = await this.reversiGameEntityService.packDetail(game, { id: targetUser.id });
this.globalEventService.publishReversiStream(targetUser.id, 'matched', { game: packed });
@ -125,6 +137,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
bw: 'random',
isLlotheo: false,
}).then(x => this.reversiGamesRepository.findOneByOrFail(x.identifiers[0]));
this.cacheGame(game);
const packed = await this.reversiGameEntityService.packDetail(game, { id: invitorId });
this.globalEventService.publishReversiStream(invitorId, 'matched', { game: packed });
@ -160,6 +173,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
bw: 'random',
isLlotheo: false,
}).then(x => this.reversiGamesRepository.findOneByOrFail(x.identifiers[0]));
this.cacheGame(game);
const packed = await this.reversiGameEntityService.packDetail(game, { id: matchedUserId });
this.globalEventService.publishReversiStream(matchedUserId, 'matched', { game: packed });
@ -182,33 +196,47 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
}
@bindThis
public async gameReady(game: MiReversiGame, user: MiUser, ready: boolean) {
public async gameReady(gameId: MiReversiGame['id'], user: MiUser, ready: boolean) {
const game = await this.get(gameId);
if (game == null) throw new Error('game not found');
if (game.isStarted) return;
let isBothReady = false;
if (game.user1Id === user.id) {
await this.reversiGamesRepository.update(game.id, {
user1Ready: ready,
});
const updatedGame = await this.reversiGamesRepository.createQueryBuilder().update()
.set({
user1Ready: ready,
})
.where('id = :id', { id: game.id })
.returning('*')
.execute()
.then((response) => response.raw[0]);
this.cacheGame(updatedGame);
this.globalEventService.publishReversiGameStream(game.id, 'changeReadyStates', {
user1: ready,
user2: game.user2Ready,
user2: updatedGame.user2Ready,
});
if (ready && game.user2Ready) isBothReady = true;
if (ready && updatedGame.user2Ready) isBothReady = true;
} else if (game.user2Id === user.id) {
await this.reversiGamesRepository.update(game.id, {
user2Ready: ready,
});
const updatedGame = await this.reversiGamesRepository.createQueryBuilder().update()
.set({
user2Ready: ready,
})
.where('id = :id', { id: game.id })
.returning('*')
.execute()
.then((response) => response.raw[0]);
this.cacheGame(updatedGame);
this.globalEventService.publishReversiGameStream(game.id, 'changeReadyStates', {
user1: game.user1Ready,
user1: updatedGame.user1Ready,
user2: ready,
});
if (ready && game.user1Ready) isBothReady = true;
if (ready && updatedGame.user1Ready) isBothReady = true;
} else {
return;
}
@ -216,71 +244,93 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
if (isBothReady) {
// 3秒後、両者readyならゲーム開始
setTimeout(async () => {
const freshGame = await this.reversiGamesRepository.findOneBy({ id: game.id });
const freshGame = await this.get(game.id);
if (freshGame == null || freshGame.isStarted || freshGame.isEnded) return;
if (!freshGame.user1Ready || !freshGame.user2Ready) return;
let bw: number;
if (freshGame.bw === 'random') {
bw = Math.random() > 0.5 ? 1 : 2;
} else {
bw = parseInt(freshGame.bw, 10);
}
function getRandomMap() {
const mapCount = Object.entries(Reversi.maps).length;
const rnd = Math.floor(Math.random() * mapCount);
return Object.values(Reversi.maps)[rnd].data;
}
const map = freshGame.map != null ? freshGame.map : getRandomMap();
const crc32 = CRC32.str(JSON.stringify(freshGame.logs)).toString();
await this.reversiGamesRepository.update(game.id, {
startedAt: new Date(),
isStarted: true,
black: bw,
map: map,
crc32,
});
//#region 盤面に最初から石がないなどして始まった瞬間に勝敗が決定する場合があるのでその処理
const o = new Reversi.Game(map, {
isLlotheo: freshGame.isLlotheo,
canPutEverywhere: freshGame.canPutEverywhere,
loopedBoard: freshGame.loopedBoard,
});
if (o.isEnded) {
let winner;
if (o.winner === true) {
winner = freshGame.black === 1 ? freshGame.user1Id : freshGame.user2Id;
} else if (o.winner === false) {
winner = freshGame.black === 1 ? freshGame.user2Id : freshGame.user1Id;
} else {
winner = null;
}
await this.reversiGamesRepository.update(game.id, {
isEnded: true,
winnerId: winner,
});
this.globalEventService.publishReversiGameStream(game.id, 'ended', {
winnerId: winner,
game: await this.reversiGameEntityService.packDetail(game.id, user),
});
}
//#endregion
this.globalEventService.publishReversiGameStream(game.id, 'started', {
game: await this.reversiGameEntityService.packDetail(game.id, user),
});
this.startGame(freshGame);
}, 3000);
}
}
@bindThis
private async startGame(game: MiReversiGame) {
let bw: number;
if (game.bw === 'random') {
bw = Math.random() > 0.5 ? 1 : 2;
} else {
bw = parseInt(game.bw, 10);
}
function getRandomMap() {
const mapCount = Object.entries(Reversi.maps).length;
const rnd = Math.floor(Math.random() * mapCount);
return Object.values(Reversi.maps)[rnd].data;
}
const map = game.map != null ? game.map : getRandomMap();
const crc32 = CRC32.str(JSON.stringify(game.logs)).toString();
const updatedGame = await this.reversiGamesRepository.createQueryBuilder().update()
.set({
startedAt: new Date(),
isStarted: true,
black: bw,
map: map,
crc32,
})
.where('id = :id', { id: game.id })
.returning('*')
.execute()
.then((response) => response.raw[0]);
this.cacheGame(updatedGame);
//#region 盤面に最初から石がないなどして始まった瞬間に勝敗が決定する場合があるのでその処理
const engine = new Reversi.Game(map, {
isLlotheo: game.isLlotheo,
canPutEverywhere: game.canPutEverywhere,
loopedBoard: game.loopedBoard,
});
if (engine.isEnded) {
let winner;
if (engine.winner === true) {
winner = bw === 1 ? game.user1Id : game.user2Id;
} else if (engine.winner === false) {
winner = bw === 1 ? game.user2Id : game.user1Id;
} else {
winner = null;
}
const updatedGame = await this.reversiGamesRepository.createQueryBuilder().update()
.set({
isEnded: true,
endedAt: new Date(),
winnerId: winner,
})
.where('id = :id', { id: game.id })
.returning('*')
.execute()
.then((response) => response.raw[0]);
this.cacheGame(updatedGame);
this.globalEventService.publishReversiGameStream(game.id, 'ended', {
winnerId: winner,
game: await this.reversiGameEntityService.packDetail(game.id),
});
return;
}
//#endregion
this.redisClient.setex(`reversi:game:turnTimer:${game.id}:1`, updatedGame.timeLimitForEachTurn, '');
this.globalEventService.publishReversiGameStream(game.id, 'started', {
game: await this.reversiGameEntityService.packDetail(game.id),
});
}
@bindThis
public async getInvitations(user: MiUser): Promise<MiUser['id'][]> {
const invitations = await this.redisClient.zrange(
@ -292,17 +342,27 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
}
@bindThis
public async updateSettings(game: MiReversiGame, user: MiUser, key: string, value: any) {
public async updateSettings(gameId: MiReversiGame['id'], user: MiUser, key: string, value: any) {
const game = await this.get(gameId);
if (game == null) throw new Error('game not found');
if (game.isStarted) return;
if ((game.user1Id !== user.id) && (game.user2Id !== user.id)) return;
if ((game.user1Id === user.id) && game.user1Ready) return;
if ((game.user2Id === user.id) && game.user2Ready) return;
if (!['map', 'bw', 'isLlotheo', 'canPutEverywhere', 'loopedBoard'].includes(key)) return;
if (!['map', 'bw', 'isLlotheo', 'canPutEverywhere', 'loopedBoard', 'timeLimitForEachTurn'].includes(key)) return;
await this.reversiGamesRepository.update(game.id, {
[key]: value,
});
// TODO: より厳格なバリデーション
const updatedGame = await this.reversiGamesRepository.createQueryBuilder().update()
.set({
[key]: value,
})
.where('id = :id', { id: game.id })
.returning('*')
.execute()
.then((response) => response.raw[0]);
this.cacheGame(updatedGame);
this.globalEventService.publishReversiGameStream(game.id, 'updateSettings', {
userId: user.id,
@ -312,7 +372,9 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
}
@bindThis
public async putStoneToGame(game: MiReversiGame, user: MiUser, pos: number, id?: string | null) {
public async putStoneToGame(gameId: MiReversiGame['id'], user: MiUser, pos: number, id?: string | null) {
const game = await this.get(gameId);
if (game == null) throw new Error('game not found');
if (!game.isStarted) return;
if (game.isEnded) return;
if ((game.user1Id !== user.id) && (game.user2Id !== user.id)) return;
@ -361,12 +423,18 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
const crc32 = CRC32.str(JSON.stringify(serializeLogs)).toString();
await this.reversiGamesRepository.update(game.id, {
crc32,
isEnded: engine.isEnded,
winnerId: winner,
logs: serializeLogs,
});
const updatedGame = await this.reversiGamesRepository.createQueryBuilder().update()
.set({
crc32,
isEnded: engine.isEnded,
winnerId: winner,
logs: serializeLogs,
})
.where('id = :id', { id: game.id })
.returning('*')
.execute()
.then((response) => response.raw[0]);
this.cacheGame(updatedGame);
this.globalEventService.publishReversiGameStream(game.id, 'log', {
...log,
@ -376,33 +444,127 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
if (engine.isEnded) {
this.globalEventService.publishReversiGameStream(game.id, 'ended', {
winnerId: winner ?? null,
game: await this.reversiGameEntityService.packDetail(game.id, user),
game: await this.reversiGameEntityService.packDetail(game.id),
});
} else {
this.redisClient.setex(`reversi:game:turnTimer:${game.id}:${engine.turn ? '1' : '0'}`, updatedGame.timeLimitForEachTurn, '');
}
}
@bindThis
public async surrender(game: MiReversiGame, user: MiUser) {
public async surrender(gameId: MiReversiGame['id'], user: MiUser) {
const game = await this.get(gameId);
if (game == null) throw new Error('game not found');
if (game.isEnded) return;
if ((game.user1Id !== user.id) && (game.user2Id !== user.id)) return;
const winnerId = game.user1Id === user.id ? game.user2Id : game.user1Id;
await this.reversiGamesRepository.update(game.id, {
surrendered: user.id,
isEnded: true,
winnerId: winnerId,
});
const updatedGame = await this.reversiGamesRepository.createQueryBuilder().update()
.set({
isEnded: true,
endedAt: new Date(),
winnerId: winnerId,
surrenderedUserId: user.id,
})
.where('id = :id', { id: game.id })
.returning('*')
.execute()
.then((response) => response.raw[0]);
this.cacheGame(updatedGame);
this.globalEventService.publishReversiGameStream(game.id, 'ended', {
winnerId: winnerId,
game: await this.reversiGameEntityService.packDetail(game.id, user),
game: await this.reversiGameEntityService.packDetail(game.id),
});
}
@bindThis
public async get(id: MiReversiGame['id']) {
return this.reversiGamesRepository.findOneBy({ id });
public async checkTimeout(gameId: MiReversiGame['id']) {
const game = await this.get(gameId);
if (game == null) throw new Error('game not found');
if (game.isEnded) return;
const engine = Reversi.Serializer.restoreGame({
map: game.map,
isLlotheo: game.isLlotheo,
canPutEverywhere: game.canPutEverywhere,
loopedBoard: game.loopedBoard,
logs: game.logs,
});
if (engine.turn == null) return;
const timer = await this.redisClient.exists(`reversi:game:turnTimer:${game.id}:${engine.turn ? '1' : '0'}`);
if (timer === 0) {
const winnerId = engine.turn ? (game.black === 1 ? game.user2Id : game.user1Id) : (game.black === 1 ? game.user1Id : game.user2Id);
const updatedGame = await this.reversiGamesRepository.createQueryBuilder().update()
.set({
isEnded: true,
endedAt: new Date(),
winnerId: winnerId,
timeoutUserId: engine.turn ? (game.black === 1 ? game.user1Id : game.user2Id) : (game.black === 1 ? game.user2Id : game.user1Id),
})
.where('id = :id', { id: game.id })
.returning('*')
.execute()
.then((response) => response.raw[0]);
this.cacheGame(updatedGame);
this.globalEventService.publishReversiGameStream(game.id, 'ended', {
winnerId: winnerId,
game: await this.reversiGameEntityService.packDetail(game.id),
});
}
}
@bindThis
public async cancelGame(gameId: MiReversiGame['id'], user: MiUser) {
const game = await this.get(gameId);
if (game == null) throw new Error('game not found');
if (game.isStarted) return;
if ((game.user1Id !== user.id) && (game.user2Id !== user.id)) return;
await this.reversiGamesRepository.delete(game.id);
this.deleteGameCache(game.id);
this.globalEventService.publishReversiGameStream(game.id, 'canceled', {
userId: user.id,
});
}
@bindThis
public async get(id: MiReversiGame['id']): Promise<MiReversiGame | null> {
const cached = await this.redisClient.get(`reversi:game:cache:${id}`);
if (cached != null) {
const parsed = JSON.parse(cached) as Serialized<MiReversiGame>;
return {
...parsed,
startedAt: parsed.startedAt != null ? new Date(parsed.startedAt) : null,
endedAt: parsed.endedAt != null ? new Date(parsed.endedAt) : null,
};
} else {
const game = await this.reversiGamesRepository.findOneBy({ id });
if (game == null) return null;
this.cacheGame(game);
return game;
}
}
@bindThis
public async checkCrc(gameId: MiReversiGame['id'], crc32: string | number) {
const game = await this.get(gameId);
if (game == null) throw new Error('game not found');
if (crc32.toString() !== game.crc32) {
return await this.reversiGameEntityService.packDetail(game);
} else {
return null;
}
}
@bindThis

View File

@ -37,6 +37,7 @@ export class ReversiGameEntityService {
id: game.id,
createdAt: this.idService.parse(game.id).date.toISOString(),
startedAt: game.startedAt && game.startedAt.toISOString(),
endedAt: game.endedAt && game.endedAt.toISOString(),
isStarted: game.isStarted,
isEnded: game.isEnded,
form1: game.form1,
@ -49,12 +50,14 @@ export class ReversiGameEntityService {
user2: this.userEntityService.pack(game.user2Id, me),
winnerId: game.winnerId,
winner: game.winnerId ? this.userEntityService.pack(game.winnerId, me) : null,
surrendered: game.surrendered,
surrenderedUserId: game.surrenderedUserId,
timeoutUserId: game.timeoutUserId,
black: game.black,
bw: game.bw,
isLlotheo: game.isLlotheo,
canPutEverywhere: game.canPutEverywhere,
loopedBoard: game.loopedBoard,
timeLimitForEachTurn: game.timeLimitForEachTurn,
logs: game.logs,
map: game.map,
});
@ -79,6 +82,7 @@ export class ReversiGameEntityService {
id: game.id,
createdAt: this.idService.parse(game.id).date.toISOString(),
startedAt: game.startedAt && game.startedAt.toISOString(),
endedAt: game.endedAt && game.endedAt.toISOString(),
isStarted: game.isStarted,
isEnded: game.isEnded,
form1: game.form1,
@ -91,12 +95,14 @@ export class ReversiGameEntityService {
user2: this.userEntityService.pack(game.user2Id, me),
winnerId: game.winnerId,
winner: game.winnerId ? this.userEntityService.pack(game.winnerId, me) : null,
surrendered: game.surrendered,
surrenderedUserId: game.surrenderedUserId,
timeoutUserId: game.timeoutUserId,
black: game.black,
bw: game.bw,
isLlotheo: game.isLlotheo,
canPutEverywhere: game.canPutEverywhere,
loopedBoard: game.loopedBoard,
timeLimitForEachTurn: game.timeLimitForEachTurn,
});
}

View File

@ -13,6 +13,12 @@ export class MiReversiGame {
})
public startedAt: Date | null;
@Column('timestamp with time zone', {
nullable: true,
comment: 'The ended date of the ReversiGame.',
})
public endedAt: Date | null;
@Column(id())
public user1Id: MiUser['id'];
@ -71,7 +77,19 @@ export class MiReversiGame {
...id(),
nullable: true,
})
public surrendered: MiUser['id'] | null;
public surrenderedUserId: MiUser['id'] | null;
@Column({
...id(),
nullable: true,
})
public timeoutUserId: MiUser['id'] | null;
// in sec
@Column('smallint', {
default: 90,
})
public timeLimitForEachTurn: number;
@Column('jsonb', {
default: [],

View File

@ -21,6 +21,11 @@ export const packedReversiGameLiteSchema = {
optional: false, nullable: true,
format: 'date-time',
},
endedAt: {
type: 'string',
optional: false, nullable: true,
format: 'date-time',
},
isStarted: {
type: 'boolean',
optional: false, nullable: false,
@ -75,7 +80,12 @@ export const packedReversiGameLiteSchema = {
optional: false, nullable: true,
ref: 'User',
},
surrendered: {
surrenderedUserId: {
type: 'string',
optional: false, nullable: true,
format: 'id',
},
timeoutUserId: {
type: 'string',
optional: false, nullable: true,
format: 'id',
@ -100,6 +110,10 @@ export const packedReversiGameLiteSchema = {
type: 'boolean',
optional: false, nullable: false,
},
timeLimitForEachTurn: {
type: 'number',
optional: false, nullable: false,
},
},
} as const;
@ -121,6 +135,11 @@ export const packedReversiGameDetailedSchema = {
optional: false, nullable: true,
format: 'date-time',
},
endedAt: {
type: 'string',
optional: false, nullable: true,
format: 'date-time',
},
isStarted: {
type: 'boolean',
optional: false, nullable: false,
@ -175,7 +194,12 @@ export const packedReversiGameDetailedSchema = {
optional: false, nullable: true,
ref: 'User',
},
surrendered: {
surrenderedUserId: {
type: 'string',
optional: false, nullable: true,
format: 'id',
},
timeoutUserId: {
type: 'string',
optional: false, nullable: true,
format: 'id',
@ -200,6 +224,10 @@ export const packedReversiGameDetailedSchema = {
type: 'boolean',
optional: false, nullable: false,
},
timeLimitForEachTurn: {
type: 'number',
optional: false, nullable: false,
},
logs: {
type: 'array',
optional: false, nullable: false,

View File

@ -62,7 +62,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.accessDenied);
}
await this.reversiService.surrender(game, me);
await this.reversiService.surrender(game.id, me);
});
}
}

View File

@ -32,11 +32,6 @@ class ReversiGameChannel extends Channel {
public async init(params: any) {
this.gameId = params.gameId as string;
const game = await this.reversiGamesRepository.findOneBy({
id: this.gameId,
});
if (game == null) return;
this.subscriber.on(`reversiGameStream:${this.gameId}`, this.send);
}
@ -45,8 +40,10 @@ class ReversiGameChannel extends Channel {
switch (type) {
case 'ready': this.ready(body); break;
case 'updateSettings': this.updateSettings(body.key, body.value); break;
case 'cancel': this.cancelGame(); break;
case 'putStone': this.putStone(body.pos, body.id); break;
case 'syncState': this.syncState(body.crc32); break;
case 'checkState': this.checkState(body.crc32); break;
case 'claimTimeIsUp': this.claimTimeIsUp(); break;
}
}
@ -54,47 +51,47 @@ class ReversiGameChannel extends Channel {
private async updateSettings(key: string, value: any) {
if (this.user == null) return;
// TODO: キャッシュしたい
const game = await this.reversiGamesRepository.findOneBy({ id: this.gameId! });
if (game == null) throw new Error('game not found');
this.reversiService.updateSettings(game, this.user, key, value);
this.reversiService.updateSettings(this.gameId!, this.user, key, value);
}
@bindThis
private async ready(ready: boolean) {
if (this.user == null) return;
const game = await this.reversiGamesRepository.findOneBy({ id: this.gameId! });
if (game == null) throw new Error('game not found');
this.reversiService.gameReady(this.gameId!, this.user, ready);
}
this.reversiService.gameReady(game, this.user, ready);
@bindThis
private async cancelGame() {
if (this.user == null) return;
this.reversiService.cancelGame(this.gameId!, this.user);
}
@bindThis
private async putStone(pos: number, id: string) {
if (this.user == null) return;
// TODO: キャッシュしたい
const game = await this.reversiGamesRepository.findOneBy({ id: this.gameId! });
if (game == null) throw new Error('game not found');
this.reversiService.putStoneToGame(game, this.user, pos, id);
this.reversiService.putStoneToGame(this.gameId!, this.user, pos, id);
}
@bindThis
private async syncState(crc32: string | number) {
// TODO: キャッシュしたい
const game = await this.reversiGamesRepository.findOneBy({ id: this.gameId! });
if (game == null) throw new Error('game not found');
private async checkState(crc32: string | number) {
if (crc32 != null) return;
if (!game.isStarted) return;
if (crc32.toString() !== game.crc32) {
this.send('rescue', await this.reversiGameEntityService.packDetail(game, this.user));
const game = await this.reversiService.checkCrc(this.gameId!, crc32);
if (game) {
this.send('rescue', game);
}
}
@bindThis
private async claimTimeIsUp() {
if (this.user == null) return;
this.reversiService.checkTimeout(this.gameId!);
}
@bindThis
public dispose() {
// Unsubscribe events

Binary file not shown.

View File

@ -56,6 +56,23 @@ function detachMedia(id: string) {
}
}
async function detachAndDeleteMedia(file: Misskey.entities.DriveFile) {
if (mock) return;
detachMedia(file.id);
const { canceled } = await os.confirm({
type: 'warning',
text: i18n.t('driveFileDeleteConfirm', { name: file.name }),
});
if (canceled) return;
os.apiWithDialog('drive/files/delete', {
fileId: file.id,
});
}
function toggleSensitive(file) {
if (mock) {
emit('changeSensitive', file, !file.isSensitive);
@ -138,6 +155,13 @@ function showFileMenu(file: Misskey.entities.DriveFile, ev: MouseEvent): void {
text: i18n.ts.attachCancel,
icon: 'ti ti-circle-x',
action: () => { detachMedia(file.id); },
}, {
type: 'divider',
}, {
text: i18n.ts.deleteFile,
icon: 'ti ti-trash',
danger: true,
action: () => { detachAndDeleteMedia(file); },
}], ev.currentTarget ?? ev.target).then(() => menuShowing = false);
menuShowing = true;
}

View File

@ -15,19 +15,20 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<div style="overflow: clip; line-height: 28px;">
<div v-if="!iAmPlayer && !game.isEnded && turnUser" class="turn">
<div v-if="!iAmPlayer && !game.isEnded && turnUser">
<Mfm :key="'turn:' + turnUser.id" :text="i18n.tsx._reversi.turnOf({ name: turnUser.name ?? turnUser.username })" :plain="true" :customEmojis="turnUser.emojis"/>
<MkEllipsis/>
</div>
<div v-if="(logPos !== game.logs.length) && turnUser" class="turn">
<div v-if="(logPos !== game.logs.length) && turnUser">
<Mfm :key="'past-turn-of:' + turnUser.id" :text="i18n.tsx._reversi.pastTurnOf({ name: turnUser.name ?? turnUser.username })" :plain="true" :customEmojis="turnUser.emojis"/>
</div>
<div v-if="iAmPlayer && !game.isEnded && !isMyTurn" class="turn1">{{ i18n.ts._reversi.opponentTurn }}<MkEllipsis/></div>
<div v-if="iAmPlayer && !game.isEnded && isMyTurn" class="turn2" style="animation: tada 1s linear infinite both;">{{ i18n.ts._reversi.myTurn }}</div>
<div v-if="game.isEnded && logPos == game.logs.length" class="result">
<div v-if="iAmPlayer && !game.isEnded && !isMyTurn">{{ i18n.ts._reversi.opponentTurn }}<MkEllipsis/><span style="margin-left: 1em; opacity: 0.7;">({{ i18n.tsx.remainingN({ n: opTurnTimerRmain }) }})</span></div>
<div v-if="iAmPlayer && !game.isEnded && isMyTurn"><span style="display: inline-block; font-weight: bold; animation: tada 1s linear infinite both;">{{ i18n.ts._reversi.myTurn }}</span><span style="margin-left: 1em; opacity: 0.7;">({{ i18n.tsx.remainingN({ n: myTurnTimerRmain }) }})</span></div>
<div v-if="game.isEnded && logPos == game.logs.length">
<template v-if="game.winner">
<Mfm :key="'won'" :text="i18n.tsx._reversi.won({ name: game.winner.name ?? game.winner.username })" :plain="true" :customEmojis="game.winner.emojis"/>
<span v-if="game.surrendered != null"> ({{ i18n.ts._reversi.surrendered }})</span>
<span v-if="game.surrenderedUserId != null"> ({{ i18n.ts._reversi.surrendered }})</span>
<span v-if="game.timeoutUserId != null"> ({{ i18n.ts._reversi.timeout }})</span>
</template>
<template v-else>{{ i18n.ts._reversi.drawn }}</template>
</div>
@ -44,6 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div :class="$style.boardCells" :style="cellsStyle">
<div
v-for="(stone, i) in engine.board"
:key="i"
v-tooltip="`${String.fromCharCode(65 + engine.posToXy(i)[0])}${engine.posToXy(i)[1] + 1}`"
:class="[$style.boardCell, {
[$style.boardCell_empty]: stone == null,
@ -55,14 +57,22 @@ SPDX-License-Identifier: AGPL-3.0-only
}]"
@click="putStone(i)"
>
<template v-if="useAvatarAsStone">
<img v-if="stone === true" :class="$style.boardCellStone" :src="blackUser.avatarUrl"/>
<img v-if="stone === false" :class="$style.boardCellStone" :src="whiteUser.avatarUrl"/>
</template>
<template v-else>
<img v-if="stone === true" :class="$style.boardCellStone" src="/client-assets/reversi/stone_b.png"/>
<img v-if="stone === false" :class="$style.boardCellStone" src="/client-assets/reversi/stone_w.png"/>
</template>
<Transition
:enterActiveClass="$style.transition_flip_enterActive"
:leaveActiveClass="$style.transition_flip_leaveActive"
:enterFromClass="$style.transition_flip_enterFrom"
:leaveToClass="$style.transition_flip_leaveTo"
mode="default"
>
<template v-if="useAvatarAsStone">
<img v-if="stone === true" :class="$style.boardCellStone" :src="blackUser.avatarUrl"/>
<img v-else-if="stone === false" :class="$style.boardCellStone" :src="whiteUser.avatarUrl"/>
</template>
<template v-else>
<img v-if="stone === true" :class="$style.boardCellStone" src="/client-assets/reversi/stone_b.png"/>
<img v-else-if="stone === false" :class="$style.boardCellStone" src="/client-assets/reversi/stone_w.png"/>
</template>
</Transition>
</div>
</div>
<div v-if="showBoardLabels" :class="$style.labelsY">
@ -74,6 +84,17 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
</div>
<div v-if="game.isEnded" class="_panel _gaps_s" style="padding: 16px;">
<div>{{ logPos }} / {{ game.logs.length }}</div>
<div v-if="!autoplaying" class="_buttonsCenter">
<MkButton :disabled="logPos === 0" @click="logPos = 0"><i class="ti ti-chevrons-left"></i></MkButton>
<MkButton :disabled="logPos === 0" @click="logPos--"><i class="ti ti-chevron-left"></i></MkButton>
<MkButton :disabled="logPos === game.logs.length" @click="logPos++"><i class="ti ti-chevron-right"></i></MkButton>
<MkButton :disabled="logPos === game.logs.length" @click="logPos = game.logs.length"><i class="ti ti-chevrons-right"></i></MkButton>
</div>
<MkButton style="margin: auto;" :disabled="autoplaying" @click="autoplay()"><i class="ti ti-player-play"></i></MkButton>
</div>
<div class="_panel" style="padding: 16px;">
<div>
<b>{{ i18n.tsx._reversi.turnCount({ count: logPos }) }}</b> {{ i18n.ts._reversi.black }}:{{ engine.blackCount }} {{ i18n.ts._reversi.white }}:{{ engine.whiteCount }} {{ i18n.ts._reversi.total }}:{{ engine.blackCount + engine.whiteCount }}
@ -111,17 +132,6 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkButton @click="share">{{ i18n.ts.share }}</MkButton>
</div>
<div v-if="game.isEnded" class="_panel _gaps_s" style="padding: 16px;">
<div>{{ logPos }} / {{ game.logs.length }}</div>
<div v-if="!autoplaying" class="_buttonsCenter">
<MkButton :disabled="logPos === 0" @click="logPos = 0"><i class="ti ti-chevrons-left"></i></MkButton>
<MkButton :disabled="logPos === 0" @click="logPos--"><i class="ti ti-chevron-left"></i></MkButton>
<MkButton :disabled="logPos === game.logs.length" @click="logPos++"><i class="ti ti-chevron-right"></i></MkButton>
<MkButton :disabled="logPos === game.logs.length" @click="logPos = game.logs.length"><i class="ti ti-chevrons-right"></i></MkButton>
</div>
<MkButton style="margin: auto;" :disabled="autoplaying" @click="autoplay()"><i class="ti ti-player-play"></i></MkButton>
</div>
<MkA v-if="game.isEnded" :to="`/reversi`">
<img src="/client-assets/reversi/logo.png" style="display: block; max-width: 100%; width: 200px; margin: auto;"/>
</MkA>
@ -130,7 +140,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
import { computed, onMounted, onUnmounted, ref, shallowRef, triggerRef, watch } from 'vue';
import { computed, onActivated, onDeactivated, onMounted, onUnmounted, ref, shallowRef, triggerRef, watch } from 'vue';
import * as CRC32 from 'crc-32';
import * as Misskey from 'misskey-js';
import * as Reversi from 'misskey-reversi';
@ -230,7 +240,7 @@ if (game.value.isStarted && !game.value.isEnded) {
if (game.value.isEnded) return;
const crc32 = CRC32.str(JSON.stringify(game.value.logs)).toString();
if (_DEV_) console.log('crc32', crc32);
props.connection.send('syncState', {
props.connection.send('checkState', {
crc32: crc32,
});
}, 10000, { immediate: false, afterMounted: true });
@ -260,9 +270,31 @@ function putStone(pos) {
});
appliedOps.push(id);
myTurnTimerRmain.value = game.value.timeLimitForEachTurn;
opTurnTimerRmain.value = game.value.timeLimitForEachTurn;
checkEnd();
}
const myTurnTimerRmain = ref<number>(game.value.timeLimitForEachTurn);
const opTurnTimerRmain = ref<number>(game.value.timeLimitForEachTurn);
const TIMER_INTERVAL_SEC = 3;
useInterval(() => {
if (myTurnTimerRmain.value > 0) {
myTurnTimerRmain.value = Math.max(0, myTurnTimerRmain.value - TIMER_INTERVAL_SEC);
}
if (opTurnTimerRmain.value > 0) {
opTurnTimerRmain.value = Math.max(0, opTurnTimerRmain.value - TIMER_INTERVAL_SEC);
}
if (iAmPlayer.value) {
if ((isMyTurn.value && myTurnTimerRmain.value === 0) || (!isMyTurn.value && opTurnTimerRmain.value === 0)) {
props.connection.send('claimTimeIsUp', {});
}
}
}, TIMER_INTERVAL_SEC * 1000, { immediate: false, afterMounted: true });
function onStreamLog(log: Reversi.Serializer.Log & { id: string | null }) {
game.value.logs = Reversi.Serializer.serializeLogs([
...Reversi.Serializer.deserializeLogs(game.value.logs),
@ -277,6 +309,9 @@ function onStreamLog(log: Reversi.Serializer.Log & { id: string | null }) {
engine.value.putStone(log.pos);
triggerRef(engine);
myTurnTimerRmain.value = game.value.timeLimitForEachTurn;
opTurnTimerRmain.value = game.value.timeLimitForEachTurn;
sound.playUrl('/client-assets/reversi/put.mp3', {
volume: 1,
playbackRate: 1,
@ -385,6 +420,18 @@ onMounted(() => {
props.connection.on('ended', onStreamEnded);
});
onActivated(() => {
props.connection.on('log', onStreamLog);
props.connection.on('rescue', onStreamRescue);
props.connection.on('ended', onStreamEnded);
});
onDeactivated(() => {
props.connection.off('log', onStreamLog);
props.connection.off('rescue', onStreamRescue);
props.connection.off('ended', onStreamEnded);
});
onUnmounted(() => {
props.connection.off('log', onStreamLog);
props.connection.off('rescue', onStreamRescue);
@ -395,6 +442,20 @@ onUnmounted(() => {
<style lang="scss" module>
@use "sass:math";
.transition_flip_enterActive,
.transition_flip_leaveActive {
backface-visibility: hidden;
transition: opacity 0.5s ease, transform 0.5s ease;
}
.transition_flip_enterFrom {
transform: rotateY(-180deg);
opacity: 0;
}
.transition_flip_leaveTo {
transform: rotateY(180deg);
opacity: 0;
}
$label-size: 16px;
$gap: 4px;
@ -460,9 +521,11 @@ $gap: 4px;
.boardCell {
background: transparent;
border-radius: 6px;
overflow: clip;
border-radius: 100%;
aspect-ratio: 1;
transform-style: preserve-3d;
perspective: 150px;
transition: border 0.25s ease, opacity 0.25s ease;
&.boardCell_empty {
border: solid 2px var(--divider);
@ -501,10 +564,14 @@ $gap: 4px;
}
.boardCellStone {
position: absolute;
top: 0;
left: 0;
pointer-events: none;
user-select: none;
display: block;
width: 100%;
height: 100%;
border-radius: 100%;
}
</style>

View File

@ -49,6 +49,22 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkRadios>
</MkFolder>
<MkFolder :defaultOpen="true">
<template #label>{{ i18n.ts._reversi.timeLimitForEachTurn }}</template>
<template #suffix>{{ game.timeLimitForEachTurn }}{{ i18n.ts._time.second }}</template>
<MkRadios v-model="game.timeLimitForEachTurn">
<option :value="5">5{{ i18n.ts._time.second }}</option>
<option :value="10">10{{ i18n.ts._time.second }}</option>
<option :value="30">30{{ i18n.ts._time.second }}</option>
<option :value="60">60{{ i18n.ts._time.second }}</option>
<option :value="90">90{{ i18n.ts._time.second }}</option>
<option :value="120">120{{ i18n.ts._time.second }}</option>
<option :value="180">180{{ i18n.ts._time.second }}</option>
<option :value="3600">3600{{ i18n.ts._time.second }}</option>
</MkRadios>
</MkFolder>
<MkFolder :defaultOpen="true">
<template #label>{{ i18n.ts._reversi.rules }}</template>
@ -70,7 +86,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template v-if="!isReady && !isOpReady">{{ i18n.ts._reversi.waitingBoth }}<MkEllipsis/></template>
</div>
<div class="_buttonsCenter">
<MkButton rounded danger @click="exit">{{ i18n.ts.cancel }}</MkButton>
<MkButton rounded danger @click="cancel">{{ i18n.ts.cancel }}</MkButton>
<MkButton v-if="!isReady" rounded primary @click="ready">{{ i18n.ts._reversi.ready }}</MkButton>
<MkButton v-if="isReady" rounded @click="unready">{{ i18n.ts._reversi.cancelReady }}</MkButton>
</div>
@ -93,9 +109,12 @@ import MkSwitch from '@/components/MkSwitch.vue';
import MkFolder from '@/components/MkFolder.vue';
import * as os from '@/os.js';
import { MenuItem } from '@/types/menu.js';
import { useRouter } from '@/global/router/supplier.js';
const $i = signinRequired();
const router = useRouter();
const mapCategories = Array.from(new Set(Object.values(Reversi.maps).map(x => x.category)));
const props = defineProps<{
@ -125,6 +144,10 @@ watch(() => game.value.bw, () => {
updateSettings('bw');
});
watch(() => game.value.timeLimitForEachTurn, () => {
updateSettings('timeLimitForEachTurn');
});
function chooseMap(ev: MouseEvent) {
const menu: MenuItem[] = [];
@ -151,8 +174,16 @@ function chooseMap(ev: MouseEvent) {
os.popupMenu(menu, ev.currentTarget ?? ev.target);
}
function exit() {
props.connection.send('exit', {});
async function cancel() {
const { canceled } = await os.confirm({
type: 'warning',
text: i18n.ts.areYouSure,
});
if (canceled) return;
props.connection.send('cancel', {});
router.push('/reversi');
}
function ready() {

View File

@ -17,6 +17,14 @@ import GameBoard from './game.board.vue';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { useStream } from '@/stream.js';
import { signinRequired } from '@/account.js';
import { useRouter } from '@/global/router/supplier.js';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
const $i = signinRequired();
const router = useRouter();
const props = defineProps<{
gameId: string;
@ -45,6 +53,17 @@ async function fetchGame() {
connection.value.on('started', x => {
game.value = x.game;
});
connection.value.on('canceled', x => {
connection.value?.dispose();
if (x.userId !== $i.id) {
os.alert({
type: 'warning',
text: i18n.ts._reversi.gameCanceled,
});
router.push('/reversi');
}
});
}
onMounted(() => {

View File

@ -10,11 +10,12 @@ SPDX-License-Identifier: AGPL-3.0-only
<img src="/client-assets/reversi/logo.png" style="display: block; max-width: 100%; max-height: 200px; margin: auto;"/>
</div>
<div class="_panel" style="padding: 16px;">
<div class="_panel _gaps" style="padding: 16px;">
<div class="_buttonsCenter">
<MkButton primary gradate rounded @click="matchAny">{{ i18n.ts._reversi.freeMatch }}</MkButton>
<MkButton primary gradate rounded @click="matchUser">{{ i18n.ts.invite }}</MkButton>
</div>
<div style="font-size: 90%; opacity: 0.7; text-align: center;"><i class="ti ti-music"></i> {{ i18n.ts.soundWillBePlayed }}</div>
</div>
<MkFolder v-if="invitations.length > 0" :defaultOpen="true">
@ -88,7 +89,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
import { computed, onMounted, onUnmounted, ref } from 'vue';
import { computed, onDeactivated, onMounted, onUnmounted, ref } from 'vue';
import * as Misskey from 'misskey-js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
@ -101,6 +102,7 @@ import MkPagination from '@/components/MkPagination.vue';
import { useRouter } from '@/global/router/supplier.js';
import * as os from '@/os.js';
import { useInterval } from '@/scripts/use-interval.js';
import * as sound from '@/scripts/sound.js';
const myGamesPagination = {
endpoint: 'reversi/games' as const,
@ -141,6 +143,12 @@ const matchingAny = ref<boolean>(false);
function startGame(game: Misskey.entities.ReversiGameDetailed) {
matchingUser.value = null;
matchingAny.value = false;
sound.playUrl('/client-assets/reversi/matched.mp3', {
volume: 1,
playbackRate: 1,
});
router.push(`/reversi/g/${game.id}`);
}
@ -206,6 +214,14 @@ onMounted(() => {
});
});
onDeactivated(() => {
cancelMatching();
});
onUnmounted(() => {
cancelMatching();
});
definePageMetadata(computed(() => ({
title: 'Reversi',
icon: 'ti ti-device-gamepad',

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { onMounted, onUnmounted } from 'vue';
import { onActivated, onDeactivated, onMounted, onUnmounted } from 'vue';
export function useInterval(fn: () => void, interval: number, options: {
immediate: boolean;
@ -28,6 +28,16 @@ export function useInterval(fn: () => void, interval: number, options: {
intervalId = null;
};
onActivated(() => {
if (intervalId) return;
if (options.immediate) fn();
intervalId = window.setInterval(fn, interval);
});
onDeactivated(() => {
clear();
});
onUnmounted(() => {
clear();
});

View File

@ -61,7 +61,7 @@
"😔":["悲しげな顔","がっかり","顔","悲しい"],
"😕":["困った顔","困った","こまった","顔"],
"🙁":["ご機嫌斜め","顔","しかめっ面","しかめっつら","悲しい","不幸"],
"☹":["しかめっつら","顔","しかめっ面","悲しい","不幸"],
"☹":["しかめっつら","顔","しかめっ面","悲しい","不幸"],
"😬":["しかめっ面","顔","しかめっつら"],
"🥺":["訴えかける顔","顔","物乞い","慈悲","子犬の目"],
"😣":["我慢している顔","顔","がんばる","頑張る"],
@ -111,7 +111,7 @@
"💩":["うんち","マンガ","漫画","フン","顔","モンスター"],
"👻":["お化け","妖怪","顔","おとぎ話","ファンタジー","幽霊","モンスター","ハロウィーン"],
"💀":["ドクロ","体","死","顔","おとぎ話","モンスター","骸骨","ハロウィーン"],
"☠":["ドクロマーク","体","交差した骨","死","顔","モンスター","骸骨","ハロウィーン"],
"☠":["ドクロマーク","体","交差した骨","死","顔","モンスター","骸骨","ハロウィーン"],
"👽":["宇宙人","怪獣","異星人","顔","おとぎ話","ファンタジー","モンスター","宇宙","UFO"],
"🤖":["ロボットの顔","顔","モンスター","ロボット"],
"🎃":["ジャック・オ・ランタン","イベント","お祝い","エンタメ","ハロウィン","ジャックオランタン","ランタン","かぼちゃ"],
@ -138,7 +138,7 @@
"🤛":["左向きのこぶし","体","拳","左向き"],
"🤜":["右向きのこぶし","体","拳","右向き"],
"🤞":["交差させた指","体","交差","指","手","幸運"],
"✌":["Vサイン","体","手","V","ブイ","勝つ","勝利","ピース"],
"✌":["Vサイン","体","手","V","ブイ","勝つ","勝利","ピース"],
"🫰":["人差し指と親指を交差した手","高い","ハート","愛","お金","スナップ"],
"🤘":["コルナ","体","指","手","角","最高"],
"🤟":["愛してるのジェスチャー","体","愛してる","好き","手"],
@ -151,10 +151,10 @@
"👉":["指差し","手の甲","体","指","手","人差し指","指さす"],
"👆":["指差し","手の甲","体","指","手","人差し指","指さす","上"],
"👇":["指差し","手の甲","体","下","指","手","人差し指","指さす"],
"☝":["指差し","体","指","手","人差し指","指さす","上"],
"☝":["指差し","体","指","手","人差し指","指さす","上"],
"✋":["挙手","体","手"],
"🤚":["手の甲","体","挙げる"],
"🖐":["広げた手のひら","体","指","手","広げる"],
"🖐":["広げた手のひら","体","指","手","広げる"],
"🖖":["長寿と繁栄を","体","指","手","スポック","バルカン"],
"👋":["バイバイ","体","手","振る","やっほー","ヤッホー","こんにちは"],
"🤙":["電話の形の手","体","電話","手"],
@ -166,7 +166,7 @@
"🦾":["メカニカルアーム","アクセシビリティ","義手","人口装具","体"],
"🖕":["中指を立てた手","体","指","手","中指"],
"🫵":["見ている人を指している人差し指","指す","あなた","指"],
"✍":["書いている手","体","手","書く"],
"✍":["書いている手","体","手","書く"],
"🤳":["自撮り","カメラ","携帯","腕"],
"💅":["マニキュア","体","ケア","化粧品","コスメ","爪","ネイル"],
"🦵":["脚","体","キック","手足"],
@ -179,7 +179,7 @@
"👂":["耳","体","鼻"],
"🦻":["補聴器を付けている耳","アクセシビリティ","補聴器","聞く","体","耳"],
"👃":["鼻","体"],
"👁":["目","体"],
"👁":["目","体"],
"👀":["目","体","顔"],
"🧠":["脳","体","臓器","知的","賢い"],
"🫀":["解剖学的な心臓","解剖学","心臓学","心臓","臓器","脈"],
@ -187,7 +187,7 @@
"🦴":["骨","体","骨格"],
"👤":["上半身のシルエット","上半身","シルエット"],
"👥":["上半身のシルエット","上半身","シルエット"],
"🗣":["喋る頭のシルエット","顔","頭","シルエット","しゃべる","話す"],
"🗣":["喋る頭のシルエット","顔","頭","シルエット","しゃべる","話す"],
"🫂":["ハグしている人たち","さようなら","こんにちは","ハグ","ありがとう"],
"👶":["赤ちゃん"],
"👧":["女の子","少女","処女","おとめ座","星座","子供"],
@ -281,7 +281,7 @@
"💂‍♂️":["男性警備員","警備員","警備","男","おとこ","男性"],
"🥷":["忍者","戦士","隠された","ステルス"],
"🕵️‍♀️":["女性の探偵","探偵","刑事","スパイ","女性","女","おんな"],
"🕵":["探偵","刑事","スパイ"],
"🕵":["探偵","刑事","スパイ"],
"🕵️‍♂️":["男性の探偵","探偵","刑事","スパイ","男","おとこ","男性"],
"🤶":["ミセス・クロース","イベント","お祝い","クリスマス","母","サンタ","クロース","女性","女","おんな"],
"🧑‍🎄":["ミクスクロース","アクティビティ","お祝い","クリスマス","サンタ","クロース"],
@ -300,7 +300,7 @@
"🩵":["ライトブルーのハート","シアン","ハート","ライトブルー","コガモ"],
"🩶":["グレーのハート","グレー","ハート","シルバー","スレート"],
"🕴️‍♀️":["宙に浮いたスーツの女性","ビジネス","スーツ","女性","女","おんな"],
"🕴":["宙に浮いたスーツの人","ビジネス","スーツ"],
"🕴":["宙に浮いたスーツの人","ビジネス","スーツ"],
"🕴️‍♂️":["宙に浮いたスーツの男性","ビジネス","スーツ","男","おとこ","男性"],
"🦸‍♀️":["女性のスーパーヒーロー","空想","善","ヒロイン","超大国","女性","女","おんな"],
"🦸":["スーパーヒーロー","空想","善","ヒーロー","ヒロイン","超大国"],
@ -468,7 +468,7 @@
"🎩":["シルクハット","アクティビティ","服","エンターテインメント","娯楽","帽子","トップス"],
"🎓":["卒業式の角帽","アクティビティ","帽子","お祝い","服","卒業","ハット"],
"👑":["冠","服","王冠","王","女王"],
"⛑":["白十字のヘルメット","救助","十字","顔","帽子","ヘルメット"],
"⛑":["白十字のヘルメット","救助","十字","顔","帽子","ヘルメット"],
"🪖":["軍隊のヘルメット","軍","ヘルメット","軍隊","軍人","兵士"],
"🎒":["ランドセル","アクティビティ","鞄","バッグ","学生鞄","学校"],
"👝":["ポーチ","鞄","バッグ","服"],
@ -476,13 +476,13 @@
"👜":["ハンドバッグ","鞄","バッグ","服"],
"💼":["ブリーフケース"],
"👓":["眼鏡","服","目","メガネ","アイウェア"],
"🕶":["サングラス","暗い","目","眼鏡","メガネ"],
"🕶":["サングラス","暗い","目","眼鏡","メガネ"],
"🥽":["ゴーグル","服","目の保護","水泳","溶接"],
"🧣":["スカーフ","服","首"],
"🧤":["手袋","服","手"],
"💍":["指輪","ダイヤモンド","恋愛","ロマンス"],
"🌂":["閉じた傘","服","雨","傘","天気"],
"☂":["傘","服","雨","天気"],
"☂":["傘","服","雨","天気"],
"🐶":["イヌの顔","犬","イヌ","顔","ペット"],
"🐱":["ネコの顔","猫","ネコ","顔","ペット"],
"🐭":["ネズミの顔","顔","ネズミ"],
@ -536,8 +536,8 @@
"🐜":["アリ","蟻","昆虫"],
"🦗":["クリケット","コオロギ","バッタ目","昆虫"],
"🪳":["ゴキブリ","昆虫","害虫"],
"🕷":["クモ","昆虫","蜘蛛"],
"🕸":["クモの巣","クモ","巣"],
"🕷":["クモ","昆虫","蜘蛛"],
"🕸":["クモの巣","クモ","巣"],
"🦂":["サソリ","さそり座","さそり","星座"],
"🦟":["蚊","病気","熱","昆虫","マラリア","ウイルス"],
"🪰":["ハエ","害虫","昆虫","蛆虫"],
@ -584,7 +584,7 @@
"🦇":["コウモリ","吸血鬼"],
"🐓":["おんどり"],
"🦃":["七面鳥(鳥)","七面鳥","鳥"],
"🕊":["平和の鳩","鳥","鳩","飛行","平和"],
"🕊":["平和の鳩","鳥","鳩","飛行","平和"],
"🦅":["ワシ","鳥"],
"🦆":["アヒル","鳥"],
"🪿":["ガチョウ","鳥","家禽","警笛の音"],
@ -605,7 +605,7 @@
"🐇":["ウサギ","バニー","ペット"],
"🐀":["ネズミ"],
"🐁":["ネズミ"],
"🐿":["シマリス"],
"🐿":["シマリス"],
"🦨":["スカンク","悪臭","臭う"],
"🦡":["アナグマ","ラーテル","ねだる"],
"🦔":["ハリネズミ","顔"],
@ -622,7 +622,7 @@
"🪴":["鉢植え","植物","観葉植物"],
"🌱":["苗木","植物","若い"],
"🌿":["ハーブ","葉","植物"],
"☘":["クローバー","植物"],
"☘":["クローバー","植物"],
"🍀":["四つ葉のクローバー","4","クローバー","四","葉","植物"],
"🎍":["門松","アクティビティ","竹","お祝い","日本","松","植物"],
"🎋":["七夕","アクティビティ","旗","お祝い","エンターテイメント","日本","木"],
@ -661,35 +661,35 @@
"🌝":["顔つき満月","明るい","顔","満ちた","月","宇宙","天気"],
"🌛":["顔つき上弦の月","顔","月","弦","宇宙","天気"],
"🌜":["顔がある下弦の月","顔","月","弦","宇宙","天気"],
"⭐":["中くらいの星","星"],
"⭐":["中くらいの星","星"],
"🌟":["光る星","きらめき","赤い光","輝く","輝き","星"],
"💫":["くらくら","漫画","めまい","星"],
"✨":["キラキラ","エンターテイメント","輝き","星"],
"☄":["彗星","宇宙"],
"☄":["彗星","宇宙"],
"🪐":["環のある惑星","宇宙","惑星","土星"],
"🌞":["顔つき太陽","明るい","顔","宇宙","太陽","天気"],
"☀️":["太陽の光","明るい","光線","宇宙","太陽","晴天","天気"],
"🌤":["太陽と小さな雲","雲","太陽","天気"],
"⛅":["晴れ時々曇り","雲","太陽","天気"],
"🌥":["晴れのち曇り","雲","太陽","天気"],
"🌦":["晴れのち曇り時々雨","雲","雨","太陽","天気"],
"🌤":["太陽と小さな雲","雲","太陽","天気"],
"⛅":["晴れ時々曇り","雲","太陽","天気"],
"🌥":["晴れのち曇り","雲","太陽","天気"],
"🌦":["晴れのち曇り時々雨","雲","雨","太陽","天気"],
"☁️":["雲","天気"],
"🌧":["雨雲","雲","雨","天気"],
"⛈":["雷雨","雲","雨","雷","天気"],
"🌩":["雷雲","雲","雷","天気"],
"⚡":["高電圧記号","危険","電気","雷","電圧","ビリビリ"],
"🌧":["雨雲","雲","雨","天気"],
"⛈":["雷雨","雲","雨","雷","天気"],
"🌩":["雷雲","雲","雷","天気"],
"⚡":["高電圧記号","危険","電気","雷","電圧","ビリビリ"],
"🔥":["炎","火","道具"],
"💥":["衝突マーク","どかーん","衝突","漫画"],
"❄️":["雪の結晶","冷たい","雪","天気"],
"🌨":["雪雲","雲","冷","雪","天気"],
"☃":["雪だるま","冷","雪","天気"],
"⛄":["雪だるま","冷","雪","天気"],
"🌬":["風が吹いている","風が吹く","雲","顔","天気","風"],
"🌨":["雪雲","雲","冷","雪","天気"],
"☃":["雪だるま","冷","雪","天気"],
"⛄":["雪だるま","冷","雪","天気"],
"🌬":["風が吹いている","風が吹く","雲","顔","天気","風"],
"💨":["ダッシュ","漫画","走る"],
"🌪":["竜巻雲","雲","竜巻","天気","旋風"],
"🌫":["霧","雲","天気"],
"🌪":["竜巻雲","雲","竜巻","天気","旋風"],
"🌫":["霧","雲","天気"],
"🌈":["虹","雨","レインボー","天気","プライド","lgbt"],
"☔":["雨と傘","衣類","しずく","雨","傘","天気"],
"☔":["雨と傘","衣類","しずく","雨","傘","天気"],
"💧":["雫","ぞっとする","漫画","したたり","汗","天気"],
"💦":["汗マーク","漫画","濡れている","汗"],
"🌊":["波","海","水","天気"],
@ -714,7 +714,7 @@
"🥑":["アボカド","フルーツ","果物"],
"🫒":["オリーブ","フルーツ"],
"🍆":["ナス","茄子","植物","野菜"],
"🌶":["トウガラシ","辛い","コショウ","植物"],
"🌶":["トウガラシ","辛い","コショウ","植物"],
"🫑":["ピーマン","唐辛子","コショウ","植物","野菜"],
"🥒":["キュウリ","ピクルス","野菜"],
"🥬":["葉っぱの緑","チンゲン菜","キャベツ","ケール","レタス"],
@ -793,7 +793,7 @@
"🍪":["クッキー","デザート","甘い"],
"🥠":["おみくじ入りクッキー","フォーチュンクッキー"],
"🥮":["月餅","秋","祭"],
"☕":["ホットドリンク","飲料","コーヒー","飲み物","温かい","蒸気","お茶"],
"☕":["ホットドリンク","飲料","コーヒー","飲み物","温かい","蒸気","お茶"],
"🍵":["湯のみ","飲料","カップ","飲み物","お茶","湯飲み"],
"🫖":["ティーポット","ドリンク","ポット","ティー","ケトル"],
"🥣":["ボウルとスプーン","朝食","シリアル","お粥","オートミール","ポリッジ","食器"],
@ -816,13 +816,13 @@
"🧊":["角氷","氷","立方体","冷たい","氷山"],
"🥄":["スプーン","食器"],
"🍴":["フォークとナイフ","調理","フォーク","ナイフ","食器"],
"🍽":["フォークとナイフとプレート","調理","フォーク","ナイフ","プレート","食器"],
"🍽":["フォークとナイフとプレート","調理","フォーク","ナイフ","プレート","食器"],
"🥢":["箸","はし"],
"🥡":["テイクアウトボックス","テイクアウト","容器","お持ち帰り"],
"⚽":["サッカーボール","ボール","サッカー"],
"⚽":["サッカーボール","ボール","サッカー"],
"🏀":["バスケットボール","ボール","バスケットリング"],
"🏈":["アメリカンフットボール","アメリカン","ボール","フットボール"],
"⚾":["野球","ボール"],
"⚾":["野球","ボール"],
"🥎":["ソフトボール","ボール","試合","スポーツ"],
"🎾":["テニスボール","ボール","ラケット","テニス"],
"🏐":["バレーボール","ボール","試合"],
@ -838,19 +838,19 @@
"🏏":["クリケットのバットとボール","ボール","フィールド","クリケット","試合"],
"🥍":["ラクロス","ボール","スティック","試合","スポーツ"],
"🥌":["カーリングストーン","カーリング","ストーン"],
"⛳":["ゴルフのカップ","ピンフラッグ","ゴルフ","ホール"],
"⛳":["ゴルフのカップ","ピンフラッグ","ゴルフ","ホール"],
"🏹":["弓矢","射手","矢","弓","射手座","道具","星座"],
"🎣":["釣竿と魚","エンターテイメント","魚","棒"],
"🤿":["ダイビングマスク","ダイビング","スキューバ","シュノーケル"],
"🥊":["ボクシンググローブ","ボクシング","グローブ"],
"🥋":["道着","柔道","空手","武道","テコンドー","ユニフォーム"],
"⛸":["アイススケート","氷"],
"⛸":["アイススケート","氷"],
"🎿":["スキーとスキーブーツ","スキー","雪"],
"🛷":["そり","ソリ","ルージュ","トボガン"],
"⛷":["スキー","雪"],
"⛷":["スキー","雪"],
"🏂":["スノーボーダー","スキー","雪","スノーボード"],
"🏋️‍♀️":["ウエイトを持ち上げる女性","挙げ","重量","女性","女","おんな"],
"🏋":["ウエイトを持ち上げる人","挙げ","重量"],
"🏋":["ウエイトを持ち上げる人","挙げ","重量"],
"🏋️‍♂️":["ウエイトを持ち上げる男性","挙げ","重量","男","おとこ","男性"],
"🤺":["フェンシングをする人","剣士","剣術","剣"],
"🤼‍♀️":["レスリングをする女性","レスリング","レスリング選手","女性","女","おんな"],
@ -860,7 +860,7 @@
"🤸":["側転をする人","側方転回","体操"],
"🤸‍♂️":["側転をする男性","側方転回","体操","男","おとこ","男性"],
"⛹️‍♀️":["ボールをバウンドさせる女性","ボール","女性","女","おんな"],
"⛹":["ボールをバウンドさせる人","ボール"],
"⛹":["ボールをバウンドさせる人","ボール"],
"⛹️‍♂️":["ボールをバウンドさせる男性","ボール","男","おとこ","男性"],
"🤾‍♀️":["ハンドボールをする女性","ボール","ハンドボール","女性","女","おんな"],
"🤾":["ハンドボールをする人","ボール","ハンドボール"],
@ -869,7 +869,7 @@
"🧗":["クライミングしている人","クライミング","ロック"],
"🧗‍♂️":["クライミングしている男性","クライミング","ロック","男性","男","おとこ"],
"🏌️‍♀️":["ゴルフをする女性","ボール","ゴルフ","ゴルファー","ゴルフする","女性","女","おんな"],
"🏌":["ゴルフをする人","ボール","ゴルフ","ゴルファー","ゴルフする"],
"🏌":["ゴルフをする人","ボール","ゴルフ","ゴルファー","ゴルフする"],
"🏌️‍♂️":["ゴルフをする男性","ボール","ゴルフ","ゴルファー","ゴルフする","男","おとこ","男性"],
"🧘‍♀️":["蓮華座の女性","瞑想","ヨガ","静穏","女性","女","おんな"],
"🧘":["蓮華座の人","瞑想","ヨガ","静穏"],
@ -897,16 +897,16 @@
"🚵":["マウンテンバイクに乗る人","マウンテンバイクライダー","クロスバイク","自転車","自転車乗り","自転車に乗る人","山"],
"🚵‍♂️":["マウンテンバイクに乗る男性","マウンテンバイクライダー","クロスバイク","自転車","自転車乗り","自転車に乗る人","サイクリスト","山","男","おとこ","男性"],
"🎽":["ランニングシャツと襷","ランニング","襷","シャツ"],
"🎖":["勲章","お祝い","メダル","軍事"],
"🎖":["勲章","お祝い","メダル","軍事"],
"🏅":["スポーツのメダル","メダル"],
"🥇":["金メダル","1位","金","メダル","1","第1位"],
"🥈":["銀メダル","メダル","2位","銀","2","第2位"],
"🥉":["銅メダル","銅","メダル","3位","3","第3位"],
"🏆":["トロフィー","賞"],
"🏵":["バラ飾り","植物"],
"🎗":["リマインダーリボン","お祝い","リマインダー","リボン"],
"🏵":["バラ飾り","植物"],
"🎗":["リマインダーリボン","お祝い","リマインダー","リボン"],
"🎫":["きっぷ","アクティビティ","入場料","エンターテイメント","チケット"],
"🎟":["入場券","入場料","エンターテイメント","チケット"],
"🎟":["入場券","入場料","エンターテイメント","チケット"],
"🎪":["サーカス小屋","アクティビティ","サーカス","エンターテイメント","テント"],
"🤹‍♀️":["ジャグリングをする女性","天秤","ジャグリング","女性","女","おんな"],
"🤹":["ジャグリングをする人","バランス","ジャグリング"],
@ -945,7 +945,7 @@
"🛺":["オートリキシャ","人力車","トゥクトゥク"],
"🚌":["バス","乗り物"],
"🚎":["トロリーバス","バス","路面電車","市街電車","乗り物"],
"🏎":["レーシングカー","車","競争"],
"🏎":["レーシングカー","車","競争"],
"🚓":["パトカー","車","パトロール","警察","乗り物"],
"🚑":["救急車","乗り物"],
"🚒":["消防車","エンジン","炎","トラック","乗り物"],
@ -954,7 +954,7 @@
"🚚":["配達用トラック","配達","トラック","乗り物"],
"🚛":["トレーラー","大型トラック","セミ","トラック","乗り物"],
"🚜":["トラクター","乗り物"],
"🏍":["レースバイク","オートバイ","レース"],
"🏍":["レースバイク","オートバイ","レース"],
"🛵":["スクーター","モーター"],
"🚲":["自転車","バイク","乗り物"],
"🦼":["電動車いす","アクセシビリティ","車いす"],
@ -984,25 +984,25 @@
"🚊":["路面電車","トロリーバス","乗り物"],
"🚉":["駅","線路","電車","乗り物"],
"🚁":["ヘリコプター","乗り物"],
"🛩":["小型航空機","飛行機","乗り物"],
"🛩":["小型航空機","飛行機","乗り物"],
"✈️":["飛行機","乗り物"],
"🛫":["飛行機の離陸","飛行機","チェックイン","出発","乗り物"],
"🛬":["飛行機の着陸","飛行機","到着","着陸","乗り物"],
"🪂":["パラシュート","パラセール","スカイダイブ","ハンググライダー"],
"💺":["座席","椅子"],
"🛰":["サテライト","衛星","宇宙","乗り物"],
"🛰":["サテライト","衛星","宇宙","乗り物"],
"🚀":["ロケット","宇宙","乗り物"],
"🛸":["空飛ぶ円盤","UFO","宇宙人","異星人","宇宙","空想"],
"🛶":["カヌー","ボート"],
"⛵":["ヨット","ボート","リゾート","海","乗り物"],
"🛥":["モーターボート","ボート","乗り物"],
"⛵":["ヨット","ボート","リゾート","海","乗り物"],
"🛥":["モーターボート","ボート","乗り物"],
"🚤":["スピードボート","ボート","乗り物"],
"⛴":["フェリー","ボート"],
"🛳":["旅客船","旅客","船","乗り物"],
"⛴":["フェリー","ボート"],
"🛳":["旅客船","旅客","船","乗り物"],
"🚢":["船","乗り物"],
"🛟":["救命浮き輪","浮き輪","ライフジャケット","ライフセーバー","救助","安全"],
"⚓":["いかり","船","ツール"],
"⛽":["ガソリンスタンド","燃料","ガソリン","給油機","サービスステーション"],
"⚓":["いかり","船","ツール"],
"⛽":["ガソリンスタンド","燃料","ガソリン","給油機","サービスステーション"],
"🚧":["工事中","工事用フェンス","建設工事"],
"🚏":["バス停","バス","停止"],
"🚦":["縦向きの信号機","信号機","信号","交通"],
@ -1011,30 +1011,30 @@
"🎡":["観覧車","アクティビティ","遊園地","エンターテイメント","フェリス"],
"🎢":["ジェットコースター","アクティビティ","遊園地","コースター","エンターテイメント","ローラー"],
"🎠":["メリーゴーランド","アクティビティ","メリーゴーラウンド","エンターテイメント","馬"],
"🏗":["建設中","建物","建設"],
"🏗":["建設中","建物","建設"],
"🌁":["霧","天気"],
"🗼":["東京タワー","東京","タワー"],
"🏭":["工場","建物"],
"⛲":["噴水"],
"⛲":["噴水"],
"🎑":["お月見","アクティビティ","お祝い","授賞式","エンターテイメント","月"],
"⛰":["山"],
"🏔":["雪山","寒い","山","雪"],
"⛰":["山"],
"🏔":["雪山","寒い","山","雪"],
"🗻":["富士山","山"],
"🌋":["火山","噴火","山","気象"],
"🗾":["日本列島","日本","地図"],
"🏕":["キャンプ"],
"⛺":["テント","キャンプ"],
"🏞":["国立公園","公園"],
"🛣":["高速道路","ハイウェイ","道路"],
"🛤":["線路","鉄道","電車"],
"🏕":["キャンプ"],
"⛺":["テント","キャンプ"],
"🏞":["国立公園","公園"],
"🛣":["高速道路","ハイウェイ","道路"],
"🛤":["線路","鉄道","電車"],
"🌅":["日の出","朝","太陽","天候"],
"🌄":["山からの日の出","朝","山","太陽","日の出","天候"],
"🏜":["砂漠"],
"🏖":["ビーチと傘","ビーチ","傘","パラソル"],
"🏝":["無人島","砂漠","島"],
"🏜":["砂漠"],
"🏖":["ビーチと傘","ビーチ","傘","パラソル"],
"🏝":["無人島","砂漠","島"],
"🌇":["ビルに沈む夕陽","建物","夕暮れ","太陽","夕日","天気"],
"🌆":["夕暮れの街並み","建物","街","夕暮れ","日暮れ","風景","太陽","夕日","天気"],
"🏙":["街並み","建物","街"],
"🏙":["街並み","建物","街"],
"🌃":["星空","夜","星","天気"],
"🌉":["夜の橋","橋","夜","天気"],
"🌌":["天の川","宇宙","天気"],
@ -1042,14 +1042,14 @@
"🎇":["線香花火","アクティビティ","お祝い","エンターテイメント","花火","キラキラ"],
"🎆":["花火","アクティビティ","お祝い","エンターテイメント"],
"🛖":["小屋","家","扇形庫","パオ"],
"🏘":["家","建物"],
"🏘":["家","建物"],
"🏰":["西洋の城","建物","城","ヨーロッパ"],
"🏯":["日本の城","建物","城","日本"],
"🏟":["スタジアム"],
"🏟":["スタジアム"],
"🗽":["自由の女神","自由","像"],
"🏠":["家","建物","自宅"],
"🏡":["庭付きの家","建物","庭","自宅","家"],
"🏚":["廃墟","建物","廃屋","家"],
"🏚":["廃墟","建物","廃屋","家"],
"🏢":["オフィスビル","建物"],
"🏬":["デパート","建物","店"],
"🏣":["日本の郵便局","建物","日本","ポスト"],
@ -1061,24 +1061,24 @@
"🏫":["学校","建物"],
"🏩":["ラブホテル","建物","ホテル","ラブ"],
"💒":["結婚式","アクティビティ","チャペル","ロマンス"],
"🏛":["歴史的な建物","建物","歴史的な"],
"⛪":["教会","建物","クリスチャン","十字架","宗教"],
"🏛":["歴史的な建物","建物","歴史的な"],
"⛪":["教会","建物","クリスチャン","十字架","宗教"],
"🕌":["モスク","イスラム","ムスリム","宗教"],
"🛕":["ヒンドゥー教寺院","ヒンドゥー教","寺院","宗教"],
"🕍":["シナゴーグ","ユダヤ人","ユダヤ教","宗教","会堂"],
"🕋":["カアバ","イスラム","ムスリム","宗教"],
"⛩":["神社","宗教","神道"],
"⌚":["腕時計","時計"],
"⛩":["神社","宗教","神道"],
"⌚":["腕時計","時計"],
"📱":["携帯電話","携帯","コミュニケーション","モバイル","電話"],
"📲":["着信中","矢印","通話","携帯","コミュニケーション","モバイル","携帯電話","受信","電話"],
"💻":["パソコン","ノートパソコン","コンピューター","パーソナル"],
"⌨":["キーボード","コンピューター"],
"🖥":["デスクトップパソコン","コンピューター","デスクトップ"],
"🖨":["プリンター","コンピューター"],
"🖱":["3ボタンマウス","3","ボタン","コンピューター","マウス","三"],
"🖲":["トラックボール","コンピューター"],
"🕹":["ジョイスティック","エンターテイメント","ゲーム","ビデオゲーム"],
"🗜":["圧縮","ツール","欠陥"],
"⌨":["キーボード","コンピューター"],
"🖥":["デスクトップパソコン","コンピューター","デスクトップ"],
"🖨":["プリンター","コンピューター"],
"🖱":["3ボタンマウス","3","ボタン","コンピューター","マウス","三"],
"🖲":["トラックボール","コンピューター"],
"🕹":["ジョイスティック","エンターテイメント","ゲーム","ビデオゲーム"],
"🗜":["圧縮","ツール","欠陥"],
"💽":["MD","パソコン","光ディスク","エンターテイメント","ミニディスク","光学"],
"💾":["フロッピーディスク","コンピューター","ディスク","フロッピー"],
"💿":["CDディスク","ブルーレイ","CD","コンピューター","ディスク","DVD","光学"],
@ -1088,23 +1088,23 @@
"📸":["フラッシュを焚いたカメラ","カメラ","フラッシュ","ビデオ"],
"📹":["ビデオカメラ","カメラ","エンターテイメント","ビデオ"],
"🎥":["ビデオカメラ","アクティビティ","カメラ","シネマ","エンターテイメント","映画"],
"📽":["映写機","シネマ","娯楽","フィルム","映画","プロジェクター","ビデオ"],
"🎞":["フィルムのフレーム","シネマ","エンターテイメント","フィルム","フレーム","映画"],
"📽":["映写機","シネマ","娯楽","フィルム","映画","プロジェクター","ビデオ"],
"🎞":["フィルムのフレーム","シネマ","エンターテイメント","フィルム","フレーム","映画"],
"📞":["受話器","コミュニケーション","電話","受信機"],
"☎️":["電話","携帯電話"],
"📟":["ポケットベル","コミュニケーション","ポケベル"],
"📠":["FAX","コミュニケーション; fAX"],
"📺":["テレビ","エンターテイメント","TV","ビデオ"],
"📻":["ラジオ","エンターテイメント","ビデオ"],
"🎙":["スタジオマイク","マイク","音楽","スタジオ"],
"🎚":["調節バー","調節","音楽","バー"],
"🎛":["コントロールノブ","コントロール","つまみ","音楽"],
"⏱":["ストップウォッチ","時計"],
"⏲":["タイマー時計","時計","タイマー"],
"🎙":["スタジオマイク","マイク","音楽","スタジオ"],
"🎚":["調節バー","調節","音楽","バー"],
"🎛":["コントロールノブ","コントロール","つまみ","音楽"],
"⏱":["ストップウォッチ","時計"],
"⏲":["タイマー時計","時計","タイマー"],
"⏰":["目覚まし時計","アラーム","時計"],
"🕰":["置き時計","時計"],
"🕰":["置き時計","時計"],
"⏳":["砂時計","砂","タイマー"],
"⌛":["砂時計","砂","タイマー"],
"⌛":["砂時計","砂","タイマー"],
"🧮":["そろばん","計算","カウント","集計表","数学"],
"📡":["衛星アンテナ","アンテナ","コミュニケーション","パラボラアンテナ","衛星"],
"🔋":["電池","バッテリー","電子","高エネルギー"],
@ -1112,10 +1112,10 @@
"🔌":["コンセント","電気","プラグ"],
"💡":["電球","漫画","電気","ひらめき","光"],
"🔦":["懐中電灯","電気","光","道具","たいまつ"],
"🕯":["ろうそく","光"],
"🕯":["ろうそく","光"],
"🧯":["消火器","消火","火","消す"],
"🗑":["ごみ箱","ゴミ箱","ごみ","ゴミ","缶","ビン"],
"🛢":["ドラム缶","ドラム","オイル"],
"🗑":["ごみ箱","ゴミ箱","ごみ","ゴミ","缶","ビン"],
"🛢":["ドラム缶","ドラム","オイル"],
"🛒":["ショッピングカート","カート","ショッピング","トロリー"],
"💸":["羽の生えたお札","銀行","紙幣","請求書","ドル","飛ぶ","お金","羽"],
"💵":["ドル札","銀行","紙幣","お札","通貨","ドル","お金"],
@ -1128,20 +1128,20 @@
"🪪":["身分証明書","資格情報","ID","ライセンス","セキュリティ"],
"🧾":["領収書","会計","簿記","証拠","証明"],
"💎":["宝石","ダイアモンド","ジュエル","ロマンス"],
"⚖":["はかり","天秤","公正","てんびん座","物差し","道具","重量","星座"],
"⚖":["はかり","天秤","公正","てんびん座","物差し","道具","重量","星座"],
"🦯":["白杖","アクセシビリティ","目が不自由"],
"🧰":["道具箱","胸","整備士","工具"],
"🔧":["レンチ","道具"],
"🪛":["ドライバー","ねじ","工具"],
"🔨":["ハンマー","道具"],
"⚒":["ハンマーとつるはし","ハンマー","つるはし","道具"],
"🛠":["ハンマーとレンチ","ハンマー","道具","レンチ"],
"⛏":["つるはし","採掘","道具"],
"⚒":["ハンマーとつるはし","ハンマー","つるはし","道具"],
"🛠":["ハンマーとレンチ","ハンマー","道具","レンチ"],
"⛏":["つるはし","採掘","道具"],
"🪓":["斧","たたき切り","手斧","割る","木材","工具"],
"🪚":["木工用のこぎり","大工","材木","のこぎり","工具"],
"🔩":["ナットとボルト","ボルト","ナット","道具"],
"⚙":["歯車","ギア","道具"],
"⛓":["鎖"],
"⚙":["歯車","ギア","道具"],
"⛓":["鎖"],
"🪝":["フック","わな","いかさま","ペテン","誘惑","フィッシング","ツール"],
"🪜":["はしご","登る","横木","段","工具"],
"🧱":["れんが","粘土","建設","モルタル","壁"],
@ -1151,13 +1151,13 @@
"🧨":["爆竹","ダイナマイト","火薬","花火"],
"💣":["爆弾"],
"🔪":["包丁","キッチンナイフ","調理","ナイフ"],
"🗡":["短剣","ナイフ"],
"⚔":["交差した剣","交差","剣"],
"🛡":["盾"],
"🗡":["短剣","ナイフ"],
"⚔":["交差した剣","交差","剣"],
"🛡":["盾"],
"🚬":["喫煙マーク","アクティビティ","喫煙"],
"⚰":["棺","死"],
"⚰":["棺","死"],
"🪦":["墓石","墓地","死","墓","墓場","ハロウィーン"],
"⚱":["骨壷","死","葬儀"],
"⚱":["骨壷","死","葬儀"],
"🏺":["アンフォラ","みずがめ座","料理","飲み物","水差し","道具","星座"],
"🔮":["水晶玉","玉","水晶","おとぎ話","ファンタジー","占い","道具"],
"🪄":["魔法の杖","魔法","棒","魔女","魔法使い"],
@ -1166,22 +1166,22 @@
"🪬":["ハムサ","お守り","ファティマ","手","メアリー","ミリアム","保護"],
"💈":["理髪店の看板柱","理髪店","床屋","散髪","看板柱"],
"🧲":["磁石","アトラクション","馬蹄"],
"⚗":["蒸留器","化学","実験","道具"],
"⚗":["蒸留器","化学","実験","道具"],
"🧪":["試験管","化学者","化学","実験","実験室","科学"],
"🧫":["ペトリ皿","バクテリア","生物学者","生物学","文化","実験室"],
"🧬":["DNA","生物学者","進化","遺伝子","遺伝子学","生命"],
"🔭":["望遠鏡","ツール"],
"🔬":["顕微鏡","ツール"],
"🕳":["穴"],
"🕳":["穴"],
"🩻":["X線","骨","医師","医療","骨格"],
"💊":["薬","医師","ピル","病気"],
"💉":["注射器","医師","薬","注射針","注射","病気","道具","ワクチン"],
"🩸":["血1滴","医師","薬","血液","生理"],
"🩹":["ガーゼ付きばんそうこう","医師","薬","バンドエイド","包帯","ばんそうこう"],
"🩺":["聴診器","医師","薬","心臓"],
"🌡":["温度計","天気","温度"],
"🌡":["温度計","天気","温度"],
"🩼":["松葉杖","杖","障碍","怪我","移動補助","棒"],
"🏷":["ラベル","荷札"],
"🏷":["ラベル","荷札"],
"🔖":["ブックマーク","しおり","印"],
"🚽":["トイレ"],
"🪠":["プランジャー","フォースカップ","配管工","吸引","トイレ"],
@ -1200,24 +1200,24 @@
"🧺":["バスケット","農業","ランドリー","ピクニック"],
"🪣":["バケツ","たる","手桶","大だる"],
"🔑":["鍵","錠","パスワード"],
"🗝":["古い鍵","かぎ","鍵","錠","古い"],
"🗝":["古い鍵","かぎ","鍵","錠","古い"],
"🪤":["ネズミ捕り器","餌","ネズミ","齧歯動物","輪なわ","わな"],
"🛋":["ソファーとランプ","ソファー","ホテル","ランプ"],
"🛋":["ソファーとランプ","ソファー","ホテル","ランプ"],
"🪑":["椅子","座席","座る"],
"🛌":["宿泊施設","寝る","ホテル","睡眠","ベッド"],
"🛏":["ベッド","ホテル","睡眠"],
"🛏":["ベッド","ホテル","睡眠"],
"🚪":["ドア","扉"],
"🪞":["鏡","反射","反射体","反射鏡"],
"🪟":["窓","枠","新鮮な空気","ガラス","開口部","透明","視界"],
"🧳":["手荷物","パッキング","旅行","スーツケース"],
"🛎":["卓上ベル","ベル","ホテル"],
"🖼":["額に入った写真","アート","額縁","美術館","絵画","写真"],
"🛎":["卓上ベル","ベル","ホテル"],
"🖼":["額に入った写真","アート","額縁","美術館","絵画","写真"],
"🧭":["コンパス","磁石","ナビゲーション","オリエンテーリング"],
"🗺":["世界地図","地図","世界"],
"⛱":["立てられたパラソル","雨","晴れ","傘","天気"],
"🗺":["世界地図","地図","世界"],
"⛱":["立てられたパラソル","雨","晴れ","傘","天気"],
"🪭":["折り畳み扇子","冷却","遠慮がち","ダンス","ファン","フラッター","熱","熱い","内気","広がる"],
"🗿":["モヤイ像","モアイ像","顔","像"],
"🛍":["買い物袋","鞄","ホテル","買い物"],
"🛍":["買い物袋","鞄","ホテル","買い物"],
"🎈":["風船","アクティビティ","お祝い","エンターテイメント"],
"🎏":["こいのぼり","アクティビティ","鯉","お祝い","エンターテイメント","旗","吹流し"],
"🎀":["リボン","お祝い"],
@ -1255,17 +1255,17 @@
"📄":["文書","ページ"],
"📅":["カレンダー","日付"],
"📆":["日めくりカレンダー","カレンダー"],
"🗓":["リングカレンダー","カレンダー","パッド","らせん状"],
"🗓":["リングカレンダー","カレンダー","パッド","らせん状"],
"📇":["名刺フォルダ","カード","索引","ローラデックス"],
"🗃":["カードファイル","箱","カード","ファイル"],
"🗳":["投票用紙と投票箱","投票用紙","箱","票","投票"],
"🗄":["ファイル収納庫","収納","ファイル"],
"🗃":["カードファイル","箱","カード","ファイル"],
"🗳":["投票用紙と投票箱","投票用紙","箱","票","投票"],
"🗄":["ファイル収納庫","収納","ファイル"],
"📋":["クリップボード"],
"🗒":["リングノート","ノート","パッド","らせん状"],
"🗒":["リングノート","ノート","パッド","らせん状"],
"📁":["フォルダ","ファイル"],
"📂":["開いたフォルダ","ファイル","フォルダ","開いた"],
"🗂":["仕切りカード","カード","仕切り","索引"],
"🗞":["丸めた新聞","ニュース","新聞","紙","丸めた"],
"🗂":["仕切りカード","カード","仕切り","索引"],
"🗞":["丸めた新聞","ニュース","新聞","紙","丸めた"],
"📰":["新聞","コミュニケーション","ニュース","紙"],
"🪧":["プラカード","デモ","柵","抗議","看板"],
"📓":["ノート"],
@ -1279,7 +1279,7 @@
"📖":["開いた本","本","開いた"],
"🔗":["リンク"],
"📎":["クリップ","ペーパークリップ"],
"🖇":["繋がったペーパークリップ","コミュニケーション","リンク","ペーパークリップ"],
"🖇":["繋がったペーパークリップ","コミュニケーション","リンク","ペーパークリップ"],
"✂️":["ハサミ","はさみ","道具"],
"📐":["三角定規","定規","配置","三角"],
"📏":["定規","直定規"],
@ -1294,13 +1294,13 @@
"🔒":["鍵","閉じられた","施錠"],
"🔓":["解錠","施錠","開ける"],
"🔏":["錠前とペン","インク","錠","ペン先","ペン","プライバシー"],
"🖊":["左下向きのボールペン","ボールペン","コミュニケーション","ペン"],
"🖋":["左下向きの万年筆","コミュニケーション","万年筆","ペン"],
"🖊":["左下向きのボールペン","ボールペン","コミュニケーション","ペン"],
"🖋":["左下向きの万年筆","コミュニケーション","万年筆","ペン"],
"✒️":["ペン先","ペン"],
"📝":["メモ","コミュニケーション","鉛筆"],
"✏️":["鉛筆"],
"🖍":["左下向きのクレヨン","コミュニケーション","クレヨン"],
"🖌":["左下向きのブラシ","コミュニケーション","ペイントブラシ","絵"],
"🖍":["左下向きのクレヨン","コミュニケーション","クレヨン"],
"🖌":["左下向きのブラシ","コミュニケーション","ペイントブラシ","絵"],
"🔍":["左向き虫眼鏡","眼鏡","拡大","検索","ツール"],
"🔎":["右向き虫眼鏡","眼鏡","拡大","検索","ツール"],
"❤️":["赤色のハート","ハート"],
@ -1313,7 +1313,7 @@
"🖤":["黒いハート","ハート","黒","悪","悪者"],
"🤍":["白のハート","ハート","白"],
"💔":["割れたハート","ハート","壊れる","破局"],
"❣":["ハートのビックリマーク","ハート","ビックリマーク","記号"],
"❣":["ハートのビックリマーク","ハート","ビックリマーク","記号"],
"💕":["2つのハート","ハート","愛"],
"💞":["回転するハート","ハート","回転"],
"💓":["鼓動するハート","ハート","鼓動","ドキドキ"],
@ -1324,40 +1324,40 @@
"❤️‍🔥":["燃えているハート","ハート","火","燃える","愛","熱情","神聖なハート"],
"❤️‍🩹":["手当しているハート","ハート","健康になる","改善している","手当している","回復している","病み上がり","元気"],
"💟":["ハートのデコレーション","ハート"],
"☮":["ピースマーク","平和"],
"✝":["ラテン十字","クリスチャン","十字架","宗教"],
"☪":["星と三日月","イスラム","ムスリム","宗教"],
"🕉":["オームマーク","ヒンドゥー教","オーム","宗教"],
"☸":["法輪","仏教徒","ダーマ","宗教"],
"✡":["ダビデの星","ダビデ","ユダヤ人","ユダヤ教","宗教","星"],
"☮":["ピースマーク","平和"],
"✝":["ラテン十字","クリスチャン","十字架","宗教"],
"☪":["星と三日月","イスラム","ムスリム","宗教"],
"🕉":["オームマーク","ヒンドゥー教","オーム","宗教"],
"☸":["法輪","仏教徒","ダーマ","宗教"],
"✡":["ダビデの星","ダビデ","ユダヤ人","ユダヤ教","宗教","星"],
"🔯":["六芒星","占い","星"],
"🕎":["ハヌッキーヤー","燭台","メノーラー","宗教"],
"☯":["陰陽","宗教","道","道家","陽","陰"],
"☦":["八端十字架","クリスチャン","十字架","宗教"],
"☯":["陰陽","宗教","道","道家","陽","陰"],
"☦":["八端十字架","クリスチャン","十字架","宗教"],
"🪯":["カンダ","宗教","シーク教徒"],
"🛐":["礼拝所","宗教","礼拝"],
"⛎":["へびつかい座","運搬人","蛇","ヘビ","星座"],
"♈":["おひつじ座","仔羊","星座"],
"♉":["おうし座","牡牛","雄牛","星座"],
"♊":["ふたご座","ふたご","星座"],
"♋":["ガン","かに座","カニ","蟹","星座"],
"♌":["しし座","ライオン","星座"],
"♍":["おとめ座","乙女","処女","星座"],
"♎":["てんびん座","天秤","公正","はかり","星座"],
"♏":["さそり座","さそり","サソリ","星座"],
"♐":["いて座","射手","射手座","星座"],
"♑":["やぎ座","ヤギ","星座"],
"♒":["みずがめ座","運搬人","水","星座"],
"♓":["うお座","魚","星座"],
"♈":["おひつじ座","仔羊","星座"],
"♉":["おうし座","牡牛","雄牛","星座"],
"♊":["ふたご座","ふたご","星座"],
"♋":["ガン","かに座","カニ","蟹","星座"],
"♌":["しし座","ライオン","星座"],
"♍":["おとめ座","乙女","処女","星座"],
"♎":["てんびん座","天秤","公正","はかり","星座"],
"♏":["さそり座","さそり","サソリ","星座"],
"♐":["いて座","射手","射手座","星座"],
"♑":["やぎ座","ヤギ","星座"],
"♒":["みずがめ座","運搬人","水","星座"],
"♓":["うお座","魚","星座"],
"🆔":["四角囲みID","ID","識別"],
"⚛":["元素記号","無神論者","原子"],
"⚛":["元素記号","無神論者","原子"],
"⚕️":["アスクレピオスの杖","健康","世話","医師","薬","杖","ヘビ"],
"☢":["放射能標識","放射能"],
"☣":["バイオハザード標識","生物災害"],
"☢":["放射能標識","放射能"],
"☣":["バイオハザード標識","生物災害"],
"📴":["携帯電話電源オフ","携帯","コミュニケーション","モバイル","オフ","携帯電話","電話"],
"📳":["マナーモード","携帯","コミュニケーション","モバイル","モード","携帯電話","電話","バイブレーション"],
"🈶":["四角囲み有","日本語","あり"],
"🈚":["四角囲み無","四角囲み否","日本語","なし"],
"🈚":["四角囲み無","四角囲み否","日本語","なし"],
"🈸":["四角囲み申","四角囲み適","中国語","申請"],
"🈺":["四角囲み営","中国語","営業"],
"🈷️":["四角囲み月","日本語","月極"],
@ -1378,11 +1378,11 @@
"🆑":["四角囲みCL","CL"],
"🅾️":["黒四角囲みO","血液型","O"],
"🆘":["四角囲みSOS","ヘルプ","SOS"],
"⛔":["立入禁止","立ち入り","禁止","だめ","できない","禁じる","交通"],
"⛔":["立入禁止","立ち入り","禁止","だめ","できない","禁じる","交通"],
"📛":["名札","バッジ","名前"],
"🚫":["進入禁止","立ち入り","禁止","だめ","できない","禁じる"],
"❌":["バツ印","キャンセル","記号","掛け算","乗算","x"],
"⭕":["太い大きな丸","丸","O"],
"⭕":["太い大きな丸","丸","O"],
"💢":["怒りマーク","怒り","漫画","激怒"],
"♨️":["温泉","温かい","湧き出る","蒸気"],
"🚷":["歩行者立入禁止","禁止","だめ","ない","歩行者","禁じる"],
@ -1392,7 +1392,7 @@
"🔞":["18歳未満禁止","18","年齢制限","十八","禁止","だめ","ない","禁止した","未成年者"],
"📵":["携帯電話禁止","携帯","通信","禁止","モバイル","だめ","できない","携帯電話","禁止されている","電話"],
"🚭":["禁煙","禁止","だめ","できない","禁止されている","喫煙"],
"❗":["赤いビックリマーク","ビックリ","マーク","記号"],
"❗":["赤いビックリマーク","ビックリ","マーク","記号"],
"❕":["白いビックリマーク","ビックリ","マーク","囲み","記号"],
"❓":["赤いはてなマーク","マーク","記号","はてな"],
"❔":["白いはてなマーク","マーク","囲み","記号","はてな"],
@ -1402,13 +1402,13 @@
"🔅":["低輝度","明るさ","薄暗い","低"],
"🔆":["高輝度","明るい","明るさ"],
"🔱":["トライデント","いかり","エンブレム","船","工具"],
"⚜":["ユリの紋章"],
"⚜":["ユリの紋章"],
"〽️":["庵点","印","部分"],
"⚠️":["警告"],
"🚸":["交差点を渡る子供たち","子供","交差点","歩行者","交通"],
"🔰":["初心者マーク","初心者","マーク","緑","日本","若葉","道具","黄"],
"♻️":["リサイクルマーク","リサイクル"],
"🈯":["四角囲み指","日本語"],
"🈯":["四角囲み指","日本語"],
"💹":["上昇トレンドのチャートと円記号","上昇中円チャート","銀行","チャート","通貨","グラフ","成長","市場","お金","上昇","トレンド","上向き","円"],
"❇️":["キラキラ"],
"✳️":["アスタリスク (8本構成)","アスタリスク"],
@ -1422,7 +1422,7 @@
"Ⓜ️":["丸囲みM","円","M"],
"🏧":["ATM","ATM記号","自動","銀行","出納"],
"🚾":["トイレ","化粧室","お手洗い","水","WC"],
"♿":["車いす","アクセス","車椅子"],
"♿":["車いす","アクセス","車椅子"],
"🅿️":["黒四角囲みP","駐車場"],
"🈳":["四角囲み空","四角囲みの空","中国語","空室","空き","空車"],
"🈂️":["四角囲みサ","日本人","サービス"],
@ -1450,26 +1450,26 @@
"🆒":["COOL","かっこいい","クール"],
"🆕":["四角囲みnew","新"],
"🆓":["四角囲みFREE","フリー","無料"],
"0⃣":["0キー","0","キー","ゼロ"],
"1⃣":["1キー","","キー","一"],
"2⃣":["2キー","2","キー","ニ"],
"3⃣":["3キー","3","キー","三"],
"4⃣":["4キー","4","四","キー"],
"5⃣":["5キー","5","五","キー"],
"6⃣":["6キー","6","キー","六"],
"7⃣":["7キー","7","キー","七"],
"8⃣":["8キー","8","八","キー"],
"9⃣":["9キー","9","キー","九"],
"0⃣":["0キー","0","キー","ゼロ"],
"1⃣":["1キー","","キー","一"],
"2⃣":["2キー","2","キー","ニ"],
"3⃣":["3キー","3","キー","三"],
"4⃣":["4キー","4","四","キー"],
"5⃣":["5キー","5","五","キー"],
"6⃣":["6キー","6","キー","六"],
"7⃣":["7キー","7","キー","七"],
"8⃣":["8キー","8","八","キー"],
"9⃣":["9キー","9","キー","九"],
"🔟":["10キー","10","キー","十"],
"🔢":["番号の入力記号","1234","入力","数字"],
"▶️":["右向き三角","再生ボタン","矢印","再生","右","三角形"],
"⏸":["2本の垂直バー","一時停止ボタン","バー","2倍","一時停止","垂直"],
"⏯":["右向きの三角形と二重垂直棒","再生または一時停止ボタン","矢印","一時停止","再生","右","三角形"],
"⏹":["停止","停止ボタン","四角"],
"⏺":["録画","録画ボタン","丸"],
"⏸":["2本の垂直バー","一時停止ボタン","バー","2倍","一時停止","垂直"],
"⏯":["右向きの三角形と二重垂直棒","再生または一時停止ボタン","矢印","一時停止","再生","右","三角形"],
"⏹":["停止","停止ボタン","四角"],
"⏺":["録画","録画ボタン","丸"],
"⏏️":["取り出しマーク","取り出しボタン"],
"⏭":["右向きの二重三角形と垂直棒","「次の曲」ボタン","矢印","次の場面","次の曲","三角形"],
"⏮":["左向きの二重三角形と垂直棒","「前の曲」ボタン","矢印","前の場面","前の曲","三角形"],
"⏭":["右向きの二重三角形と垂直棒","「次の曲」ボタン","矢印","次の場面","次の曲","三角形"],
"⏮":["左向きの二重三角形と垂直棒","「前の曲」ボタン","矢印","前の場面","前の曲","三角形"],
"⏩":["右向きの二重三角形","早送りボタン","矢印","2倍","高速","進む"],
"⏪":["左向きの二重三角形","早戻しボタン","矢印","2倍","巻き戻し"],
"🔀":["ねじり右向き矢印の絵文字","シャッフル","矢印","交差"],
@ -1496,7 +1496,7 @@
"🔃":["ループ矢印","時計の針","矢印","時計回り","リロード"],
"⤴️":["右上へカーブする矢印","上へカーブする右矢印","矢印"],
"⤵️":["右下へカーブする矢印","下にカーブする右矢印","矢印","下"],
"#⃣":["#キー","ハッシュ","キー","ポンド"],
"#⃣":["#キー","ハッシュ","キー","ポンド"],
"*⃣":["アスタリスクキー","アスタリスク","キー","星"],
"":["情報源","i","インフォメーション"],
"🔤":["アルファベット入力","abc","アルファベット","入力","ラテン","文字"],
@ -1532,8 +1532,8 @@
"🔵":["青丸","青","円","幾何学"],
"🟣":["紫の丸","円","幾何学","紫"],
"🟤":["茶色の丸","円","幾何学","茶色"],
"⚫":["黒丸","円","幾何学"],
"⚪":["白丸","円","幾何学"],
"⚫":["黒丸","円","幾何学"],
"⚪":["白丸","円","幾何学"],
"🟥":["赤の正方形","正方形","幾何学","赤"],
"🟧":["オレンジ色の正方形","正方形","幾何学","オレンジ"],
"🟨":["黄色の正方形","正方形","幾何学","黄色"],
@ -1541,12 +1541,12 @@
"🟦":["青の正方形","正方形","幾何学","青"],
"🟪":["紫の正方形","正方形","幾何学","紫"],
"🟫":["茶色の正方形","正方形","幾何学","茶色"],
"⬛":["黒い大きな四角","幾何学","正方形"],
"⬜":["白い大きな四角","幾何学","正方形"],
"⬛":["黒い大きな四角","幾何学","正方形"],
"⬜":["白い大きな四角","幾何学","正方形"],
"◼️":["黒い中くらいの四角","幾何学","正方形"],
"◻️":["白くて中くらいの四角","幾何学","正方形"],
"◾":["黒くて中くらいの小さい四角","幾何学","正方形"],
"◽":["白い中くらいの小さな四角","幾何学","正方形"],
"◾":["黒くて中くらいの小さい四角","幾何学","正方形"],
"◽":["白い中くらいの小さな四角","幾何学","正方形"],
"▪️":["黒い小さな四角","幾何学","正方形"],
"▫️":["白い小さな四角","幾何学","正方形"],
"🔸":["小さいオレンジのダイヤモンド","ダイヤモンド","幾何学","オレンジ"],
@ -1566,16 +1566,16 @@
"🔔":["ベル"],
"🔕":["ミュート","スラッシュベル","鐘","禁じられた","だめ","ない","禁止","静か"],
"🃏":["トランプのジョーカー","カード","エンターテイメント","ゲーム","ジョーカー","プレイ"],
"🀄":["麻雀牌の中","ゲーム","麻雀","赤"],
"🀄":["麻雀牌の中","ゲーム","麻雀","赤"],
"♠️":["トランプのスペード","カード","ゲーム","スペード","スーツ"],
"♣️":["トランプのクラブ","カード","クラブ","ゲーム","スーツ"],
"♥️":["トランプのハート","カード","ゲーム","ハート","スーツ"],
"♦️":["トランプのダイヤ","カード","ダイヤ","ダイヤモンド","ゲーム","スーツ"],
"🎴":["花札","アクティビティ","カード","エンターテイメント","花","ゲーム","日本","プレイ"],
"👁‍🗨":["吹き出しの目","吹き出し","目","スピーチ","証人"],
"🗨":["左向きの吹き出し","セリフ","スピーチ"],
"🗨":["左向きの吹き出し","セリフ","スピーチ"],
"💭":["考え吹き出し","吹き出し","泡","漫画","考え"],
"🗯":["右向きの怒りの吹き出し","怒り","吹き出し","泡","激怒"],
"🗯":["右向きの怒りの吹き出し","怒り","吹き出し","泡","激怒"],
"💬":["吹き出し","泡","漫画","セリフ","スピーチ"],
"🕐":["1時","0分","1","時計","時","一"],
"🕑":["2時","0分","2","時計","時","二"],
@ -1601,7 +1601,7 @@
"🕥":["10時半","10時","半","時刻","十","30"],
"🕦":["11時半","11時","半","時刻","十一","30"],
"🕧":["12時半","12時","半","時刻","30","十二"],
"🏳":["なびく白旗","旗","なびく"],
"🏳":["なびく白旗","旗","なびく"],
"🏴":["なびく黒旗","旗","なびく"],
"🏁":["チェッカーフラッグ","市松模様","旗","レース"],
"🚩":["三角旗","旗","ポスト"],
@ -1861,5 +1861,6 @@
"🇾🇹":["マヨットの旗","国旗","マヨット"],
"🇿🇦":["南アフリカ国旗","国旗","南","南アフリカ"],
"🇿🇲":["ザンビア国旗","国旗","ザンビア"],
"🇿🇼":["ジンバブエ国旗","国旗","ジンバブエ"]
"🇿🇼":["ジンバブエ国旗","国旗","ジンバブエ"],
"": ["渋谷109", "SHIBUYA109", "109"]
}

View File

@ -61,7 +61,7 @@
"😔": ["かなしげなかお","がっかり","かお","かなしい"],
"😕": ["こまったかお","こまった","かお"],
"🙁": ["ごきげんななめ","かお","しかめっつら","かなしい","ふこう"],
"☹": ["しかめっつら","かお","かなしい","ふこう"],
"☹": ["しかめっつら","かお","かなしい","ふこう"],
"😬": ["しかめっつら","かお"],
"🥺": ["うったえかけるかお","かお","ものごい","じひ","こいぬのめ"],
"😣": ["がまんしているかお","かお","がんばる"],
@ -111,7 +111,7 @@
"💩": ["うんち","まんが","ふん","かお","もんすたー"],
"👻": ["おばけ","ようかい","かお","おとぎばなし","ふぁんたじー","ゆうれい","もんすたー","はろうぃーん"],
"💀": ["どくろ","からだ","し","かお","おとぎばなし","もんすたー","がいこつ","はろうぃーん"],
"☠": ["どくろまーく","からだ","こうさしたほね","し","かお","もんすたー","がいこつ","はろうぃーん"],
"☠": ["どくろまーく","からだ","こうさしたほね","し","かお","もんすたー","がいこつ","はろうぃーん"],
"👽": ["うちゅうじん","かいじゅう","いせいじん","かお","おとぎばなし","ふぁんたじー","もんすたー","うちゅう","UFO"],
"🤖": ["ろぼっとのかお","かお","もんすたー","ろぼっと"],
"🎃": ["じゃっく・お・らんたん","いべんと","おいわい","えんため","はろうぃん","じゃっくおらんたん","らんたん","かぼちゃ"],
@ -138,7 +138,7 @@
"🤛": ["ひだりむきのこぶし","からだ","こぶし","ひだりむき"],
"🤜": ["みぎむきのこぶし","からだ","こぶし","みぎむき"],
"🤞": ["こうささせたゆび","からだ","こうさ","ゆび","て","こううん"],
"✌": ["Vさいん","からだ","て","V","ぶい","かつ","しょうり","ぴーす"],
"✌": ["Vさいん","からだ","て","V","ぶい","かつ","しょうり","ぴーす"],
"🫰": ["ひとさしゆびとおやゆびをこうさしたて","たかい","はーと","あい","おかね","すなっぷ"],
"🤘": ["こるな","からだ","ゆび","て","つの","さいこう"],
"🤟": ["あいしてるのじぇすちゃー","からだ","あいしてる","すき","て"],
@ -151,10 +151,10 @@
"👉": ["ゆびさし","てのこう","からだ","ゆび","て","ひとさしゆび","ゆびさす"],
"👆": ["ゆびさし","てのこう","からだ","ゆび","て","ひとさしゆび","ゆびさす","うえ"],
"👇": ["ゆびさし","てのこう","からだ","した","ゆび","て","ひとさしゆび","ゆびさす"],
"☝": ["ゆびさし","からだ","ゆび","て","ひとさしゆび","ゆびさす","うえ"],
"☝": ["ゆびさし","からだ","ゆび","て","ひとさしゆび","ゆびさす","うえ"],
"✋": ["きょしゅ","からだ","て"],
"🤚": ["てのこう","からだ","あげる"],
"🖐": ["ひろげたてのひら","からだ","ゆび","て","ひろげる"],
"🖐": ["ひろげたてのひら","からだ","ゆび","て","ひろげる"],
"🖖": ["ちょうじゅとはんえいを","からだ","ゆび","て","すぽっく","ばるかん"],
"👋": ["ばいばい","からだ","て","ふる","やっほー","こんにちは"],
"🤙": ["でんわのかたちのて","からだ","でんわ","て"],
@ -166,7 +166,7 @@
"🦾": ["めかにかるあーむ","あくせしびりてぃ","ぎしゅ","じんこうそうぐ","からだ"],
"🖕": ["なかゆびをたてたて","からだ","ゆび","て","なかゆび"],
"🫵": ["みているひとをさしているひとさしゆび","さす","あなた","ゆび"],
"✍": ["かいているて","からだ","て","かく"],
"✍": ["かいているて","からだ","て","かく"],
"🤳": ["じどり","かめら","けいたい","うで"],
"💅": ["まにきゅあ","からだ","けあ","けしょうひん","こすめ","つめ","ねいる"],
"🦵": ["あし","からだ","きっく","てあし"],
@ -179,7 +179,7 @@
"👂": ["みみ","からだ","はな"],
"🦻": ["ほちょうきをつけているみみ","あくせしびりてぃ","ほちょうき","きく","からだ","みみ"],
"👃": ["はな","からだ"],
"👁": ["め","からだ"],
"👁": ["め","からだ"],
"👀": ["め","からだ","かお"],
"🧠": ["のう","からだ","ぞうき","ちてき","かしこい"],
"🫀": ["かいぼうがくてきなしんぞう","かいぼうがく","しんぞうがく","しんぞう","ぞうき","みゃく"],
@ -187,7 +187,7 @@
"🦴": ["ほね","からだ","こっかく"],
"👤": ["じょうはんしんのしるえっと","じょうはんしん","しるえっと"],
"👥": ["じょうはんしんのしるえっと","じょうはんしん","しるえっと"],
"🗣": ["しゃべるあたまのしるえっと","かお","あたま","しるえっと","しゃべる","はなす"],
"🗣": ["しゃべるあたまのしるえっと","かお","あたま","しるえっと","しゃべる","はなす"],
"🫂": ["はぐしているひとたち","さようなら","こんにちは","はぐ","ありがとう"],
"👶": ["あかちゃん"],
"👧": ["おんなのこ","しょうじょ","しょじょ","おとめざ","せいざ","こども"],
@ -281,7 +281,7 @@
"💂‍♂️": ["だんせいけいびいん","けいびいん","けいび","おとこ","だんせい"],
"🥷": ["にんじゃ","せんし","かくされた","すてるす"],
"🕵️‍♀️": ["じょせいのたんてい","たんてい","けいじ","すぱい","じょせい","おんな"],
"🕵": ["たんてい","けいじ","すぱい"],
"🕵": ["たんてい","けいじ","すぱい"],
"🕵️‍♂️": ["だんせいのたんてい","たんてい","けいじ","すぱい","おとこ","だんせい"],
"🤶": ["みせす・くろーす","いべんと","おいわい","くりすます","はは","さんた","くろーす","じょせい","おんな"],
"🧑‍🎄": ["みくすくろーす","あくてぃびてぃ","おいわい","くりすます","さんた","くろーす"],
@ -300,7 +300,7 @@
"🩵": ["らいとぶるーのはーと","しあん","はーと","らいとぶるー","こがも"],
"🩶": ["ぐれーのはーと","ぐれー","はーと","しるばー","すれーと"],
"🕴️‍♀️": ["ちゅうにういたすーつのじょせい","びじねす","すーつ","じょせい","おんな"],
"🕴": ["ちゅうにういたすーつのひと","びじねす","すーつ"],
"🕴": ["ちゅうにういたすーつのひと","びじねす","すーつ"],
"🕴️‍♂️": ["ちゅうにういたすーつのだんせい","びじねす","すーつ","おとこ","だんせい"],
"🦸‍♀️": ["じょせいのすーぱーひーろー","くうそう","ぜん","ひろいん","ちょうたいこく","じょせい","おんな"],
"🦸": ["すーぱーひーろー","くうそう","ぜん","ひーろー","ひろいん","ちょうたいこく"],
@ -468,7 +468,7 @@
"🎩": ["しるくはっと","あくてぃびてぃ","ふく","えんたーていんめんと","ごらく","ぼうし","とっぷす"],
"🎓": ["そつぎょうしきのかくぼう","あくてぃびてぃ","ぼうし","おいわい","ふく","そつぎょう","はっと"],
"👑": ["かんむり","ふく","おうかん","おう","じょおう"],
"⛑": ["しろじゅうじのへるめっと","きゅうじょ","じゅうじ","かお","ぼうし","へるめっと"],
"⛑": ["しろじゅうじのへるめっと","きゅうじょ","じゅうじ","かお","ぼうし","へるめっと"],
"🪖": ["ぐんたいのへるめっと","ぐん","へるめっと","ぐんたい","ぐんじん","へいし"],
"🎒": ["らんどせる","あくてぃびてぃ","かばん","ばっぐ","がくせいかばん","がっこう"],
"👝": ["ぽーち","かばん","ばっぐ","ふく"],
@ -476,13 +476,13 @@
"👜": ["はんどばっぐ","かばん","ばっぐ","ふく"],
"💼": ["ぶりーふけーす"],
"👓": ["めがね","ふく","め","あいうぇあ"],
"🕶": ["さんぐらす","くらい","め","めがね"],
"🕶": ["さんぐらす","くらい","め","めがね"],
"🥽": ["ごーぐる","ふく","めのほご","すいえい","ようせつ"],
"🧣": ["すかーふ","ふく","くび"],
"🧤": ["てぶくろ","ふく","て"],
"💍": ["ゆびわ","だいやもんど","れんあい","ろまんす"],
"🌂": ["とじたかさ","ふく","あめ","かさ","てんき"],
"☂": ["かさ","ふく","あめ","てんき"],
"☂": ["かさ","ふく","あめ","てんき"],
"🐶": ["いぬのかお","けん","いぬ","かお","ぺっと"],
"🐱": ["ねこのかお","ねこ","かお","ぺっと"],
"🐭": ["ねずみのかお","かお","ねずみ"],
@ -536,8 +536,8 @@
"🐜": ["あり","こんちゅう"],
"🦗": ["くりけっと","こおろぎ","ばっため","こんちゅう"],
"🪳": ["ごきぶり","こんちゅう","がいちゅう"],
"🕷": ["くも","こんちゅう"],
"🕸": ["くものす","くも","す"],
"🕷": ["くも","こんちゅう"],
"🕸": ["くものす","くも","す"],
"🦂": ["さそり","さそりざ","せいざ"],
"🦟": ["か","びょうき","ねつ","こんちゅう","まらりあ","ういるす"],
"🪰": ["はえ","がいちゅう","こんちゅう","うじむし"],
@ -584,7 +584,7 @@
"🦇": ["こうもり","きゅうけつき"],
"🐓": ["おんどり"],
"🦃": ["しちめんちょう(とり)","しちめんちょう","とり"],
"🕊": ["へいわのはと","とり","はと","ひこう","へいわ"],
"🕊": ["へいわのはと","とり","はと","ひこう","へいわ"],
"🦅": ["わし","とり"],
"🦆": ["あひる","とり"],
"🪿": ["がちょう","とり","かきん","けいてきのおと"],
@ -605,7 +605,7 @@
"🐇": ["うさぎ","ばにー","ぺっと"],
"🐀": ["ねずみ"],
"🐁": ["ねずみ"],
"🐿": ["しまりす"],
"🐿": ["しまりす"],
"🦨": ["すかんく","あくしゅう","におう"],
"🦡": ["あなぐま","らーてる","ねだる"],
"🦔": ["はりねずみ","かお"],
@ -622,7 +622,7 @@
"🪴": ["はちうえ","しょくぶつ","かんようしょくぶつ"],
"🌱": ["なえぎ","しょくぶつ","わかい"],
"🌿": ["はーぶ","は","しょくぶつ"],
"☘": ["くろーばー","しょくぶつ"],
"☘": ["くろーばー","しょくぶつ"],
"🍀": ["よっつはのくろーばー","4","くろーばー","よん","は","しょくぶつ"],
"🎍": ["かどまつ","あくてぃびてぃ","たけ","おいわい","にっぽん","まつ","しょくぶつ"],
"🎋": ["ななゆう","あくてぃびてぃ","はた","おいわい","えんたーていめんと","にっぽん"],
@ -661,35 +661,35 @@
"🌝": ["かおつきまんげつ","あかるい","かお","みちた","つき","うちゅう","てんき"],
"🌛": ["かおつきじょうげんのつき","かお","つき","げん","うちゅう","てんき"],
"🌜": ["がおがあるかげんのつき","かお","つき","げん","うちゅう","てんき"],
"⭐": ["ちゅうくらいのほし","ほし"],
"⭐": ["ちゅうくらいのほし","ほし"],
"🌟": ["ひかるほし","きらめき","あかいひかり","かがやく","かがやき","ほし"],
"💫": ["くらくら","まんが","めまい","ほし"],
"✨": ["きらきら","えんたーていめんと","かがやき","ほし"],
"☄": ["すいせい","うちゅう"],
"☄": ["すいせい","うちゅう"],
"🪐": ["たまきのあるわくせい","うちゅう","わくせい","どせい"],
"🌞": ["かおつきたいよう","あかるい","かお","うちゅう","たいよう","てんき"],
"☀️": ["たいようのひかり","あかるい","こうせん","うちゅう","たいよう","せいてん","てんき"],
"🌤": ["たいようとちいさなくも","くも","たいよう","てんき"],
"⛅": ["はれときどきくもり","くも","たいよう","てんき"],
"🌥": ["はれのちくもり","くも","たいよう","てんき"],
"🌦": ["はれのちくもりときどきあめ","くも","あめ","たいよう","てんき"],
"🌤": ["たいようとちいさなくも","くも","たいよう","てんき"],
"⛅": ["はれときどきくもり","くも","たいよう","てんき"],
"🌥": ["はれのちくもり","くも","たいよう","てんき"],
"🌦": ["はれのちくもりときどきあめ","くも","あめ","たいよう","てんき"],
"☁️": ["くも","てんき"],
"🌧": ["あまぐも","くも","あめ","てんき"],
"⛈": ["らいう","くも","あめ","かみなり","てんき"],
"🌩": ["らいうん","くも","かみなり","てんき"],
"⚡": ["だかでんあつきごう","きけん","でんき","かみなり","でんあつ","びりびり"],
"🌧": ["あまぐも","くも","あめ","てんき"],
"⛈": ["らいう","くも","あめ","かみなり","てんき"],
"🌩": ["らいうん","くも","かみなり","てんき"],
"⚡": ["だかでんあつきごう","きけん","でんき","かみなり","でんあつ","びりびり"],
"🔥": ["えん","ひ","どうぐ"],
"💥": ["しょうとつまーく","どかーん","しょうとつ","まんが"],
"❄️": ["せつのけっしょう","つめたい","ゆき","てんき"],
"🌨": ["ゆきぐも","くも","れい","ゆき","てんき"],
"☃": ["ゆきだるま","れい","ゆき","てんき"],
"⛄": ["ゆきだるま","れい","ゆき","てんき"],
"🌬": ["かぜがふいている","かぜがふく","くも","かお","てんき","ふう"],
"🌨": ["ゆきぐも","くも","れい","ゆき","てんき"],
"☃": ["ゆきだるま","れい","ゆき","てんき"],
"⛄": ["ゆきだるま","れい","ゆき","てんき"],
"🌬": ["かぜがふいている","かぜがふく","くも","かお","てんき","ふう"],
"💨": ["だっしゅ","まんが","はしる"],
"🌪": ["たつまきぐも","くも","たつまき","てんき","せんぷう"],
"🌫": ["きり","くも","てんき"],
"🌪": ["たつまきぐも","くも","たつまき","てんき","せんぷう"],
"🌫": ["きり","くも","てんき"],
"🌈": ["にじ","あめ","れいんぼー","てんき","ぷらいど","lgbt"],
"☔": ["うとかさ","いるい","しずく","あめ","かさ","てんき"],
"☔": ["うとかさ","いるい","しずく","あめ","かさ","てんき"],
"💧": ["しずく","ぞっとする","まんが","したたり","あせ","てんき"],
"💦": ["あせまーく","まんが","ぬれている","あせ"],
"🌊": ["なみ","うみ","みず","てんき"],
@ -714,7 +714,7 @@
"🥑": ["あぼかど","ふるーつ","くだもの"],
"🫒": ["おりーぶ","ふるーつ"],
"🍆": ["なす","なすび","しょくぶつ","やさい"],
"🌶": ["とうがらし","からい","こしょう","しょくぶつ"],
"🌶": ["とうがらし","からい","こしょう","しょくぶつ"],
"🫑": ["ぴーまん","とうがらし","こしょう","しょくぶつ","やさい"],
"🥒": ["きゅうり","ぴくるす","やさい"],
"🥬": ["はっぱのみどり","ちんげんさい","きゃべつ","けーる","れたす"],
@ -793,7 +793,7 @@
"🍪": ["くっきー","でざーと","あまい"],
"🥠": ["おみくじいりくっきー","ふぉーちゅんくっきー"],
"🥮": ["げっぺい","あき","まつり"],
"☕": ["ほっとどりんく","いんりょう","こーひー","のみもの","あたたかい","じょうき","おちゃ"],
"☕": ["ほっとどりんく","いんりょう","こーひー","のみもの","あたたかい","じょうき","おちゃ"],
"🍵": ["ゆのみ","いんりょう","かっぷ","のみもの","おちゃ"],
"🫖": ["てぃーぽっと","どりんく","ぽっと","てぃー","けとる"],
"🥣": ["ぼうるとすぷーん","ちょうしょく","しりある","おかゆ","おーとみーる","ぽりっじ","しょっき"],
@ -816,13 +816,13 @@
"🧊": ["かくこおり","こおり","りっぽうたい","つめたい","ひょうざん"],
"🥄": ["すぷーん","しょっき"],
"🍴": ["ふぉーくとないふ","ちょうり","ふぉーく","ないふ","しょっき"],
"🍽": ["ふぉーくとないふとぷれーと","ちょうり","ふぉーく","ないふ","ぷれーと","しょっき"],
"🍽": ["ふぉーくとないふとぷれーと","ちょうり","ふぉーく","ないふ","ぷれーと","しょっき"],
"🥢": ["はし"],
"🥡": ["ていくあうとぼっくす","ていくあうと","ようき","おもちかえり"],
"⚽": ["さっかーぼーる","ぼーる","さっかー"],
"⚽": ["さっかーぼーる","ぼーる","さっかー"],
"🏀": ["ばすけっとぼーる","ぼーる","ばすけっとりんぐ"],
"🏈": ["あめりかんふっとぼーる","あめりかん","ぼーる","ふっとぼーる"],
"⚾": ["やきゅう","ぼーる"],
"⚾": ["やきゅう","ぼーる"],
"🥎": ["そふとぼーる","ぼーる","しあい","すぽーつ"],
"🎾": ["てにすぼーる","ぼーる","らけっと","てにす"],
"🏐": ["ばれーぼーる","ぼーる","しあい"],
@ -838,19 +838,19 @@
"🏏": ["くりけっとのばっととぼーる","ぼーる","ふぃーるど","くりけっと","しあい"],
"🥍": ["らくろす","ぼーる","すてぃっく","しあい","すぽーつ"],
"🥌": ["かーりんぐすとーん","かーりんぐ","すとーん"],
"⛳": ["ごるふのかっぷ","ぴんふらっぐ","ごるふ","ほーる"],
"⛳": ["ごるふのかっぷ","ぴんふらっぐ","ごるふ","ほーる"],
"🏹": ["ゆみや","しゃしゅ","や","ゆみ","しゃしゅざ","どうぐ","せいざ"],
"🎣": ["つりざおとさかな","えんたーていめんと","さかな","ぼう"],
"🤿": ["だいびんぐますく","だいびんぐ","すきゅーば","しゅのーける"],
"🥊": ["ぼくしんぐぐろーぶ","ぼくしんぐ","ぐろーぶ"],
"🥋": ["どうぎ","じゅうどう","からて","ぶどう","てこんどー","ゆにふぉーむ"],
"⛸": ["あいすすけーと","こおり"],
"⛸": ["あいすすけーと","こおり"],
"🎿": ["すきーとすきーぶーつ","すきー","ゆき"],
"🛷": ["そり","るーじゅ","とぼがん"],
"⛷": ["すきー","ゆき"],
"⛷": ["すきー","ゆき"],
"🏂": ["すのーぼーだー","すきー","ゆき","すのーぼーど"],
"🏋️‍♀️": ["うえいとをもちあげるじょせい","あげ","じゅうりょう","じょせい","おんな"],
"🏋": ["うえいとをもちあげるひと","あげ","じゅうりょう"],
"🏋": ["うえいとをもちあげるひと","あげ","じゅうりょう"],
"🏋️‍♂️": ["うえいとをもちあげるだんせい","あげ","じゅうりょう","おとこ","だんせい"],
"🤺": ["ふぇんしんぐをするひと","けんし","けんじゅつ","けん"],
"🤼‍♀️": ["れすりんぐをするじょせい","れすりんぐ","れすりんぐせんしゅ","じょせい","おんな"],
@ -860,7 +860,7 @@
"🤸": ["そくてんをするひと","そくほうてんかい","たいそう"],
"🤸‍♂️": ["そくてんをするだんせい","そくほうてんかい","たいそう","おとこ","だんせい"],
"⛹️‍♀️": ["ぼーるをばうんどさせるじょせい","ぼーる","じょせい","おんな"],
"⛹": ["ぼーるをばうんどさせるひと","ぼーる"],
"⛹": ["ぼーるをばうんどさせるひと","ぼーる"],
"⛹️‍♂️": ["ぼーるをばうんどさせるだんせい","ぼーる","おとこ","だんせい"],
"🤾‍♀️": ["はんどぼーるをするじょせい","ぼーる","はんどぼーる","じょせい","おんな"],
"🤾": ["はんどぼーるをするひと","ぼーる","はんどぼーる"],
@ -869,7 +869,7 @@
"🧗": ["くらいみんぐしているひと","くらいみんぐ","ろっく"],
"🧗‍♂️": ["くらいみんぐしているだんせい","くらいみんぐ","ろっく","だんせい","おとこ"],
"🏌️‍♀️": ["ごるふをするじょせい","ぼーる","ごるふ","ごるふぁー","ごるふする","じょせい","おんな"],
"🏌": ["ごるふをするひと","ぼーる","ごるふ","ごるふぁー","ごるふする"],
"🏌": ["ごるふをするひと","ぼーる","ごるふ","ごるふぁー","ごるふする"],
"🏌️‍♂️": ["ごるふをするだんせい","ぼーる","ごるふ","ごるふぁー","ごるふする","おとこ","だんせい"],
"🧘‍♀️": ["れんげざのじょせい","めいそう","よが","せいおん","じょせい","おんな"],
"🧘": ["れんげざのひと","めいそう","よが","せいおん"],
@ -897,16 +897,16 @@
"🚵": ["まうんてんばいくにのるひと","まうんてんばいくらいだー","くろすばいく","じてんしゃ","じてんしゃのり","じてんしゃにのるひと","やま"],
"🚵‍♂️": ["まうんてんばいくにのるだんせい","まうんてんばいくらいだー","くろすばいく","じてんしゃ","じてんしゃのり","じてんしゃにのるひと","さいくりすと","やま","おとこ","だんせい"],
"🎽": ["らんにんぐしゃつとたすき","らんにんぐ","たすき","しゃつ"],
"🎖": ["くんしょう","おいわい","めだる","ぐんじ"],
"🎖": ["くんしょう","おいわい","めだる","ぐんじ"],
"🏅": ["すぽーつのめだる","めだる"],
"🥇": ["きんめだる","1い","きん","めだる","1","だい1い"],
"🥈": ["ぎんめだる","めだる","2い","ぎん","2","だい2い"],
"🥉": ["どうめだる","どう","めだる","3い","3","だい3い"],
"🏆": ["とろふぃー","しょう"],
"🏵": ["ばらかざり","しょくぶつ"],
"🎗": ["りまいんだーりぼん","おいわい","りまいんだー","りぼん"],
"🏵": ["ばらかざり","しょくぶつ"],
"🎗": ["りまいんだーりぼん","おいわい","りまいんだー","りぼん"],
"🎫": ["きっぷ","あくてぃびてぃ","にゅうじょうりょう","えんたーていめんと","ちけっと"],
"🎟": ["にゅうじょうけん","にゅうじょうりょう","えんたーていめんと","ちけっと"],
"🎟": ["にゅうじょうけん","にゅうじょうりょう","えんたーていめんと","ちけっと"],
"🎪": ["さーかすごや","あくてぃびてぃ","さーかす","えんたーていめんと","てんと"],
"🤹‍♀️": ["じゃぐりんぐをするじょせい","てんびん","じゃぐりんぐ","じょせい","おんな"],
"🤹": ["じゃぐりんぐをするひと","ばらんす","じゃぐりんぐ"],
@ -945,7 +945,7 @@
"🛺": ["おーとりきしゃ","じんりきしゃ","とぅくとぅく"],
"🚌": ["ばす","のりもの"],
"🚎": ["とろりーばす","ばす","ろめんでんしゃ","しがいでんしゃ","のりもの"],
"🏎": ["れーしんぐかー","くるま","きょうそう"],
"🏎": ["れーしんぐかー","くるま","きょうそう"],
"🚓": ["ぱとかー","くるま","ぱとろーる","けいさつ","のりもの"],
"🚑": ["きゅうきゅうしゃ","のりもの"],
"🚒": ["しょうぼうしゃ","えんじん","えん","とらっく","のりもの"],
@ -954,7 +954,7 @@
"🚚": ["はいたつようとらっく","はいたつ","とらっく","のりもの"],
"🚛": ["とれーらー","おおがたとらっく","せみ","とらっく","のりもの"],
"🚜": ["とらくたー","のりもの"],
"🏍": ["れーすばいく","おーとばい","れーす"],
"🏍": ["れーすばいく","おーとばい","れーす"],
"🛵": ["すくーたー","もーたー"],
"🚲": ["じてんしゃ","ばいく","のりもの"],
"🦼": ["でんどうくるまいす","あくせしびりてぃ","くるまいす"],
@ -984,25 +984,25 @@
"🚊": ["ろめんでんしゃ","とろりーばす","のりもの"],
"🚉": ["えき","せんろ","でんしゃ","のりもの"],
"🚁": ["へりこぷたー","のりもの"],
"🛩": ["こがたこうくうき","ひこうき","のりもの"],
"🛩": ["こがたこうくうき","ひこうき","のりもの"],
"✈️": ["ひこうき","のりもの"],
"🛫": ["ひこうきのりりく","ひこうき","ちぇっくいん","しゅっぱつ","のりもの"],
"🛬": ["ひこうきのちゃくりく","ひこうき","とうちゃく","ちゃくりく","のりもの"],
"🪂": ["ぱらしゅーと","ぱらせーる","すかいだいぶ","はんぐぐらいだー"],
"💺": ["ざせき","いす"],
"🛰": ["さてらいと","えいせい","うちゅう","のりもの"],
"🛰": ["さてらいと","えいせい","うちゅう","のりもの"],
"🚀": ["ろけっと","うちゅう","のりもの"],
"🛸": ["そらとぶえんばん","UFO","うちゅうじん","いほしじん","うちゅう","くうそう"],
"🛶": ["かぬー","ぼーと"],
"⛵": ["よっと","ぼーと","りぞーと","うみ","のりもの"],
"🛥": ["もーたーぼーと","ぼーと","のりもの"],
"⛵": ["よっと","ぼーと","りぞーと","うみ","のりもの"],
"🛥": ["もーたーぼーと","ぼーと","のりもの"],
"🚤": ["すぴーどぼーと","ぼーと","のりもの"],
"⛴": ["ふぇりー","ぼーと"],
"🛳": ["りょかくせん","りょかく","ふね","のりもの"],
"⛴": ["ふぇりー","ぼーと"],
"🛳": ["りょかくせん","りょかく","ふね","のりもの"],
"🚢": ["ふね","のりもの"],
"🛟": ["きゅうめいうきわ","うきわ","らいふじゃけっと","らいふせーばー","きゅうじょ","あんぜん"],
"⚓": ["いかり","ふね","つーる"],
"⛽": ["がそりんすたんど","ねんりょう","がそりん","きゅうゆき","さーびすすてーしょん"],
"⚓": ["いかり","ふね","つーる"],
"⛽": ["がそりんすたんど","ねんりょう","がそりん","きゅうゆき","さーびすすてーしょん"],
"🚧": ["こうじちゅう","こうじようふぇんす","けんせつこうじ"],
"🚏": ["ばすてい","ばす","ていし"],
"🚦": ["たてむきのしんごうき","しんごうき","しんごう","こうつう"],
@ -1011,30 +1011,30 @@
"🎡": ["かんらんしゃ","あくてぃびてぃ","ゆうえんち","えんたーていめんと","ふぇりす"],
"🎢": ["じぇっとこーすたー","あくてぃびてぃ","ゆうえんち","こーすたー","えんたーていめんと","ろーらー"],
"🎠": ["めりーごーらんど","あくてぃびてぃ","めりーごーらうんど","えんたーていめんと","うま"],
"🏗": ["けんせつちゅう","たてもの","けんせつ"],
"🏗": ["けんせつちゅう","たてもの","けんせつ"],
"🌁": ["きり","てんき"],
"🗼": ["とうきょうたわー","とうきょう","たわー"],
"🏭": ["こうじょう","たてもの"],
"⛲": ["ふんすい"],
"⛲": ["ふんすい"],
"🎑": ["おつきみ","あくてぃびてぃ","おいわい","じゅしょうしき","えんたーていめんと","つき"],
"⛰": ["やま"],
"🏔": ["ゆきやま","さむい","やま","ゆき"],
"⛰": ["やま"],
"🏔": ["ゆきやま","さむい","やま","ゆき"],
"🗻": ["ふじさん","やま"],
"🌋": ["かざん","ふんか","やま","きしょう"],
"🗾": ["にっぽんれっとう","にっぽん","ちず"],
"🏕": ["きゃんぷ"],
"⛺": ["てんと","きゃんぷ"],
"🏞": ["こくりつこうえん","こうえん"],
"🛣": ["こうそくどうろ","はいうぇい","どうろ"],
"🛤": ["せんろ","てつどう","でんしゃ"],
"🏕": ["きゃんぷ"],
"⛺": ["てんと","きゃんぷ"],
"🏞": ["こくりつこうえん","こうえん"],
"🛣": ["こうそくどうろ","はいうぇい","どうろ"],
"🛤": ["せんろ","てつどう","でんしゃ"],
"🌅": ["ひので","あさ","たいよう","てんこう"],
"🌄": ["やまからのひので","あさ","やま","たいよう","ひので","てんこう"],
"🏜": ["さばく"],
"🏖": ["びーちとかさ","びーち","かさ","ぱらそる"],
"🏝": ["むじんとう","さばく","しま"],
"🏜": ["さばく"],
"🏖": ["びーちとかさ","びーち","かさ","ぱらそる"],
"🏝": ["むじんとう","さばく","しま"],
"🌇": ["びるにしずむゆうひ","たてもの","ゆうぐれ","たいよう","ゆうひ","てんき"],
"🌆": ["ゆうぐれのまちなみ","たてもの","まち","ゆうぐれ","ひぐれ","ふうけい","たいよう","ゆうひ","てんき"],
"🏙": ["まちなみ","たてもの","まち"],
"🏙": ["まちなみ","たてもの","まち"],
"🌃": ["ほしぞら","よる","ほし","てんき"],
"🌉": ["よるのはし","はし","よる","てんき"],
"🌌": ["あまのがわ","うちゅう","てんき"],
@ -1042,14 +1042,14 @@
"🎇": ["せんこうはなび","あくてぃびてぃ","おいわい","えんたーていめんと","はなび","きらきら"],
"🎆": ["はなび","あくてぃびてぃ","おいわい","えんたーていめんと"],
"🛖": ["こや","いえ","せんけいこ","ぱお"],
"🏘": ["いえ","たてもの"],
"🏘": ["いえ","たてもの"],
"🏰": ["せいようのしろ","たてもの","しろ","よーろっぱ"],
"🏯": ["にっぽんのしろ","たてもの","しろ","にっぽん"],
"🏟": ["すたじあむ"],
"🏟": ["すたじあむ"],
"🗽": ["じゆうのめがみ","じゆう","ぞう"],
"🏠": ["いえ","たてもの","じたく"],
"🏡": ["にわつきのいえ","たてもの","にわ","じたく","いえ"],
"🏚": ["はいきょ","たてもの","はいおく","いえ"],
"🏚": ["はいきょ","たてもの","はいおく","いえ"],
"🏢": ["おふぃすびる","たてもの"],
"🏬": ["でぱーと","たてもの","てん"],
"🏣": ["にっぽんのゆうびんきょく","たてもの","にっぽん","ぽすと"],
@ -1061,24 +1061,24 @@
"🏫": ["がっこう","たてもの"],
"🏩": ["らぶほてる","たてもの","ほてる","らぶ"],
"💒": ["けっこんしき","あくてぃびてぃ","ちゃぺる","ろまんす"],
"🏛": ["れきしてきなたてもの","たてもの","れきしてきな"],
"⛪": ["きょうかい","たてもの","くりすちゃん","じゅうじか","しゅうきょう"],
"🏛": ["れきしてきなたてもの","たてもの","れきしてきな"],
"⛪": ["きょうかい","たてもの","くりすちゃん","じゅうじか","しゅうきょう"],
"🕌": ["もすく","いすらむ","むすりむ","しゅうきょう"],
"🛕": ["ひんどぅーきょうじいん","ひんどぅーきょう","じいん","しゅうきょう"],
"🕍": ["しなごーぐ","ゆだやじん","ゆだやきょう","しゅうきょう","かいどう"],
"🕋": ["かあば","いすらむ","むすりむ","しゅうきょう"],
"⛩": ["じんじゃ","しゅうきょう","しんとう"],
"⌚": ["うでどけい","とけい"],
"⛩": ["じんじゃ","しゅうきょう","しんとう"],
"⌚": ["うでどけい","とけい"],
"📱": ["けいたいでんわ","けいたい","こみゅにけーしょん","もばいる","でんわ"],
"📲": ["ちゃくしんちゅう","やじるし","つうわ","けいたい","こみゅにけーしょん","もばいる","けいたいでんわ","じゅしん","でんわ"],
"💻": ["ぱそこん","のーとぱそこん","こんぴゅーたー","ぱーそなる"],
"⌨": ["きーぼーど","こんぴゅーたー"],
"🖥": ["ですくとっぷぱそこん","こんぴゅーたー","ですくとっぷ"],
"🖨": ["ぷりんたー","こんぴゅーたー"],
"🖱": ["3ぼたんまうす","3","ぼたん","こんぴゅーたー","まうす","さん"],
"🖲": ["とらっくぼーる","こんぴゅーたー"],
"🕹": ["じょいすてぃっく","えんたーていめんと","げーむ","びでおげーむ"],
"🗜": ["あっしゅく","つーる","けっかん"],
"⌨": ["きーぼーど","こんぴゅーたー"],
"🖥": ["ですくとっぷぱそこん","こんぴゅーたー","ですくとっぷ"],
"🖨": ["ぷりんたー","こんぴゅーたー"],
"🖱": ["3ぼたんまうす","3","ぼたん","こんぴゅーたー","まうす","さん"],
"🖲": ["とらっくぼーる","こんぴゅーたー"],
"🕹": ["じょいすてぃっく","えんたーていめんと","げーむ","びでおげーむ"],
"🗜": ["あっしゅく","つーる","けっかん"],
"💽": ["MD","ぱそこん","ひかりでぃすく","えんたーていめんと","みにでぃすく","こうがく"],
"💾": ["ふろっぴーでぃすく","こんぴゅーたー","でぃすく","ふろっぴー"],
"💿": ["CDでぃすく","ぶるーれい","CD","こんぴゅーたー","でぃすく","DVD","こうがく"],
@ -1088,23 +1088,23 @@
"📸": ["ふらっしゅをたいたかめら","かめら","ふらっしゅ","びでお"],
"📹": ["びでおかめら","かめら","えんたーていめんと","びでお"],
"🎥": ["びでおかめら","あくてぃびてぃ","かめら","しねま","えんたーていめんと","えいが"],
"📽": ["えいしゃき","しねま","ごらく","ふぃるむ","えいが","ぷろじぇくたー","びでお"],
"🎞": ["ふぃるむのふれーむ","しねま","えんたーていめんと","ふぃるむ","ふれーむ","えいが"],
"📽": ["えいしゃき","しねま","ごらく","ふぃるむ","えいが","ぷろじぇくたー","びでお"],
"🎞": ["ふぃるむのふれーむ","しねま","えんたーていめんと","ふぃるむ","ふれーむ","えいが"],
"📞": ["じゅわき","こみゅにけーしょん","でんわ","じゅしんき"],
"☎️": ["でんわ","けいたいでんわ"],
"📟": ["ぽけっとべる","こみゅにけーしょん","ぽけべる"],
"📠": ["FAX","こみゅにけーしょん; fAX"],
"📺": ["てれび","えんたーていめんと","TV","びでお"],
"📻": ["らじお","えんたーていめんと","びでお"],
"🎙": ["すたじおまいく","まいく","おんがく","すたじお"],
"🎚": ["ちょうせつばー","ちょうせつ","おんがく","ばー"],
"🎛": ["こんとろーるのぶ","こんとろーる","つまみ","おんがく"],
"⏱": ["すとっぷうぉっち","とけい"],
"⏲": ["たいまーとけい","とけい","たいまー"],
"🎙": ["すたじおまいく","まいく","おんがく","すたじお"],
"🎚": ["ちょうせつばー","ちょうせつ","おんがく","ばー"],
"🎛": ["こんとろーるのぶ","こんとろーる","つまみ","おんがく"],
"⏱": ["すとっぷうぉっち","とけい"],
"⏲": ["たいまーとけい","とけい","たいまー"],
"⏰": ["めざましとけい","あらーむ","とけい"],
"🕰": ["おきどけい","とけい"],
"🕰": ["おきどけい","とけい"],
"⏳": ["すなどけい","すな","たいまー"],
"⌛": ["すなどけい","すな","たいまー"],
"⌛": ["すなどけい","すな","たいまー"],
"🧮": ["そろばん","けいさん","かうんと","しゅうけいひょう","すうがく"],
"📡": ["えいせいあんてな","あんてな","こみゅにけーしょん","ぱらぼらあんてな","えいせい"],
"🔋": ["でんち","ばってりー","でんし","だかえねるぎー"],
@ -1112,10 +1112,10 @@
"🔌": ["こんせんと","でんき","ぷらぐ"],
"💡": ["でんきゅう","まんが","でんき","ひらめき","ひかり"],
"🔦": ["かいちゅうでんとう","でんき","ひかり","どうぐ","たいまつ"],
"🕯": ["ろうそく","ひかり"],
"🕯": ["ろうそく","ひかり"],
"🧯": ["しょうかき","しょうか","ひ","けす"],
"🗑": ["ごみばこ","ごみ","かん","びん"],
"🛢": ["どらむかん","どらむ","おいる"],
"🗑": ["ごみばこ","ごみ","かん","びん"],
"🛢": ["どらむかん","どらむ","おいる"],
"🛒": ["しょっぴんぐかーと","かーと","しょっぴんぐ","とろりー"],
"💸": ["はねのはえたおさつ","ぎんこう","しへい","せいきゅうしょ","どる","とぶ","おかね","はね"],
"💵": ["どるさつ","ぎんこう","しへい","おさつ","つうか","どる","おかね"],
@ -1128,20 +1128,20 @@
"🪪": ["みぶんしょうめいしょ","しかくじょうほう","ID","らいせんす","せきゅりてぃ"],
"🧾": ["りょうしゅうしょ","かいけい","ぼき","しょうこ","しょうめい"],
"💎": ["ほうせき","だいあもんど","じゅえる","ろまんす"],
"⚖": ["はかり","てんびん","こうせい","てんびんざ","ものさし","どうぐ","じゅうりょう","せいざ"],
"⚖": ["はかり","てんびん","こうせい","てんびんざ","ものさし","どうぐ","じゅうりょう","せいざ"],
"🦯": ["しろつえ","あくせしびりてぃ","めがふじゆう"],
"🧰": ["どうぐばこ","むね","せいびし","こうぐ"],
"🔧": ["れんち","どうぐ"],
"🪛": ["どらいばー","ねじ","こうぐ"],
"🔨": ["はんまー","どうぐ"],
"⚒": ["はんまーとつるはし","はんまー","つるはし","どうぐ"],
"🛠": ["はんまーとれんち","はんまー","どうぐ","れんち"],
"⛏": ["つるはし","さいくつ","どうぐ"],
"⚒": ["はんまーとつるはし","はんまー","つるはし","どうぐ"],
"🛠": ["はんまーとれんち","はんまー","どうぐ","れんち"],
"⛏": ["つるはし","さいくつ","どうぐ"],
"🪓": ["おの","たたきぎり","ておの","われる","もくざい","こうぐ"],
"🪚": ["もっこうようのこぎり","だいく","ざいもく","のこぎり","こうぐ"],
"🔩": ["なっととぼると","ぼると","なっと","どうぐ"],
"⚙": ["はぐるま","ぎあ","どうぐ"],
"⛓": ["くさり"],
"⚙": ["はぐるま","ぎあ","どうぐ"],
"⛓": ["くさり"],
"🪝": ["ふっく","わな","いかさま","ぺてん","ゆうわく","ふぃっしんぐ","つーる"],
"🪜": ["はしご","のぼる","よこぎ","だん","こうぐ"],
"🧱": ["れんが","ねんど","けんせつ","もるたる","かべ"],
@ -1151,13 +1151,13 @@
"🧨": ["ばくちく","だいなまいと","かやく","はなび"],
"💣": ["ばくだん"],
"🔪": ["ほうちょう","きっちんないふ","ちょうり","ないふ"],
"🗡": ["たんけん","ないふ"],
"⚔": ["こうさしたけん","こうさ","けん"],
"🛡": ["たて"],
"🗡": ["たんけん","ないふ"],
"⚔": ["こうさしたけん","こうさ","けん"],
"🛡": ["たて"],
"🚬": ["きつえんまーく","あくてぃびてぃ","きつえん"],
"⚰": ["かん","し"],
"⚰": ["かん","し"],
"🪦": ["はかいし","ぼち","し","ぼ","はかば","はろうぃーん"],
"⚱": ["こつつぼ","し","そうぎ"],
"⚱": ["こつつぼ","し","そうぎ"],
"🏺": ["あんふぉら","みずがめざ","りょうり","のみもの","みずさし","どうぐ","せいざ"],
"🔮": ["すいしょうだま","たま","すいしょう","おとぎばなし","ふぁんたじー","うらない","どうぐ"],
"🪄": ["まほうのつえ","まほう","ぼう","まじょ","まほうつかい"],
@ -1166,22 +1166,22 @@
"🪬": ["はむさ","おまもり","ふぁてぃま","て","めありー","みりあむ","ほご"],
"💈": ["りはつてんのかんばんばしら","りはつてん","とこや","さんぱつ","かんばんばしら"],
"🧲": ["じしゃく","あとらくしょん","ばてい"],
"⚗": ["じょうりゅうき","かがく","じっけん","どうぐ"],
"⚗": ["じょうりゅうき","かがく","じっけん","どうぐ"],
"🧪": ["しけんかん","かがくしゃ","かがく","じっけん","じっけんしつ"],
"🧫": ["ぺとりさら","ばくてりあ","せいぶつがくしゃ","せいぶつがく","ぶんか","じっけんしつ"],
"🧬": ["DNA","せいぶつがくしゃ","しんか","いでんし","いでんしがく","せいめい"],
"🔭": ["ぼうえんきょう","つーる"],
"🔬": ["けんびきょう","つーる"],
"🕳": ["あな"],
"🕳": ["あな"],
"🩻": ["Xせん","ほね","いし","いりょう","こっかく"],
"💊": ["くすり","いし","ぴる","びょうき"],
"💉": ["ちゅうしゃき","いし","くすり","ちゅうしゃはり","ちゅうしゃ","びょうき","どうぐ","わくちん"],
"🩸": ["ち1てき","いし","くすり","けつえき","せいり"],
"🩹": ["がーぜつきばんそうこう","いし","くすり","ばんどえいど","ほうたい","ばんそうこう"],
"🩺": ["ちょうしんき","いし","くすり","しんぞう"],
"🌡": ["おんどけい","てんき","おんど"],
"🌡": ["おんどけい","てんき","おんど"],
"🩼": ["まつばづえ","つえ","しょうがい","けが","いどうほじょ","ぼう"],
"🏷": ["らべる","にふだ"],
"🏷": ["らべる","にふだ"],
"🔖": ["ぶっくまーく","しおり","しるし"],
"🚽": ["といれ"],
"🪠": ["ぷらんじゃー","ふぉーすかっぷ","はいかんこう","きゅういん","といれ"],
@ -1200,24 +1200,24 @@
"🧺": ["ばすけっと","のうぎょう","らんどりー","ぴくにっく"],
"🪣": ["ばけつ","たる","ておけ","おおだる"],
"🔑": ["かぎ","じょう","ぱすわーど"],
"🗝": ["ふるいかぎ","かぎ","じょう","ふるい"],
"🗝": ["ふるいかぎ","かぎ","じょう","ふるい"],
"🪤": ["ねずみとりき","えさ","ねずみ","かじはどうぶつ","わなわ","わな"],
"🛋": ["そふぁーとらんぷ","そふぁー","ほてる","らんぷ"],
"🛋": ["そふぁーとらんぷ","そふぁー","ほてる","らんぷ"],
"🪑": ["いす","ざせき","すわる"],
"🛌": ["しゅくはくしせつ","ねる","ほてる","すいみん","べっど"],
"🛏": ["べっど","ほてる","すいみん"],
"🛏": ["べっど","ほてる","すいみん"],
"🚪": ["どあ","とびら"],
"🪞": ["かがみ","はんしゃ","はんしゃたい","はんしゃきょう"],
"🪟": ["まど","わく","しんせんなくうき","がらす","かいこうぶ","とうめい","しかい"],
"🧳": ["てにもつ","ぱっきんぐ","りょこう","すーつけーす"],
"🛎": ["たくじょうべる","べる","ほてる"],
"🖼": ["がくにはいったしゃしん","あーと","がくぶち","びじゅつかん","かいが","しゃしん"],
"🛎": ["たくじょうべる","べる","ほてる"],
"🖼": ["がくにはいったしゃしん","あーと","がくぶち","びじゅつかん","かいが","しゃしん"],
"🧭": ["こんぱす","じしゃく","なびげーしょん","おりえんてーりんぐ"],
"🗺": ["せかいちず","ちず","せかい"],
"⛱": ["たてられたぱらそる","あめ","はれ","かさ","てんき"],
"🗺": ["せかいちず","ちず","せかい"],
"⛱": ["たてられたぱらそる","あめ","はれ","かさ","てんき"],
"🪭": ["おりたたみせんす","れいきゃく","えんりょがち","だんす","ふぁん","ふらったー","ねつ","あつい","うちき","ひろがる"],
"🗿": ["もやいぞう","もあいぞう","かお","ぞう"],
"🛍": ["かいものぶくろ","かばん","ほてる","かいもの"],
"🛍": ["かいものぶくろ","かばん","ほてる","かいもの"],
"🎈": ["ふうせん","あくてぃびてぃ","おいわい","えんたーていめんと"],
"🎏": ["こいのぼり","あくてぃびてぃ","こい","おいわい","えんたーていめんと","はた","ふきながし"],
"🎀": ["りぼん","おいわい"],
@ -1255,17 +1255,17 @@
"📄": ["ぶんしょ","ぺーじ"],
"📅": ["かれんだー","ひづけ"],
"📆": ["ひめくりかれんだー","かれんだー"],
"🗓": ["りんぐかれんだー","かれんだー","ぱっど","らせんじょう"],
"🗓": ["りんぐかれんだー","かれんだー","ぱっど","らせんじょう"],
"📇": ["めいしふぉるだ","かーど","さくいん","ろーらでっくす"],
"🗃": ["かーどふぁいる","はこ","かーど","ふぁいる"],
"🗳": ["とうひょうようしととうひょうばこ","とうひょうようし","はこ","ひょう","とうひょう"],
"🗄": ["ふぁいるしゅうのうこ","しゅうのう","ふぁいる"],
"🗃": ["かーどふぁいる","はこ","かーど","ふぁいる"],
"🗳": ["とうひょうようしととうひょうばこ","とうひょうようし","はこ","ひょう","とうひょう"],
"🗄": ["ふぁいるしゅうのうこ","しゅうのう","ふぁいる"],
"📋": ["くりっぷぼーど"],
"🗒": ["りんぐのーと","のーと","ぱっど","らせんじょう"],
"🗒": ["りんぐのーと","のーと","ぱっど","らせんじょう"],
"📁": ["ふぉるだ","ふぁいる"],
"📂": ["ひらいたふぉるだ","ふぁいる","ふぉるだ","ひらいた"],
"🗂": ["しきりかーど","かーど","しきり","さくいん"],
"🗞": ["まるめたしんぶん","にゅーす","しんぶん","かみ","まるめた"],
"🗂": ["しきりかーど","かーど","しきり","さくいん"],
"🗞": ["まるめたしんぶん","にゅーす","しんぶん","かみ","まるめた"],
"📰": ["しんぶん","こみゅにけーしょん","にゅーす","かみ"],
"🪧": ["ぷらかーど","でも","しがらみ","こうぎ","かんばん"],
"📓": ["のーと"],
@ -1279,7 +1279,7 @@
"📖": ["ひらいたほん","ほん","ひらいた"],
"🔗": ["りんく"],
"📎": ["くりっぷ","ぺーぱーくりっぷ"],
"🖇": ["つながったぺーぱーくりっぷ","こみゅにけーしょん","りんく","ぺーぱーくりっぷ"],
"🖇": ["つながったぺーぱーくりっぷ","こみゅにけーしょん","りんく","ぺーぱーくりっぷ"],
"✂️": ["はさみ","どうぐ"],
"📐": ["さんかくじょうぎ","じょうぎ","はいち","さんかく"],
"📏": ["じょうぎ","ちょくじょうぎ"],
@ -1294,13 +1294,13 @@
"🔒": ["かぎ","とじられた","せじょう"],
"🔓": ["かいじょう","せじょう","あける"],
"🔏": ["じょうまえとぺん","いんく","じょう","ぺんさき","ぺん","ぷらいばしー"],
"🖊": ["ひだりしたむきのぼーるぺん","ぼーるぺん","こみゅにけーしょん","ぺん"],
"🖋": ["ひだりしたむきのまんねんひつ","こみゅにけーしょん","まんねんひつ","ぺん"],
"🖊": ["ひだりしたむきのぼーるぺん","ぼーるぺん","こみゅにけーしょん","ぺん"],
"🖋": ["ひだりしたむきのまんねんひつ","こみゅにけーしょん","まんねんひつ","ぺん"],
"✒️": ["ぺんさき","ぺん"],
"📝": ["めも","こみゅにけーしょん","えんぴつ"],
"✏️": ["えんぴつ"],
"🖍": ["ひだりしたむきのくれよん","こみゅにけーしょん","くれよん"],
"🖌": ["ひだりしたむきのぶらし","こみゅにけーしょん","ぺいんとぶらし","え"],
"🖍": ["ひだりしたむきのくれよん","こみゅにけーしょん","くれよん"],
"🖌": ["ひだりしたむきのぶらし","こみゅにけーしょん","ぺいんとぶらし","え"],
"🔍": ["ひだりむきむしめがね","めがね","かくだい","けんさく","つーる"],
"🔎": ["みぎむきむしめがね","めがね","かくだい","けんさく","つーる"],
"❤️": ["あかいろのはーと","はーと"],
@ -1313,7 +1313,7 @@
"🖤": ["くろいはーと","はーと","くろ","あく","わるもの"],
"🤍": ["しろのはーと","はーと","しろ"],
"💔": ["われたはーと","はーと","こわれる","はきょく"],
"❣": ["はーとのびっくりまーく","はーと","びっくりまーく","きごう"],
"❣": ["はーとのびっくりまーく","はーと","びっくりまーく","きごう"],
"💕": ["2つのはーと","はーと","あい"],
"💞": ["かいてんするはーと","はーと","かいてん"],
"💓": ["こどうするはーと","はーと","こどう","どきどき"],
@ -1324,40 +1324,40 @@
"❤️‍🔥": ["もえているはーと","はーと","ひ","もえる","あい","ねつじょう","しんせいなはーと"],
"❤️‍🩹": ["てあてしているはーと","はーと","けんこうになる","かいぜんしている","てあてしている","かいふくしている","やみあがり","げんき"],
"💟": ["はーとのでこれーしょん","はーと"],
"☮": ["ぴーすまーく","へいわ"],
"✝": ["らてんじゅうじ","くりすちゃん","じゅうじか","しゅうきょう"],
"☪": ["ほしとみかづき","いすらむ","むすりむ","しゅうきょう"],
"🕉": ["おーむまーく","ひんどぅーきょう","おーむ","しゅうきょう"],
"☸": ["ほうりん","ぶっきょうと","だーま","しゅうきょう"],
"✡": ["だびでのほし","だびで","ゆだやじん","ゆだやきょう","しゅうきょう","ほし"],
"☮": ["ぴーすまーく","へいわ"],
"✝": ["らてんじゅうじ","くりすちゃん","じゅうじか","しゅうきょう"],
"☪": ["ほしとみかづき","いすらむ","むすりむ","しゅうきょう"],
"🕉": ["おーむまーく","ひんどぅーきょう","おーむ","しゅうきょう"],
"☸": ["ほうりん","ぶっきょうと","だーま","しゅうきょう"],
"✡": ["だびでのほし","だびで","ゆだやじん","ゆだやきょう","しゅうきょう","ほし"],
"🔯": ["ろくぼうせい","うらない","ほし"],
"🕎": ["はぬっきーやー","しょくだい","めのーらー","しゅうきょう"],
"☯": ["いんよう","しゅうきょう","どう","どうか","ひ","かげ"],
"☦": ["はったんじゅうじか","くりすちゃん","じゅうじか","しゅうきょう"],
"☯": ["いんよう","しゅうきょう","どう","どうか","ひ","かげ"],
"☦": ["はったんじゅうじか","くりすちゃん","じゅうじか","しゅうきょう"],
"🪯": ["かんだ","しゅうきょう","しーくきょうと"],
"🛐": ["れいはいしょ","しゅうきょう","れいはい"],
"⛎": ["へびつかいざ","うんぱんにん","へび","せいざ"],
"♈": ["おひつじざ","こひつじ","せいざ"],
"♉": ["おうしざ","おすうし","ゆううし","せいざ"],
"♊": ["ふたござ","ふたご","せいざ"],
"♋": ["がん","かにざ","かに","せいざ"],
"♌": ["ししざ","らいおん","せいざ"],
"♍": ["おとめざ","おとめ","しょじょ","せいざ"],
"♎": ["てんびんざ","てんびん","こうせい","はかり","せいざ"],
"♏": ["さそりざ","さそり","せいざ"],
"♐": ["いてざ","しゃしゅ","しゃしゅざ","せいざ"],
"♑": ["やぎざ","やぎ","せいざ"],
"♒": ["みずがめざ","うんぱんじん","みず","せいざ"],
"♓": ["うおざ","さかな","せいざ"],
"♈": ["おひつじざ","こひつじ","せいざ"],
"♉": ["おうしざ","おすうし","ゆううし","せいざ"],
"♊": ["ふたござ","ふたご","せいざ"],
"♋": ["がん","かにざ","かに","せいざ"],
"♌": ["ししざ","らいおん","せいざ"],
"♍": ["おとめざ","おとめ","しょじょ","せいざ"],
"♎": ["てんびんざ","てんびん","こうせい","はかり","せいざ"],
"♏": ["さそりざ","さそり","せいざ"],
"♐": ["いてざ","しゃしゅ","しゃしゅざ","せいざ"],
"♑": ["やぎざ","やぎ","せいざ"],
"♒": ["みずがめざ","うんぱんじん","みず","せいざ"],
"♓": ["うおざ","さかな","せいざ"],
"🆔": ["しかくかこみID","ID","しきべつ"],
"⚛": ["げんそきごう","むしんろんしゃ","げんし"],
"⚛": ["げんそきごう","むしんろんしゃ","げんし"],
"⚕️": ["あすくれぴおすのつえ","けんこう","せわ","いし","くすり","つえ","へび"],
"☢": ["ほうしゃのうひょうしき","ほうしゃのう"],
"☣": ["ばいおはざーどひょうしき","せいぶつさいがい"],
"☢": ["ほうしゃのうひょうしき","ほうしゃのう"],
"☣": ["ばいおはざーどひょうしき","せいぶつさいがい"],
"📴": ["けいたいでんわでんげんおふ","けいたい","こみゅにけーしょん","もばいる","おふ","けいたいでんわ","でんわ"],
"📳": ["まなーもーど","けいたい","こみゅにけーしょん","もばいる","もーど","けいたいでんわ","でんわ","ばいぶれーしょん"],
"🈶": ["しかくかこみゆう","にほんご","あり"],
"🈚": ["しかくかこみむ","しかくかこみいな","にほんご","なし"],
"🈚": ["しかくかこみむ","しかくかこみいな","にほんご","なし"],
"🈸": ["しかくかこみしん","しかくかこみてき","ちゅうごくご","しんせい"],
"🈺": ["しかくかこみえい","ちゅうごくご","えいぎょう"],
"🈷️": ["しかくかこみつき","にほんご","つきぎめ"],
@ -1378,11 +1378,11 @@
"🆑": ["しかくかこみCL","CL"],
"🅾️": ["くろしかくかこみO","けつえきがた","O"],
"🆘": ["しかくかこみSOS","へるぷ","SOS"],
"⛔": ["たちいりきんし","たちいり","きんし","だめ","できない","きんじる","こうつう"],
"⛔": ["たちいりきんし","たちいり","きんし","だめ","できない","きんじる","こうつう"],
"📛": ["なふだ","ばっじ","なまえ"],
"🚫": ["しんにゅうきんし","たちいり","きんし","だめ","できない","きんじる"],
"❌": ["ばつしるし","きゃんせる","きごう","かけざん","じょうざん","x"],
"⭕": ["ふといおおきなまる","まる","O"],
"⭕": ["ふといおおきなまる","まる","O"],
"💢": ["いかりまーく","いかり","まんが","げきど"],
"♨️": ["おんせん","あたたかい","わきでる","じょうき"],
"🚷": ["ほこうしゃたちいりきんし","きんし","だめ","ない","ほこうしゃ","きんじる"],
@ -1392,7 +1392,7 @@
"🔞": ["18さいみまんきんし","18","ねんれいせいげん","じゅうはち","きんし","だめ","ない","きんしした","みせいねんしゃ"],
"📵": ["けいたいでんわきんし","けいたい","つうしん","きんし","もばいる","だめ","できない","けいたいでんわ","きんしされている","でんわ"],
"🚭": ["きんえん","きんし","だめ","できない","きんしされている","きつえん"],
"❗": ["あかいびっくりまーく","びっくり","まーく","きごう"],
"❗": ["あかいびっくりまーく","びっくり","まーく","きごう"],
"❕": ["しろいびっくりまーく","びっくり","まーく","かこみ","きごう"],
"❓": ["あかいはてなまーく","まーく","きごう","はてな"],
"❔": ["しろいはてなまーく","まーく","かこみ","きごう","はてな"],
@ -1402,13 +1402,13 @@
"🔅": ["ていきど","あかるさ","うすぐらい","てい"],
"🔆": ["こうきど","あかるい","あかるさ"],
"🔱": ["とらいでんと","いかり","えんぶれむ","ふね","こうぐ"],
"⚜": ["ゆりのもんしょう"],
"⚜": ["ゆりのもんしょう"],
"〽️": ["いおりてん","しるし","ぶぶん"],
"⚠️": ["けいこく"],
"🚸": ["こうさてんをわたるこどもたち","こども","こうさてん","ほこうしゃ","こうつう"],
"🔰": ["しょしんしゃまーく","しょしんしゃ","まーく","みどり","にっぽん","わかば","どうぐ","き"],
"♻️": ["りさいくるまーく","りさいくる"],
"🈯": ["しかくかこみゆび","にほんご"],
"🈯": ["しかくかこみゆび","にほんご"],
"💹": ["じょうしょうとれんどのちゃーととえんきごう","じょうしょうちゅうえんちゃーと","ぎんこう","ちゃーと","つうか","ぐらふ","せいちょう","しじょう","おかね","じょうしょう","とれんど","うわむき","えん"],
"❇️": ["きらきら"],
"✳️": ["あすたりすく (8ほんこうせい)","あすたりすく"],
@ -1422,7 +1422,7 @@
"Ⓜ️": ["まるかこみM","えん","M"],
"🏧": ["ATM","ATMきごう","じどう","ぎんこう","すいとう"],
"🚾": ["といれ","けしょうしつ","おてあらい","みず","WC"],
"♿": ["くるまいす","あくせす"],
"♿": ["くるまいす","あくせす"],
"🅿️": ["くろしかくかこみP","ちゅうしゃじょう"],
"🈳": ["しかくかこみそら","しかくかこみのそら","ちゅうごくご","そらしつ","あき","くうしゃ"],
"🈂️": ["しかくかこみさ","にっぽんじん","さーびす"],
@ -1450,26 +1450,26 @@
"🆒": ["COOL","かっこいい","くーる"],
"🆕": ["しかくかこみnew","しん"],
"🆓": ["しかくかこみFREE","ふりー","むりょう"],
"0⃣": ["0きー","0","きー","ぜろ"],
"1⃣": ["1きー","いち","きー"],
"2⃣": ["2きー","2","きー","に"],
"3⃣": ["3きー","3","きー","さん"],
"4⃣": ["4きー","4","よん","きー"],
"5⃣": ["5きー","5","ご","きー"],
"6⃣": ["6きー","6","きー","ろく"],
"7⃣": ["7きー","7","きー","なな"],
"8⃣": ["8きー","8","はち","きー"],
"9⃣": ["9きー","9","きー","きゅう"],
"0⃣": ["0きー","0","きー","ぜろ"],
"1⃣": ["1きー","いち","きー"],
"2⃣": ["2きー","2","きー","に"],
"3⃣": ["3きー","3","きー","さん"],
"4⃣": ["4きー","4","よん","きー"],
"5⃣": ["5きー","5","ご","きー"],
"6⃣": ["6きー","6","きー","ろく"],
"7⃣": ["7きー","7","きー","なな"],
"8⃣": ["8きー","8","はち","きー"],
"9⃣": ["9きー","9","きー","きゅう"],
"🔟": ["10きー","10","きー","じゅう"],
"🔢": ["ばんごうのにゅうりょくきごう","1234","にゅうりょく","すうじ"],
"▶️": ["みぎむきさんかく","さいせいぼたん","やじるし","さいせい","みぎ","さんかっけい"],
"⏸": ["2ほんのすいちょくばー","いちじていしぼたん","ばー","2ばい","いちじていし","すいちょく"],
"⏯": ["みぎむきのさんかっけいとにじゅうすいちょくぼう","さいせいまたはいちじていしぼたん","やじるし","いちじていし","さいせい","みぎ","さんかっけい"],
"⏹": ["ていし","ていしぼたん","しかく"],
"⏺": ["ろくが","ろくがぼたん","まる"],
"⏸": ["2ほんのすいちょくばー","いちじていしぼたん","ばー","2ばい","いちじていし","すいちょく"],
"⏯": ["みぎむきのさんかっけいとにじゅうすいちょくぼう","さいせいまたはいちじていしぼたん","やじるし","いちじていし","さいせい","みぎ","さんかっけい"],
"⏹": ["ていし","ていしぼたん","しかく"],
"⏺": ["ろくが","ろくがぼたん","まる"],
"⏏️": ["とりだしまーく","とりだしぼたん"],
"⏭": ["みぎむきのにじゅうさんかっけいとすいちょくぼう","「つぎのきょく」ぼたん","やじるし","つぎのばめん","つぎのきょく","さんかっけい"],
"⏮": ["ひだりむきのにじゅうさんかっけいとすいちょくぼう","「まえのきょく」ぼたん","やじるし","まえのばめん","まえのきょく","さんかっけい"],
"⏭": ["みぎむきのにじゅうさんかっけいとすいちょくぼう","「つぎのきょく」ぼたん","やじるし","つぎのばめん","つぎのきょく","さんかっけい"],
"⏮": ["ひだりむきのにじゅうさんかっけいとすいちょくぼう","「まえのきょく」ぼたん","やじるし","まえのばめん","まえのきょく","さんかっけい"],
"⏩": ["みぎむきのにじゅうさんかっけい","はやおくりぼたん","やじるし","2ばい","こうそく","すすむ"],
"⏪": ["ひだりむきのにじゅうさんかっけい","はやもどしぼたん","やじるし","2ばい","まきもどし"],
"🔀": ["ねじりみぎむきやじるしのえもじ","しゃっふる","やじるし","こうさ"],
@ -1496,7 +1496,7 @@
"🔃": ["るーぷやじるし","とけいのはり","やじるし","とけいまわり","りろーど"],
"⤴️": ["みぎうえへかーぶするやじるし","うえへかーぶするみぎやじるし","やじるし"],
"⤵️": ["みぎしたへかーぶするやじるし","したにかーぶするみぎやじるし","やじるし","した"],
"#⃣": ["#きー","はっしゅ","きー","ぽんど"],
"#⃣": ["#きー","はっしゅ","きー","ぽんど"],
"*⃣": ["あすたりすくきー","あすたりすく","きー","ほし"],
"": ["じょうほうげん","i","いんふぉめーしょん"],
"🔤": ["あるふぁべっとにゅうりょく","abc","あるふぁべっと","にゅうりょく","らてん","もじ"],
@ -1532,8 +1532,8 @@
"🔵": ["あおまる","あお","えん","きかがく"],
"🟣": ["むらさきのまる","えん","きかがく","むらさき"],
"🟤": ["ちゃいろのまる","えん","きかがく","ちゃいろ"],
"⚫": ["くろまる","えん","きかがく"],
"⚪": ["しろまる","えん","きかがく"],
"⚫": ["くろまる","えん","きかがく"],
"⚪": ["しろまる","えん","きかがく"],
"🟥": ["あかのせいほうけい","せいほうけい","きかがく","あか"],
"🟧": ["おれんじしょくのせいほうけい","せいほうけい","きかがく","おれんじ"],
"🟨": ["きいろのせいほうけい","せいほうけい","きかがく","きいろ"],
@ -1541,12 +1541,12 @@
"🟦": ["あおのせいほうけい","せいほうけい","きかがく","あお"],
"🟪": ["むらさきのせいほうけい","せいほうけい","きかがく","むらさき"],
"🟫": ["ちゃいろのせいほうけい","せいほうけい","きかがく","ちゃいろ"],
"⬛": ["くろいおおきなしかく","きかがく","せいほうけい"],
"⬜": ["しろいおおきなしかく","きかがく","せいほうけい"],
"⬛": ["くろいおおきなしかく","きかがく","せいほうけい"],
"⬜": ["しろいおおきなしかく","きかがく","せいほうけい"],
"◼️": ["くろいちゅうくらいのしかく","きかがく","せいほうけい"],
"◻️": ["しろくてちゅうくらいのしかく","きかがく","せいほうけい"],
"◾": ["くろくてちゅうくらいのちいさいしかく","きかがく","せいほうけい"],
"◽": ["しろいちゅうくらいのちいさなしかく","きかがく","せいほうけい"],
"◾": ["くろくてちゅうくらいのちいさいしかく","きかがく","せいほうけい"],
"◽": ["しろいちゅうくらいのちいさなしかく","きかがく","せいほうけい"],
"▪️": ["くろいちいさなしかく","きかがく","せいほうけい"],
"▫️": ["しろいちいさなしかく","きかがく","せいほうけい"],
"🔸": ["ちいさいおれんじのだいやもんど","だいやもんど","きかがく","おれんじ"],
@ -1566,16 +1566,16 @@
"🔔": ["べる"],
"🔕": ["みゅーと","すらっしゅべる","かね","きんじられた","だめ","ない","きんし","しずか"],
"🃏": ["とらんぷのじょーかー","かーど","えんたーていめんと","げーむ","じょーかー","ぷれい"],
"🀄": ["まーじゃんぱいのちゅう","げーむ","まーじゃん","あか"],
"🀄": ["まーじゃんぱいのちゅう","げーむ","まーじゃん","あか"],
"♠️": ["とらんぷのすぺーど","かーど","げーむ","すぺーど","すーつ"],
"♣️": ["とらんぷのくらぶ","かーど","くらぶ","げーむ","すーつ"],
"♥️": ["とらんぷのはーと","かーど","げーむ","はーと","すーつ"],
"♦️": ["とらんぷのだいや","かーど","だいや","だいやもんど","げーむ","すーつ"],
"🎴": ["はなふだ","あくてぃびてぃ","かーど","えんたーていめんと","はな","げーむ","にっぽん","ぷれい"],
"👁‍🗨": ["ふきだしのめ","ふきだし","め","すぴーち","しょうにん"],
"🗨": ["ひだりむきのふきだし","せりふ","すぴーち"],
"🗨": ["ひだりむきのふきだし","せりふ","すぴーち"],
"💭": ["かんがえふきだし","ふきだし","あわ","まんが","かんがえ"],
"🗯": ["みぎむきのいかりのふきだし","いかり","ふきだし","あわ","げきど"],
"🗯": ["みぎむきのいかりのふきだし","いかり","ふきだし","あわ","げきど"],
"💬": ["ふきだし","あわ","まんが","せりふ","すぴーち"],
"🕐": ["1じ","0ふん","1","とけい","とき","いち"],
"🕑": ["2じ","0ふん","2","とけい","とき","に"],
@ -1601,7 +1601,7 @@
"🕥": ["10じはん","10じ","はん","じこく","じゅう","30"],
"🕦": ["11じはん","11じ","はん","じこく","じゅういち","30"],
"🕧": ["12じはん","12じ","はん","じこく","30","じゅうに"],
"🏳": ["なびくしろはた","はた","なびく"],
"🏳": ["なびくしろはた","はた","なびく"],
"🏴": ["なびくくろはた","はた","なびく"],
"🏁": ["ちぇっかーふらっぐ","いちまつもよう","はた","れーす"],
"🚩": ["さんかくはた","はた","ぽすと"],
@ -1861,5 +1861,6 @@
"🇾🇹": ["まよっとのはた","こっき","まよっと"],
"🇿🇦": ["みなみあふりかこっき","こっき","みなみ","みなみあふりか"],
"🇿🇲": ["ざんびあこっき","こっき","ざんびあ"],
"🇿🇼": ["じんばぶえこっき","こっき","じんばぶえ"]
}
"🇿🇼": ["じんばぶえこっき","こっき","じんばぶえ"],
"": ["しぶや109", "SHIBUYA109", "109"]
}

View File

@ -1,6 +1,6 @@
/*
* version: 2023.12.2
* generatedAt: 2024-01-20T04:59:59.768Z
* generatedAt: 2024-01-21T01:01:12.332Z
*/
import type { SwitchCaseResponseType } from '../api.js';

View File

@ -1,6 +1,6 @@
/*
* version: 2023.12.2
* generatedAt: 2024-01-20T04:59:59.766Z
* generatedAt: 2024-01-21T01:01:12.330Z
*/
import type {

View File

@ -1,6 +1,6 @@
/*
* version: 2023.12.2
* generatedAt: 2024-01-20T04:59:59.765Z
* generatedAt: 2024-01-21T01:01:12.328Z
*/
import { operations } from './types.js';

View File

@ -1,6 +1,6 @@
/*
* version: 2023.12.2
* generatedAt: 2024-01-20T04:59:59.764Z
* generatedAt: 2024-01-21T01:01:12.327Z
*/
import { components } from './types.js';

View File

@ -3,7 +3,7 @@
/*
* version: 2023.12.2
* generatedAt: 2024-01-20T04:59:59.681Z
* generatedAt: 2024-01-21T01:01:12.246Z
*/
/**
@ -4465,6 +4465,8 @@ export type components = {
createdAt: string;
/** Format: date-time */
startedAt: string | null;
/** Format: date-time */
endedAt: string | null;
isStarted: boolean;
isEnded: boolean;
form1: Record<string, never> | null;
@ -4481,12 +4483,15 @@ export type components = {
winnerId: string | null;
winner: components['schemas']['User'] | null;
/** Format: id */
surrendered: string | null;
surrenderedUserId: string | null;
/** Format: id */
timeoutUserId: string | null;
black: number | null;
bw: string;
isLlotheo: boolean;
canPutEverywhere: boolean;
loopedBoard: boolean;
timeLimitForEachTurn: number;
};
ReversiGameDetailed: {
/** Format: id */
@ -4495,6 +4500,8 @@ export type components = {
createdAt: string;
/** Format: date-time */
startedAt: string | null;
/** Format: date-time */
endedAt: string | null;
isStarted: boolean;
isEnded: boolean;
form1: Record<string, never> | null;
@ -4511,12 +4518,15 @@ export type components = {
winnerId: string | null;
winner: components['schemas']['User'] | null;
/** Format: id */
surrendered: string | null;
surrenderedUserId: string | null;
/** Format: id */
timeoutUserId: string | null;
black: number | null;
bw: string;
isLlotheo: boolean;
canPutEverywhere: boolean;
loopedBoard: boolean;
timeLimitForEachTurn: number;
logs: unknown[][];
map: string[];
};

View File

@ -6,6 +6,7 @@
import { get } from 'idb-keyval';
import * as Misskey from 'misskey-js';
import type { PushNotificationDataMap } from '@/types.js';
import type { I18n, Locale } from '@/scripts/i18n.js';
import { createEmptyNotification, createNotification } from '@/scripts/create-notification.js';
import { swLang } from '@/scripts/lang.js';
import * as swos from '@/scripts/operations.js';
@ -26,8 +27,15 @@ globalThis.addEventListener('activate', ev => {
);
});
function offlineContentHTML(): string {
return `<!doctype html>Offline. Service Worker @${_VERSION_} <button onclick="location.reload()">reload</button>`;
async function offlineContentHTML() {
const i18n = await (swLang.i18n ?? swLang.fetchLocale()) as Partial<I18n<Locale>>;
const messages = {
title: i18n.ts?._offlineScreen?.title ?? 'Offline - Could not connect to server',
header: i18n.ts?._offlineScreen?.header ?? 'Could not connect to server',
reload: i18n.ts?.reload ?? 'Reload',
};
return `<!DOCTYPE html><html lang="ja"><head><meta charset="UTF-8"><meta content="width=device-width,initial-scale=1"name="viewport"><title>${messages.title}</title><style>body{background-color:#0c1210;color:#dee7e4;font-family:Hiragino Maru Gothic Pro,BIZ UDGothic,Roboto,HelveticaNeue,Arial,sans-serif;line-height:1.35;display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100vh;margin:0;padding:24px;box-sizing:border-box}.icon{max-width:120px;width:100%;height:auto;margin-bottom:20px;}.message{text-align:center;font-size:20px;font-weight:700;margin-bottom:20px}.version{text-align:center;font-size:90%;margin-bottom:20px}button{padding:7px 14px;min-width:100px;font-weight:700;font-family:Hiragino Maru Gothic Pro,BIZ UDGothic,Roboto,HelveticaNeue,Arial,sans-serif;line-height:1.35;border-radius:99rem;background-color:#b4e900;color:#192320;border:none;cursor:pointer;-webkit-tap-highlight-color:transparent}button:hover{background-color:#c6ff03}</style></head><body><svg class="icon"fill="none"height="24"stroke="currentColor"stroke-linecap="round"stroke-linejoin="round"stroke-width="2"viewBox="0 0 24 24"width="24"xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z"fill="none"stroke="none"/><path d="M9.58 5.548c.24 -.11 .492 -.207 .752 -.286c1.88 -.572 3.956 -.193 5.444 1c1.488 1.19 2.162 3.007 1.77 4.769h.99c1.913 0 3.464 1.56 3.464 3.486c0 .957 -.383 1.824 -1.003 2.454m-2.997 1.033h-11.343c-2.572 -.004 -4.657 -2.011 -4.657 -4.487c0 -2.475 2.085 -4.482 4.657 -4.482c.13 -.582 .37 -1.128 .7 -1.62"/><path d="M3 3l18 18"/></svg><div class="message">${messages.header}</div><div class="version">v${_VERSION_}</div><button onclick="reloadPage()">${messages.reload}</button><script>function reloadPage(){location.reload(!0)}</script></body></html>`;
}
globalThis.addEventListener('fetch', ev => {
@ -43,8 +51,9 @@ globalThis.addEventListener('fetch', ev => {
if (!isHTMLRequest) return;
ev.respondWith(
fetch(ev.request)
.catch(() => {
return new Response(offlineContentHTML(), {
.catch(async () => {
const html = await offlineContentHTML();
return new Response(html, {
status: 200,
headers: {
'content-type': 'text/html',