From 3548290ff266cba0e0d1cd4f9384c25ca985db5f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?=
 <root@acid-chicken.com>
Date: Wed, 13 Feb 2019 23:43:55 +0900
Subject: [PATCH 1/3] Fix tslint.json styles (#4219)

---
 tslint.json | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/tslint.json b/tslint.json
index d7d9f2b56f..d24523ae5c 100644
--- a/tslint.json
+++ b/tslint.json
@@ -7,15 +7,15 @@
 	"jsRules": {},
 	"rules": {
 		"align": false,
-		"indent": ["tab"],
-		"quotemark": ["single"],
+		"indent": [true, "tabs"],
+		"quotemark": [true, "single"],
 		"no-var-requires": false,
 		"no-string-throw": false,
 		"trailing-comma": [false],
 		"object-literal-sort-keys": false,
 		"curly": false,
 		"no-console": [false],
-		"no-empty":false,
+		"no-empty": false,
 		"ordered-imports": [false],
 		"arrow-parens": false,
 		"array-type": [true, "array"],
@@ -31,11 +31,12 @@
 		"max-classes-per-file": false,
 		"member-ordering": [false],
 		"ban-types": [
+			true,
 			"Object"
 		],
 		"ban": [
 			true,
-			{"name": ["*", "forEach"], "message": "Use for-of loop instead."}
+			{ "name": ["*", "forEach"], "message": "Use for-of loop instead." }
 		],
 		"no-duplicate-string": false,
 		"no-commented-code": false,

From 4b6c11325158b7c2410b4fd940b6bec986341588 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?=
 <root@acid-chicken.com>
Date: Wed, 13 Feb 2019 23:45:35 +0900
Subject: [PATCH 2/3] Add prelude function for URL Query (#4135)

* Update string.ts

* Refactor

* Update string.ts

* Update wrap-url.ts

* Update string.ts

* Update get-static-image-url.ts

* Use querystring.stringify

* Update outbox.ts

* Back to the urlQuery

* Update followers.ts

* Update following.ts

* Update outbox.ts

* Update string.ts

* Update get-static-image-url.ts

* Update string.ts

* Update string.ts

* Separate prelude files
---
 .../app/common/scripts/get-static-image-url.ts  | 12 +++++++-----
 src/prelude/url.ts                              |  7 +++++++
 src/server/activitypub/followers.ts             | 13 ++++++++++---
 src/server/activitypub/following.ts             | 13 ++++++++++---
 src/server/activitypub/outbox.ts                | 17 ++++++++++++++---
 5 files changed, 48 insertions(+), 14 deletions(-)
 create mode 100644 src/prelude/url.ts

diff --git a/src/client/app/common/scripts/get-static-image-url.ts b/src/client/app/common/scripts/get-static-image-url.ts
index f84adf709c..7460ca38f2 100644
--- a/src/client/app/common/scripts/get-static-image-url.ts
+++ b/src/client/app/common/scripts/get-static-image-url.ts
@@ -1,9 +1,11 @@
 import { url as instanceUrl } from '../../config';
+import * as url from '../../../../prelude/url';
 
-export function getStaticImageUrl(url: string): string {
-	const u = new URL(url);
+export function getStaticImageUrl(baseUrl: string): string {
+	const u = new URL(baseUrl);
 	const dummy = `${u.host}${u.pathname}`;	// 拡張子がないとキャッシュしてくれないCDNがあるので
-	let result = `${instanceUrl}/proxy/${dummy}?url=${encodeURIComponent(u.href)}`;
-	result += '&static=1';
-	return result;
+	return `${instanceUrl}/proxy/${dummy}?${url.query({
+		url: u.href,
+		static: '1'
+	})}`;
 }
diff --git a/src/prelude/url.ts b/src/prelude/url.ts
new file mode 100644
index 0000000000..ff1012d4c1
--- /dev/null
+++ b/src/prelude/url.ts
@@ -0,0 +1,7 @@
+import { stringify } from 'querystring';
+
+export function query(obj: {}): string {
+	return stringify(Object.entries(obj)
+		.filter(([, v]) => Array.isArray(v) ? v.length : v !== undefined)
+		.reduce((a, [k, v]) => (a[k] = v, a), {} as Record<string, any>));
+}
diff --git a/src/server/activitypub/followers.ts b/src/server/activitypub/followers.ts
index bf5066008d..563b3da653 100644
--- a/src/server/activitypub/followers.ts
+++ b/src/server/activitypub/followers.ts
@@ -5,6 +5,7 @@ import $ from 'cafy';
 import ID, { transform } from '../../misc/cafy-id';
 import User from '../../models/user';
 import Following from '../../models/following';
+import * as url from '../../prelude/url';
 import { renderActivity } from '../../remote/activitypub/renderer';
 import renderOrderedCollection from '../../remote/activitypub/renderer/ordered-collection';
 import renderOrderedCollectionPage from '../../remote/activitypub/renderer/ordered-collection-page';
@@ -20,7 +21,7 @@ export default async (ctx: Router.IRouterContext) => {
 	const userId = new ObjectID(ctx.params.user);
 
 	// Get 'cursor' parameter
-	const [cursor = null, cursorErr] = $.optional.type(ID).get(ctx.request.query.cursor);
+	const [cursor, cursorErr] = $.optional.type(ID).get(ctx.request.query.cursor);
 
 	// Get 'page' parameter
 	const pageErr = !$.optional.str.or(['true', 'false']).ok(ctx.request.query.page);
@@ -72,10 +73,16 @@ export default async (ctx: Router.IRouterContext) => {
 
 		const renderedFollowers = await Promise.all(followings.map(following => renderFollowUser(following.followerId)));
 		const rendered = renderOrderedCollectionPage(
-			`${partOf}?page=true${cursor ? `&cursor=${cursor}` : ''}`,
+			`${partOf}?${url.query({
+				page: 'true',
+				cursor
+			})}`,
 			user.followersCount, renderedFollowers, partOf,
 			null,
-			inStock ? `${partOf}?page=true&cursor=${followings[followings.length - 1]._id}` : null
+			inStock ? `${partOf}?${url.query({
+				page: 'true',
+				cursor: followings[followings.length - 1]._id.toHexString()
+			})}` : null
 		);
 
 		ctx.body = renderActivity(rendered);
diff --git a/src/server/activitypub/following.ts b/src/server/activitypub/following.ts
index cb86546f1c..f23e177e25 100644
--- a/src/server/activitypub/following.ts
+++ b/src/server/activitypub/following.ts
@@ -5,6 +5,7 @@ import $ from 'cafy';
 import ID, { transform } from '../../misc/cafy-id';
 import User from '../../models/user';
 import Following from '../../models/following';
+import * as url from '../../prelude/url';
 import { renderActivity } from '../../remote/activitypub/renderer';
 import renderOrderedCollection from '../../remote/activitypub/renderer/ordered-collection';
 import renderOrderedCollectionPage from '../../remote/activitypub/renderer/ordered-collection-page';
@@ -20,7 +21,7 @@ export default async (ctx: Router.IRouterContext) => {
 	const userId = new ObjectID(ctx.params.user);
 
 	// Get 'cursor' parameter
-	const [cursor = null, cursorErr] = $.optional.type(ID).get(ctx.request.query.cursor);
+	const [cursor, cursorErr] = $.optional.type(ID).get(ctx.request.query.cursor);
 
 	// Get 'page' parameter
 	const pageErr = !$.optional.str.or(['true', 'false']).ok(ctx.request.query.page);
@@ -72,10 +73,16 @@ export default async (ctx: Router.IRouterContext) => {
 
 		const renderedFollowees = await Promise.all(followings.map(following => renderFollowUser(following.followeeId)));
 		const rendered = renderOrderedCollectionPage(
-			`${partOf}?page=true${cursor ? `&cursor=${cursor}` : ''}`,
+			`${partOf}?${url.query({
+				page: 'true',
+				cursor
+			})}`,
 			user.followingCount, renderedFollowees, partOf,
 			null,
-			inStock ? `${partOf}?page=true&cursor=${followings[followings.length - 1]._id}` : null
+			inStock ? `${partOf}?${url.query({
+				page: 'true',
+				cursor: followings[followings.length - 1]._id.toHexString()
+			})}` : null
 		);
 
 		ctx.body = renderActivity(rendered);
diff --git a/src/server/activitypub/outbox.ts b/src/server/activitypub/outbox.ts
index 508e7e5ec9..8b65ce993a 100644
--- a/src/server/activitypub/outbox.ts
+++ b/src/server/activitypub/outbox.ts
@@ -14,6 +14,7 @@ import renderNote from '../../remote/activitypub/renderer/note';
 import renderCreate from '../../remote/activitypub/renderer/create';
 import renderAnnounce from '../../remote/activitypub/renderer/announce';
 import { countIf } from '../../prelude/array';
+import * as url from '../../prelude/url';
 
 export default async (ctx: Router.IRouterContext) => {
 	if (!ObjectID.isValid(ctx.params.user)) {
@@ -88,10 +89,20 @@ export default async (ctx: Router.IRouterContext) => {
 
 		const activities = await Promise.all(notes.map(note => packActivity(note)));
 		const rendered = renderOrderedCollectionPage(
-			`${partOf}?page=true${sinceId ? `&since_id=${sinceId}` : ''}${untilId ? `&until_id=${untilId}` : ''}`,
+			`${partOf}?${url.query({
+				page: 'true',
+				since_id: sinceId,
+				until_id: untilId
+			})}`,
 			user.notesCount, activities, partOf,
-			notes.length > 0 ? `${partOf}?page=true&since_id=${notes[0]._id}` : null,
-			notes.length > 0 ? `${partOf}?page=true&until_id=${notes[notes.length - 1]._id}` : null
+			notes.length ? `${partOf}?${url.query({
+				page: 'true',
+				since_id: notes[0]._id.toHexString()
+			})}` : null,
+			notes.length ? `${partOf}?${url.query({
+				page: 'true',
+				until_id: notes[notes.length - 1]._id.toHexString()
+			})}` : null
 		);
 
 		ctx.body = renderActivity(rendered);

From fa5ea45726ef55c9cb7802ea8c03310ed04a444f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?=
 <root@acid-chicken.com>
Date: Wed, 13 Feb 2019 23:45:58 +0900
Subject: [PATCH 3/3] Docker: Remove unnecessary workaround for BusyBox's
 "free" (#4199) (#4213)

systeminformation gets incorrect memory information due to BusyBox's
"free" issue.(#3409)
A workaround for avoiding it was made.

But it never works because the runner container has no effect.
It should be deleted.
---
 Dockerfile | 2 --
 1 file changed, 2 deletions(-)

diff --git a/Dockerfile b/Dockerfile
index 4d7d450f8f..719be064d2 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -8,7 +8,6 @@ WORKDIR /misskey
 
 FROM base AS builder
 
-RUN unlink /usr/bin/free
 RUN apk add --no-cache \
     autoconf \
     automake \
@@ -20,7 +19,6 @@ RUN apk add --no-cache \
     make \
     nasm \
     pkgconfig \
-    procps \
     python \
     zlib-dev
 RUN npm i -g yarn