From b07911ec686a00c2fa82e4dd328dba8ae3aebea1 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Tue, 19 Jun 2018 07:56:26 +0900
Subject: [PATCH 01/90] Fix

---
 src/server/api/index.ts | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/server/api/index.ts b/src/server/api/index.ts
index c39911c35f..004c21b821 100644
--- a/src/server/api/index.ts
+++ b/src/server/api/index.ts
@@ -45,7 +45,6 @@ router.post('/signin', require('./private/signin').default);
 
 router.use(require('./service/github').routes());
 router.use(require('./service/twitter').routes());
-router.use(require('./bot/interfaces/line').routes());
 
 // Register router
 app.use(router.routes());

From 01ff8d171a86622a35572aa8264b9860fca7a841 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Tue, 19 Jun 2018 08:03:00 +0900
Subject: [PATCH 02/90] Fix bug

---
 src/remote/activitypub/renderer/note.ts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/remote/activitypub/renderer/note.ts b/src/remote/activitypub/renderer/note.ts
index b908f8bb1e..7cee2be22c 100644
--- a/src/remote/activitypub/renderer/note.ts
+++ b/src/remote/activitypub/renderer/note.ts
@@ -54,11 +54,11 @@ export default async function renderNote(note: INote, dive = true): Promise<any>
 		? [`${attributedTo}/followers`].concat(mentions)
 		: [];
 
-	const mentionedUsers = await User.find({
+	const mentionedUsers = note.mentions ? await User.find({
 		_id: {
 			$in: note.mentions
 		}
-	});
+	}) : [];
 
 	const hashtagTags = (note.tags || []).map(tag => renderHashtag(tag));
 	const mentionTags = mentionedUsers.map(u => renderMention(u));

From 127c126ef55db9c9ce550cc94341f218d5c83604 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Tue, 19 Jun 2018 08:03:39 +0900
Subject: [PATCH 03/90] 4.3.1

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

diff --git a/package.json b/package.json
index 9961782c9d..02a3a52a96 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "4.3.0",
+	"version": "4.3.1",
 	"clientVersion": "1.0.6630",
 	"codename": "nighthike",
 	"main": "./built/index.js",

From 2e22bd2ecf1972ec46fef888d0f2b9c72d6f682a Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Tue, 19 Jun 2018 19:07:39 +0900
Subject: [PATCH 04/90] Update manifest.json

---
 src/client/assets/manifest.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/client/assets/manifest.json b/src/client/assets/manifest.json
index dcd1e26790..bae0ee7f1d 100644
--- a/src/client/assets/manifest.json
+++ b/src/client/assets/manifest.json
@@ -37,6 +37,6 @@
 		}
 	],
 	"share_target": {
-		"url_template": "share?text={title}%20-%20{text}%20-%20{url}"
+		"url_template": "share?text=【{title}】%0A{text}%0A{url}"
 	}
 }

From 2458255e2244944b24cd90101e9fa00d07e35a1d Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Wed, 20 Jun 2018 19:55:34 +0900
Subject: [PATCH 05/90] nanka iroiro

---
 .../app/common/views/components/index.ts      |   4 +-
 .../components/messaging-room.message.vue     |   2 +-
 ...e-html.ts => misskey-flavored-markdown.ts} |   2 +-
 .../views/components/welcome-timeline.vue     |   2 +-
 .../desktop/views/components/note-detail.vue  |   2 +-
 .../desktop/views/components/notes.note.vue   |   2 +-
 .../views/components/sub-note-content.vue     |   2 +-
 .../desktop/views/pages/deck/deck.note.vue    |   2 +-
 .../desktop/views/pages/user/user.header.vue  |  95 +++++-----------
 .../desktop/views/pages/user/user.home.vue    | 103 ------------------
 .../desktop/views/pages/user/user.profile.vue |  16 +--
 .../app/desktop/views/pages/user/user.vue     |  88 +++++++++++++--
 .../mobile/views/components/note-detail.vue   |   2 +-
 .../app/mobile/views/components/note.vue      |   2 +-
 .../views/components/sub-note-content.vue     |   2 +-
 src/client/app/mobile/views/pages/user.vue    |   4 +-
 16 files changed, 130 insertions(+), 200 deletions(-)
 rename src/client/app/common/views/components/{note-html.ts => misskey-flavored-markdown.ts} (98%)
 delete mode 100644 src/client/app/desktop/views/pages/user/user.home.vue

diff --git a/src/client/app/common/views/components/index.ts b/src/client/app/common/views/components/index.ts
index 5b2fa084fb..e2cba2e53b 100644
--- a/src/client/app/common/views/components/index.ts
+++ b/src/client/app/common/views/components/index.ts
@@ -9,7 +9,7 @@ import forkit from './forkit.vue';
 import acct from './acct.vue';
 import avatar from './avatar.vue';
 import nav from './nav.vue';
-import noteHtml from './note-html';
+import misskeyFlavoredMarkdown from './misskey-flavored-markdown';
 import poll from './poll.vue';
 import pollEditor from './poll-editor.vue';
 import reactionIcon from './reaction-icon.vue';
@@ -47,7 +47,7 @@ Vue.component('mk-forkit', forkit);
 Vue.component('mk-acct', acct);
 Vue.component('mk-avatar', avatar);
 Vue.component('mk-nav', nav);
-Vue.component('mk-note-html', noteHtml);
+Vue.component('misskey-flavored-markdown', misskeyFlavoredMarkdown);
 Vue.component('mk-poll', poll);
 Vue.component('mk-poll-editor', pollEditor);
 Vue.component('mk-reaction-icon', reactionIcon);
diff --git a/src/client/app/common/views/components/messaging-room.message.vue b/src/client/app/common/views/components/messaging-room.message.vue
index a77b5f3658..d7e7c6dcb5 100644
--- a/src/client/app/common/views/components/messaging-room.message.vue
+++ b/src/client/app/common/views/components/messaging-room.message.vue
@@ -8,7 +8,7 @@
 				<img src="/assets/desktop/messaging/delete.png" alt="Delete"/>
 			</button>
 			<div class="content" v-if="!message.isDeleted">
-				<mk-note-html class="text" v-if="message.text" ref="text" :text="message.text" :i="$store.state.i"/>
+				<misskey-flavored-markdown class="text" v-if="message.text" ref="text" :text="message.text" :i="$store.state.i"/>
 				<div class="file" v-if="message.file">
 					<a :href="message.file.url" target="_blank" :title="message.file.name">
 						<img v-if="message.file.type.split('/')[0] == 'image'" :src="message.file.url" :alt="message.file.name"/>
diff --git a/src/client/app/common/views/components/note-html.ts b/src/client/app/common/views/components/misskey-flavored-markdown.ts
similarity index 98%
rename from src/client/app/common/views/components/note-html.ts
rename to src/client/app/common/views/components/misskey-flavored-markdown.ts
index 8fa5f380dd..61dbc02d9a 100644
--- a/src/client/app/common/views/components/note-html.ts
+++ b/src/client/app/common/views/components/misskey-flavored-markdown.ts
@@ -10,7 +10,7 @@ const flatten = list => list.reduce(
 	(a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []
 );
 
-export default Vue.component('mk-note-html', {
+export default Vue.component('misskey-flavored-markdown', {
 	props: {
 		text: {
 			type: String,
diff --git a/src/client/app/common/views/components/welcome-timeline.vue b/src/client/app/common/views/components/welcome-timeline.vue
index f3372bf062..bf2c653766 100644
--- a/src/client/app/common/views/components/welcome-timeline.vue
+++ b/src/client/app/common/views/components/welcome-timeline.vue
@@ -13,7 +13,7 @@
 				</div>
 			</header>
 			<div class="text">
-				<mk-note-html v-if="note.text" :text="note.text"/>
+				<misskey-flavored-markdown v-if="note.text" :text="note.text"/>
 			</div>
 		</div>
 	</div>
diff --git a/src/client/app/desktop/views/components/note-detail.vue b/src/client/app/desktop/views/components/note-detail.vue
index 4b5e5bebdf..017f599e31 100644
--- a/src/client/app/desktop/views/components/note-detail.vue
+++ b/src/client/app/desktop/views/components/note-detail.vue
@@ -40,7 +40,7 @@
 			<div class="text">
 				<span v-if="p.isHidden" style="opacity: 0.5">%i18n:@private%</span>
 				<span v-if="p.deletedAt" style="opacity: 0.5">%i18n:@deleted%</span>
-				<mk-note-html v-if="p.text" :text="p.text" :i="$store.state.i"/>
+				<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i"/>
 			</div>
 			<div class="media" v-if="p.media.length > 0">
 				<mk-media-list :media-list="p.media" :raw="true"/>
diff --git a/src/client/app/desktop/views/components/notes.note.vue b/src/client/app/desktop/views/components/notes.note.vue
index ee11fcc55f..661223ee25 100644
--- a/src/client/app/desktop/views/components/notes.note.vue
+++ b/src/client/app/desktop/views/components/notes.note.vue
@@ -25,7 +25,7 @@
 						<span v-if="p.isHidden" style="opacity: 0.5">%i18n:@private%</span>
 						<span v-if="p.deletedAt" style="opacity: 0.5">%i18n:@deleted%</span>
 						<a class="reply" v-if="p.reply">%fa:reply%</a>
-						<mk-note-html v-if="p.text && !canHideText(p)" :text="p.text" :i="$store.state.i" :class="$style.text"/>
+						<misskey-flavored-markdown v-if="p.text && !canHideText(p)" :text="p.text" :i="$store.state.i" :class="$style.text"/>
 						<a class="rp" v-if="p.renote">RP:</a>
 					</div>
 					<div class="media" v-if="p.media.length > 0">
diff --git a/src/client/app/desktop/views/components/sub-note-content.vue b/src/client/app/desktop/views/components/sub-note-content.vue
index 45ce6a6f8f..cb0374b910 100644
--- a/src/client/app/desktop/views/components/sub-note-content.vue
+++ b/src/client/app/desktop/views/components/sub-note-content.vue
@@ -4,7 +4,7 @@
 		<span v-if="note.isHidden" style="opacity: 0.5">%i18n:@private%</span>
 		<span v-if="note.deletedAt" style="opacity: 0.5">%i18n:@deleted%</span>
 		<a class="reply" v-if="note.replyId">%fa:reply%</a>
-		<mk-note-html v-if="note.text" :text="note.text" :i="$store.state.i"/>
+		<misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i"/>
 		<a class="rp" v-if="note.renoteId" :href="`/notes/${note.renoteId}`">RP: ...</a>
 	</div>
 	<details v-if="note.media.length > 0">
diff --git a/src/client/app/desktop/views/pages/deck/deck.note.vue b/src/client/app/desktop/views/pages/deck/deck.note.vue
index 5a8dc2ea65..067297af37 100644
--- a/src/client/app/desktop/views/pages/deck/deck.note.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.note.vue
@@ -25,7 +25,7 @@
 						<span v-if="p.isHidden" style="opacity: 0.5">(%i18n:@private%)</span>
 						<span v-if="p.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span>
 						<a class="reply" v-if="p.reply">%fa:reply%</a>
-						<mk-note-html v-if="p.text && !canHideText(p)" :text="p.text" :i="$store.state.i"/>
+						<misskey-flavored-markdown v-if="p.text && !canHideText(p)" :text="p.text" :i="$store.state.i"/>
 						<a class="rp" v-if="p.renote != null">RP:</a>
 					</div>
 					<div class="media" v-if="p.media.length > 0">
diff --git a/src/client/app/desktop/views/pages/user/user.header.vue b/src/client/app/desktop/views/pages/user/user.header.vue
index d52c6b762c..d0976a32e1 100644
--- a/src/client/app/desktop/views/pages/user/user.header.vue
+++ b/src/client/app/desktop/views/pages/user/user.header.vue
@@ -5,17 +5,15 @@
 	<div class="banner-container" :style="style">
 		<div class="banner" ref="banner" :style="style" @click="onBannerClick"></div>
 		<div class="fade"></div>
-	</div>
-	<div class="container">
-		<mk-avatar class="avatar" :user="user" :disable-preview="true"/>
 		<div class="title">
 			<p class="name">{{ user | userName }}</p>
 			<p class="username"><mk-acct :user="user"/></p>
 			<p class="location" v-if="user.host === null && user.profile.location">%fa:map-marker%{{ user.profile.location }}</p>
 		</div>
-		<footer>
-			<router-link :to="user | userPage" :data-active="$parent.page == 'home'">%fa:home%ホーム</router-link>
-		</footer>
+	</div>
+	<mk-avatar class="avatar" :user="user" :disable-preview="true"/>
+	<div class="body">
+		<misskey-flavored-markdown v-if="user.description" :text="user.description" :i="$store.state.i"/>
 	</div>
 </div>
 </template>
@@ -76,12 +74,11 @@ export default Vue.extend({
 <style lang="stylus" scoped>
 @import '~const.styl'
 
-.header
-	$footer-height = 58px
-
+root(isDark)
+	background isDark ? #282C37 : #fff
+	border 1px solid rgba(#000, 0.075)
+	border-radius 6px
 	overflow hidden
-	background #f7f7f7
-	box-shadow 0 1px 1px rgba(#000, 0.075)
 
 	> .is-suspended
 	> .is-remote
@@ -110,7 +107,6 @@ export default Vue.extend({
 			> .fade
 				background linear-gradient(transparent, rgba(#000, 0.7))
 
-		> .container
 			> .title
 				color #fff
 
@@ -118,7 +114,7 @@ export default Vue.extend({
 					text-shadow 0 0 8px #000
 
 	> .banner-container
-		height 320px
+		height 250px
 		overflow hidden
 		background-size cover
 		background-position center
@@ -136,37 +132,21 @@ export default Vue.extend({
 			width 100%
 			height 78px
 
-	> .container
-		max-width 1200px
-		margin 0 auto
-
-		> .avatar
-			display block
-			position absolute
-			bottom 16px
-			left 16px
-			z-index 2
-			width 160px
-			height 160px
-			border solid 3px #fff
-			border-radius 8px
-			box-shadow 1px 1px 3px rgba(#000, 0.2)
-
 		> .title
 			position absolute
-			bottom $footer-height
+			bottom 0
 			left 0
 			width 100%
-			padding 0 0 8px 195px
+			padding 0 0 8px 154px
 			color #5e6367
 			font-family '游ゴシック', 'YuGothic', 'ヒラギノ角ゴ ProN W3', 'Hiragino Kaku Gothic ProN', 'Meiryo', 'メイリオ', sans-serif
 
 			> .name
 				display block
 				margin 0
-				line-height 40px
+				line-height 32px
 				font-weight bold
-				font-size 2em
+				font-size 1.8em
 
 			> .username
 			> .location
@@ -178,41 +158,24 @@ export default Vue.extend({
 				> i
 					margin-right 4px
 
-		> footer
-			z-index 1
-			height $footer-height
-			padding-left 195px
+	> .avatar
+		display block
+		position absolute
+		top 170px
+		left 16px
+		z-index 2
+		width 120px
+		height 120px
+		box-shadow 1px 1px 3px rgba(#000, 0.2)
 
-			> a
-				display inline-block
-				margin 0
-				padding 0 16px
-				height $footer-height
-				line-height $footer-height
-				color #555
+	> .body
+		padding 16px 16px 16px 154px
+		color isDark ? #c5ced6 : #555
 
-				&[data-active]
-					border-bottom solid 4px $theme-color
+.header[data-darkmode]
+	root(true)
 
-				> i
-					margin-right 6px
-
-			> button
-				display block
-				position absolute
-				top 0
-				right 0
-				margin 8px
-				padding 0
-				width $footer-height - 16px
-				line-height $footer-height - 16px - 2px
-				font-size 1.2em
-				color #777
-				border solid 1px #eee
-				border-radius 4px
-
-				&:hover
-					color #555
-					border solid 1px #ddd
+.header:not([data-darkmode])
+	root(false)
 
 </style>
diff --git a/src/client/app/desktop/views/pages/user/user.home.vue b/src/client/app/desktop/views/pages/user/user.home.vue
deleted file mode 100644
index afaf97dc9e..0000000000
--- a/src/client/app/desktop/views/pages/user/user.home.vue
+++ /dev/null
@@ -1,103 +0,0 @@
-<template>
-<div class="home">
-	<div>
-		<div ref="left">
-			<x-profile :user="user"/>
-			<x-photos :user="user"/>
-			<x-followers-you-know v-if="$store.getters.isSignedIn && $store.state.i.id != user.id" :user="user"/>
-			<p v-if="user.host === null">%i18n:@last-used-at%: <b><mk-time :time="user.lastUsedAt"/></b></p>
-		</div>
-	</div>
-	<main>
-		<mk-note-detail v-if="user.pinnedNote" :note="user.pinnedNote" :compact="true"/>
-		<x-timeline class="timeline" ref="tl" :user="user"/>
-	</main>
-	<div>
-		<div ref="right">
-			<mk-calendar @chosen="warp" :start="new Date(user.createdAt)"/>
-			<mk-activity :user="user"/>
-			<x-friends :user="user"/>
-			<div class="nav"><mk-nav/></div>
-		</div>
-	</div>
-</div>
-</template>
-
-<script lang="ts">
-import Vue from 'vue';
-import XTimeline from './user.timeline.vue';
-import XProfile from './user.profile.vue';
-import XPhotos from './user.photos.vue';
-import XFollowersYouKnow from './user.followers-you-know.vue';
-import XFriends from './user.friends.vue';
-
-export default Vue.extend({
-	components: {
-		XTimeline,
-		XProfile,
-		XPhotos,
-		XFollowersYouKnow,
-		XFriends
-	},
-	props: ['user'],
-	methods: {
-		warp(date) {
-			(this.$refs.tl as any).warp(date);
-		}
-	}
-});
-</script>
-
-<style lang="stylus" scoped>
-.home
-	display flex
-	justify-content center
-	margin 0 auto
-	max-width 1200px
-
-	> main
-	> div > div
-		> *:not(:last-child)
-			margin-bottom 16px
-
-	> main
-		padding 16px
-		width calc(100% - 275px * 2)
-
-		> .timeline
-			border solid 1px rgba(#000, 0.075)
-			border-radius 6px
-
-	> div
-		width 275px
-		margin 0
-
-		&:first-child > div
-			padding 16px 0 16px 16px
-
-			> p
-				display block
-				margin 0
-				padding 0 12px
-				text-align center
-				font-size 0.8em
-				color #aaa
-
-		&:last-child > div
-			padding 16px 16px 16px 0
-
-			> .nav
-				padding 16px
-				font-size 12px
-				color #aaa
-				background #fff
-				border solid 1px rgba(#000, 0.075)
-				border-radius 6px
-
-				a
-					color #999
-
-				i
-					color #ccc
-
-</style>
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 5aa08f7c85..8afa7122b3 100644
--- a/src/client/app/desktop/views/pages/user/user.profile.vue
+++ b/src/client/app/desktop/views/pages/user/user.profile.vue
@@ -15,7 +15,6 @@
 		</button>
 		<button class="mute ui" @click="list">%fa:list% リストに追加</button>
 	</div>
-	<div class="description" v-if="user.description">{{ user.description }}</div>
 	<div class="birthday" v-if="user.host === null && user.profile.birthday">
 		<p>%fa:birthday-cake%{{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ age }}歳)</p>
 	</div>
@@ -116,8 +115,8 @@ export default Vue.extend({
 </script>
 
 <style lang="stylus" scoped>
-.profile
-	background #fff
+root(isDark)
+	background isDark ? #282C37 : #fff
 	border solid 1px rgba(#000, 0.075)
 	border-radius 6px
 
@@ -153,11 +152,6 @@ export default Vue.extend({
 			&:not(:last-child)
 				margin-bottom 12px
 
-	> .description
-		padding 16px
-		color #555
-		border-top solid 1px #eee
-
 	> .birthday
 		padding 16px
 		color #555
@@ -192,4 +186,10 @@ export default Vue.extend({
 				margin-left 8px
 				margin-right 8px
 
+.profile[data-darkmode]
+	root(true)
+
+.profile:not([data-darkmode])
+	root(false)
+
 </style>
diff --git a/src/client/app/desktop/views/pages/user/user.vue b/src/client/app/desktop/views/pages/user/user.vue
index 3644286fbc..3741629b72 100644
--- a/src/client/app/desktop/views/pages/user/user.vue
+++ b/src/client/app/desktop/views/pages/user/user.vue
@@ -1,8 +1,21 @@
 <template>
 <mk-ui>
-	<div class="user" v-if="!fetching">
-		<x-header :user="user"/>
-		<x-home v-if="page == 'home'" :user="user"/>
+	<div class="zwwan0di1v4356rmdbjmwnn32tptpdp2" v-if="!fetching">
+		<div class="main">
+			<x-header :user="user"/>
+			<mk-note-detail v-if="user.pinnedNote" :note="user.pinnedNote" :compact="true"/>
+			<x-timeline class="timeline" ref="tl" :user="user"/>
+		</div>
+		<div class="side">
+			<x-profile :user="user"/>
+			<mk-calendar @chosen="warp" :start="new Date(user.createdAt)"/>
+			<mk-activity :user="user"/>
+			<x-photos :user="user"/>
+			<x-friends :user="user"/>
+			<x-followers-you-know v-if="$store.getters.isSignedIn && $store.state.i.id != user.id" :user="user"/>
+			<div class="nav"><mk-nav/></div>
+			<p v-if="user.host === null">%i18n:@last-used-at%: <b><mk-time :time="user.lastUsedAt"/></b></p>
+		</div>
 	</div>
 </mk-ui>
 </template>
@@ -13,17 +26,20 @@ import parseAcct from '../../../../../../acct/parse';
 import getUserName from '../../../../../../renderers/get-user-name';
 import Progress from '../../../../common/scripts/loading';
 import XHeader from './user.header.vue';
-import XHome from './user.home.vue';
+import XTimeline from './user.timeline.vue';
+import XProfile from './user.profile.vue';
+import XPhotos from './user.photos.vue';
+import XFollowersYouKnow from './user.followers-you-know.vue';
+import XFriends from './user.friends.vue';
 
 export default Vue.extend({
 	components: {
 		XHeader,
-		XHome
-	},
-	props: {
-		page: {
-			default: 'home'
-		}
+		XTimeline,
+		XProfile,
+		XPhotos,
+		XFollowersYouKnow,
+		XFriends
 	},
 	data() {
 		return {
@@ -47,8 +63,60 @@ export default Vue.extend({
 				Progress.done();
 				document.title = getUserName(this.user) + ' | Misskey';
 			});
+		},
+
+		warp(date) {
+			(this.$refs.tl as any).warp(date);
 		}
 	}
 });
 </script>
 
+<style lang="stylus" scoped>
+.zwwan0di1v4356rmdbjmwnn32tptpdp2
+	display flex
+	justify-content center
+	width 980px
+	padding 16px
+	margin 0 auto
+
+	> .main
+	> .side
+		> *:not(:last-child)
+			margin-bottom 16px
+
+	> .main
+		flex 1
+		margin-right 16px
+
+		> .timeline
+			border 1px solid rgba(#000, 0.075)
+			border-radius 6px
+
+	> .side
+		width 275px
+
+		> p
+			display block
+			margin 0
+			padding 0 12px
+			text-align center
+			font-size 0.8em
+			color #aaa
+
+		> .nav
+			padding 16px
+			font-size 12px
+			color #aaa
+			background #fff
+			border solid 1px rgba(#000, 0.075)
+			border-radius 6px
+
+			a
+				color #999
+
+			i
+				color #ccc
+
+
+</style>
diff --git a/src/client/app/mobile/views/components/note-detail.vue b/src/client/app/mobile/views/components/note-detail.vue
index f3e77d7062..6499f78f1b 100644
--- a/src/client/app/mobile/views/components/note-detail.vue
+++ b/src/client/app/mobile/views/components/note-detail.vue
@@ -38,7 +38,7 @@
 			<div class="text">
 				<span v-if="p.isHidden" style="opacity: 0.5">(%i18n:@private%)</span>
 				<span v-if="p.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span>
-				<mk-note-html v-if="p.text" :text="p.text" :i="$store.state.i"/>
+				<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i"/>
 			</div>
 			<div class="tags" v-if="p.tags && p.tags.length > 0">
 				<router-link v-for="tag in p.tags" :key="tag" :to="`/tags/${tag}`">{{ tag }}</router-link>
diff --git a/src/client/app/mobile/views/components/note.vue b/src/client/app/mobile/views/components/note.vue
index 4498bb5633..77513a6591 100644
--- a/src/client/app/mobile/views/components/note.vue
+++ b/src/client/app/mobile/views/components/note.vue
@@ -25,7 +25,7 @@
 						<span v-if="p.isHidden" style="opacity: 0.5">(%i18n:@private%)</span>
 						<span v-if="p.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span>
 						<a class="reply" v-if="p.reply">%fa:reply%</a>
-						<mk-note-html v-if="p.text && !canHideText(p)" :text="p.text" :i="$store.state.i" :class="$style.text"/>
+						<misskey-flavored-markdown v-if="p.text && !canHideText(p)" :text="p.text" :i="$store.state.i" :class="$style.text"/>
 						<a class="rp" v-if="p.renote != null">RP:</a>
 					</div>
 					<div class="media" v-if="p.media.length > 0">
diff --git a/src/client/app/mobile/views/components/sub-note-content.vue b/src/client/app/mobile/views/components/sub-note-content.vue
index 4ad90b97df..a4ce49786e 100644
--- a/src/client/app/mobile/views/components/sub-note-content.vue
+++ b/src/client/app/mobile/views/components/sub-note-content.vue
@@ -4,7 +4,7 @@
 		<span v-if="note.isHidden" style="opacity: 0.5">(%i18n:@private%)</span>
 		<span v-if="note.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span>
 		<a class="reply" v-if="note.replyId">%fa:reply%</a>
-		<mk-note-html v-if="note.text" :text="note.text" :i="$store.state.i"/>
+		<misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i"/>
 		<a class="rp" v-if="note.renoteId">RP: ...</a>
 	</div>
 	<details v-if="note.media.length > 0">
diff --git a/src/client/app/mobile/views/pages/user.vue b/src/client/app/mobile/views/pages/user.vue
index 3d37015906..ba9de9f8a6 100644
--- a/src/client/app/mobile/views/pages/user.vue
+++ b/src/client/app/mobile/views/pages/user.vue
@@ -18,7 +18,9 @@
 					<span class="username"><mk-acct :user="user"/></span>
 					<span class="followed" v-if="user.isFollowed">%i18n:@follows-you%</span>
 				</div>
-				<div class="description">{{ user.description }}</div>
+				<div class="description">
+					<misskey-flavored-markdown v-if="user.description" :text="user.description" :i="$store.state.i"/>
+				</div>
 				<div class="info">
 					<p class="location" v-if="user.host === null && user.profile.location">
 						%fa:map-marker%{{ user.profile.location }}

From f2f7a6de6bf255fc3ce8014284b4db47e2cc039b Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Wed, 20 Jun 2018 10:59:54 +0000
Subject: [PATCH 06/90] chore(package): update dependencies

---
 package.json | 74 ++++++++++++++++++++++++++--------------------------
 1 file changed, 37 insertions(+), 37 deletions(-)

diff --git a/package.json b/package.json
index 02a3a52a96..e7c2b492b1 100644
--- a/package.json
+++ b/package.json
@@ -33,20 +33,20 @@
 		"@types/bcryptjs": "2.4.1",
 		"@types/debug": "0.0.30",
 		"@types/deep-equal": "1.0.1",
-		"@types/elasticsearch": "5.0.23",
+		"@types/elasticsearch": "5.0.24",
 		"@types/gm": "1.18.0",
-		"@types/gulp": "3.8.36",
+		"@types/gulp": "4.0.5",
 		"@types/gulp-htmlmin": "1.3.32",
 		"@types/gulp-mocha": "0.0.32",
 		"@types/gulp-rename": "0.0.33",
 		"@types/gulp-replace": "0.0.31",
 		"@types/gulp-uglify": "3.0.5",
 		"@types/gulp-util": "3.0.34",
-		"@types/inquirer": "0.0.41",
+		"@types/inquirer": "0.0.42",
 		"@types/is-root": "1.0.0",
 		"@types/is-url": "1.2.28",
 		"@types/js-yaml": "3.11.1",
-		"@types/koa": "2.0.45",
+		"@types/koa": "2.0.46",
 		"@types/koa-bodyparser": "4.2.0",
 		"@types/koa-compress": "2.0.8",
 		"@types/koa-favicon": "2.0.19",
@@ -57,47 +57,47 @@
 		"@types/koa-send": "4.1.1",
 		"@types/koa-views": "2.0.3",
 		"@types/koa__cors": "2.2.2",
-		"@types/kue": "0.11.8",
+		"@types/kue": "0.11.9",
 		"@types/license-checker": "15.0.0",
 		"@types/mkdirp": "0.5.2",
-		"@types/mocha": "5.2.0",
-		"@types/mongodb": "3.0.18",
+		"@types/mocha": "5.2.2",
+		"@types/mongodb": "3.0.21",
 		"@types/ms": "0.7.30",
-		"@types/node": "10.1.2",
+		"@types/node": "10.3.4",
 		"@types/nopt": "3.0.29",
-		"@types/parse5": "3.0.0",
+		"@types/parse5": "5.0.0",
 		"@types/pug": "2.0.4",
-		"@types/qrcode": "0.8.1",
+		"@types/qrcode": "1.2.0",
 		"@types/ratelimiter": "2.1.28",
 		"@types/redis": "2.8.6",
-		"@types/request": "2.47.0",
-		"@types/request-promise-native": "1.0.14",
+		"@types/request": "2.47.1",
+		"@types/request-promise-native": "1.0.15",
 		"@types/rimraf": "2.0.2",
 		"@types/seedrandom": "2.4.27",
 		"@types/single-line-log": "1.1.0",
 		"@types/speakeasy": "2.0.2",
 		"@types/tmp": "0.0.33",
 		"@types/uuid": "3.4.3",
-		"@types/webpack": "4.4.0",
+		"@types/webpack": "4.4.1",
 		"@types/webpack-stream": "3.2.10",
 		"@types/websocket": "0.0.39",
-		"@types/ws": "5.1.1",
+		"@types/ws": "5.1.2",
 		"animejs": "2.2.0",
 		"autosize": "4.0.2",
 		"autwh": "0.1.0",
 		"bcryptjs": "2.4.3",
-		"bootstrap-vue": "2.0.0-rc.6",
-		"cafy": "8.0.0",
+		"bootstrap-vue": "2.0.0-rc.11",
+		"cafy": "10.0.0",
 		"chalk": "2.4.1",
 		"crc-32": "1.2.0",
 		"css-loader": "0.28.11",
 		"debug": "3.1.0",
 		"deep-equal": "1.0.1",
-		"deepcopy": "0.6.3",
+		"deepcopy": "1.0.0",
 		"diskusage": "0.2.4",
-		"dompurify": "1.0.4",
+		"dompurify": "1.0.5",
 		"elasticsearch": "15.0.0",
-		"element-ui": "2.3.9",
+		"element-ui": "2.4.1",
 		"emojilib": "2.2.12",
 		"escape-regexp": "0.0.1",
 		"eslint": "4.19.1",
@@ -114,7 +114,7 @@
 		"gulp-imagemin": "4.1.0",
 		"gulp-mocha": "6.0.0",
 		"gulp-pug": "4.0.1",
-		"gulp-rename": "1.2.3",
+		"gulp-rename": "1.3.0",
 		"gulp-replace": "1.0.0",
 		"gulp-sourcemaps": "2.6.4",
 		"gulp-stylus": "2.7.0",
@@ -122,14 +122,14 @@
 		"gulp-typescript": "4.0.2",
 		"gulp-uglify": "3.0.0",
 		"gulp-util": "3.0.8",
-		"hard-source-webpack-plugin": "0.6.10",
+		"hard-source-webpack-plugin": "0.8.1",
 		"highlight.js": "9.12.0",
 		"html-minifier": "3.5.16",
 		"http-signature": "1.2.0",
-		"inquirer": "5.2.0",
+		"inquirer": "6.0.0",
 		"is-root": "2.0.0",
 		"is-url": "1.2.4",
-		"js-yaml": "3.11.0",
+		"js-yaml": "3.12.0",
 		"jsdom": "11.11.0",
 		"koa": "2.5.1",
 		"koa-bodyparser": "4.2.1",
@@ -140,11 +140,11 @@
 		"koa-mount": "3.0.0",
 		"koa-multer": "1.0.2",
 		"koa-router": "7.4.0",
-		"koa-send": "4.1.3",
+		"koa-send": "5.0.0",
 		"koa-slow": "2.1.0",
 		"koa-views": "6.1.4",
 		"kue": "0.11.6",
-		"license-checker": "20.0.0",
+		"license-checker": "20.1.0",
 		"loader-utils": "1.1.0",
 		"mecab-async": "0.1.2",
 		"mkdirp": "0.5.1",
@@ -155,7 +155,7 @@
 		"ms": "2.1.1",
 		"nan": "2.10.0",
 		"node-sass": "4.9.0",
-		"node-sass-json-importer": "3.2.0",
+		"node-sass-json-importer": "3.3.1",
 		"nopt": "4.0.1",
 		"nprogress": "0.2.0",
 		"object-assign-deep": "0.4.0",
@@ -177,7 +177,7 @@
 		"rimraf": "2.6.2",
 		"rndstr": "1.0.0",
 		"s-age": "1.1.2",
-		"sass-loader": "7.0.1",
+		"sass-loader": "7.0.3",
 		"seedrandom": "2.4.3",
 		"single-line-log": "1.1.2",
 		"speakeasy": "2.0.0",
@@ -190,20 +190,20 @@
 		"tcp-port-used": "0.1.2",
 		"textarea-caret": "3.1.0",
 		"tmp": "0.0.33",
-		"ts-loader": "4.3.0",
-		"ts-node": "6.0.4",
+		"ts-loader": "4.4.1",
+		"ts-node": "6.1.1",
 		"tslint": "5.10.0",
-		"typescript": "2.8.3",
-		"typescript-eslint-parser": "15.0.0",
+		"typescript": "2.9.2",
+		"typescript-eslint-parser": "16.0.0",
 		"uglify-es": "3.3.9",
 		"url-loader": "1.0.1",
 		"uuid": "3.2.1",
 		"v-animate-css": "0.0.2",
 		"vue": "2.5.16",
-		"vue-cropperjs": "2.2.0",
-		"vue-js-modal": "1.3.13",
+		"vue-cropperjs": "2.2.1",
+		"vue-js-modal": "1.3.15",
 		"vue-json-tree-view": "2.1.4",
-		"vue-loader": "15.2.1",
+		"vue-loader": "15.2.4",
 		"vue-router": "3.0.1",
 		"vue-template-compiler": "2.5.16",
 		"vuedraggable": "2.16.0",
@@ -211,12 +211,12 @@
 		"vuex-persistedstate": "^2.5.4",
 		"web-push": "3.3.1",
 		"webfinger.js": "2.6.6",
-		"webpack": "4.9.1",
-		"webpack-cli": "2.1.4",
+		"webpack": "4.12.0",
+		"webpack-cli": "3.0.8",
 		"websocket": "1.0.26",
 		"ws": "5.2.0",
 		"xev": "2.0.1",
 		"@types/file-type": "5.2.1",
-		"@types/jsdom": "11.0.5"
+		"@types/jsdom": "11.0.6"
 	}
 }

From 8128656a9e88788fd01c540f13563601092af1e4 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Wed, 20 Jun 2018 10:59:57 +0000
Subject: [PATCH 07/90] docs(readme): add Greenkeeper badge

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index f8738421cf..dc07b264c3 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
 [![][dependencies-badge]][dependencies-link]
 [![][himawari-badge]][himasaku]
 [![][sakurako-badge]][himasaku]
-[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
+[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) [![Greenkeeper badge](https://badges.greenkeeper.io/syuilo/misskey.svg)](https://greenkeeper.io/)
 
 > Lead Maintainer: [syuilo][syuilo-link]
 

From f00ba4e704d7a83543115c27072edbde2394415a Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Wed, 20 Jun 2018 20:02:03 +0900
Subject: [PATCH 08/90] Prevent update those packages

---
 package.json | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/package.json b/package.json
index 02a3a52a96..dd3c30be4c 100644
--- a/package.json
+++ b/package.json
@@ -218,5 +218,11 @@
 		"xev": "2.0.1",
 		"@types/file-type": "5.2.1",
 		"@types/jsdom": "11.0.5"
+	},
+	"greenkeeper": {
+		"ignore": [
+			"deepcopy",
+			"cafy"
+		]
 	}
 }

From 278a6c504a4f98d4a8e2c4f886a2e0315ea90aa2 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Wed, 20 Jun 2018 20:04:28 +0900
Subject: [PATCH 09/90] :v:

---
 DONATORS.md => docs/DONATORS.md |  6 +-----
 docs/donate.ja.md               | 26 --------------------------
 2 files changed, 1 insertion(+), 31 deletions(-)
 rename DONATORS.md => docs/DONATORS.md (74%)
 delete mode 100644 docs/donate.ja.md

diff --git a/DONATORS.md b/docs/DONATORS.md
similarity index 74%
rename from DONATORS.md
rename to docs/DONATORS.md
index 6fe5df04b7..9da5c1a94e 100644
--- a/DONATORS.md
+++ b/docs/DONATORS.md
@@ -22,8 +22,4 @@ The list of people who have sent donation for Misskey.
 
 ---
 
-If your name is missing,  please contact us!
-
-If you want to donate to Misskey, please get in touch with [@syuilo][syuilo-link].
-
-[syuilo-link]: https://syuilo.com
+If your name is missing, please contact us!
diff --git a/docs/donate.ja.md b/docs/donate.ja.md
deleted file mode 100644
index b19d7bc370..0000000000
--- a/docs/donate.ja.md
+++ /dev/null
@@ -1,26 +0,0 @@
-# Misskeyにカンパする方法
-Misskeyのサポートにご興味をお持ちいただきありがとうございます!
-Misskeyにカンパをしていただくと、貴方のお名前と好きなURLなどをMisskeyのリポジトリに刻む権利がもらえます。
-
-Misskeyにカンパして開発・運営をサポートするには、次のいくつかの方法があります:
-
-## ConoHaカードを購入する
-(本家)Misskeyは、ConoHaというVPSサービスを利用しています。ConoHaカードを購入して、
-カードに記載されているクーポンコードを syuilotan@yahoo.co.jp までお送りいただければ、
-そのクーポンをチャージしてサーバーの運営費に充てることができます。
-
-ConoHaカードについてはこちらをご覧ください: https://www.conoha.jp/conohacard/
-
-Amazonでも買えます: https://www.amazon.co.jp/dp/B01N9E3416
-
-## Amazonギフトカード
-これは間接的な方法です。
-
-## 銀行振込
-syuilotan@yahoo.co.jp までお問い合わせください。
-
-## 手渡し
-オフ会を行ったときなどに行使できる方法です。
-
-## その他
-なにかいいアイデアがあればお教えください。

From 89361cfce439e2afaf21e5f71f91f94d47f02a0d Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Wed, 20 Jun 2018 20:08:36 +0900
Subject: [PATCH 10/90] 4.4.0

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

diff --git a/package.json b/package.json
index dd3c30be4c..d975df2db9 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "4.3.1",
-	"clientVersion": "1.0.6630",
+	"version": "4.4.0",
+	"clientVersion": "1.0.6655",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,

From 3633d7ada156c9da771f1788ca15296d1d68c94e Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Wed, 20 Jun 2018 22:28:08 +0900
Subject: [PATCH 11/90] Disable transitions to avoid memory leak

---
 src/client/app/desktop/views/components/notes.vue          | 5 +++--
 src/client/app/desktop/views/pages/deck/deck.notes.vue     | 5 +++--
 .../app/desktop/views/pages/deck/deck.notifications.vue    | 7 +++++--
 3 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/src/client/app/desktop/views/components/notes.vue b/src/client/app/desktop/views/components/notes.vue
index 69f3739f79..5c595c4ca5 100644
--- a/src/client/app/desktop/views/components/notes.vue
+++ b/src/client/app/desktop/views/components/notes.vue
@@ -9,7 +9,8 @@
 		<button @click="resolveInitPromise">%i18n:@retry%</button>
 	</div>
 
-	<transition-group name="mk-notes" class="transition">
+	<!-- トランジションを有効にするとなぜかメモリリークする -->
+	<!--<transition-group name="mk-notes" class="transition">-->
 		<template v-for="(note, i) in _notes">
 			<x-note :note="note" :key="note.id" @update:note="onNoteUpdated(i, $event)"/>
 			<p class="date" :key="note.id + '_date'" v-if="i != notes.length - 1 && note._date != _notes[i + 1]._date">
@@ -17,7 +18,7 @@
 				<span>%fa:angle-down%{{ _notes[i + 1]._datetext }}</span>
 			</p>
 		</template>
-	</transition-group>
+	<!--</transition-group>-->
 
 	<footer v-if="more">
 		<button @click="loadMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
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 8862b0e0fc..c135c6cd5a 100644
--- a/src/client/app/desktop/views/pages/deck/deck.notes.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.notes.vue
@@ -7,7 +7,8 @@
 		<button @click="resolveInitPromise">%i18n:@retry%</button>
 	</div>
 
-	<transition-group name="mk-notes" class="transition">
+	<!-- トランジションを有効にするとなぜかメモリリークする -->
+	<!--<transition-group name="mk-notes" class="transition">-->
 		<template v-for="(note, i) in _notes">
 			<x-note :note="note" :key="note.id" @update:note="onNoteUpdated(i, $event)" :media-view="mediaView"/>
 			<p class="date" :key="note.id + '_date'" v-if="i != notes.length - 1 && note._date != _notes[i + 1]._date">
@@ -15,7 +16,7 @@
 				<span>%fa:angle-down%{{ _notes[i + 1]._datetext }}</span>
 			</p>
 		</template>
-	</transition-group>
+	<!--</transition-group>-->
 
 	<footer v-if="more">
 		<button @click="loadMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
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 f54ad1a3cd..10c06b0ad2 100644
--- a/src/client/app/desktop/views/pages/deck/deck.notifications.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.notifications.vue
@@ -1,6 +1,8 @@
 <template>
 <div class="oxynyeqmfvracxnglgulyqfgqxnxmehl">
-	<transition-group name="mk-notifications" class="transition notifications">
+	<!-- トランジションを有効にするとなぜかメモリリークする -->
+	<!--<transition-group name="mk-notifications" class="transition notifications">-->
+	<div class="notifications">
 		<template v-for="(notification, i) in _notifications">
 			<x-notification class="notification" :notification="notification" :key="notification.id"/>
 			<p class="date" v-if="i != notifications.length - 1 && notification._date != _notifications[i + 1]._date" :key="notification.id + '-time'">
@@ -8,7 +10,8 @@
 				<span>%fa:angle-down%{{ _notifications[i + 1]._datetext }}</span>
 			</p>
 		</template>
-	</transition-group>
+	</div>
+	<!--</transition-group>-->
 	<button class="more" :class="{ fetching: fetchingMoreNotifications }" v-if="moreNotifications" @click="fetchMoreNotifications" :disabled="fetchingMoreNotifications">
 		<template v-if="fetchingMoreNotifications">%fa:spinner .pulse .fw%</template>{{ fetchingMoreNotifications ? '%i18n:common.loading%' : '%i18n:@more%' }}
 	</button>

From 5786434f3751a18096b53bb34dc25325c0bc8bbd Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Wed, 20 Jun 2018 22:40:02 +0900
Subject: [PATCH 12/90] Update README.md

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index dc07b264c3..0f3296d032 100644
--- a/README.md
+++ b/README.md
@@ -26,7 +26,7 @@ ultimately sophisticated professional microblogging software.
   * and widgets!
 * Private messages
 * Mute
-* Streaming
+* Real-time timelines
 * ActivityPub compatible
 
 and more! You can see it with your own eyes at [misskey.xyz](https://misskey.xyz).

From 79d1bf30a49e1fd1ef1f8b743a9aff84d104fb89 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Thu, 21 Jun 2018 01:21:57 +0900
Subject: [PATCH 13/90] =?UTF-8?q?=E3=83=AA=E3=83=A2=E3=83=BC=E3=83=88?=
 =?UTF-8?q?=E3=83=A6=E3=83=BC=E3=82=B6=E3=83=BC=E3=81=AEHTML=E3=81=A7?=
 =?UTF-8?q?=E8=A1=A8=E7=8F=BE=E3=81=95=E3=82=8C=E3=81=9F=E3=83=97=E3=83=AD?=
 =?UTF-8?q?=E3=83=95=E3=82=A3=E3=83=BC=E3=83=AB=E3=82=92MFM=E3=81=AB?=
 =?UTF-8?q?=E5=A4=89=E6=8F=9B=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../components/messaging-room.message.vue     |  2 +-
 .../components/misskey-flavored-markdown.ts   |  2 +-
 .../desktop/views/components/note-detail.vue  |  2 +-
 .../desktop/views/components/notes.note.vue   |  2 +-
 .../desktop/views/components/post-form.vue    |  2 +-
 .../desktop/views/pages/deck/deck.note.vue    |  2 +-
 .../mobile/views/components/note-detail.vue   |  2 +-
 .../app/mobile/views/components/note.vue      |  2 +-
 .../app/mobile/views/components/post-form.vue |  2 +-
 src/mfm/html-to-mfm.ts                        | 71 ++++++++++++++++++
 src/{text => mfm}/html.ts                     |  0
 .../parse/core/syntax-highlighter.ts          |  0
 src/{text => mfm}/parse/elements/bold.ts      |  0
 src/{text => mfm}/parse/elements/code.ts      |  0
 src/{text => mfm}/parse/elements/emoji.ts     |  0
 src/{text => mfm}/parse/elements/hashtag.ts   |  0
 .../parse/elements/inline-code.ts             |  0
 src/{text => mfm}/parse/elements/link.ts      |  0
 src/{text => mfm}/parse/elements/mention.ts   |  0
 src/{text => mfm}/parse/elements/quote.ts     |  0
 src/{text => mfm}/parse/elements/search.ts    |  0
 src/{text => mfm}/parse/elements/title.ts     |  0
 src/{text => mfm}/parse/elements/url.ts       |  0
 src/{text => mfm}/parse/index.ts              |  0
 src/remote/activitypub/misc/get-note-html.ts  |  4 +-
 src/remote/activitypub/models/note.ts         | 74 +------------------
 src/remote/activitypub/models/person.ts       |  9 +--
 src/services/note/create.ts                   |  2 +-
 test/{text.ts => mfm.ts}                      |  4 +-
 29 files changed, 90 insertions(+), 92 deletions(-)
 create mode 100644 src/mfm/html-to-mfm.ts
 rename src/{text => mfm}/html.ts (100%)
 rename src/{text => mfm}/parse/core/syntax-highlighter.ts (100%)
 rename src/{text => mfm}/parse/elements/bold.ts (100%)
 rename src/{text => mfm}/parse/elements/code.ts (100%)
 rename src/{text => mfm}/parse/elements/emoji.ts (100%)
 rename src/{text => mfm}/parse/elements/hashtag.ts (100%)
 rename src/{text => mfm}/parse/elements/inline-code.ts (100%)
 rename src/{text => mfm}/parse/elements/link.ts (100%)
 rename src/{text => mfm}/parse/elements/mention.ts (100%)
 rename src/{text => mfm}/parse/elements/quote.ts (100%)
 rename src/{text => mfm}/parse/elements/search.ts (100%)
 rename src/{text => mfm}/parse/elements/title.ts (100%)
 rename src/{text => mfm}/parse/elements/url.ts (100%)
 rename src/{text => mfm}/parse/index.ts (100%)
 rename test/{text.ts => mfm.ts} (96%)

diff --git a/src/client/app/common/views/components/messaging-room.message.vue b/src/client/app/common/views/components/messaging-room.message.vue
index d7e7c6dcb5..f33173da6f 100644
--- a/src/client/app/common/views/components/messaging-room.message.vue
+++ b/src/client/app/common/views/components/messaging-room.message.vue
@@ -32,7 +32,7 @@
 
 <script lang="ts">
 import Vue from 'vue';
-import parse from '../../../../../text/parse';
+import parse from '../../../../../mfm/parse';
 
 export default Vue.extend({
 	props: {
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 61dbc02d9a..30ad3ce3f2 100644
--- a/src/client/app/common/views/components/misskey-flavored-markdown.ts
+++ b/src/client/app/common/views/components/misskey-flavored-markdown.ts
@@ -1,6 +1,6 @@
 import Vue from 'vue';
 import * as emojilib from 'emojilib';
-import parse from '../../../../../text/parse';
+import parse from '../../../../../mfm/parse';
 import getAcct from '../../../../../acct/render';
 import { url } from '../../../config';
 import MkUrl from './url.vue';
diff --git a/src/client/app/desktop/views/components/note-detail.vue b/src/client/app/desktop/views/components/note-detail.vue
index 017f599e31..a9640ff9c4 100644
--- a/src/client/app/desktop/views/components/note-detail.vue
+++ b/src/client/app/desktop/views/components/note-detail.vue
@@ -83,7 +83,7 @@
 <script lang="ts">
 import Vue from 'vue';
 import dateStringify from '../../../common/scripts/date-stringify';
-import parse from '../../../../../text/parse';
+import parse from '../../../../../mfm/parse';
 
 import MkPostFormWindow from './post-form-window.vue';
 import MkRenoteFormWindow from './renote-form-window.vue';
diff --git a/src/client/app/desktop/views/components/notes.note.vue b/src/client/app/desktop/views/components/notes.note.vue
index 661223ee25..b96ae2da5a 100644
--- a/src/client/app/desktop/views/components/notes.note.vue
+++ b/src/client/app/desktop/views/components/notes.note.vue
@@ -76,7 +76,7 @@
 import Vue from 'vue';
 import dateStringify from '../../../common/scripts/date-stringify';
 import canHideText from '../../../common/scripts/can-hide-text';
-import parse from '../../../../../text/parse';
+import parse from '../../../../../mfm/parse';
 
 import MkPostFormWindow from './post-form-window.vue';
 import MkRenoteFormWindow from './renote-form-window.vue';
diff --git a/src/client/app/desktop/views/components/post-form.vue b/src/client/app/desktop/views/components/post-form.vue
index 33f2288e06..3832e5b38c 100644
--- a/src/client/app/desktop/views/components/post-form.vue
+++ b/src/client/app/desktop/views/components/post-form.vue
@@ -49,7 +49,7 @@ import Vue from 'vue';
 import * as XDraggable from 'vuedraggable';
 import getKao from '../../../common/scripts/get-kao';
 import MkVisibilityChooser from '../../../common/views/components/visibility-chooser.vue';
-import parse from '../../../../../text/parse';
+import parse from '../../../../../mfm/parse';
 import { host } from '../../../config';
 
 export default Vue.extend({
diff --git a/src/client/app/desktop/views/pages/deck/deck.note.vue b/src/client/app/desktop/views/pages/deck/deck.note.vue
index 067297af37..d50fc3c235 100644
--- a/src/client/app/desktop/views/pages/deck/deck.note.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.note.vue
@@ -67,7 +67,7 @@
 
 <script lang="ts">
 import Vue from 'vue';
-import parse from '../../../../../../text/parse';
+import parse from '../../../../../../mfm/parse';
 import canHideText from '../../../../common/scripts/can-hide-text';
 
 import MkNoteMenu from '../../../../common/views/components/note-menu.vue';
diff --git a/src/client/app/mobile/views/components/note-detail.vue b/src/client/app/mobile/views/components/note-detail.vue
index 6499f78f1b..76633490fd 100644
--- a/src/client/app/mobile/views/components/note-detail.vue
+++ b/src/client/app/mobile/views/components/note-detail.vue
@@ -83,7 +83,7 @@
 
 <script lang="ts">
 import Vue from 'vue';
-import parse from '../../../../../text/parse';
+import parse from '../../../../../mfm/parse';
 
 import MkNoteMenu from '../../../common/views/components/note-menu.vue';
 import MkReactionPicker from '../../../common/views/components/reaction-picker.vue';
diff --git a/src/client/app/mobile/views/components/note.vue b/src/client/app/mobile/views/components/note.vue
index 77513a6591..ecdfee3b44 100644
--- a/src/client/app/mobile/views/components/note.vue
+++ b/src/client/app/mobile/views/components/note.vue
@@ -68,7 +68,7 @@
 
 <script lang="ts">
 import Vue from 'vue';
-import parse from '../../../../../text/parse';
+import parse from '../../../../../mfm/parse';
 import canHideText from '../../../common/scripts/can-hide-text';
 
 import MkNoteMenu from '../../../common/views/components/note-menu.vue';
diff --git a/src/client/app/mobile/views/components/post-form.vue b/src/client/app/mobile/views/components/post-form.vue
index 62fa185085..1015a44115 100644
--- a/src/client/app/mobile/views/components/post-form.vue
+++ b/src/client/app/mobile/views/components/post-form.vue
@@ -45,7 +45,7 @@ import Vue from 'vue';
 import * as XDraggable from 'vuedraggable';
 import MkVisibilityChooser from '../../../common/views/components/visibility-chooser.vue';
 import getKao from '../../../common/scripts/get-kao';
-import parse from '../../../../../text/parse';
+import parse from '../../../../../mfm/parse';
 import { host } from '../../../config';
 
 export default Vue.extend({
diff --git a/src/mfm/html-to-mfm.ts b/src/mfm/html-to-mfm.ts
new file mode 100644
index 0000000000..540635036a
--- /dev/null
+++ b/src/mfm/html-to-mfm.ts
@@ -0,0 +1,71 @@
+const parse5 = require('parse5');
+
+export default function(html: string): string {
+	const dom = parse5.parseFragment(html);
+
+	let text = '';
+
+	dom.childNodes.forEach((n: any) => analyze(n));
+
+	return text.trim();
+
+	function getText(node: any) {
+		if (node.nodeName == '#text') return node.value;
+
+		if (node.childNodes) {
+			return node.childNodes.map((n: any) => getText(n)).join('');
+		}
+
+		return '';
+	}
+
+	function analyze(node: any) {
+		switch (node.nodeName) {
+			case '#text':
+				text += node.value;
+				break;
+
+			case 'br':
+				text += '\n';
+				break;
+
+			case 'a':
+				const txt = getText(node);
+
+				// メンション
+				if (txt.startsWith('@')) {
+					const part = txt.split('@');
+
+					if (part.length == 2) {
+						//#region ホスト名部分が省略されているので復元する
+						const href = new URL(node.attrs.find((x: any) => x.name == 'href').value);
+						const acct = txt + '@' + href.hostname;
+						text += acct;
+						break;
+						//#endregion
+					} else if (part.length == 3) {
+						text += txt;
+						break;
+					}
+				}
+
+				if (node.childNodes) {
+					node.childNodes.forEach((n: any) => analyze(n));
+				}
+				break;
+
+			case 'p':
+				text += '\n\n';
+				if (node.childNodes) {
+					node.childNodes.forEach((n: any) => analyze(n));
+				}
+				break;
+
+			default:
+				if (node.childNodes) {
+					node.childNodes.forEach((n: any) => analyze(n));
+				}
+				break;
+		}
+	}
+}
diff --git a/src/text/html.ts b/src/mfm/html.ts
similarity index 100%
rename from src/text/html.ts
rename to src/mfm/html.ts
diff --git a/src/text/parse/core/syntax-highlighter.ts b/src/mfm/parse/core/syntax-highlighter.ts
similarity index 100%
rename from src/text/parse/core/syntax-highlighter.ts
rename to src/mfm/parse/core/syntax-highlighter.ts
diff --git a/src/text/parse/elements/bold.ts b/src/mfm/parse/elements/bold.ts
similarity index 100%
rename from src/text/parse/elements/bold.ts
rename to src/mfm/parse/elements/bold.ts
diff --git a/src/text/parse/elements/code.ts b/src/mfm/parse/elements/code.ts
similarity index 100%
rename from src/text/parse/elements/code.ts
rename to src/mfm/parse/elements/code.ts
diff --git a/src/text/parse/elements/emoji.ts b/src/mfm/parse/elements/emoji.ts
similarity index 100%
rename from src/text/parse/elements/emoji.ts
rename to src/mfm/parse/elements/emoji.ts
diff --git a/src/text/parse/elements/hashtag.ts b/src/mfm/parse/elements/hashtag.ts
similarity index 100%
rename from src/text/parse/elements/hashtag.ts
rename to src/mfm/parse/elements/hashtag.ts
diff --git a/src/text/parse/elements/inline-code.ts b/src/mfm/parse/elements/inline-code.ts
similarity index 100%
rename from src/text/parse/elements/inline-code.ts
rename to src/mfm/parse/elements/inline-code.ts
diff --git a/src/text/parse/elements/link.ts b/src/mfm/parse/elements/link.ts
similarity index 100%
rename from src/text/parse/elements/link.ts
rename to src/mfm/parse/elements/link.ts
diff --git a/src/text/parse/elements/mention.ts b/src/mfm/parse/elements/mention.ts
similarity index 100%
rename from src/text/parse/elements/mention.ts
rename to src/mfm/parse/elements/mention.ts
diff --git a/src/text/parse/elements/quote.ts b/src/mfm/parse/elements/quote.ts
similarity index 100%
rename from src/text/parse/elements/quote.ts
rename to src/mfm/parse/elements/quote.ts
diff --git a/src/text/parse/elements/search.ts b/src/mfm/parse/elements/search.ts
similarity index 100%
rename from src/text/parse/elements/search.ts
rename to src/mfm/parse/elements/search.ts
diff --git a/src/text/parse/elements/title.ts b/src/mfm/parse/elements/title.ts
similarity index 100%
rename from src/text/parse/elements/title.ts
rename to src/mfm/parse/elements/title.ts
diff --git a/src/text/parse/elements/url.ts b/src/mfm/parse/elements/url.ts
similarity index 100%
rename from src/text/parse/elements/url.ts
rename to src/mfm/parse/elements/url.ts
diff --git a/src/text/parse/index.ts b/src/mfm/parse/index.ts
similarity index 100%
rename from src/text/parse/index.ts
rename to src/mfm/parse/index.ts
diff --git a/src/remote/activitypub/misc/get-note-html.ts b/src/remote/activitypub/misc/get-note-html.ts
index 0ceecdd00b..8df440930b 100644
--- a/src/remote/activitypub/misc/get-note-html.ts
+++ b/src/remote/activitypub/misc/get-note-html.ts
@@ -1,6 +1,6 @@
 import { INote } from '../../../models/note';
-import toHtml from '../../../text/html';
-import parse from '../../../text/parse';
+import toHtml from '../../../mfm/html';
+import parse from '../../../mfm/parse';
 import config from '../../../config';
 
 export default function(note: INote) {
diff --git a/src/remote/activitypub/models/note.ts b/src/remote/activitypub/models/note.ts
index b0fe045e6d..85a8f89bc8 100644
--- a/src/remote/activitypub/models/note.ts
+++ b/src/remote/activitypub/models/note.ts
@@ -1,5 +1,4 @@
 import * as mongo from 'mongodb';
-const parse5 = require('parse5');
 import * as debug from 'debug';
 
 import config from '../../../config';
@@ -10,79 +9,10 @@ import { INote as INoteActivityStreamsObject, IObject } from '../type';
 import { resolvePerson, updatePerson } from './person';
 import { resolveImage } from './image';
 import { IRemoteUser, IUser } from '../../../models/user';
+import htmlToMFM from '../../../mfm/html-to-mfm';
 
 const log = debug('misskey:activitypub');
 
-function parse(html: string): string {
-	const dom = parse5.parseFragment(html);
-
-	let text = '';
-
-	dom.childNodes.forEach((n: any) => analyze(n));
-
-	return text.trim();
-
-	function getText(node: any) {
-		if (node.nodeName == '#text') return node.value;
-
-		if (node.childNodes) {
-			return node.childNodes.map((n: any) => getText(n)).join('');
-		}
-
-		return '';
-	}
-
-	function analyze(node: any) {
-		switch (node.nodeName) {
-			case '#text':
-				text += node.value;
-				break;
-
-			case 'br':
-				text += '\n';
-				break;
-
-			case 'a':
-				const txt = getText(node);
-
-				// メンション
-				if (txt.startsWith('@')) {
-					const part = txt.split('@');
-
-					if (part.length == 2) {
-						//#region ホスト名部分が省略されているので復元する
-						const href = new URL(node.attrs.find((x: any) => x.name == 'href').value);
-						const acct = txt + '@' + href.hostname;
-						text += acct;
-						break;
-						//#endregion
-					} else if (part.length == 3) {
-						text += txt;
-						break;
-					}
-				}
-
-				if (node.childNodes) {
-					node.childNodes.forEach((n: any) => analyze(n));
-				}
-				break;
-
-			case 'p':
-				text += '\n\n';
-				if (node.childNodes) {
-					node.childNodes.forEach((n: any) => analyze(n));
-				}
-				break;
-
-			default:
-				if (node.childNodes) {
-					node.childNodes.forEach((n: any) => analyze(n));
-				}
-				break;
-		}
-	}
-}
-
 /**
  * Noteをフェッチします。
  *
@@ -158,7 +88,7 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
 	const reply = note.inReplyTo ? await resolveNote(note.inReplyTo, resolver) : null;
 
 	// テキストのパース
-	const text = parse(note.content);
+	const text = htmlToMFM(note.content);
 
 	// ユーザーの情報が古かったらついでに更新しておく
 	if (actor.updatedAt == null || Date.now() - actor.updatedAt.getTime() > 1000 * 60 * 60 * 24) {
diff --git a/src/remote/activitypub/models/person.ts b/src/remote/activitypub/models/person.ts
index 42ee5a27df..f233346395 100644
--- a/src/remote/activitypub/models/person.ts
+++ b/src/remote/activitypub/models/person.ts
@@ -1,5 +1,4 @@
 import * as mongo from 'mongodb';
-import { JSDOM } from 'jsdom';
 import { toUnicode } from 'punycode';
 import * as debug from 'debug';
 
@@ -11,6 +10,7 @@ import { resolveImage } from './image';
 import { isCollectionOrOrderedCollection, IObject, IPerson } from '../type';
 import { IDriveFile } from '../../../models/drive-file';
 import Meta from '../../../models/meta';
+import htmlToMFM from '../../../mfm/html-to-mfm';
 
 const log = debug('misskey:activitypub');
 
@@ -80,7 +80,6 @@ export async function createPerson(value: any, resolver?: Resolver): Promise<IUs
 	]);
 
 	const host = toUnicode(finger.subject.replace(/^.*?@/, '')).toLowerCase();
-	const summaryDOM = JSDOM.fragment(person.summary);
 
 	// Create user
 	let user: IRemoteUser;
@@ -89,7 +88,7 @@ export async function createPerson(value: any, resolver?: Resolver): Promise<IUs
 			avatarId: null,
 			bannerId: null,
 			createdAt: Date.parse(person.published) || null,
-			description: summaryDOM.textContent,
+			description: htmlToMFM(person.summary),
 			followersCount,
 			followingCount,
 			notesCount,
@@ -211,8 +210,6 @@ export async function updatePerson(value: string | IObject, resolver?: Resolver)
 		)
 	]);
 
-	const summaryDOM = JSDOM.fragment(person.summary);
-
 	// アイコンとヘッダー画像をフェッチ
 	const [avatar, banner] = (await Promise.all<IDriveFile>([
 		person.icon,
@@ -231,7 +228,7 @@ export async function updatePerson(value: string | IObject, resolver?: Resolver)
 			bannerId: banner ? banner._id : null,
 			avatarUrl: avatar && avatar.metadata.isMetaOnly ? avatar.metadata.url : null,
 			bannerUrl: banner && banner.metadata.isMetaOnly ? banner.metadata.url : null,
-			description: summaryDOM.textContent,
+			description: htmlToMFM(person.summary),
 			followersCount,
 			followingCount,
 			notesCount,
diff --git a/src/services/note/create.ts b/src/services/note/create.ts
index ef03c4e044..782ac5a4fe 100644
--- a/src/services/note/create.ts
+++ b/src/services/note/create.ts
@@ -14,7 +14,7 @@ import watch from './watch';
 import Mute from '../../models/mute';
 import pushSw from '../../publishers/push-sw';
 import event from '../../publishers/stream';
-import parse from '../../text/parse';
+import parse from '../../mfm/parse';
 import { IApp } from '../../models/app';
 import UserList from '../../models/user-list';
 import resolveUser from '../../remote/resolve-user';
diff --git a/test/text.ts b/test/mfm.ts
similarity index 96%
rename from test/text.ts
rename to test/mfm.ts
index a64999fc0b..de722bffb3 100644
--- a/test/text.ts
+++ b/test/mfm.ts
@@ -1,7 +1,7 @@
 import * as assert from 'assert';
 
-import analyze from '../src/text/parse';
-import syntaxhighlighter from '../src/text/parse/core/syntax-highlighter';
+import analyze from '../src/mfm/parse';
+import syntaxhighlighter from '../src/mfm/parse/core/syntax-highlighter';
 
 describe('Text', () => {
 	it('can be analyzed', () => {

From 46d7cee63972cfd4bb4a86619379cfb9ef01955b Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Thu, 21 Jun 2018 01:46:35 +0900
Subject: [PATCH 14/90] :art:

---
 locales/ja.yml                                |   2 +-
 .../desktop/views/pages/user/user.header.vue  |  33 +----
 .../views/pages/user/user.timeline.vue        |  53 +++++--
 .../app/desktop/views/pages/user/user.vue     | 129 +++++++++++-------
 4 files changed, 126 insertions(+), 91 deletions(-)

diff --git a/locales/ja.yml b/locales/ja.yml
index f2a85eb4e6..436a97f1eb 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -727,7 +727,7 @@ desktop/views/pages/user/user.friends.vue:
   loading: "読み込み中"
   no-users: "よく話すユーザーはいません"
 
-desktop/views/pages/user/user.header.vue:
+desktop/views/pages/user/user.vue:
   is-suspended: "このユーザーは凍結されています。"
   is-remote: "このユーザーはリモートユーザーです。"
   view-remote: "正確な情報を見る"
diff --git a/src/client/app/desktop/views/pages/user/user.header.vue b/src/client/app/desktop/views/pages/user/user.header.vue
index d0976a32e1..afb8de4b2a 100644
--- a/src/client/app/desktop/views/pages/user/user.header.vue
+++ b/src/client/app/desktop/views/pages/user/user.header.vue
@@ -1,7 +1,5 @@
 <template>
 <div class="header" :data-is-dark-background="user.bannerUrl != null">
-	<div class="is-suspended" v-if="user.isSuspended"><p>%fa:exclamation-triangle% %i18n:@is-suspended%</p></div>
-	<div class="is-remote" v-if="user.host != null"><p>%fa:exclamation-triangle% %i18n:@is-remote%<a :href="user.url || user.uri" target="_blank">%i18n:@view-remote%</a></p></div>
 	<div class="banner-container" :style="style">
 		<div class="banner" ref="banner" :style="style" @click="onBannerClick"></div>
 		<div class="fade"></div>
@@ -34,16 +32,16 @@ export default Vue.extend({
 	},
 	mounted() {
 		if (this.user.bannerUrl) {
-			window.addEventListener('load', this.onScroll);
-			window.addEventListener('scroll', this.onScroll, { passive: true });
-			window.addEventListener('resize', this.onScroll);
+			//window.addEventListener('load', this.onScroll);
+			//window.addEventListener('scroll', this.onScroll, { passive: true });
+			//window.addEventListener('resize', this.onScroll);
 		}
 	},
 	beforeDestroy() {
 		if (this.user.bannerUrl) {
-			window.removeEventListener('load', this.onScroll);
-			window.removeEventListener('scroll', this.onScroll);
-			window.removeEventListener('resize', this.onScroll);
+			//window.removeEventListener('load', this.onScroll);
+			//window.removeEventListener('scroll', this.onScroll);
+			//window.removeEventListener('resize', this.onScroll);
 		}
 	},
 	methods: {
@@ -80,25 +78,6 @@ root(isDark)
 	border-radius 6px
 	overflow hidden
 
-	> .is-suspended
-	> .is-remote
-		&.is-suspended
-			color #570808
-			background #ffdbdb
-
-		&.is-remote
-			color #573c08
-			background #fff0db
-
-		> p
-			margin 0 auto
-			padding 14px 16px
-			max-width 1200px
-			font-size 14px
-
-			> a
-				font-weight bold
-
 	&[data-is-dark-background]
 		> .banner-container
 			> .banner
diff --git a/src/client/app/desktop/views/pages/user/user.timeline.vue b/src/client/app/desktop/views/pages/user/user.timeline.vue
index 812b5b4229..67987fcb94 100644
--- a/src/client/app/desktop/views/pages/user/user.timeline.vue
+++ b/src/client/app/desktop/views/pages/user/user.timeline.vue
@@ -1,9 +1,9 @@
 <template>
-<div class="timeline">
+<div class="oh5y2r7l5lx8j6jj791ykeiwgihheguk">
 	<header>
-		<span :data-active="mode == 'default'" @click="mode = 'default'">%i18n:@default%</span>
-		<span :data-active="mode == 'with-replies'" @click="mode = 'with-replies'">%i18n:@with-replies%</span>
-		<span :data-active="mode == 'with-media'" @click="mode = 'with-media'">%i18n:@with-media%</span>
+		<span :data-active="mode == 'default'" @click="mode = 'default'">%fa:comment-alt R% %i18n:@default%</span>
+		<span :data-active="mode == 'with-replies'" @click="mode = 'with-replies'">%fa:comments% %i18n:@with-replies%</span>
+		<span :data-active="mode == 'with-media'" @click="mode = 'with-media'">%fa:images% %i18n:@with-media%</span>
 	</header>
 	<div class="loading" v-if="fetching">
 		<mk-ellipsis-icon/>
@@ -114,25 +114,44 @@ export default Vue.extend({
 <style lang="stylus" scoped>
 @import '~const.styl'
 
-.timeline
-	background #fff
+root(isDark)
+	background isDark ? #282C37 : #fff
 
 	> header
-		padding 8px 16px
-		border-bottom solid 1px #eee
+		padding 0 8px
+		z-index 10
+		background isDark ? #313543 : #fff
+		border-radius 6px 6px 0 0
+		box-shadow 0 1px isDark ? rgba(#000, 0.15) : rgba(#000, 0.08)
 
 		> span
-			margin-right 16px
-			line-height 27px
-			font-size 18px
-			color #555
+			display inline-block
+			padding 0 10px
+			line-height 42px
+			font-size 12px
+			user-select none
+
+			&[data-active]
+				color $theme-color
+				cursor default
+				font-weight bold
+
+				&:before
+					content ""
+					display block
+					position absolute
+					bottom 0
+					left -8px
+					width calc(100% + 16px)
+					height 2px
+					background $theme-color
 
 			&:not([data-active])
-				color $theme-color
+				color isDark ? #9aa2a7 : #6f7477
 				cursor pointer
 
 				&:hover
-					text-decoration underline
+					color isDark ? #d9dcde : #525a5f
 
 	> .loading
 		padding 64px 0
@@ -151,4 +170,10 @@ export default Vue.extend({
 			font-size 3em
 			color #ccc
 
+.oh5y2r7l5lx8j6jj791ykeiwgihheguk[data-darkmode]
+	root(true)
+
+.oh5y2r7l5lx8j6jj791ykeiwgihheguk:not([data-darkmode])
+	root(false)
+
 </style>
diff --git a/src/client/app/desktop/views/pages/user/user.vue b/src/client/app/desktop/views/pages/user/user.vue
index 3741629b72..0e0d4f5768 100644
--- a/src/client/app/desktop/views/pages/user/user.vue
+++ b/src/client/app/desktop/views/pages/user/user.vue
@@ -1,21 +1,25 @@
 <template>
 <mk-ui>
-	<div class="zwwan0di1v4356rmdbjmwnn32tptpdp2" v-if="!fetching">
-		<div class="main">
-			<x-header :user="user"/>
-			<mk-note-detail v-if="user.pinnedNote" :note="user.pinnedNote" :compact="true"/>
-			<x-timeline class="timeline" ref="tl" :user="user"/>
-		</div>
-		<div class="side">
-			<x-profile :user="user"/>
-			<mk-calendar @chosen="warp" :start="new Date(user.createdAt)"/>
-			<mk-activity :user="user"/>
-			<x-photos :user="user"/>
-			<x-friends :user="user"/>
-			<x-followers-you-know v-if="$store.getters.isSignedIn && $store.state.i.id != user.id" :user="user"/>
-			<div class="nav"><mk-nav/></div>
-			<p v-if="user.host === null">%i18n:@last-used-at%: <b><mk-time :time="user.lastUsedAt"/></b></p>
-		</div>
+	<div class="zwwan0di1v4356rmdbjmwnn32tptpdp2" v-if="!fetching" :data-darkmode="$store.state.device.darkmode">
+		<div class="is-suspended" v-if="user.isSuspended || true">%fa:exclamation-triangle% %i18n:@is-suspended%</div>
+		<div class="is-remote" v-if="user.host != null || true">%fa:exclamation-triangle% %i18n:@is-remote%<a :href="user.url || user.uri" target="_blank">%i18n:@view-remote%</a></div>
+		<main>
+			<div class="main">
+				<x-header :user="user"/>
+				<mk-note-detail v-if="user.pinnedNote" :note="user.pinnedNote" :compact="true"/>
+				<x-timeline class="timeline" ref="tl" :user="user"/>
+			</div>
+			<div class="side">
+				<x-profile :user="user"/>
+				<mk-calendar @chosen="warp" :start="new Date(user.createdAt)"/>
+				<mk-activity :user="user"/>
+				<x-photos :user="user"/>
+				<x-friends :user="user"/>
+				<x-followers-you-know v-if="$store.getters.isSignedIn && $store.state.i.id != user.id" :user="user"/>
+				<div class="nav"><mk-nav/></div>
+				<p v-if="user.host === null">%i18n:@last-used-at%: <b><mk-time :time="user.lastUsedAt"/></b></p>
+			</div>
+		</main>
 	</div>
 </mk-ui>
 </template>
@@ -73,50 +77,77 @@ export default Vue.extend({
 </script>
 
 <style lang="stylus" scoped>
-.zwwan0di1v4356rmdbjmwnn32tptpdp2
-	display flex
-	justify-content center
+root(isDark)
 	width 980px
 	padding 16px
 	margin 0 auto
 
-	> .main
-	> .side
-		> *:not(:last-child)
-			margin-bottom 16px
+	> .is-suspended
+	> .is-remote
+		margin-bottom 16px
+		padding 14px 16px
+		font-size 14px
+		border-radius 6px
 
-	> .main
-		flex 1
-		margin-right 16px
+		&.is-suspended
+			color isDark ? #ffb4b4 : #570808
+			background isDark ? #611d1d : #ffdbdb
+			border solid 1px isDarl ? #d64a4a : #e09696
 
-		> .timeline
-			border 1px solid rgba(#000, 0.075)
-			border-radius 6px
+		&.is-remote
+			color isDark ? #ffbd3e : #573c08
+			background isDark ? #42321c : #fff0db
+			border solid 1px isDark ? #90733c : #dcbb7b
 
-	> .side
-		width 275px
+		> a
+			font-weight bold
 
-		> p
-			display block
-			margin 0
-			padding 0 12px
-			text-align center
-			font-size 0.8em
-			color #aaa
+	> main
+		display flex
+		justify-content center
 
-		> .nav
-			padding 16px
-			font-size 12px
-			color #aaa
-			background #fff
-			border solid 1px rgba(#000, 0.075)
-			border-radius 6px
+		> .main
+		> .side
+			> *:not(:last-child)
+				margin-bottom 16px
 
-			a
-				color #999
+		> .main
+			flex 1
+			margin-right 16px
 
-			i
-				color #ccc
+			> .timeline
+				border 1px solid rgba(#000, 0.075)
+				border-radius 6px
 
+		> .side
+			width 275px
+
+			> p
+				display block
+				margin 0
+				padding 0 12px
+				text-align center
+				font-size 0.8em
+				color #aaa
+
+			> .nav
+				padding 16px
+				font-size 12px
+				color #aaa
+				background #fff
+				border solid 1px rgba(#000, 0.075)
+				border-radius 6px
+
+				a
+					color #999
+
+				i
+					color #ccc
+
+.zwwan0di1v4356rmdbjmwnn32tptpdp2[data-darkmode]
+	root(true)
+
+.zwwan0di1v4356rmdbjmwnn32tptpdp2:not([data-darkmode])
+	root(false)
 
 </style>

From 50bd1d9a5d92904873fc8064d8d6d5399922aa27 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Thu, 21 Jun 2018 01:58:47 +0900
Subject: [PATCH 15/90] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E3=83=80=E3=82=A4?=
 =?UTF-8?q?=E3=82=A2=E3=83=AD=E3=82=B0=E3=82=92HTML=E3=81=A7=E6=8F=8F?=
 =?UTF-8?q?=E7=94=BB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 locales/ja.yml                                |   1 +
 .../app/common/scripts/check-for-update.ts    |   9 +-
 .../app/desktop/views/pages/user/user.vue     |   4 +-
 src/client/app/mobile/api/dialog.ts           |  19 +-
 src/client/app/mobile/script.ts               |   2 +-
 .../app/mobile/views/components/dialog.vue    | 171 ++++++++++++++++++
 6 files changed, 199 insertions(+), 7 deletions(-)
 create mode 100644 src/client/app/mobile/views/components/dialog.vue

diff --git a/locales/ja.yml b/locales/ja.yml
index 436a97f1eb..052dd59971 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -50,6 +50,7 @@ common:
   delete: "削除"
   loading: "読み込み中"
   ok: "わかった"
+  update-available-title: "更新があります"
   update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
   my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
   i-like-sushi: "私は(プリンよりむしろ)寿司が好き"
diff --git a/src/client/app/common/scripts/check-for-update.ts b/src/client/app/common/scripts/check-for-update.ts
index b5ba6916d1..e2d5b7923b 100644
--- a/src/client/app/common/scripts/check-for-update.ts
+++ b/src/client/app/common/scripts/check-for-update.ts
@@ -23,11 +23,18 @@ export default async function(mios: MiOS, force = false, silent = false) {
 		}
 
 		if (!silent) {
-			alert('%i18n:common.update-available%'.replace('{newer}', newer).replace('{current}', current));
+			mios.apis.dialog({
+				title: '%i18n:common.update-available-title%',
+				text: '%i18n:common.update-available%'.replace('{newer}', newer).replace('{current}', current)
+			});
 		}
 
 		return newer;
 	} else {
+		mios.apis.dialog({
+			title: '%i18n:common.update-available-title%',
+			text: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
+		});
 		return null;
 	}
 }
diff --git a/src/client/app/desktop/views/pages/user/user.vue b/src/client/app/desktop/views/pages/user/user.vue
index 0e0d4f5768..7f05c695af 100644
--- a/src/client/app/desktop/views/pages/user/user.vue
+++ b/src/client/app/desktop/views/pages/user/user.vue
@@ -1,8 +1,8 @@
 <template>
 <mk-ui>
 	<div class="zwwan0di1v4356rmdbjmwnn32tptpdp2" v-if="!fetching" :data-darkmode="$store.state.device.darkmode">
-		<div class="is-suspended" v-if="user.isSuspended || true">%fa:exclamation-triangle% %i18n:@is-suspended%</div>
-		<div class="is-remote" v-if="user.host != null || true">%fa:exclamation-triangle% %i18n:@is-remote%<a :href="user.url || user.uri" target="_blank">%i18n:@view-remote%</a></div>
+		<div class="is-suspended" v-if="user.isSuspended">%fa:exclamation-triangle% %i18n:@is-suspended%</div>
+		<div class="is-remote" v-if="user.host != null">%fa:exclamation-triangle% %i18n:@is-remote%<a :href="user.url || user.uri" target="_blank">%i18n:@view-remote%</a></div>
 		<main>
 			<div class="main">
 				<x-header :user="user"/>
diff --git a/src/client/app/mobile/api/dialog.ts b/src/client/app/mobile/api/dialog.ts
index a2378767be..23f35b7aa9 100644
--- a/src/client/app/mobile/api/dialog.ts
+++ b/src/client/app/mobile/api/dialog.ts
@@ -1,5 +1,18 @@
-export default function(opts) {
+import OS from '../../mios';
+import Dialog from '../views/components/dialog.vue';
+
+export default (os: OS) => opts => {
 	return new Promise<string>((res, rej) => {
-		alert('dialog not implemented yet');
+		const o = opts || {};
+		const d = os.new(Dialog, {
+			title: o.title,
+			text: o.text,
+			modal: o.modal,
+			buttons: o.actions
+		});
+		d.$once('clicked', id => {
+			res(id);
+		});
+		document.body.appendChild(d.$el);
 	});
-}
+};
diff --git a/src/client/app/mobile/script.ts b/src/client/app/mobile/script.ts
index cc0a8331ba..cfa9654e61 100644
--- a/src/client/app/mobile/script.ts
+++ b/src/client/app/mobile/script.ts
@@ -88,7 +88,7 @@ init((launch) => {
 	launch(router, os => ({
 		chooseDriveFolder,
 		chooseDriveFile,
-		dialog,
+		dialog: dialog(os),
 		input,
 		post: post(os),
 		notify
diff --git a/src/client/app/mobile/views/components/dialog.vue b/src/client/app/mobile/views/components/dialog.vue
new file mode 100644
index 0000000000..9ee01cb782
--- /dev/null
+++ b/src/client/app/mobile/views/components/dialog.vue
@@ -0,0 +1,171 @@
+<template>
+<div class="mk-dialog">
+	<div class="bg" ref="bg" @click="onBgClick"></div>
+	<div class="main" ref="main">
+		<header v-html="title" :class="$style.header"></header>
+		<div class="body" v-html="text"></div>
+		<div class="buttons">
+			<button v-for="button in buttons" @click="click(button)">{{ button.text }}</button>
+		</div>
+	</div>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+import * as anime from 'animejs';
+
+export default Vue.extend({
+	props: {
+		title: {
+			type: String,
+			required: false
+		},
+		text: {
+			type: String,
+			required: true
+		},
+		buttons: {
+			type: Array,
+			default: () => {
+				return [{
+					text: 'OK'
+				}];
+			}
+		},
+		modal: {
+			type: Boolean,
+			default: false
+		}
+	},
+	mounted() {
+		this.$nextTick(() => {
+			(this.$refs.bg as any).style.pointerEvents = 'auto';
+			anime({
+				targets: this.$refs.bg,
+				opacity: 1,
+				duration: 100,
+				easing: 'linear'
+			});
+
+			anime({
+				targets: this.$refs.main,
+				opacity: 1,
+				scale: [1.2, 1],
+				duration: 300,
+				easing: [0, 0.5, 0.5, 1]
+			});
+		});
+	},
+	methods: {
+		click(button) {
+			this.$emit('clicked', button.id);
+			this.close();
+		},
+		close() {
+			(this.$refs.bg as any).style.pointerEvents = 'none';
+			anime({
+				targets: this.$refs.bg,
+				opacity: 0,
+				duration: 300,
+				easing: 'linear'
+			});
+
+			(this.$refs.main as any).style.pointerEvents = 'none';
+			anime({
+				targets: this.$refs.main,
+				opacity: 0,
+				scale: 0.8,
+				duration: 300,
+				easing: [ 0.5, -0.5, 1, 0.5 ],
+				complete: () => this.$destroy()
+			});
+		},
+		onBgClick() {
+			if (!this.modal) {
+				this.close();
+			}
+		}
+	}
+});
+</script>
+
+<style lang="stylus" scoped>
+@import '~const.styl'
+
+.mk-dialog
+	> .bg
+		display block
+		position fixed
+		z-index 8192
+		top 0
+		left 0
+		width 100%
+		height 100%
+		background rgba(#000, 0.7)
+		opacity 0
+		pointer-events none
+
+	> .main
+		display block
+		position fixed
+		z-index 8192
+		top 20%
+		left 0
+		right 0
+		margin 0 auto 0 auto
+		padding 16px
+		width calc(100% - 32px)
+		max-width 300px
+		background #fff
+		opacity 0
+
+		> .body
+			margin 1em 0
+			color #888
+
+		> .buttons
+			> button
+				display inline-block
+				float right
+				margin 0
+				padding 0 10px
+				font-size 1.1em
+				font-weight normal
+				text-decoration none
+				color #888
+				background transparent
+				outline none
+				border none
+				border-radius 0
+				cursor pointer
+				transition color 0.1s ease
+
+				i
+					margin 0 0.375em
+
+				&:hover
+					color $theme-color
+
+				&:active
+					color darken($theme-color, 10%)
+					transition color 0s ease
+
+</style>
+
+<style lang="stylus" module>
+@import '~const.styl'
+
+.header
+	margin 0 0 1em 0
+	color $theme-color
+	// color #43A4EC
+	font-weight bold
+
+	&:empty
+		display none
+
+	> i
+		margin-right 0.5em
+
+</style>

From 75f8d5e7d9ddc4624280d0966e77ab82a4bd1c24 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Thu, 21 Jun 2018 02:03:25 +0900
Subject: [PATCH 16/90] :v:

---
 src/client/app/common/scripts/check-for-update.ts | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/src/client/app/common/scripts/check-for-update.ts b/src/client/app/common/scripts/check-for-update.ts
index e2d5b7923b..4445eefc39 100644
--- a/src/client/app/common/scripts/check-for-update.ts
+++ b/src/client/app/common/scripts/check-for-update.ts
@@ -31,10 +31,6 @@ export default async function(mios: MiOS, force = false, silent = false) {
 
 		return newer;
 	} else {
-		mios.apis.dialog({
-			title: '%i18n:common.update-available-title%',
-			text: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
-		});
 		return null;
 	}
 }

From c3679a84e5c5f6f922c74a609957b4cdb2c1748b Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Thu, 21 Jun 2018 02:12:20 +0900
Subject: [PATCH 17/90] :v:

---
 package.json | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/package.json b/package.json
index ad312b8715..c46632b6fc 100644
--- a/package.json
+++ b/package.json
@@ -34,8 +34,9 @@
 		"@types/debug": "0.0.30",
 		"@types/deep-equal": "1.0.1",
 		"@types/elasticsearch": "5.0.24",
+		"@types/file-type": "5.2.1",
 		"@types/gm": "1.18.0",
-		"@types/gulp": "4.0.5",
+		"@types/gulp": "3.8.36",
 		"@types/gulp-htmlmin": "1.3.32",
 		"@types/gulp-mocha": "0.0.32",
 		"@types/gulp-rename": "0.0.33",
@@ -46,6 +47,7 @@
 		"@types/is-root": "1.0.0",
 		"@types/is-url": "1.2.28",
 		"@types/js-yaml": "3.11.1",
+		"@types/jsdom": "11.0.6",
 		"@types/koa": "2.0.46",
 		"@types/koa-bodyparser": "4.2.0",
 		"@types/koa-compress": "2.0.8",
@@ -215,14 +217,13 @@
 		"webpack-cli": "3.0.8",
 		"websocket": "1.0.26",
 		"ws": "5.2.0",
-		"xev": "2.0.1",
-		"@types/file-type": "5.2.1",
-		"@types/jsdom": "11.0.6"
+		"xev": "2.0.1"
 	},
 	"greenkeeper": {
 		"ignore": [
 			"deepcopy",
-			"cafy"
+			"cafy",
+			"@types/gulp"
 		]
 	}
 }

From 09f3a10b467d5e296ac2201974786f6232ea09d2 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Thu, 21 Jun 2018 02:14:26 +0900
Subject: [PATCH 18/90] 4.5.0

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

diff --git a/package.json b/package.json
index c46632b6fc..782ffa0452 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "4.4.0",
-	"clientVersion": "1.0.6655",
+	"version": "4.5.0",
+	"clientVersion": "1.0.6668",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,

From 0105587d045906bb0425a992b98816f994bb91a8 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Wed, 20 Jun 2018 20:49:11 +0000
Subject: [PATCH 19/90] fix(package): update ts-node to version 6.1.2

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

diff --git a/package.json b/package.json
index 782ffa0452..c57d1493a4 100644
--- a/package.json
+++ b/package.json
@@ -193,7 +193,7 @@
 		"textarea-caret": "3.1.0",
 		"tmp": "0.0.33",
 		"ts-loader": "4.4.1",
-		"ts-node": "6.1.1",
+		"ts-node": "6.1.2",
 		"tslint": "5.10.0",
 		"typescript": "2.9.2",
 		"typescript-eslint-parser": "16.0.0",

From 370f6384d9a8ac95209da4c901133861c947d4fa Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Wed, 20 Jun 2018 21:58:40 +0000
Subject: [PATCH 20/90] fix(package): update web-push to version 3.3.2

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

diff --git a/package.json b/package.json
index 782ffa0452..4a343bc3a7 100644
--- a/package.json
+++ b/package.json
@@ -211,7 +211,7 @@
 		"vuedraggable": "2.16.0",
 		"vuex": "3.0.1",
 		"vuex-persistedstate": "^2.5.4",
-		"web-push": "3.3.1",
+		"web-push": "3.3.2",
 		"webfinger.js": "2.6.6",
 		"webpack": "4.12.0",
 		"webpack-cli": "3.0.8",

From 54548c3ed0d2215143fcec7c5909d89345f042b0 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Thu, 21 Jun 2018 00:21:18 +0000
Subject: [PATCH 21/90] fix(package): update @types/koa-bodyparser to version
 5.0.0

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

diff --git a/package.json b/package.json
index 1eb3b6d378..0562cac7b3 100644
--- a/package.json
+++ b/package.json
@@ -49,7 +49,7 @@
 		"@types/js-yaml": "3.11.1",
 		"@types/jsdom": "11.0.6",
 		"@types/koa": "2.0.46",
-		"@types/koa-bodyparser": "4.2.0",
+		"@types/koa-bodyparser": "5.0.0",
 		"@types/koa-compress": "2.0.8",
 		"@types/koa-favicon": "2.0.19",
 		"@types/koa-logger": "3.1.0",

From cde7d0f463e946e2382b9999a4490785ef6c7a25 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Thu, 21 Jun 2018 00:29:15 +0000
Subject: [PATCH 22/90] fix(package): update @types/koa-router to version
 7.0.29

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

diff --git a/package.json b/package.json
index 1eb3b6d378..db1e0e3395 100644
--- a/package.json
+++ b/package.json
@@ -55,7 +55,7 @@
 		"@types/koa-logger": "3.1.0",
 		"@types/koa-mount": "3.0.1",
 		"@types/koa-multer": "1.0.0",
-		"@types/koa-router": "7.0.28",
+		"@types/koa-router": "7.0.29",
 		"@types/koa-send": "4.1.1",
 		"@types/koa-views": "2.0.3",
 		"@types/koa__cors": "2.2.2",

From c24b5410bc0cba09f7e5a36e0c50da18fed56e1a Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Thu, 21 Jun 2018 00:38:08 +0000
Subject: [PATCH 23/90] fix(package): update @types/mocha to version 5.2.3

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

diff --git a/package.json b/package.json
index 1eb3b6d378..925b07d67b 100644
--- a/package.json
+++ b/package.json
@@ -62,7 +62,7 @@
 		"@types/kue": "0.11.9",
 		"@types/license-checker": "15.0.0",
 		"@types/mkdirp": "0.5.2",
-		"@types/mocha": "5.2.2",
+		"@types/mocha": "5.2.3",
 		"@types/mongodb": "3.0.21",
 		"@types/ms": "0.7.30",
 		"@types/node": "10.3.4",

From 39779ca8d59bbc4c27bf33b06497c12500c0a22c Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Thu, 21 Jun 2018 00:50:02 +0000
Subject: [PATCH 24/90] fix(package): update @types/webpack to version 4.4.2

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

diff --git a/package.json b/package.json
index bd5ae7b8c8..97c58b685f 100644
--- a/package.json
+++ b/package.json
@@ -80,7 +80,7 @@
 		"@types/speakeasy": "2.0.2",
 		"@types/tmp": "0.0.33",
 		"@types/uuid": "3.4.3",
-		"@types/webpack": "4.4.1",
+		"@types/webpack": "4.4.2",
 		"@types/webpack-stream": "3.2.10",
 		"@types/websocket": "0.0.39",
 		"@types/ws": "5.1.2",

From 87fc6522fb204e9196e34ce62c0ddccfed0b5e57 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Thu, 21 Jun 2018 11:35:28 +0900
Subject: [PATCH 25/90] Improve ServiceWorker notification

---
 .../common/scripts/compose-notification.ts    | 62 ++++++++++--------
 src/client/app/desktop/script.ts              | 36 +++-------
 src/publishers/notify.ts                      | 10 ++-
 src/services/note/create.ts                   | 65 +++++++------------
 src/services/note/reaction/create.ts          | 11 +---
 5 files changed, 77 insertions(+), 107 deletions(-)

diff --git a/src/client/app/common/scripts/compose-notification.ts b/src/client/app/common/scripts/compose-notification.ts
index cc28f75998..2e58649ac2 100644
--- a/src/client/app/common/scripts/compose-notification.ts
+++ b/src/client/app/common/scripts/compose-notification.ts
@@ -20,34 +20,6 @@ export default function(type, data): Notification {
 				icon: data.url + '?thumbnail&size=64'
 			};
 
-		case 'mention':
-			return {
-				title: `${getUserName(data.user)}さんから:`,
-				body: getNoteSummary(data),
-				icon: data.user.avatarUrl + '?thumbnail&size=64'
-			};
-
-		case 'reply':
-			return {
-				title: `${getUserName(data.user)}さんから返信:`,
-				body: getNoteSummary(data),
-				icon: data.user.avatarUrl + '?thumbnail&size=64'
-			};
-
-		case 'quote':
-			return {
-				title: `${getUserName(data.user)}さんが引用:`,
-				body: getNoteSummary(data),
-				icon: data.user.avatarUrl + '?thumbnail&size=64'
-			};
-
-		case 'reaction':
-			return {
-				title: `${getUserName(data.user)}: ${getReactionEmoji(data.reaction)}:`,
-				body: getNoteSummary(data.note),
-				icon: data.user.avatarUrl + '?thumbnail&size=64'
-			};
-
 		case 'unread_messaging_message':
 			return {
 				title: `${getUserName(data.user)}さんからメッセージ:`,
@@ -62,6 +34,40 @@ export default function(type, data): Notification {
 				icon: data.parent.avatarUrl + '?thumbnail&size=64'
 			};
 
+		case 'notification':
+			switch (data.type) {
+				case 'mention':
+					return {
+						title: `${getUserName(data.user)}さんから:`,
+						body: getNoteSummary(data),
+						icon: data.user.avatarUrl + '?thumbnail&size=64'
+					};
+
+				case 'reply':
+					return {
+						title: `${getUserName(data.user)}さんから返信:`,
+						body: getNoteSummary(data),
+						icon: data.user.avatarUrl + '?thumbnail&size=64'
+					};
+
+				case 'quote':
+					return {
+						title: `${getUserName(data.user)}さんが引用:`,
+						body: getNoteSummary(data),
+						icon: data.user.avatarUrl + '?thumbnail&size=64'
+					};
+
+				case 'reaction':
+					return {
+						title: `${getUserName(data.user)}: ${getReactionEmoji(data.reaction)}:`,
+						body: getNoteSummary(data.note),
+						icon: data.user.avatarUrl + '?thumbnail&size=64'
+					};
+
+				default:
+					return null;
+			}
+
 		default:
 			return null;
 	}
diff --git a/src/client/app/desktop/script.ts b/src/client/app/desktop/script.ts
index 201ab0a83d..beb358c7ee 100644
--- a/src/client/app/desktop/script.ts
+++ b/src/client/app/desktop/script.ts
@@ -115,6 +115,15 @@ function registerNotifications(stream: HomeStreamManager) {
 	});
 
 	function attach(connection) {
+		connection.on('notification', notification => {
+			const _n = composeNotification('notification', notification);
+			const n = new Notification(_n.title, {
+				body: _n.body,
+				icon: _n.icon
+			});
+			setTimeout(n.close.bind(n), 6000);
+		});
+
 		connection.on('drive_file_created', file => {
 			const _n = composeNotification('drive_file_created', file);
 			const n = new Notification(_n.title, {
@@ -124,33 +133,6 @@ function registerNotifications(stream: HomeStreamManager) {
 			setTimeout(n.close.bind(n), 5000);
 		});
 
-		connection.on('mention', note => {
-			const _n = composeNotification('mention', note);
-			const n = new Notification(_n.title, {
-				body: _n.body,
-				icon: _n.icon
-			});
-			setTimeout(n.close.bind(n), 6000);
-		});
-
-		connection.on('reply', note => {
-			const _n = composeNotification('reply', note);
-			const n = new Notification(_n.title, {
-				body: _n.body,
-				icon: _n.icon
-			});
-			setTimeout(n.close.bind(n), 6000);
-		});
-
-		connection.on('quote', note => {
-			const _n = composeNotification('quote', note);
-			const n = new Notification(_n.title, {
-				body: _n.body,
-				icon: _n.icon
-			});
-			setTimeout(n.close.bind(n), 6000);
-		});
-
 		connection.on('unread_messaging_message', message => {
 			const _n = composeNotification('unread_messaging_message', message);
 			const n = new Notification(_n.title, {
diff --git a/src/publishers/notify.ts b/src/publishers/notify.ts
index 0e480ef010..5b25fbf8aa 100644
--- a/src/publishers/notify.ts
+++ b/src/publishers/notify.ts
@@ -4,6 +4,7 @@ import Mute from '../models/mute';
 import { pack } from '../models/notification';
 import stream from './stream';
 import User from '../models/user';
+import pushSw from '../publishers/push-sw';
 
 export default (
 	notifiee: mongo.ObjectID,
@@ -26,9 +27,10 @@ export default (
 
 	resolve(notification);
 
+	const packed = await pack(notification);
+
 	// Publish notification event
-	stream(notifiee, 'notification',
-		await pack(notification));
+	stream(notifiee, 'notification', packed);
 
 	// Update flag
 	User.update({ _id: notifiee }, {
@@ -52,7 +54,9 @@ export default (
 			}
 			//#endregion
 
-			stream(notifiee, 'unread_notification', await pack(notification));
+			stream(notifiee, 'unread_notification', packed);
+
+			pushSw(notifiee, 'notification', packed);
 		}
 	}, 3000);
 });
diff --git a/src/services/note/create.ts b/src/services/note/create.ts
index 782ac5a4fe..feabe2f0b7 100644
--- a/src/services/note/create.ts
+++ b/src/services/note/create.ts
@@ -12,7 +12,6 @@ import notify from '../../publishers/notify';
 import NoteWatching from '../../models/note-watching';
 import watch from './watch';
 import Mute from '../../models/mute';
-import pushSw from '../../publishers/push-sw';
 import event from '../../publishers/stream';
 import parse from '../../mfm/parse';
 import { IApp } from '../../models/app';
@@ -20,56 +19,56 @@ import UserList from '../../models/user-list';
 import resolveUser from '../../remote/resolve-user';
 import Meta from '../../models/meta';
 
-type Reason = 'reply' | 'quote' | 'mention';
+type Type = 'reply' | 'renote' | 'quote' | 'mention';
 
 /**
- * ServiceWorkerへの通知を担当
+ * 通知を担当
  */
 class NotificationManager {
-	private user: IUser;
+	private notifier: IUser;
 	private note: any;
-	private list: Array<{
-		user: ILocalUser['_id'],
-		reason: Reason;
+	private queue: Array<{
+		notifiee: ILocalUser['_id'],
+		type: Type;
 	}> = [];
 
-	constructor(user: IUser, note: any) {
-		this.user = user;
+	constructor(notifier: IUser, note: any) {
+		this.notifier = notifier;
 		this.note = note;
 	}
 
-	public push(user: ILocalUser['_id'], reason: Reason) {
+	public push(notifiee: ILocalUser['_id'], type: Type) {
 		// 自分自身へは通知しない
-		if (this.user._id.equals(user)) return;
+		if (this.notifier._id.equals(notifiee)) return;
 
-		const exist = this.list.find(x => x.user.equals(user));
+		const exist = this.queue.find(x => x.notifiee.equals(notifiee));
 
 		if (exist) {
 			// 「メンションされているかつ返信されている」場合は、メンションとしての通知ではなく返信としての通知にする
-			if (reason != 'mention') {
-				exist.reason = reason;
+			if (type != 'mention') {
+				exist.type = type;
 			}
 		} else {
-			this.list.push({
-				user, reason
+			this.queue.push({
+				notifiee, type
 			});
 		}
 	}
 
 	public deliver() {
-		this.list.forEach(async x => {
-			const mentionee = x.user;
-
+		this.queue.forEach(async x => {
 			// ミュート情報を取得
 			const mentioneeMutes = await Mute.find({
-				muterId: mentionee
+				muterId: x.notifiee
 			});
 
 			const mentioneesMutedUserIds = mentioneeMutes.map(m => m.muteeId.toString());
 
 			// 通知される側のユーザーが通知する側のユーザーをミュートしていない限りは通知する
-			if (!mentioneesMutedUserIds.includes(this.user._id.toString())) {
-				pushSw(mentionee, x.reason, this.note);
+			if (!mentioneesMutedUserIds.includes(this.notifier._id.toString())) {
+				notify(x.notifiee, this.notifier._id, x.type, {
+					noteId: this.note._id
+				});
 			}
 		});
 	}
@@ -264,10 +263,6 @@ export default async (user: IUser, data: {
 			if (data.renote && data.renote.userId.equals(u._id)) return;
 
 			// Create notification
-			notify(u._id, user._id, 'mention', {
-				noteId: note._id
-			});
-
 			nm.push(u._id, 'mention');
 		});
 
@@ -371,11 +366,6 @@ export default async (user: IUser, data: {
 			}
 		});
 
-		// (自分自身へのリプライでない限りは)通知を作成
-		notify(data.reply.userId, user._id, 'reply', {
-			noteId: note._id
-		});
-
 		// Fetch watchers
 		NoteWatching.find({
 			noteId: data.reply._id,
@@ -388,9 +378,7 @@ export default async (user: IUser, data: {
 			}
 		}).then(watchers => {
 			watchers.forEach(watcher => {
-				notify(watcher.userId, user._id, 'reply', {
-					noteId: note._id
-				});
+				nm.push(watcher.userId, 'reply');
 			});
 		});
 
@@ -399,6 +387,7 @@ export default async (user: IUser, data: {
 			watch(user._id, data.reply);
 		}
 
+		// (自分自身へのリプライでない限りは)通知を作成
 		nm.push(data.reply.userId, 'reply');
 	}
 
@@ -406,9 +395,7 @@ export default async (user: IUser, data: {
 	if (data.renote) {
 		// Notify
 		const type = data.text ? 'quote' : 'renote';
-		notify(data.renote.userId, user._id, type, {
-			noteId: note._id
-		});
+		nm.push(data.renote.userId, type);
 
 		// Fetch watchers
 		NoteWatching.find({
@@ -420,9 +407,7 @@ export default async (user: IUser, data: {
 			}
 		}).then(watchers => {
 			watchers.forEach(watcher => {
-				notify(watcher.userId, user._id, type, {
-					noteId: note._id
-				});
+				nm.push(watcher.userId, type);
 			});
 		});
 
diff --git a/src/services/note/reaction/create.ts b/src/services/note/reaction/create.ts
index 5b30bb5e15..b3235e94dc 100644
--- a/src/services/note/reaction/create.ts
+++ b/src/services/note/reaction/create.ts
@@ -1,9 +1,8 @@
-import { IUser, pack as packUser, isLocalUser, isRemoteUser } from '../../../models/user';
-import Note, { INote, pack as packNote } from '../../../models/note';
+import { IUser, isLocalUser, isRemoteUser } from '../../../models/user';
+import Note, { INote } from '../../../models/note';
 import NoteReaction from '../../../models/note-reaction';
 import { publishNoteStream } from '../../../publishers/stream';
 import notify from '../../../publishers/notify';
-import pushSw from '../../../publishers/push-sw';
 import NoteWatching from '../../../models/note-watching';
 import watch from '../watch';
 import renderLike from '../../../remote/activitypub/renderer/like';
@@ -54,12 +53,6 @@ export default async (user: IUser, note: INote, reaction: string) => new Promise
 		});
 	}
 
-	pushSw(note.userId, 'reaction', {
-		user: await packUser(user, note.userId),
-		note: await packNote(note, note.userId),
-		reaction: reaction
-	});
-
 	// Fetch watchers
 	NoteWatching
 		.find({

From b54539b647f29d4dc13a6187a84a38bfe211766a Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Thu, 21 Jun 2018 11:37:18 +0900
Subject: [PATCH 26/90] Fix bug

---
 src/client/app/desktop/views/components/notes.vue      | 3 +++
 src/client/app/desktop/views/pages/deck/deck.notes.vue | 3 +++
 2 files changed, 6 insertions(+)

diff --git a/src/client/app/desktop/views/components/notes.vue b/src/client/app/desktop/views/components/notes.vue
index 5c595c4ca5..1206eb7136 100644
--- a/src/client/app/desktop/views/components/notes.vue
+++ b/src/client/app/desktop/views/components/notes.vue
@@ -11,6 +11,7 @@
 
 	<!-- トランジションを有効にするとなぜかメモリリークする -->
 	<!--<transition-group name="mk-notes" class="transition">-->
+	<div class="notes">
 		<template v-for="(note, i) in _notes">
 			<x-note :note="note" :key="note.id" @update:note="onNoteUpdated(i, $event)"/>
 			<p class="date" :key="note.id + '_date'" v-if="i != notes.length - 1 && note._date != _notes[i + 1]._date">
@@ -18,6 +19,7 @@
 				<span>%fa:angle-down%{{ _notes[i + 1]._datetext }}</span>
 			</p>
 		</template>
+	</div>
 	<!--</transition-group>-->
 
 	<footer v-if="more">
@@ -222,6 +224,7 @@ root(isDark)
 		> *
 			transition transform .3s ease, opacity .3s ease
 
+	> .notes
 		> .date
 			display block
 			margin 0
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 c135c6cd5a..a5ed45b64c 100644
--- a/src/client/app/desktop/views/pages/deck/deck.notes.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.notes.vue
@@ -9,6 +9,7 @@
 
 	<!-- トランジションを有効にするとなぜかメモリリークする -->
 	<!--<transition-group name="mk-notes" class="transition">-->
+	<div class="notes">
 		<template v-for="(note, i) in _notes">
 			<x-note :note="note" :key="note.id" @update:note="onNoteUpdated(i, $event)" :media-view="mediaView"/>
 			<p class="date" :key="note.id + '_date'" v-if="i != notes.length - 1 && note._date != _notes[i + 1]._date">
@@ -16,6 +17,7 @@
 				<span>%fa:angle-down%{{ _notes[i + 1]._datetext }}</span>
 			</p>
 		</template>
+	</div>
 	<!--</transition-group>-->
 
 	<footer v-if="more">
@@ -199,6 +201,7 @@ root(isDark)
 		> *
 			transition transform .3s ease, opacity .3s ease
 
+	> .notes
 		> .date
 			display block
 			margin 0

From f92c116564d989486cbd9d5ab606bbc4e41ddb8d Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Thu, 21 Jun 2018 11:39:54 +0900
Subject: [PATCH 27/90] 4.6.0

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

diff --git a/package.json b/package.json
index 97c58b685f..99f8956838 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "4.5.0",
-	"clientVersion": "1.0.6668",
+	"version": "4.6.0",
+	"clientVersion": "1.0.6707",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,

From 5b015778101e0ad5201bcf3d9aa10400df211eae Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Thu, 21 Jun 2018 19:59:33 +0900
Subject: [PATCH 28/90] Improve note-header

---
 src/client/app/common/views/components/note-header.vue | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/client/app/common/views/components/note-header.vue b/src/client/app/common/views/components/note-header.vue
index 6e64a6a6d3..48997f5df6 100644
--- a/src/client/app/common/views/components/note-header.vue
+++ b/src/client/app/common/views/components/note-header.vue
@@ -85,6 +85,7 @@ root(isDark)
 			color isDark ? #d42c41 : #f56a7b
 
 	> .username
+		flex-shrink 10000
 		margin 0 .5em 0 0
 		overflow hidden
 		text-overflow ellipsis

From d6ef923134ea633d28842e72baf7d36abb8002f5 Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Thu, 21 Jun 2018 21:19:54 +0900
Subject: [PATCH 29/90] :v:

---
 src/client/app/common/views/components/note-header.vue | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/client/app/common/views/components/note-header.vue b/src/client/app/common/views/components/note-header.vue
index 48997f5df6..4669347376 100644
--- a/src/client/app/common/views/components/note-header.vue
+++ b/src/client/app/common/views/components/note-header.vue
@@ -57,6 +57,7 @@ root(isDark)
 
 	> .name
 		display block
+		flex-shrink 0
 		margin 0 .5em 0 0
 		padding 0
 		overflow hidden
@@ -72,6 +73,7 @@ root(isDark)
 	> .is-admin
 	> .is-bot
 	> .is-cat
+		flex-shrink 0
 		align-self center
 		margin 0 .5em 0 0
 		padding 1px 6px
@@ -85,7 +87,6 @@ root(isDark)
 			color isDark ? #d42c41 : #f56a7b
 
 	> .username
-		flex-shrink 10000
 		margin 0 .5em 0 0
 		overflow hidden
 		text-overflow ellipsis

From f1f9f235c7d4260711ad974413461113ac24b337 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Fri, 22 Jun 2018 02:13:16 +0900
Subject: [PATCH 30/90] Update README.md

---
 README.md | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/README.md b/README.md
index 0f3296d032..3478936805 100644
--- a/README.md
+++ b/README.md
@@ -49,9 +49,9 @@ If you want to...
 [![Backers][backers-image]][support-url]
 [![Sponsors][sponsors-image]][support-url]
 
-| ![][ooo-icon] |
-|:-:|
-| [ooo][ooo-link] |
+| ![][nagarus-icon] | ![][dansup-icon] |
+|:-:|:-:|
+| [nagarus][nagarus-link] | [dansup][dansup-link] |
 
 :four_leaf_clover: Copyright
 ----------------------------------------------------------------
@@ -82,5 +82,8 @@ Misskey is an open-source software licensed under [GNU AGPLv3](LICENSE).
 [syuilo-link]:      https://syuilo.com
 [syuilo-icon]:      https://avatars2.githubusercontent.com/u/4439005?v=3&s=70
 
-[ooo-link]:   https://www.patreon.com/user/creators?u=11601413
-[ooo-icon]:   https://c10.patreonusercontent.com/3/eyJ2IjoiMSIsInciOjIwMH0%3D/patreon-media/user/11601413/20cb15f209924302b399b99d3c98b850?token-time=2145916800&token-hash=IO31nK6VZCMWBWU2VAk2c824BX2QZ4DNPKyHHZXS0iw%3D
+[nagarus-link]: https://www.patreon.com/user/creators?u=11601413
+[nagarus-icon]: https://c10.patreonusercontent.com/3/eyJ2IjoiMSIsInciOjIwMH0%3D/patreon-media/user/11601413/20cb15f209924302b399b99d3c98b850?token-time=2145916800&token-hash=IO31nK6VZCMWBWU2VAk2c824BX2QZ4DNPKyHHZXS0iw%3D
+[dansup-link]: https://www.patreon.com/dansup
+[dansup-icon]: https://c10.patreonusercontent.com/3/eyJ2IjoiMSIsInciOjIwMH0%3D/patreon-media/user/4503830/ccf2cc867ea64de0b524bb2e24b9a1cb?token-time=2145916800&token-hash=opXAM_pnhUTuN1jCA6p_Nn_YsaqohY465YFjWFqMEEE%3D
+

From 90e6feeb4c71749caa9fba12ef1b21a2693ce4b7 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Fri, 22 Jun 2018 01:51:01 +0000
Subject: [PATCH 31/90] fix(package): update @types/koa-router to version
 7.0.30

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

diff --git a/package.json b/package.json
index 99f8956838..572045a976 100644
--- a/package.json
+++ b/package.json
@@ -55,7 +55,7 @@
 		"@types/koa-logger": "3.1.0",
 		"@types/koa-mount": "3.0.1",
 		"@types/koa-multer": "1.0.0",
-		"@types/koa-router": "7.0.29",
+		"@types/koa-router": "7.0.30",
 		"@types/koa-send": "4.1.1",
 		"@types/koa-views": "2.0.3",
 		"@types/koa__cors": "2.2.2",

From 1be279dbaab783246d0ae4cdb812099111ddcb51 Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Fri, 22 Jun 2018 11:15:11 +0900
Subject: [PATCH 32/90] revert :v: d6ef92

---
 src/client/app/common/views/components/note-header.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/client/app/common/views/components/note-header.vue b/src/client/app/common/views/components/note-header.vue
index 4669347376..3af92f3362 100644
--- a/src/client/app/common/views/components/note-header.vue
+++ b/src/client/app/common/views/components/note-header.vue
@@ -57,7 +57,6 @@ root(isDark)
 
 	> .name
 		display block
-		flex-shrink 0
 		margin 0 .5em 0 0
 		padding 0
 		overflow hidden
@@ -91,6 +90,7 @@ root(isDark)
 		overflow hidden
 		text-overflow ellipsis
 		color isDark ? #606984 : #ccc
+		flex-shrink 10000
 
 	> .info
 		margin-left auto

From fb1d727db95816182a0184bf449051ff94694bac Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Fri, 22 Jun 2018 13:20:27 +0900
Subject: [PATCH 33/90] =?UTF-8?q?trifling=20style=20changes=20=E6=8A=95?=
 =?UTF-8?q?=E7=A8=BF=E3=81=AE=E3=82=BF=E3=82=B0=E3=81=AE=E3=83=9E=E3=83=BC?=
 =?UTF-8?q?=E3=82=B8=E3=83=B3=E3=81=A8=E8=89=B2=E3=81=AE=E6=9C=80=E9=81=A9?=
 =?UTF-8?q?=E5=8C=96=20=E3=83=A6=E3=83=BC=E3=82=B6=E3=83=BC=E3=83=9A?=
 =?UTF-8?q?=E3=83=BC=E3=82=B8=E3=81=AE=E4=BF=AE=E6=AD=A3(=E5=B9=85?=
 =?UTF-8?q?=E3=81=8C=E4=BC=B8=E3=81=B3=E3=82=8B=E3=80=81profile=E3=81=AE?=
 =?UTF-8?q?=E8=89=B2)=20=E3=82=A6=E3=82=A7=E3=83=AB=E3=82=AB=E3=83=A0?=
 =?UTF-8?q?=E3=83=9A=E3=83=BC=E3=82=B8=E3=81=AE=E4=BF=AE=E6=AD=A3(?=
 =?UTF-8?q?=E3=83=80=E3=83=BC=E3=82=AF=E3=83=A2=E3=83=BC=E3=83=89=E6=99=82?=
 =?UTF-8?q?)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../app/desktop/views/components/notes.note.vue  |  4 ++--
 .../app/desktop/views/pages/deck/deck.note.vue   |  4 ++--
 .../desktop/views/pages/user/user.profile.vue    | 16 ++++++++--------
 src/client/app/desktop/views/pages/user/user.vue |  3 ++-
 src/client/app/desktop/views/pages/welcome.vue   |  2 +-
 src/client/app/mobile/views/components/note.vue  |  4 ++--
 6 files changed, 17 insertions(+), 16 deletions(-)

diff --git a/src/client/app/desktop/views/components/notes.note.vue b/src/client/app/desktop/views/components/notes.note.vue
index b96ae2da5a..3727d7d278 100644
--- a/src/client/app/desktop/views/components/notes.note.vue
+++ b/src/client/app/desktop/views/components/notes.note.vue
@@ -473,10 +473,10 @@ root(isDark)
 
 						> *
 							display inline-block
-							margin 0 8px 0 0
+							margin 0 0 4px 6px
 							padding 2px 8px 2px 16px
 							font-size 90%
-							color #8d969e
+							color #f66e4f
 							background isDark ? #313543 : #edf0f3
 							border-radius 4px
 
diff --git a/src/client/app/desktop/views/pages/deck/deck.note.vue b/src/client/app/desktop/views/pages/deck/deck.note.vue
index d50fc3c235..8b014fe942 100644
--- a/src/client/app/desktop/views/pages/deck/deck.note.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.note.vue
@@ -381,10 +381,10 @@ root(isDark)
 
 						> *
 							display inline-block
-							margin 0 8px 0 0
+							margin 0 0 4px 6px
 							padding 2px 8px 2px 16px
 							font-size 90%
-							color #8d969e
+							color #f66e4f
 							background isDark ? #313543 : #edf0f3
 							border-radius 4px
 
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 8afa7122b3..21f3c57c75 100644
--- a/src/client/app/desktop/views/pages/user/user.profile.vue
+++ b/src/client/app/desktop/views/pages/user/user.profile.vue
@@ -126,7 +126,7 @@ root(isDark)
 	> .friend-form
 		padding 16px
 		text-align center
-		border-top solid 1px #eee
+		border-bottom solid 1px isDark ? #21242f : #eee
 
 		> .followed
 			margin 12px 0 0 0
@@ -144,7 +144,7 @@ root(isDark)
 	> .action-form
 		padding 16px
 		text-align center
-		border-top solid 1px #eee
+		border-bottom solid 1px isDark ? #21242f : #eee
 
 		> *
 			width 100%
@@ -154,8 +154,8 @@ root(isDark)
 
 	> .birthday
 		padding 16px
-		color #555
-		border-top solid 1px #eee
+		color isDark ? #e3e7ea : #555
+		border-bottom solid 1px isDark ? #21242f : #eee
 
 		> p
 			margin 0
@@ -165,8 +165,8 @@ root(isDark)
 
 	> .twitter
 		padding 16px
-		color #555
-		border-top solid 1px #eee
+		color isDark ? #e3e7ea : #555
+		border-bottom solid 1px isDark ? #21242f : #eee
 
 		> p
 			margin 0
@@ -176,8 +176,8 @@ root(isDark)
 
 	> .status
 		padding 16px
-		color #555
-		border-top solid 1px #eee
+		color isDark ? #e3e7ea : #555
+		border-bottom solid 1px isDark ? #21242f : #eee
 
 		> p
 			margin 8px 0
diff --git a/src/client/app/desktop/views/pages/user/user.vue b/src/client/app/desktop/views/pages/user/user.vue
index 7f05c695af..c8a04c6b04 100644
--- a/src/client/app/desktop/views/pages/user/user.vue
+++ b/src/client/app/desktop/views/pages/user/user.vue
@@ -92,7 +92,7 @@ root(isDark)
 		&.is-suspended
 			color isDark ? #ffb4b4 : #570808
 			background isDark ? #611d1d : #ffdbdb
-			border solid 1px isDarl ? #d64a4a : #e09696
+			border solid 1px isDark ? #d64a4a : #e09696
 
 		&.is-remote
 			color isDark ? #ffbd3e : #573c08
@@ -105,6 +105,7 @@ root(isDark)
 	> main
 		display flex
 		justify-content center
+		width 673px
 
 		> .main
 		> .side
diff --git a/src/client/app/desktop/views/pages/welcome.vue b/src/client/app/desktop/views/pages/welcome.vue
index 029e44e27c..2203efcc92 100644
--- a/src/client/app/desktop/views/pages/welcome.vue
+++ b/src/client/app/desktop/views/pages/welcome.vue
@@ -199,7 +199,7 @@ root(isDark)
 				> .login
 					width $loginWidth
 					padding 16px 32px 32px 32px
-					background #f5f5f5
+					background isDark ? #2e3440 : #f5f5f5
 
 			> .info
 				margin 16px auto
diff --git a/src/client/app/mobile/views/components/note.vue b/src/client/app/mobile/views/components/note.vue
index ecdfee3b44..76ac9a1310 100644
--- a/src/client/app/mobile/views/components/note.vue
+++ b/src/client/app/mobile/views/components/note.vue
@@ -424,10 +424,10 @@ root(isDark)
 
 						> *
 							display inline-block
-							margin 0 8px 0 0
+							margin 0 0 4px 6px
 							padding 2px 8px 2px 16px
 							font-size 90%
-							color #8d969e
+							color #f66e4f
 							background isDark ? #313543 : #edf0f3
 							border-radius 4px
 

From 6f38c6f33999b64d06f2aab657e6b1efc9cfea91 Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Fri, 22 Jun 2018 13:37:46 +0900
Subject: [PATCH 34/90] $theme-color

---
 src/client/app/desktop/views/components/notes.note.vue | 2 +-
 src/client/app/desktop/views/pages/deck/deck.note.vue  | 2 +-
 src/client/app/mobile/views/components/note.vue        | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/client/app/desktop/views/components/notes.note.vue b/src/client/app/desktop/views/components/notes.note.vue
index 3727d7d278..6f466e576f 100644
--- a/src/client/app/desktop/views/components/notes.note.vue
+++ b/src/client/app/desktop/views/components/notes.note.vue
@@ -476,7 +476,7 @@ root(isDark)
 							margin 0 0 4px 6px
 							padding 2px 8px 2px 16px
 							font-size 90%
-							color #f66e4f
+							color $theme-color
 							background isDark ? #313543 : #edf0f3
 							border-radius 4px
 
diff --git a/src/client/app/desktop/views/pages/deck/deck.note.vue b/src/client/app/desktop/views/pages/deck/deck.note.vue
index 8b014fe942..617f633f56 100644
--- a/src/client/app/desktop/views/pages/deck/deck.note.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.note.vue
@@ -384,7 +384,7 @@ root(isDark)
 							margin 0 0 4px 6px
 							padding 2px 8px 2px 16px
 							font-size 90%
-							color #f66e4f
+							color $theme-color
 							background isDark ? #313543 : #edf0f3
 							border-radius 4px
 
diff --git a/src/client/app/mobile/views/components/note.vue b/src/client/app/mobile/views/components/note.vue
index 76ac9a1310..bd0a0d1b5e 100644
--- a/src/client/app/mobile/views/components/note.vue
+++ b/src/client/app/mobile/views/components/note.vue
@@ -427,7 +427,7 @@ root(isDark)
 							margin 0 0 4px 6px
 							padding 2px 8px 2px 16px
 							font-size 90%
-							color #f66e4f
+							color $theme-color
 							background isDark ? #313543 : #edf0f3
 							border-radius 4px
 

From 0be8bbc19fafb601d6269ee630915f372d847ab7 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Fri, 22 Jun 2018 17:49:21 +0900
Subject: [PATCH 35/90] Update README.md

---
 README.md | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/README.md b/README.md
index 3478936805..120e9fa5c0 100644
--- a/README.md
+++ b/README.md
@@ -5,8 +5,6 @@
 
 [![][travis-badge]][travis-link]
 [![][dependencies-badge]][dependencies-link]
-[![][himawari-badge]][himasaku]
-[![][sakurako-badge]][himasaku]
 [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) [![Greenkeeper badge](https://badges.greenkeeper.io/syuilo/misskey.svg)](https://greenkeeper.io/)
 
 > Lead Maintainer: [syuilo][syuilo-link]
@@ -67,9 +65,6 @@ Misskey is an open-source software licensed under [GNU AGPLv3](LICENSE).
 [travis-badge]:       http://img.shields.io/travis/syuilo/misskey/master.svg?style=flat-square
 [dependencies-link]:  https://david-dm.org/syuilo/misskey
 [dependencies-badge]: https://img.shields.io/david/syuilo/misskey.svg?style=flat-square
-[himasaku]:           https://himasaku.net
-[himawari-badge]:     https://img.shields.io/badge/%E5%8F%A4%E8%B0%B7-%E5%90%91%E6%97%A5%E8%91%B5-1684c5.svg?style=flat-square
-[sakurako-badge]:     https://img.shields.io/badge/%E5%A4%A7%E5%AE%A4-%E6%AB%BB%E5%AD%90-efb02a.svg?style=flat-square
 
 [backer-url]: #backers
 [backer-badge]: https://opencollective.com/misskey/backers/badge.svg

From 06cfa207fc1ec40c9604b69ede7170cb02d52a15 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Fri, 22 Jun 2018 17:51:36 +0900
Subject: [PATCH 36/90] :v:

---
 src/client/app/common/scripts/can-hide-text.ts   | 16 ----------------
 .../app/desktop/views/components/notes.note.vue  |  5 +----
 .../app/desktop/views/pages/deck/deck.note.vue   |  5 +----
 src/client/app/mobile/views/components/note.vue  |  5 +----
 4 files changed, 3 insertions(+), 28 deletions(-)
 delete mode 100644 src/client/app/common/scripts/can-hide-text.ts

diff --git a/src/client/app/common/scripts/can-hide-text.ts b/src/client/app/common/scripts/can-hide-text.ts
deleted file mode 100644
index 4a4be8d9d0..0000000000
--- a/src/client/app/common/scripts/can-hide-text.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-export default function(note) {
-	if (note.text == null) return true;
-
-	let txt = note.text;
-
-	if (note.media) {
-		note.media.forEach(file => {
-			txt = txt.replace(file.url, '');
-			if (file.src) txt = txt.replace(file.src, '');
-		});
-
-		if (txt == '') return true;
-	}
-
-	return false;
-}
diff --git a/src/client/app/desktop/views/components/notes.note.vue b/src/client/app/desktop/views/components/notes.note.vue
index 6f466e576f..24f8d2f65b 100644
--- a/src/client/app/desktop/views/components/notes.note.vue
+++ b/src/client/app/desktop/views/components/notes.note.vue
@@ -25,7 +25,7 @@
 						<span v-if="p.isHidden" style="opacity: 0.5">%i18n:@private%</span>
 						<span v-if="p.deletedAt" style="opacity: 0.5">%i18n:@deleted%</span>
 						<a class="reply" v-if="p.reply">%fa:reply%</a>
-						<misskey-flavored-markdown v-if="p.text && !canHideText(p)" :text="p.text" :i="$store.state.i" :class="$style.text"/>
+						<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i" :class="$style.text"/>
 						<a class="rp" v-if="p.renote">RP:</a>
 					</div>
 					<div class="media" v-if="p.media.length > 0">
@@ -75,7 +75,6 @@
 <script lang="ts">
 import Vue from 'vue';
 import dateStringify from '../../../common/scripts/date-stringify';
-import canHideText from '../../../common/scripts/can-hide-text';
 import parse from '../../../../../mfm/parse';
 
 import MkPostFormWindow from './post-form-window.vue';
@@ -190,8 +189,6 @@ export default Vue.extend({
 	},
 
 	methods: {
-		canHideText,
-
 		capture(withHandler = false) {
 			if (this.$store.getters.isSignedIn) {
 				this.connection.send({
diff --git a/src/client/app/desktop/views/pages/deck/deck.note.vue b/src/client/app/desktop/views/pages/deck/deck.note.vue
index 617f633f56..f4139c1bd8 100644
--- a/src/client/app/desktop/views/pages/deck/deck.note.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.note.vue
@@ -25,7 +25,7 @@
 						<span v-if="p.isHidden" style="opacity: 0.5">(%i18n:@private%)</span>
 						<span v-if="p.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span>
 						<a class="reply" v-if="p.reply">%fa:reply%</a>
-						<misskey-flavored-markdown v-if="p.text && !canHideText(p)" :text="p.text" :i="$store.state.i"/>
+						<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i"/>
 						<a class="rp" v-if="p.renote != null">RP:</a>
 					</div>
 					<div class="media" v-if="p.media.length > 0">
@@ -68,7 +68,6 @@
 <script lang="ts">
 import Vue from 'vue';
 import parse from '../../../../../../mfm/parse';
-import canHideText from '../../../../common/scripts/can-hide-text';
 
 import MkNoteMenu from '../../../../common/views/components/note-menu.vue';
 import MkReactionPicker from '../../../../common/views/components/reaction-picker.vue';
@@ -148,8 +147,6 @@ export default Vue.extend({
 	},
 
 	methods: {
-		canHideText,
-
 		capture(withHandler = false) {
 			if (this.$store.getters.isSignedIn) {
 				this.connection.send({
diff --git a/src/client/app/mobile/views/components/note.vue b/src/client/app/mobile/views/components/note.vue
index bd0a0d1b5e..c3d4181a5d 100644
--- a/src/client/app/mobile/views/components/note.vue
+++ b/src/client/app/mobile/views/components/note.vue
@@ -25,7 +25,7 @@
 						<span v-if="p.isHidden" style="opacity: 0.5">(%i18n:@private%)</span>
 						<span v-if="p.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span>
 						<a class="reply" v-if="p.reply">%fa:reply%</a>
-						<misskey-flavored-markdown v-if="p.text && !canHideText(p)" :text="p.text" :i="$store.state.i" :class="$style.text"/>
+						<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i" :class="$style.text"/>
 						<a class="rp" v-if="p.renote != null">RP:</a>
 					</div>
 					<div class="media" v-if="p.media.length > 0">
@@ -69,7 +69,6 @@
 <script lang="ts">
 import Vue from 'vue';
 import parse from '../../../../../mfm/parse';
-import canHideText from '../../../common/scripts/can-hide-text';
 
 import MkNoteMenu from '../../../common/views/components/note-menu.vue';
 import MkReactionPicker from '../../../common/views/components/reaction-picker.vue';
@@ -165,8 +164,6 @@ export default Vue.extend({
 	},
 
 	methods: {
-		canHideText,
-
 		capture(withHandler = false) {
 			if (this.$store.getters.isSignedIn) {
 				this.connection.send({

From 16c2aefe7b71ec362a26bd1c12ee458bb6b37948 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Fri, 22 Jun 2018 17:55:58 +0900
Subject: [PATCH 37/90] Clean up: Remove the unused file

---
 src/utils/type.ts | 3 ---
 1 file changed, 3 deletions(-)
 delete mode 100644 src/utils/type.ts

diff --git a/src/utils/type.ts b/src/utils/type.ts
deleted file mode 100644
index ba6ea0be77..0000000000
--- a/src/utils/type.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-// https://github.com/Microsoft/TypeScript/issues/12215
-export type Diff<T extends string, U extends string> = ({ [P in T]: P } & { [P in U]: never } & { [x: string]: never })[T];
-export type Omit<T, K extends keyof T> = { [P in Diff<keyof T, K>]: T[P] };

From 09c5efc161585f0c7443bb6e1cc737397a149dde Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Fri, 22 Jun 2018 18:03:08 +0900
Subject: [PATCH 38/90] :v:

---
 src/client/app/common/views/widgets/hashtags.vue         | 7 +++++--
 .../app/desktop/views/components/notifications.vue       | 9 ++++++---
 src/client/app/mobile/views/components/notes.vue         | 7 +++++--
 src/client/app/mobile/views/components/notifications.vue | 7 +++++--
 4 files changed, 21 insertions(+), 9 deletions(-)

diff --git a/src/client/app/common/views/widgets/hashtags.vue b/src/client/app/common/views/widgets/hashtags.vue
index 9ab855d927..2065bd407c 100644
--- a/src/client/app/common/views/widgets/hashtags.vue
+++ b/src/client/app/common/views/widgets/hashtags.vue
@@ -6,7 +6,9 @@
 		<div class="mkw-hashtags--body" :data-mobile="platform == 'mobile'">
 			<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
 			<p class="empty" v-else-if="stats.length == 0">%fa:exclamation-circle%%i18n:@empty%</p>
-			<transition-group v-else tag="div" name="chart">
+			<!-- トランジションを有効にするとなぜかメモリリークする -->
+			<!-- <transition-group v-else tag="div" name="chart"> -->
+			<div>
 				<div v-for="stat in stats" :key="stat.tag">
 					<div class="tag">
 						<router-link :to="`/tags/${ stat.tag }`" :title="stat.tag">#{{ stat.tag }}</router-link>
@@ -14,7 +16,8 @@
 					</div>
 					<x-chart class="chart" :src="stat.chart"/>
 				</div>
-			</transition-group>
+			</div>
+			<!-- </transition-group> -->
 		</div>
 	</mk-widget-container>
 </div>
diff --git a/src/client/app/desktop/views/components/notifications.vue b/src/client/app/desktop/views/components/notifications.vue
index e479ffadbf..32b36994db 100644
--- a/src/client/app/desktop/views/components/notifications.vue
+++ b/src/client/app/desktop/views/components/notifications.vue
@@ -1,7 +1,9 @@
 <template>
 <div class="mk-notifications">
 	<div class="notifications" v-if="notifications.length != 0">
-		<transition-group name="mk-notifications" class="transition">
+		<!-- トランジションを有効にするとなぜかメモリリークする -->
+		<!-- <transition-group name="mk-notifications" class="transition"> -->
+		<div>
 			<template v-for="(notification, i) in _notifications">
 				<div class="notification" :class="notification.type" :key="notification.id">
 					<mk-time :time="notification.createdAt"/>
@@ -95,7 +97,8 @@
 					<span>%fa:angle-down%{{ _notifications[i + 1]._datetext }}</span>
 				</p>
 			</template>
-		</transition-group>
+		</div>
+		<!-- </transition-group> -->
 	</div>
 	<button class="more" :class="{ fetching: fetchingMoreNotifications }" v-if="moreNotifications" @click="fetchMoreNotifications" :disabled="fetchingMoreNotifications">
 		<template v-if="fetchingMoreNotifications">%fa:spinner .pulse .fw%</template>{{ fetchingMoreNotifications ? '%i18n:common.loading%' : '%i18n:@more%' }}
@@ -201,7 +204,7 @@ root(isDark)
 			transition transform .3s ease, opacity .3s ease
 
 	> .notifications
-		> *
+		> div
 			> .notification
 				margin 0
 				padding 16px
diff --git a/src/client/app/mobile/views/components/notes.vue b/src/client/app/mobile/views/components/notes.vue
index 7aaf0424c7..06d22c7258 100644
--- a/src/client/app/mobile/views/components/notes.vue
+++ b/src/client/app/mobile/views/components/notes.vue
@@ -13,7 +13,9 @@
 		<button @click="resolveInitPromise">%i18n:@retry%</button>
 	</div>
 
-	<transition-group name="mk-notes" class="transition">
+	<!-- トランジションを有効にするとなぜかメモリリークする -->
+	<!-- <transition-group name="mk-notes" class="transition"> -->
+	<div class="transition">
 		<template v-for="(note, i) in _notes">
 			<mk-note :note="note" :key="note.id" @update:note="onNoteUpdated(i, $event)"/>
 			<p class="date" :key="note.id + '_date'" v-if="i != notes.length - 1 && note._date != _notes[i + 1]._date">
@@ -21,7 +23,8 @@
 				<span>%fa:angle-down%{{ _notes[i + 1]._datetext }}</span>
 			</p>
 		</template>
-	</transition-group>
+	</div>
+	<!-- </transition-group> -->
 
 	<footer v-if="more">
 		<button @click="loadMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
diff --git a/src/client/app/mobile/views/components/notifications.vue b/src/client/app/mobile/views/components/notifications.vue
index 6bb9e9bb2c..fc220c252a 100644
--- a/src/client/app/mobile/views/components/notifications.vue
+++ b/src/client/app/mobile/views/components/notifications.vue
@@ -1,6 +1,8 @@
 <template>
 <div class="mk-notifications">
-	<transition-group name="mk-notifications" class="transition notifications">
+	<!-- トランジションを有効にするとなぜかメモリリークする -->
+	<!-- <transition-group name="mk-notifications" class="transition notifications"> -->
+	<div class="transition notifications">
 		<template v-for="(notification, i) in _notifications">
 			<mk-notification :notification="notification" :key="notification.id"/>
 			<p class="date" :key="notification.id + '_date'" v-if="i != notifications.length - 1 && notification._date != _notifications[i + 1]._date">
@@ -8,7 +10,8 @@
 				<span>%fa:angle-down%{{ _notifications[i + 1]._datetext }}</span>
 			</p>
 		</template>
-	</transition-group>
+	</div>
+	<!-- </transition-group> -->
 
 	<button class="more" v-if="moreNotifications" @click="fetchMoreNotifications" :disabled="fetchingMoreNotifications">
 		<template v-if="fetchingMoreNotifications">%fa:spinner .pulse .fw%</template>

From 6037b0acc5541b1fadf5150b037f27890dfa00f0 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Fri, 22 Jun 2018 18:32:21 +0900
Subject: [PATCH 39/90] =?UTF-8?q?=E9=9D=9E=E3=83=AD=E3=82=B0=E3=82=A4?=
 =?UTF-8?q?=E3=83=B3=E6=99=82=E3=81=AE=E3=83=88=E3=83=83=E3=83=97=E3=81=AB?=
 =?UTF-8?q?=E3=83=88=E3=83=AC=E3=83=B3=E3=83=89=E3=82=92=E8=A1=A8=E7=A4=BA?=
 =?UTF-8?q?=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../views/components/welcome-timeline.vue     |  8 +++
 .../app/desktop/views/pages/welcome.vue       | 53 ++++++++++++-------
 src/client/app/mobile/views/pages/welcome.vue | 20 ++++++-
 src/server/api/endpoints.ts                   |  3 +-
 4 files changed, 63 insertions(+), 21 deletions(-)

diff --git a/src/client/app/common/views/components/welcome-timeline.vue b/src/client/app/common/views/components/welcome-timeline.vue
index bf2c653766..5a8b9df476 100644
--- a/src/client/app/common/views/components/welcome-timeline.vue
+++ b/src/client/app/common/views/components/welcome-timeline.vue
@@ -24,6 +24,13 @@
 import Vue from 'vue';
 
 export default Vue.extend({
+	props: {
+		max: {
+			type: Number,
+			required: false,
+			default: undefined
+		}
+	},
 	data() {
 		return {
 			fetching: true,
@@ -37,6 +44,7 @@ export default Vue.extend({
 		fetch(cb?) {
 			this.fetching = true;
 			(this as any).api('notes', {
+				limit: this.max,
 				local: true,
 				reply: false,
 				renote: false,
diff --git a/src/client/app/desktop/views/pages/welcome.vue b/src/client/app/desktop/views/pages/welcome.vue
index 2203efcc92..cac4007b40 100644
--- a/src/client/app/desktop/views/pages/welcome.vue
+++ b/src/client/app/desktop/views/pages/welcome.vue
@@ -7,6 +7,13 @@
 	</button>
 	<div class="body" :style="{ backgroundImage: `url('${ welcomeBgUrl }')` }">
 		<div class="container">
+			<div class="info">
+				<span>%i18n:common.misskey% <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>
+				</span>
+			</div>
 			<main>
 				<div class="about">
 					<h1 v-if="name">{{ name }}</h1>
@@ -19,12 +26,8 @@
 					<mk-signin/>
 				</div>
 			</main>
-			<div class="info">
-				<span>%i18n:common.misskey% <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>
-				</span>
+			<div class="hashtags">
+				<router-link v-for="tag in tags" :key="tag" :to="`/tags/${ tag }`" :title="tag">#{{ tag }}</router-link>
 			</div>
 			<mk-nav class="nav"/>
 		</div>
@@ -32,7 +35,7 @@
 		<img src="assets/title.dark.svg" alt="Misskey">
 	</div>
 	<div class="tl">
-		<mk-welcome-timeline/>
+		<mk-welcome-timeline :max="20"/>
 	</div>
 	<modal name="signup" width="500px" height="auto" scrollable>
 		<header :class="$style.signupFormHeader">%i18n:@signup%</header>
@@ -54,13 +57,18 @@ export default Vue.extend({
 			host,
 			name,
 			description,
-			pointerInterval: null
+			pointerInterval: null,
+			tags: []
 		};
 	},
 	created() {
 		(this as any).api('stats').then(stats => {
 			this.stats = stats;
 		});
+
+		(this as any).api('hashtags/trend').then(stats => {
+			this.tags = stats.map(x => x.tag);
+		});
 	},
 	mounted() {
 		this.point();
@@ -161,6 +169,20 @@ root(isDark)
 			$loginWidth = 340px
 			$width = $aboutWidth + $loginWidth
 
+			> .info
+				margin 0 auto 16px auto
+				width $width
+				font-size 14px
+				color #fff
+
+				> .stats
+					margin-left 16px
+					padding-left 16px
+					border-left solid 1px #fff
+
+					> *
+						margin-right 16px
+
 			> main
 				display flex
 				margin auto
@@ -201,22 +223,17 @@ root(isDark)
 					padding 16px 32px 32px 32px
 					background isDark ? #2e3440 : #f5f5f5
 
-			> .info
+			> .hashtags
 				margin 16px auto
-				padding 12px
 				width $width
 				font-size 14px
 				color #fff
-				background rgba(#000, 0.2)
+				background rgba(#000, 0.3)
 				border-radius 8px
 
-				> .stats
-					margin-left 16px
-					padding-left 16px
-					border-left solid 1px #fff
-
-					> *
-						margin-right 16px
+				> *
+					display inline-block
+					margin 14px
 
 			> .nav
 				display block
diff --git a/src/client/app/mobile/views/pages/welcome.vue b/src/client/app/mobile/views/pages/welcome.vue
index cd8f5841e7..feef2e8c6f 100644
--- a/src/client/app/mobile/views/pages/welcome.vue
+++ b/src/client/app/mobile/views/pages/welcome.vue
@@ -14,6 +14,9 @@
 		<div class="tl">
 			<mk-welcome-timeline/>
 		</div>
+		<div class="hashtags">
+			<router-link v-for="tag in tags" :key="tag" :to="`/tags/${ tag }`" :title="tag">#{{ tag }}</router-link>
+		</div>
 		<div class="stats" v-if="stats">
 			<span>%fa:user% {{ stats.originalUsersCount | number }}</span>
 			<span>%fa:pencil-alt% {{ stats.originalNotesCount | number }}</span>
@@ -37,13 +40,18 @@ export default Vue.extend({
 			stats: null,
 			host,
 			name,
-			description
+			description,
+			tags: []
 		};
 	},
 	created() {
 		(this as any).api('stats').then(stats => {
 			this.stats = stats;
 		});
+
+		(this as any).api('hashtags/trend').then(stats => {
+			this.tags = stats.map(x => x.tag);
+		});
 	}
 });
 </script>
@@ -116,12 +124,22 @@ export default Vue.extend({
 						box-shadow 0 1px 3px rgba(#000, 0.075), inset 0 0 5px rgba(#000, 0.2)
 
 		> .tl
+			margin 16px 0
+
 			> *
 				max-height 300px
 				border-radius 6px
 				overflow auto
 				-webkit-overflow-scrolling touch
 
+		> .hashtags
+			border solid 2px #ddd
+			border-radius 8px
+
+			> *
+				display inline-block
+				margin 16px
+
 		> .stats
 			margin 16px 0
 			padding 8px
diff --git a/src/server/api/endpoints.ts b/src/server/api/endpoints.ts
index a5d13b0237..f613710c80 100644
--- a/src/server/api/endpoints.ts
+++ b/src/server/api/endpoints.ts
@@ -629,8 +629,7 @@ const endpoints: Endpoint[] = [
 	},
 
 	{
-		name: 'hashtags/trend',
-		withCredential: true
+		name: 'hashtags/trend'
 	},
 
 	{

From 9d8391583f21980319303727fa87a5619f3c8df5 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Fri, 22 Jun 2018 18:47:23 +0900
Subject: [PATCH 40/90] :v:

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

diff --git a/src/client/app/desktop/views/pages/user/user.vue b/src/client/app/desktop/views/pages/user/user.vue
index c8a04c6b04..5cea4b99e5 100644
--- a/src/client/app/desktop/views/pages/user/user.vue
+++ b/src/client/app/desktop/views/pages/user/user.vue
@@ -105,7 +105,6 @@ root(isDark)
 	> main
 		display flex
 		justify-content center
-		width 673px
 
 		> .main
 		> .side
@@ -114,6 +113,7 @@ root(isDark)
 
 		> .main
 			flex 1
+			min-width 0 // SEE: http://kudakurage.hatenadiary.com/entry/2016/04/01/232722
 			margin-right 16px
 
 			> .timeline
@@ -122,6 +122,7 @@ root(isDark)
 
 		> .side
 			width 275px
+			flex-shrink 0
 
 			> p
 				display block

From 19bdd4fa2ac5f40d1fee8d264609a254e166f707 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Fri, 22 Jun 2018 18:51:41 +0900
Subject: [PATCH 41/90] 4.7.0

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

diff --git a/package.json b/package.json
index 572045a976..2c84da7779 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "4.6.0",
-	"clientVersion": "1.0.6707",
+	"version": "4.7.0",
+	"clientVersion": "1.0.6728",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,

From 57f62c919ca210e2e7ba11058c08795f7dcc2dc8 Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Fri, 22 Jun 2018 20:55:19 +0900
Subject: [PATCH 42/90] change flex-shrink of .username to 2147483647

---
 src/client/app/common/views/components/note-header.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/client/app/common/views/components/note-header.vue b/src/client/app/common/views/components/note-header.vue
index 3af92f3362..25a3339264 100644
--- a/src/client/app/common/views/components/note-header.vue
+++ b/src/client/app/common/views/components/note-header.vue
@@ -90,7 +90,7 @@ root(isDark)
 		overflow hidden
 		text-overflow ellipsis
 		color isDark ? #606984 : #ccc
-		flex-shrink 10000
+		flex-shrink 2147483647
 
 	> .info
 		margin-left auto

From a7e9d5a60ba541678827e7eeac9f9c40644b4f19 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Fri, 22 Jun 2018 13:55:39 +0000
Subject: [PATCH 43/90] fix(package): update ratelimiter to version 3.1.0

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

diff --git a/package.json b/package.json
index 2c84da7779..5c47dc22e7 100644
--- a/package.json
+++ b/package.json
@@ -170,7 +170,7 @@
 		"pug": "2.0.3",
 		"punycode": "2.1.1",
 		"qrcode": "1.2.0",
-		"ratelimiter": "3.0.3",
+		"ratelimiter": "3.1.0",
 		"recaptcha-promise": "0.1.3",
 		"reconnecting-websocket": "3.2.2",
 		"redis": "2.8.0",

From 3c3c67a34c76875b71e70c1d9f9d9d490e127af6 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Fri, 22 Jun 2018 19:17:54 +0000
Subject: [PATCH 44/90] fix(package): update ts-node to version 7.0.0

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

diff --git a/package.json b/package.json
index 5c47dc22e7..b61c701b54 100644
--- a/package.json
+++ b/package.json
@@ -193,7 +193,7 @@
 		"textarea-caret": "3.1.0",
 		"tmp": "0.0.33",
 		"ts-loader": "4.4.1",
-		"ts-node": "6.1.2",
+		"ts-node": "7.0.0",
 		"tslint": "5.10.0",
 		"typescript": "2.9.2",
 		"typescript-eslint-parser": "16.0.0",

From c6cbadc514dbaf0890f30a20e90ee2ccf5a83eac Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Sat, 23 Jun 2018 00:27:09 +0000
Subject: [PATCH 45/90] fix(package): update @types/node to version 10.3.5

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

diff --git a/package.json b/package.json
index 5c47dc22e7..5a5d715124 100644
--- a/package.json
+++ b/package.json
@@ -65,7 +65,7 @@
 		"@types/mocha": "5.2.3",
 		"@types/mongodb": "3.0.21",
 		"@types/ms": "0.7.30",
-		"@types/node": "10.3.4",
+		"@types/node": "10.3.5",
 		"@types/nopt": "3.0.29",
 		"@types/parse5": "5.0.0",
 		"@types/pug": "2.0.4",

From 40235463bcd9f5b66e02258d322f257b4f9c3cd1 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 23 Jun 2018 11:30:18 +0900
Subject: [PATCH 46/90] Fix

---
 src/client/app/mobile/views/pages/welcome.vue | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/client/app/mobile/views/pages/welcome.vue b/src/client/app/mobile/views/pages/welcome.vue
index feef2e8c6f..ec21588ade 100644
--- a/src/client/app/mobile/views/pages/welcome.vue
+++ b/src/client/app/mobile/views/pages/welcome.vue
@@ -133,12 +133,12 @@ export default Vue.extend({
 				-webkit-overflow-scrolling touch
 
 		> .hashtags
+			padding 16px 0
 			border solid 2px #ddd
 			border-radius 8px
 
 			> *
-				display inline-block
-				margin 16px
+				margin 0 16px
 
 		> .stats
 			margin 16px 0

From 60229d73c970b11f58182fb0c4ad9e36e9896cf8 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Sat, 23 Jun 2018 02:35:38 +0000
Subject: [PATCH 47/90] fix(package): update hard-source-webpack-plugin to
 version 0.9.0

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

diff --git a/package.json b/package.json
index 5c47dc22e7..eab1f0940d 100644
--- a/package.json
+++ b/package.json
@@ -124,7 +124,7 @@
 		"gulp-typescript": "4.0.2",
 		"gulp-uglify": "3.0.0",
 		"gulp-util": "3.0.8",
-		"hard-source-webpack-plugin": "0.8.1",
+		"hard-source-webpack-plugin": "0.9.0",
 		"highlight.js": "9.12.0",
 		"html-minifier": "3.5.16",
 		"http-signature": "1.2.0",

From e2c3d4f2fb9b9d1cfff2c358d0be54c45b0c804a Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Sat, 23 Jun 2018 02:46:37 +0000
Subject: [PATCH 48/90] fix(package): update eslint to version 5.0.0

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

diff --git a/package.json b/package.json
index 5c47dc22e7..d4ba3406f0 100644
--- a/package.json
+++ b/package.json
@@ -102,7 +102,7 @@
 		"element-ui": "2.4.1",
 		"emojilib": "2.2.12",
 		"escape-regexp": "0.0.1",
-		"eslint": "4.19.1",
+		"eslint": "5.0.0",
 		"eslint-plugin-vue": "4.5.0",
 		"eventemitter3": "3.1.0",
 		"exif-js": "2.3.0",

From 24d8617f812a97cdc095b4d22ff7c126a1e1f8cc Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 23 Jun 2018 12:09:09 +0900
Subject: [PATCH 49/90] Fix bug

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

diff --git a/src/client/app/desktop/views/components/home.vue b/src/client/app/desktop/views/components/home.vue
index ba48ce24e8..ab276d3c4b 100644
--- a/src/client/app/desktop/views/components/home.vue
+++ b/src/client/app/desktop/views/components/home.vue
@@ -66,7 +66,7 @@
 			</div>
 			<div class="main">
 				<mk-post-form class="form" v-if="$store.state.settings.showPostFormOnTopOfTl"/>
-				<mk-timeline class="tl" cref="tl" @loaded="onTlLoaded" v-if="mode == 'timeline'"/>
+				<mk-timeline class="tl" ref="tl" @loaded="onTlLoaded" v-if="mode == 'timeline'"/>
 			</div>
 		</template>
 	</div>

From 328dc80324a788b92e77b811036a8f938c351d09 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 23 Jun 2018 12:09:58 +0900
Subject: [PATCH 50/90] 4.7.1

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

diff --git a/package.json b/package.json
index 5c47dc22e7..23a7a5b498 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "4.7.0",
-	"clientVersion": "1.0.6728",
+	"version": "4.7.1",
+	"clientVersion": "1.0.6735",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,

From 2c0b13784891c0e7f75109051c0411c6bdaf4caf Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 23 Jun 2018 16:55:52 +0900
Subject: [PATCH 51/90] =?UTF-8?q?=E3=83=AA=E3=83=90=E3=83=BC=E3=82=B7?=
 =?UTF-8?q?=E3=81=AE=E3=83=A9=E3=83=99=E3=83=AB=E3=82=92=E8=A1=A8=E7=A4=BA?=
 =?UTF-8?q?=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 locales/ja.yml                                |   1 +
 .../common/views/components/reversi.game.vue  | 140 +++++++++++++-----
 .../app/desktop/views/components/settings.vue |   7 +
 .../app/mobile/views/pages/settings.vue       |   8 +
 src/client/app/store.ts                       |   3 +-
 5 files changed, 117 insertions(+), 42 deletions(-)

diff --git a/locales/ja.yml b/locales/ja.yml
index 052dd59971..80fb50ea3e 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -54,6 +54,7 @@ common:
   update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
   my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
   i-like-sushi: "私は(プリンよりむしろ)寿司が好き"
+  show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示"
 
   widgets:
     analog-clock: "アナログ時計"
diff --git a/src/client/app/common/views/components/reversi.game.vue b/src/client/app/common/views/components/reversi.game.vue
index dc79c95bb8..b38ca856ab 100644
--- a/src/client/app/common/views/components/reversi.game.vue
+++ b/src/client/app/common/views/components/reversi.game.vue
@@ -13,14 +13,23 @@
 		</p>
 	</div>
 
-	<div class="board" :style="{ 'grid-template-rows': `repeat(${ game.settings.map.length }, 1fr)`, 'grid-template-columns': `repeat(${ game.settings.map[0].length }, 1fr)` }">
-		<div v-for="(stone, i) in o.board"
-			:class="{ empty: stone == null, none: o.map[i] == 'null', isEnded: game.isEnded, myTurn: !game.isEnded && isMyTurn, can: turnUser ? o.canPut(turnUser.id == blackUser.id, i) : null, prev: o.prevPos == i }"
-			@click="set(i)"
-			:title="'[' + (o.transformPosToXy(i)[0] + 1) + ', ' + (o.transformPosToXy(i)[1] + 1) + '] (' + i + ')'"
-		>
-			<img v-if="stone === true" :src="`${blackUser.avatarUrl}?thumbnail&size=128`" alt="">
-			<img v-if="stone === false" :src="`${whiteUser.avatarUrl}?thumbnail&size=128`" alt="">
+	<div class="board">
+		<div class="labels-x" v-if="this.$store.state.settings.reversiBoardLabels">
+			<span v-for="i in game.settings.map[0].length">{{ String.fromCharCode(96 + i) }}</span>
+		</div>
+		<div class="flex">
+			<div class="labels-y" v-if="this.$store.state.settings.reversiBoardLabels">
+				<div v-for="i in game.settings.map.length">{{ i }}</div>
+			</div>
+			<div class="cells" :style="cellsStyle">
+				<div v-for="(stone, i) in o.board"
+						:class="{ empty: stone == null, none: o.map[i] == 'null', isEnded: game.isEnded, myTurn: !game.isEnded && isMyTurn, can: turnUser ? o.canPut(turnUser.id == blackUser.id, i) : null, prev: o.prevPos == i }"
+						@click="set(i)"
+						:title="`${String.fromCharCode(97 + o.transformPosToXy(i)[0])}${o.transformPosToXy(i)[1] + 1}`">
+					<img v-if="stone === true" :src="`${blackUser.avatarUrl}?thumbnail&size=128`" alt="">
+					<img v-if="stone === false" :src="`${whiteUser.avatarUrl}?thumbnail&size=128`" alt="">
+				</div>
+			</div>
 		</div>
 	</div>
 
@@ -92,6 +101,12 @@ export default Vue.extend({
 		isMyTurn(): boolean {
 			if (this.turnUser == null) return null;
 			return this.turnUser.id == this.$store.state.i.id;
+		},
+		cellsStyle(): any {
+			return {
+				'grid-template-rows': `repeat(${ this.game.settings.map.length }, 1fr)`,
+				'grid-template-columns': `repeat(${ this.game.settings.map[0].length }, 1fr)`
+			};
 		}
 	},
 
@@ -244,54 +259,97 @@ export default Vue.extend({
 		border-bottom dashed 1px #c4cdd4
 
 	> .board
-		display grid
-		grid-gap 4px
 		width 350px
 		height 350px
 		margin 0 auto
 
-		> div
-			background transparent
-			border-radius 6px
-			overflow hidden
+		$label-size = 32px
+		$gap = 4px
 
-			*
-				pointer-events none
-				user-select none
+		> .labels-x
+			height $label-size
+			padding-left $label-size
+			display flex
 
-			&.empty
-				border solid 2px #eee
+			> *
+				flex 1
+				display flex
+				align-items center
+				justify-content center
 
-			&.empty.can
-				background #eee
+				&:first-child
+					margin-left -($gap / 2)
 
-			&.empty.myTurn
-				border-color #ddd
+				&:last-child
+					margin-right -($gap / 2)
 
-				&.can
-					background #eee
-					cursor pointer
+		> .flex
+			display flex
 
-					&:hover
-						border-color darken($theme-color, 10%)
-						background $theme-color
+			> .labels-y
+				width $label-size
+				display flex
+				flex-direction column
 
-					&:active
-						background darken($theme-color, 10%)
+				> *
+					flex 1
+					display flex
+					align-items center
+					justify-content center
 
-			&.prev
-				box-shadow 0 0 0 4px rgba($theme-color, 0.7)
+					&:first-child
+						margin-top -($gap / 2)
 
-			&.isEnded
-				border-color #ddd
+					&:last-child
+						margin-bottom -($gap / 2)
 
-			&.none
-				border-color transparent !important
+			> .cells
+				flex 1
+				display grid
+				grid-gap $gap
 
-			> img
-				display block
-				width 100%
-				height 100%
+				> div
+					background transparent
+					border-radius 6px
+					overflow hidden
+
+					*
+						pointer-events none
+						user-select none
+
+					&.empty
+						border solid 2px #eee
+
+					&.empty.can
+						background #eee
+
+					&.empty.myTurn
+						border-color #ddd
+
+						&.can
+							background #eee
+							cursor pointer
+
+							&:hover
+								border-color darken($theme-color, 10%)
+								background $theme-color
+
+							&:active
+								background darken($theme-color, 10%)
+
+					&.prev
+						box-shadow 0 0 0 4px rgba($theme-color, 0.7)
+
+					&.isEnded
+						border-color #ddd
+
+					&.none
+						border-color transparent !important
+
+					> img
+						display block
+						width 100%
+						height 100%
 
 	> .graph
 		display grid
diff --git a/src/client/app/desktop/views/components/settings.vue b/src/client/app/desktop/views/components/settings.vue
index 536d270dce..74ab45626d 100644
--- a/src/client/app/desktop/views/components/settings.vue
+++ b/src/client/app/desktop/views/components/settings.vue
@@ -54,6 +54,7 @@
 			<mk-switch v-model="$store.state.settings.showMaps" @change="onChangeShowMaps" text="%i18n:@show-maps%">
 				<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%"/>
 		</section>
 
 		<section class="web" v-show="page == 'web'">
@@ -369,6 +370,12 @@ export default Vue.extend({
 				value: v
 			});
 		},
+		onChangeReversiBoardLabels(v) {
+			this.$store.dispatch('settings/set', {
+				key: 'reversiBoardLabels',
+				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 34482fccba..89e5eaff67 100644
--- a/src/client/app/mobile/views/pages/settings.vue
+++ b/src/client/app/mobile/views/pages/settings.vue
@@ -13,6 +13,7 @@
 				<ui-switch v-model="darkmode">%i18n:@dark-mode%</ui-switch>
 				<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>
 
 				<div>
 					<div>%i18n:@timeline%</div>
@@ -182,6 +183,13 @@ export default Vue.extend({
 			});
 		},
 
+		onChangeReversiBoardLabels(v) {
+			this.$store.dispatch('settings/set', {
+				key: 'reversiBoardLabels',
+				value: v
+			});
+		},
+
 		onChangeShowReplyTarget(v) {
 			this.$store.dispatch('settings/set', {
 				key: 'showReplyTarget',
diff --git a/src/client/app/store.ts b/src/client/app/store.ts
index 1bc39ae66d..dfb24bb5f4 100644
--- a/src/client/app/store.ts
+++ b/src/client/app/store.ts
@@ -19,7 +19,8 @@ const defaultSettings = {
 	loadRemoteMedia: true,
 	disableViaMobile: false,
 	memo: null,
-	iLikeSushi: false
+	iLikeSushi: false,
+	reversiBoardLabels: false
 };
 
 const defaultDeviceSettings = {

From 2b1a785f24f8386ad2e3b67c97ae7c1c4894cd57 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 23 Jun 2018 16:58:54 +0900
Subject: [PATCH 52/90] =?UTF-8?q?=E3=81=8D=E3=82=83=E3=83=BC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

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

diff --git a/src/client/app/common/views/components/reversi.vue b/src/client/app/common/views/components/reversi.vue
index e4d7740bde..61705163ac 100644
--- a/src/client/app/common/views/components/reversi.vue
+++ b/src/client/app/common/views/components/reversi.vue
@@ -10,7 +10,7 @@
 		</div>
 	</div>
 	<div class="index" v-else>
-		<h1>Misskey %fa:circle%thell%fa:circle R%</h1>
+		<h1>Misskey Reversi</h1>
 		<p>他のMisskeyユーザーとリバーシで対戦しよう</p>
 		<div class="play">
 			<el-button round>フリーマッチ(準備中)</el-button>

From 5ff59b333915dc1da6f36d92edeaab223b3b68c1 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 23 Jun 2018 17:00:28 +0900
Subject: [PATCH 53/90] 4.8.0

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

diff --git a/package.json b/package.json
index 815e541194..d4c30967ba 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "4.7.1",
-	"clientVersion": "1.0.6735",
+	"version": "4.8.0",
+	"clientVersion": "1.0.6746",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,

From 509cdae8322ad286c444ef8a2b31b645f5fdfadd Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 23 Jun 2018 19:16:50 +0900
Subject: [PATCH 54/90] Fix bug

---
 src/remote/activitypub/models/person.ts   | 32 ++++++++++++++++-------
 src/remote/activitypub/renderer/person.ts |  2 +-
 2 files changed, 23 insertions(+), 11 deletions(-)

diff --git a/src/remote/activitypub/models/person.ts b/src/remote/activitypub/models/person.ts
index f233346395..28cbdb1ff7 100644
--- a/src/remote/activitypub/models/person.ts
+++ b/src/remote/activitypub/models/person.ts
@@ -47,16 +47,28 @@ export async function createPerson(value: any, resolver?: Resolver): Promise<IUs
 
 	const object = await resolver.resolve(value) as any;
 
-	if (
-		object == null ||
-		object.type !== 'Person' ||
-		typeof object.preferredUsername !== 'string' ||
-		typeof object.inbox !== 'string' ||
-		!validateUsername(object.preferredUsername) ||
-		!isValidName(object.name == '' ? null : object.name)
-	) {
-		log(`invalid person: ${JSON.stringify(object, null, 2)}`);
-		throw new Error('invalid person');
+	if (object == null) {
+		throw new Error('invalid person: object is null');
+	}
+
+	if (object.type != 'Person' && object.type != 'Service') {
+		throw new Error('invalid person: object is not a person or service');
+	}
+
+	if (typeof object.preferredUsername !== 'string') {
+		throw new Error('invalid person: preferredUsername is not a string');
+	}
+
+	if (typeof object.inbox !== 'string') {
+		throw new Error('invalid person: inbox is not a string');
+	}
+
+	if (!validateUsername(object.preferredUsername)) {
+		throw new Error('invalid person: invalid username');
+	}
+
+	if (!isValidName(object.name == '' ? null : object.name)) {
+		throw new Error('invalid person: invalid name');
 	}
 
 	const person: IPerson = object;
diff --git a/src/remote/activitypub/renderer/person.ts b/src/remote/activitypub/renderer/person.ts
index 8825c56c25..6ee69cbae7 100644
--- a/src/remote/activitypub/renderer/person.ts
+++ b/src/remote/activitypub/renderer/person.ts
@@ -7,7 +7,7 @@ export default (user: ILocalUser) => {
 	const id = `${config.url}/users/${user._id}`;
 
 	return {
-		type: 'Person',
+		type: user.isBot ? 'Service' : 'Person',
 		id,
 		inbox: `${id}/inbox`,
 		outbox: `${id}/outbox`,

From 247f3343346a67bc6c41d5a5f98d23dfbf97a0a2 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 23 Jun 2018 19:18:14 +0900
Subject: [PATCH 55/90] Fix

---
 src/remote/activitypub/models/person.ts | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/remote/activitypub/models/person.ts b/src/remote/activitypub/models/person.ts
index 28cbdb1ff7..94a6cee0bc 100644
--- a/src/remote/activitypub/models/person.ts
+++ b/src/remote/activitypub/models/person.ts
@@ -93,6 +93,8 @@ export async function createPerson(value: any, resolver?: Resolver): Promise<IUs
 
 	const host = toUnicode(finger.subject.replace(/^.*?@/, '')).toLowerCase();
 
+	const isBot = object.type == 'Service';
+
 	// Create user
 	let user: IRemoteUser;
 	try {
@@ -117,7 +119,8 @@ export async function createPerson(value: any, resolver?: Resolver): Promise<IUs
 			inbox: person.inbox,
 			endpoints: person.endpoints,
 			uri: person.id,
-			url: person.url
+			url: person.url,
+			isBot
 		}) as IRemoteUser;
 	} catch (e) {
 		// duplicate key error

From e4aa00315758c0d7490de5232b60c36db2bd0b98 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 23 Jun 2018 19:31:28 +0900
Subject: [PATCH 56/90] MFM: Improve search syntax

---
 src/mfm/parse/elements/search.ts |  2 +-
 test/mfm.ts                      | 22 ++++++++++++++++++++++
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/src/mfm/parse/elements/search.ts b/src/mfm/parse/elements/search.ts
index e5d9b9f0c2..9c4b7ffbe5 100644
--- a/src/mfm/parse/elements/search.ts
+++ b/src/mfm/parse/elements/search.ts
@@ -9,7 +9,7 @@ export type TextElementSearch = {
 };
 
 export default function(text: string) {
-	const match = text.match(/^(.+?) 検索(\n|$)/);
+	const match = text.match(/^(.+?) (検索|Search)(\n|$)/i);
 	if (!match) return null;
 	return {
 		type: 'search',
diff --git a/test/mfm.ts b/test/mfm.ts
index de722bffb3..f7fa1c0f5d 100644
--- a/test/mfm.ts
+++ b/test/mfm.ts
@@ -93,6 +93,28 @@ describe('Text', () => {
 			assert.equal(tokens[0].type, 'inline-code');
 			assert.equal(tokens[0].content, '`var x = "Strawberry Pasta";`');
 		});
+
+		it('search', () => {
+			const tokens1 = analyze('a b c 検索');
+			assert.deepEqual([
+				{ type: 'search', content: 'a b c 検索', query: 'a b c'}
+			], tokens1);
+
+			const tokens2 = analyze('a b c Search');
+			assert.deepEqual([
+				{ type: 'search', content: 'a b c Search', query: 'a b c'}
+			], tokens2);
+
+			const tokens3 = analyze('a b c search');
+			assert.deepEqual([
+				{ type: 'search', content: 'a b c search', query: 'a b c'}
+			], tokens3);
+
+			const tokens4 = analyze('a b c SEARCH');
+			assert.deepEqual([
+				{ type: 'search', content: 'a b c SEARCH', query: 'a b c'}
+			], tokens4);
+		});
 	});
 
 	describe('syntax highlighting', () => {

From a76fb4c1738dea589f4dc308d05b5466f3e451d4 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 23 Jun 2018 19:35:19 +0900
Subject: [PATCH 57/90] i18n

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

diff --git a/locales/ja.yml b/locales/ja.yml
index 80fb50ea3e..78779da206 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -47,6 +47,7 @@ common:
     e: "ここに書いてください"
     f: "あなたが書くのを待っています..."
 
+  search: "検索"
   delete: "削除"
   loading: "読み込み中"
   ok: "わかった"
diff --git a/src/client/app/common/views/components/google.vue b/src/client/app/common/views/components/google.vue
index 92817d3c1f..8272961ef2 100644
--- a/src/client/app/common/views/components/google.vue
+++ b/src/client/app/common/views/components/google.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="mk-google">
 	<input type="search" v-model="query" :placeholder="q">
-	<button @click="search">検索</button>
+	<button @click="search">%fa:search% %i18n:common.search%</button>
 </div>
 </template>
 

From 44f3888c249768503ac0c994d62695928a6668af Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 23 Jun 2018 19:57:23 +0900
Subject: [PATCH 58/90] =?UTF-8?q?=E3=82=B9=E3=83=9A=E3=82=A4=E3=83=B3?=
 =?UTF-8?q?=E8=AA=9E=E3=82=92=E8=BF=BD=E5=8A=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 locales/index.ts | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/locales/index.ts b/locales/index.ts
index 2ae84f30ae..f96074f1ae 100644
--- a/locales/index.ts
+++ b/locales/index.ts
@@ -18,7 +18,8 @@ const langs: { [key: string]: LocaleObject } = {
 	'en': loadLang('en'),
 	'fr': loadLang('fr'),
 	'ja': native,
-	'pl': loadLang('pl')
+	'pl': loadLang('pl'),
+	'es': loadLang('es')
 };
 
 Object.entries(langs).map(([, locale]) => {

From 4d48b0be991b326684aae816e323ad59d2b5d4be Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 23 Jun 2018 21:48:36 +0900
Subject: [PATCH 59/90] Fix type

---
 locales/index.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/locales/index.ts b/locales/index.ts
index f96074f1ae..45b5df0957 100644
--- a/locales/index.ts
+++ b/locales/index.ts
@@ -5,7 +5,7 @@
 import * as fs from 'fs';
 import * as yaml from 'js-yaml';
 
-export type LangKey = 'de' | 'en' | 'fr' | 'ja' | 'pl';
+export type LangKey = 'de' | 'en' | 'fr' | 'ja' | 'pl' | 'es';
 export type LocaleObject = { [key: string]: any };
 
 const loadLang = (lang: LangKey) => yaml.safeLoad(

From 488f36d49179712b015637b006b728bc764a0829 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 23 Jun 2018 21:56:47 +0900
Subject: [PATCH 60/90] i18n

---
 locales/ja.yml                                         |  7 +++++++
 .../app/common/views/components/reversi.game.vue       | 10 +++++-----
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/locales/ja.yml b/locales/ja.yml
index 78779da206..21e43b662f 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -57,6 +57,13 @@ common:
   i-like-sushi: "私は(プリンよりむしろ)寿司が好き"
   show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示"
 
+  reversi:
+    drawn: "引き分け"
+    my-turn: "あなたのターンです"
+    opponent-turn: "相手のターンです"
+    turn-of: "{}のターンです"
+    past-turn-of: "{}のターン"
+
   widgets:
     analog-clock: "アナログ時計"
     profile: "プロフィール"
diff --git a/src/client/app/common/views/components/reversi.game.vue b/src/client/app/common/views/components/reversi.game.vue
index b38ca856ab..2f41a4431a 100644
--- a/src/client/app/common/views/components/reversi.game.vue
+++ b/src/client/app/common/views/components/reversi.game.vue
@@ -3,13 +3,13 @@
 	<header><b>{{ blackUser.name }}</b>(黒) vs <b>{{ whiteUser.name }}</b>(白)</header>
 
 	<div style="overflow: hidden">
-		<p class="turn" v-if="!iAmPlayer && !game.isEnded">{{ turnUser.name }}のターンです<mk-ellipsis/></p>
-		<p class="turn" v-if="logPos != logs.length">{{ turnUser.name }}のターン</p>
-		<p class="turn1" v-if="iAmPlayer && !game.isEnded && !isMyTurn">相手のターンです<mk-ellipsis/></p>
-		<p class="turn2" v-if="iAmPlayer && !game.isEnded && isMyTurn" v-animate-css="{ classes: 'tada', iteration: 'infinite' }">あなたのターンです</p>
+		<p class="turn" v-if="!iAmPlayer && !game.isEnded">{{ '%i18n:common.reversi.turn-of%'.replace('{}', turnUser.name) }}<mk-ellipsis/></p>
+		<p class="turn" v-if="logPos != logs.length">{{ '%i18n:common.reversi.past-turn-of%'.replace('{}', turnUser.name) }}</p>
+		<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"><b>{{ game.winner.name }}</b>の勝ち{{ game.settings.isLlotheo ? ' (ロセオ)' : '' }}</template>
-			<template v-else>引き分け</template>
+			<template v-else>%i18n:common.reversi.drawn%</template>
 		</p>
 	</div>
 

From 3a8a374e875127bd146a1e14c6e7500063e313a3 Mon Sep 17 00:00:00 2001
From: Aya Morisawa <AyaMorisawa4869@gmail.com>
Date: Sat, 23 Jun 2018 22:25:22 +0900
Subject: [PATCH 61/90] Use capital letters for othello label

---
 src/client/app/common/views/components/reversi.game.vue | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/client/app/common/views/components/reversi.game.vue b/src/client/app/common/views/components/reversi.game.vue
index 2f41a4431a..b3790f4847 100644
--- a/src/client/app/common/views/components/reversi.game.vue
+++ b/src/client/app/common/views/components/reversi.game.vue
@@ -15,7 +15,7 @@
 
 	<div class="board">
 		<div class="labels-x" v-if="this.$store.state.settings.reversiBoardLabels">
-			<span v-for="i in game.settings.map[0].length">{{ String.fromCharCode(96 + i) }}</span>
+			<span v-for="i in game.settings.map[0].length">{{ String.fromCharCode(64 + i) }}</span>
 		</div>
 		<div class="flex">
 			<div class="labels-y" v-if="this.$store.state.settings.reversiBoardLabels">
@@ -25,7 +25,7 @@
 				<div v-for="(stone, i) in o.board"
 						:class="{ empty: stone == null, none: o.map[i] == 'null', isEnded: game.isEnded, myTurn: !game.isEnded && isMyTurn, can: turnUser ? o.canPut(turnUser.id == blackUser.id, i) : null, prev: o.prevPos == i }"
 						@click="set(i)"
-						:title="`${String.fromCharCode(97 + o.transformPosToXy(i)[0])}${o.transformPosToXy(i)[1] + 1}`">
+						:title="`${String.fromCharCode(65 + o.transformPosToXy(i)[0])}${o.transformPosToXy(i)[1] + 1}`">
 					<img v-if="stone === true" :src="`${blackUser.avatarUrl}?thumbnail&size=128`" alt="">
 					<img v-if="stone === false" :src="`${whiteUser.avatarUrl}?thumbnail&size=128`" alt="">
 				</div>

From 874411990bda7ff1b5b6fce366dc771180fc31c9 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 23 Jun 2018 22:55:32 +0900
Subject: [PATCH 62/90] :v:

---
 locales/ja.yml                                |  5 ++
 .../desktop/views/pages/user/user.header.vue  | 76 +++++++++++++++----
 .../desktop/views/pages/user/user.profile.vue | 58 --------------
 .../desktop/views/pages/user/user.twitter.vue | 21 +++++
 .../app/desktop/views/pages/user/user.vue     |  5 +-
 5 files changed, 93 insertions(+), 72 deletions(-)
 create mode 100644 src/client/app/desktop/views/pages/user/user.twitter.vue

diff --git a/locales/ja.yml b/locales/ja.yml
index 21e43b662f..23ee6a625a 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -759,6 +759,11 @@ desktop/views/pages/user/user.profile.vue:
   muted: "ミュートしています"
   unmute: "ミュート解除"
 
+desktop/views/pages/user/user.header.vue:
+  posts: "投稿"
+  following: "フォロー"
+  followers: "フォロワー"
+
 desktop/views/pages/user/user.timeline.vue:
   default: "投稿"
   with-replies: "投稿と返信"
diff --git a/src/client/app/desktop/views/pages/user/user.header.vue b/src/client/app/desktop/views/pages/user/user.header.vue
index afb8de4b2a..76b7c3f381 100644
--- a/src/client/app/desktop/views/pages/user/user.header.vue
+++ b/src/client/app/desktop/views/pages/user/user.header.vue
@@ -5,19 +5,32 @@
 		<div class="fade"></div>
 		<div class="title">
 			<p class="name">{{ user | userName }}</p>
-			<p class="username"><mk-acct :user="user"/></p>
-			<p class="location" v-if="user.host === null && user.profile.location">%fa:map-marker%{{ user.profile.location }}</p>
+			<div>
+				<template v-if="user.isBot">%fa:robot%</template>
+				<p class="username"><mk-acct :user="user"/></p>
+				<p class="location" v-if="user.host === null && user.profile.location">%fa:map-marker%{{ user.profile.location }}</p>
+				<p class="birthday" v-if="user.host === null && user.profile.birthday">%fa:birthday-cake%{{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ age }}歳)</p>
+			</div>
 		</div>
 	</div>
 	<mk-avatar class="avatar" :user="user" :disable-preview="true"/>
 	<div class="body">
-		<misskey-flavored-markdown v-if="user.description" :text="user.description" :i="$store.state.i"/>
+		<div class="description">
+			<misskey-flavored-markdown v-if="user.description" :text="user.description" :i="$store.state.i"/>
+		</div>
+		<div class="status">
+			<span class="notes-count"><b>{{ user.notesCount | number }}</b>%i18n:@posts%</span>
+			<span class="following clickable" @click="showFollowing"><b>{{ user.followingCount | number }}</b>%i18n:@following%</span>
+			<span class="followers clickable" @click="showFollowers"><b>{{ user.followersCount | number }}</b>%i18n:@followers%</span>
+		</div>
 	</div>
 </div>
 </template>
 
 <script lang="ts">
 import Vue from 'vue';
+import MkFollowingWindow from '../../components/following-window.vue';
+import MkFollowersWindow from '../../components/followers-window.vue';
 
 export default Vue.extend({
 	props: ['user'],
@@ -64,7 +77,19 @@ export default Vue.extend({
 			(this as any).apis.updateBanner().then(i => {
 				this.user.bannerUrl = i.bannerUrl;
 			});
-		}
+		},
+
+		showFollowing() {
+			(this as any).os.new(MkFollowingWindow, {
+				user: this.user
+			});
+		},
+
+		showFollowers() {
+			(this as any).os.new(MkFollowersWindow, {
+				user: this.user
+			});
+		},
 	}
 });
 </script>
@@ -118,7 +143,6 @@ root(isDark)
 			width 100%
 			padding 0 0 8px 154px
 			color #5e6367
-			font-family '游ゴシック', 'YuGothic', 'ヒラギノ角ゴ ProN W3', 'Hiragino Kaku Gothic ProN', 'Meiryo', 'メイリオ', sans-serif
 
 			> .name
 				display block
@@ -127,15 +151,15 @@ root(isDark)
 				font-weight bold
 				font-size 1.8em
 
-			> .username
-			> .location
-				display inline-block
-				margin 0 16px 0 0
-				line-height 20px
-				opacity 0.8
+			> div
+				> *
+					display inline-block
+					margin 0 16px 0 0
+					line-height 20px
+					opacity 0.8
 
-				> i
-					margin-right 4px
+					> i
+						margin-right 4px
 
 	> .avatar
 		display block
@@ -151,6 +175,32 @@ root(isDark)
 		padding 16px 16px 16px 154px
 		color isDark ? #c5ced6 : #555
 
+		> .status
+			margin-top 16px
+			padding-top 16px
+			border-top solid 1px rgba(#000, isDark ? 0.2 : 0.1)
+			font-size 80%
+
+			> *
+				display inline-block
+				padding-right 16px
+				margin-right 16px
+
+				&:not(:last-child)
+					border-right solid 1px rgba(#000, isDark ? 0.2 : 0.1)
+
+				&.clickable
+					cursor pointer
+
+					&:hover
+						color isDark ? #fff : #000
+
+				> b
+					margin-right 4px
+					font-size 1rem
+					font-weight bold
+					color $theme-color
+
 .header[data-darkmode]
 	root(true)
 
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 21f3c57c75..fda1db2849 100644
--- a/src/client/app/desktop/views/pages/user/user.profile.vue
+++ b/src/client/app/desktop/views/pages/user/user.profile.vue
@@ -15,25 +15,12 @@
 		</button>
 		<button class="mute ui" @click="list">%fa:list% リストに追加</button>
 	</div>
-	<div class="birthday" v-if="user.host === null && user.profile.birthday">
-		<p>%fa:birthday-cake%{{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ age }}歳)</p>
-	</div>
-	<div class="twitter" v-if="user.host === null && user.twitter">
-		<p>%fa:B twitter%<a :href="`https://twitter.com/${user.twitter.screenName}`" target="_blank">@{{ user.twitter.screenName }}</a></p>
-	</div>
-	<div class="status">
-		<p class="notes-count">%fa:angle-right%<a>{{ user.notesCount }}</a><b>投稿</b></p>
-		<p class="following">%fa:angle-right%<a @click="showFollowing">{{ user.followingCount }}</a>人を<b>フォロー</b></p>
-		<p class="followers">%fa:angle-right%<a @click="showFollowers">{{ user.followersCount }}</a>人の<b>フォロワー</b></p>
-	</div>
 </div>
 </template>
 
 <script lang="ts">
 import Vue from 'vue';
 import * as age from 's-age';
-import MkFollowingWindow from '../../components/following-window.vue';
-import MkFollowersWindow from '../../components/followers-window.vue';
 import MkUserListsWindow from '../../components/user-lists-window.vue';
 
 export default Vue.extend({
@@ -44,17 +31,6 @@ export default Vue.extend({
 		}
 	},
 	methods: {
-		showFollowing() {
-			(this as any).os.new(MkFollowingWindow, {
-				user: this.user
-			});
-		},
-
-		showFollowers() {
-			(this as any).os.new(MkFollowersWindow, {
-				user: this.user
-			});
-		},
 
 		stalk() {
 			(this as any).api('following/stalk', {
@@ -152,40 +128,6 @@ root(isDark)
 			&:not(:last-child)
 				margin-bottom 12px
 
-	> .birthday
-		padding 16px
-		color isDark ? #e3e7ea : #555
-		border-bottom solid 1px isDark ? #21242f : #eee
-
-		> p
-			margin 0
-
-			> i
-				margin-right 8px
-
-	> .twitter
-		padding 16px
-		color isDark ? #e3e7ea : #555
-		border-bottom solid 1px isDark ? #21242f : #eee
-
-		> p
-			margin 0
-
-			> i
-				margin-right 8px
-
-	> .status
-		padding 16px
-		color isDark ? #e3e7ea : #555
-		border-bottom solid 1px isDark ? #21242f : #eee
-
-		> p
-			margin 8px 0
-
-			> i
-				margin-left 8px
-				margin-right 8px
-
 .profile[data-darkmode]
 	root(true)
 
diff --git a/src/client/app/desktop/views/pages/user/user.twitter.vue b/src/client/app/desktop/views/pages/user/user.twitter.vue
new file mode 100644
index 0000000000..a5707b475f
--- /dev/null
+++ b/src/client/app/desktop/views/pages/user/user.twitter.vue
@@ -0,0 +1,21 @@
+<template>
+<div class="adsvaidqfznoartcbplullnejvxjphcn">
+	<p>%fa:B twitter%<a :href="`https://twitter.com/${user.twitter.screenName}`" target="_blank">@{{ user.twitter.screenName }}</a></p>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+
+export default Vue.extend({
+	props: ['user']
+});
+</script>
+
+<style lang="stylus" scoped>
+.adsvaidqfznoartcbplullnejvxjphcn
+	padding 32px
+	background #1a94f2
+	color #fff
+
+</style>
diff --git a/src/client/app/desktop/views/pages/user/user.vue b/src/client/app/desktop/views/pages/user/user.vue
index 5cea4b99e5..3123614c72 100644
--- a/src/client/app/desktop/views/pages/user/user.vue
+++ b/src/client/app/desktop/views/pages/user/user.vue
@@ -11,6 +11,7 @@
 			</div>
 			<div class="side">
 				<x-profile :user="user"/>
+				<a-twitter :user="user" v-if="user.host === null && user.twitter"/>
 				<mk-calendar @chosen="warp" :start="new Date(user.createdAt)"/>
 				<mk-activity :user="user"/>
 				<x-photos :user="user"/>
@@ -35,6 +36,7 @@ import XProfile from './user.profile.vue';
 import XPhotos from './user.photos.vue';
 import XFollowersYouKnow from './user.followers-you-know.vue';
 import XFriends from './user.friends.vue';
+import XTwitter from './user.twitter.vue';
 
 export default Vue.extend({
 	components: {
@@ -43,7 +45,8 @@ export default Vue.extend({
 		XProfile,
 		XPhotos,
 		XFollowersYouKnow,
-		XFriends
+		XFriends,
+		XTwitter
 	},
 	data() {
 		return {

From 3f0b5e431814348510c32bbb0dd48e7aaaf70ec6 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 23 Jun 2018 23:03:25 +0900
Subject: [PATCH 63/90] :v:

---
 locales/ja.yml                                          | 1 +
 src/client/app/desktop/views/pages/user/user.header.vue | 9 +++------
 2 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/locales/ja.yml b/locales/ja.yml
index 23ee6a625a..d3d04eb28a 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -763,6 +763,7 @@ desktop/views/pages/user/user.header.vue:
   posts: "投稿"
   following: "フォロー"
   followers: "フォロワー"
+  is-bot: "このアカウントはBotです"
 
 desktop/views/pages/user/user.timeline.vue:
   default: "投稿"
diff --git a/src/client/app/desktop/views/pages/user/user.header.vue b/src/client/app/desktop/views/pages/user/user.header.vue
index 76b7c3f381..ab0880d9bd 100644
--- a/src/client/app/desktop/views/pages/user/user.header.vue
+++ b/src/client/app/desktop/views/pages/user/user.header.vue
@@ -6,10 +6,10 @@
 		<div class="title">
 			<p class="name">{{ user | userName }}</p>
 			<div>
-				<template v-if="user.isBot">%fa:robot%</template>
+				<p v-if="user.isBot" title="%i18n:@is-bot%">%fa:robot%</p>
 				<p class="username"><mk-acct :user="user"/></p>
-				<p class="location" v-if="user.host === null && user.profile.location">%fa:map-marker%{{ user.profile.location }}</p>
-				<p class="birthday" v-if="user.host === null && user.profile.birthday">%fa:birthday-cake%{{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ age }}歳)</p>
+				<p class="location" v-if="user.host === null && user.profile.location">%fa:map-marker% {{ user.profile.location }}</p>
+				<p class="birthday" v-if="user.host === null && user.profile.birthday">%fa:birthday-cake% {{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ age }}歳)</p>
 			</div>
 		</div>
 	</div>
@@ -158,9 +158,6 @@ root(isDark)
 					line-height 20px
 					opacity 0.8
 
-					> i
-						margin-right 4px
-
 	> .avatar
 		display block
 		position absolute

From a8017369d0cc8261c15b4a641d7aa9bbd1862252 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 23 Jun 2018 23:04:49 +0900
Subject: [PATCH 64/90] 4.9.0

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

diff --git a/package.json b/package.json
index d4c30967ba..c78f4f2213 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "4.8.0",
-	"clientVersion": "1.0.6746",
+	"version": "4.9.0",
+	"clientVersion": "1.0.6759",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,

From b502627494077700401af28a2e87e5e9ffebeda9 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 23 Jun 2018 23:18:39 +0900
Subject: [PATCH 65/90] Fix nado

---
 .../desktop/views/pages/user/user.header.vue   | 18 +++++++++++++-----
 .../desktop/views/pages/user/user.profile.vue  |  8 +-------
 .../app/desktop/views/pages/user/user.vue      |  2 +-
 3 files changed, 15 insertions(+), 13 deletions(-)

diff --git a/src/client/app/desktop/views/pages/user/user.header.vue b/src/client/app/desktop/views/pages/user/user.header.vue
index ab0880d9bd..00545723e2 100644
--- a/src/client/app/desktop/views/pages/user/user.header.vue
+++ b/src/client/app/desktop/views/pages/user/user.header.vue
@@ -6,10 +6,10 @@
 		<div class="title">
 			<p class="name">{{ user | userName }}</p>
 			<div>
-				<p v-if="user.isBot" title="%i18n:@is-bot%">%fa:robot%</p>
-				<p class="username"><mk-acct :user="user"/></p>
-				<p class="location" v-if="user.host === null && user.profile.location">%fa:map-marker% {{ user.profile.location }}</p>
-				<p class="birthday" v-if="user.host === null && user.profile.birthday">%fa:birthday-cake% {{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ age }}歳)</p>
+				<span class="username"><mk-acct :user="user"/></span>
+				<span v-if="user.isBot" title="%i18n:@is-bot%">%fa:robot%</span>
+				<span class="location" v-if="user.host === null && user.profile.location">%fa:map-marker% {{ user.profile.location }}</span>
+				<span class="birthday" v-if="user.host === null && user.profile.birthday">%fa:birthday-cake% {{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ age }}歳)</span>
 			</div>
 		</div>
 	</div>
@@ -31,6 +31,7 @@
 import Vue from 'vue';
 import MkFollowingWindow from '../../components/following-window.vue';
 import MkFollowersWindow from '../../components/followers-window.vue';
+import * as age from 's-age';
 
 export default Vue.extend({
 	props: ['user'],
@@ -41,6 +42,10 @@ export default Vue.extend({
 				backgroundColor: this.user.bannerColor && this.user.bannerColor.length == 3 ? `rgb(${ this.user.bannerColor.join(',') })` : null,
 				backgroundImage: `url(${ this.user.bannerUrl })`
 			};
+		},
+
+		age(): number {
+			return age(this.user.profile.birthday);
 		}
 	},
 	mounted() {
@@ -154,10 +159,13 @@ root(isDark)
 			> div
 				> *
 					display inline-block
-					margin 0 16px 0 0
+					margin-right 16px
 					line-height 20px
 					opacity 0.8
 
+					&.username
+						font-weight bold
+
 	> .avatar
 		display block
 		position absolute
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 fda1db2849..0134d6f0be 100644
--- a/src/client/app/desktop/views/pages/user/user.profile.vue
+++ b/src/client/app/desktop/views/pages/user/user.profile.vue
@@ -20,18 +20,12 @@
 
 <script lang="ts">
 import Vue from 'vue';
-import * as age from 's-age';
 import MkUserListsWindow from '../../components/user-lists-window.vue';
 
 export default Vue.extend({
 	props: ['user'],
-	computed: {
-		age(): number {
-			return age(this.user.profile.birthday);
-		}
-	},
-	methods: {
 
+	methods: {
 		stalk() {
 			(this as any).api('following/stalk', {
 				userId: this.user.id
diff --git a/src/client/app/desktop/views/pages/user/user.vue b/src/client/app/desktop/views/pages/user/user.vue
index 3123614c72..0337befdbd 100644
--- a/src/client/app/desktop/views/pages/user/user.vue
+++ b/src/client/app/desktop/views/pages/user/user.vue
@@ -11,7 +11,7 @@
 			</div>
 			<div class="side">
 				<x-profile :user="user"/>
-				<a-twitter :user="user" v-if="user.host === null && user.twitter"/>
+				<x-twitter :user="user" v-if="user.host === null && user.twitter"/>
 				<mk-calendar @chosen="warp" :start="new Date(user.createdAt)"/>
 				<mk-activity :user="user"/>
 				<x-photos :user="user"/>

From 31b472fa473adc3d161034213b138a60997d5411 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 23 Jun 2018 23:19:15 +0900
Subject: [PATCH 66/90] 4.10.0

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

diff --git a/package.json b/package.json
index c78f4f2213..a4852d0fbe 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "4.9.0",
-	"clientVersion": "1.0.6759",
+	"version": "4.10.0",
+	"clientVersion": "1.0.6761",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,

From be74ca472a40ea40bee65b90a43fc67ef47a0974 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Sat, 23 Jun 2018 17:55:11 +0000
Subject: [PATCH 67/90] fix(package): update ws to version 5.2.1

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

diff --git a/package.json b/package.json
index a4852d0fbe..b814949213 100644
--- a/package.json
+++ b/package.json
@@ -216,7 +216,7 @@
 		"webpack": "4.12.0",
 		"webpack-cli": "3.0.8",
 		"websocket": "1.0.26",
-		"ws": "5.2.0",
+		"ws": "5.2.1",
 		"xev": "2.0.1"
 	},
 	"greenkeeper": {

From abc082f7c06bdefe2eae9d7493757e770897d151 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 24 Jun 2018 13:08:48 +0900
Subject: [PATCH 68/90] =?UTF-8?q?=E3=83=AA=E3=83=A2=E3=83=BC=E3=83=88?=
 =?UTF-8?q?=E3=83=95=E3=82=A9=E3=83=AD=E3=83=BC=E3=83=95=E3=82=A9=E3=83=BC?=
 =?UTF-8?q?=E3=83=A0=E3=82=92=E5=AE=9F=E8=A3=85=E3=81=99=E3=82=8B=E3=81=AA?=
 =?UTF-8?q?=E3=81=A9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 locales/ja.yml                                |   7 +
 src/client/app/common/views/pages/follow.vue  | 215 ++++++++++++++++++
 src/client/app/desktop/script.ts              |   4 +-
 .../app/desktop/views/pages/user/user.vue     |   6 +-
 src/client/app/mobile/script.ts               |   4 +-
 src/server/activitypub.ts                     |  16 +-
 6 files changed, 232 insertions(+), 20 deletions(-)
 create mode 100644 src/client/app/common/views/pages/follow.vue

diff --git a/locales/ja.yml b/locales/ja.yml
index d3d04eb28a..0f1d9cd510 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -280,6 +280,13 @@ common/views/widgets/memo.vue:
   memo: "ここに書いて!"
   save: "保存"
 
+common/views/pages/follow.vue:
+  signed-in-as: "{}としてサインイン中"
+  following: "フォロー中"
+  follow: "フォロー"
+  request-pending: "フォロー許可待ち"
+  follow-request: "フォロー申請"
+
 desktop/views/components/activity.chart.vue:
   total: "Black ... Total"
   notes: "Blue ... Notes"
diff --git a/src/client/app/common/views/pages/follow.vue b/src/client/app/common/views/pages/follow.vue
new file mode 100644
index 0000000000..c8e838be85
--- /dev/null
+++ b/src/client/app/common/views/pages/follow.vue
@@ -0,0 +1,215 @@
+<template>
+<div class="syxhndwprovvuqhmyvveewmbqayniwkv" v-if="!fetching" :data-darkmode="$store.state.device.darkmode">
+	<div class="signed-in-as" v-html="'%i18n:@signed-in-as%'.replace('{}', '<b>' + myName + '</b>')"></div>
+
+	<main>
+		<div class="banner" :style="bannerStyle"></div>
+		<mk-avatar class="avatar" :user="user" :disable-preview="true"/>
+		<div class="body">
+			<router-link :to="user | userPage" class="name">{{ user | userName }}</router-link>
+			<span class="username">@{{ user | acct }}</span>
+			<div class="description">
+				<misskey-flavored-markdown v-if="user.description" :text="user.description" :i="$store.state.i"/>
+			</div>
+		</div>
+	</main>
+
+	<button
+			:class="{ wait: followWait, active: user.isFollowing || user.hasPendingFollowRequestFromYou }"
+			@click="onClick"
+			:disabled="followWait">
+		<template v-if="!followWait">
+			<template v-if="user.hasPendingFollowRequestFromYou">%fa:hourglass-half% %i18n:@request-pending%</template>
+			<template v-else-if="user.isFollowing">%fa:minus% %i18n:@following%</template>
+			<template v-else-if="!user.isFollowing && user.isLocked">%fa:plus% %i18n:@follow-request%</template>
+			<template v-else-if="!user.isFollowing && !user.isLocked">%fa:plus% %i18n:@follow%</template>
+		</template>
+		<template v-else>%fa:spinner .pulse .fw%</template>
+	</button>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+import parseAcct from '../../../../../acct/parse';
+import getUserName from '../../../../../renderers/get-user-name';
+import Progress from '../../../common/scripts/loading';
+
+export default Vue.extend({
+	data() {
+		return {
+			fetching: true,
+			user: null,
+			followWait: false
+		};
+	},
+
+	computed: {
+		myName(): string {
+			return Vue.filter('userName')(this.$store.state.i);
+		},
+
+		bannerStyle(): any {
+			if (this.user.bannerUrl == null) return {};
+			return {
+				backgroundColor: this.user.bannerColor && this.user.bannerColor.length == 3 ? `rgb(${ this.user.bannerColor.join(',') })` : null,
+				backgroundImage: `url(${ this.user.bannerUrl })`
+			};
+		}
+	},
+
+	created() {
+		this.fetch();
+	},
+
+	methods: {
+		fetch() {
+			const acct = new URL(location.href).searchParams.get('acct');
+			this.fetching = true;
+			Progress.start();
+			(this as any).api('users/show', parseAcct(acct)).then(user => {
+				this.user = user;
+				this.fetching = false;
+				Progress.done();
+				document.title = getUserName(this.user) + ' | Misskey';
+			});
+		},
+
+		async onClick() {
+			this.followWait = true;
+
+			try {
+				if (this.user.isFollowing) {
+					this.user = await (this as any).api('following/delete', {
+						userId: this.user.id
+					});
+				} else {
+					if (this.user.isLocked && this.user.hasPendingFollowRequestFromYou) {
+						this.user = await (this as any).api('following/requests/cancel', {
+							userId: this.user.id
+						});
+					} else if (this.user.isLocked) {
+						this.user = await (this as any).api('following/create', {
+							userId: this.user.id
+						});
+					} else {
+						this.user = await (this as any).api('following/create', {
+							userId: this.user.id
+						});
+					}
+				}
+			} catch (e) {
+				console.error(e);
+			} finally {
+				this.followWait = false;
+			}
+		}
+	}
+});
+</script>
+
+<style lang="stylus" scoped>
+@import '~const.styl'
+
+root(isDark)
+	padding 32px
+	max-width 500px
+	margin 0 auto
+	text-align center
+	color isDark ? #9baec8 : #868c8c
+
+	$bg = isDark ? #282C37 : #fff
+
+	@media (max-width 400px)
+		padding 16px
+
+	> .signed-in-as
+		margin-bottom 16px
+		font-size 14px
+		color isDark ? #9baec8 : #9daab3
+
+	> main
+		margin-bottom 16px
+		background $bg
+		border-radius 8px
+		box-shadow 0 4px 12px rgba(#000, 0.1)
+		overflow hidden
+
+		> .banner
+			height 128px
+			background-position center
+			background-size cover
+
+		> .avatar
+			display block
+			margin -50px auto 0 auto
+			width 100px
+			height 100px
+			border-radius 100%
+			border solid 4px $bg
+
+		> .body
+			padding 4px 32px 32px 32px
+
+			@media (max-width 400px)
+				padding 4px 16px 16px 16px
+
+			> .name
+				font-size 20px
+				font-weight bold
+
+			> .username
+				display block
+				opacity 0.7
+
+			> .description
+				margin-top 16px
+
+	> button
+		display block
+		user-select none
+		cursor pointer
+		padding 10px 16px
+		margin 0
+		width 100%
+		min-width 150px
+		font-size 14px
+		font-weight bold
+		color $theme-color
+		background transparent
+		outline none
+		border solid 1px $theme-color
+		border-radius 36px
+
+		&:hover
+			background rgba($theme-color, 0.1)
+
+		&:active
+			background rgba($theme-color, 0.2)
+
+		&.active
+			color $theme-color-foreground
+			background $theme-color
+
+			&:hover
+				background lighten($theme-color, 10%)
+				border-color lighten($theme-color, 10%)
+
+			&:active
+				background darken($theme-color, 10%)
+				border-color darken($theme-color, 10%)
+
+		&.wait
+			cursor wait !important
+			opacity 0.7
+
+		*
+			pointer-events none
+
+.syxhndwprovvuqhmyvveewmbqayniwkv[data-darkmode]
+	root(true)
+
+.syxhndwprovvuqhmyvveewmbqayniwkv:not([data-darkmode])
+	root(false)
+
+</style>
diff --git a/src/client/app/desktop/script.ts b/src/client/app/desktop/script.ts
index beb358c7ee..297100e0e0 100644
--- a/src/client/app/desktop/script.ts
+++ b/src/client/app/desktop/script.ts
@@ -36,6 +36,7 @@ import MkSearch from './views/pages/search.vue';
 import MkTag from './views/pages/tag.vue';
 import MkReversi from './views/pages/reversi.vue';
 import MkShare from './views/pages/share.vue';
+import MkFollow from '../common/views/pages/follow.vue';
 
 /**
  * init
@@ -67,7 +68,8 @@ init(async (launch) => {
 			{ path: '/reversi', component: MkReversi },
 			{ path: '/reversi/:game', component: MkReversi },
 			{ path: '/@:user', component: MkUser },
-			{ path: '/notes/:note', component: MkNote }
+			{ path: '/notes/:note', component: MkNote },
+			{ path: '/authorize-follow', component: MkFollow }
 		]
 	});
 
diff --git a/src/client/app/desktop/views/pages/user/user.vue b/src/client/app/desktop/views/pages/user/user.vue
index 0337befdbd..fc5c900037 100644
--- a/src/client/app/desktop/views/pages/user/user.vue
+++ b/src/client/app/desktop/views/pages/user/user.vue
@@ -1,6 +1,6 @@
 <template>
 <mk-ui>
-	<div class="zwwan0di1v4356rmdbjmwnn32tptpdp2" v-if="!fetching" :data-darkmode="$store.state.device.darkmode">
+	<div class="xygkxeaeontfaokvqmiblezmhvhostak" v-if="!fetching" :data-darkmode="$store.state.device.darkmode">
 		<div class="is-suspended" v-if="user.isSuspended">%fa:exclamation-triangle% %i18n:@is-suspended%</div>
 		<div class="is-remote" v-if="user.host != null">%fa:exclamation-triangle% %i18n:@is-remote%<a :href="user.url || user.uri" target="_blank">%i18n:@view-remote%</a></div>
 		<main>
@@ -149,10 +149,10 @@ root(isDark)
 				i
 					color #ccc
 
-.zwwan0di1v4356rmdbjmwnn32tptpdp2[data-darkmode]
+.xygkxeaeontfaokvqmiblezmhvhostak[data-darkmode]
 	root(true)
 
-.zwwan0di1v4356rmdbjmwnn32tptpdp2:not([data-darkmode])
+.xygkxeaeontfaokvqmiblezmhvhostak:not([data-darkmode])
 	root(false)
 
 </style>
diff --git a/src/client/app/mobile/script.ts b/src/client/app/mobile/script.ts
index cfa9654e61..cb43f9d520 100644
--- a/src/client/app/mobile/script.ts
+++ b/src/client/app/mobile/script.ts
@@ -38,6 +38,7 @@ import MkSettings from './views/pages/settings.vue';
 import MkReversi from './views/pages/reversi.vue';
 import MkTag from './views/pages/tag.vue';
 import MkShare from './views/pages/share.vue';
+import MkFollow from '../common/views/pages/follow.vue';
 
 /**
  * init
@@ -80,7 +81,8 @@ init((launch) => {
 			{ path: '/@:user', component: MkUser },
 			{ path: '/@:user/followers', component: MkFollowers },
 			{ path: '/@:user/following', component: MkFollowing },
-			{ path: '/notes/:note', component: MkNote }
+			{ path: '/notes/:note', component: MkNote },
+			{ path: '/authorize-follow', component: MkFollow }
 		]
 	});
 
diff --git a/src/server/activitypub.ts b/src/server/activitypub.ts
index 1fbc621e91..f8a01a6ffe 100644
--- a/src/server/activitypub.ts
+++ b/src/server/activitypub.ts
@@ -11,7 +11,7 @@ import renderNote from '../remote/activitypub/renderer/note';
 import renderKey from '../remote/activitypub/renderer/key';
 import renderPerson from '../remote/activitypub/renderer/person';
 import renderOrderedCollection from '../remote/activitypub/renderer/ordered-collection';
-//import parseAcct from '../acct/parse';
+import parseAcct from '../acct/parse';
 import config from '../config';
 
 // Init router
@@ -142,20 +142,6 @@ router.get('/@:user', async (ctx, next) => {
 
 	userInfo(ctx, user);
 });
-
-// follow form
-router.get('/authorize-follow', async ctx => {
-	/* TODO
-	const { username, host } = parseAcct(ctx.query.acct);
-	if (host === null) {
-		res.sendStatus(422);
-		return;
-	}
-
-	const finger = await request(`https://${host}`)
-	*/
-});
-
 //#endregion
 
 export default router;

From 17792716a74532d32b9fbc86db5f50504dee128d Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 24 Jun 2018 13:09:22 +0900
Subject: [PATCH 69/90] 4.11.0

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

diff --git a/package.json b/package.json
index b814949213..da34f70549 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "4.10.0",
-	"clientVersion": "1.0.6761",
+	"version": "4.11.0",
+	"clientVersion": "1.0.6766",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,

From e15643ca46cf4be4c6fc58694c1f5f3a60bf9bf9 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 24 Jun 2018 13:18:22 +0900
Subject: [PATCH 70/90] Better reversi labels

---
 .../app/common/views/components/reversi.game.vue     | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/src/client/app/common/views/components/reversi.game.vue b/src/client/app/common/views/components/reversi.game.vue
index b3790f4847..94583a76fd 100644
--- a/src/client/app/common/views/components/reversi.game.vue
+++ b/src/client/app/common/views/components/reversi.game.vue
@@ -30,6 +30,12 @@
 					<img v-if="stone === false" :src="`${whiteUser.avatarUrl}?thumbnail&size=128`" alt="">
 				</div>
 			</div>
+			<div class="labels-y" v-if="this.$store.state.settings.reversiBoardLabels">
+				<div v-for="i in game.settings.map.length">{{ i }}</div>
+			</div>
+		</div>
+		<div class="labels-x" v-if="this.$store.state.settings.reversiBoardLabels">
+			<span v-for="i in game.settings.map[0].length">{{ String.fromCharCode(64 + i) }}</span>
 		</div>
 	</div>
 
@@ -263,12 +269,12 @@ export default Vue.extend({
 		height 350px
 		margin 0 auto
 
-		$label-size = 32px
+		$label-size = 16px
 		$gap = 4px
 
 		> .labels-x
 			height $label-size
-			padding-left $label-size
+			padding 0 $label-size
 			display flex
 
 			> *
@@ -276,6 +282,7 @@ export default Vue.extend({
 				display flex
 				align-items center
 				justify-content center
+				font-size 12px
 
 				&:first-child
 					margin-left -($gap / 2)
@@ -296,6 +303,7 @@ export default Vue.extend({
 					display flex
 					align-items center
 					justify-content center
+					font-size 12px
 
 					&:first-child
 						margin-top -($gap / 2)

From 21a2e5f4157dd590fd196b8b1d0ac2e1eb4d34c7 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 24 Jun 2018 13:23:57 +0900
Subject: [PATCH 71/90] 4.12.0

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

diff --git a/package.json b/package.json
index da34f70549..0f33ac045c 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "4.11.0",
-	"clientVersion": "1.0.6766",
+	"version": "4.12.0",
+	"clientVersion": "1.0.6780",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,

From db6018884773295d94fe10fad60ebff9f44c480e Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 24 Jun 2018 15:51:03 +0900
Subject: [PATCH 72/90] Fix bug

---
 src/services/note/create.ts | 43 ++++++++++---------------------------
 1 file changed, 11 insertions(+), 32 deletions(-)

diff --git a/src/services/note/create.ts b/src/services/note/create.ts
index feabe2f0b7..7e2fb4ff6a 100644
--- a/src/services/note/create.ts
+++ b/src/services/note/create.ts
@@ -27,51 +27,30 @@ type Type = 'reply' | 'renote' | 'quote' | 'mention';
 class NotificationManager {
 	private notifier: IUser;
 	private note: any;
-	private queue: Array<{
-		notifiee: ILocalUser['_id'],
-		type: Type;
-	}> = [];
 
 	constructor(notifier: IUser, note: any) {
 		this.notifier = notifier;
 		this.note = note;
 	}
 
-	public push(notifiee: ILocalUser['_id'], type: Type) {
+	public async push(notifiee: ILocalUser['_id'], type: Type) {
 		// 自分自身へは通知しない
 		if (this.notifier._id.equals(notifiee)) return;
 
-		const exist = this.queue.find(x => x.notifiee.equals(notifiee));
+		// ミュート情報を取得
+		const mentioneeMutes = await Mute.find({
+			muterId: notifiee
+		});
 
-		if (exist) {
-			// 「メンションされているかつ返信されている」場合は、メンションとしての通知ではなく返信としての通知にする
-			if (type != 'mention') {
-				exist.type = type;
-			}
-		} else {
-			this.queue.push({
-				notifiee, type
+		const mentioneesMutedUserIds = mentioneeMutes.map(m => m.muteeId.toString());
+
+		// 通知される側のユーザーが通知する側のユーザーをミュートしていない限りは通知する
+		if (!mentioneesMutedUserIds.includes(this.notifier._id.toString())) {
+			notify(notifiee, this.notifier._id, type, {
+				noteId: this.note._id
 			});
 		}
 	}
-
-	public deliver() {
-		this.queue.forEach(async x => {
-			// ミュート情報を取得
-			const mentioneeMutes = await Mute.find({
-				muterId: x.notifiee
-			});
-
-			const mentioneesMutedUserIds = mentioneeMutes.map(m => m.muteeId.toString());
-
-			// 通知される側のユーザーが通知する側のユーザーをミュートしていない限りは通知する
-			if (!mentioneesMutedUserIds.includes(this.notifier._id.toString())) {
-				notify(x.notifiee, this.notifier._id, x.type, {
-					noteId: this.note._id
-				});
-			}
-		});
-	}
 }
 
 export default async (user: IUser, data: {

From cdd9585cb8f39bbe7aca3179038e985b7eeaccbf Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 24 Jun 2018 15:55:41 +0900
Subject: [PATCH 73/90] :art:

---
 src/client/app/desktop/views/pages/user/user.twitter.vue | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/client/app/desktop/views/pages/user/user.twitter.vue b/src/client/app/desktop/views/pages/user/user.twitter.vue
index a5707b475f..228ce1de96 100644
--- a/src/client/app/desktop/views/pages/user/user.twitter.vue
+++ b/src/client/app/desktop/views/pages/user/user.twitter.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="adsvaidqfznoartcbplullnejvxjphcn">
-	<p>%fa:B twitter%<a :href="`https://twitter.com/${user.twitter.screenName}`" target="_blank">@{{ user.twitter.screenName }}</a></p>
+	<span>%fa:B twitter%<a :href="`https://twitter.com/${user.twitter.screenName}`" target="_blank">@{{ user.twitter.screenName }}</a></span>
 </div>
 </template>
 
@@ -16,6 +16,11 @@ export default Vue.extend({
 .adsvaidqfznoartcbplullnejvxjphcn
 	padding 32px
 	background #1a94f2
+	border-radius 6px
 	color #fff
 
+	a
+		margin-left 8px
+		color #fff
+
 </style>

From 47c45d48b1d5a35b64ee7b26a08b0d2edfd7076d Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 24 Jun 2018 15:56:18 +0900
Subject: [PATCH 74/90] 4.13.0

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

diff --git a/package.json b/package.json
index 0f33ac045c..1943de1d25 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "4.12.0",
-	"clientVersion": "1.0.6780",
+	"version": "4.13.0",
+	"clientVersion": "1.0.6783",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,

From a77f67fc320d8581be23825dbd368e723db7cc74 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sun, 24 Jun 2018 16:09:41 +0900
Subject: [PATCH 75/90] 4.13.1

---
 package.json                | 2 +-
 src/services/note/create.ts | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/package.json b/package.json
index 1943de1d25..ec3927a742 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "4.13.0",
+	"version": "4.13.1",
 	"clientVersion": "1.0.6783",
 	"codename": "nighthike",
 	"main": "./built/index.js",
diff --git a/src/services/note/create.ts b/src/services/note/create.ts
index 7e2fb4ff6a..a793c8e580 100644
--- a/src/services/note/create.ts
+++ b/src/services/note/create.ts
@@ -26,9 +26,9 @@ type Type = 'reply' | 'renote' | 'quote' | 'mention';
  */
 class NotificationManager {
 	private notifier: IUser;
-	private note: any;
+	private note: INote;
 
-	constructor(notifier: IUser, note: any) {
+	constructor(notifier: IUser, note: INote) {
 		this.notifier = notifier;
 		this.note = note;
 	}
@@ -192,7 +192,7 @@ export default async (user: IUser, data: {
 	// Serialize
 	const noteObj = await pack(note);
 
-	const nm = new NotificationManager(user, noteObj);
+	const nm = new NotificationManager(user, note);
 
 	const render = async () => {
 		const content = data.renote && data.text == null

From 3ff4f53bbdfcb2a345864169d9015fd0e4ceb68c Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Sun, 24 Jun 2018 08:49:27 +0000
Subject: [PATCH 76/90] fix(package): update webpack to version 4.12.1

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

diff --git a/package.json b/package.json
index ec3927a742..eb983830f9 100644
--- a/package.json
+++ b/package.json
@@ -213,7 +213,7 @@
 		"vuex-persistedstate": "^2.5.4",
 		"web-push": "3.3.2",
 		"webfinger.js": "2.6.6",
-		"webpack": "4.12.0",
+		"webpack": "4.12.1",
 		"webpack-cli": "3.0.8",
 		"websocket": "1.0.26",
 		"ws": "5.2.1",

From 3ffe90146c306a16eb4f36360131db45ccdf1240 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Mon, 25 Jun 2018 13:47:22 +0900
Subject: [PATCH 77/90] Update README.md

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 120e9fa5c0..7a10f5b811 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@ ultimately sophisticated professional microblogging software.
 
 <a href="https://www.patreon.com/syuilo"><img src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" alt="Become a Patron!" width="160" /></a>
 
-![](https://c10.patreonusercontent.com/3/e30%3D/patreon-posts/RsKWEDEKf8D_wYDQWAbex9CSb-1DnXW1nfqfLvuys5ROj2k0VF6_luuzHMTyf95n.png?token-time=1529539200&token-hash=RmcSP0947mw5o2-B6g1L6aU_OoDXANe198kLU6HMO30%3D)
+![](https://ja.mstdn.wiki/images/e/ed/Deck.jpg)
 
 :sparkles: Features
 ----------------------------------------------------------------

From da0d3e4129e37cdf6a16dc086c6ac2bac372ad5b Mon Sep 17 00:00:00 2001
From: otya <otya128@users.noreply.github.com>
Date: Mon, 25 Jun 2018 21:05:12 +0900
Subject: [PATCH 78/90] =?UTF-8?q?=E6=AD=A3=E3=81=97=E3=81=84v('=CF=89')v?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 locales/de.yml                           | 2 +-
 locales/en.yml                           | 2 +-
 locales/es.yml                           | 2 +-
 locales/fr.yml                           | 2 +-
 locales/it.yml                           | 2 +-
 locales/ja.yml                           | 2 +-
 locales/ko.yml                           | 2 +-
 locales/pl.yml                           | 2 +-
 locales/pt.yml                           | 2 +-
 locales/ru.yml                           | 2 +-
 locales/zh.yml                           | 2 +-
 src/client/app/common/scripts/get-kao.ts | 2 +-
 12 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/locales/de.yml b/locales/de.yml
index 2348097ebe..4feec5b0cc 100644
--- a/locales/de.yml
+++ b/locales/de.yml
@@ -400,7 +400,7 @@ desktop/views/components/post-form.vue:
   attach-media-from-local: "Medien von deinem PC hinzufügen"
   attach-media-from-drive: "Medien von deinem Speicher hinzufügen"
   attach-cancel: "Hinzufügen abbrechen"
-  insert-a-kao: "v(‘ω’)v"
+  insert-a-kao: "v('ω')v"
   create-poll: "Eine Abstimmung erstellen"
   text-remain: "{} Zeichen verbleibend"
 desktop/views/components/post-form-window.vue:
diff --git a/locales/en.yml b/locales/en.yml
index 645b4e9407..83d1c9e427 100644
--- a/locales/en.yml
+++ b/locales/en.yml
@@ -400,7 +400,7 @@ desktop/views/components/post-form.vue:
   attach-media-from-local: "Attach media from your PC"
   attach-media-from-drive: "Attach media from your Drive"
   attach-cancel: "Cancel attachment"
-  insert-a-kao: "v(‘ω’)v"
+  insert-a-kao: "v('ω')v"
   create-poll: "Create a poll"
   text-remain: "{} characters remaining"
 desktop/views/components/post-form-window.vue:
diff --git a/locales/es.yml b/locales/es.yml
index da41dcb24f..944c8a6699 100644
--- a/locales/es.yml
+++ b/locales/es.yml
@@ -400,7 +400,7 @@ desktop/views/components/post-form.vue:
   attach-media-from-local: "PCからメディアを添付"
   attach-media-from-drive: "Adjunta multimedia desde tu Disco"
   attach-cancel: "Quitar el archivo adjunto"
-  insert-a-kao: "v(‘ω’)v"
+  insert-a-kao: "v('ω')v"
   create-poll: "Crea una encuesta"
   text-remain: "quedan {} caracteres"
 desktop/views/components/post-form-window.vue:
diff --git a/locales/fr.yml b/locales/fr.yml
index fb47c0db47..199c633eef 100644
--- a/locales/fr.yml
+++ b/locales/fr.yml
@@ -400,7 +400,7 @@ desktop/views/components/post-form.vue:
   attach-media-from-local: "Joindre un media depuis votre PC"
   attach-media-from-drive: "Joindre un media depuis votre Drive"
   attach-cancel: "Annuler la jointure de fichier"
-  insert-a-kao: "v(‘ω’)v"
+  insert-a-kao: "v('ω')v"
   create-poll: "Créer un sondage"
   text-remain: "{} charactères restants"
 desktop/views/components/post-form-window.vue:
diff --git a/locales/it.yml b/locales/it.yml
index c911f7561e..4cd959cab4 100644
--- a/locales/it.yml
+++ b/locales/it.yml
@@ -400,7 +400,7 @@ desktop/views/components/post-form.vue:
   attach-media-from-local: "PCからメディアを添付"
   attach-media-from-drive: "ドライブからメディアを添付"
   attach-cancel: "添付取り消し"
-  insert-a-kao: "v(‘ω’)v"
+  insert-a-kao: "v('ω')v"
   create-poll: "アンケートを作成"
   text-remain: "残り{}文字"
 desktop/views/components/post-form-window.vue:
diff --git a/locales/ja.yml b/locales/ja.yml
index 0f1d9cd510..0d552565f2 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -461,7 +461,7 @@ desktop/views/components/post-form.vue:
   attach-media-from-local: "PCからメディアを添付"
   attach-media-from-drive: "ドライブからメディアを添付"
   attach-cancel: "添付取り消し"
-  insert-a-kao: "v(‘ω’)v"
+  insert-a-kao: "v('ω')v"
   create-poll: "アンケートを作成"
   text-remain: "残り{}文字"
 
diff --git a/locales/ko.yml b/locales/ko.yml
index c911f7561e..4cd959cab4 100644
--- a/locales/ko.yml
+++ b/locales/ko.yml
@@ -400,7 +400,7 @@ desktop/views/components/post-form.vue:
   attach-media-from-local: "PCからメディアを添付"
   attach-media-from-drive: "ドライブからメディアを添付"
   attach-cancel: "添付取り消し"
-  insert-a-kao: "v(‘ω’)v"
+  insert-a-kao: "v('ω')v"
   create-poll: "アンケートを作成"
   text-remain: "残り{}文字"
 desktop/views/components/post-form-window.vue:
diff --git a/locales/pl.yml b/locales/pl.yml
index 21a89fab8a..68fe4ea586 100644
--- a/locales/pl.yml
+++ b/locales/pl.yml
@@ -400,7 +400,7 @@ desktop/views/components/post-form.vue:
   attach-media-from-local: "Załącz zawartość multimedialną z komputera"
   attach-media-from-drive: "Załącz zawartość multimedialną z dysku"
   attach-cancel: "Usuń załącznik"
-  insert-a-kao: "v(‘ω’)v"
+  insert-a-kao: "v('ω')v"
   create-poll: "Utwórz ankietę"
   text-remain: "pozostałe znaki: {}"
 desktop/views/components/post-form-window.vue:
diff --git a/locales/pt.yml b/locales/pt.yml
index 5627facd31..91c76e312f 100644
--- a/locales/pt.yml
+++ b/locales/pt.yml
@@ -400,7 +400,7 @@ desktop/views/components/post-form.vue:
   attach-media-from-local: "PCからメディアを添付"
   attach-media-from-drive: "ドライブからメディアを添付"
   attach-cancel: "添付取り消し"
-  insert-a-kao: "v(‘ω’)v"
+  insert-a-kao: "v('ω')v"
   create-poll: "アンケートを作成"
   text-remain: "残り{}文字"
 desktop/views/components/post-form-window.vue:
diff --git a/locales/ru.yml b/locales/ru.yml
index acf1115b00..32a787a43b 100644
--- a/locales/ru.yml
+++ b/locales/ru.yml
@@ -400,7 +400,7 @@ desktop/views/components/post-form.vue:
   attach-media-from-local: "PCからメディアを添付"
   attach-media-from-drive: "ドライブからメディアを添付"
   attach-cancel: "添付取り消し"
-  insert-a-kao: "v(‘ω’)v"
+  insert-a-kao: "v('ω')v"
   create-poll: "アンケートを作成"
   text-remain: "残り{}文字"
 desktop/views/components/post-form-window.vue:
diff --git a/locales/zh.yml b/locales/zh.yml
index d50544222c..23adc4a3b6 100644
--- a/locales/zh.yml
+++ b/locales/zh.yml
@@ -400,7 +400,7 @@ desktop/views/components/post-form.vue:
   attach-media-from-local: "PCからメディアを添付"
   attach-media-from-drive: "ドライブからメディアを添付"
   attach-cancel: "添付取り消し"
-  insert-a-kao: "v(‘ω’)v"
+  insert-a-kao: "v('ω')v"
   create-poll: "アンケートを作成"
   text-remain: "残り{}文字"
 desktop/views/components/post-form-window.vue:
diff --git a/src/client/app/common/scripts/get-kao.ts b/src/client/app/common/scripts/get-kao.ts
index 2168c5be88..d380187510 100644
--- a/src/client/app/common/scripts/get-kao.ts
+++ b/src/client/app/common/scripts/get-kao.ts
@@ -1,5 +1,5 @@
 export default () => [
 	'(=^・・^=)',
-	'v(‘ω’)v',
+	'v('ω')v',
 	'🐡( \'-\' 🐡 )フグパンチ!!!!'
 ][Math.floor(Math.random() * 3)];

From 89190821798a6009b870fe05c2189d6eb6fee392 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Mon, 25 Jun 2018 20:53:04 +0000
Subject: [PATCH 79/90] fix(package): update html-minifier to version 3.5.17

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

diff --git a/package.json b/package.json
index eb983830f9..790f6bb71a 100644
--- a/package.json
+++ b/package.json
@@ -126,7 +126,7 @@
 		"gulp-util": "3.0.8",
 		"hard-source-webpack-plugin": "0.9.0",
 		"highlight.js": "9.12.0",
-		"html-minifier": "3.5.16",
+		"html-minifier": "3.5.17",
 		"http-signature": "1.2.0",
 		"inquirer": "6.0.0",
 		"is-root": "2.0.0",

From fd00c7bd81017463bd7f7d1c5965dfdb3b091755 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Tue, 26 Jun 2018 01:40:05 +0000
Subject: [PATCH 80/90] fix(package): update @types/node to version 10.3.6

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

diff --git a/package.json b/package.json
index eb983830f9..55bcf92791 100644
--- a/package.json
+++ b/package.json
@@ -65,7 +65,7 @@
 		"@types/mocha": "5.2.3",
 		"@types/mongodb": "3.0.21",
 		"@types/ms": "0.7.30",
-		"@types/node": "10.3.5",
+		"@types/node": "10.3.6",
 		"@types/nopt": "3.0.29",
 		"@types/parse5": "5.0.0",
 		"@types/pug": "2.0.4",

From 91c2b07cd8e9e01ea0b7601d53d2151612579e9b Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Tue, 26 Jun 2018 03:06:03 +0000
Subject: [PATCH 81/90] fix(package): update @types/webpack to version 4.4.3

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

diff --git a/package.json b/package.json
index eb983830f9..eb3cb4916e 100644
--- a/package.json
+++ b/package.json
@@ -80,7 +80,7 @@
 		"@types/speakeasy": "2.0.2",
 		"@types/tmp": "0.0.33",
 		"@types/uuid": "3.4.3",
-		"@types/webpack": "4.4.2",
+		"@types/webpack": "4.4.3",
 		"@types/webpack-stream": "3.2.10",
 		"@types/websocket": "0.0.39",
 		"@types/ws": "5.1.2",

From 19e9099a783f80e5e157f9668d0304d37b2754e1 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Tue, 26 Jun 2018 03:50:37 +0000
Subject: [PATCH 82/90] fix(package): update eslint to version 5.0.1

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

diff --git a/package.json b/package.json
index eb983830f9..012d3702ba 100644
--- a/package.json
+++ b/package.json
@@ -102,7 +102,7 @@
 		"element-ui": "2.4.1",
 		"emojilib": "2.2.12",
 		"escape-regexp": "0.0.1",
-		"eslint": "5.0.0",
+		"eslint": "5.0.1",
 		"eslint-plugin-vue": "4.5.0",
 		"eventemitter3": "3.1.0",
 		"exif-js": "2.3.0",

From 36c2f8fe5d550b7aa4acbfc242ff4ec456727b78 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Tue, 26 Jun 2018 18:25:27 +0900
Subject: [PATCH 83/90] Improve usability

---
 .../views/components/reaction-picker.vue      | 35 +++++++++++++++++--
 .../mobile/views/components/note-detail.vue   |  3 +-
 .../app/mobile/views/components/note.vue      |  3 +-
 3 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/src/client/app/common/views/components/reaction-picker.vue b/src/client/app/common/views/components/reaction-picker.vue
index 0db6f66b37..ed7aedb58e 100644
--- a/src/client/app/common/views/components/reaction-picker.vue
+++ b/src/client/app/common/views/components/reaction-picker.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="mk-reaction-picker">
 	<div class="backdrop" ref="backdrop" @click="close"></div>
-	<div class="popover" :class="{ compact }" ref="popover">
+	<div class="popover" :class="{ compact, big }" ref="popover">
 		<p v-if="!compact">{{ title }}</p>
 		<div>
 			<button @click="react('like')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="1" title="%i18n:common.reactions.like%"><mk-reaction-icon reaction='like'/></button>
@@ -25,7 +25,28 @@ import * as anime from 'animejs';
 const placeholder = '%i18n:@choose-reaction%';
 
 export default Vue.extend({
-	props: ['note', 'source', 'compact', 'cb'],
+	props: {
+		note: {
+			type: Object,
+			required: true
+		},
+		source: {
+			required: true
+		},
+		compact: {
+			type: Boolean,
+			required: false,
+			default: false
+		},
+		cb: {
+			required: false
+		},
+		big: {
+			type: Boolean,
+			required: false,
+			default: false
+		}
+	},
 	data() {
 		return {
 			title: placeholder
@@ -162,6 +183,16 @@ root(isDark)
 				border-right solid $balloon-size transparent
 				border-bottom solid $balloon-size $bgcolor
 
+		&.compact
+			> div
+				width 280px
+
+				> button
+					width 50px
+					height 50px
+					font-size 28px
+					border-radius 4px
+
 		> p
 			display block
 			margin 0
diff --git a/src/client/app/mobile/views/components/note-detail.vue b/src/client/app/mobile/views/components/note-detail.vue
index 76633490fd..48c9c8bcb0 100644
--- a/src/client/app/mobile/views/components/note-detail.vue
+++ b/src/client/app/mobile/views/components/note-detail.vue
@@ -197,7 +197,8 @@ export default Vue.extend({
 			(this as any).os.new(MkReactionPicker, {
 				source: this.$refs.reactButton,
 				note: this.p,
-				compact: true
+				compact: true,
+				big: true
 			});
 		},
 		menu() {
diff --git a/src/client/app/mobile/views/components/note.vue b/src/client/app/mobile/views/components/note.vue
index c3d4181a5d..c947a6c562 100644
--- a/src/client/app/mobile/views/components/note.vue
+++ b/src/client/app/mobile/views/components/note.vue
@@ -213,7 +213,8 @@ export default Vue.extend({
 			(this as any).os.new(MkReactionPicker, {
 				source: this.$refs.reactButton,
 				note: this.p,
-				compact: true
+				compact: true,
+				big: true
 			});
 		},
 

From d63044a15eaa0d6abfe20a694371a26a31bc1b3a Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Tue, 26 Jun 2018 18:34:17 +0900
Subject: [PATCH 84/90] Fix #1781

---
 src/remote/activitypub/renderer/person.ts | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/remote/activitypub/renderer/person.ts b/src/remote/activitypub/renderer/person.ts
index 6ee69cbae7..d4b3f40e41 100644
--- a/src/remote/activitypub/renderer/person.ts
+++ b/src/remote/activitypub/renderer/person.ts
@@ -2,6 +2,8 @@ import renderImage from './image';
 import renderKey from './key';
 import config from '../../../config';
 import { ILocalUser } from '../../../models/user';
+import toHtml from '../../../mfm/html';
+import parse from '../../../mfm/parse';
 
 export default (user: ILocalUser) => {
 	const id = `${config.url}/users/${user._id}`;
@@ -15,7 +17,7 @@ export default (user: ILocalUser) => {
 		url: `${config.url}/@${user.username}`,
 		preferredUsername: user.username,
 		name: user.name,
-		summary: user.description,
+		summary: toHtml(parse(user.description)),
 		icon: user.avatarId && renderImage(user.avatarId),
 		image: user.bannerId && renderImage(user.bannerId),
 		manuallyApprovesFollowers: user.isLocked,

From 58064ec6338863106574260c0643df12be5ec029 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Tue, 26 Jun 2018 18:42:00 +0900
Subject: [PATCH 85/90] MFM: Improve title syntax

---
 src/mfm/parse/elements/title.ts |  2 +-
 test/mfm.ts                     | 12 ++++++++++++
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/src/mfm/parse/elements/title.ts b/src/mfm/parse/elements/title.ts
index b89739a7c5..86ce8ab472 100644
--- a/src/mfm/parse/elements/title.ts
+++ b/src/mfm/parse/elements/title.ts
@@ -9,7 +9,7 @@ export type TextElementTitle = {
 };
 
 export default function(text: string) {
-	const match = text.match(/^【(.+?)】\n/);
+	const match = text.match(/^(【|\[)(.+?)(】|])\n/);
 	if (!match) return null;
 	const title = match[0];
 	return {
diff --git a/test/mfm.ts b/test/mfm.ts
index f7fa1c0f5d..df0f0be045 100644
--- a/test/mfm.ts
+++ b/test/mfm.ts
@@ -115,6 +115,18 @@ describe('Text', () => {
 				{ type: 'search', content: 'a b c SEARCH', query: 'a b c'}
 			], tokens4);
 		});
+
+		it('title', () => {
+			const tokens1 = analyze('【yee】\nhaw');
+			assert.deepEqual(
+				{ type: 'title', content: '【yee】\n', title: 'yee'}
+			, tokens1[0]);
+
+			const tokens2 = analyze('[yee]\nhaw');
+			assert.deepEqual(
+				{ type: 'title', content: '[yee]\n', title: 'yee'}
+			, tokens2[0]);
+		});
 	});
 
 	describe('syntax highlighting', () => {

From 55be57ad21599dafb41bd71db7453dba38f3da4c Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Tue, 26 Jun 2018 18:47:09 +0900
Subject: [PATCH 86/90] Clean up

---
 .../components/misskey-flavored-markdown.ts   | 11 -------
 .../desktop/views/components/note-detail.vue  | 32 -------------------
 .../desktop/views/components/notes.note.vue   | 32 -------------------
 .../desktop/views/pages/deck/deck.note.vue    | 28 ----------------
 .../mobile/views/components/note-detail.vue   | 28 ----------------
 .../app/mobile/views/components/note.vue      | 28 ----------------
 6 files changed, 159 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 30ad3ce3f2..c321c76104 100644
--- a/src/client/app/common/views/components/misskey-flavored-markdown.ts
+++ b/src/client/app/common/views/components/misskey-flavored-markdown.ts
@@ -40,17 +40,6 @@ export default Vue.component('misskey-flavored-markdown', {
 			ast = this.ast;
 		}
 
-		if (ast.filter(x => x.type != 'hashtag').length == 0) {
-			return;
-		}
-
-		while (ast[ast.length - 1] && (
-			ast[ast.length - 1].type == 'hashtag' ||
-			(ast[ast.length - 1].type == 'text' && ast[ast.length - 1].content == ' ') ||
-			(ast[ast.length - 1].type == 'text' && ast[ast.length - 1].content == '\n'))) {
-			ast.pop();
-		}
-
 		// Parse ast to DOM
 		const els = flatten(ast.map(token => {
 			switch (token.type) {
diff --git a/src/client/app/desktop/views/components/note-detail.vue b/src/client/app/desktop/views/components/note-detail.vue
index a9640ff9c4..e3d16d7056 100644
--- a/src/client/app/desktop/views/components/note-detail.vue
+++ b/src/client/app/desktop/views/components/note-detail.vue
@@ -47,9 +47,6 @@
 			</div>
 			<mk-poll v-if="p.poll" :note="p"/>
 			<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
-			<div class="tags" v-if="p.tags && p.tags.length > 0">
-				<router-link v-for="tag in p.tags" :key="tag" :to="`/tags/${tag}`">{{ tag }}</router-link>
-			</div>
 			<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a>
 			<div class="map" v-if="p.geo" ref="map"></div>
 			<div class="renote" v-if="p.renote">
@@ -363,35 +360,6 @@ root(isDark)
 			> .mk-url-preview
 				margin-top 8px
 
-			> .tags
-				margin 4px 0 0 0
-
-				> *
-					display inline-block
-					margin 0 8px 0 0
-					padding 2px 8px 2px 16px
-					font-size 90%
-					color #8d969e
-					background #edf0f3
-					border-radius 4px
-
-					&:before
-						content ""
-						display block
-						position absolute
-						top 0
-						bottom 0
-						left 4px
-						width 8px
-						height 8px
-						margin auto 0
-						background #fff
-						border-radius 100%
-
-					&:hover
-						text-decoration none
-						background #e2e7ec
-
 		> footer
 			font-size 1.2em
 
diff --git a/src/client/app/desktop/views/components/notes.note.vue b/src/client/app/desktop/views/components/notes.note.vue
index 24f8d2f65b..b8aff2d86e 100644
--- a/src/client/app/desktop/views/components/notes.note.vue
+++ b/src/client/app/desktop/views/components/notes.note.vue
@@ -32,9 +32,6 @@
 						<mk-media-list :media-list="p.media"/>
 					</div>
 					<mk-poll v-if="p.poll" :note="p" ref="pollViewer"/>
-					<div class="tags" v-if="p.tags && p.tags.length > 0">
-						<router-link v-for="tag in p.tags" :key="tag" :to="`/tags/${tag}`">{{ tag }}</router-link>
-					</div>
 					<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% 位置情報</a>
 					<div class="map" v-if="p.geo" ref="map"></div>
 					<div class="renote" v-if="p.renote">
@@ -465,35 +462,6 @@ root(isDark)
 						&:empty
 							display none
 
-					> .tags
-						margin 4px 0 0 0
-
-						> *
-							display inline-block
-							margin 0 0 4px 6px
-							padding 2px 8px 2px 16px
-							font-size 90%
-							color $theme-color
-							background isDark ? #313543 : #edf0f3
-							border-radius 4px
-
-							&:before
-								content ""
-								display block
-								position absolute
-								top 0
-								bottom 0
-								left 4px
-								width 8px
-								height 8px
-								margin auto 0
-								background isDark ? #282c37 : #fff
-								border-radius 100%
-
-							&:hover
-								text-decoration none
-								background #e2e7ec
-
 					.mk-url-preview
 						margin-top 8px
 
diff --git a/src/client/app/desktop/views/pages/deck/deck.note.vue b/src/client/app/desktop/views/pages/deck/deck.note.vue
index f4139c1bd8..c7df715a05 100644
--- a/src/client/app/desktop/views/pages/deck/deck.note.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.note.vue
@@ -32,9 +32,6 @@
 						<mk-media-list :media-list="p.media"/>
 					</div>
 					<mk-poll v-if="p.poll" :note="p" ref="pollViewer"/>
-					<div class="tags" v-if="p.tags && p.tags.length > 0">
-						<router-link v-for="tag in p.tags" :key="tag" :to="`/tags/${tag}`">{{ tag }}</router-link>
-					</div>
 					<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a>
 					<div class="renote" v-if="p.renote">
 						<mk-note-preview :note="p.renote" :mini="true"/>
@@ -373,31 +370,6 @@ root(isDark)
 					.mk-url-preview
 						margin-top 8px
 
-					> .tags
-						margin 4px 0 0 0
-
-						> *
-							display inline-block
-							margin 0 0 4px 6px
-							padding 2px 8px 2px 16px
-							font-size 90%
-							color $theme-color
-							background isDark ? #313543 : #edf0f3
-							border-radius 4px
-
-							&:before
-								content ""
-								display block
-								position absolute
-								top 0
-								bottom 0
-								left 4px
-								width 8px
-								height 8px
-								margin auto 0
-								background isDark ? #282c37 : #fff
-								border-radius 100%
-
 					> .media
 						> img
 							display block
diff --git a/src/client/app/mobile/views/components/note-detail.vue b/src/client/app/mobile/views/components/note-detail.vue
index 48c9c8bcb0..fa15922183 100644
--- a/src/client/app/mobile/views/components/note-detail.vue
+++ b/src/client/app/mobile/views/components/note-detail.vue
@@ -40,9 +40,6 @@
 				<span v-if="p.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span>
 				<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i"/>
 			</div>
-			<div class="tags" v-if="p.tags && p.tags.length > 0">
-				<router-link v-for="tag in p.tags" :key="tag" :to="`/tags/${tag}`">{{ tag }}</router-link>
-			</div>
 			<div class="media" v-if="p.media.length > 0">
 				<mk-media-list :media-list="p.media" :raw="true"/>
 			</div>
@@ -370,31 +367,6 @@ root(isDark)
 					display block
 					max-width 100%
 
-			> .tags
-				margin 4px 0 0 0
-
-				> *
-					display inline-block
-					margin 0 8px 0 0
-					padding 2px 8px 2px 16px
-					font-size 90%
-					color #8d969e
-					background #edf0f3
-					border-radius 4px
-
-					&:before
-						content ""
-						display block
-						position absolute
-						top 0
-						bottom 0
-						left 4px
-						width 8px
-						height 8px
-						margin auto 0
-						background #fff
-						border-radius 100%
-
 		> .time
 			font-size 16px
 			color isDark ? #606984 : #c0c0c0
diff --git a/src/client/app/mobile/views/components/note.vue b/src/client/app/mobile/views/components/note.vue
index c947a6c562..8fc8af7f8d 100644
--- a/src/client/app/mobile/views/components/note.vue
+++ b/src/client/app/mobile/views/components/note.vue
@@ -32,9 +32,6 @@
 						<mk-media-list :media-list="p.media"/>
 					</div>
 					<mk-poll v-if="p.poll" :note="p" ref="pollViewer"/>
-					<div class="tags" v-if="p.tags && p.tags.length > 0">
-						<router-link v-for="tag in p.tags" :key="tag" :to="`/tags/${tag}`">{{ tag }}</router-link>
-					</div>
 					<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
 					<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a>
 					<div class="map" v-if="p.geo" ref="map"></div>
@@ -417,31 +414,6 @@ root(isDark)
 					.mk-url-preview
 						margin-top 8px
 
-					> .tags
-						margin 4px 0 0 0
-
-						> *
-							display inline-block
-							margin 0 0 4px 6px
-							padding 2px 8px 2px 16px
-							font-size 90%
-							color $theme-color
-							background isDark ? #313543 : #edf0f3
-							border-radius 4px
-
-							&:before
-								content ""
-								display block
-								position absolute
-								top 0
-								bottom 0
-								left 4px
-								width 8px
-								height 8px
-								margin auto 0
-								background isDark ? #282c37 : #fff
-								border-radius 100%
-
 					> .media
 						> img
 							display block

From 30b1be97dd960389429ee41c51b8bb4638d58216 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Tue, 26 Jun 2018 18:53:06 +0900
Subject: [PATCH 87/90] :art:

---
 src/client/app/common/views/components/reversi.game.vue | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/client/app/common/views/components/reversi.game.vue b/src/client/app/common/views/components/reversi.game.vue
index 94583a76fd..a2a6fd0dc1 100644
--- a/src/client/app/common/views/components/reversi.game.vue
+++ b/src/client/app/common/views/components/reversi.game.vue
@@ -265,8 +265,8 @@ export default Vue.extend({
 		border-bottom dashed 1px #c4cdd4
 
 	> .board
-		width 350px
-		height 350px
+		width calc(100% - 16px)
+		max-width 500px
 		margin 0 auto
 
 		$label-size = 16px

From 839c93961cf96d68e4517e6d2439cc6ae4e3dd45 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Tue, 26 Jun 2018 18:53:35 +0900
Subject: [PATCH 88/90] 4.14.0

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

diff --git a/package.json b/package.json
index 5a26eba0c1..de7bff6e73 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "4.13.1",
-	"clientVersion": "1.0.6783",
+	"version": "4.14.0",
+	"clientVersion": "1.0.6815",
 	"codename": "nighthike",
 	"main": "./built/index.js",
 	"private": true,

From 041415519be256b827ec5fd6705903b99b45906e Mon Sep 17 00:00:00 2001
From: Zero King <l2dy@icloud.com>
Date: Tue, 26 Jun 2018 13:27:52 +0000
Subject: [PATCH 89/90] i18n

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

diff --git a/locales/en.yml b/locales/en.yml
index 83d1c9e427..cdb179fe9e 100644
--- a/locales/en.yml
+++ b/locales/en.yml
@@ -552,6 +552,8 @@ desktop/views/components/timeline.vue:
   local: "Local"
   global: "Global"
   list: "Lists"
+desktop/views/components/ui.header.vue:
+  welcome-back: "Welcome back, "
 desktop/views/components/ui.header.account.vue:
   profile: "Your profile"
   drive: "Drive"
diff --git a/locales/ja.yml b/locales/ja.yml
index 0d552565f2..fc790d8c53 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -639,6 +639,9 @@ desktop/views/components/timeline.vue:
   global: "グローバル"
   list: "リスト"
 
+desktop/views/components/ui.header.vue:
+  welcome-back: "おかえりなさい、"
+
 desktop/views/components/ui.header.account.vue:
   profile: "プロフィール"
   drive: "ドライブ"
diff --git a/src/client/app/desktop/views/components/ui.header.vue b/src/client/app/desktop/views/components/ui.header.vue
index 7045790054..aa7c3ac44d 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">おかえりなさい、<b>{{ $store.state.i | userName }}</b>さん</p>
+			<p ref="welcomeback" v-if="$store.getters.isSignedIn">%i18n:@welcome-back%<b>{{ $store.state.i | userName }}</b>さん</p>
 			<div class="container" ref="mainContainer">
 				<div class="left">
 					<x-nav/>

From 910dfd6ad2ec171edb4c5208d49f2053475dcc46 Mon Sep 17 00:00:00 2001
From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com>
Date: Tue, 26 Jun 2018 13:28:53 +0000
Subject: [PATCH 90/90] fix(package): update uuid to version 3.3.0

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

diff --git a/package.json b/package.json
index de7bff6e73..7c84161a98 100644
--- a/package.json
+++ b/package.json
@@ -199,7 +199,7 @@
 		"typescript-eslint-parser": "16.0.0",
 		"uglify-es": "3.3.9",
 		"url-loader": "1.0.1",
-		"uuid": "3.2.1",
+		"uuid": "3.3.0",
 		"v-animate-css": "0.0.2",
 		"vue": "2.5.16",
 		"vue-cropperjs": "2.2.1",