From 8272118e2945be46d19d098befcfcf5bb1dfbcc3 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Fri, 3 Aug 2018 23:01:55 +0900
Subject: [PATCH 01/94] typo

---
 locales/ja.yml                                                  | 2 +-
 .../app/common/views/components/games/reversi/reversi.room.vue  | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/locales/ja.yml b/locales/ja.yml
index 4cbee25128..9760f976ae 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -209,7 +209,7 @@ common/views/components/games/reversi/reversi.room.vue:
   looped-map: "ループマップ"
   can-put-everywhere: "どこでも置けるモード"
   settings-of-the-bot: "Botの設定"
-  this-gane-is-started-soon: "ゲームは数秒後に開始されます"
+  this-game-is-started-soon: "ゲームは数秒後に開始されます"
   waiting-for-other: "相手の準備が完了するのを待っています"
   waiting-for-me: "あなたの準備が完了するのを待っています"
   waiting-for-both: "準備中"
diff --git a/src/client/app/common/views/components/games/reversi/reversi.room.vue b/src/client/app/common/views/components/games/reversi/reversi.room.vue
index de5040f630..f925a45f62 100644
--- a/src/client/app/common/views/components/games/reversi/reversi.room.vue
+++ b/src/client/app/common/views/components/games/reversi/reversi.room.vue
@@ -93,7 +93,7 @@
 
 	<footer>
 		<p class="status">
-			<template v-if="isAccepted && isOpAccepted">%i18n:@this-gane-is-started-soon%<mk-ellipsis/></template>
+			<template v-if="isAccepted && isOpAccepted">%i18n:@this-game-is-started-soon%<mk-ellipsis/></template>
 			<template v-if="isAccepted && !isOpAccepted">%i18n:@waiting-for-other%<mk-ellipsis/></template>
 			<template v-if="!isAccepted && isOpAccepted">%i18n:@waiting-for-me%</template>
 			<template v-if="!isAccepted && !isOpAccepted">%i18n:@waiting-for-both%<mk-ellipsis/></template>

From 42fbc7ab668319563374c7810d0b20a2fa0a71c7 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Fri, 3 Aug 2018 23:06:58 +0900
Subject: [PATCH 02/94] Fix #2047

---
 src/client/app/desktop/views/widgets/polls.vue | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/client/app/desktop/views/widgets/polls.vue b/src/client/app/desktop/views/widgets/polls.vue
index 7421a81102..8ff0bb5d0d 100644
--- a/src/client/app/desktop/views/widgets/polls.vue
+++ b/src/client/app/desktop/views/widgets/polls.vue
@@ -6,8 +6,8 @@
 
 		<div class="mkw-polls--body" :data-darkmode="$store.state.device.darkmode">
 			<div class="poll" v-if="!fetching && poll != null">
-				<p v-if="poll.text"><router-link to="poll | notePage">{{ poll.text }}</router-link></p>
-				<p v-if="!poll.text"><router-link to="poll | notePage">%fa:link%</router-link></p>
+				<p v-if="poll.text"><router-link :to="poll | notePage">{{ poll.text }}</router-link></p>
+				<p v-if="!poll.text"><router-link :to="poll | notePage">%fa:link%</router-link></p>
 				<mk-poll :note="poll"/>
 			</div>
 			<p class="empty" v-if="!fetching && poll == null">%i18n:@nothing%</p>

From d456e5e45c8a2367c9362b1e1d1e87d6959b6977 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Fri, 3 Aug 2018 23:27:37 +0900
Subject: [PATCH 03/94] Implement new MFM syntax

---
 .../components/misskey-flavored-markdown.ts   | 13 +++++++++++-
 src/mfm/html.ts                               |  6 ++++++
 src/mfm/parse/elements/big.ts                 | 20 +++++++++++++++++++
 src/mfm/parse/index.ts                        |  3 +++
 test/mfm.ts                                   |  8 ++++++++
 5 files changed, 49 insertions(+), 1 deletion(-)
 create mode 100644 src/mfm/parse/elements/big.ts

diff --git a/src/client/app/common/views/components/misskey-flavored-markdown.ts b/src/client/app/common/views/components/misskey-flavored-markdown.ts
index 1480c0325c..096ffcbf8a 100644
--- a/src/client/app/common/views/components/misskey-flavored-markdown.ts
+++ b/src/client/app/common/views/components/misskey-flavored-markdown.ts
@@ -56,7 +56,18 @@ export default Vue.component('misskey-flavored-markdown', {
 					}
 
 				case 'bold':
-					return createElement('strong', token.bold);
+					return createElement('b', token.bold);
+
+				case 'big':
+					return (createElement as any)('strong', {
+						attrs: {
+							style: 'display: inline-block; font-size: 200%;'
+						},
+						directives: [{
+							name: 'animate-css',
+							value: { classes: 'tada', iteration: 'infinite' }
+						}]
+					}, token.big);
 
 				case 'url':
 					return createElement(MkUrl, {
diff --git a/src/mfm/html.ts b/src/mfm/html.ts
index 71b4739476..eeaa4d8136 100644
--- a/src/mfm/html.ts
+++ b/src/mfm/html.ts
@@ -11,6 +11,12 @@ const handlers: { [key: string]: (window: any, token: any, mentionedRemoteUsers:
 		document.body.appendChild(b);
 	},
 
+	big({ document }, { big }) {
+		const b = document.createElement('strong');
+		b.textContent = big;
+		document.body.appendChild(b);
+	},
+
 	code({ document }, { code }) {
 		const pre = document.createElement('pre');
 		const inner = document.createElement('code');
diff --git a/src/mfm/parse/elements/big.ts b/src/mfm/parse/elements/big.ts
new file mode 100644
index 0000000000..ca798986e9
--- /dev/null
+++ b/src/mfm/parse/elements/big.ts
@@ -0,0 +1,20 @@
+/**
+ * Bold
+ */
+
+export type TextElementBig = {
+	type: 'big'
+	content: string
+	big: string
+};
+
+export default function(text: string) {
+	const match = text.match(/^\*\*\*(.+?)\*\*\*/);
+	if (!match) return null;
+	const big = match[0];
+	return {
+		type: 'big',
+		content: big,
+		big: match[1]
+	} as TextElementBig;
+}
diff --git a/src/mfm/parse/index.ts b/src/mfm/parse/index.ts
index 8d71409e58..066c062559 100644
--- a/src/mfm/parse/index.ts
+++ b/src/mfm/parse/index.ts
@@ -3,6 +3,7 @@
  */
 
 import { TextElementBold } from './elements/bold';
+import { TextElementBig } from './elements/big';
 import { TextElementCode } from './elements/code';
 import { TextElementEmoji } from './elements/emoji';
 import { TextElementHashtag } from './elements/hashtag';
@@ -15,6 +16,7 @@ import { TextElementTitle } from './elements/title';
 import { TextElementUrl } from './elements/url';
 
 const elements = [
+	require('./elements/big'),
 	require('./elements/bold'),
 	require('./elements/title'),
 	require('./elements/url'),
@@ -30,6 +32,7 @@ const elements = [
 
 export type TextElement = { type: 'text', content: string }
 	| TextElementBold
+	| TextElementBig
 	| TextElementCode
 	| TextElementEmoji
 	| TextElementHashtag
diff --git a/test/mfm.ts b/test/mfm.ts
index df0f0be045..1a22e1491b 100644
--- a/test/mfm.ts
+++ b/test/mfm.ts
@@ -31,6 +31,14 @@ describe('Text', () => {
 			], tokens);
 		});
 
+		it('big', () => {
+			const tokens = analyze('***Strawberry*** Pasta');
+			assert.deepEqual([
+				{ type: 'big', content: '***Strawberry***', bold: 'Strawberry' },
+				{ type: 'text', content: ' Pasta' }
+			], tokens);
+		});
+
 		it('mention', () => {
 			const tokens = analyze('@himawari お腹ペコい');
 			assert.deepEqual([

From ce395e626f810ada7e0907c414851f58c41a9703 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Fri, 3 Aug 2018 23:28:24 +0900
Subject: [PATCH 04/94] 5.11.0

---
 package.json | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 54bf473e52..6203170489 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "5.10.0",
-	"clientVersion": "1.0.7828",
+	"version": "5.11.0",
+	"clientVersion": "1.0.7938",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,

From b13f42645be527d19d4cfc6d2fc4d5644d4f24ed Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 4 Aug 2018 01:03:48 +0900
Subject: [PATCH 05/94] Fix bug

---
 .../components/games/reversi/reversi.vue      | 33 ++++++++++++-------
 1 file changed, 21 insertions(+), 12 deletions(-)

diff --git a/src/client/app/common/views/components/games/reversi/reversi.vue b/src/client/app/common/views/components/games/reversi/reversi.vue
index 94431845b0..4b84e4562f 100644
--- a/src/client/app/common/views/components/games/reversi/reversi.vue
+++ b/src/client/app/common/views/components/games/reversi/reversi.vue
@@ -9,6 +9,9 @@
 			<form-button round @click="cancel">%i18n:@matching.cancel%</form-button>
 		</div>
 	</div>
+	<div v-if="gameId">
+		...
+	</div>
 	<div class="index" v-else>
 		<x-index @go="nav" @matching="onMatching"/>
 	</div>
@@ -45,22 +48,14 @@ export default Vue.extend({
 	},
 
 	watch: {
-		gameId(id) {
-			if (id == null) {
-				this.game = null;
-			} else {
-				Progress.start();
-				(this as any).api('games/reversi/games/show', {
-					gameId: id
-				}).then(game => {
-					this.nav(game, true);
-					Progress.done();
-				});
-			}
+		gameId() {
+			this.fetch();
 		}
 	},
 
 	mounted() {
+		this.fetch();
+
 		if (this.$store.getters.isSignedIn) {
 			this.connection = (this as any).os.streams.reversiStream.getConnection();
 			this.connectionId = (this as any).os.streams.reversiStream.use();
@@ -88,6 +83,20 @@ export default Vue.extend({
 	},
 
 	methods: {
+		fetch() {
+			if (this.gameId == null) {
+				this.game = null;
+			} else {
+				Progress.start();
+				(this as any).api('games/reversi/games/show', {
+					gameId: this.gameId
+				}).then(game => {
+					this.nav(game, true);
+					Progress.done();
+				});
+			}
+		},
+
 		nav(game, silent) {
 			this.matching = null;
 			this.game = game;

From 420164c59a138385c448f1944512ab8c69f163c8 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 4 Aug 2018 01:09:00 +0900
Subject: [PATCH 06/94] Trim text

---
 src/services/note/create.ts | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/services/note/create.ts b/src/services/note/create.ts
index 20dfc78c04..64556c160a 100644
--- a/src/services/note/create.ts
+++ b/src/services/note/create.ts
@@ -103,6 +103,10 @@ export default async (user: IUser, data: Option, silent = false) => new Promise<
 		data.visibleUsers = data.visibleUsers.filter(x => x != null);
 	}
 
+	if (data.text) {
+		data.text = data.text.trim();
+	}
+
 	// Parse MFM
 	const tokens = data.text ? parse(data.text) : [];
 

From caec6933d199d0e4f310a37af52aa539356ca30c Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 4 Aug 2018 01:47:57 +0900
Subject: [PATCH 07/94] Fix bug

---
 .../app/common/views/components/games/reversi/reversi.vue       | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/client/app/common/views/components/games/reversi/reversi.vue b/src/client/app/common/views/components/games/reversi/reversi.vue
index 4b84e4562f..ac5fc9048a 100644
--- a/src/client/app/common/views/components/games/reversi/reversi.vue
+++ b/src/client/app/common/views/components/games/reversi/reversi.vue
@@ -9,7 +9,7 @@
 			<form-button round @click="cancel">%i18n:@matching.cancel%</form-button>
 		</div>
 	</div>
-	<div v-if="gameId">
+	<div v-else-if="gameId">
 		...
 	</div>
 	<div class="index" v-else>

From 0389afa0fe031e339068aa97c08aeb979e275b6f Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 4 Aug 2018 01:48:02 +0900
Subject: [PATCH 08/94] :art:

---
 .../common/views/components/games/reversi/reversi.room.vue    | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/client/app/common/views/components/games/reversi/reversi.room.vue b/src/client/app/common/views/components/games/reversi/reversi.room.vue
index f925a45f62..2f5c3cf816 100644
--- a/src/client/app/common/views/components/games/reversi/reversi.room.vue
+++ b/src/client/app/common/views/components/games/reversi/reversi.room.vue
@@ -73,7 +73,7 @@
 						</header>
 
 						<div>
-							<el-radio v-for="(r, i) in item.items" :key="item.id + ':' + i" v-model="item.value" :label="r.value" @change="onChangeForm($event, item)">{{ r.label }}</el-radio>
+							<form-radio v-for="(r, i) in item.items" :key="item.id + ':' + i" v-model="item.value" :value="r.value" @change="onChangeForm($event, item)">{{ r.label }}</form-radio>
 						</div>
 					</div>
 
@@ -317,7 +317,7 @@ root(isDark)
 			border-radius 4px
 			background isDark ? #282C37 : #fff
 			color isDark ? #fff : #303133
-			box-shadow 0 2px 12px 0 rgba(#000, 0.1)
+			box-shadow 0 2px 12px 0 rgba(#000, isDark ? 0.7 : 0.1)
 
 			> header
 				padding 18px 20px

From bbe740785d560b4364b56f14e2666c9a503b5508 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 4 Aug 2018 01:49:32 +0900
Subject: [PATCH 09/94] Fix doc

---
 src/docs/reversi-bot.ja.md | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/docs/reversi-bot.ja.md b/src/docs/reversi-bot.ja.md
index 6fe62003df..cb273a1ce8 100644
--- a/src/docs/reversi-bot.ja.md
+++ b/src/docs/reversi-bot.ja.md
@@ -1,15 +1,15 @@
 # MisskeyリバーシBotの開発
 Misskeyのリバーシ機能に対応したBotの開発方法をここに記します。
 
-1. `reversi`ストリームに以下のパラメータを付けて接続する:
+1. `games/reversi`ストリームに以下のパラメータを付けて接続する:
 	* `i`: botアカウントのAPIキー
 
 2. 対局への招待が来たら、ストリームから`invited`イベントが流れてくる
 	* イベントの中身に、`parent`という名前で対局へ誘ってきたユーザーの情報が含まれている
 
-3. `reversi/match`へ、`user_id`として`parent`の`id`が含まれたリクエストを送信する
+3. `games/reversi/match`へ、`user_id`として`parent`の`id`が含まれたリクエストを送信する
 
-4. 上手くいくとゲーム情報が返ってくるので、`reversi-game`ストリームへ、以下のパラメータを付けて接続する:
+4. 上手くいくとゲーム情報が返ってくるので、`games/reversi-game`ストリームへ、以下のパラメータを付けて接続する:
 	* `i`: botアカウントのAPIキー
 	* `game`: `game`の`id`
 

From 69f82508cb3b8c1092498a7b6eeb99618e840afd Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 4 Aug 2018 01:50:45 +0900
Subject: [PATCH 10/94] 5.12.0

---
 package.json | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 6203170489..ba5eab2fbb 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "5.11.0",
-	"clientVersion": "1.0.7938",
+	"version": "5.12.0",
+	"clientVersion": "1.0.7948",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,

From e14f244e83b08a140f572e4e91032c5e17922755 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Sat, 4 Aug 2018 00:14:18 +0000
Subject: [PATCH 11/94] fix(package): update commander to version 2.17.0

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index ba5eab2fbb..0e6d74df02 100644
--- a/package.json
+++ b/package.json
@@ -90,7 +90,7 @@
 		"bootstrap-vue": "2.0.0-rc.11",
 		"cafy": "11.3.0",
 		"chalk": "2.4.1",
-		"commander": "2.16.0",
+		"commander": "2.17.0",
 		"crc-32": "1.2.0",
 		"css-loader": "1.0.0",
 		"dateformat": "3.0.3",

From ee050cc37edbaa9b3eba03fa6403cd9ed05811d7 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 4 Aug 2018 10:40:09 +0900
Subject: [PATCH 12/94] :v:

---
 .gitignore                      |  1 +
 package.json                    |  2 --
 src/games/reversi/package.json  | 18 ++++++++++++++++++
 src/games/reversi/tsconfig.json | 21 +++++++++++++++++++++
 src/mfm/html.ts                 |  2 +-
 5 files changed, 41 insertions(+), 3 deletions(-)
 create mode 100644 src/games/reversi/package.json
 create mode 100644 src/games/reversi/tsconfig.json

diff --git a/.gitignore b/.gitignore
index 51e6a31b74..2cea822c18 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
 /node_modules
 /build
 /built
+built
 /data
 /.cache-loader
 npm-debug.log
diff --git a/package.json b/package.json
index ba5eab2fbb..8eff18b097 100644
--- a/package.json
+++ b/package.json
@@ -43,7 +43,6 @@
 		"@types/is-root": "1.0.0",
 		"@types/is-url": "1.2.28",
 		"@types/js-yaml": "3.11.2",
-		"@types/jsdom": "11.0.6",
 		"@types/koa": "2.0.46",
 		"@types/koa-bodyparser": "5.0.1",
 		"@types/koa-compress": "2.0.8",
@@ -61,7 +60,6 @@
 		"@types/mongodb": "3.1.3",
 		"@types/ms": "0.7.30",
 		"@types/node": "10.5.5",
-		"@types/parse5": "5.0.0",
 		"@types/portscanner": "2.1.0",
 		"@types/pug": "2.0.4",
 		"@types/qrcode": "1.2.0",
diff --git a/src/games/reversi/package.json b/src/games/reversi/package.json
new file mode 100644
index 0000000000..5e7fdcb58a
--- /dev/null
+++ b/src/games/reversi/package.json
@@ -0,0 +1,18 @@
+{
+  "name": "misskey-reversi",
+  "version": "0.0.5",
+  "description": "Misskey reversi engine",
+  "keywords": [
+    "misskey"
+  ],
+  "author": "syuilo <i@syuilo.com>",
+  "license": "MIT",
+  "repository": "https://github.com/syuilo/misskey.git",
+  "bugs": "https://github.com/syuilo/misskey/issues",
+  "main": "./built/core.js",
+  "types": "./built/core.d.ts",
+  "scripts": {
+    "build": "tsc"
+  },
+  "dependencies": {}
+}
diff --git a/src/games/reversi/tsconfig.json b/src/games/reversi/tsconfig.json
new file mode 100644
index 0000000000..851fb6b7e4
--- /dev/null
+++ b/src/games/reversi/tsconfig.json
@@ -0,0 +1,21 @@
+{
+	"compilerOptions": {
+		"noEmitOnError": false,
+		"noImplicitAny": false,
+		"noImplicitReturns": true,
+		"noFallthroughCasesInSwitch": true,
+		"experimentalDecorators": true,
+		"declaration": true,
+		"sourceMap": false,
+		"target": "es2017",
+		"module": "commonjs",
+		"removeComments": false,
+		"noLib": false,
+		"outDir": "./built",
+		"rootDir": "./"
+	},
+	"compileOnSave": false,
+	"include": [
+		"./core.ts"
+	]
+}
diff --git a/src/mfm/html.ts b/src/mfm/html.ts
index eeaa4d8136..c047043cb7 100644
--- a/src/mfm/html.ts
+++ b/src/mfm/html.ts
@@ -1,5 +1,5 @@
 const { lib: emojilib } = require('emojilib');
-import { JSDOM } from 'jsdom';
+const JSDOM = require('jsdom');
 import config from '../config';
 import { INote } from '../models/note';
 import { TextElement } from './parse';

From 864d1a39cd700c0fb1a58428dee4f52982b3f762 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Sat, 4 Aug 2018 01:48:39 +0000
Subject: [PATCH 13/94] fix(package): update @types/node to version 10.5.6

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 8eff18b097..92e4067c4b 100644
--- a/package.json
+++ b/package.json
@@ -59,7 +59,7 @@
 		"@types/mocha": "5.2.3",
 		"@types/mongodb": "3.1.3",
 		"@types/ms": "0.7.30",
-		"@types/node": "10.5.5",
+		"@types/node": "10.5.6",
 		"@types/portscanner": "2.1.0",
 		"@types/pug": "2.0.4",
 		"@types/qrcode": "1.2.0",

From 33d3d5c5705474ffbaef86399a9dfd44c7f5cfe5 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 4 Aug 2018 11:24:15 +0900
Subject: [PATCH 14/94] =?UTF-8?q?=E3=82=B9=E3=83=A9=E3=82=A4=E3=83=80?=
 =?UTF-8?q?=E3=83=BC=E3=82=B3=E3=83=B3=E3=83=88=E3=83=AD=E3=83=BC=E3=83=AB?=
 =?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0=E3=81=99=E3=82=8B=E3=81=AA=E3=81=A9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../components/games/reversi/reversi.room.vue | 24 +++++++++++++++---
 src/docs/reversi-bot.ja.md                    | 25 +++++++++++++------
 2 files changed, 38 insertions(+), 11 deletions(-)

diff --git a/src/client/app/common/views/components/games/reversi/reversi.room.vue b/src/client/app/common/views/components/games/reversi/reversi.room.vue
index 2f5c3cf816..d482f70765 100644
--- a/src/client/app/common/views/components/games/reversi/reversi.room.vue
+++ b/src/client/app/common/views/components/games/reversi/reversi.room.vue
@@ -53,7 +53,7 @@
 			</div>
 		</div>
 
-		<div class="card" v-if="form">
+		<div class="card form" v-if="form">
 			<header>
 				<span>%i18n:@settings-of-the-bot%</span>
 			</header>
@@ -65,7 +65,7 @@
 						:key="message.id"/>
 
 				<template v-for="item in form">
-					<mk-switch v-if="item.type == 'button'" v-model="item.value" :key="item.id" :text="item.label" @change="onChangeForm($event, item)">{{ item.desc || '' }}</mk-switch>
+					<mk-switch v-if="item.type == 'switch'" v-model="item.value" :key="item.id" :text="item.label" @change="onChangeForm($event, item)">{{ item.desc || '' }}</mk-switch>
 
 					<div class="card" v-if="item.type == 'radio'" :key="item.id">
 						<header>
@@ -77,6 +77,16 @@
 						</div>
 					</div>
 
+					<div class="card" v-if="item.type == 'slider'" :key="item.id">
+						<header>
+							<span>{{ item.label }}</span>
+						</header>
+
+						<div>
+							<input type="range" :min="item.min" :max="item.max" :step="item.step || 1" v-model="item.value" @change="onChangeForm($event, item)"/>
+						</div>
+					</div>
+
 					<div class="card" v-if="item.type == 'textbox'" :key="item.id">
 						<header>
 							<span>{{ item.label }}</span>
@@ -214,7 +224,7 @@ export default Vue.extend({
 			this.connection.send({
 				type: 'update-form',
 				id: item.id,
-				value: v
+				value: item.value
 			});
 		},
 
@@ -312,6 +322,14 @@ root(isDark)
 							&[data-none]
 								border-color transparent
 
+			&.form
+				> div
+					> .card + .card
+						margin-top 16px
+
+					input[type='range']
+						width 100%
+
 		.card
 			max-width 400px
 			border-radius 4px
diff --git a/src/docs/reversi-bot.ja.md b/src/docs/reversi-bot.ja.md
index cb273a1ce8..cf5a3e4178 100644
--- a/src/docs/reversi-bot.ja.md
+++ b/src/docs/reversi-bot.ja.md
@@ -96,8 +96,8 @@ y = Math.floor(pos / mapWidth)
 フォームコントロールは、次のようなオブジェクトです:
 ```javascript
 {
-  id: 'button1',
-  type: 'button',
+  id: 'switch1',
+  type: 'switch',
   label: 'Enable hoge',
   value: false
 }
@@ -110,21 +110,21 @@ y = Math.floor(pos / mapWidth)
 ### フォームの操作を受け取る
 ユーザーがフォームを操作すると、ストリームから`update-form`イベントが流れてきます。
 イベントの中身には、コントロールのIDと、ユーザーが設定した値が含まれています。
-例えば、上で示したボタンをユーザーがオンにしたとすると、次のイベントが流れてきます:
+例えば、上で示したスイッチをユーザーがオンにしたとすると、次のイベントが流れてきます:
 ```javascript
 {
-  id: 'button1',
+  id: 'switch1',
   value: true
 }
 ```
 
 ### フォームコントロールの種類
-#### ボタン
-type: `button`
-ボタンを表示します。何かの機能をオン/オフさせたい場合に有用です。
+#### スイッチ
+type: `switch`
+スイッチを表示します。何かの機能をオン/オフさせたい場合に有用です。
 
 ##### プロパティ
-`desc` ... ボタンの詳細な説明。
+`desc` ... スイッチの詳細な説明。
 
 #### ラジオボタン
 type: `radio`
@@ -145,6 +145,15 @@ items: [{
 }]
 ```
 
+#### スライダー
+type: `slider`
+スライダーを表示します。
+
+##### プロパティ
+`min` ... スライダーの下限。
+`max` ... スライダーの上限。
+`step` ... 入力欄で刻むステップ値。
+
 #### テキストボックス
 type: `textbox`
 テキストボックスを表示します。ユーザーになにか入力させる一般的な用途に利用できます。

From 67e97310cf31e2b380bd90456f8ba2c24ff802d0 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 4 Aug 2018 11:25:39 +0900
Subject: [PATCH 15/94] Clean up

---
 .../views/components/games/reversi/reversi.room.vue    | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/client/app/common/views/components/games/reversi/reversi.room.vue b/src/client/app/common/views/components/games/reversi/reversi.room.vue
index d482f70765..f22aeadf64 100644
--- a/src/client/app/common/views/components/games/reversi/reversi.room.vue
+++ b/src/client/app/common/views/components/games/reversi/reversi.room.vue
@@ -65,7 +65,7 @@
 						:key="message.id"/>
 
 				<template v-for="item in form">
-					<mk-switch v-if="item.type == 'switch'" v-model="item.value" :key="item.id" :text="item.label" @change="onChangeForm($event, item)">{{ item.desc || '' }}</mk-switch>
+					<mk-switch v-if="item.type == 'switch'" v-model="item.value" :key="item.id" :text="item.label" @change="onChangeForm(item)">{{ item.desc || '' }}</mk-switch>
 
 					<div class="card" v-if="item.type == 'radio'" :key="item.id">
 						<header>
@@ -73,7 +73,7 @@
 						</header>
 
 						<div>
-							<form-radio v-for="(r, i) in item.items" :key="item.id + ':' + i" v-model="item.value" :value="r.value" @change="onChangeForm($event, item)">{{ r.label }}</form-radio>
+							<form-radio v-for="(r, i) in item.items" :key="item.id + ':' + i" v-model="item.value" :value="r.value" @change="onChangeForm(item)">{{ r.label }}</form-radio>
 						</div>
 					</div>
 
@@ -83,7 +83,7 @@
 						</header>
 
 						<div>
-							<input type="range" :min="item.min" :max="item.max" :step="item.step || 1" v-model="item.value" @change="onChangeForm($event, item)"/>
+							<input type="range" :min="item.min" :max="item.max" :step="item.step || 1" v-model="item.value" @change="onChangeForm(item)"/>
 						</div>
 					</div>
 
@@ -93,7 +93,7 @@
 						</header>
 
 						<div>
-							<el-input v-model="item.value" @change="onChangeForm($event, item)"/>
+							<el-input v-model="item.value" @change="onChangeForm(item)"/>
 						</div>
 					</div>
 				</template>
@@ -220,7 +220,7 @@ export default Vue.extend({
 			this.messages.unshift(x.message);
 		},
 
-		onChangeForm(v, item) {
+		onChangeForm(item) {
 			this.connection.send({
 				type: 'update-form',
 				id: item.id,

From 29418ecbb48490d01c3e65532b53d92607de8b10 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 4 Aug 2018 11:32:53 +0900
Subject: [PATCH 16/94] :art:

---
 .../app/common/views/components/games/reversi/reversi.room.vue | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/client/app/common/views/components/games/reversi/reversi.room.vue b/src/client/app/common/views/components/games/reversi/reversi.room.vue
index f22aeadf64..aed8718dd0 100644
--- a/src/client/app/common/views/components/games/reversi/reversi.room.vue
+++ b/src/client/app/common/views/components/games/reversi/reversi.room.vue
@@ -284,6 +284,9 @@ root(isDark)
 						color isDark ? #fff : #606266
 						cursor pointer
 						transition border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1)
+						-webkit-appearance none
+						-moz-appearance none
+						appearance none
 
 						&:hover
 							border-color isDark ? #a7aebd : #c0c4cc

From b60af54db190f349db90425e877c423d4085f61c Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 4 Aug 2018 11:34:36 +0900
Subject: [PATCH 17/94] 5.13.0

---
 package.json | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 8eff18b097..4b50820ff3 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "5.12.0",
-	"clientVersion": "1.0.7948",
+	"version": "5.13.0",
+	"clientVersion": "1.0.7963",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,

From 4ba6e1c2b2ce8baf28567a8faf9d1d0b45a89cc2 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 4 Aug 2018 11:39:59 +0900
Subject: [PATCH 18/94] Fix bug

---
 src/mfm/html.ts | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/mfm/html.ts b/src/mfm/html.ts
index c047043cb7..dfe291b3a5 100644
--- a/src/mfm/html.ts
+++ b/src/mfm/html.ts
@@ -1,5 +1,6 @@
 const { lib: emojilib } = require('emojilib');
-const JSDOM = require('jsdom');
+const jsdom = require('jsdom');
+const { JSDOM } = jsdom;
 import config from '../config';
 import { INote } from '../models/note';
 import { TextElement } from './parse';

From 4f7c19461e8816f9fb424f01431e15fd37ef0541 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 4 Aug 2018 11:40:06 +0900
Subject: [PATCH 19/94] 5.13.1

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 4b50820ff3..a26b7915b6 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "5.13.0",
+	"version": "5.13.1",
 	"clientVersion": "1.0.7963",
 	"codename": "nighthike",
 	"main": "./built/index.js",

From 61a9ad23f17b12f1ed5dc3cf791f1ad7313f7606 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 4 Aug 2018 12:35:57 +0900
Subject: [PATCH 20/94] Fix bug

---
 .../app/common/views/components/games/reversi/reversi.vue     | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/client/app/common/views/components/games/reversi/reversi.vue b/src/client/app/common/views/components/games/reversi/reversi.vue
index ac5fc9048a..d99634a950 100644
--- a/src/client/app/common/views/components/games/reversi/reversi.vue
+++ b/src/client/app/common/views/components/games/reversi/reversi.vue
@@ -48,6 +48,10 @@ export default Vue.extend({
 	},
 
 	watch: {
+		game() {
+			this.$emit('gamed', this.game);
+		},
+
 		gameId() {
 			this.fetch();
 		}

From 244d567b3a238f4aeeb496428b051b8d562db1fb Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 4 Aug 2018 12:38:14 +0900
Subject: [PATCH 21/94] 5.13.2

---
 package.json | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index a26b7915b6..619447ac17 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "5.13.1",
-	"clientVersion": "1.0.7963",
+	"version": "5.13.2",
+	"clientVersion": "1.0.7967",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,

From be9f6ad29433b1403850397c6b24e63d0a15619a Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 4 Aug 2018 22:28:01 +0900
Subject: [PATCH 22/94] Implement surrender of reversi

---
 locales/ja.yml                                |  4 ++
 .../components/games/reversi/reversi.game.vue | 36 ++++++++++-
 src/models/games/reversi/game.ts              |  1 +
 .../games/reversi/games/surrender.ts          | 59 +++++++++++++++++++
 4 files changed, 98 insertions(+), 2 deletions(-)
 create mode 100644 src/server/api/endpoints/games/reversi/games/surrender.ts

diff --git a/locales/ja.yml b/locales/ja.yml
index 9760f976ae..936bdea214 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -182,6 +182,10 @@ common/views/components/games/reversi/reversi.vue:
     waiting-for: "{}を待っています"
     cancel: "キャンセル"
 
+common/views/components/games/reversi/reversi.game.vue:
+  surrender: "投了"
+  surrendered: "投了により"
+
 common/views/components/games/reversi/reversi.index.vue:
   title: "Misskey Reversi"
   sub-title: "他のMisskeyユーザーとリバーシで対戦しよう"
diff --git a/src/client/app/common/views/components/games/reversi/reversi.game.vue b/src/client/app/common/views/components/games/reversi/reversi.game.vue
index bbfec2c1cc..66973e1970 100644
--- a/src/client/app/common/views/components/games/reversi/reversi.game.vue
+++ b/src/client/app/common/views/components/games/reversi/reversi.game.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="xqnhankfuuilcwvhgsopeqncafzsquya">
-	<header><b>{{ blackUser | userName }}</b>(%i18n:common.reversi.black%) vs <b>{{ whiteUser | userName }}</b>(%i18n:common.reversi.white%)</header>
+	<header><b><router-link :to="blackUser | userPage">{{ blackUser | userName }}</router-link></b>(%i18n:common.reversi.black%) vs <b><router-link :to="whiteUser | userPage">{{ whiteUser | userName }}</router-link></b>(%i18n:common.reversi.white%)</header>
 
 	<div style="overflow: hidden">
 		<p class="turn" v-if="!iAmPlayer && !game.isEnded">{{ '%i18n:common.reversi.turn-of%'.replace('{}', $options.filters.userName(turnUser)) }}<mk-ellipsis/></p>
@@ -8,7 +8,10 @@
 		<p class="turn1" v-if="iAmPlayer && !game.isEnded && !isMyTurn">%i18n:common.reversi.opponent-turn%<mk-ellipsis/></p>
 		<p class="turn2" v-if="iAmPlayer && !game.isEnded && isMyTurn" v-animate-css="{ classes: 'tada', iteration: 'infinite' }">%i18n:common.reversi.my-turn%</p>
 		<p class="result" v-if="game.isEnded && logPos == logs.length">
-			<template v-if="game.winner">{{ '%i18n:common.reversi.won%'.replace('{}', $options.filters.userName(game.winner)) }}{{ game.settings.isLlotheo ? ' (ロセオ)' : '' }}</template>
+			<template v-if="game.winner">
+				<span>{{ '%i18n:common.reversi.won%'.replace('{}', $options.filters.userName(game.winner)) }}</span>
+				<span v-if="game.surrendered != null"> (%i18n:@surrendered%)</span>
+			</template>
 			<template v-else>%i18n:common.reversi.drawn%</template>
 		</p>
 	</div>
@@ -41,6 +44,10 @@
 
 	<p class="status"><b>{{ '%i18n:common.reversi.this-turn%'.split('{}')[0] }}{{ logPos }}{{ '%i18n:common.reversi.this-turn%'.split('{}')[1] }}</b> %i18n:common.reversi.black%:{{ o.blackCount }} %i18n:common.reversi.white%:{{ o.whiteCount }} %i18n:common.reversi.total%:{{ o.blackCount + o.whiteCount }}</p>
 
+	<div class="actions" v-if="!game.isEnded && iAmPlayer">
+		<form-button @click="surrender">%i18n:@surrender%</form-button>
+	</div>
+
 	<div class="player" v-if="game.isEnded">
 		<el-button-group>
 			<el-button type="primary" @click="logPos = 0" :disabled="logPos == 0">%fa:angle-double-left%</el-button>
@@ -79,22 +86,27 @@ export default Vue.extend({
 			if (!this.$store.getters.isSignedIn) return false;
 			return this.game.user1Id == this.$store.state.i.id || this.game.user2Id == this.$store.state.i.id;
 		},
+
 		myColor(): Color {
 			if (!this.iAmPlayer) return null;
 			if (this.game.user1Id == this.$store.state.i.id && this.game.black == 1) return true;
 			if (this.game.user2Id == this.$store.state.i.id && this.game.black == 2) return true;
 			return false;
 		},
+
 		opColor(): Color {
 			if (!this.iAmPlayer) return null;
 			return this.myColor === true ? false : true;
 		},
+
 		blackUser(): any {
 			return this.game.black == 1 ? this.game.user1 : this.game.user2;
 		},
+
 		whiteUser(): any {
 			return this.game.black == 1 ? this.game.user2 : this.game.user1;
 		},
+
 		turnUser(): any {
 			if (this.o.turn === true) {
 				return this.game.black == 1 ? this.game.user1 : this.game.user2;
@@ -104,11 +116,13 @@ export default Vue.extend({
 				return null;
 			}
 		},
+
 		isMyTurn(): boolean {
 			if (!this.iAmPlayer) return false;
 			if (this.turnUser == null) return false;
 			return this.turnUser.id == this.$store.state.i.id;
 		},
+
 		cellsStyle(): any {
 			return {
 				'grid-template-rows': `repeat(${this.game.settings.map.length}, 1fr)`,
@@ -165,11 +179,13 @@ export default Vue.extend({
 	mounted() {
 		this.connection.on('set', this.onSet);
 		this.connection.on('rescue', this.onRescue);
+		this.connection.on('ended', this.onEnded);
 	},
 
 	beforeDestroy() {
 		this.connection.off('set', this.onSet);
 		this.connection.off('rescue', this.onRescue);
+		this.connection.off('ended', this.onEnded);
 
 		clearInterval(this.pollingClock);
 	},
@@ -215,6 +231,10 @@ export default Vue.extend({
 			}
 		},
 
+		onEnded(x) {
+			this.game = x.game;
+		},
+
 		checkEnd() {
 			this.game.isEnded = this.o.isEnded;
 			if (this.game.isEnded) {
@@ -250,6 +270,12 @@ export default Vue.extend({
 
 			this.checkEnd();
 			this.$forceUpdate();
+		},
+
+		surrender() {
+			(this as any).api('games/reversi/games/surrender', {
+				gameId: this.game.id
+			});
 		}
 	}
 });
@@ -265,6 +291,9 @@ root(isDark)
 		padding 8px
 		border-bottom dashed 1px isDark ? #4c5761 : #c4cdd4
 
+		a
+			color inherit
+
 	> .board
 		width calc(100% - 16px)
 		max-width 500px
@@ -381,6 +410,9 @@ root(isDark)
 		margin 0
 		padding 16px 0
 
+	> .actions
+		padding-bottom 16px
+
 	> .player
 		padding-bottom 32px
 
diff --git a/src/models/games/reversi/game.ts b/src/models/games/reversi/game.ts
index 8255db0584..6a6c6463d9 100644
--- a/src/models/games/reversi/game.ts
+++ b/src/models/games/reversi/game.ts
@@ -25,6 +25,7 @@ export interface IReversiGame {
 	isStarted: boolean;
 	isEnded: boolean;
 	winnerId: mongo.ObjectID;
+	surrendered: mongo.ObjectID;
 	logs: Array<{
 		at: Date;
 		color: boolean;
diff --git a/src/server/api/endpoints/games/reversi/games/surrender.ts b/src/server/api/endpoints/games/reversi/games/surrender.ts
new file mode 100644
index 0000000000..dc9908aef1
--- /dev/null
+++ b/src/server/api/endpoints/games/reversi/games/surrender.ts
@@ -0,0 +1,59 @@
+import $ from 'cafy'; import ID from '../../../../../../misc/cafy-id';
+import ReversiGame, { pack } from '../../../../../../models/games/reversi/game';
+import { ILocalUser } from '../../../../../../models/user';
+import getParams from '../../../../get-params';
+import { publishReversiGameStream } from '../../../../../../stream';
+
+export const meta = {
+	desc: {
+		ja: '指定したリバーシの対局で投了します。'
+	},
+
+	requireCredential: true,
+
+	params: {
+		gameId: $.type(ID).optional.note({
+			desc: {
+				ja: '投了したい対局'
+			}
+		})
+	}
+};
+
+export default (params: any, user: ILocalUser) => new Promise(async (res, rej) => {
+	const [ps, psErr] = getParams(meta, params);
+	if (psErr) return rej(psErr);
+
+	const game = await ReversiGame.findOne({ _id: ps.gameId });
+
+	if (game == null) {
+		return rej('game not found');
+	}
+
+	if (game.isEnded) {
+		return rej('this game is already ended');
+	}
+
+	if (!game.user1Id.equals(user._id) && !game.user2Id.equals(user._id)) {
+		return rej('access denied');
+	}
+
+	const winnerId = game.user1Id.equals(user._id) ? game.user2Id : game.user1Id;
+
+	await ReversiGame.update({
+		_id: game._id
+	}, {
+		$set: {
+			surrendered: user._id,
+			isEnded: true,
+			winnerId: winnerId
+		}
+	});
+
+	publishReversiGameStream(game._id, 'ended', {
+		winnerId: winnerId,
+		game: await pack(game._id, user)
+	});
+
+	res();
+});

From daed63d66cc6a45016d1d26581e4e9c54557a068 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 4 Aug 2018 22:33:37 +0900
Subject: [PATCH 23/94] Update doc

---
 src/docs/reversi-bot.ja.md | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/docs/reversi-bot.ja.md b/src/docs/reversi-bot.ja.md
index cf5a3e4178..98b543ca6c 100644
--- a/src/docs/reversi-bot.ja.md
+++ b/src/docs/reversi-bot.ja.md
@@ -172,3 +172,6 @@ type: `textbox`
 }
 ```
 メッセージの種類: `success`, `info`, `warning`, `error`。
+
+## 投了する
+投了をするには、<a href="./api/endpoints/games/reversi/games/surrender">このエンドポイント</a>にリクエストします。

From 9a2ff56a79efc08be194022a3119843cea74a657 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 4 Aug 2018 22:48:35 +0900
Subject: [PATCH 24/94] =?UTF-8?q?=E5=8B=95=E3=81=8D=E3=81=AE=E3=81=82?=
 =?UTF-8?q?=E3=82=8BMFM=E3=82=92=E7=84=A1=E5=8A=B9=E3=81=AB=E3=81=99?=
 =?UTF-8?q?=E3=82=8B=E3=82=AA=E3=83=97=E3=82=B7=E3=83=A7=E3=83=B3=E3=82=92?=
 =?UTF-8?q?=E5=AE=9F=E8=A3=85?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 locales/ja.yml                                            | 1 +
 .../common/views/components/misskey-flavored-markdown.ts  | 2 +-
 src/client/app/desktop/views/components/settings.vue      | 7 +++++++
 src/client/app/mobile/views/pages/settings.vue            | 8 ++++++++
 4 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/locales/ja.yml b/locales/ja.yml
index 936bdea214..1e0359254f 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -95,6 +95,7 @@ common:
   i-like-sushi: "私は(プリンよりむしろ)寿司が好き"
   show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示"
   verified-user: "認証済みのユーザー"
+  disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
 
   reversi:
     drawn: "引き分け"
diff --git a/src/client/app/common/views/components/misskey-flavored-markdown.ts b/src/client/app/common/views/components/misskey-flavored-markdown.ts
index 096ffcbf8a..f9c97bd35a 100644
--- a/src/client/app/common/views/components/misskey-flavored-markdown.ts
+++ b/src/client/app/common/views/components/misskey-flavored-markdown.ts
@@ -63,7 +63,7 @@ export default Vue.component('misskey-flavored-markdown', {
 						attrs: {
 							style: 'display: inline-block; font-size: 200%;'
 						},
-						directives: [{
+						directives: [this.$store.state.settings.disableAnimatedMfm ? {} : {
 							name: 'animate-css',
 							value: { classes: 'tada', iteration: 'infinite' }
 						}]
diff --git a/src/client/app/desktop/views/components/settings.vue b/src/client/app/desktop/views/components/settings.vue
index 00bd7a8783..84ea768a5c 100644
--- a/src/client/app/desktop/views/components/settings.vue
+++ b/src/client/app/desktop/views/components/settings.vue
@@ -55,6 +55,7 @@
 				<span>%i18n:@show-maps-desc%</span>
 			</mk-switch>
 			<mk-switch v-model="$store.state.settings.reversiBoardLabels" @change="onChangeReversiBoardLabels" text="%i18n:common.show-reversi-board-labels%"/>
+			<mk-switch v-model="$store.state.settings.disableAnimatedMfm" @change="onChangeDisableAnimatedMfm" text="%i18n:common.disable-animated-mfm%"/>
 		</section>
 
 		<section class="web" v-show="page == 'web'">
@@ -376,6 +377,12 @@ export default Vue.extend({
 				value: v
 			});
 		},
+		onChangeDisableAnimatedMfm(v) {
+			this.$store.dispatch('settings/set', {
+				key: 'disableAnimatedMfm',
+				value: v
+			});
+		},
 		onChangeGradientWindowHeader(v) {
 			this.$store.dispatch('settings/set', {
 				key: 'gradientWindowHeader',
diff --git a/src/client/app/mobile/views/pages/settings.vue b/src/client/app/mobile/views/pages/settings.vue
index 73bff55e44..63fca64ab1 100644
--- a/src/client/app/mobile/views/pages/settings.vue
+++ b/src/client/app/mobile/views/pages/settings.vue
@@ -14,6 +14,7 @@
 				<ui-switch v-model="$store.state.settings.circleIcons" @change="onChangeCircleIcons">%i18n:@circle-icons%</ui-switch>
 				<ui-switch v-model="$store.state.settings.iLikeSushi" @change="onChangeILikeSushi">%i18n:common.i-like-sushi%</ui-switch>
 				<ui-switch v-model="$store.state.settings.reversiBoardLabels" @change="onChangeReversiBoardLabels">%i18n:common.show-reversi-board-labels%</ui-switch>
+				<ui-switch v-model="$store.state.settings.disableAnimatedMfm" @change="onChangeDisableAnimatedMfm">%i18n:common.disable-animated-mfm%</ui-switch>
 
 				<div>
 					<div>%i18n:@timeline%</div>
@@ -192,6 +193,13 @@ export default Vue.extend({
 			});
 		},
 
+		onChangeDisableAnimatedMfm(v) {
+			this.$store.dispatch('settings/set', {
+				key: 'disableAnimatedMfm',
+				value: v
+			});
+		},
+
 		onChangeShowReplyTarget(v) {
 			this.$store.dispatch('settings/set', {
 				key: 'showReplyTarget',

From d84cae9358c5f026f4b6957f3bcac47f60ef3c02 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 4 Aug 2018 23:04:45 +0900
Subject: [PATCH 25/94] 5.14.0

---
 package.json | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 619447ac17..8520475717 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "5.13.2",
-	"clientVersion": "1.0.7967",
+	"version": "5.14.0",
+	"clientVersion": "1.0.7997",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,

From de448fc99f521d03883b6050f16a7154cfe159c1 Mon Sep 17 00:00:00 2001
From: gutfuckllc <40531868+gutfuckllc@users.noreply.github.com>
Date: Sat, 4 Aug 2018 13:13:29 -0400
Subject: [PATCH 26/94] Added start.sh

---
 start.sh | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 start.sh

diff --git a/start.sh b/start.sh
new file mode 100644
index 0000000000..86ee8aab31
--- /dev/null
+++ b/start.sh
@@ -0,0 +1 @@
+/sbin/start-stop-daemon /usr/bin/node /var/www/misskey/built/ --pidfile /run/misskey -S
\ No newline at end of file

From 911762fedfd05c112ce9135a9477349cc8cb173b Mon Sep 17 00:00:00 2001
From: gutfuckllc <40531868+gutfuckllc@users.noreply.github.com>
Date: Sat, 4 Aug 2018 13:13:56 -0400
Subject: [PATCH 27/94] Removed start.sh

---
 start.sh | 1 -
 1 file changed, 1 deletion(-)
 delete mode 100644 start.sh

diff --git a/start.sh b/start.sh
deleted file mode 100644
index 86ee8aab31..0000000000
--- a/start.sh
+++ /dev/null
@@ -1 +0,0 @@
-/sbin/start-stop-daemon /usr/bin/node /var/www/misskey/built/ --pidfile /run/misskey -S
\ No newline at end of file

From cd28504dd8e4623ed864de2ad76e88e1022b08b1 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 5 Aug 2018 12:33:51 +0900
Subject: [PATCH 28/94] Add new MFM syntax

---
 .../components/misskey-flavored-markdown.ts   | 11 ++++++++++
 src/mfm/html.ts                               |  6 ++++++
 src/mfm/parse/elements/motion.ts              | 20 +++++++++++++++++++
 src/mfm/parse/index.ts                        |  7 +++++--
 test/mfm.ts                                   |  8 ++++++++
 5 files changed, 50 insertions(+), 2 deletions(-)
 create mode 100644 src/mfm/parse/elements/motion.ts

diff --git a/src/client/app/common/views/components/misskey-flavored-markdown.ts b/src/client/app/common/views/components/misskey-flavored-markdown.ts
index f9c97bd35a..683b4e806c 100644
--- a/src/client/app/common/views/components/misskey-flavored-markdown.ts
+++ b/src/client/app/common/views/components/misskey-flavored-markdown.ts
@@ -69,6 +69,17 @@ export default Vue.component('misskey-flavored-markdown', {
 						}]
 					}, token.big);
 
+				case 'motion':
+					return (createElement as any)('span', {
+						attrs: {
+							style: 'display: inline-block;'
+						},
+						directives: [this.$store.state.settings.disableAnimatedMfm ? {} : {
+							name: 'animate-css',
+							value: { classes: 'rubberBand', iteration: 'infinite' }
+						}]
+					}, token.motion);
+
 				case 'url':
 					return createElement(MkUrl, {
 						props: {
diff --git a/src/mfm/html.ts b/src/mfm/html.ts
index dfe291b3a5..c11bd55cf4 100644
--- a/src/mfm/html.ts
+++ b/src/mfm/html.ts
@@ -18,6 +18,12 @@ const handlers: { [key: string]: (window: any, token: any, mentionedRemoteUsers:
 		document.body.appendChild(b);
 	},
 
+	motion({ document }, { big }) {
+		const b = document.createElement('strong');
+		b.textContent = big;
+		document.body.appendChild(b);
+	},
+
 	code({ document }, { code }) {
 		const pre = document.createElement('pre');
 		const inner = document.createElement('code');
diff --git a/src/mfm/parse/elements/motion.ts b/src/mfm/parse/elements/motion.ts
new file mode 100644
index 0000000000..555a989750
--- /dev/null
+++ b/src/mfm/parse/elements/motion.ts
@@ -0,0 +1,20 @@
+/**
+ * Motion
+ */
+
+export type TextElementMotion = {
+	type: 'motion'
+	content: string
+	motion: string
+};
+
+export default function(text: string) {
+	const match = text.match(/^\(\(\((.+?)\)\)\)/);
+	if (!match) return null;
+	const motion = match[0];
+	return {
+		type: 'motion',
+		content: motion,
+		motion: match[1]
+	} as TextElementMotion;
+}
diff --git a/src/mfm/parse/index.ts b/src/mfm/parse/index.ts
index 066c062559..99c00ae649 100644
--- a/src/mfm/parse/index.ts
+++ b/src/mfm/parse/index.ts
@@ -14,6 +14,7 @@ import { TextElementQuote } from './elements/quote';
 import { TextElementSearch } from './elements/search';
 import { TextElementTitle } from './elements/title';
 import { TextElementUrl } from './elements/url';
+import { TextElementMotion } from './elements/motion';
 
 const elements = [
 	require('./elements/big'),
@@ -27,7 +28,8 @@ const elements = [
 	require('./elements/inline-code'),
 	require('./elements/quote'),
 	require('./elements/emoji'),
-	require('./elements/search')
+	require('./elements/search'),
+	require('./elements/motion')
 ].map(element => element.default as TextElementProcessor);
 
 export type TextElement = { type: 'text', content: string }
@@ -42,7 +44,8 @@ export type TextElement = { type: 'text', content: string }
 	| TextElementQuote
 	| TextElementSearch
 	| TextElementTitle
-	| TextElementUrl;
+	| TextElementUrl
+	| TextElementMotion;
 export type TextElementProcessor = (text: string, i: number) => TextElement | TextElement[];
 
 export default (source: string): TextElement[] => {
diff --git a/test/mfm.ts b/test/mfm.ts
index 1a22e1491b..fcd5f3f076 100644
--- a/test/mfm.ts
+++ b/test/mfm.ts
@@ -39,6 +39,14 @@ describe('Text', () => {
 			], tokens);
 		});
 
+		it('motion', () => {
+			const tokens = analyze('(((Strawberry))) Pasta');
+			assert.deepEqual([
+				{ type: 'motion', content: '***Strawberry***', motion: 'Strawberry' },
+				{ type: 'text', content: ' Pasta' }
+			], tokens);
+		});
+
 		it('mention', () => {
 			const tokens = analyze('@himawari お腹ペコい');
 			assert.deepEqual([

From b68f74f39c7a8c86fdeecb5d298cfe7c8d98ebf2 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 5 Aug 2018 12:33:55 +0900
Subject: [PATCH 29/94] typo

---
 src/mfm/parse/elements/big.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/mfm/parse/elements/big.ts b/src/mfm/parse/elements/big.ts
index ca798986e9..8e39c75a55 100644
--- a/src/mfm/parse/elements/big.ts
+++ b/src/mfm/parse/elements/big.ts
@@ -1,5 +1,5 @@
 /**
- * Bold
+ * Big
  */
 
 export type TextElementBig = {

From 128a201b9d417038583abdbcda09dba1e8c0239d Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 5 Aug 2018 13:40:26 +0900
Subject: [PATCH 30/94] =?UTF-8?q?#2080=20=E3=81=AA=E3=81=A9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../components/games/reversi/reversi.game.vue | 28 +++++++++++++++-
 .../games/reversi/reversi.gameroom.vue        | 16 +++++++--
 .../games/reversi/reversi.index.vue           |  6 +---
 .../components/games/reversi/reversi.vue      | 33 ++++++++++++++-----
 .../app/desktop/views/pages/games/reversi.vue | 13 +++++---
 .../app/mobile/views/pages/games/reversi.vue  | 11 +++++--
 6 files changed, 84 insertions(+), 23 deletions(-)

diff --git a/src/client/app/common/views/components/games/reversi/reversi.game.vue b/src/client/app/common/views/components/games/reversi/reversi.game.vue
index 66973e1970..5ecbc9d8c1 100644
--- a/src/client/app/common/views/components/games/reversi/reversi.game.vue
+++ b/src/client/app/common/views/components/games/reversi/reversi.game.vue
@@ -1,5 +1,6 @@
 <template>
 <div class="xqnhankfuuilcwvhgsopeqncafzsquya">
+	<button class="go-index" v-if="selfNav" @click="goIndex">%fa:arrow-left%</button>
 	<header><b><router-link :to="blackUser | userPage">{{ blackUser | userName }}</router-link></b>(%i18n:common.reversi.black%) vs <b><router-link :to="whiteUser | userPage">{{ whiteUser | userName }}</router-link></b>(%i18n:common.reversi.white%)</header>
 
 	<div style="overflow: hidden">
@@ -69,7 +70,20 @@ import Reversi, { Color } from '../../../../../../../games/reversi/core';
 import { url } from '../../../../../config';
 
 export default Vue.extend({
-	props: ['initGame', 'connection'],
+	props: {
+		initGame: {
+			type: Object,
+			require: true
+		},
+		connection: {
+			type: Object,
+			require: true
+		},
+		selfNav: {
+			type: Boolean,
+			require: true
+		}
+	},
 
 	data() {
 		return {
@@ -276,6 +290,10 @@ export default Vue.extend({
 			(this as any).api('games/reversi/games/surrender', {
 				gameId: this.game.id
 			});
+		},
+
+		goIndex() {
+			this.$emit('go-index');
 		}
 	}
 });
@@ -287,6 +305,14 @@ export default Vue.extend({
 root(isDark)
 	text-align center
 
+	> .go-index
+		position absolute
+		top 0
+		left 0
+		z-index 1
+		width 42px
+		height 42px
+
 	> header
 		padding 8px
 		border-bottom dashed 1px isDark ? #4c5761 : #c4cdd4
diff --git a/src/client/app/common/views/components/games/reversi/reversi.gameroom.vue b/src/client/app/common/views/components/games/reversi/reversi.gameroom.vue
index 4969a9347e..1539c88de0 100644
--- a/src/client/app/common/views/components/games/reversi/reversi.gameroom.vue
+++ b/src/client/app/common/views/components/games/reversi/reversi.gameroom.vue
@@ -1,7 +1,7 @@
 <template>
 <div>
 	<x-room v-if="!g.isStarted" :game="g" :connection="connection"/>
-	<x-game v-else :init-game="g" :connection="connection"/>
+	<x-game v-else :init-game="g" :connection="connection" :self-nav="selfNav" @go-index="goIndex"/>
 </div>
 </template>
 
@@ -16,7 +16,16 @@ export default Vue.extend({
 		XGame,
 		XRoom
 	},
-	props: ['game'],
+	props: {
+		game: {
+			type: Object,
+			required: true
+		},
+		selfNav: {
+			type: Boolean,
+			require: true
+		}
+	},
 	data() {
 		return {
 			connection: null,
@@ -36,6 +45,9 @@ export default Vue.extend({
 		onStarted(game) {
 			Object.assign(this.g, game);
 			this.$forceUpdate();
+		},
+		goIndex() {
+			this.$emit('go-index');
 		}
 	}
 });
diff --git a/src/client/app/common/views/components/games/reversi/reversi.index.vue b/src/client/app/common/views/components/games/reversi/reversi.index.vue
index 026159a0fd..d4d35f6a86 100644
--- a/src/client/app/common/views/components/games/reversi/reversi.index.vue
+++ b/src/client/app/common/views/components/games/reversi/reversi.index.vue
@@ -96,11 +96,7 @@ export default Vue.extend({
 
 	methods: {
 		go(game) {
-			(this as any).api('games/reversi/games/show', {
-				gameId: game.id
-			}).then(game => {
-				this.$emit('go', game);
-			});
+			this.$emit('go', game);
 		},
 
 		match() {
diff --git a/src/client/app/common/views/components/games/reversi/reversi.vue b/src/client/app/common/views/components/games/reversi/reversi.vue
index d99634a950..223ec4597a 100644
--- a/src/client/app/common/views/components/games/reversi/reversi.vue
+++ b/src/client/app/common/views/components/games/reversi/reversi.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="vchtoekanapleubgzioubdtmlkribzfd">
 	<div v-if="game">
-		<x-gameroom :game="game"/>
+		<x-gameroom :game="game" :self-nav="selfNav" @go-index="goIndex"/>
 	</div>
 	<div class="matching" v-else-if="matching">
 		<h1>{{ '%i18n:@matching.waiting-for%'.split('{}')[0] }}<b>{{ matching | userName }}</b>{{ '%i18n:@matching.waiting-for%'.split('{}')[1] }}<mk-ellipsis/></h1>
@@ -34,6 +34,11 @@ export default Vue.extend({
 		gameId: {
 			type: String,
 			required: false
+		},
+		selfNav: {
+			type: Boolean,
+			require: false,
+			default: true
 		}
 	},
 
@@ -95,18 +100,24 @@ export default Vue.extend({
 				(this as any).api('games/reversi/games/show', {
 					gameId: this.gameId
 				}).then(game => {
-					this.nav(game, true);
+					this.game = game;
 					Progress.done();
 				});
 			}
 		},
 
-		nav(game, silent) {
-			this.matching = null;
-			this.game = game;
+		async nav(game, actualNav = true) {
+			if (this.selfNav) {
+				// 受け取ったゲーム情報が省略されたものなら完全な情報を取得する
+				if (game != null && (game.settings == null || game.settings.map == null)) {
+					game = await (this as any).api('games/reversi/games/show', {
+						gameId: game.id
+					});
+				}
 
-			if (!silent) {
-				this.$emit('nav', this.game);
+				this.game = game;
+			} else {
+				this.$emit('nav', game, actualNav);
 			}
 		},
 
@@ -125,7 +136,8 @@ export default Vue.extend({
 			}).then(game => {
 				if (game) {
 					this.matching = null;
-					this.game = game;
+
+					this.nav(game);
 				}
 			});
 		},
@@ -133,6 +145,11 @@ export default Vue.extend({
 		onMatched(game) {
 			this.matching = null;
 			this.game = game;
+			this.nav(game, false);
+		},
+
+		goIndex() {
+			this.nav(null);
 		}
 	}
 });
diff --git a/src/client/app/desktop/views/pages/games/reversi.vue b/src/client/app/desktop/views/pages/games/reversi.vue
index 590bda2d86..ce9b42c65f 100644
--- a/src/client/app/desktop/views/pages/games/reversi.vue
+++ b/src/client/app/desktop/views/pages/games/reversi.vue
@@ -1,6 +1,6 @@
 <template>
 <component :is="ui ? 'mk-ui' : 'div'">
-	<mk-reversi :game-id="$route.params.game" @nav="nav"/>
+	<mk-reversi :game-id="$route.params.game" @nav="nav" :self-nav="false"/>
 </component>
 </template>
 
@@ -14,9 +14,14 @@ export default Vue.extend({
 		}
 	},
 	methods: {
-		nav(game) {
-			history.pushState(null, null, '/reversi/' + game.id);
-		},
+		nav(game, actualNav) {
+			if (actualNav) {
+				this.$router.push('/reversi/' + game.id);
+			} else {
+				// TODO: https://github.com/vuejs/vue-router/issues/703
+				this.$router.push('/reversi/' + game.id);
+			}
+		}
 	}
 });
 </script>
diff --git a/src/client/app/mobile/views/pages/games/reversi.vue b/src/client/app/mobile/views/pages/games/reversi.vue
index 7118644ef3..e6e6325f8b 100644
--- a/src/client/app/mobile/views/pages/games/reversi.vue
+++ b/src/client/app/mobile/views/pages/games/reversi.vue
@@ -1,7 +1,7 @@
 <template>
 <mk-ui>
 	<span slot="header">%fa:gamepad%%i18n:@reversi%</span>
-	<mk-reversi :game-id="$route.params.game" @nav="nav"/>
+	<mk-reversi :game-id="$route.params.game" @nav="nav" :self-nav="false"/>
 </mk-ui>
 </template>
 
@@ -14,8 +14,13 @@ export default Vue.extend({
 		document.documentElement.style.background = '#fff';
 	},
 	methods: {
-		nav(game) {
-			history.pushState(null, null, '/reversi/' + game.id);
+		nav(game, actualNav) {
+			if (actualNav) {
+				this.$router.push('/reversi/' + game.id);
+			} else {
+				// TODO: https://github.com/vuejs/vue-router/issues/703
+				this.$router.push('/reversi/' + game.id);
+			}
 		}
 	}
 });

From 9e5e3c2f2e6d8527a6bdd63714b85f6407d12583 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 5 Aug 2018 13:44:44 +0900
Subject: [PATCH 31/94] :v:

---
 src/server/api/service/github.ts | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/server/api/service/github.ts b/src/server/api/service/github.ts
index 9024740a96..c8d588eaaf 100644
--- a/src/server/api/service/github.ts
+++ b/src/server/api/service/github.ts
@@ -11,7 +11,7 @@ const handler = new EventEmitter();
 
 let bot: IUser;
 
-const post = async (text: string) => {
+const post = async (text: string, home = true) => {
 	if (bot == null) {
 		const account = await User.findOne({
 			usernameLower: config.github_bot.username.toLowerCase()
@@ -25,7 +25,7 @@ const post = async (text: string) => {
 		}
 	}
 
-	createNote(bot, { text, visibility: 'home' });
+	createNote(bot, { text, visibility: home ? 'home' : 'public' });
 };
 
 // Init router
@@ -130,7 +130,7 @@ handler.on('issue_comment', event => {
 
 handler.on('watch', event => {
 	const sender = event.sender;
-	post(`⭐️ Starred by **${sender.login}** ⭐️`);
+	post(`(((⭐️))) Starred by **${sender.login}** (((⭐️)))`, false);
 });
 
 handler.on('fork', event => {

From 255222bfb473d19bfbaa49bae55050f46a9c38a9 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 5 Aug 2018 13:47:51 +0900
Subject: [PATCH 32/94] 5.15.0

---
 package.json | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 9d8ba28e03..dea93d11a2 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "5.14.0",
-	"clientVersion": "1.0.7997",
+	"version": "5.15.0",
+	"clientVersion": "1.0.8007",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,

From 005d25a07b21efbd4996e31a232fcf5393deb4d5 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 5 Aug 2018 13:50:49 +0900
Subject: [PATCH 33/94] Fix test

---
 test/mfm.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/mfm.ts b/test/mfm.ts
index fcd5f3f076..652a6e9820 100644
--- a/test/mfm.ts
+++ b/test/mfm.ts
@@ -42,7 +42,7 @@ describe('Text', () => {
 		it('motion', () => {
 			const tokens = analyze('(((Strawberry))) Pasta');
 			assert.deepEqual([
-				{ type: 'motion', content: '***Strawberry***', motion: 'Strawberry' },
+				{ type: 'motion', content: '(((Strawberry)))', motion: 'Strawberry' },
 				{ type: 'text', content: ' Pasta' }
 			], tokens);
 		});

From 5bbc95d6597625772ae305e6a81fb7b1ddace5b7 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 5 Aug 2018 19:20:26 +0900
Subject: [PATCH 34/94] =?UTF-8?q?=E6=96=87=E5=AD=97=E6=95=B0=E3=81=8C?=
 =?UTF-8?q?=E5=A4=9A=E3=81=84=E5=A0=B4=E5=90=88=E3=81=AF=E5=8B=95=E3=81=8D?=
 =?UTF-8?q?=E3=82=92=E7=84=A1=E5=8A=B9=E3=81=AB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 package.json                                  |  1 +
 .../components/misskey-flavored-markdown.ts   | 52 +++++++++++++------
 2 files changed, 36 insertions(+), 17 deletions(-)

diff --git a/package.json b/package.json
index dea93d11a2..2da5bf0eca 100644
--- a/package.json
+++ b/package.json
@@ -183,6 +183,7 @@
 		"showdown-highlightjs-extension": "0.1.2",
 		"single-line-log": "1.1.2",
 		"speakeasy": "2.0.0",
+		"stringz": "1.0.0",
 		"style-loader": "0.21.0",
 		"stylus": "0.54.5",
 		"stylus-loader": "3.0.2",
diff --git a/src/client/app/common/views/components/misskey-flavored-markdown.ts b/src/client/app/common/views/components/misskey-flavored-markdown.ts
index 683b4e806c..69e727d6f3 100644
--- a/src/client/app/common/views/components/misskey-flavored-markdown.ts
+++ b/src/client/app/common/views/components/misskey-flavored-markdown.ts
@@ -1,5 +1,6 @@
 import Vue from 'vue';
 import * as emojilib from 'emojilib';
+import { length } from 'stringz';
 import parse from '../../../../../mfm/parse';
 import getAcct from '../../../../../misc/acct/render';
 import { url } from '../../../config';
@@ -43,7 +44,7 @@ export default Vue.component('misskey-flavored-markdown', {
 		// Parse ast to DOM
 		const els = flatten(ast.map(token => {
 			switch (token.type) {
-				case 'text':
+				case 'text': {
 					const text = token.content.replace(/(\r\n|\n|\r)/g, '\n');
 
 					if (this.shouldBreak) {
@@ -54,41 +55,48 @@ export default Vue.component('misskey-flavored-markdown', {
 					} else {
 						return createElement('span', text.replace(/\n/g, ' '));
 					}
+				}
 
-				case 'bold':
+				case 'bold': {
 					return createElement('b', token.bold);
+				}
 
-				case 'big':
+				case 'big': {
+					const isLong = length(token.big) > 10;
 					return (createElement as any)('strong', {
 						attrs: {
 							style: 'display: inline-block; font-size: 200%;'
 						},
-						directives: [this.$store.state.settings.disableAnimatedMfm ? {} : {
+						directives: [this.$store.state.settings.disableAnimatedMfm || isLong ? {} : {
 							name: 'animate-css',
 							value: { classes: 'tada', iteration: 'infinite' }
 						}]
 					}, token.big);
+				}
 
-				case 'motion':
+				case 'motion': {
+					const isLong = length(token.motion) > 10;
 					return (createElement as any)('span', {
 						attrs: {
 							style: 'display: inline-block;'
 						},
-						directives: [this.$store.state.settings.disableAnimatedMfm ? {} : {
+						directives: [this.$store.state.settings.disableAnimatedMfm || isLong ? {} : {
 							name: 'animate-css',
 							value: { classes: 'rubberBand', iteration: 'infinite' }
 						}]
 					}, token.motion);
+				}
 
-				case 'url':
+				case 'url': {
 					return createElement(MkUrl, {
 						props: {
 							url: token.content,
 							target: '_blank'
 						}
 					});
+				}
 
-				case 'link':
+				case 'link': {
 					return createElement('a', {
 						attrs: {
 							class: 'link',
@@ -97,8 +105,9 @@ export default Vue.component('misskey-flavored-markdown', {
 							title: token.url
 						}
 					}, token.title);
+				}
 
-				case 'mention':
+				case 'mention': {
 					return (createElement as any)('a', {
 						attrs: {
 							href: `${url}/@${getAcct(token)}`,
@@ -110,16 +119,18 @@ export default Vue.component('misskey-flavored-markdown', {
 							value: token.content
 						}]
 					}, token.content);
+				}
 
-				case 'hashtag':
+				case 'hashtag': {
 					return createElement('a', {
 						attrs: {
 							href: `${url}/tags/${encodeURIComponent(token.hashtag)}`,
 							target: '_blank'
 						}
 					}, token.content);
+				}
 
-				case 'code':
+				case 'code': {
 					return createElement('pre', {
 						class: 'code'
 					}, [
@@ -129,15 +140,17 @@ export default Vue.component('misskey-flavored-markdown', {
 							}
 						})
 					]);
+				}
 
-				case 'inline-code':
+				case 'inline-code': {
 					return createElement('code', {
 						domProps: {
 							innerHTML: token.html
 						}
 					});
+				}
 
-				case 'quote':
+				case 'quote': {
 					const text2 = token.quote.replace(/(\r\n|\n|\r)/g, '\n');
 
 					if (this.shouldBreak) {
@@ -156,27 +169,32 @@ export default Vue.component('misskey-flavored-markdown', {
 							}
 						}, text2.replace(/\n/g, ' '));
 					}
+				}
 
-				case 'title':
+				case 'title': {
 					return createElement('div', {
 						attrs: {
 							class: 'title'
 						}
 					}, token.title);
+				}
 
-				case 'emoji':
+				case 'emoji': {
 					const emoji = emojilib.lib[token.emoji];
 					return createElement('span', emoji ? emoji.char : token.content);
+				}
 
-				case 'search':
+				case 'search': {
 					return createElement(MkGoogle, {
 						props: {
 							q: token.query
 						}
 					});
+				}
 
-				default:
+				default: {
 					console.log('unknown ast type:', token.type);
+				}
 			}
 		}));
 

From 6ef28214df4899043077dc3d7efa4cf1bfaf9a72 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 5 Aug 2018 19:36:19 +0900
Subject: [PATCH 35/94] =?UTF-8?q?=E3=81=B2=E3=81=A8=E3=81=A4=E3=81=AE?=
 =?UTF-8?q?=E6=8A=95=E7=A8=BF=E5=86=85=E3=81=A7=E4=BD=BF=E3=81=88=E3=82=8B?=
 =?UTF-8?q?=E3=81=9D=E3=82=8C=E3=81=9E=E3=82=8C=E3=81=AE=E5=8B=95=E3=81=8D?=
 =?UTF-8?q?=E3=81=AE=E3=81=82=E3=82=8BMFM=E6=A7=8B=E6=96=87=E3=81=AF3?=
 =?UTF-8?q?=E5=9B=9E=E3=81=BE=E3=81=A7=E3=81=AB=E5=88=B6=E9=99=90?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../views/components/misskey-flavored-markdown.ts   | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/src/client/app/common/views/components/misskey-flavored-markdown.ts b/src/client/app/common/views/components/misskey-flavored-markdown.ts
index 69e727d6f3..2a349c6e5f 100644
--- a/src/client/app/common/views/components/misskey-flavored-markdown.ts
+++ b/src/client/app/common/views/components/misskey-flavored-markdown.ts
@@ -41,6 +41,9 @@ export default Vue.component('misskey-flavored-markdown', {
 			ast = this.ast;
 		}
 
+		let bigCount = 0;
+		let motionCount = 0;
+
 		// Parse ast to DOM
 		const els = flatten(ast.map(token => {
 			switch (token.type) {
@@ -62,12 +65,14 @@ export default Vue.component('misskey-flavored-markdown', {
 				}
 
 				case 'big': {
+					bigCount++;
 					const isLong = length(token.big) > 10;
+					const isMany = bigCount > 3;
 					return (createElement as any)('strong', {
 						attrs: {
-							style: 'display: inline-block; font-size: 200%;'
+							style: `display: inline-block; font-size: ${ isMany ? '100%' : '200%' };`
 						},
-						directives: [this.$store.state.settings.disableAnimatedMfm || isLong ? {} : {
+						directives: [this.$store.state.settings.disableAnimatedMfm || isLong || isMany ? {} : {
 							name: 'animate-css',
 							value: { classes: 'tada', iteration: 'infinite' }
 						}]
@@ -75,12 +80,14 @@ export default Vue.component('misskey-flavored-markdown', {
 				}
 
 				case 'motion': {
+					motionCount++;
 					const isLong = length(token.motion) > 10;
+					const isMany = motionCount > 3;
 					return (createElement as any)('span', {
 						attrs: {
 							style: 'display: inline-block;'
 						},
-						directives: [this.$store.state.settings.disableAnimatedMfm || isLong ? {} : {
+						directives: [this.$store.state.settings.disableAnimatedMfm || isLong || isMany ? {} : {
 							name: 'animate-css',
 							value: { classes: 'rubberBand', iteration: 'infinite' }
 						}]

From 2e454dad2d133556e1aafaa6727370b8d229e2f2 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 5 Aug 2018 20:57:24 +0900
Subject: [PATCH 36/94] :art:

---
 .../app/common/views/components/games/reversi/reversi.game.vue  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/client/app/common/views/components/games/reversi/reversi.game.vue b/src/client/app/common/views/components/games/reversi/reversi.game.vue
index 5ecbc9d8c1..d1809d741f 100644
--- a/src/client/app/common/views/components/games/reversi/reversi.game.vue
+++ b/src/client/app/common/views/components/games/reversi/reversi.game.vue
@@ -3,7 +3,7 @@
 	<button class="go-index" v-if="selfNav" @click="goIndex">%fa:arrow-left%</button>
 	<header><b><router-link :to="blackUser | userPage">{{ blackUser | userName }}</router-link></b>(%i18n:common.reversi.black%) vs <b><router-link :to="whiteUser | userPage">{{ whiteUser | userName }}</router-link></b>(%i18n:common.reversi.white%)</header>
 
-	<div style="overflow: hidden">
+	<div style="overflow: hidden; line-height: 28px;">
 		<p class="turn" v-if="!iAmPlayer && !game.isEnded">{{ '%i18n:common.reversi.turn-of%'.replace('{}', $options.filters.userName(turnUser)) }}<mk-ellipsis/></p>
 		<p class="turn" v-if="logPos != logs.length">{{ '%i18n:common.reversi.past-turn-of%'.replace('{}', $options.filters.userName(turnUser)) }}</p>
 		<p class="turn1" v-if="iAmPlayer && !game.isEnded && !isMyTurn">%i18n:common.reversi.opponent-turn%<mk-ellipsis/></p>

From 813804a43ecec5efe58b6b9523a78e497c3dbd3b Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 5 Aug 2018 21:01:03 +0900
Subject: [PATCH 37/94] 5.16.0

---
 package.json | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 2da5bf0eca..882291ae87 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "5.15.0",
-	"clientVersion": "1.0.8007",
+	"version": "5.16.0",
+	"clientVersion": "1.0.8018",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,

From 43b6140dbebefe083a68bc69e6b355610391669b Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 5 Aug 2018 21:03:52 +0900
Subject: [PATCH 38/94] Fix bug

---
 src/server/api/endpoints/games/reversi/games/surrender.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/server/api/endpoints/games/reversi/games/surrender.ts b/src/server/api/endpoints/games/reversi/games/surrender.ts
index dc9908aef1..49821650ed 100644
--- a/src/server/api/endpoints/games/reversi/games/surrender.ts
+++ b/src/server/api/endpoints/games/reversi/games/surrender.ts
@@ -12,7 +12,7 @@ export const meta = {
 	requireCredential: true,
 
 	params: {
-		gameId: $.type(ID).optional.note({
+		gameId: $.type(ID).note({
 			desc: {
 				ja: '投了したい対局'
 			}

From be67f5f422c2999fb430e1574de07919c193e02f Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 5 Aug 2018 23:38:31 +0900
Subject: [PATCH 39/94] :art:

---
 .../app/common/views/components/misskey-flavored-markdown.ts    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/client/app/common/views/components/misskey-flavored-markdown.ts b/src/client/app/common/views/components/misskey-flavored-markdown.ts
index 2a349c6e5f..e97da4302c 100644
--- a/src/client/app/common/views/components/misskey-flavored-markdown.ts
+++ b/src/client/app/common/views/components/misskey-flavored-markdown.ts
@@ -70,7 +70,7 @@ export default Vue.component('misskey-flavored-markdown', {
 					const isMany = bigCount > 3;
 					return (createElement as any)('strong', {
 						attrs: {
-							style: `display: inline-block; font-size: ${ isMany ? '100%' : '200%' };`
+							style: `display: inline-block; font-size: ${ isMany ? '100%' : '150%' };`
 						},
 						directives: [this.$store.state.settings.disableAnimatedMfm || isLong || isMany ? {} : {
 							name: 'animate-css',

From d0926a3ba1e4666cad7ffb4aac4ff5fdc3a1476b Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 5 Aug 2018 23:56:08 +0900
Subject: [PATCH 40/94] =?UTF-8?q?MFM=E3=81=AE((()))=E6=A7=8B=E6=96=87?=
 =?UTF-8?q?=E3=81=8C=E9=A1=94=E6=96=87=E5=AD=97=E3=81=A8=E7=AB=B6=E5=90=88?=
 =?UTF-8?q?=E3=81=99=E3=82=8B=E5=AF=BE=E7=AD=96=E3=81=A8=E3=81=97=E3=81=A6?=
 =?UTF-8?q?=E3=82=BF=E3=82=B0=E5=BD=A2=E5=BC=8F=E3=81=AE=E6=A7=8B=E6=96=87?=
 =?UTF-8?q?=E3=82=82=E8=BF=BD=E5=8A=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/mfm/parse/elements/motion.ts |  2 +-
 test/mfm.ts                      | 10 ++++++++--
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/src/mfm/parse/elements/motion.ts b/src/mfm/parse/elements/motion.ts
index 555a989750..9e7370e071 100644
--- a/src/mfm/parse/elements/motion.ts
+++ b/src/mfm/parse/elements/motion.ts
@@ -9,7 +9,7 @@ export type TextElementMotion = {
 };
 
 export default function(text: string) {
-	const match = text.match(/^\(\(\((.+?)\)\)\)/);
+	const match = text.match(/^\(\(\((.+?)\)\)\)/) || text.match(/^<motion>(.+?)<\/motion>/);
 	if (!match) return null;
 	const motion = match[0];
 	return {
diff --git a/test/mfm.ts b/test/mfm.ts
index 652a6e9820..697d92e170 100644
--- a/test/mfm.ts
+++ b/test/mfm.ts
@@ -40,11 +40,17 @@ describe('Text', () => {
 		});
 
 		it('motion', () => {
-			const tokens = analyze('(((Strawberry))) Pasta');
+			const tokens1 = analyze('(((Strawberry))) Pasta');
 			assert.deepEqual([
 				{ type: 'motion', content: '(((Strawberry)))', motion: 'Strawberry' },
 				{ type: 'text', content: ' Pasta' }
-			], tokens);
+			], tokens1);
+
+			const tokens2 = analyze('<motion>Strawberry</motion> Pasta');
+			assert.deepEqual([
+				{ type: 'motion', content: '<motion>Strawberry</motion>', motion: 'Strawberry' },
+				{ type: 'text', content: ' Pasta' }
+			], tokens2);
 		});
 
 		it('mention', () => {

From 0d9782571f2c6a62116a0c6d1718a84b481fcc93 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Mon, 6 Aug 2018 00:09:21 +0900
Subject: [PATCH 41/94] :art:

---
 src/client/app/common/views/components/ui/form/button.vue | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/client/app/common/views/components/ui/form/button.vue b/src/client/app/common/views/components/ui/form/button.vue
index 6e1475bc38..9c37b3118b 100644
--- a/src/client/app/common/views/components/ui/form/button.vue
+++ b/src/client/app/common/views/components/ui/form/button.vue
@@ -45,6 +45,9 @@ root(isDark)
 		color isDark ? #fff : #606266
 		transition 0.1s
 
+		*
+			pointer-events none
+
 		&:hover
 		&:focus
 			color $theme-color

From 1ccd2def50c9318770faa01663caf8871e5f4737 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Mon, 6 Aug 2018 00:15:13 +0900
Subject: [PATCH 42/94] 5.17.0

---
 package.json | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 882291ae87..11090ef422 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "5.16.0",
-	"clientVersion": "1.0.8018",
+	"version": "5.17.0",
+	"clientVersion": "1.0.8026",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,

From ee765d081250ec9ddd8d0c616d1a79ada7a9d594 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Mon, 6 Aug 2018 00:31:09 +0900
Subject: [PATCH 43/94] Fix test

---
 test/mfm.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/mfm.ts b/test/mfm.ts
index 697d92e170..706c4c549a 100644
--- a/test/mfm.ts
+++ b/test/mfm.ts
@@ -34,7 +34,7 @@ describe('Text', () => {
 		it('big', () => {
 			const tokens = analyze('***Strawberry*** Pasta');
 			assert.deepEqual([
-				{ type: 'big', content: '***Strawberry***', bold: 'Strawberry' },
+				{ type: 'big', content: '***Strawberry***', big: 'Strawberry' },
 				{ type: 'text', content: ' Pasta' }
 			], tokens);
 		});

From 84a417488338e16572988c606225c3e50939988c Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Mon, 6 Aug 2018 04:07:22 +0900
Subject: [PATCH 44/94] =?UTF-8?q?=E5=89=8A=E9=99=A4=E3=81=95=E3=82=8C?=
 =?UTF-8?q?=E3=81=9F=E6=8A=95=E7=A8=BF=E3=81=AB=E8=BF=94=E4=BF=A1=E3=81=97?=
 =?UTF-8?q?=E3=81=9F=E3=82=8ARenote=E3=81=97=E3=81=9F=E3=82=8A=E3=81=A7?=
 =?UTF-8?q?=E3=81=8D=E3=81=AA=E3=81=84=E3=82=88=E3=81=86=E3=81=AB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/services/note/create.ts | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/src/services/note/create.ts b/src/services/note/create.ts
index 64556c160a..136e4fd076 100644
--- a/src/services/note/create.ts
+++ b/src/services/note/create.ts
@@ -103,6 +103,14 @@ export default async (user: IUser, data: Option, silent = false) => new Promise<
 		data.visibleUsers = data.visibleUsers.filter(x => x != null);
 	}
 
+	if (data.reply && data.reply.deletedAt != null) {
+		return rej();
+	}
+
+	if (data.renote && data.renote.deletedAt != null) {
+		return rej();
+	}
+
 	if (data.text) {
 		data.text = data.text.trim();
 	}

From 10f9549a0467dc89c5741c949745d85d4c3511a7 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Mon, 6 Aug 2018 04:38:31 +0900
Subject: [PATCH 45/94] =?UTF-8?q?=E9=9D=9E=E5=85=AC=E9=96=8B=E3=81=AE?=
 =?UTF-8?q?=E6=8A=95=E7=A8=BF=E3=81=AB=E8=87=AA=E5=88=86=E4=BB=A5=E5=A4=96?=
 =?UTF-8?q?=E3=81=8C=E8=BF=94=E4=BF=A1=E3=81=97=E3=81=9F=E3=82=8ARenote?=
 =?UTF-8?q?=E3=81=97=E3=81=9F=E3=82=8A=E3=81=A7=E3=81=8D=E3=81=AA=E3=81=84?=
 =?UTF-8?q?=E3=82=88=E3=81=86=E3=81=AB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/services/note/create.ts | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/src/services/note/create.ts b/src/services/note/create.ts
index 136e4fd076..4f90a19f2c 100644
--- a/src/services/note/create.ts
+++ b/src/services/note/create.ts
@@ -111,6 +111,16 @@ export default async (user: IUser, data: Option, silent = false) => new Promise<
 		return rej();
 	}
 
+	// リプライ先が自分以外の非公開の投稿なら禁止
+	if (data.reply && data.reply.visibility == 'private' && !data.reply.userId.equals(user._id)) {
+		return rej();
+	}
+
+	// Renote先が自分以外の非公開の投稿なら禁止
+	if (data.renote && data.renote.visibility == 'private' && !data.renote.userId.equals(user._id)) {
+		return rej();
+	}
+
 	if (data.text) {
 		data.text = data.text.trim();
 	}

From 06390380f86e7cd505283e00fa93eb354ecd0f0b Mon Sep 17 00:00:00 2001
From: gutfuckllc <40531868+gutfuckllc@users.noreply.github.com>
Date: Mon, 6 Aug 2018 03:18:52 -0400
Subject: [PATCH 46/94] Translated mute.

---
 locales/ja.yml                                           | 1 +
 src/client/app/desktop/views/pages/user/user.profile.vue | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/locales/ja.yml b/locales/ja.yml
index 1e0359254f..4928178060 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -964,6 +964,7 @@ desktop/views/pages/user/user.profile.vue:
   mute: "ミュートする"
   muted: "ミュートしています"
   unmute: "ミュート解除"
+  add-to-list: "リストに追加"
 
 desktop/views/pages/user/user.header.vue:
   posts: "投稿"
diff --git a/src/client/app/desktop/views/pages/user/user.profile.vue b/src/client/app/desktop/views/pages/user/user.profile.vue
index b74dbc7e25..35993f19a5 100644
--- a/src/client/app/desktop/views/pages/user/user.profile.vue
+++ b/src/client/app/desktop/views/pages/user/user.profile.vue
@@ -13,7 +13,7 @@
 			<span v-if="user.isMuted">%fa:eye% %i18n:@unmute%</span>
 			<span v-if="!user.isMuted">%fa:eye-slash% %i18n:@mute%</span>
 		</button>
-		<button class="mute ui" @click="list">%fa:list% リストに追加</button>
+		<button class="mute ui" @click="list">%fa:list% %i18n:@add-to-list%</button>
 	</div>
 </div>
 </template>

From 2ec4cc9a072e321fd95f172f207e52b10bf228ac Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Mon, 6 Aug 2018 07:19:30 +0000
Subject: [PATCH 47/94] fix(package): update webpack to version 4.16.5

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 11090ef422..ec0e7becb9 100644
--- a/package.json
+++ b/package.json
@@ -214,7 +214,7 @@
 		"vuex-persistedstate": "2.5.4",
 		"web-push": "3.3.2",
 		"webfinger.js": "2.6.6",
-		"webpack": "4.16.4",
+		"webpack": "4.16.5",
 		"webpack-cli": "3.1.0",
 		"websocket": "1.0.26",
 		"ws": "6.0.0",

From 5f208a7d99cf985e9c613e2d65656ae4d46aa68a Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Mon, 6 Aug 2018 18:28:27 +0900
Subject: [PATCH 48/94] =?UTF-8?q?=E3=83=A6=E3=83=BC=E3=82=B6=E3=83=BC?=
 =?UTF-8?q?=E6=A4=9C=E7=B4=A2API=E3=82=92=E7=B5=B1=E5=90=88?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../common/views/components/autocomplete.vue  |   2 +-
 src/server/api/endpoints/users/search.ts      | 161 +++++++++++++++---
 .../api/endpoints/users/search_by_username.ts |  70 --------
 3 files changed, 143 insertions(+), 90 deletions(-)
 delete mode 100644 src/server/api/endpoints/users/search_by_username.ts

diff --git a/src/client/app/common/views/components/autocomplete.vue b/src/client/app/common/views/components/autocomplete.vue
index cd6066877c..b274eaa0a0 100644
--- a/src/client/app/common/views/components/autocomplete.vue
+++ b/src/client/app/common/views/components/autocomplete.vue
@@ -132,7 +132,7 @@ export default Vue.extend({
 					this.users = users;
 					this.fetching = false;
 				} else {
-					(this as any).api('users/search_by_username', {
+					(this as any).api('users/search', {
 						query: this.q,
 						limit: 30
 					}).then(users => {
diff --git a/src/server/api/endpoints/users/search.ts b/src/server/api/endpoints/users/search.ts
index d443d35b47..eda3f95728 100644
--- a/src/server/api/endpoints/users/search.ts
+++ b/src/server/api/endpoints/users/search.ts
@@ -1,33 +1,156 @@
 import $ from 'cafy';
-import User, { pack, ILocalUser } from '../../../../models/user';
 const escapeRegexp = require('escape-regexp');
+import User, { pack, ILocalUser, validateUsername, IUser } from '../../../../models/user';
+import getParams from '../../get-params';
+
+export const meta = {
+	desc: {
+		ja: 'ユーザーを検索します。'
+	},
+
+	requireCredential: false,
+
+	params: {
+		query: $.str.note({
+			desc: {
+				ja: 'クエリ'
+			}
+		}),
+
+		offset: $.num.optional.min(0).note({
+			default: 0,
+			desc: {
+				ja: 'オフセット'
+			}
+		}),
+
+		limit: $.num.optional.range(1, 100).note({
+			default: 10,
+			desc: {
+				ja: '取得する数'
+			}
+		}),
+
+		localOnly: $.bool.optional.note({
+			default: false,
+			desc: {
+				ja: 'ローカルユーザーのみ検索対象にするか否か'
+			}
+		}),
+	},
+};
 
 /**
  * Search a user
  */
 export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => {
-	// Get 'query' parameter
-	const [query, queryError] = $.str.pipe(x => x != '').get(params.query);
-	if (queryError) return rej('invalid query param');
+	const [ps, psErr] = getParams(meta, params);
+	if (psErr) return rej(psErr);
 
-	// Get 'max' parameter
-	const [max = 10, maxErr] = $.num.optional.range(1, 30).get(params.max);
-	if (maxErr) return rej('invalid max param');
+	const isUsername = validateUsername(ps.query.replace('@', ''));
 
-	const escapedQuery = escapeRegexp(query);
+	let users: IUser[] = [];
 
-	// Search users
-	const users = await User
-		.find({
-			host: null,
-			$or: [{
-				usernameLower: new RegExp(escapedQuery.replace('@', '').toLowerCase())
+	if (isUsername) {
+		users = await User
+			.find({
+				host: null,
+				usernameLower: new RegExp('^' + escapeRegexp(ps.query.replace('@', '').toLowerCase()))
 			}, {
-				name: new RegExp(escapedQuery)
-			}]
-		}, {
-			limit: max
-		});
+				limit: ps.limit,
+				skip: ps.offset
+			});
+
+		if (users.length < ps.limit && !ps.localOnly) {
+			const otherUsers = await User
+				.find({
+					host: { $ne: null },
+					usernameLower: new RegExp('^' + escapeRegexp(ps.query.replace('@', '').toLowerCase()))
+				}, {
+					limit: ps.limit - users.length
+				});
+
+			users = users.concat(otherUsers);
+		}
+
+		if (users.length < ps.limit) {
+			const otherUsers = await User
+				.find({
+					_id: { $nin: users.map(u => u._id) },
+					host: null,
+					usernameLower: new RegExp(escapeRegexp(ps.query.replace('@', '').toLowerCase()))
+				}, {
+					limit: ps.limit - users.length
+				});
+
+			users = users.concat(otherUsers);
+		}
+
+		if (users.length < ps.limit && !ps.localOnly) {
+			const otherUsers = await User
+				.find({
+					_id: { $nin: users.map(u => u._id) },
+					host: { $ne: null },
+					usernameLower: new RegExp(escapeRegexp(ps.query.replace('@', '').toLowerCase()))
+				}, {
+					limit: ps.limit - users.length
+				});
+
+			users = users.concat(otherUsers);
+		}
+	}
+
+	if (users.length < ps.limit) {
+		const otherUsers = await User
+			.find({
+				_id: { $nin: users.map(u => u._id) },
+				host: null,
+				name: new RegExp('^' + escapeRegexp(ps.query.toLowerCase()))
+			}, {
+				limit: ps.limit - users.length
+			});
+
+		users = users.concat(otherUsers);
+	}
+
+	if (users.length < ps.limit && !ps.localOnly) {
+		const otherUsers = await User
+			.find({
+				_id: { $nin: users.map(u => u._id) },
+				host: { $ne: null },
+				name: new RegExp('^' + escapeRegexp(ps.query.toLowerCase()))
+			}, {
+				limit: ps.limit - users.length
+			});
+
+		users = users.concat(otherUsers);
+	}
+
+	if (users.length < ps.limit) {
+		const otherUsers = await User
+			.find({
+				_id: { $nin: users.map(u => u._id) },
+				host: null,
+				name: new RegExp(escapeRegexp(ps.query.toLowerCase()))
+			}, {
+				limit: ps.limit - users.length
+			});
+
+		users = users.concat(otherUsers);
+	}
+
+	if (users.length < ps.limit && !ps.localOnly) {
+		const otherUsers = await User
+			.find({
+				_id: { $nin: users.map(u => u._id) },
+				host: { $ne: null },
+				name: new RegExp(escapeRegexp(ps.query.toLowerCase()))
+			}, {
+				limit: ps.limit - users.length
+			});
+
+		users = users.concat(otherUsers);
+	}
 
 	// Serialize
 	res(await Promise.all(users.map(user => pack(user, me, { detail: true }))));
diff --git a/src/server/api/endpoints/users/search_by_username.ts b/src/server/api/endpoints/users/search_by_username.ts
deleted file mode 100644
index bfab378389..0000000000
--- a/src/server/api/endpoints/users/search_by_username.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-import $ from 'cafy';
-import User, { pack, ILocalUser } from '../../../../models/user';
-const escapeRegexp = require('escape-regexp');
-
-/**
- * Search a user by username
- */
-export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => {
-	// Get 'query' parameter
-	const [query, queryError] = $.str.get(params.query);
-	if (queryError) return rej('invalid query param');
-
-	// Get 'offset' parameter
-	const [offset = 0, offsetErr] = $.num.optional.min(0).get(params.offset);
-	if (offsetErr) return rej('invalid offset param');
-
-	// Get 'limit' parameter
-	const [limit = 10, limitErr] = $.num.optional.range(1, 100).get(params.limit);
-	if (limitErr) return rej('invalid limit param');
-
-	let users = await User
-		.find({
-			host: null,
-			usernameLower: new RegExp('^' + escapeRegexp(query.toLowerCase()))
-		}, {
-			limit: limit,
-			skip: offset
-		});
-
-	if (users.length < limit) {
-		const otherUsers = await User
-			.find({
-				host: { $ne: null },
-				usernameLower: new RegExp('^' + escapeRegexp(query.toLowerCase()))
-			}, {
-				limit: limit - users.length
-			});
-
-		users = users.concat(otherUsers);
-	}
-
-	if (users.length < limit) {
-		const otherUsers = await User
-			.find({
-				_id: { $nin: users.map(u => u._id) },
-				host: null,
-				usernameLower: new RegExp(escapeRegexp(query.toLowerCase()))
-			}, {
-				limit: limit - users.length
-			});
-
-		users = users.concat(otherUsers);
-	}
-
-	if (users.length < limit) {
-		const otherUsers = await User
-			.find({
-				_id: { $nin: users.map(u => u._id) },
-				host: { $ne: null },
-				usernameLower: new RegExp(escapeRegexp(query.toLowerCase()))
-			}, {
-				limit: limit - users.length
-			});
-
-		users = users.concat(otherUsers);
-	}
-
-	// Serialize
-	res(await Promise.all(users.map(user => pack(user, me, { detail: true }))));
-});

From b6157e0012e23842f24f38dfdd652c7d719e4da3 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Mon, 6 Aug 2018 18:30:19 +0900
Subject: [PATCH 49/94] 5.18.0

---
 package.json | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index ec0e7becb9..2b8a1f36d6 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "5.17.0",
-	"clientVersion": "1.0.8026",
+	"version": "5.18.0",
+	"clientVersion": "1.0.8033",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,

From 99f4ab700028cc8d959d173d1d17b25f26b7e4a3 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Mon, 6 Aug 2018 21:35:49 +0900
Subject: [PATCH 50/94] :v:

---
 src/index.ts | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/index.ts b/src/index.ts
index 18eff8176c..0dda8b05b7 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -4,6 +4,8 @@
 
 Error.stackTraceLimit = Infinity;
 
+require('events').EventEmitter.defaultMaxListeners = 128;
+
 import * as os from 'os';
 import * as cluster from 'cluster';
 import * as debug from 'debug';

From 4260ec713fa51a7e50a09445dfe0a23840b63f9e Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Mon, 6 Aug 2018 21:48:23 +0900
Subject: [PATCH 51/94] Improve error handling

---
 src/queue/processors/http/deliver.ts | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/queue/processors/http/deliver.ts b/src/queue/processors/http/deliver.ts
index e06866da4e..75e46559dd 100644
--- a/src/queue/processors/http/deliver.ts
+++ b/src/queue/processors/http/deliver.ts
@@ -7,6 +7,11 @@ export default async (job: bq.Job, done: any): Promise<void> => {
 		await request(job.data.user, job.data.to, job.data.content);
 		done();
 	} catch (res) {
+		if (!res.hasOwnProperty('statusCode')) {
+			console.warn(`deliver failed (unknown): ${res}`);
+			return done();
+		}
+
 		if (res.statusCode == null) return done();
 		if (res.statusCode >= 400 && res.statusCode < 500) {
 			// HTTPステータスコード4xxはクライアントエラーであり、それはつまり

From d733a1b445db1e70f55b3cbac4786d81486bc34a Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Tue, 7 Aug 2018 03:20:26 +0900
Subject: [PATCH 52/94] i18n

---
 locales/ja.yml                                | 27 ++++++++++++-------
 .../app/common/scripts/date-stringify.ts      | 13 ---------
 .../app/common/views/components/signin.vue    |  2 +-
 src/client/app/desktop/api/update-avatar.ts   | 16 +++++------
 src/client/app/desktop/api/update-banner.ts   | 16 +++++------
 .../desktop/views/components/note-detail.vue  |  3 +--
 .../desktop/views/components/note-preview.vue |  3 +--
 .../views/components/notes.note.sub.vue       |  3 +--
 .../desktop/views/components/notes.note.vue   |  3 +--
 .../views/components/user-lists-window.vue    |  2 +-
 .../desktop/views/pages/user/user.profile.vue |  4 +--
 .../app/desktop/views/widgets/post-form.vue   |  2 +-
 12 files changed, 43 insertions(+), 51 deletions(-)
 delete mode 100644 src/client/app/common/scripts/date-stringify.ts

diff --git a/locales/ja.yml b/locales/ja.yml
index 1e0359254f..6aac8acca2 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -11,6 +11,7 @@ common:
     warning: "<strong>Misskeyは広告を掲載していません</strong>が、広告をブロックする機能が有効だと一部の機能が利用できなかったり、不具合が発生する場合があります。"
   application-authorization: "アプリの連携"
   close: "閉じる"
+  got-it: "わかった"
   customization-tips:
     title: "カスタマイズのヒント"
     paragraph1: "ホームのカスタマイズでは、ウィジェットを追加/削除したり、ドラッグ&ドロップして並べ替えたりすることができます。"
@@ -41,13 +42,6 @@ common:
 
   trash: "ゴミ箱"
 
-  date:
-    full-year: "年"
-    month: "月"
-    day: "日"
-    hours: "時"
-    minutes: "分"
-
   weekday-short:
     sunday: "日"
     monday: "月"
@@ -311,6 +305,8 @@ common/views/components/signin.vue:
   token: "トークン"
   signing-in: "やってます..."
   signin: "サインイン"
+  or: "または"
+  signin-with-twitter: "Twitterでログイン"
 
 common/views/components/signup.vue:
   username: "ユーザー名"
@@ -438,6 +434,18 @@ common/views/pages/follow.vue:
   request-pending: "フォロー許可待ち"
   follow-request: "フォロー申請"
 
+desktop:
+  banner-crop-title: "バナーとして表示する部分を選択"
+  banner: "バナー"
+  uploading-banner: "新しいバナーをアップロードしています"
+  banner-updated: "バナーを更新しました"
+  choose-banner: "バナーにする画像を選択"
+  avatar-crop-title: "アバターとして表示する部分を選択"
+  avatar: "アバター"
+  uploading-avatar: "新しいアバターをアップロードしています"
+  avatar-updated: "アバターを更新しました"
+  choose-avatar: "アバターにする画像を選択"
+
 desktop/views/components/activity.chart.vue:
   total: "Black ... Total"
   notes: "Blue ... Notes"
@@ -855,11 +863,10 @@ desktop/views/components/received-follow-requests-window.vue:
   accept: "承認"
   reject: "拒否"
 
-
-
 desktop/views/components/user-lists-window.vue:
   title: "リスト"
   create-list: "リストを作成"
+  list-name: "リスト名"
 
 desktop/views/components/user-preview.vue:
   notes: "投稿"
@@ -964,6 +971,8 @@ desktop/views/pages/user/user.profile.vue:
   mute: "ミュートする"
   muted: "ミュートしています"
   unmute: "ミュート解除"
+  push-to-a-list: "リストに追加"
+  list-pushed: "{user}を{list}に追加しました。"
 
 desktop/views/pages/user/user.header.vue:
   posts: "投稿"
diff --git a/src/client/app/common/scripts/date-stringify.ts b/src/client/app/common/scripts/date-stringify.ts
deleted file mode 100644
index 2b8e525567..0000000000
--- a/src/client/app/common/scripts/date-stringify.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-export default date => {
-	if (typeof date == 'string') date = new Date(date);
-	return (
-		date.getFullYear()    + '%i18n:common.date.full-year%' +
-		(date.getMonth() + 1) + '%i18n:common.date.month%' +
-		date.getDate()        + '%i18n:common.date.day%' +
-		' ' +
-		date.getHours()       + '%i18n:common.date.hours%' +
-		date.getMinutes()     + '%i18n:common.date.minutes%' +
-		' ' +
-		`(${['日', '月', '火', '水', '木', '金', '土'][date.getDay()]})`
-	);
-};
diff --git a/src/client/app/common/views/components/signin.vue b/src/client/app/common/views/components/signin.vue
index 58241cef09..deaeeca6a7 100644
--- a/src/client/app/common/views/components/signin.vue
+++ b/src/client/app/common/views/components/signin.vue
@@ -12,7 +12,7 @@
 	</ui-input>
 	<ui-input v-if="user && user.twoFactorEnabled" v-model="token" type="number" required/>
 	<ui-button type="submit" :disabled="signing">{{ signing ? '%i18n:@signing-in%' : '%i18n:@signin%' }}</ui-button>
-	<p style="margin: 8px 0;">または<a :href="`${apiUrl}/signin/twitter`">Twitterでログイン</a></p>
+	<p style="margin: 8px 0;">%i18n:@or%<a :href="`${apiUrl}/signin/twitter`">%i18n:@signin-with-twitter%</a></p>
 </form>
 </template>
 
diff --git a/src/client/app/desktop/api/update-avatar.ts b/src/client/app/desktop/api/update-avatar.ts
index 887367a24e..83820f92bd 100644
--- a/src/client/app/desktop/api/update-avatar.ts
+++ b/src/client/app/desktop/api/update-avatar.ts
@@ -8,7 +8,7 @@ export default (os: OS) => (cb, file = null) => {
 
 		const w = os.new(CropWindow, {
 			image: file,
-			title: 'アバターとして表示する部分を選択',
+			title: '%i18n:desktop.avatar-crop-title%',
 			aspectRatio: 1 / 1
 		});
 
@@ -18,11 +18,11 @@ export default (os: OS) => (cb, file = null) => {
 			data.append('file', blob, file.name + '.cropped.png');
 
 			os.api('drive/folders/find', {
-				name: 'アイコン'
+				name: '%i18n:desktop.avatar%'
 			}).then(iconFolder => {
 				if (iconFolder.length === 0) {
 					os.api('drive/folders/create', {
-						name: 'アイコン'
+						name: '%i18n:desktop.avatar%'
 					}).then(iconFolder => {
 						upload(data, iconFolder);
 					});
@@ -41,7 +41,7 @@ export default (os: OS) => (cb, file = null) => {
 
 	const upload = (data, folder) => {
 		const dialog = os.new(ProgressDialog, {
-			title: '新しいアバターをアップロードしています'
+			title: '%i18n:desktop.uploading-avatar%'
 		});
 		document.body.appendChild(dialog.$el);
 
@@ -76,10 +76,10 @@ export default (os: OS) => (cb, file = null) => {
 			});
 
 			os.apis.dialog({
-				title: '%fa:info-circle%アバターを更新しました',
-				text: '新しいアバターが反映されるまで時間がかかる場合があります。',
+				title: '%fa:info-circle% %i18n:desktop.avatar-updated%',
+				text: null,
 				actions: [{
-					text: 'わかった'
+					text: '%i18n:common.got-it%'
 				}]
 			});
 
@@ -92,7 +92,7 @@ export default (os: OS) => (cb, file = null) => {
 	} else {
 		os.apis.chooseDriveFile({
 			multiple: false,
-			title: '%fa:image%アバターにする画像を選択'
+			title: '%fa:image% %i18n:desktop.choose-avatar%'
 		}).then(file => {
 			fileSelected(file);
 		});
diff --git a/src/client/app/desktop/api/update-banner.ts b/src/client/app/desktop/api/update-banner.ts
index 4e6dd4e2c7..33c4e306a2 100644
--- a/src/client/app/desktop/api/update-banner.ts
+++ b/src/client/app/desktop/api/update-banner.ts
@@ -8,7 +8,7 @@ export default (os: OS) => {
 	const cropImage = file => new Promise((resolve, reject) => {
 		const w = os.new(CropWindow, {
 			image: file,
-			title: 'バナーとして表示する部分を選択',
+			title: '%i18n:desktop.banner-crop-title%',
 			aspectRatio: 16 / 9
 		});
 
@@ -18,11 +18,11 @@ export default (os: OS) => {
 			data.append('file', blob, file.name + '.cropped.png');
 
 			os.api('drive/folders/find', {
-				name: 'バナー'
+				name: '%i18n:desktop.banner%'
 			}).then(bannerFolder => {
 				if (bannerFolder.length === 0) {
 					os.api('drive/folders/create', {
-						name: 'バナー'
+						name: '%i18n:desktop.banner%'
 					}).then(iconFolder => {
 						resolve(upload(data, iconFolder));
 					});
@@ -43,7 +43,7 @@ export default (os: OS) => {
 
 	const upload = (data, folder) => new Promise((resolve, reject) => {
 		const dialog = os.new(ProgressDialog, {
-			title: '新しいバナーをアップロードしています'
+			title: '%i18n:desktop.uploading-banner%'
 		});
 		document.body.appendChild(dialog.$el);
 
@@ -79,10 +79,10 @@ export default (os: OS) => {
 			});
 
 			os.apis.dialog({
-				title: '%fa:info-circle%バナーを更新しました',
-				text: '新しいバナーが反映されるまで時間がかかる場合があります。',
+				title: '%fa:info-circle% %i18n:desktop.banner-updated%',
+				text: null,
 				actions: [{
-					text: 'わかった'
+					text: '%i18n:common.got-it%'
 				}]
 			});
 
@@ -95,7 +95,7 @@ export default (os: OS) => {
 			? Promise.resolve(file)
 			: os.apis.chooseDriveFile({
 				multiple: false,
-				title: '%fa:image%バナーにする画像を選択'
+				title: '%fa:image% %i18n:desktop.choose-banner%'
 			});
 
 		return selectedFile
diff --git a/src/client/app/desktop/views/components/note-detail.vue b/src/client/app/desktop/views/components/note-detail.vue
index 36a5889220..b6980fae72 100644
--- a/src/client/app/desktop/views/components/note-detail.vue
+++ b/src/client/app/desktop/views/components/note-detail.vue
@@ -79,7 +79,6 @@
 
 <script lang="ts">
 import Vue from 'vue';
-import dateStringify from '../../../common/scripts/date-stringify';
 import parse from '../../../../../mfm/parse';
 
 import MkPostFormWindow from './post-form-window.vue';
@@ -129,7 +128,7 @@ export default Vue.extend({
 				: 0;
 		},
 		title(): string {
-			return dateStringify(this.p.createdAt);
+			return new Date(this.p.createdAt).toLocaleString();
 		},
 		urls(): string[] {
 			if (this.p.text) {
diff --git a/src/client/app/desktop/views/components/note-preview.vue b/src/client/app/desktop/views/components/note-preview.vue
index 2a49557247..c723db98c0 100644
--- a/src/client/app/desktop/views/components/note-preview.vue
+++ b/src/client/app/desktop/views/components/note-preview.vue
@@ -12,7 +12,6 @@
 
 <script lang="ts">
 import Vue from 'vue';
-import dateStringify from '../../../common/scripts/date-stringify';
 
 export default Vue.extend({
 	props: {
@@ -28,7 +27,7 @@ export default Vue.extend({
 	},
 	computed: {
 		title(): string {
-			return dateStringify(this.note.createdAt);
+			return new Date(this.note.createdAt).toLocaleString();
 		}
 	}
 });
diff --git a/src/client/app/desktop/views/components/notes.note.sub.vue b/src/client/app/desktop/views/components/notes.note.sub.vue
index a8186fb7e4..fc851e83e9 100644
--- a/src/client/app/desktop/views/components/notes.note.sub.vue
+++ b/src/client/app/desktop/views/components/notes.note.sub.vue
@@ -12,13 +12,12 @@
 
 <script lang="ts">
 import Vue from 'vue';
-import dateStringify from '../../../common/scripts/date-stringify';
 
 export default Vue.extend({
 	props: ['note'],
 	computed: {
 		title(): string {
-			return dateStringify(this.note.createdAt);
+			return new Date(this.note.createdAt).toLocaleString();
 		}
 	}
 });
diff --git a/src/client/app/desktop/views/components/notes.note.vue b/src/client/app/desktop/views/components/notes.note.vue
index 3aa52f75f0..fbbd524070 100644
--- a/src/client/app/desktop/views/components/notes.note.vue
+++ b/src/client/app/desktop/views/components/notes.note.vue
@@ -71,7 +71,6 @@
 
 <script lang="ts">
 import Vue from 'vue';
-import dateStringify from '../../../common/scripts/date-stringify';
 import parse from '../../../../../mfm/parse';
 
 import MkPostFormWindow from './post-form-window.vue';
@@ -128,7 +127,7 @@ export default Vue.extend({
 		},
 
 		title(): string {
-			return dateStringify(this.p.createdAt);
+			return new Date(this.p.createdAt).toLocaleString();
 		},
 
 		urls(): string[] {
diff --git a/src/client/app/desktop/views/components/user-lists-window.vue b/src/client/app/desktop/views/components/user-lists-window.vue
index 47648c287d..72ae9cf4e4 100644
--- a/src/client/app/desktop/views/components/user-lists-window.vue
+++ b/src/client/app/desktop/views/components/user-lists-window.vue
@@ -27,7 +27,7 @@ export default Vue.extend({
 	methods: {
 		add() {
 			(this as any).apis.input({
-				title: 'リスト名',
+				title: '%i18n:@list-name%',
 			}).then(async title => {
 				const list = await (this as any).api('users/lists/create', {
 					title
diff --git a/src/client/app/desktop/views/pages/user/user.profile.vue b/src/client/app/desktop/views/pages/user/user.profile.vue
index b74dbc7e25..efd5be4672 100644
--- a/src/client/app/desktop/views/pages/user/user.profile.vue
+++ b/src/client/app/desktop/views/pages/user/user.profile.vue
@@ -13,7 +13,7 @@
 			<span v-if="user.isMuted">%fa:eye% %i18n:@unmute%</span>
 			<span v-if="!user.isMuted">%fa:eye-slash% %i18n:@mute%</span>
 		</button>
-		<button class="mute ui" @click="list">%fa:list% リストに追加</button>
+		<button class="mute ui" @click="list">%fa:list% %i18n:@push-to-a-list%</button>
 	</div>
 </div>
 </template>
@@ -76,7 +76,7 @@ export default Vue.extend({
 				});
 				(this as any).apis.dialog({
 					title: 'Done!',
-					text: `${this.user.name}を${list.title}に追加しました。`
+					text: '%i18n:@list-pushed%'.replace('{user}', this.user.name).replace('{list}', list.title)
 				});
 			});
 		}
diff --git a/src/client/app/desktop/views/widgets/post-form.vue b/src/client/app/desktop/views/widgets/post-form.vue
index 618d19efc4..19a2790d95 100644
--- a/src/client/app/desktop/views/widgets/post-form.vue
+++ b/src/client/app/desktop/views/widgets/post-form.vue
@@ -55,7 +55,7 @@ export default define({
 			}).then(data => {
 				this.clear();
 			}).catch(err => {
-				alert('失敗した');
+				alert('Something happened');
 			}).then(() => {
 				this.posting = false;
 			});

From d81acae17ea207e626d184ef08fdb45d1c283963 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Tue, 7 Aug 2018 03:33:21 +0900
Subject: [PATCH 53/94] 5.19.0

---
 package.json | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 2b8a1f36d6..5a7c0a2dd8 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "5.18.0",
-	"clientVersion": "1.0.8033",
+	"version": "5.19.0",
+	"clientVersion": "1.0.8052",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,

From 096fab575cdb7d4c2778729a9f1a65963134def2 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Mon, 6 Aug 2018 19:52:58 +0000
Subject: [PATCH 54/94] fix(package): update typescript-eslint-parser to
 version 18.0.0

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 5a7c0a2dd8..83ca4541a8 100644
--- a/package.json
+++ b/package.json
@@ -196,7 +196,7 @@
 		"ts-node": "7.0.0",
 		"tslint": "5.10.0",
 		"typescript": "2.9.2",
-		"typescript-eslint-parser": "17.0.1",
+		"typescript-eslint-parser": "18.0.0",
 		"uglify-es": "3.3.9",
 		"url-loader": "1.0.1",
 		"uuid": "3.3.2",

From a303d52990a9796bcdec8c7479e709d9e884dd87 Mon Sep 17 00:00:00 2001
From: gutfuckllc <40531868+gutfuckllc@users.noreply.github.com>
Date: Mon, 6 Aug 2018 15:53:06 -0400
Subject: [PATCH 55/94] Fix typo

---
 src/client/app/common/scripts/compose-notification.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/client/app/common/scripts/compose-notification.ts b/src/client/app/common/scripts/compose-notification.ts
index 4fb0610fd7..f42af94370 100644
--- a/src/client/app/common/scripts/compose-notification.ts
+++ b/src/client/app/common/scripts/compose-notification.ts
@@ -38,7 +38,7 @@ export default function(type, data): Notification {
 			switch (data.type) {
 				case 'mention':
 					return {
-						title: '%i18n:common.notification.notified-by%'.split("{}")[0] + `${getUserName(data.user)}さんから:` + '%i18n:common.notification.notified-by%'.split("{}")[1],
+						title: '%i18n:common.notification.notified-by%'.split("{}")[0] + `${getUserName(data.user)}:` + '%i18n:common.notification.notified-by%'.split("{}")[1],
 						body: getNoteSummary(data),
 						icon: data.user.avatarUrl
 					};

From 790e6ceca4497e0748d0153b391c456bfa072fa4 Mon Sep 17 00:00:00 2001
From: gutfuckllc <40531868+gutfuckllc@users.noreply.github.com>
Date: Mon, 6 Aug 2018 15:53:21 -0400
Subject: [PATCH 56/94] Localize unlocalized line

---
 locales/ja.yml                                            | 1 +
 src/client/app/common/views/components/messaging-room.vue | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/locales/ja.yml b/locales/ja.yml
index 6aac8acca2..a77ce46531 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -253,6 +253,7 @@ common/views/components/messaging-room.vue:
   no-history: "これより過去の履歴はありません"
   resize-form: "ドラッグしてフォームの広さを調整"
   new-message: "新しいメッセージがあります"
+  only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
 
 common/views/components/messaging-room.form.vue:
   input-message-here: "ここにメッセージを入力"
diff --git a/src/client/app/common/views/components/messaging-room.vue b/src/client/app/common/views/components/messaging-room.vue
index b2831d6928..e4cc30ded9 100644
--- a/src/client/app/common/views/components/messaging-room.vue
+++ b/src/client/app/common/views/components/messaging-room.vue
@@ -111,7 +111,7 @@ export default Vue.extend({
 				this.form.upload(e.dataTransfer.files[0]);
 				return;
 			} else if (e.dataTransfer.files.length > 1) {
-				alert('メッセージに添付できるのはひとつのファイルのみです');
+				alert('%i18n:@only-one-file-attached%');
 				return;
 			}
 

From be12e23aa1750693097c382a5f8e4892f3318fe3 Mon Sep 17 00:00:00 2001
From: gutfuckllc <40531868+gutfuckllc@users.noreply.github.com>
Date: Mon, 6 Aug 2018 15:55:39 -0400
Subject: [PATCH 57/94] Localize unlocalized line.

---
 locales/ja.yml                                         | 2 ++
 src/client/app/desktop/views/components/notes.note.vue | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/locales/ja.yml b/locales/ja.yml
index a77ce46531..08a2d6d8f2 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -606,6 +606,8 @@ desktop/views/components/notes.note.vue:
   detail: "詳細"
   private: "この投稿は非公開です"
   deleted: "この投稿は削除されました"
+  hide: "隠す"
+  see-more: "もっと見る"
 
 desktop/views/components/notes.vue:
   error: "読み込みに失敗しました。"
diff --git a/src/client/app/desktop/views/components/notes.note.vue b/src/client/app/desktop/views/components/notes.note.vue
index fbbd524070..a98df104a3 100644
--- a/src/client/app/desktop/views/components/notes.note.vue
+++ b/src/client/app/desktop/views/components/notes.note.vue
@@ -18,7 +18,7 @@
 			<div class="body">
 				<p v-if="p.cw != null" class="cw">
 					<span class="text" v-if="p.cw != ''">{{ p.cw }}</span>
-					<span class="toggle" @click="showContent = !showContent">{{ showContent ? '隠す' : 'もっと見る' }}</span>
+					<span class="toggle" @click="showContent = !showContent">{{ showContent ? '%i18n:@hide%' : '%i18n:@see-more%' }}</span>
 				</p>
 				<div class="content" v-show="p.cw == null || showContent">
 					<div class="text">

From 1e4f11a9798419fc341d247292b8b97f3aba0389 Mon Sep 17 00:00:00 2001
From: gutfuckllc <40531868+gutfuckllc@users.noreply.github.com>
Date: Mon, 6 Aug 2018 15:58:09 -0400
Subject: [PATCH 58/94] Localize japanese adjective.

---
 locales/ja.yml                                        | 1 +
 src/client/app/desktop/views/components/ui.header.vue | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/locales/ja.yml b/locales/ja.yml
index 08a2d6d8f2..47f3ea9901 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -834,6 +834,7 @@ desktop/views/components/timeline.vue:
 
 desktop/views/components/ui.header.vue:
   welcome-back: "おかえりなさい、"
+  adjective: "さん"
 
 desktop/views/components/ui.header.account.vue:
   profile: "プロフィール"
diff --git a/src/client/app/desktop/views/components/ui.header.vue b/src/client/app/desktop/views/components/ui.header.vue
index 1ed5c3523b..83df4b2fbc 100644
--- a/src/client/app/desktop/views/components/ui.header.vue
+++ b/src/client/app/desktop/views/components/ui.header.vue
@@ -4,7 +4,7 @@
 	<div class="main" ref="main">
 		<div class="backdrop"></div>
 		<div class="main">
-			<p ref="welcomeback" v-if="$store.getters.isSignedIn">%i18n:@welcome-back%<b>{{ $store.state.i | userName }}</b>さん</p>
+			<p ref="welcomeback" v-if="$store.getters.isSignedIn">%i18n:@welcome-back%<b>{{ $store.state.i | userName }}</b>%i18n:@adjective%</p>
 			<div class="container" ref="mainContainer">
 				<div class="left">
 					<x-nav/>

From 1f75cf4ace1d9262131e487f91ad55b403e0a564 Mon Sep 17 00:00:00 2001
From: gutfuckllc <40531868+gutfuckllc@users.noreply.github.com>
Date: Mon, 6 Aug 2018 16:00:12 -0400
Subject: [PATCH 59/94] Localize missing line

---
 src/client/app/dev/views/app.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/client/app/dev/views/app.vue b/src/client/app/dev/views/app.vue
index a35b032b73..54d99ec82a 100644
--- a/src/client/app/dev/views/app.vue
+++ b/src/client/app/dev/views/app.vue
@@ -1,6 +1,6 @@
 <template>
 <mk-ui>
-	<p v-if="fetching">読み込み中</p>
+	<p v-if="fetching">%i18n:common.loading%</p>
 	<b-card v-if="!fetching" :header="app.name">
 		<b-form-group label="App Secret">
 			<b-input :value="app.secret" readonly/>

From f5b5b290e452dcab4f2c41566fbfce6f69ad5096 Mon Sep 17 00:00:00 2001
From: gutfuckllc <40531868+gutfuckllc@users.noreply.github.com>
Date: Mon, 6 Aug 2018 16:02:53 -0400
Subject: [PATCH 60/94] Localized copy-paste message (added common)

---
 locales/ja.yml         | 1 +
 src/client/app/init.ts | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/locales/ja.yml b/locales/ja.yml
index 47f3ea9901..03719d745a 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -10,6 +10,7 @@ common:
     detected: "広告ブロッカーを無効にしてください"
     warning: "<strong>Misskeyは広告を掲載していません</strong>が、広告をブロックする機能が有効だと一部の機能が利用できなかったり、不具合が発生する場合があります。"
   application-authorization: "アプリの連携"
+  do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。"
   close: "閉じる"
   got-it: "わかった"
   customization-tips:
diff --git a/src/client/app/init.ts b/src/client/app/init.ts
index 043f26d0bc..18f510ea24 100644
--- a/src/client/app/init.ts
+++ b/src/client/app/init.ts
@@ -55,7 +55,7 @@ Vue.mixin({
 
 console.info(`Misskey v${version} (${codename})`);
 console.info(
-	'%cここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。',
+	'%c%i18n:common.do-not-copy-paste%',
 	'color: red; background: yellow; font-size: 16px; font-weight: bold;');
 
 // BootTimer解除

From 4f590e0a96b55a2af0932dc56100d3f0b8ab5c77 Mon Sep 17 00:00:00 2001
From: gutfuckllc <40531868+gutfuckllc@users.noreply.github.com>
Date: Mon, 6 Aug 2018 16:04:20 -0400
Subject: [PATCH 61/94] Localized adjective

---
 locales/ja.yml                                       | 1 +
 src/client/app/mobile/views/components/ui.header.vue | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/locales/ja.yml b/locales/ja.yml
index 03719d745a..ccd18855bc 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -1133,6 +1133,7 @@ mobile/views/components/timeline.vue:
 
 mobile/views/components/ui.header.vue:
   welcome-back: "おかえりなさい、"
+  adjective: "さん"
 
 mobile/views/components/ui.nav.vue:
   timeline: "タイムライン"
diff --git a/src/client/app/mobile/views/components/ui.header.vue b/src/client/app/mobile/views/components/ui.header.vue
index 794ec9a307..63399f7465 100644
--- a/src/client/app/mobile/views/components/ui.header.vue
+++ b/src/client/app/mobile/views/components/ui.header.vue
@@ -3,7 +3,7 @@
 	<mk-special-message/>
 	<div class="main" ref="main">
 		<div class="backdrop"></div>
-		<p ref="welcomeback" v-if="$store.getters.isSignedIn">%i18n:@welcome-back%<b>{{ $store.state.i | userName }}</b>さん</p>
+		<p ref="welcomeback" v-if="$store.getters.isSignedIn">%i18n:@welcome-back%<b>{{ $store.state.i | userName }}</b>%i18n:@adjective%</p>
 		<div class="content" ref="mainContainer">
 			<button class="nav" @click="$parent.isDrawerOpening = true">%fa:bars%</button>
 			<template v-if="hasUnreadNotification || hasUnreadMessagingMessage || hasGameInvitation">%fa:circle%</template>

From 249a7f4f68ba4e911e51b35fc7234fbebf8ed362 Mon Sep 17 00:00:00 2001
From: gutfuckllc <40531868+gutfuckllc@users.noreply.github.com>
Date: Mon, 6 Aug 2018 16:05:32 -0400
Subject: [PATCH 62/94] Slight reordering

---
 locales/ja.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/locales/ja.yml b/locales/ja.yml
index ccd18855bc..d72a0a19fe 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -10,8 +10,8 @@ common:
     detected: "広告ブロッカーを無効にしてください"
     warning: "<strong>Misskeyは広告を掲載していません</strong>が、広告をブロックする機能が有効だと一部の機能が利用できなかったり、不具合が発生する場合があります。"
   application-authorization: "アプリの連携"
-  do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。"
   close: "閉じる"
+  do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。"
   got-it: "わかった"
   customization-tips:
     title: "カスタマイズのヒント"

From a169c7756ff78401053a6c49e80c7805940d570e Mon Sep 17 00:00:00 2001
From: gutfuckllc <40531868+gutfuckllc@users.noreply.github.com>
Date: Mon, 6 Aug 2018 16:05:48 -0400
Subject: [PATCH 63/94] Added more close buttons

---
 src/client/app/mobile/views/pages/share.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/client/app/mobile/views/pages/share.vue b/src/client/app/mobile/views/pages/share.vue
index 3e33e32732..fffbea9033 100644
--- a/src/client/app/mobile/views/pages/share.vue
+++ b/src/client/app/mobile/views/pages/share.vue
@@ -6,7 +6,7 @@
 		<mk-post-form v-else-if="!posted" :initial-text="text" :instant="true" @posted="posted = true"/>
 		<p v-if="posted" class="posted">%fa:check%</p>
 	</div>
-	<ui-button class="close" v-if="posted" @click="close">閉じる</ui-button>
+	<ui-button class="close" v-if="posted" @click="close">%i18n:common.close%</ui-button>
 </div>
 </template>
 

From 24de518922c05cd35aba4da9e65b35244147871f Mon Sep 17 00:00:00 2001
From: gutfuckllc <40531868+gutfuckllc@users.noreply.github.com>
Date: Mon, 6 Aug 2018 16:08:54 -0400
Subject: [PATCH 64/94] Localized 2 missing lines for mobile widgets.vue

---
 locales/ja.yml                                | 2 ++
 src/client/app/mobile/views/pages/widgets.vue | 4 ++--
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/locales/ja.yml b/locales/ja.yml
index d72a0a19fe..d1cc5c325c 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -1195,6 +1195,8 @@ mobile/views/pages/welcome.vue:
 mobile/views/pages/widgets.vue:
   dashboard: "ダッシュボード"
   widgets-hints: "ウィジェットを追加/削除したり並べ替えたりできます。ウィジェットを移動するには「三」をドラッグします。ウィジェットを削除するには「x」をタップします。いくつかのウィジェットはタップすることで表示を変更できます。"
+  add-widget: "追加"
+  customization-tips: "カスタマイズのヒント"
 
 mobile/views/pages/widgets/activity.vue:
   activity: "アクティビティ"
diff --git a/src/client/app/mobile/views/pages/widgets.vue b/src/client/app/mobile/views/pages/widgets.vue
index 4400132bf2..543ee8f7d8 100644
--- a/src/client/app/mobile/views/pages/widgets.vue
+++ b/src/client/app/mobile/views/pages/widgets.vue
@@ -24,8 +24,8 @@
 					<option value="nav">%i18n:common.widgets.nav%</option>
 					<option value="tips">%i18n:common.widgets.tips%</option>
 				</select>
-				<button @click="addWidget">追加</button>
-				<p><a @click="hint">カスタマイズのヒント</a></p>
+				<button @click="addWidget">%i18n:add-widget%</button>
+				<p><a @click="hint">%i18n:customization-tips%</a></p>
 			</header>
 			<x-draggable
 				:list="widgets"

From 22b8aab7a031d124f002f4120a33b5b07c524da5 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Mon, 6 Aug 2018 22:08:57 +0000
Subject: [PATCH 65/94] fix(package): update @types/node to version 10.5.7

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 5a7c0a2dd8..ec0ce434ce 100644
--- a/package.json
+++ b/package.json
@@ -59,7 +59,7 @@
 		"@types/mocha": "5.2.3",
 		"@types/mongodb": "3.1.3",
 		"@types/ms": "0.7.30",
-		"@types/node": "10.5.6",
+		"@types/node": "10.5.7",
 		"@types/portscanner": "2.1.0",
 		"@types/pug": "2.0.4",
 		"@types/qrcode": "1.2.0",

From a98392ff27add48fb62a875865ec6bd39413c7a7 Mon Sep 17 00:00:00 2001
From: gutfuckllc <40531868+gutfuckllc@users.noreply.github.com>
Date: Mon, 6 Aug 2018 20:57:14 -0400
Subject: [PATCH 66/94] Localize "only one file attached" popup

---
 locales/ja.yml                                                | 1 +
 .../app/common/views/components/messaging-room.form.vue       | 4 ++--
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/locales/ja.yml b/locales/ja.yml
index d1cc5c325c..87de0f6624 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -261,6 +261,7 @@ common/views/components/messaging-room.form.vue:
   send: "送信"
   attach-from-local: "PCからファイルを添付する"
   attach-from-drive: "ドライブからファイルを添付する"
+  only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
 
 common/views/components/messaging-room.message.vue:
   is-read: "既読"
diff --git a/src/client/app/common/views/components/messaging-room.form.vue b/src/client/app/common/views/components/messaging-room.form.vue
index b6ca902660..f183749fad 100644
--- a/src/client/app/common/views/components/messaging-room.form.vue
+++ b/src/client/app/common/views/components/messaging-room.form.vue
@@ -83,7 +83,7 @@ export default Vue.extend({
 				}
 			} else {
 				if (items[0].kind == 'file') {
-					alert('メッセージに添付できるのはひとつのファイルのみです');
+					alert('%i18n:only-one-file-attached%');
 				}
 			}
 		},
@@ -105,7 +105,7 @@ export default Vue.extend({
 				return;
 			} else if (e.dataTransfer.files.length > 1) {
 				e.preventDefault();
-				alert('メッセージに添付できるのはひとつのファイルのみです');
+				alert('%i18n:only-one-file-attached%');
 				return;
 			}
 

From ff325d9588f8c1beab0b258d29691001af9dc32a Mon Sep 17 00:00:00 2001
From: gutfuckllc <40531868+gutfuckllc@users.noreply.github.com>
Date: Mon, 6 Aug 2018 21:00:58 -0400
Subject: [PATCH 67/94] Localized annotations line

---
 locales/ja.yml                                        | 1 +
 src/client/app/desktop/views/components/post-form.vue | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/locales/ja.yml b/locales/ja.yml
index 87de0f6624..efc4e575ef 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -648,6 +648,7 @@ desktop/views/components/post-form.vue:
   geolocation-alert: "お使いの端末は位置情報に対応していません"
   error: "エラー"
   enter-username: "ユーザー名を入力してください"
+  annotations: "内容への注釈 (オプション)"
 
 desktop/views/components/post-form-window.vue:
   note: "新規投稿"
diff --git a/src/client/app/desktop/views/components/post-form.vue b/src/client/app/desktop/views/components/post-form.vue
index 9b8a0c0f18..334a457504 100644
--- a/src/client/app/desktop/views/components/post-form.vue
+++ b/src/client/app/desktop/views/components/post-form.vue
@@ -14,7 +14,7 @@
 			<b>%i18n:@recent-tags%:</b>
 			<a v-for="tag in recentHashtags.slice(0, 5)" @click="addTag(tag)" title="%@click-to-tagging%">#{{ tag }}</a>
 		</div>
-		<input v-show="useCw" v-model="cw" placeholder="内容への注釈 (オプション)">
+		<input v-show="useCw" v-model="cw" placeholder="%i18n:@annotations%">
 		<textarea :class="{ with: (files.length != 0 || poll) }"
 			ref="text" v-model="text" :disabled="posting"
 			@keydown="onKeydown" @paste="onPaste" :placeholder="placeholder"

From eb8c3fe884a866d9221398b72c328d56fbcfcb9f Mon Sep 17 00:00:00 2001
From: gutfuckllc <40531868+gutfuckllc@users.noreply.github.com>
Date: Mon, 6 Aug 2018 21:03:24 -0400
Subject: [PATCH 68/94] Localize a dev file

---
 locales/ja.yml                     | 4 ++++
 src/client/app/dev/views/index.vue | 2 +-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/locales/ja.yml b/locales/ja.yml
index efc4e575ef..9fd6130763 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -1351,3 +1351,7 @@ docs:
       name: "名前"
       type: "型"
       description: "説明"
+
+      
+dev/views/index.vue:
+  manage-apps: "アプリの管理"
\ No newline at end of file
diff --git a/src/client/app/dev/views/index.vue b/src/client/app/dev/views/index.vue
index 3f572b3907..bb137481f4 100644
--- a/src/client/app/dev/views/index.vue
+++ b/src/client/app/dev/views/index.vue
@@ -1,6 +1,6 @@
 <template>
 <mk-ui>
-	<b-button to="/apps" variant="primary">アプリの管理</b-button>
+	<b-button to="/apps" variant="primary">%i18n:@manage-apps%</b-button>
 </mk-ui>
 </template>
 

From b85f13dad3c95ca0dc0737a7fe9c76ab5f2efcd4 Mon Sep 17 00:00:00 2001
From: gutfuckllc <40531868+gutfuckllc@users.noreply.github.com>
Date: Mon, 6 Aug 2018 21:06:09 -0400
Subject: [PATCH 69/94] Localize mobile search.vue

---
 locales/ja.yml                               | 1 +
 src/client/app/mobile/views/pages/search.vue | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/locales/ja.yml b/locales/ja.yml
index 9fd6130763..ed0ad4f3ff 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -1247,6 +1247,7 @@ mobile/views/pages/settings/settings.profile.vue:
 mobile/views/pages/search.vue:
   search: "検索"
   empty: "「{}」に関する投稿は見つかりませんでした。"
+  not-found: "「{}」に関する投稿は見つかりませんでした。"
 
 mobile/views/pages/selectdrive.vue:
   select-file: "ファイルを選択"
diff --git a/src/client/app/mobile/views/pages/search.vue b/src/client/app/mobile/views/pages/search.vue
index 7801068c1a..a90513dc7c 100644
--- a/src/client/app/mobile/views/pages/search.vue
+++ b/src/client/app/mobile/views/pages/search.vue
@@ -3,7 +3,7 @@
 	<span slot="header">%fa:search% {{ q }}</span>
 
 	<main>
-		<p v-if="!fetching && empty">%fa:search%「{{ q }}」に関する投稿は見つかりませんでした。</p>
+		<p :class="$style.empty" v-if="!fetching && empty">%fa:search% {{ '%i18n:not-found%'.split('{}')[0] }}{{ q }}{{ '%i18n:not-found%'.split('{}')[1] }}</p>
 		<mk-notes ref="timeline" :more="existMore ? more : null"/>
 	</main>
 </mk-ui>

From d86cfa86e4acbb5b3c96a67f3ff96df503fe08ad Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Tue, 7 Aug 2018 02:05:20 +0000
Subject: [PATCH 70/94] fix(package): update vue-loader to version 15.2.7

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 5a7c0a2dd8..d4af4258c4 100644
--- a/package.json
+++ b/package.json
@@ -205,7 +205,7 @@
 		"vue-cropperjs": "2.2.1",
 		"vue-js-modal": "1.3.16",
 		"vue-json-tree-view": "2.1.4",
-		"vue-loader": "15.2.6",
+		"vue-loader": "15.2.7",
 		"vue-router": "3.0.1",
 		"vue-style-loader": "4.1.1",
 		"vue-template-compiler": "2.5.17",

From d4f7058574e414fc0937373b47d50c42856bcd1b Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Tue, 7 Aug 2018 12:37:17 +0900
Subject: [PATCH 71/94] :pizza:

---
 src/client/app/common/views/widgets/server.disk.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/client/app/common/views/widgets/server.disk.vue b/src/client/app/common/views/widgets/server.disk.vue
index 5c7e9678de..99ce624051 100644
--- a/src/client/app/common/views/widgets/server.disk.vue
+++ b/src/client/app/common/views/widgets/server.disk.vue
@@ -4,7 +4,7 @@
 	<div>
 		<p>%fa:R hdd%Storage</p>
 		<p>Total: {{ total | bytes(1) }}</p>
-		<p>Available: {{ available | bytes(1) }}</p>
+		<p>Free: {{ available | bytes(1) }}</p>
 		<p>Used: {{ used | bytes(1) }}</p>
 	</div>
 </div>

From 7bd33ecc72c7cbb53a15f3a74f7548564c75fa6b Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Tue, 7 Aug 2018 13:25:50 +0900
Subject: [PATCH 72/94] :v:

---
 locales/ja.yml                                         |  6 +++---
 src/client/app/auth/script.ts                          |  4 ++--
 .../app/common/views/components/messaging-room.vue     |  2 +-
 src/client/app/common/views/pages/follow.vue           |  1 -
 src/client/app/desktop/views/components/notes.vue      |  8 ++++----
 .../app/desktop/views/components/notifications.vue     |  2 +-
 src/client/app/desktop/views/pages/deck/deck.notes.vue |  2 +-
 .../desktop/views/pages/deck/deck.notifications.vue    |  2 +-
 src/client/app/desktop/views/pages/home-customize.vue  |  4 +++-
 src/client/app/desktop/views/pages/home.vue            |  3 ++-
 src/client/app/desktop/views/pages/share.vue           |  4 +++-
 src/client/app/desktop/views/pages/user/user.vue       |  1 -
 src/client/app/desktop/views/pages/welcome.vue         | 10 +++++-----
 src/client/app/dev/views/ui.vue                        |  2 +-
 src/client/app/mobile/views/components/notes.vue       |  5 +++--
 .../app/mobile/views/components/notifications.vue      |  2 +-
 src/client/app/mobile/views/components/ui.header.vue   |  4 +++-
 src/client/app/mobile/views/pages/drive.vue            |  9 +++++----
 src/client/app/mobile/views/pages/favorites.vue        |  3 ++-
 src/client/app/mobile/views/pages/followers.vue        |  3 ++-
 src/client/app/mobile/views/pages/following.vue        |  3 ++-
 src/client/app/mobile/views/pages/games/reversi.vue    |  3 ++-
 src/client/app/mobile/views/pages/home.vue             |  3 ++-
 src/client/app/mobile/views/pages/messaging-room.vue   |  3 ++-
 src/client/app/mobile/views/pages/messaging.vue        |  3 ++-
 src/client/app/mobile/views/pages/note.vue             |  3 ++-
 src/client/app/mobile/views/pages/notifications.vue    |  2 +-
 .../mobile/views/pages/received-follow-requests.vue    |  2 +-
 src/client/app/mobile/views/pages/search.vue           |  3 ++-
 src/client/app/mobile/views/pages/settings.vue         |  2 +-
 src/client/app/mobile/views/pages/share.vue            |  4 +++-
 src/client/app/mobile/views/pages/user-lists.vue       |  2 +-
 src/client/app/mobile/views/pages/user.vue             |  3 ++-
 src/client/app/mobile/views/pages/welcome.vue          |  4 ++--
 src/client/app/mobile/views/pages/widgets.vue          |  3 ++-
 src/config/load.ts                                     |  2 ++
 36 files changed, 72 insertions(+), 50 deletions(-)

diff --git a/locales/ja.yml b/locales/ja.yml
index ed0ad4f3ff..ecde1bb6a1 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -28,7 +28,6 @@ common:
     notified-by: "{}さんから"
     reply-from: "{}さんから返信:"
     quoted-by: "{}さんが引用:"
-  name: "Misskey"
   time:
     unknown: "なぞのじかん"
     future: "未来"
@@ -40,6 +39,7 @@ common:
     weeks_ago: "{}週間前"
     months_ago: "{}ヶ月前"
     years_ago: "{}年前"
+  month-and-day: "{month}月 {day}日"
 
   trash: "ゴミ箱"
 
@@ -1353,6 +1353,6 @@ docs:
       type: "型"
       description: "説明"
 
-      
+
 dev/views/index.vue:
-  manage-apps: "アプリの管理"
\ No newline at end of file
+  manage-apps: "アプリの管理"
diff --git a/src/client/app/auth/script.ts b/src/client/app/auth/script.ts
index bdfdf70be3..64ab6536db 100644
--- a/src/client/app/auth/script.ts
+++ b/src/client/app/auth/script.ts
@@ -8,14 +8,14 @@ import VueRouter from 'vue-router';
 import './style.styl';
 
 import init from '../init';
-
 import Index from './views/index.vue';
+import * as config from '../config';
 
 /**
  * init
  */
 init(launch => {
-	document.title = '%i18n:common.name% | %i18n:common.application-authorization%';
+	document.title = `${config.name} | %i18n:common.application-authorization%`;
 
 	// Init router
 	const router = new VueRouter({
diff --git a/src/client/app/common/views/components/messaging-room.vue b/src/client/app/common/views/components/messaging-room.vue
index e4cc30ded9..30143b4f1d 100644
--- a/src/client/app/common/views/components/messaging-room.vue
+++ b/src/client/app/common/views/components/messaging-room.vue
@@ -61,7 +61,7 @@ export default Vue.extend({
 				const date = new Date(message.createdAt).getDate();
 				const month = new Date(message.createdAt).getMonth() + 1;
 				message._date = date;
-				message._datetext = `${month}月 ${date}日`;
+				message._datetext = '%i18n:common.month-and-day%'.replace('{month}', month.toString()).replace('{day}', date.toString());
 				return message;
 			});
 		},
diff --git a/src/client/app/common/views/pages/follow.vue b/src/client/app/common/views/pages/follow.vue
index e1b5b1f120..13d855d20a 100644
--- a/src/client/app/common/views/pages/follow.vue
+++ b/src/client/app/common/views/pages/follow.vue
@@ -71,7 +71,6 @@ export default Vue.extend({
 				this.user = user;
 				this.fetching = false;
 				Progress.done();
-				document.title = getUserName(this.user) + ' | %i18n:common.name%';
 			});
 		},
 
diff --git a/src/client/app/desktop/views/components/notes.vue b/src/client/app/desktop/views/components/notes.vue
index 0ec2f16dbc..02167ef85c 100644
--- a/src/client/app/desktop/views/components/notes.vue
+++ b/src/client/app/desktop/views/components/notes.vue
@@ -33,7 +33,7 @@
 
 <script lang="ts">
 import Vue from 'vue';
-import { url } from '../../../config';
+import * as config from '../../../config';
 import getNoteSummary from '../../../../../misc/get-note-summary';
 
 import XNote from './notes.note.vue';
@@ -69,7 +69,7 @@ export default Vue.extend({
 				const date = new Date(note.createdAt).getDate();
 				const month = new Date(note.createdAt).getMonth() + 1;
 				note._date = date;
-				note._datetext = `${month}月 ${date}日`;
+				note._datetext = '%i18n:common.month-and-day%'.replace('{month}', month.toString()).replace('{day}', date.toString());
 				return note;
 			});
 		}
@@ -149,7 +149,7 @@ export default Vue.extend({
 
 				// サウンドを再生する
 				if (this.$store.state.device.enableSounds && !silent) {
-					const sound = new Audio(`${url}/assets/post.mp3`);
+					const sound = new Audio(`${config.url}/assets/post.mp3`);
 					sound.volume = this.$store.state.device.soundVolume;
 					sound.play();
 				}
@@ -187,7 +187,7 @@ export default Vue.extend({
 
 		clearNotification() {
 			this.unreadCount = 0;
-			document.title = '%i18n:common.name%';
+			document.title = config.name;
 		},
 
 		onVisibilitychange() {
diff --git a/src/client/app/desktop/views/components/notifications.vue b/src/client/app/desktop/views/components/notifications.vue
index b291e1f54a..bfe71903e4 100644
--- a/src/client/app/desktop/views/components/notifications.vue
+++ b/src/client/app/desktop/views/components/notifications.vue
@@ -130,7 +130,7 @@ export default Vue.extend({
 				const date = new Date(notification.createdAt).getDate();
 				const month = new Date(notification.createdAt).getMonth() + 1;
 				notification._date = date;
-				notification._datetext = `${month}月 ${date}日`;
+				notification._datetext = '%i18n:common.month-and-day%'.replace('{month}', month.toString()).replace('{day}', date.toString());
 				return notification;
 			});
 		}
diff --git a/src/client/app/desktop/views/pages/deck/deck.notes.vue b/src/client/app/desktop/views/pages/deck/deck.notes.vue
index a5ed45b64c..3578e17287 100644
--- a/src/client/app/desktop/views/pages/deck/deck.notes.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.notes.vue
@@ -72,7 +72,7 @@ export default Vue.extend({
 				const date = new Date(note.createdAt).getDate();
 				const month = new Date(note.createdAt).getMonth() + 1;
 				note._date = date;
-				note._datetext = `${month}月 ${date}日`;
+				note._datetext = '%i18n:common.month-and-day%'.replace('{month}', month.toString()).replace('{day}', date.toString());
 				return note;
 			});
 		}
diff --git a/src/client/app/desktop/views/pages/deck/deck.notifications.vue b/src/client/app/desktop/views/pages/deck/deck.notifications.vue
index 10c06b0ad2..fcb74b9140 100644
--- a/src/client/app/desktop/views/pages/deck/deck.notifications.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.notifications.vue
@@ -51,7 +51,7 @@ export default Vue.extend({
 				const date = new Date(notification.createdAt).getDate();
 				const month = new Date(notification.createdAt).getMonth() + 1;
 				notification._date = date;
-				notification._datetext = `${month}月 ${date}日`;
+				notification._datetext = '%i18n:common.month-and-day%'.replace('{month}', month.toString()).replace('{day}', date.toString());
 				return notification;
 			});
 		}
diff --git a/src/client/app/desktop/views/pages/home-customize.vue b/src/client/app/desktop/views/pages/home-customize.vue
index ffdcf39fe2..4318e89821 100644
--- a/src/client/app/desktop/views/pages/home-customize.vue
+++ b/src/client/app/desktop/views/pages/home-customize.vue
@@ -4,9 +4,11 @@
 
 <script lang="ts">
 import Vue from 'vue';
+import * as config from '../../../config';
+
 export default Vue.extend({
 	mounted() {
-		document.title = '%i18n:common.name% - %i18n:@title%';
+		document.title = `${config.name} - %i18n:@title%`;
 	}
 });
 </script>
diff --git a/src/client/app/desktop/views/pages/home.vue b/src/client/app/desktop/views/pages/home.vue
index 0c42e42bd2..3d3c24bfa4 100644
--- a/src/client/app/desktop/views/pages/home.vue
+++ b/src/client/app/desktop/views/pages/home.vue
@@ -7,6 +7,7 @@
 <script lang="ts">
 import Vue from 'vue';
 import Progress from '../../../common/scripts/loading';
+import * as config from '../../../config';
 
 export default Vue.extend({
 	props: {
@@ -16,7 +17,7 @@ export default Vue.extend({
 		}
 	},
 	mounted() {
-		document.title = '%i18n:common.name%';
+		document.title = config.name;
 
 		Progress.start();
 	},
diff --git a/src/client/app/desktop/views/pages/share.vue b/src/client/app/desktop/views/pages/share.vue
index f5f5c4e184..4a7bdb14cd 100644
--- a/src/client/app/desktop/views/pages/share.vue
+++ b/src/client/app/desktop/views/pages/share.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="pptjhabgjtt7kwskbfv4y3uml6fpuhmr">
-	<h1>{{'%i18n:@share-with%'.split("{}")[0] + '%i18n:common.name%' + '%i18n:@share-with%'.split("{}")[1]}}</h1>
+	<h1>{{ '%i18n:@share-with%'.replace('{}', name) }}</h1>
 	<div>
 		<mk-signin v-if="!$store.getters.isSignedIn"/>
 		<mk-post-form v-else-if="!posted" :initial-text="text" :instant="true" @posted="posted = true"/>
@@ -12,10 +12,12 @@
 
 <script lang="ts">
 import Vue from 'vue';
+import * as config from '../../../config';
 
 export default Vue.extend({
 	data() {
 		return {
+			name: config.name,
 			posted: false,
 			text: new URLSearchParams(location.search).get('text')
 		};
diff --git a/src/client/app/desktop/views/pages/user/user.vue b/src/client/app/desktop/views/pages/user/user.vue
index 1a83f81342..300fd68f06 100644
--- a/src/client/app/desktop/views/pages/user/user.vue
+++ b/src/client/app/desktop/views/pages/user/user.vue
@@ -68,7 +68,6 @@ export default Vue.extend({
 				this.user = user;
 				this.fetching = false;
 				Progress.done();
-				document.title = getUserName(this.user) + ' | %i18n:common.name%';
 			});
 		},
 
diff --git a/src/client/app/desktop/views/pages/welcome.vue b/src/client/app/desktop/views/pages/welcome.vue
index 9543a55b9a..a01b44fc73 100644
--- a/src/client/app/desktop/views/pages/welcome.vue
+++ b/src/client/app/desktop/views/pages/welcome.vue
@@ -8,7 +8,7 @@
 	<div class="body" :style="{ backgroundImage: `url('${ welcomeBgUrl }')` }">
 		<div class="container">
 			<div class="info">
-				<span>%i18n:common.name% <b>{{ host }}</b></span>
+				<span><b>{{ host }}</b></span>
 				<span class="stats" v-if="stats">
 					<span>%fa:user% {{ stats.originalUsersCount | number }}</span>
 					<span>%fa:pencil-alt% {{ stats.originalNotesCount | number }}</span>
@@ -16,9 +16,9 @@
 			</div>
 			<main>
 				<div class="about">
-					<h1 v-if="name">{{ name }}</h1>
-					<h1 v-else><img :src="$store.state.device.darkmode ? 'assets/title.dark.svg' : 'assets/title.light.svg'" alt="%i18n:common.name%"></h1>
-					<p class="powerd-by" v-if="name">%i18n:@powered-by-misskey%</p>
+					<h1 v-if="name != 'Misskey'">{{ name }}</h1>
+					<h1 v-else><img :src="$store.state.device.darkmode ? 'assets/title.dark.svg' : 'assets/title.light.svg'" :alt="name"></h1>
+					<p class="powerd-by" v-if="name != 'Misskey'">%i18n:@powered-by-misskey%</p>
 					<p class="desc" v-html="description || '%i18n:common.about%'"></p>
 					<a ref="signup" @click="signup">📦 %i18n:@signup%</a>
 				</div>
@@ -32,7 +32,7 @@
 			<mk-nav class="nav"/>
 		</div>
 		<mk-forkit class="forkit"/>
-		<img src="assets/title.dark.svg" alt="%i18n:common.name%">
+		<img src="assets/title.dark.svg" :alt="name">
 	</div>
 	<div class="tl">
 		<mk-welcome-timeline :max="20"/>
diff --git a/src/client/app/dev/views/ui.vue b/src/client/app/dev/views/ui.vue
index 0a1cdf829b..f1e001909f 100644
--- a/src/client/app/dev/views/ui.vue
+++ b/src/client/app/dev/views/ui.vue
@@ -1,7 +1,7 @@
 <template>
 <div>
 	<b-navbar toggleable="md" type="dark" variant="info">
-		<b-navbar-brand>%i18n:common.name% Developers</b-navbar-brand>
+		<b-navbar-brand>Developers</b-navbar-brand>
 		<b-navbar-nav>
 			<b-nav-item to="/">Home</b-nav-item>
 			<b-nav-item to="/apps">Apps</b-nav-item>
diff --git a/src/client/app/mobile/views/components/notes.vue b/src/client/app/mobile/views/components/notes.vue
index cba8ef1804..aed372d9a2 100644
--- a/src/client/app/mobile/views/components/notes.vue
+++ b/src/client/app/mobile/views/components/notes.vue
@@ -38,6 +38,7 @@
 <script lang="ts">
 import Vue from 'vue';
 import getNoteSummary from '../../../../../misc/get-note-summary';
+import * as config from '../../../config';
 
 const displayLimit = 30;
 
@@ -66,7 +67,7 @@ export default Vue.extend({
 				const date = new Date(note.createdAt).getDate();
 				const month = new Date(note.createdAt).getMonth() + 1;
 				note._date = date;
-				note._datetext = `${month}月 ${date}日`;
+				note._datetext = '%i18n:common.month-and-day%'.replace('{month}', month.toString()).replace('{day}', date.toString());
 				return note;
 			});
 		}
@@ -183,7 +184,7 @@ export default Vue.extend({
 
 		clearNotification() {
 			this.unreadCount = 0;
-			document.title = '%i18n:common.name%';
+			document.title = config.name;
 		},
 
 		onVisibilitychange() {
diff --git a/src/client/app/mobile/views/components/notifications.vue b/src/client/app/mobile/views/components/notifications.vue
index fc220c252a..9f20c3fb22 100644
--- a/src/client/app/mobile/views/components/notifications.vue
+++ b/src/client/app/mobile/views/components/notifications.vue
@@ -42,7 +42,7 @@ export default Vue.extend({
 				const date = new Date(notification.createdAt).getDate();
 				const month = new Date(notification.createdAt).getMonth() + 1;
 				notification._date = date;
-				notification._datetext = `${month}月 ${date}日`;
+				notification._datetext = '%i18n:common.month-and-day%'.replace('{month}', month.toString()).replace('{day}', date.toString());
 				return notification;
 			});
 		}
diff --git a/src/client/app/mobile/views/components/ui.header.vue b/src/client/app/mobile/views/components/ui.header.vue
index 63399f7465..b87c6f1eb7 100644
--- a/src/client/app/mobile/views/components/ui.header.vue
+++ b/src/client/app/mobile/views/components/ui.header.vue
@@ -8,7 +8,7 @@
 			<button class="nav" @click="$parent.isDrawerOpening = true">%fa:bars%</button>
 			<template v-if="hasUnreadNotification || hasUnreadMessagingMessage || hasGameInvitation">%fa:circle%</template>
 			<h1>
-				<slot>%i18n:common.name%</slot>
+				<slot>config.name</slot>
 			</h1>
 			<slot name="func"></slot>
 		</div>
@@ -20,11 +20,13 @@
 <script lang="ts">
 import Vue from 'vue';
 import * as anime from 'animejs';
+import * as config from '../../../config';
 
 export default Vue.extend({
 	props: ['func'],
 	data() {
 		return {
+			config,
 			hasGameInvitation: false,
 			connection: null,
 			connectionId: null
diff --git a/src/client/app/mobile/views/pages/drive.vue b/src/client/app/mobile/views/pages/drive.vue
index 9c635be05b..72427a4780 100644
--- a/src/client/app/mobile/views/pages/drive.vue
+++ b/src/client/app/mobile/views/pages/drive.vue
@@ -25,6 +25,7 @@
 <script lang="ts">
 import Vue from 'vue';
 import Progress from '../../../common/scripts/loading';
+import * as config from '../../../config';
 
 export default Vue.extend({
 	data() {
@@ -43,7 +44,7 @@ export default Vue.extend({
 		window.addEventListener('popstate', this.onPopState);
 	},
 	mounted() {
-		document.title = '%i18n:common.name% Drive';
+		document.title = `${config.name} Drive`;
 		document.documentElement.style.background = '#fff';
 	},
 	beforeDestroy() {
@@ -63,7 +64,7 @@ export default Vue.extend({
 			(this.$refs as any).browser.openContextMenu();
 		},
 		onMoveRoot(silent) {
-			const title = '%i18n:common.name% Drive';
+			const title = `${config.name} Drive`;
 
 			if (!silent) {
 				// Rewrite URL
@@ -76,7 +77,7 @@ export default Vue.extend({
 			this.folder = null;
 		},
 		onOpenFolder(folder, silent) {
-			const title = folder.name + ' | %i18n:common.name% Drive';
+			const title = `${folder.name} | ${config.name} Drive`;
 
 			if (!silent) {
 				// Rewrite URL
@@ -89,7 +90,7 @@ export default Vue.extend({
 			this.folder = folder;
 		},
 		onOpenFile(file, silent) {
-			const title = file.name + ' | %i18n:common.name% Drive';
+			const title = `${file.name} | ${config.name} Drive`;
 
 			if (!silent) {
 				// Rewrite URL
diff --git a/src/client/app/mobile/views/pages/favorites.vue b/src/client/app/mobile/views/pages/favorites.vue
index 88a84bd8a2..491890bb0e 100644
--- a/src/client/app/mobile/views/pages/favorites.vue
+++ b/src/client/app/mobile/views/pages/favorites.vue
@@ -14,6 +14,7 @@
 <script lang="ts">
 import Vue from 'vue';
 import Progress from '../../../common/scripts/loading';
+import * as config from '../../../config';
 
 export default Vue.extend({
 	data() {
@@ -28,7 +29,7 @@ export default Vue.extend({
 		this.fetch();
 	},
 	mounted() {
-		document.title = '%i18n:common.name% | %i18n:@notifications%';
+		document.title = `${config.name} | %i18n:@notifications%`;
 	},
 	methods: {
 		fetch() {
diff --git a/src/client/app/mobile/views/pages/followers.vue b/src/client/app/mobile/views/pages/followers.vue
index 4956eb1b94..5bba534ba0 100644
--- a/src/client/app/mobile/views/pages/followers.vue
+++ b/src/client/app/mobile/views/pages/followers.vue
@@ -21,6 +21,7 @@ import Vue from 'vue';
 import Progress from '../../../common/scripts/loading';
 import parseAcct from '../../../../../misc/acct/parse';
 import getUserName from '../../../../../misc/get-user-name';
+import * as config from '../../../config';
 
 export default Vue.extend({
 	data() {
@@ -49,7 +50,7 @@ export default Vue.extend({
 				this.user = user;
 				this.fetching = false;
 
-				document.title = '%i18n:@followers-of%'.replace('{}', this.name) + ' | %i18n:common.name%';
+				document.title = '%i18n:@followers-of%'.replace('{}', this.name) + ' | ' + config.name;
 			});
 		},
 		onLoaded() {
diff --git a/src/client/app/mobile/views/pages/following.vue b/src/client/app/mobile/views/pages/following.vue
index fa6807a245..cdc009b768 100644
--- a/src/client/app/mobile/views/pages/following.vue
+++ b/src/client/app/mobile/views/pages/following.vue
@@ -20,6 +20,7 @@
 import Vue from 'vue';
 import Progress from '../../../common/scripts/loading';
 import parseAcct from '../../../../../misc/acct/parse';
+import * as config from '../../../config';
 
 export default Vue.extend({
 	data() {
@@ -48,7 +49,7 @@ export default Vue.extend({
 				this.user = user;
 				this.fetching = false;
 
-				document.title = '%i18n:@followers-of%'.replace('{}', this.name) + ' | %i18n:common.name%';
+				document.title = '%i18n:@followers-of%'.replace('{}', this.name) + ' | ' + config.name;
 			});
 		},
 		onLoaded() {
diff --git a/src/client/app/mobile/views/pages/games/reversi.vue b/src/client/app/mobile/views/pages/games/reversi.vue
index e6e6325f8b..448c9b8d77 100644
--- a/src/client/app/mobile/views/pages/games/reversi.vue
+++ b/src/client/app/mobile/views/pages/games/reversi.vue
@@ -7,10 +7,11 @@
 
 <script lang="ts">
 import Vue from 'vue';
+import * as config from '../../../../config';
 
 export default Vue.extend({
 	mounted() {
-		document.title = '%i18n:common.name% %i18n:@reversi%';
+		document.title = `${config.name} %i18n:@reversi%`;
 		document.documentElement.style.background = '#fff';
 	},
 	methods: {
diff --git a/src/client/app/mobile/views/pages/home.vue b/src/client/app/mobile/views/pages/home.vue
index 7b14c7ee98..c1ed97ac13 100644
--- a/src/client/app/mobile/views/pages/home.vue
+++ b/src/client/app/mobile/views/pages/home.vue
@@ -49,6 +49,7 @@
 import Vue from 'vue';
 import Progress from '../../../common/scripts/loading';
 import XTl from './home.timeline.vue';
+import * as config from '../../../config';
 
 export default Vue.extend({
 	components: {
@@ -96,7 +97,7 @@ export default Vue.extend({
 	},
 
 	mounted() {
-		document.title = '%i18n:common.name%';
+		document.title = config.name;
 
 		Progress.start();
 
diff --git a/src/client/app/mobile/views/pages/messaging-room.vue b/src/client/app/mobile/views/pages/messaging-room.vue
index 24ffc658a3..e2016fc82a 100644
--- a/src/client/app/mobile/views/pages/messaging-room.vue
+++ b/src/client/app/mobile/views/pages/messaging-room.vue
@@ -11,6 +11,7 @@
 <script lang="ts">
 import Vue from 'vue';
 import parseAcct from '../../../../../misc/acct/parse';
+import * as config from '../../../config';
 
 export default Vue.extend({
 	data() {
@@ -47,7 +48,7 @@ export default Vue.extend({
 				this.user = user;
 				this.fetching = false;
 
-				document.title = `%i18n:@messaging%: ${Vue.filter('userName')(this.user)} | %i18n:common.name%`;
+				document.title = `%i18n:@messaging%: ${Vue.filter('userName')(this.user)} | ${config.name}`;
 			});
 		}
 	}
diff --git a/src/client/app/mobile/views/pages/messaging.vue b/src/client/app/mobile/views/pages/messaging.vue
index b5a4f405fb..9f2beb860c 100644
--- a/src/client/app/mobile/views/pages/messaging.vue
+++ b/src/client/app/mobile/views/pages/messaging.vue
@@ -8,10 +8,11 @@
 <script lang="ts">
 import Vue from 'vue';
 import getAcct from '../../../../../misc/acct/render';
+import * as config from '../../../config';
 
 export default Vue.extend({
 	mounted() {
-		document.title = '%i18n:common.name% %i18n:@messaging%';
+		document.title = `${config.name} %i18n:@messaging%`;
 	},
 	methods: {
 		navigate(user) {
diff --git a/src/client/app/mobile/views/pages/note.vue b/src/client/app/mobile/views/pages/note.vue
index 64d46f051b..8b1095c509 100644
--- a/src/client/app/mobile/views/pages/note.vue
+++ b/src/client/app/mobile/views/pages/note.vue
@@ -16,6 +16,7 @@
 <script lang="ts">
 import Vue from 'vue';
 import Progress from '../../../common/scripts/loading';
+import * as config from '../../../config';
 
 export default Vue.extend({
 	data() {
@@ -31,7 +32,7 @@ export default Vue.extend({
 		this.fetch();
 	},
 	mounted() {
-		document.title = '%i18n:common.name%';
+		document.title = config.name;
 	},
 	methods: {
 		fetch() {
diff --git a/src/client/app/mobile/views/pages/notifications.vue b/src/client/app/mobile/views/pages/notifications.vue
index 3688721613..4d3c8ee534 100644
--- a/src/client/app/mobile/views/pages/notifications.vue
+++ b/src/client/app/mobile/views/pages/notifications.vue
@@ -15,7 +15,7 @@ import Progress from '../../../common/scripts/loading';
 
 export default Vue.extend({
 	mounted() {
-		document.title = '%i18n:common.name% | %i18n:@notifications%';
+		document.title = '%i18n:@notifications%';
 
 		Progress.start();
 	},
diff --git a/src/client/app/mobile/views/pages/received-follow-requests.vue b/src/client/app/mobile/views/pages/received-follow-requests.vue
index fff2fdea56..77938c3d60 100644
--- a/src/client/app/mobile/views/pages/received-follow-requests.vue
+++ b/src/client/app/mobile/views/pages/received-follow-requests.vue
@@ -25,7 +25,7 @@ export default Vue.extend({
 		};
 	},
 	mounted() {
-		document.title = '%i18n:common.name% | %i18n:@title%';
+		document.title = '%i18n:@title%';
 
 		Progress.start();
 
diff --git a/src/client/app/mobile/views/pages/search.vue b/src/client/app/mobile/views/pages/search.vue
index a90513dc7c..0b37a3c7bd 100644
--- a/src/client/app/mobile/views/pages/search.vue
+++ b/src/client/app/mobile/views/pages/search.vue
@@ -12,6 +12,7 @@
 <script lang="ts">
 import Vue from 'vue';
 import Progress from '../../../common/scripts/loading';
+import * as config from '../../../config';
 
 const limit = 20;
 
@@ -34,7 +35,7 @@ export default Vue.extend({
 		}
 	},
 	mounted() {
-		document.title = `%i18n:@search%: ${this.q} | %i18n:common.name%`;
+		document.title = `%i18n:@search%: ${this.q} | ${config.name}`;
 
 		this.fetch();
 	},
diff --git a/src/client/app/mobile/views/pages/settings.vue b/src/client/app/mobile/views/pages/settings.vue
index 63fca64ab1..f74b734b6e 100644
--- a/src/client/app/mobile/views/pages/settings.vue
+++ b/src/client/app/mobile/views/pages/settings.vue
@@ -143,7 +143,7 @@ export default Vue.extend({
 	},
 
 	mounted() {
-		document.title = '%i18n:common.name% | %i18n:@settings%';
+		document.title = '%i18n:@settings%';
 	},
 
 	methods: {
diff --git a/src/client/app/mobile/views/pages/share.vue b/src/client/app/mobile/views/pages/share.vue
index fffbea9033..dcb55e6702 100644
--- a/src/client/app/mobile/views/pages/share.vue
+++ b/src/client/app/mobile/views/pages/share.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="azibmfpleajagva420swmu4c3r7ni7iw">
-	<h1>{{'%i18n:@share-with%'.split("{}")[0] + '%i18n:common.name%' + '%i18n:@share-with%'.split("{}")[1]}}</h1>
+	<h1>{{ '%i18n:@share-with%'.replace('{}', name) }}</h1>
 	<div>
 		<mk-signin v-if="!$store.getters.isSignedIn"/>
 		<mk-post-form v-else-if="!posted" :initial-text="text" :instant="true" @posted="posted = true"/>
@@ -12,10 +12,12 @@
 
 <script lang="ts">
 import Vue from 'vue';
+import * as config from '../../../config';
 
 export default Vue.extend({
 	data() {
 		return {
+			name: config.name,
 			posted: false,
 			text: new URLSearchParams(location.search).get('text')
 		};
diff --git a/src/client/app/mobile/views/pages/user-lists.vue b/src/client/app/mobile/views/pages/user-lists.vue
index 1cce3e9bdd..abd04c1496 100644
--- a/src/client/app/mobile/views/pages/user-lists.vue
+++ b/src/client/app/mobile/views/pages/user-lists.vue
@@ -23,7 +23,7 @@ export default Vue.extend({
 		};
 	},
 	mounted() {
-		document.title = '%i18n:common.name% | %i18n:@title%';
+		document.title = '%i18n:@title%';
 
 		Progress.start();
 
diff --git a/src/client/app/mobile/views/pages/user.vue b/src/client/app/mobile/views/pages/user.vue
index d016345717..11ca1caebf 100644
--- a/src/client/app/mobile/views/pages/user.vue
+++ b/src/client/app/mobile/views/pages/user.vue
@@ -67,6 +67,7 @@ import * as age from 's-age';
 import parseAcct from '../../../../../misc/acct/parse';
 import Progress from '../../../common/scripts/loading';
 import XHome from './user/home.vue';
+import * as config from '../../../config';
 
 export default Vue.extend({
 	components: {
@@ -106,7 +107,7 @@ export default Vue.extend({
 				this.fetching = false;
 
 				Progress.done();
-				document.title = Vue.filter('userName')(this.user) + ' | %i18n:common.name%';
+				document.title = Vue.filter('userName')(this.user) + ' | ' + config.name;
 			});
 		}
 	}
diff --git a/src/client/app/mobile/views/pages/welcome.vue b/src/client/app/mobile/views/pages/welcome.vue
index acc8e2c490..f8a7ff1c80 100644
--- a/src/client/app/mobile/views/pages/welcome.vue
+++ b/src/client/app/mobile/views/pages/welcome.vue
@@ -1,10 +1,10 @@
 <template>
 <div class="welcome">
 	<div>
-		<img :src="$store.state.device.darkmode ? 'assets/title.dark.svg' : 'assets/title.light.svg'" alt="%i18n:common.name%">
+		<img :src="$store.state.device.darkmode ? 'assets/title.dark.svg' : 'assets/title.light.svg'" :alt="name">
 		<p class="host">{{ host }}</p>
 		<div class="about">
-			<h2>{{ name || 'unidentified' }}</h2>
+			<h2>{{ name }}</h2>
 			<p v-html="description || '%i18n:common.about%'"></p>
 			<router-link class="signup" to="/signup">%i18n:@signup%</router-link>
 		</div>
diff --git a/src/client/app/mobile/views/pages/widgets.vue b/src/client/app/mobile/views/pages/widgets.vue
index 543ee8f7d8..b90d710c67 100644
--- a/src/client/app/mobile/views/pages/widgets.vue
+++ b/src/client/app/mobile/views/pages/widgets.vue
@@ -53,6 +53,7 @@
 import Vue from 'vue';
 import * as XDraggable from 'vuedraggable';
 import * as uuid from 'uuid';
+import * as config from '../../../config';
 
 export default Vue.extend({
 	components: {
@@ -102,7 +103,7 @@ export default Vue.extend({
 	},
 
 	mounted() {
-		document.title = '%i18n:common.name%';
+		document.title = config.name;
 	},
 
 	methods: {
diff --git a/src/config/load.ts b/src/config/load.ts
index 44a24c96ae..1c59f82b3e 100644
--- a/src/config/load.ts
+++ b/src/config/load.ts
@@ -47,6 +47,8 @@ export default function load() {
 	if (config.localDriveCapacityMb == null) config.localDriveCapacityMb = 256;
 	if (config.remoteDriveCapacityMb == null) config.remoteDriveCapacityMb = 8;
 
+	if (config.name == null) config.name = 'Misskey';
+
 	return Object.assign(config, mixin);
 }
 

From c730e5edfa9f34e43c06948ed1bdf0e6db54b14f Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Tue, 7 Aug 2018 11:23:35 +0000
Subject: [PATCH 73/94] fix(package): update commander to version 2.17.1

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index cb4b12ede1..d2ddfe6015 100644
--- a/package.json
+++ b/package.json
@@ -88,7 +88,7 @@
 		"bootstrap-vue": "2.0.0-rc.11",
 		"cafy": "11.3.0",
 		"chalk": "2.4.1",
-		"commander": "2.17.0",
+		"commander": "2.17.1",
 		"crc-32": "1.2.0",
 		"css-loader": "1.0.0",
 		"dateformat": "3.0.3",

From 90eed0ea0d56cfcf477494c6d77c87c69f9d06a5 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Tue, 7 Aug 2018 13:13:16 +0000
Subject: [PATCH 74/94] fix(package): update style-loader to version 0.22.0

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index cb4b12ede1..5ab3b16156 100644
--- a/package.json
+++ b/package.json
@@ -184,7 +184,7 @@
 		"single-line-log": "1.1.2",
 		"speakeasy": "2.0.0",
 		"stringz": "1.0.0",
-		"style-loader": "0.21.0",
+		"style-loader": "0.22.0",
 		"stylus": "0.54.5",
 		"stylus-loader": "3.0.2",
 		"summaly": "2.0.6",

From 1dc1feca0f597b1995f45d43b5f825a00a4b22ec Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Tue, 7 Aug 2018 21:34:59 +0000
Subject: [PATCH 75/94] fix(package): update vue-loader to version 15.3.0

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index cb4b12ede1..ced877dabd 100644
--- a/package.json
+++ b/package.json
@@ -205,7 +205,7 @@
 		"vue-cropperjs": "2.2.1",
 		"vue-js-modal": "1.3.16",
 		"vue-json-tree-view": "2.1.4",
-		"vue-loader": "15.2.7",
+		"vue-loader": "15.3.0",
 		"vue-router": "3.0.1",
 		"vue-style-loader": "4.1.1",
 		"vue-template-compiler": "2.5.17",

From bef617cb7c724c6d7702eefc6c507fd15daaa009 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Wed, 8 Aug 2018 05:13:03 +0000
Subject: [PATCH 76/94] fix(package): update systeminformation to version
 3.42.9

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index cb4b12ede1..54dba819b2 100644
--- a/package.json
+++ b/package.json
@@ -188,7 +188,7 @@
 		"stylus": "0.54.5",
 		"stylus-loader": "3.0.2",
 		"summaly": "2.0.6",
-		"systeminformation": "3.42.8",
+		"systeminformation": "3.42.9",
 		"syuilo-password-strength": "0.0.1",
 		"textarea-caret": "3.1.0",
 		"tmp": "0.0.33",

From 869c19c66677cae8c5db843a4bc18c16303e1d59 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Wed, 8 Aug 2018 15:03:55 +0000
Subject: [PATCH 77/94] fix(package): update style-loader to version 0.22.1

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 1236cc2113..5a83cc3361 100644
--- a/package.json
+++ b/package.json
@@ -184,7 +184,7 @@
 		"single-line-log": "1.1.2",
 		"speakeasy": "2.0.0",
 		"stringz": "1.0.0",
-		"style-loader": "0.22.0",
+		"style-loader": "0.22.1",
 		"stylus": "0.54.5",
 		"stylus-loader": "3.0.2",
 		"summaly": "2.0.6",

From e724c1e7e87f2c329f406e1d6371de8c299e6911 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?=
 <root@acid-chicken.com>
Date: Thu, 9 Aug 2018 03:32:09 +0900
Subject: [PATCH 78/94] Update url-preview.vue

---
 src/client/app/common/views/components/url-preview.vue | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/client/app/common/views/components/url-preview.vue b/src/client/app/common/views/components/url-preview.vue
index 1e625f69ed..2c265a9a71 100644
--- a/src/client/app/common/views/components/url-preview.vue
+++ b/src/client/app/common/views/components/url-preview.vue
@@ -2,6 +2,9 @@
 <iframe v-if="youtubeId" type="text/html" height="250"
 	:src="`https://www.youtube.com/embed/${youtubeId}?origin=${misskeyUrl}`"
 	frameborder="0"/>
+<iframe v-else-if="spotifyId"
+	:src="`https://open.spotify.com/embed/track/${spotifyId}`"
+	frameborder="0" allowtransparency="true" allow="encrypted-media" />
 <div v-else-if="tweetUrl && detail" class="twitter">
 	<blockquote ref="tweet" class="twitter-tweet" :data-theme="$store.state.device.darkmode ? 'dark' : null">
 		<a :href="url"></a>
@@ -60,6 +63,8 @@ export default Vue.extend({
 			this.youtubeId = url.searchParams.get('v');
 		} else if (url.hostname == 'youtu.be') {
 			this.youtubeId = url.pathname;
+		} else if (url.hostname == 'open.spotify.com') {
+			this.spotifyId = url.pathname.split('/').reverse().filter(x => x !== '')[0];
 		} else if (this.detail && url.hostname == 'twitter.com' && /^\/.+\/status(es)?\/\d+/.test(url.pathname)) {
 			this.tweetUrl = url;
 			const twttr = (window as any).twttr || {};

From ebf0479ecc11d3eada4453772a1ebdc0063e00af Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?=
 <root@acid-chicken.com>
Date: Thu, 9 Aug 2018 04:05:28 +0900
Subject: [PATCH 79/94] Update url-preview.vue

---
 src/client/app/common/views/components/url-preview.vue | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/src/client/app/common/views/components/url-preview.vue b/src/client/app/common/views/components/url-preview.vue
index 2c265a9a71..a61e9fd817 100644
--- a/src/client/app/common/views/components/url-preview.vue
+++ b/src/client/app/common/views/components/url-preview.vue
@@ -5,6 +5,9 @@
 <iframe v-else-if="spotifyId"
 	:src="`https://open.spotify.com/embed/track/${spotifyId}`"
 	frameborder="0" allowtransparency="true" allow="encrypted-media" />
+<iframe v-else-if="nicovideoId"
+	:src="`https://embed.nicovideo.jp/watch/${nicovideoId}?oldScript=1&referer=${misskeyUrl}&from=${position || '0'}&allowProgrammaticFullScreen=1`"
+	frameborder="0" allow="autoplay; encrypted-media" allowfullscreen />
 <div v-else-if="tweetUrl && detail" class="twitter">
 	<blockquote ref="tweet" class="twitter-tweet" :data-theme="$store.state.device.darkmode ? 'dark' : null">
 		<a :href="url"></a>
@@ -52,6 +55,9 @@ export default Vue.extend({
 			icon: null,
 			sitename: null,
 			youtubeId: null,
+			spotifyId: null,
+			nicovideoId: null,
+			position: null,
 			tweetUrl: null,
 			misskeyUrl
 		};
@@ -65,6 +71,9 @@ export default Vue.extend({
 			this.youtubeId = url.pathname;
 		} else if (url.hostname == 'open.spotify.com') {
 			this.spotifyId = url.pathname.split('/').reverse().filter(x => x !== '')[0];
+		} else if (['nicovideo.jp', 'www.nicovideo.jp', 'nico.ms'].includes(url.hostname)) {
+			this.nicovideoId = url.pathname.split('/').reverse().filter(x => x !== '')[0];
+			this.position = url.searchParams.get('from');
 		} else if (this.detail && url.hostname == 'twitter.com' && /^\/.+\/status(es)?\/\d+/.test(url.pathname)) {
 			this.tweetUrl = url;
 			const twttr = (window as any).twttr || {};

From 6a92c192277a15061582bd3862c9b768de1f787b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?=
 <root@acid-chicken.com>
Date: Thu, 9 Aug 2018 04:21:25 +0900
Subject: [PATCH 80/94] Update url-preview.vue

---
 .../common/views/components/url-preview.vue   | 35 +++++++++++--------
 1 file changed, 21 insertions(+), 14 deletions(-)

diff --git a/src/client/app/common/views/components/url-preview.vue b/src/client/app/common/views/components/url-preview.vue
index a61e9fd817..4f1e34c6ca 100644
--- a/src/client/app/common/views/components/url-preview.vue
+++ b/src/client/app/common/views/components/url-preview.vue
@@ -67,13 +67,20 @@ export default Vue.extend({
 
 		if (url.hostname == 'www.youtube.com') {
 			this.youtubeId = url.searchParams.get('v');
+			return;
 		} else if (url.hostname == 'youtu.be') {
 			this.youtubeId = url.pathname;
+			return;
 		} else if (url.hostname == 'open.spotify.com') {
 			this.spotifyId = url.pathname.split('/').reverse().filter(x => x !== '')[0];
+			return;
 		} else if (['nicovideo.jp', 'www.nicovideo.jp', 'nico.ms'].includes(url.hostname)) {
-			this.nicovideoId = url.pathname.split('/').reverse().filter(x => x !== '')[0];
-			this.position = url.searchParams.get('from');
+			const id = url.pathname.split('/').reverse().filter(x => x !== '')[0];
+			if (['sm', 'nm', 'ax', 'ca', 'cd', 'cw', 'fx', 'ig', 'na', 'om', 'sd', 'sk', 'yk', 'yo', 'za', 'zb', 'zc', 'zd', 'ze', 'nl', 'so', ...Array(10).keys()].some(x => id.startsWith(x)) {
+				this.nicovideoId = id;
+				this.position = url.searchParams.get('from');
+				return;
+			}
 		} else if (this.detail && url.hostname == 'twitter.com' && /^\/.+\/status(es)?\/\d+/.test(url.pathname)) {
 			this.tweetUrl = url;
 			const twttr = (window as any).twttr || {};
@@ -93,19 +100,19 @@ export default Vue.extend({
 				twttr.ready = loadTweet;
 				(window as any).twttr = twttr;
 			}
-		} else {
-			fetch('/url?url=' + encodeURIComponent(this.url)).then(res => {
-				res.json().then(info => {
-					this.title = info.title;
-					this.description = info.description;
-					this.thumbnail = info.thumbnail;
-					this.icon = info.icon;
-					this.sitename = info.sitename;
-
-					this.fetching = false;
-				});
-			});
+			return;
 		}
+		fetch('/url?url=' + encodeURIComponent(this.url)).then(res => {
+			res.json().then(info => {
+				this.title = info.title;
+				this.description = info.description;
+				this.thumbnail = info.thumbnail;
+				this.icon = info.icon;
+				this.sitename = info.sitename;
+
+				this.fetching = false;
+			});
+		});
 	}
 });
 </script>

From 4333ff00a0c1cbdaf584e55e8bd5912f892a7458 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Thu, 9 Aug 2018 04:34:21 +0900
Subject: [PATCH 81/94] New Crowdin translations (#2116)

---
 locales/ca.yml | 15 +++++++-
 locales/de.yml | 15 +++++++-
 locales/en.yml | 17 +++++++--
 locales/es.yml | 15 +++++++-
 locales/fr.yml | 95 ++++++++++++++++++++++++++++----------------------
 locales/it.yml | 15 +++++++-
 locales/ko.yml | 15 +++++++-
 locales/pl.yml | 27 ++++++++++----
 locales/pt.yml | 15 +++++++-
 locales/ru.yml | 15 +++++++-
 locales/zh.yml | 15 +++++++-
 11 files changed, 201 insertions(+), 58 deletions(-)

diff --git a/locales/ca.yml b/locales/ca.yml
index 8e4f7cc2cb..fbd955c3fd 100644
--- a/locales/ca.yml
+++ b/locales/ca.yml
@@ -11,6 +11,7 @@ common:
     warning: "<strong>Misskeyは広告を掲載していません</strong>が、広告をブロックする機能が有効だと一部の機能が利用できなかったり、不具合が発生する場合があります。"
   application-authorization: "アプリの連携"
   close: "閉じる"
+  do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。"
   got-it: "わかった"
   customization-tips:
     title: "カスタマイズのヒント"
@@ -27,7 +28,6 @@ common:
     notified-by: "{}さんから"
     reply-from: "{}さんから返信:"
     quoted-by: "{}さんが引用:"
-  name: "Misskey"
   time:
     unknown: "なぞのじかん"
     future: "未来"
@@ -39,6 +39,7 @@ common:
     weeks_ago: "{}週間前"
     months_ago: "{}ヶ月前"
     years_ago: "{}年前"
+  month-and-day: "{month}月 {day}日"
   trash: "ゴミ箱"
   weekday-short:
     sunday: "日"
@@ -234,11 +235,13 @@ common/views/components/messaging-room.vue:
   no-history: "これより過去の履歴はありません"
   resize-form: "ドラッグしてフォームの広さを調整"
   new-message: "新しいメッセージがあります"
+  only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
 common/views/components/messaging-room.form.vue:
   input-message-here: "ここにメッセージを入力"
   send: "送信"
   attach-from-local: "PCからファイルを添付する"
   attach-from-drive: "ドライブからファイルを添付する"
+  only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
 common/views/components/messaging-room.message.vue:
   is-read: "既読"
   deleted: "このメッセージは削除されました"
@@ -534,6 +537,8 @@ desktop/views/components/notes.note.vue:
   detail: "詳細"
   private: "この投稿は非公開です"
   deleted: "この投稿は削除されました"
+  hide: "隠す"
+  see-more: "もっと見る"
 desktop/views/components/notes.vue:
   error: "読み込みに失敗しました。"
   retry: "リトライ"
@@ -569,6 +574,7 @@ desktop/views/components/post-form.vue:
   geolocation-alert: "お使いの端末は位置情報に対応していません"
   error: "エラー"
   enter-username: "ユーザー名を入力してください"
+  annotations: "内容への注釈 (オプション)"
 desktop/views/components/post-form-window.vue:
   note: "新規投稿"
   reply: "返信"
@@ -730,6 +736,7 @@ desktop/views/components/timeline.vue:
   list: "リスト"
 desktop/views/components/ui.header.vue:
   welcome-back: "おかえりなさい、"
+  adjective: "さん"
 desktop/views/components/ui.header.account.vue:
   profile: "プロフィール"
   drive: "ドライブ"
@@ -970,6 +977,7 @@ mobile/views/components/timeline.vue:
   load-more: "もっと"
 mobile/views/components/ui.header.vue:
   welcome-back: "おかえりなさい、"
+  adjective: "さん"
 mobile/views/components/ui.nav.vue:
   timeline: "タイムライン"
   notifications: "通知"
@@ -1018,6 +1026,8 @@ mobile/views/pages/welcome.vue:
 mobile/views/pages/widgets.vue:
   dashboard: "ダッシュボード"
   widgets-hints: "ウィジェットを追加/削除したり並べ替えたりできます。ウィジェットを移動するには「三」をドラッグします。ウィジェットを削除するには「x」をタップします。いくつかのウィジェットはタップすることで表示を変更できます。"
+  add-widget: "追加"
+  customization-tips: "カスタマイズのヒント"
 mobile/views/pages/widgets/activity.vue:
   activity: "アクティビティ"
 mobile/views/pages/share.vue:
@@ -1056,6 +1066,7 @@ mobile/views/pages/settings/settings.profile.vue:
 mobile/views/pages/search.vue:
   search: "検索"
   empty: "「{}」に関する投稿は見つかりませんでした。"
+  not-found: "「{}」に関する投稿は見つかりませんでした。"
 mobile/views/pages/selectdrive.vue:
   select-file: "ファイルを選択"
 mobile/views/pages/settings.vue:
@@ -1150,3 +1161,5 @@ docs:
       name: "名前"
       type: "型"
       description: "説明"
+dev/views/index.vue:
+  manage-apps: "アプリの管理"
diff --git a/locales/de.yml b/locales/de.yml
index f2d7e55ff9..e1f382aa71 100644
--- a/locales/de.yml
+++ b/locales/de.yml
@@ -11,6 +11,7 @@ common:
     warning: "<strong>Misskeyは広告を掲載していません</strong>が、広告をブロックする機能が有効だと一部の機能が利用できなかったり、不具合が発生する場合があります。"
   application-authorization: "アプリの連携"
   close: "閉じる"
+  do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。"
   got-it: "わかった"
   customization-tips:
     title: "カスタマイズのヒント"
@@ -27,7 +28,6 @@ common:
     notified-by: "{}さんから"
     reply-from: "{}さんから返信:"
     quoted-by: "{}さんが引用:"
-  name: "Misskey"
   time:
     unknown: "Unbekannt"
     future: "Zukunft"
@@ -39,6 +39,7 @@ common:
     weeks_ago: "vor {0} Woche{0:n}"
     months_ago: "vor {0} Monat{0:en}"
     years_ago: "vor {} Jahr{0:en}"
+  month-and-day: "{month}月 {day}日"
   trash: "ゴミ箱"
   weekday-short:
     sunday: "So"
@@ -234,11 +235,13 @@ common/views/components/messaging-room.vue:
   no-history: "Keine weitere Chronik vorhanden"
   resize-form: "Ziehen um die Größe zu verändern"
   new-message: "Neue Nachricht"
+  only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
 common/views/components/messaging-room.form.vue:
   input-message-here: "Nachricht hier eingeben"
   send: "Senden"
   attach-from-local: "Wähle Dateien von deinem PC aus"
   attach-from-drive: "Wähle Dateien von deinem Speicher aus"
+  only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
 common/views/components/messaging-room.message.vue:
   is-read: "Gelesen"
   deleted: "Diese Nachricht wurde gelöscht"
@@ -534,6 +537,8 @@ desktop/views/components/notes.note.vue:
   detail: "Zeige Details"
   private: "Dieser Beitrag ist eine privat"
   deleted: "Dieser Beitrag wurde entfernt"
+  hide: "隠す"
+  see-more: "もっと見る"
 desktop/views/components/notes.vue:
   error: "Laden fehlgeschlagen."
   retry: "Erneut versuchen"
@@ -569,6 +574,7 @@ desktop/views/components/post-form.vue:
   geolocation-alert: "お使いの端末は位置情報に対応していません"
   error: "エラー"
   enter-username: "ユーザー名を入力してください"
+  annotations: "内容への注釈 (オプション)"
 desktop/views/components/post-form-window.vue:
   note: "Neue Notiz"
   reply: "Antworten"
@@ -730,6 +736,7 @@ desktop/views/components/timeline.vue:
   list: "Listen"
 desktop/views/components/ui.header.vue:
   welcome-back: "おかえりなさい、"
+  adjective: "さん"
 desktop/views/components/ui.header.account.vue:
   profile: "Dein Profil"
   drive: "Speicher"
@@ -970,6 +977,7 @@ mobile/views/components/timeline.vue:
   load-more: "もっと"
 mobile/views/components/ui.header.vue:
   welcome-back: "おかえりなさい、"
+  adjective: "さん"
 mobile/views/components/ui.nav.vue:
   timeline: "タイムライン"
   notifications: "通知"
@@ -1018,6 +1026,8 @@ mobile/views/pages/welcome.vue:
 mobile/views/pages/widgets.vue:
   dashboard: "ダッシュボード"
   widgets-hints: "ウィジェットを追加/削除したり並べ替えたりできます。ウィジェットを移動するには「三」をドラッグします。ウィジェットを削除するには「x」をタップします。いくつかのウィジェットはタップすることで表示を変更できます。"
+  add-widget: "追加"
+  customization-tips: "カスタマイズのヒント"
 mobile/views/pages/widgets/activity.vue:
   activity: "アクティビティ"
 mobile/views/pages/share.vue:
@@ -1056,6 +1066,7 @@ mobile/views/pages/settings/settings.profile.vue:
 mobile/views/pages/search.vue:
   search: "検索"
   empty: "「{}」に関する投稿は見つかりませんでした。"
+  not-found: "「{}」に関する投稿は見つかりませんでした。"
 mobile/views/pages/selectdrive.vue:
   select-file: "ファイルを選択"
 mobile/views/pages/settings.vue:
@@ -1150,3 +1161,5 @@ docs:
       name: "名前"
       type: "型"
       description: "説明"
+dev/views/index.vue:
+  manage-apps: "アプリの管理"
diff --git a/locales/en.yml b/locales/en.yml
index bddc9702c0..351e1f4423 100644
--- a/locales/en.yml
+++ b/locales/en.yml
@@ -11,6 +11,7 @@ common:
     warning: "<strong>Misskey is not running ads</strong>, but some features may be unavailable or malfunctioning if ad blocking features are enabled."
   application-authorization: "Application authorizations."
   close: "Close"
+  do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。"
   got-it: "Got it!"
   customization-tips:
     title: "Customization tips"
@@ -27,7 +28,6 @@ common:
     notified-by: "Notified by {}:"
     reply-from: "Reply from {}:"
     quoted-by: "Quoted by {}:"
-  name: "Misskey"
   time:
     unknown: "unknown"
     future: "future"
@@ -39,6 +39,7 @@ common:
     weeks_ago: "{}week(s) ago"
     months_ago: "{}month(s) ago"
     years_ago: "{}year(s) ago"
+  month-and-day: "{month}/{day}"
   trash: "Trash"
   weekday-short:
     sunday: "S"
@@ -234,11 +235,13 @@ common/views/components/messaging-room.vue:
   no-history: "There is no further history"
   resize-form: "Drag to resize"
   new-message: "New message"
+  only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
 common/views/components/messaging-room.form.vue:
   input-message-here: "Enter message here"
   send: "Send"
   attach-from-local: "Attach files from your device"
   attach-from-drive: "Attach files from your Drive"
+  only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
 common/views/components/messaging-room.message.vue:
   is-read: "Read"
   deleted: "This message has been deleted"
@@ -534,6 +537,8 @@ desktop/views/components/notes.note.vue:
   detail: "Show details"
   private: "This post is private"
   deleted: "The post has been deleted"
+  hide: "Hide"
+  see-more: "See more"
 desktop/views/components/notes.vue:
   error: "Loading failed."
   retry: "Retry"
@@ -569,6 +574,7 @@ desktop/views/components/post-form.vue:
   geolocation-alert: "Your device does not support geolocalization."
   error: "Error"
   enter-username: "Please enter a username..."
+  annotations: "内容への注釈 (オプション)"
 desktop/views/components/post-form-window.vue:
   note: "New note"
   reply: "Reply"
@@ -730,6 +736,7 @@ desktop/views/components/timeline.vue:
   list: "Lists"
 desktop/views/components/ui.header.vue:
   welcome-back: "Welcome back,"
+  adjective: "さん"
 desktop/views/components/ui.header.account.vue:
   profile: "Your profile"
   drive: "Media storage"
@@ -805,7 +812,7 @@ desktop/views/pages/selectdrive.vue:
   cancel: "Cancel"
   upload: "Upload files from your device"
 desktop/views/pages/search.vue:
-  not-available: "The search function can not be used."
+  not-available: "The search feature is not available."
   not-found: "No posts were found for '{}'"
 desktop/views/pages/share.vue:
   share-with: "Share with {}."
@@ -970,6 +977,7 @@ mobile/views/components/timeline.vue:
   load-more: "More"
 mobile/views/components/ui.header.vue:
   welcome-back: "Welcome back, "
+  adjective: "さん"
 mobile/views/components/ui.nav.vue:
   timeline: "Timeline"
   notifications: "Notifications"
@@ -1018,6 +1026,8 @@ mobile/views/pages/welcome.vue:
 mobile/views/pages/widgets.vue:
   dashboard: "Dashboard"
   widgets-hints: "You can add/delete/rearrange widgets. To move the widget, drag \"三\". Tap \"x\" to delete the widget. Some widgets can change display by tapping."
+  add-widget: "Add"
+  customization-tips: "Customization tips"
 mobile/views/pages/widgets/activity.vue:
   activity: "Activity"
 mobile/views/pages/share.vue:
@@ -1056,6 +1066,7 @@ mobile/views/pages/settings/settings.profile.vue:
 mobile/views/pages/search.vue:
   search: "Search"
   empty: "No posts were found for '{}'"
+  not-found: "「{}」に関する投稿は見つかりませんでした。"
 mobile/views/pages/selectdrive.vue:
   select-file: "Choose files"
 mobile/views/pages/settings.vue:
@@ -1150,3 +1161,5 @@ docs:
       name: "Name"
       type: "Type"
       description: "Description"
+dev/views/index.vue:
+  manage-apps: "Manage apps"
diff --git a/locales/es.yml b/locales/es.yml
index 5f24b2d574..21a36c6a4f 100644
--- a/locales/es.yml
+++ b/locales/es.yml
@@ -11,6 +11,7 @@ common:
     warning: "<strong>Misskey no tiene anuncios publicitarios.</strong> Sin embargo, algunas características podrían no estar disponibles si el bloqueador de publicidad está habilitado."
   application-authorization: "Autorizaciones de la aplicación."
   close: "Cerrar"
+  do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。"
   got-it: "¡Listo!"
   customization-tips:
     title: "Consejos de personalización"
@@ -27,7 +28,6 @@ common:
     notified-by: "Notificado por {}:"
     reply-from: "Respuesta de {}:"
     quoted-by: "Citado por {}:"
-  name: "Misskey"
   time:
     unknown: "Desconocido"
     future: "Futuro"
@@ -39,6 +39,7 @@ common:
     weeks_ago: "Hace {} semana(s)"
     months_ago: "Hace {} mes(es)"
     years_ago: "Hace {} año(s)"
+  month-and-day: "{month}月 {day}日"
   trash: "Papelera"
   weekday-short:
     sunday: "domingo"
@@ -234,11 +235,13 @@ common/views/components/messaging-room.vue:
   no-history: "El historial se ha acabado"
   resize-form: "Arrastra para redimensionar"
   new-message: "Nuevo mensaje"
+  only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
 common/views/components/messaging-room.form.vue:
   input-message-here: "Escribe el mensaje aquí"
   send: "Enviar"
   attach-from-local: "Adjunta ficheros desde tu PC"
   attach-from-drive: "Adjunta ficheros desde tu disco"
+  only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
 common/views/components/messaging-room.message.vue:
   is-read: "Leer"
   deleted: "El mensaje se ha borrado"
@@ -534,6 +537,8 @@ desktop/views/components/notes.note.vue:
   detail: "Mostrar detalles"
   private: "Esta publicación es privada"
   deleted: "Esta publicación ha sido borrada"
+  hide: "隠す"
+  see-more: "もっと見る"
 desktop/views/components/notes.vue:
   error: "Error al cargar."
   retry: "Reintentar"
@@ -569,6 +574,7 @@ desktop/views/components/post-form.vue:
   geolocation-alert: "Tu dispositivo no tiene soporte de geolocalización."
   error: "Error"
   enter-username: "Por favor escribe un nombre de usuario..."
+  annotations: "内容への注釈 (オプション)"
 desktop/views/components/post-form-window.vue:
   note: "Nota nueva"
   reply: "Responder"
@@ -730,6 +736,7 @@ desktop/views/components/timeline.vue:
   list: "リスト"
 desktop/views/components/ui.header.vue:
   welcome-back: "おかえりなさい、"
+  adjective: "さん"
 desktop/views/components/ui.header.account.vue:
   profile: "プロフィール"
   drive: "ドライブ"
@@ -970,6 +977,7 @@ mobile/views/components/timeline.vue:
   load-more: "もっと"
 mobile/views/components/ui.header.vue:
   welcome-back: "おかえりなさい、"
+  adjective: "さん"
 mobile/views/components/ui.nav.vue:
   timeline: "タイムライン"
   notifications: "通知"
@@ -1018,6 +1026,8 @@ mobile/views/pages/welcome.vue:
 mobile/views/pages/widgets.vue:
   dashboard: "ダッシュボード"
   widgets-hints: "ウィジェットを追加/削除したり並べ替えたりできます。ウィジェットを移動するには「三」をドラッグします。ウィジェットを削除するには「x」をタップします。いくつかのウィジェットはタップすることで表示を変更できます。"
+  add-widget: "追加"
+  customization-tips: "カスタマイズのヒント"
 mobile/views/pages/widgets/activity.vue:
   activity: "アクティビティ"
 mobile/views/pages/share.vue:
@@ -1056,6 +1066,7 @@ mobile/views/pages/settings/settings.profile.vue:
 mobile/views/pages/search.vue:
   search: "検索"
   empty: "「{}」に関する投稿は見つかりませんでした。"
+  not-found: "「{}」に関する投稿は見つかりませんでした。"
 mobile/views/pages/selectdrive.vue:
   select-file: "ファイルを選択"
 mobile/views/pages/settings.vue:
@@ -1150,3 +1161,5 @@ docs:
       name: "名前"
       type: "型"
       description: "説明"
+dev/views/index.vue:
+  manage-apps: "アプリの管理"
diff --git a/locales/fr.yml b/locales/fr.yml
index cc4924ed68..271914d460 100644
--- a/locales/fr.yml
+++ b/locales/fr.yml
@@ -11,7 +11,8 @@ common:
     warning: "<strong>Misskey n'utilise pas de publicités</strong>, mais quelques options peuvent être non disponibles ou fonctionneraient mal si un bloqueur de publicités est activé."
   application-authorization: "Permissions de l'application"
   close: "Fermer"
-  got-it: "わかった"
+  do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。"
+  got-it: "J'ai compris !"
   customization-tips:
     title: "Conseils de personnalisation"
     paragraph1: "La personnalisation à la maison vous permet d'ajouter / supprimer, glisser et déposer et réorganiser les widgets."
@@ -27,7 +28,6 @@ common:
     notified-by: "Notifié par {} :"
     reply-from: "Réponse de {} :"
     quoted-by: "Cité·e par {} :"
-  name: "Misskey"
   time:
     unknown: "inconnu"
     future: "future"
@@ -39,6 +39,7 @@ common:
     weeks_ago: "Il y a {} semaines·s"
     months_ago: "Il y a {} mois"
     years_ago: "Il y a {} an·s"
+  month-and-day: "{month}/{day}"
   trash: "Corbeille"
   weekday-short:
     sunday: "D"
@@ -201,7 +202,7 @@ common/views/components/games/reversi/reversi.room.vue:
   ready: "Prêt"
   cancel-ready: "Annuler \"Je suis prêt\""
 common/views/components/connect-failed.vue:
-  title: "Impossible de se connecter au server."
+  title: "Échec de connexion au serveur"
   description: "Il y a soit un problème avec votre connexion internet, soit le serveur est hors-ligne ou en maintenance. Veuillez {ressayer} plus tard."
   thanks: "On vous remercie d'utiliser Misskey."
   troubleshoot: "dépanner"
@@ -211,7 +212,7 @@ common/views/components/connect-failed.troubleshooter.vue:
   checking-network: "Vérification de la connexion au réseau"
   internet: "Connexion Internet"
   checking-internet: "Vérification de la connexion internet"
-  server: "Connexion au server"
+  server: "Connexion au serveur"
   checking-server: "Vérification de la connexion au serveur"
   finding: "Recherche d'un problème"
   no-network: "Aucune connexion au réseau"
@@ -219,9 +220,9 @@ common/views/components/connect-failed.troubleshooter.vue:
   no-internet: "Aucune connexion internet."
   no-internet-desc: "Veuillez vérifier que vous êtes bien connecté à internet."
   no-server: "Impossible de se connecter au serveur"
-  no-server-desc: "Votre connexion est OK, mais il a été impossible de vous connecter au serveur de Misskey. Il y a des chances que le serveur soit hors-ligne ou en maintenance, veuillez ressayer plus tard."
-  success: "Connexion au serveur de Misskey reussie!"
-  success-desc: "La connexion au serveur a été reussie. Veuillez recharger la page."
+  no-server-desc: "Votre connexion semble correcte, mais il a été impossible de vous connecter au serveur de Misskey. Il se peut que le serveur soit hors-ligne ou en maintenance, veuillez ressayer plus tard."
+  success: "Connexion au serveur de Misskey réussie !"
+  success-desc: "Succès de la connexion au serveur de Misskey. Veuillez recharger la page."
   flush: "Vider le cache"
   set-version: "Choisissez une version"
 common/views/components/messaging.vue:
@@ -234,11 +235,13 @@ common/views/components/messaging-room.vue:
   no-history: "Il n'y a pas plus d'historique"
   resize-form: "Faites glisser pour redimensionner"
   new-message: "Nouveau message"
+  only-one-file-attached: "Un seul fichier uniquement peut être joint au message"
 common/views/components/messaging-room.form.vue:
   input-message-here: "Tapez ici votre message"
   send: "Envoyer"
   attach-from-local: "Joindre un fichier depuis votre PC"
   attach-from-drive: "Joindre un fichier depuis votre Drive"
+  only-one-file-attached: "Un seul fichier uniquement peut être joint au message"
 common/views/components/messaging-room.message.vue:
   is-read: "Lu"
   deleted: "Ce message a été supprimé"
@@ -278,8 +281,8 @@ common/views/components/signin.vue:
   token: "Token"
   signing-in: "Connexion...."
   signin: "Se connecter"
-  or: "または"
-  signin-with-twitter: "Twitterでログイン"
+  or: "Ou"
+  signin-with-twitter: "Se connecter via Twitter"
 common/views/components/signup.vue:
   username: "Nom d'utilisateur"
   checking: "Vérification"
@@ -287,10 +290,10 @@ common/views/components/signup.vue:
   unavailable: "Non disponible"
   error: "Erreur de réseau"
   invalid-format: "Utilisez seulement des lettres, nombres et/ou -."
-  too-short: "Veuillez taper au moins un charactère!"
-  too-long: "Veuillez entrer au maximum 20 charactères."
+  too-short: "Veuillez saisir au moins un caractère !"
+  too-long: "Veuillez entrer au maximum 20 caractères."
   password: "Mot de Passe"
-  password-placeholder: "Nous recommendons au moins 8 charactères."
+  password-placeholder: "Nous recommendons au moins 8 caractères."
   weak-password: "Faible"
   normal-password: "Moyen"
   strong-password: "Fort"
@@ -300,21 +303,21 @@ common/views/components/signup.vue:
   password-not-matched: "Les mots de passes ne correspondent pas."
   recaptcha: "Vérifier"
   create: "Créer un compte"
-  some-error: "La création de compte a échoué. Veuillez ressayer."
+  some-error: "La création du compte a échoué. Veuillez réessayer."
 common/views/components/special-message.vue:
-  new-year: "Bonne année!"
-  christmas: "Joyeux Noël!"
+  new-year: "Bonne année !"
+  christmas: "Joyeux Noël !"
 common/views/components/stream-indicator.vue:
   connecting: "Connexion en cours"
-  reconnecting: "Re-connexion en cours"
+  reconnecting: "Reconnexion en cours"
   connected: "Connecté"
 common/views/components/twitter-setting.vue:
   description: "Si vous liez votre compte Twitter à votre compte Misskey, vous verrez ensuite votre compte Twitter s'afficher sur votre profile, vous aurez aussi la possibilité de vous connecter à Misskey en utilisant votre compte Twitter."
-  connected-to: "Vous êtes connecté à ce compte"
-  detail: "Detail..."
+  connected-to: "Vous êtes connecté à ce compte Twitter"
+  detail: "Détails …"
   reconnect: "Reconnecter"
   connect: "Lier votre compte Twitter"
-  disconnect: "Deconnecter"
+  disconnect: "Déconnecter"
 common/views/components/uploader.vue:
   waiting: "En attente"
 common/views/components/visibility-chooser.vue:
@@ -324,12 +327,12 @@ common/views/components/visibility-chooser.vue:
   followers: "Abonné·e·s"
   followers-desc: "Publier à vos abonné·e·s uniquement"
   specified: "Direct"
-  specified-desc: "Publier aux utilisateurs mentionnés"
+  specified-desc: "Publier aux utilisateurs·trices mentionné·es"
   private: "Privé"
 common/views/widgets/broadcast.vue:
   fetching: "Récuperation"
-  no-broadcasts: "No broadcasts"
-  have-a-nice-day: "Passez une bonne journée!"
+  no-broadcasts: "Aucune annonce"
+  have-a-nice-day: "Passez une bonne journée !"
   next: "Suivant"
 common/views/widgets/calendar.vue:
   year: "{} année"
@@ -340,13 +343,13 @@ common/views/widgets/calendar.vue:
   this-year: "Cette année :"
 common/views/widgets/donation.vue:
   title: "Dons"
-  text: "Toutes les depences pour couvrir les frais de Misskey sortent directement de notre poche. Nous ne recevons pas d'argent, si vous pouvez nous faire dons d'argent, on vous serait eternellement reconnaissant. Si vous êtes intéressés veuilles contacter {}. Merci pour votre contribution!"
+  text: "Les frais pour faire fonctionner Misskey sortent directement de notre poche. Nous ne recevons pas d'argent issu de la publicité, si vous pouvez nous faire des dons, on vous serait éternellement reconnaissants. Si vous êtes intéressé·es veuillez contacter {}. Merci pour votre contribution !"
 common/views/widgets/photo-stream.vue:
   title: "Flux de photo"
   no-photos: "Pas de photos"
 common/views/widgets/posts-monitor.vue:
   title: "Graph des publications"
-  toggle: "Basculer les vues"
+  toggle: "Basculer entre les vues"
 common/views/widgets/hashtags.vue:
   title: "Étiquettes"
   count: "{} utilisateurs mentionnés"
@@ -367,7 +370,7 @@ common/views/widgets/tips.vue:
   tips-line2: "<kbd>p</kbd>または<kbd>n</kbd>で投稿フォームを開きます"
   tips-line3: "Vous pouvez glisser et déposer des fichiers sur la fenêtre de la note"
   tips-line4: "Vous pouvez coller des images à partir du presse-papier sur la fenêtre de la note"
-  tips-line5: "ドライブにファイルをドラッグ&ドロップしてアップロードできます"
+  tips-line5: "Vous pouvez téléverser des fichiers sur le Drive en faisant un glisser/déplacer"
   tips-line6: "ドライブでファイルをドラッグしてフォルダ移動できます"
   tips-line7: "ドライブでフォルダをドラッグしてフォルダ移動できます"
   tips-line8: "Vous pouvez personnaliser l'Accueil via les paramètres"
@@ -376,7 +379,7 @@ common/views/widgets/tips.vue:
   tips-line11: "Vous pouvez épingler des notes sur votre page en appuyant sur \"…\""
   tips-line13: "Tous les fichiers attachés à cette publication sont sauvegardés dans le Drive"
   tips-line14: "ホームのカスタマイズ中、ウィジェットを右クリックしてデザインを変更できます"
-  tips-line17: "「**」でテキストを囲むと**強調表示**されます"
+  tips-line17: "Vous pouvez mettre un texte en surbrillance en le mettant entre ** **"
   tips-line19: "いくつかのウィンドウはブラウザの外に切り離すことができます"
   tips-line20: "カレンダーウィジェットのパーセンテージは、経過の割合を示しています"
   tips-line21: "Vous pouvez aussi utiliser l'API pour développer des Bots."
@@ -390,16 +393,16 @@ common/views/pages/follow.vue:
   request-pending: "Demande d'abonnement en attente"
   follow-request: "Demande d'abonnement"
 desktop:
-  banner-crop-title: "バナーとして表示する部分を選択"
-  banner: "バナー"
-  uploading-banner: "新しいバナーをアップロードしています"
-  banner-updated: "バナーを更新しました"
-  choose-banner: "バナーにする画像を選択"
-  avatar-crop-title: "アバターとして表示する部分を選択"
-  avatar: "アバター"
-  uploading-avatar: "新しいアバターをアップロードしています"
-  avatar-updated: "アバターを更新しました"
-  choose-avatar: "アバターにする画像を選択"
+  banner-crop-title: "Découpez la partie qui apparaîtra comme une bannière"
+  banner: "Bannière"
+  uploading-banner: "Téléversement d'une nouvelle bannière"
+  banner-updated: "La bannière est mise à jour"
+  choose-banner: "Choisir une bannière"
+  avatar-crop-title: "Découpez la partie qui apparaîtra dans l'avatar"
+  avatar: "Avatar"
+  uploading-avatar: "Téléversement du nouvel avatar"
+  avatar-updated: "L'avatar est mis à jour"
+  choose-avatar: "Choisir un avatar"
 desktop/views/components/activity.chart.vue:
   total: "Noirs ... Total"
   notes: "Bleu ... Notes"
@@ -534,6 +537,8 @@ desktop/views/components/notes.note.vue:
   detail: "Afficher les détails"
   private: "cette publication est privée"
   deleted: "cette publication a été supprimée"
+  hide: "Masquer"
+  see-more: "Voir plus"
 desktop/views/components/notes.vue:
   error: "Échec du chargement."
   retry: "Réessayer"
@@ -569,6 +574,7 @@ desktop/views/components/post-form.vue:
   geolocation-alert: "Votre appareil ne prend pas en charge les services de localisation"
   error: "Erreur"
   enter-username: "Saisir un nom d'utilisateur …"
+  annotations: "内容への注釈 (オプション)"
 desktop/views/components/post-form-window.vue:
   note: "Nouvelle note"
   reply: "Répondre"
@@ -615,7 +621,7 @@ desktop/views/components/settings.vue:
   circle-icons: "Utiliser des icônes circulaires"
   gradient-window-header: "Utiliser les dégradés sur la barre de titre de la fenêtre"
   post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
-  show-reply-target: "リプライ先を表示する"
+  show-reply-target: "Afficher les réponses"
   show-my-renotes: "Afficher mes republications dans le fil"
   show-renoted-my-notes: "Renoteされた自分の投稿をタイムラインに表示する"
   show-maps: "Afficher la carte"
@@ -730,6 +736,7 @@ desktop/views/components/timeline.vue:
   list: "Listes"
 desktop/views/components/ui.header.vue:
   welcome-back: "Content de vous revoir !"
+  adjective: "さん"
 desktop/views/components/ui.header.account.vue:
   profile: "Votre profil"
   drive: "Drive"
@@ -758,7 +765,7 @@ desktop/views/components/received-follow-requests-window.vue:
 desktop/views/components/user-lists-window.vue:
   title: "Listes de l'utilisateur"
   create-list: "Créer une liste"
-  list-name: "リスト名"
+  list-name: "Nom de la liste"
 desktop/views/components/user-preview.vue:
   notes: "Publications"
   following: "Abonné à"
@@ -841,8 +848,8 @@ desktop/views/pages/user/user.profile.vue:
   mute: "Mettre en sourdine"
   muted: "Muting"
   unmute: "Enlever la sourdine"
-  push-to-a-list: "リストに追加"
-  list-pushed: "{user}を{list}に追加しました。"
+  push-to-a-list: "Ajouter à la liste"
+  list-pushed: "Vous avez ajouté {user} à la liste {list}."
 desktop/views/pages/user/user.header.vue:
   posts: "Notes"
   following: "Suit"
@@ -969,7 +976,8 @@ mobile/views/components/timeline.vue:
   empty: "Pas de notes"
   load-more: "Afficher plus"
 mobile/views/components/ui.header.vue:
-  welcome-back: "おかえりなさい、"
+  welcome-back: "Bon retour parmi nous !"
+  adjective: "さん"
 mobile/views/components/ui.nav.vue:
   timeline: "Fil d'actualité"
   notifications: "Notifications"
@@ -1018,6 +1026,8 @@ mobile/views/pages/welcome.vue:
 mobile/views/pages/widgets.vue:
   dashboard: "Tableau de bord"
   widgets-hints: "ウィジェットを追加/削除したり並べ替えたりできます。ウィジェットを移動するには「三」をドラッグします。ウィジェットを削除するには「x」をタップします。いくつかのウィジェットはタップすることで表示を変更できます。"
+  add-widget: "Ajouter"
+  customization-tips: "Conseils de personnalisation"
 mobile/views/pages/widgets/activity.vue:
   activity: "Activité"
 mobile/views/pages/share.vue:
@@ -1056,6 +1066,7 @@ mobile/views/pages/settings/settings.profile.vue:
 mobile/views/pages/search.vue:
   search: "Chercher"
   empty: "Aucun message trouvé pour '{}' "
+  not-found: "「{}」に関する投稿は見つかりませんでした。"
 mobile/views/pages/selectdrive.vue:
   select-file: "Choisissez un fichier"
 mobile/views/pages/settings.vue:
@@ -1150,3 +1161,5 @@ docs:
       name: "Nom"
       type: "Type"
       description: "Description"
+dev/views/index.vue:
+  manage-apps: "Gestion des applications"
diff --git a/locales/it.yml b/locales/it.yml
index 8e4f7cc2cb..fbd955c3fd 100644
--- a/locales/it.yml
+++ b/locales/it.yml
@@ -11,6 +11,7 @@ common:
     warning: "<strong>Misskeyは広告を掲載していません</strong>が、広告をブロックする機能が有効だと一部の機能が利用できなかったり、不具合が発生する場合があります。"
   application-authorization: "アプリの連携"
   close: "閉じる"
+  do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。"
   got-it: "わかった"
   customization-tips:
     title: "カスタマイズのヒント"
@@ -27,7 +28,6 @@ common:
     notified-by: "{}さんから"
     reply-from: "{}さんから返信:"
     quoted-by: "{}さんが引用:"
-  name: "Misskey"
   time:
     unknown: "なぞのじかん"
     future: "未来"
@@ -39,6 +39,7 @@ common:
     weeks_ago: "{}週間前"
     months_ago: "{}ヶ月前"
     years_ago: "{}年前"
+  month-and-day: "{month}月 {day}日"
   trash: "ゴミ箱"
   weekday-short:
     sunday: "日"
@@ -234,11 +235,13 @@ common/views/components/messaging-room.vue:
   no-history: "これより過去の履歴はありません"
   resize-form: "ドラッグしてフォームの広さを調整"
   new-message: "新しいメッセージがあります"
+  only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
 common/views/components/messaging-room.form.vue:
   input-message-here: "ここにメッセージを入力"
   send: "送信"
   attach-from-local: "PCからファイルを添付する"
   attach-from-drive: "ドライブからファイルを添付する"
+  only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
 common/views/components/messaging-room.message.vue:
   is-read: "既読"
   deleted: "このメッセージは削除されました"
@@ -534,6 +537,8 @@ desktop/views/components/notes.note.vue:
   detail: "詳細"
   private: "この投稿は非公開です"
   deleted: "この投稿は削除されました"
+  hide: "隠す"
+  see-more: "もっと見る"
 desktop/views/components/notes.vue:
   error: "読み込みに失敗しました。"
   retry: "リトライ"
@@ -569,6 +574,7 @@ desktop/views/components/post-form.vue:
   geolocation-alert: "お使いの端末は位置情報に対応していません"
   error: "エラー"
   enter-username: "ユーザー名を入力してください"
+  annotations: "内容への注釈 (オプション)"
 desktop/views/components/post-form-window.vue:
   note: "新規投稿"
   reply: "返信"
@@ -730,6 +736,7 @@ desktop/views/components/timeline.vue:
   list: "リスト"
 desktop/views/components/ui.header.vue:
   welcome-back: "おかえりなさい、"
+  adjective: "さん"
 desktop/views/components/ui.header.account.vue:
   profile: "プロフィール"
   drive: "ドライブ"
@@ -970,6 +977,7 @@ mobile/views/components/timeline.vue:
   load-more: "もっと"
 mobile/views/components/ui.header.vue:
   welcome-back: "おかえりなさい、"
+  adjective: "さん"
 mobile/views/components/ui.nav.vue:
   timeline: "タイムライン"
   notifications: "通知"
@@ -1018,6 +1026,8 @@ mobile/views/pages/welcome.vue:
 mobile/views/pages/widgets.vue:
   dashboard: "ダッシュボード"
   widgets-hints: "ウィジェットを追加/削除したり並べ替えたりできます。ウィジェットを移動するには「三」をドラッグします。ウィジェットを削除するには「x」をタップします。いくつかのウィジェットはタップすることで表示を変更できます。"
+  add-widget: "追加"
+  customization-tips: "カスタマイズのヒント"
 mobile/views/pages/widgets/activity.vue:
   activity: "アクティビティ"
 mobile/views/pages/share.vue:
@@ -1056,6 +1066,7 @@ mobile/views/pages/settings/settings.profile.vue:
 mobile/views/pages/search.vue:
   search: "検索"
   empty: "「{}」に関する投稿は見つかりませんでした。"
+  not-found: "「{}」に関する投稿は見つかりませんでした。"
 mobile/views/pages/selectdrive.vue:
   select-file: "ファイルを選択"
 mobile/views/pages/settings.vue:
@@ -1150,3 +1161,5 @@ docs:
       name: "名前"
       type: "型"
       description: "説明"
+dev/views/index.vue:
+  manage-apps: "アプリの管理"
diff --git a/locales/ko.yml b/locales/ko.yml
index 7b67488097..252027fa87 100644
--- a/locales/ko.yml
+++ b/locales/ko.yml
@@ -11,6 +11,7 @@ common:
     warning: "<strong>Misskey는 광고를 게재하지 않습니다</strong> 그러나 광고를 차단하는 기능 기능을 사용할 경우 일부 기능을 사용할 수 없게 될 가능성이나 결함이 발생하는 경우가 있습니다."
   application-authorization: "앱의 연계"
   close: "닫기"
+  do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。"
   got-it: "わかった"
   customization-tips:
     title: "사용자 정의 팁"
@@ -27,7 +28,6 @@ common:
     notified-by: "{}님"
     reply-from: "{}님으로부터 답글:"
     quoted-by: "{}씨가 인용:"
-  name: "Misskey"
   time:
     unknown: "수수께끼의 시간"
     future: "미래"
@@ -39,6 +39,7 @@ common:
     weeks_ago: "{}주전"
     months_ago: "{}개월전"
     years_ago: "{}년전"
+  month-and-day: "{month}月 {day}日"
   trash: "휴지통"
   weekday-short:
     sunday: "일"
@@ -234,11 +235,13 @@ common/views/components/messaging-room.vue:
   no-history: "これより過去の履歴はありません"
   resize-form: "ドラッグしてフォームの広さを調整"
   new-message: "新しいメッセージがあります"
+  only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
 common/views/components/messaging-room.form.vue:
   input-message-here: "ここにメッセージを入力"
   send: "送信"
   attach-from-local: "PCからファイルを添付する"
   attach-from-drive: "ドライブからファイルを添付する"
+  only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
 common/views/components/messaging-room.message.vue:
   is-read: "既読"
   deleted: "このメッセージは削除されました"
@@ -534,6 +537,8 @@ desktop/views/components/notes.note.vue:
   detail: "詳細"
   private: "この投稿は非公開です"
   deleted: "この投稿は削除されました"
+  hide: "隠す"
+  see-more: "もっと見る"
 desktop/views/components/notes.vue:
   error: "読み込みに失敗しました。"
   retry: "リトライ"
@@ -569,6 +574,7 @@ desktop/views/components/post-form.vue:
   geolocation-alert: "お使いの端末は位置情報に対応していません"
   error: "エラー"
   enter-username: "ユーザー名を入力してください"
+  annotations: "内容への注釈 (オプション)"
 desktop/views/components/post-form-window.vue:
   note: "新規投稿"
   reply: "返信"
@@ -730,6 +736,7 @@ desktop/views/components/timeline.vue:
   list: "リスト"
 desktop/views/components/ui.header.vue:
   welcome-back: "おかえりなさい、"
+  adjective: "さん"
 desktop/views/components/ui.header.account.vue:
   profile: "プロフィール"
   drive: "ドライブ"
@@ -970,6 +977,7 @@ mobile/views/components/timeline.vue:
   load-more: "もっと"
 mobile/views/components/ui.header.vue:
   welcome-back: "おかえりなさい、"
+  adjective: "さん"
 mobile/views/components/ui.nav.vue:
   timeline: "タイムライン"
   notifications: "通知"
@@ -1018,6 +1026,8 @@ mobile/views/pages/welcome.vue:
 mobile/views/pages/widgets.vue:
   dashboard: "ダッシュボード"
   widgets-hints: "ウィジェットを追加/削除したり並べ替えたりできます。ウィジェットを移動するには「三」をドラッグします。ウィジェットを削除するには「x」をタップします。いくつかのウィジェットはタップすることで表示を変更できます。"
+  add-widget: "追加"
+  customization-tips: "カスタマイズのヒント"
 mobile/views/pages/widgets/activity.vue:
   activity: "アクティビティ"
 mobile/views/pages/share.vue:
@@ -1056,6 +1066,7 @@ mobile/views/pages/settings/settings.profile.vue:
 mobile/views/pages/search.vue:
   search: "検索"
   empty: "「{}」に関する投稿は見つかりませんでした。"
+  not-found: "「{}」に関する投稿は見つかりませんでした。"
 mobile/views/pages/selectdrive.vue:
   select-file: "ファイルを選択"
 mobile/views/pages/settings.vue:
@@ -1150,3 +1161,5 @@ docs:
       name: "名前"
       type: "型"
       description: "説明"
+dev/views/index.vue:
+  manage-apps: "アプリの管理"
diff --git a/locales/pl.yml b/locales/pl.yml
index 3fe348dda8..319062a9e0 100644
--- a/locales/pl.yml
+++ b/locales/pl.yml
@@ -11,7 +11,8 @@ common:
     warning: "<strong>Misskey nie zawiera reklam</strong>, ale część funkcji może nie działać prawidłowo z włączonym blokowaniem reklam."
   application-authorization: "アプリの連携"
   close: "Zamknij"
-  got-it: "わかった"
+  do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。"
+  got-it: "Rozumiem!"
   customization-tips:
     title: "Wskazówki o dostosowywaniu"
     paragraph1: "Dostosowywanie strony głównej pozwala na dodawanie, usuwanie, przeciąganie i zmienianie kolejności widżetów."
@@ -27,7 +28,6 @@ common:
     notified-by: "Powiadomiono przez {}:"
     reply-from: "Odpowiedź od {}:"
     quoted-by: "Zacytowano przez {}:"
-  name: "Misskey"
   time:
     unknown: "nieznany"
     future: "w przyszłości"
@@ -39,6 +39,7 @@ common:
     weeks_ago: "{} tyg. temu"
     months_ago: "{} mies. temu"
     years_ago: "{} lat temu"
+  month-and-day: "{month}月 {day}日"
   trash: "Kosz"
   weekday-short:
     sunday: "N"
@@ -234,11 +235,13 @@ common/views/components/messaging-room.vue:
   no-history: "Brak dalszej historii"
   resize-form: "Przeciągnij aby zmienić rozmiar"
   new-message: "Nowa wiadomość"
+  only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
 common/views/components/messaging-room.form.vue:
   input-message-here: "Wprowadź wiadomość tutaj"
   send: "Wyślij"
   attach-from-local: "Załącz pliki z komputera"
   attach-from-drive: "Załącz pliki z dysku"
+  only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
 common/views/components/messaging-room.message.vue:
   is-read: "Przeczytano"
   deleted: "Wiadomość została usunięta"
@@ -279,7 +282,7 @@ common/views/components/signin.vue:
   signing-in: "Logowanie…"
   signin: "Zaloguj"
   or: "または"
-  signin-with-twitter: "Twitterでログイン"
+  signin-with-twitter: "Zaloguj się za pomocą Twittera"
 common/views/components/signup.vue:
   username: "Nazwa użytkownika"
   checking: "Sprawdzanie…"
@@ -369,7 +372,7 @@ common/views/widgets/tips.vue:
   tips-line4: "投稿フォームにクリップボードにある画像データをペーストできます"
   tips-line5: "Możesz wysłać pliki przeciągając i upuszczając je w Dysku."
   tips-line6: "Możesz przenieść katalog przeciągając go w Dysku."
-  tips-line7: "ドライブでフォルダをドラッグしてフォルダ移動できます"
+  tips-line7: "Możesz przenieść katalog przeciągając go w Dysku."
   tips-line8: "Strona główna może zostać dostosowana w ustawieniach."
   tips-line9: "Misskey jest dostępny na licencji AGPLv3."
   tips-line10: "タイムマシンウィジェットを利用すると、簡単に過去のタイムラインに遡れます"
@@ -534,6 +537,8 @@ desktop/views/components/notes.note.vue:
   detail: "Pokaż szczegóły"
   private: "ten wpis jest prywatny"
   deleted: "ten wpis został usunięty"
+  hide: "Zwiń"
+  see-more: "Więcej"
 desktop/views/components/notes.vue:
   error: "Ładowanie nie powiodło się."
   retry: "Spróbuj ponownie"
@@ -569,6 +574,7 @@ desktop/views/components/post-form.vue:
   geolocation-alert: "Twoje urządzenie nie obsługuje geolokalizacji."
   error: "Bład"
   enter-username: "Wprowadź nazwę użytkownika…"
+  annotations: "Treść ostrzeżenia (opcjonalnie)"
 desktop/views/components/post-form-window.vue:
   note: "Nowy wpis"
   reply: "Odpowiedz"
@@ -730,6 +736,7 @@ desktop/views/components/timeline.vue:
   list: "Listy"
 desktop/views/components/ui.header.vue:
   welcome-back: "Witaj ponownie,"
+  adjective: "さん"
 desktop/views/components/ui.header.account.vue:
   profile: "Twój profil"
   drive: "Dysk"
@@ -758,7 +765,7 @@ desktop/views/components/received-follow-requests-window.vue:
 desktop/views/components/user-lists-window.vue:
   title: "Listy"
   create-list: "Utwórz listę"
-  list-name: "リスト名"
+  list-name: "Nazwa listy"
 desktop/views/components/user-preview.vue:
   notes: "Wpisy"
   following: "Śledzeni"
@@ -841,8 +848,8 @@ desktop/views/pages/user/user.profile.vue:
   mute: "Wycisz"
   muted: "Wyciszyłeś"
   unmute: "Cofnij wyciszenie"
-  push-to-a-list: "リストに追加"
-  list-pushed: "{user}を{list}に追加しました。"
+  push-to-a-list: "Dodaj do listy"
+  list-pushed: "Dodałeś(-aś) {user} do {list}."
 desktop/views/pages/user/user.header.vue:
   posts: "Wpisy"
   following: "Śledzeni"
@@ -970,6 +977,7 @@ mobile/views/components/timeline.vue:
   load-more: "Więcej"
 mobile/views/components/ui.header.vue:
   welcome-back: "Witaj ponownie, "
+  adjective: "さん"
 mobile/views/components/ui.nav.vue:
   timeline: "Oś czasu"
   notifications: "Powiadomienia"
@@ -1018,6 +1026,8 @@ mobile/views/pages/welcome.vue:
 mobile/views/pages/widgets.vue:
   dashboard: "Kokpit"
   widgets-hints: "ウィジェットを追加/削除したり並べ替えたりできます。ウィジェットを移動するには「三」をドラッグします。ウィジェットを削除するには「x」をタップします。いくつかのウィジェットはタップすることで表示を変更できます。"
+  add-widget: "Dodaj"
+  customization-tips: "カスタマイズのヒント"
 mobile/views/pages/widgets/activity.vue:
   activity: "Aktywność"
 mobile/views/pages/share.vue:
@@ -1056,6 +1066,7 @@ mobile/views/pages/settings/settings.profile.vue:
 mobile/views/pages/search.vue:
   search: "Szukaj"
   empty: "Nie znaleziono wpisów zawierających '{}'"
+  not-found: "「{}」に関する投稿は見つかりませんでした。"
 mobile/views/pages/selectdrive.vue:
   select-file: "Wybierz plik"
 mobile/views/pages/settings.vue:
@@ -1150,3 +1161,5 @@ docs:
       name: "Nazwa"
       type: "Rodzaj"
       description: "Opis"
+dev/views/index.vue:
+  manage-apps: "アプリの管理"
diff --git a/locales/pt.yml b/locales/pt.yml
index 61d852c3cd..3cc4530447 100644
--- a/locales/pt.yml
+++ b/locales/pt.yml
@@ -11,6 +11,7 @@ common:
     warning: "<strong>Misskeyは広告を掲載していません</strong>が、広告をブロックする機能が有効だと一部の機能が利用できなかったり、不具合が発生する場合があります。"
   application-authorization: "アプリの連携"
   close: "閉じる"
+  do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。"
   got-it: "わかった"
   customization-tips:
     title: "カスタマイズのヒント"
@@ -27,7 +28,6 @@ common:
     notified-by: "{}さんから"
     reply-from: "{}さんから返信:"
     quoted-by: "{}さんが引用:"
-  name: "Misskey"
   time:
     unknown: "なぞのじかん"
     future: "未来"
@@ -39,6 +39,7 @@ common:
     weeks_ago: "{}週間前"
     months_ago: "{}ヶ月前"
     years_ago: "{}年前"
+  month-and-day: "{month}月 {day}日"
   trash: "ゴミ箱"
   weekday-short:
     sunday: "日"
@@ -234,11 +235,13 @@ common/views/components/messaging-room.vue:
   no-history: "これより過去の履歴はありません"
   resize-form: "ドラッグしてフォームの広さを調整"
   new-message: "新しいメッセージがあります"
+  only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
 common/views/components/messaging-room.form.vue:
   input-message-here: "ここにメッセージを入力"
   send: "送信"
   attach-from-local: "PCからファイルを添付する"
   attach-from-drive: "ドライブからファイルを添付する"
+  only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
 common/views/components/messaging-room.message.vue:
   is-read: "既読"
   deleted: "このメッセージは削除されました"
@@ -534,6 +537,8 @@ desktop/views/components/notes.note.vue:
   detail: "詳細"
   private: "この投稿は非公開です"
   deleted: "この投稿は削除されました"
+  hide: "隠す"
+  see-more: "もっと見る"
 desktop/views/components/notes.vue:
   error: "読み込みに失敗しました。"
   retry: "リトライ"
@@ -569,6 +574,7 @@ desktop/views/components/post-form.vue:
   geolocation-alert: "お使いの端末は位置情報に対応していません"
   error: "エラー"
   enter-username: "ユーザー名を入力してください"
+  annotations: "内容への注釈 (オプション)"
 desktop/views/components/post-form-window.vue:
   note: "新規投稿"
   reply: "返信"
@@ -730,6 +736,7 @@ desktop/views/components/timeline.vue:
   list: "リスト"
 desktop/views/components/ui.header.vue:
   welcome-back: "おかえりなさい、"
+  adjective: "さん"
 desktop/views/components/ui.header.account.vue:
   profile: "プロフィール"
   drive: "ドライブ"
@@ -970,6 +977,7 @@ mobile/views/components/timeline.vue:
   load-more: "もっと"
 mobile/views/components/ui.header.vue:
   welcome-back: "おかえりなさい、"
+  adjective: "さん"
 mobile/views/components/ui.nav.vue:
   timeline: "タイムライン"
   notifications: "通知"
@@ -1018,6 +1026,8 @@ mobile/views/pages/welcome.vue:
 mobile/views/pages/widgets.vue:
   dashboard: "ダッシュボード"
   widgets-hints: "ウィジェットを追加/削除したり並べ替えたりできます。ウィジェットを移動するには「三」をドラッグします。ウィジェットを削除するには「x」をタップします。いくつかのウィジェットはタップすることで表示を変更できます。"
+  add-widget: "追加"
+  customization-tips: "カスタマイズのヒント"
 mobile/views/pages/widgets/activity.vue:
   activity: "アクティビティ"
 mobile/views/pages/share.vue:
@@ -1056,6 +1066,7 @@ mobile/views/pages/settings/settings.profile.vue:
 mobile/views/pages/search.vue:
   search: "検索"
   empty: "「{}」に関する投稿は見つかりませんでした。"
+  not-found: "「{}」に関する投稿は見つかりませんでした。"
 mobile/views/pages/selectdrive.vue:
   select-file: "ファイルを選択"
 mobile/views/pages/settings.vue:
@@ -1150,3 +1161,5 @@ docs:
       name: "名前"
       type: "型"
       description: "説明"
+dev/views/index.vue:
+  manage-apps: "アプリの管理"
diff --git a/locales/ru.yml b/locales/ru.yml
index 4b65a52e3f..7b2c240f0e 100644
--- a/locales/ru.yml
+++ b/locales/ru.yml
@@ -11,6 +11,7 @@ common:
     warning: "<strong>Misskeyは広告を掲載していません</strong>が、広告をブロックする機能が有効だと一部の機能が利用できなかったり、不具合が発生する場合があります。"
   application-authorization: "アプリの連携"
   close: "閉じる"
+  do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。"
   got-it: "わかった"
   customization-tips:
     title: "カスタマイズのヒント"
@@ -27,7 +28,6 @@ common:
     notified-by: "{}さんから"
     reply-from: "{}さんから返信:"
     quoted-by: "{}さんが引用:"
-  name: "Misskey"
   time:
     unknown: "なぞのじかん"
     future: "未来"
@@ -39,6 +39,7 @@ common:
     weeks_ago: "{}週間前"
     months_ago: "{}ヶ月前"
     years_ago: "{}年前"
+  month-and-day: "{month}月 {day}日"
   trash: "ゴミ箱"
   weekday-short:
     sunday: "日"
@@ -234,11 +235,13 @@ common/views/components/messaging-room.vue:
   no-history: "これより過去の履歴はありません"
   resize-form: "ドラッグしてフォームの広さを調整"
   new-message: "新しいメッセージがあります"
+  only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
 common/views/components/messaging-room.form.vue:
   input-message-here: "ここにメッセージを入力"
   send: "送信"
   attach-from-local: "PCからファイルを添付する"
   attach-from-drive: "ドライブからファイルを添付する"
+  only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
 common/views/components/messaging-room.message.vue:
   is-read: "既読"
   deleted: "このメッセージは削除されました"
@@ -534,6 +537,8 @@ desktop/views/components/notes.note.vue:
   detail: "詳細"
   private: "この投稿は非公開です"
   deleted: "この投稿は削除されました"
+  hide: "隠す"
+  see-more: "もっと見る"
 desktop/views/components/notes.vue:
   error: "読み込みに失敗しました。"
   retry: "リトライ"
@@ -569,6 +574,7 @@ desktop/views/components/post-form.vue:
   geolocation-alert: "お使いの端末は位置情報に対応していません"
   error: "エラー"
   enter-username: "ユーザー名を入力してください"
+  annotations: "内容への注釈 (オプション)"
 desktop/views/components/post-form-window.vue:
   note: "新規投稿"
   reply: "返信"
@@ -730,6 +736,7 @@ desktop/views/components/timeline.vue:
   list: "リスト"
 desktop/views/components/ui.header.vue:
   welcome-back: "おかえりなさい、"
+  adjective: "さん"
 desktop/views/components/ui.header.account.vue:
   profile: "プロフィール"
   drive: "ドライブ"
@@ -970,6 +977,7 @@ mobile/views/components/timeline.vue:
   load-more: "もっと"
 mobile/views/components/ui.header.vue:
   welcome-back: "おかえりなさい、"
+  adjective: "さん"
 mobile/views/components/ui.nav.vue:
   timeline: "タイムライン"
   notifications: "通知"
@@ -1018,6 +1026,8 @@ mobile/views/pages/welcome.vue:
 mobile/views/pages/widgets.vue:
   dashboard: "ダッシュボード"
   widgets-hints: "ウィジェットを追加/削除したり並べ替えたりできます。ウィジェットを移動するには「三」をドラッグします。ウィジェットを削除するには「x」をタップします。いくつかのウィジェットはタップすることで表示を変更できます。"
+  add-widget: "追加"
+  customization-tips: "カスタマイズのヒント"
 mobile/views/pages/widgets/activity.vue:
   activity: "アクティビティ"
 mobile/views/pages/share.vue:
@@ -1056,6 +1066,7 @@ mobile/views/pages/settings/settings.profile.vue:
 mobile/views/pages/search.vue:
   search: "検索"
   empty: "「{}」に関する投稿は見つかりませんでした。"
+  not-found: "「{}」に関する投稿は見つかりませんでした。"
 mobile/views/pages/selectdrive.vue:
   select-file: "ファイルを選択"
 mobile/views/pages/settings.vue:
@@ -1150,3 +1161,5 @@ docs:
       name: "名前"
       type: "型"
       description: "説明"
+dev/views/index.vue:
+  manage-apps: "アプリの管理"
diff --git a/locales/zh.yml b/locales/zh.yml
index 3d40531e0a..d11899b159 100644
--- a/locales/zh.yml
+++ b/locales/zh.yml
@@ -11,6 +11,7 @@ common:
     warning: "<strong>Misskeyは広告を掲載していません</strong>が、広告をブロックする機能が有効だと一部の機能が利用できなかったり、不具合が発生する場合があります。"
   application-authorization: "アプリの連携"
   close: "閉じる"
+  do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。"
   got-it: "わかった"
   customization-tips:
     title: "カスタマイズのヒント"
@@ -27,7 +28,6 @@ common:
     notified-by: "{}さんから"
     reply-from: "{}さんから返信:"
     quoted-by: "{}さんが引用:"
-  name: "Misskey"
   time:
     unknown: "なぞのじかん"
     future: "未来"
@@ -39,6 +39,7 @@ common:
     weeks_ago: "{}週間前"
     months_ago: "{}ヶ月前"
     years_ago: "{}年前"
+  month-and-day: "{month}月 {day}日"
   trash: "ゴミ箱"
   weekday-short:
     sunday: "日"
@@ -234,11 +235,13 @@ common/views/components/messaging-room.vue:
   no-history: "これより過去の履歴はありません"
   resize-form: "ドラッグしてフォームの広さを調整"
   new-message: "新しいメッセージがあります"
+  only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
 common/views/components/messaging-room.form.vue:
   input-message-here: "ここにメッセージを入力"
   send: "送信"
   attach-from-local: "PCからファイルを添付する"
   attach-from-drive: "ドライブからファイルを添付する"
+  only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
 common/views/components/messaging-room.message.vue:
   is-read: "既読"
   deleted: "このメッセージは削除されました"
@@ -534,6 +537,8 @@ desktop/views/components/notes.note.vue:
   detail: "詳細"
   private: "この投稿は非公開です"
   deleted: "この投稿は削除されました"
+  hide: "隠す"
+  see-more: "もっと見る"
 desktop/views/components/notes.vue:
   error: "読み込みに失敗しました。"
   retry: "リトライ"
@@ -569,6 +574,7 @@ desktop/views/components/post-form.vue:
   geolocation-alert: "お使いの端末は位置情報に対応していません"
   error: "エラー"
   enter-username: "ユーザー名を入力してください"
+  annotations: "内容への注釈 (オプション)"
 desktop/views/components/post-form-window.vue:
   note: "新規投稿"
   reply: "返信"
@@ -730,6 +736,7 @@ desktop/views/components/timeline.vue:
   list: "リスト"
 desktop/views/components/ui.header.vue:
   welcome-back: "おかえりなさい、"
+  adjective: "さん"
 desktop/views/components/ui.header.account.vue:
   profile: "プロフィール"
   drive: "ドライブ"
@@ -970,6 +977,7 @@ mobile/views/components/timeline.vue:
   load-more: "もっと"
 mobile/views/components/ui.header.vue:
   welcome-back: "おかえりなさい、"
+  adjective: "さん"
 mobile/views/components/ui.nav.vue:
   timeline: "タイムライン"
   notifications: "通知"
@@ -1018,6 +1026,8 @@ mobile/views/pages/welcome.vue:
 mobile/views/pages/widgets.vue:
   dashboard: "ダッシュボード"
   widgets-hints: "ウィジェットを追加/削除したり並べ替えたりできます。ウィジェットを移動するには「三」をドラッグします。ウィジェットを削除するには「x」をタップします。いくつかのウィジェットはタップすることで表示を変更できます。"
+  add-widget: "追加"
+  customization-tips: "カスタマイズのヒント"
 mobile/views/pages/widgets/activity.vue:
   activity: "アクティビティ"
 mobile/views/pages/share.vue:
@@ -1056,6 +1066,7 @@ mobile/views/pages/settings/settings.profile.vue:
 mobile/views/pages/search.vue:
   search: "検索"
   empty: "「{}」に関する投稿は見つかりませんでした。"
+  not-found: "「{}」に関する投稿は見つかりませんでした。"
 mobile/views/pages/selectdrive.vue:
   select-file: "ファイルを選択"
 mobile/views/pages/settings.vue:
@@ -1150,3 +1161,5 @@ docs:
       name: "名前"
       type: "型"
       description: "説明"
+dev/views/index.vue:
+  manage-apps: "アプリの管理"

From 01d3f5f09ddc13b063e820b48df271b9521d1a58 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Thu, 9 Aug 2018 04:35:17 +0900
Subject: [PATCH 82/94] 5.20.0

---
 package.json | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 5a83cc3361..5fdfe57c5e 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "5.19.0",
-	"clientVersion": "1.0.8052",
+	"version": "5.20.0",
+	"clientVersion": "1.0.8099",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,

From 52286f4be81e571fd7f76ae35abc59d8153a4eb7 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Fri, 10 Aug 2018 00:25:16 +0900
Subject: [PATCH 83/94] fix(package): update summaly to version 2.1.0 (#2132)

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 5fdfe57c5e..daec55efe2 100644
--- a/package.json
+++ b/package.json
@@ -187,7 +187,7 @@
 		"style-loader": "0.22.1",
 		"stylus": "0.54.5",
 		"stylus-loader": "3.0.2",
-		"summaly": "2.0.6",
+		"summaly": "2.1.0",
 		"systeminformation": "3.42.9",
 		"syuilo-password-strength": "0.0.1",
 		"textarea-caret": "3.1.0",

From 1affdbdbab84c99903f1acb3796b8cc181ae3c96 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Fri, 10 Aug 2018 00:25:25 +0900
Subject: [PATCH 84/94] fix(package): update node-sass to version 4.9.3 (#2131)

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index daec55efe2..21b7e3c5c9 100644
--- a/package.json
+++ b/package.json
@@ -154,7 +154,7 @@
 		"monk": "6.0.6",
 		"ms": "2.1.1",
 		"nan": "2.10.0",
-		"node-sass": "4.9.2",
+		"node-sass": "4.9.3",
 		"node-sass-json-importer": "3.3.1",
 		"nprogress": "0.2.0",
 		"object-assign-deep": "0.4.0",

From 454d294cf3f1b2ad414469e7282209fd0c4ab384 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Fri, 10 Aug 2018 00:51:40 +0900
Subject: [PATCH 85/94] =?UTF-8?q?Fix=20#2133=20=E3=81=AA=E3=81=A9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/client/app/common/views/components/avatar.vue | 15 +++++++++++++--
 src/client/app/desktop/views/widgets/profile.vue  |  5 +++--
 2 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/src/client/app/common/views/components/avatar.vue b/src/client/app/common/views/components/avatar.vue
index a924b62e64..6685296c16 100644
--- a/src/client/app/common/views/components/avatar.vue
+++ b/src/client/app/common/views/components/avatar.vue
@@ -1,6 +1,8 @@
 <template>
-	<router-link class="mk-avatar" :to="user | userPage" :title="user | acct" :target="target" :style="style" v-if="disablePreview"></router-link>
-	<router-link class="mk-avatar" :to="user | userPage" :title="user | acct" :target="target" :style="style" v-else v-user-preview="user.id"></router-link>
+	<span class="mk-avatar" :title="user | acct" :style="style" v-if="disableLink && !disablePreview" v-user-preview="user.id" @click="onClick"></span>
+	<span class="mk-avatar" :title="user | acct" :style="style" v-else-if="disableLink && disablePreview" @click="onClick"></span>
+	<router-link class="mk-avatar" :to="user | userPage" :title="user | acct" :target="target" :style="style" v-else-if="!disableLink && !disablePreview" v-user-preview="user.id"></router-link>
+	<router-link class="mk-avatar" :to="user | userPage" :title="user | acct" :target="target" :style="style" v-else-if="!disableLink && disablePreview"></router-link>
 </template>
 
 <script lang="ts">
@@ -15,6 +17,10 @@ export default Vue.extend({
 			required: false,
 			default: null
 		},
+		disableLink: {
+			required: false,
+			default: false
+		},
 		disablePreview: {
 			required: false,
 			default: false
@@ -35,6 +41,11 @@ export default Vue.extend({
 				borderRadius: this.$store.state.settings.circleIcons ? '100%' : null
 			};
 		}
+	},
+	methods: {
+		onClick(e) {
+			this.$emit('click', e);
+		}
 	}
 });
 </script>
diff --git a/src/client/app/desktop/views/widgets/profile.vue b/src/client/app/desktop/views/widgets/profile.vue
index 9702aaa90a..a22607b612 100644
--- a/src/client/app/desktop/views/widgets/profile.vue
+++ b/src/client/app/desktop/views/widgets/profile.vue
@@ -6,10 +6,11 @@
 	<div class="banner"
 		:style="$store.state.i.bannerUrl ? `background-image: url(${$store.state.i.bannerUrl})` : ''"
 		title="%i18n:@update-banner%"
-		@click="os.apis.updateBanner"
+		@click="() => os.apis.updateBanner()"
 	></div>
 	<mk-avatar class="avatar" :user="$store.state.i"
-		@click="os.apis.updateAvatar"
+		:disable-link="true"
+		@click="() => os.apis.updateAvatar()"
 		title="%i18n:@update-avatar%"
 	/>
 	<router-link class="name" :to="$store.state.i | userPage">{{ $store.state.i | userName }}</router-link>

From 7f65f896f91b46b347719ebbba5249fae6caed90 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Fri, 10 Aug 2018 01:02:20 +0900
Subject: [PATCH 86/94] fix(package): update summaly to version 2.1.1 (#2135)

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 21b7e3c5c9..ad25c9c44d 100644
--- a/package.json
+++ b/package.json
@@ -187,7 +187,7 @@
 		"style-loader": "0.22.1",
 		"stylus": "0.54.5",
 		"stylus-loader": "3.0.2",
-		"summaly": "2.1.0",
+		"summaly": "2.1.1",
 		"systeminformation": "3.42.9",
 		"syuilo-password-strength": "0.0.1",
 		"textarea-caret": "3.1.0",

From 2c11cc3f0aac9427000a54e00d7b5baf8edc0fee Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Fri, 10 Aug 2018 01:04:40 +0900
Subject: [PATCH 87/94] 5.20.1

---
 package.json | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index ad25c9c44d..ab5ae1dd92 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "5.20.0",
-	"clientVersion": "1.0.8099",
+	"version": "5.20.1",
+	"clientVersion": "1.0.8105",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,

From 6372451d176c7d780d587142edf9645fef53576c Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Fri, 10 Aug 2018 14:15:12 +0900
Subject: [PATCH 88/94] Fix bug

---
 src/queue/processors/http/deliver.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/queue/processors/http/deliver.ts b/src/queue/processors/http/deliver.ts
index 75e46559dd..e14a162105 100644
--- a/src/queue/processors/http/deliver.ts
+++ b/src/queue/processors/http/deliver.ts
@@ -7,7 +7,7 @@ export default async (job: bq.Job, done: any): Promise<void> => {
 		await request(job.data.user, job.data.to, job.data.content);
 		done();
 	} catch (res) {
-		if (!res.hasOwnProperty('statusCode')) {
+		if (res == null || !res.hasOwnProperty('statusCode')) {
 			console.warn(`deliver failed (unknown): ${res}`);
 			return done();
 		}

From ab7725ff6912bf1fe8473d4c1f0b101a4ad086a7 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Fri, 10 Aug 2018 14:33:34 +0900
Subject: [PATCH 89/94] =?UTF-8?q?=E8=89=AF=E3=81=84=E6=84=9F=E3=81=98?=
 =?UTF-8?q?=E3=81=AB=E3=81=97=E3=81=9F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/models/drive-file.ts       |  2 +-
 src/services/drive/add-file.ts | 39 +++++++++++++++++++++++++---------
 2 files changed, 30 insertions(+), 11 deletions(-)

diff --git a/src/models/drive-file.ts b/src/models/drive-file.ts
index 33c0451905..ad5496d7ca 100644
--- a/src/models/drive-file.ts
+++ b/src/models/drive-file.ts
@@ -10,7 +10,7 @@ import DriveFileThumbnail, { deleteDriveFileThumbnail } from './drive-file-thumb
 
 const DriveFile = monkDb.get<IDriveFile>('driveFiles.files');
 DriveFile.createIndex('md5');
-DriveFile.createIndex('metadata.uri', { sparse: true, unique: true });
+DriveFile.createIndex(['metadata.uri', 'metadata.userId'], { sparse: true, unique: true });
 export default DriveFile;
 
 export const DriveFileChunk = monkDb.get('driveFiles.chunks');
diff --git a/src/services/drive/add-file.ts b/src/services/drive/add-file.ts
index a04bab9dbd..701d547776 100644
--- a/src/services/drive/add-file.ts
+++ b/src/services/drive/add-file.ts
@@ -294,16 +294,35 @@ export default async function(
 		metadata.uri = uri;
 	}
 
-	const driveFile = isLink
-		? await DriveFile.insert({
-			length: 0,
-			uploadDate: new Date(),
-			md5: hash,
-			filename: detectedName,
-			metadata: metadata,
-			contentType: mime
-		})
-		: await (save(fs.createReadStream(path), detectedName, mime, hash, size, metadata));
+	let driveFile: IDriveFile;
+
+	if (isLink) {
+		try {
+			driveFile = await DriveFile.insert({
+				length: 0,
+				uploadDate: new Date(),
+				md5: hash,
+				filename: detectedName,
+				metadata: metadata,
+				contentType: mime
+			});
+		} catch (e) {
+			// duplicate key error (when already registered)
+			if (e.code === 11000) {
+				log(`already registered ${metadata.uri}`);
+
+				driveFile = await DriveFile.findOne({
+					'metadata.uri': metadata.uri,
+					'metadata.userId': user._id
+				});
+			} else {
+				console.error(e);
+				throw e;
+			}
+		}
+	} else {
+		driveFile = await (save(fs.createReadStream(path), detectedName, mime, hash, size, metadata));
+	}
 
 	log(`drive file has been created ${driveFile._id}`);
 

From 3d10b19727418c06b78804a444e202c9704f48c8 Mon Sep 17 00:00:00 2001
From: MeiMei <30769358+mei23@users.noreply.github.com>
Date: Fri, 10 Aug 2018 20:11:54 +0900
Subject: [PATCH 90/94] Fix Powered by <b>Misskey</b>. (#2140)

---
 src/client/app/desktop/views/pages/welcome.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/client/app/desktop/views/pages/welcome.vue b/src/client/app/desktop/views/pages/welcome.vue
index a01b44fc73..585a23de2d 100644
--- a/src/client/app/desktop/views/pages/welcome.vue
+++ b/src/client/app/desktop/views/pages/welcome.vue
@@ -18,7 +18,7 @@
 				<div class="about">
 					<h1 v-if="name != 'Misskey'">{{ name }}</h1>
 					<h1 v-else><img :src="$store.state.device.darkmode ? 'assets/title.dark.svg' : 'assets/title.light.svg'" :alt="name"></h1>
-					<p class="powerd-by" v-if="name != 'Misskey'">%i18n:@powered-by-misskey%</p>
+					<p class="powerd-by" v-if="name != 'Misskey'" v-html="'%i18n:@powered-by-misskey%'"></p>
 					<p class="desc" v-html="description || '%i18n:common.about%'"></p>
 					<a ref="signup" @click="signup">📦 %i18n:@signup%</a>
 				</div>

From 9658e2b3fbaf1da296e3836c09efb17d1813cc4e Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Fri, 10 Aug 2018 09:30:48 +0000
Subject: [PATCH 91/94] fix(package): update element-ui to version 2.4.6

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index ab5ae1dd92..1058ca52aa 100644
--- a/package.json
+++ b/package.json
@@ -98,7 +98,7 @@
 		"diskusage": "0.2.4",
 		"dompurify": "1.0.5",
 		"elasticsearch": "15.1.1",
-		"element-ui": "2.4.5",
+		"element-ui": "2.4.6",
 		"emojilib": "2.3.0",
 		"escape-regexp": "0.0.1",
 		"eslint": "5.0.1",

From fbbd33ded25803bd5ee791f55701eb795014e0f2 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Fri, 10 Aug 2018 07:42:57 +0000
Subject: [PATCH 92/94] fix(package): update file-type to version 9.0.0

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 1058ca52aa..dffa8c608e 100644
--- a/package.json
+++ b/package.json
@@ -106,7 +106,7 @@
 		"eventemitter3": "3.1.0",
 		"exif-js": "2.3.0",
 		"file-loader": "1.1.11",
-		"file-type": "8.1.0",
+		"file-type": "9.0.0",
 		"fuckadblock": "3.2.1",
 		"gulp": "3.9.1",
 		"gulp-cssnano": "2.1.3",

From a1f0cb1bc76761b946be60fc39334799dce913c7 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Sat, 11 Aug 2018 00:44:26 +0900
Subject: [PATCH 93/94] fix(package): update summaly to version 2.1.2 (#2149)

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index dffa8c608e..64f9b577a4 100644
--- a/package.json
+++ b/package.json
@@ -187,7 +187,7 @@
 		"style-loader": "0.22.1",
 		"stylus": "0.54.5",
 		"stylus-loader": "3.0.2",
-		"summaly": "2.1.1",
+		"summaly": "2.1.2",
 		"systeminformation": "3.42.9",
 		"syuilo-password-strength": "0.0.1",
 		"textarea-caret": "3.1.0",

From fa469725c781f6c699ead5d271dffd1bb30bf64e Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 11 Aug 2018 00:49:29 +0900
Subject: [PATCH 94/94] Add doc

---
 src/docs/api/entities/drive-folder.yaml | 41 +++++++++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 src/docs/api/entities/drive-folder.yaml

diff --git a/src/docs/api/entities/drive-folder.yaml b/src/docs/api/entities/drive-folder.yaml
new file mode 100644
index 0000000000..0fb8308dd4
--- /dev/null
+++ b/src/docs/api/entities/drive-folder.yaml
@@ -0,0 +1,41 @@
+name: "DriveFolder"
+
+desc:
+  ja: "ドライブのフォルダを表します。"
+  en: "A folder of Drive."
+
+props:
+  id:
+    type: "id"
+    optional: false
+    desc:
+      ja: "フォルダID"
+      en: "The ID of this folder"
+
+  createdAt:
+    type: "date"
+    optional: false
+    desc:
+      ja: "作成日時"
+      en: "The created date of this folder"
+
+  userId:
+    type: "id(User)"
+    optional: false
+    desc:
+      ja: "所有者ID"
+      en: "The ID of the owner of this folder"
+
+  parentId:
+    type: "entity(DriveFolder)"
+    optional: false
+    desc:
+      ja: "親フォルダのID (ルートなら null)"
+      en: "The ID of parent folder"
+
+  name:
+    type: "string"
+    optional: false
+    desc:
+      ja: "フォルダ名"
+      en: "The name of this folder"