From ea41e39dd26c2b47c154fbb1ae31dbe42622d40d Mon Sep 17 00:00:00 2001
From: "Misty (Bot)" <deploy@nodebb.org>
Date: Sat, 7 Oct 2017 09:25:55 +0000
Subject: [PATCH 01/16] Latest translations and fallbacks

---
 public/language/zh-CN/admin/settings/email.json | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/public/language/zh-CN/admin/settings/email.json b/public/language/zh-CN/admin/settings/email.json
index e08da21512..c9e4bc5d1f 100644
--- a/public/language/zh-CN/admin/settings/email.json
+++ b/public/language/zh-CN/admin/settings/email.json
@@ -6,8 +6,8 @@
 	"from-help": "用于邮件中显示的发送者",
 
 	"smtp-transport": "SMTP 通信",
-	"smtp-transport.enabled": "使用一个外部邮箱系统来发送邮件",
-	"smtp-transport-help": "你可以从列表中选取一个已知的服务或自定义。",
+	"smtp-transport.enabled": "使用一个外部电子邮箱系统来发送邮件",
+	"smtp-transport-help": "您可以从列表中选取一个已知的服务或自定义。",
 	"smtp-transport.service": "选择服务",
 	"smtp-transport.service-custom": "自定义",
 	"smtp-transport.service-help": "选取一个上方服务以便使用已知的信息。此外,还可以选取 “自定义”并在下方输入配置细节。",
@@ -20,7 +20,7 @@
 	"smtp-transport.security-starttls": "StartTLS",
 	"smtp-transport.security-none": "None",
 	"smtp-transport.username": "用户名",
-	"smtp-transport.username-help": "<b>对于Gmail服务,</b>请在这里输入完整的电子邮件地址,尤其是如果你使用的是 Google Apps 托管的域名。",
+	"smtp-transport.username-help": "<b>对于Gmail服务,</b>请在这里输入完整的电子邮箱地址,尤其是如果您使用的是 Google Apps 托管的域名。",
 	"smtp-transport.password": "密码",
 
 	"template": "编辑电子邮件模板",

From bb6dcf377905932596d8915c12afd1cace2dedc5 Mon Sep 17 00:00:00 2001
From: "Misty (Bot)" <deploy@nodebb.org>
Date: Mon, 9 Oct 2017 09:26:12 +0000
Subject: [PATCH 02/16] Latest translations and fallbacks

---
 public/language/he/error.json         | 4 ++--
 public/language/he/notifications.json | 2 +-
 public/language/he/pages.json         | 4 ++--
 public/language/he/success.json       | 2 +-
 public/language/he/topic.json         | 8 ++++----
 5 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/public/language/he/error.json b/public/language/he/error.json
index 0599a1b34b..ecf75c2ed2 100644
--- a/public/language/he/error.json
+++ b/public/language/he/error.json
@@ -4,7 +4,7 @@
     "not-logged-in": "נראה שאינך מחובר למערכת.",
     "account-locked": "חשבונך נחסם באופן זמני",
     "search-requires-login": "פעולת החיפוש דורשת חשבון - בבקשה התחבר או הרשם.",
-    "goback": "Press back to return to the previous page",
+    "goback": "לחץ back לחזרה לעמוד הקודם",
     "invalid-cid": "זהוי קטגוריה שגוי",
     "invalid-tid": "זהוי נושא שגוי",
     "invalid-pid": "זהוי פוסט שגוי",
@@ -59,7 +59,7 @@
     "post-delete-duration-expired-hours": "You are only allowed to delete posts for %1 hour(s) after posting",
     "post-delete-duration-expired-hours-minutes": "You are only allowed to delete posts for %1 hour(s) %2 minute(s) after posting",
     "post-delete-duration-expired-days": "You are only allowed to delete posts for %1 day(s) after posting",
-    "post-delete-duration-expired-days-hours": "You are only allowed to delete posts for %1 day(s) %2 hour(s) after posting",
+    "post-delete-duration-expired-days-hours": "אתה מורשה למחוק פוסט רק %1 ימים ו %2 שעות אחרי פרסומו",
     "cant-delete-topic-has-reply": "אינך יכול למחוק נושא אחרי שכבר הגיבו בו.",
     "cant-delete-topic-has-replies": "לא ניתן למחוק את הנושא לאחר שקיבל %1 תגובות",
     "content-too-short": "אנא הכנס פוסט ארוך יותר. פוסטים חייבים להכיל לפחות %1 תווים.",
diff --git a/public/language/he/notifications.json b/public/language/he/notifications.json
index e58a931827..1cab5188ab 100644
--- a/public/language/he/notifications.json
+++ b/public/language/he/notifications.json
@@ -41,7 +41,7 @@
     "new_register": "<strong>%1</strong> שלח בקשת הרשמה.",
     "new_register_multiple": "ישנן <strong>%1</strong> בקשות הרשמה שמחכות לבדיקה.",
     "flag_assigned_to_you": "<strong>דיווח %1</strong> הוקצה עבורך",
-    "post_awaiting_review": "Post awaiting review",
+    "post_awaiting_review": "הפוסט ממתין לאישור",
     "email-confirmed": "כתובת המייל אושרה",
     "email-confirmed-message": "תודה שאישרת את כתובת המייל שלך. החשבון שלך פעיל כעת.",
     "email-confirm-error-message": "אירעה שגיאה בעת אישור המייל שלך. ייתכן כי הקוד היה שגוי או פג תוקף.",
diff --git a/public/language/he/pages.json b/public/language/he/pages.json
index 46a3aa6a5b..617bd93223 100644
--- a/public/language/he/pages.json
+++ b/public/language/he/pages.json
@@ -6,10 +6,10 @@
     "popular-month": "נושאים חמים החודש",
     "popular-alltime": "הנושאים החמים בכל הזמנים",
     "recent": "נושאים אחרונים",
-    "moderator-tools": "Moderator Tools",
+    "moderator-tools": "כלי מודרטור",
     "flagged-content": "תוכן מדווח",
     "ip-blacklist": "רשימת IP שחורה",
-    "post-queue": "Post Queue",
+    "post-queue": "פוסטים ממתינים",
     "users/online": "משתמשים מחוברים",
     "users/latest": "משתמשים אחרונים",
     "users/sort-posts": "משתמשים עם המונה הגבוה ביותר",
diff --git a/public/language/he/success.json b/public/language/he/success.json
index 2b24b55fac..da04fbee46 100644
--- a/public/language/he/success.json
+++ b/public/language/he/success.json
@@ -1,7 +1,7 @@
 {
     "success": "הצלחה",
     "topic-post": "העלת פוסט בהצלחה.",
-    "post-queued": "Your post is queued for approval.",
+    "post-queued": "הפוסט שלך ממתין לאישור.",
     "authentication-successful": "הנתונים אומתו בהצלחה",
     "settings-saved": "הנתונים נשמרו!"
 }
\ No newline at end of file
diff --git a/public/language/he/topic.json b/public/language/he/topic.json
index e457ea82e1..b9630978ea 100644
--- a/public/language/he/topic.json
+++ b/public/language/he/topic.json
@@ -59,7 +59,7 @@
     "thread_tools.unlock": "הסר נעילה",
     "thread_tools.move": "הזז נושא",
     "thread_tools.move_all": "הזז הכל",
-    "thread_tools.select_category": "Select Category",
+    "thread_tools.select_category": "בחר קטגוריה",
     "thread_tools.fork": "שכפל נושא",
     "thread_tools.delete": "מחק נושא",
     "thread_tools.delete-posts": "מחק פוסטים",
@@ -75,9 +75,9 @@
     "load_categories": "טוען קטגוריות",
     "confirm_move": "הזז",
     "confirm_fork": "שכפל",
-    "bookmark": "Bookmark",
-    "bookmarks": "Bookmarks",
-    "bookmarks.has_no_bookmarks": "You haven't bookmarked any posts yet.",
+    "bookmark": "הוסף למועדפים",
+    "bookmarks": "מועדפים",
+    "bookmarks.has_no_bookmarks": "לא צירפת אף פוסט למועדפים עדיין",
     "loading_more_posts": "טוען פוסטים נוספים",
     "move_topic": "הזז נושא",
     "move_topics": "הזז נושאים",

From 1c35213934e4c3734da34838278a6f78f591f616 Mon Sep 17 00:00:00 2001
From: Peter Jaszkowiak <p.jaszkow@gmail.com>
Date: Mon, 9 Oct 2017 09:40:36 -0600
Subject: [PATCH 03/16] Fix #5970 and forking while debugging (#5965)

* Fix forking while debugging

Debugger address in use no longer happens

* Fix cropper error
---
 app.js                               |  2 +-
 public/src/modules/pictureCropper.js |  6 ++--
 src/meta/debugFork.js                | 41 ++++++++++++++++++++++++++++
 src/meta/debugParams.js              | 16 -----------
 src/meta/minifier.js                 |  8 ++----
 src/password.js                      |  5 ++--
 test/meta.js                         | 27 ++++++++++++++----
 7 files changed, 71 insertions(+), 34 deletions(-)
 create mode 100644 src/meta/debugFork.js
 delete mode 100644 src/meta/debugParams.js

diff --git a/app.js b/app.js
index d3b4af0697..686b355602 100644
--- a/app.js
+++ b/app.js
@@ -37,7 +37,7 @@ var winston = require('winston');
 var path = require('path');
 var pkg = require('./package.json');
 var file = require('./src/file');
-var debug = require('./src/meta/debugParams')().execArgv.length;
+var debug = require('./src/meta/debugFork').debugging;
 
 global.env = process.env.NODE_ENV || 'production';
 
diff --git a/public/src/modules/pictureCropper.js b/public/src/modules/pictureCropper.js
index 3bd8cf1516..5a02962d1a 100644
--- a/public/src/modules/pictureCropper.js
+++ b/public/src/modules/pictureCropper.js
@@ -1,7 +1,7 @@
 'use strict';
 
 
-define('pictureCropper', ['translator', 'cropper', 'benchpress'], function (translator, cropper, Benchpress) {
+define('pictureCropper', ['translator', 'cropper', 'benchpress'], function (translator, Cropper, Benchpress) {
 	var module = {};
 
 	module.show = function (data, callback) {
@@ -46,7 +46,7 @@ define('pictureCropper', ['translator', 'cropper', 'benchpress'], function (tran
 				var img = document.getElementById('cropped-image');
 				$(img).css('max-height', cropBoxHeight);
 
-				var cropperTool = new cropper.default(img, {
+				var cropperTool = new Cropper(img, {
 					aspectRatio: data.aspectRatio,
 					autoCropArea: 1,
 					viewMode: 1,
@@ -122,7 +122,7 @@ define('pictureCropper', ['translator', 'cropper', 'benchpress'], function (tran
 							$(this).addClass('disabled');
 							cropperTool.destroy();
 
-							cropperTool = new cropper.default(img, {
+							cropperTool = new Cropper(img, {
 								viewMode: 1,
 								autoCropArea: 1,
 								ready: function () {
diff --git a/src/meta/debugFork.js b/src/meta/debugFork.js
new file mode 100644
index 0000000000..575eebd610
--- /dev/null
+++ b/src/meta/debugFork.js
@@ -0,0 +1,41 @@
+'use strict';
+
+var fork = require('child_process').fork;
+
+var debugArg = process.execArgv.find(function (arg) {
+	return /^--(debug|inspect)/.test(arg);
+});
+var debugging = !!debugArg;
+
+debugArg = debugArg ? debugArg.replace('-brk', '').split('=') : ['--debug', 5859];
+var lastAddress = parseInt(debugArg[1], 10);
+
+/**
+ * child-process.fork, but safe for use in debuggers
+ * @param {string} modulePath
+ * @param {string[]} [args]
+ * @param {any} [options]
+ */
+function debugFork(modulePath, args, options) {
+	var execArgv = [];
+	if (global.v8debug || debugging) {
+		lastAddress += 1;
+
+		execArgv = [debugArg[0] + '=' + lastAddress, '--nolazy'];
+	}
+
+	if (!Array.isArray(args)) {
+		options = args;
+		args = [];
+	}
+
+	options = options || {};
+	options = Object.assign({}, options, {
+		execArgv: execArgv,
+	});
+
+	return fork(modulePath, args, options);
+}
+debugFork.debugging = debugging;
+
+module.exports = debugFork;
diff --git a/src/meta/debugParams.js b/src/meta/debugParams.js
deleted file mode 100644
index 6b84500bff..0000000000
--- a/src/meta/debugParams.js
+++ /dev/null
@@ -1,16 +0,0 @@
-'use strict';
-
-module.exports = function (execArgv) {
-	execArgv = execArgv || process.execArgv;
-	var debugArg = execArgv.find(function (arg) {
-		return /^--(debug|inspect)/.test(arg);
-	});
-	if (global.v8debug || debugArg) {
-		debugArg = debugArg ? debugArg.split('=') : ['--debug', 5859];
-		var num = parseInt(debugArg[1], 10) + 1;
-
-		return { execArgv: [debugArg[0] + '=' + num, '--nolazy'] };
-	}
-
-	return { execArgv: [] };
-};
diff --git a/src/meta/minifier.js b/src/meta/minifier.js
index 3b26f99ec5..c51f41578b 100644
--- a/src/meta/minifier.js
+++ b/src/meta/minifier.js
@@ -1,7 +1,6 @@
 'use strict';
 
 var fs = require('fs');
-var childProcess = require('child_process');
 var os = require('os');
 var uglifyjs = require('uglify-js');
 var async = require('async');
@@ -11,7 +10,7 @@ var postcss = require('postcss');
 var autoprefixer = require('autoprefixer');
 var clean = require('postcss-clean');
 
-var debugParams = require('./debugParams');
+var fork = require('./debugFork');
 
 var Minifier = module.exports;
 
@@ -47,13 +46,12 @@ function getChild() {
 		return free.shift();
 	}
 
-	var forkProcessParams = debugParams();
-	var proc = childProcess.fork(__filename, [], Object.assign({}, forkProcessParams, {
+	var proc = fork(__filename, [], {
 		cwd: __dirname,
 		env: {
 			minifier_child: true,
 		},
-	}));
+	});
 	pool.push(proc);
 
 	return proc;
diff --git a/src/password.js b/src/password.js
index 137382c993..6cc1e1776a 100644
--- a/src/password.js
+++ b/src/password.js
@@ -1,9 +1,8 @@
 'use strict';
 
-var fork = require('child_process').fork;
 var path = require('path');
 
-var debugParams = require('./meta/debugParams');
+var fork = require('./meta/debugFork');
 
 exports.hash = function (rounds, password, callback) {
 	forkChild({ type: 'hash', rounds: rounds, password: password }, callback);
@@ -17,7 +16,7 @@ exports.compare = function (password, hash, callback) {
 };
 
 function forkChild(message, callback) {
-	var child = fork(path.join(__dirname, 'bcrypt'), [], debugParams());
+	var child = fork(path.join(__dirname, 'bcrypt'));
 
 	child.on('message', function (msg) {
 		if (msg.err) {
diff --git a/test/meta.js b/test/meta.js
index 539cb57c98..451184d63b 100644
--- a/test/meta.js
+++ b/test/meta.js
@@ -276,13 +276,28 @@ describe('meta', function () {
 		});
 	});
 
-	describe('debug params', function () {
-		it('should return fork arguments for debug', function (done) {
-			var debugParams = require('../src/meta/debugParams');
-			var data = debugParams(['--debug=5858', '--foo=1']);
-			assert.equal(data.execArgv[0], '--debug=5859');
-			assert.equal(data.execArgv[1], '--nolazy');
+	describe('debugFork', function () {
+		var oldArgv;
+		before(function () {
+			oldArgv = process.execArgv;
+			process.execArgv = ['--debug=5858', '--foo=1'];
+		});
+
+		it('should detect debugging', function (done) {
+			var debugFork = require('../src/meta/debugFork');
+			assert(!debugFork.debugging);
+
+			var debugForkPath = require.resolve('../src/meta/debugFork');
+			delete require.cache[debugForkPath];
+
+			debugFork = require('../src/meta/debugFork');
+			assert(debugFork.debugging);
+
 			done();
 		});
+
+		after(function () {
+			process.execArgv = oldArgv;
+		});
 	});
 });

From 425db49fe884249992a66614aa3b6c09efddfef3 Mon Sep 17 00:00:00 2001
From: "Misty (Bot)" <deploy@nodebb.org>
Date: Tue, 10 Oct 2017 09:25:44 +0000
Subject: [PATCH 04/16] Latest translations and fallbacks

---
 public/language/cs/admin/settings/email.json | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/public/language/cs/admin/settings/email.json b/public/language/cs/admin/settings/email.json
index 5a82b3aad5..27d14b96bc 100644
--- a/public/language/cs/admin/settings/email.json
+++ b/public/language/cs/admin/settings/email.json
@@ -15,10 +15,10 @@
 	"smtp-transport.gmail-warning2": "Další informace o tomto řešení, <a href=\"https://nodemailer.com/usage/using-gmail/\">konzultujte s NodeMailer.</a>Alternativou je použití e-mailového rozšíření třetích stran jako je SendGrid, Mailgun atd.<a href=\"{config.relative_path}/admin/extend/plugins\">Dostupné rozšíření zde</a>.",
 	"smtp-transport.host": "Hostitel SMTP",
 	"smtp-transport.port": "Port SMTP",
-	"smtp-transport.security": "Connection security",
-	"smtp-transport.security-encrypted": "Encrypted",
+	"smtp-transport.security": "Zabezpečení připojení",
+	"smtp-transport.security-encrypted": "Šifrované",
 	"smtp-transport.security-starttls": "StartTLS",
-	"smtp-transport.security-none": "None",
+	"smtp-transport.security-none": "Nic",
 	"smtp-transport.username": "Uživatelské jméno",
 	"smtp-transport.username-help": "<b>Pro službu Gmail,</b> zadejte plnou e-mailovou adresu, zvláště, používáte-li spravovanou doménu Google Apps.",
 	"smtp-transport.password": "Heslo",

From 9e9de2edd00b60ce1208e186dd93830fbbef0be5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?=
 <baris@nodebb.org>
Date: Tue, 10 Oct 2017 11:01:10 -0400
Subject: [PATCH 05/16] closes #5976

---
 src/controllers/category.js | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/controllers/category.js b/src/controllers/category.js
index 8edc68d076..c7414fc096 100644
--- a/src/controllers/category.js
+++ b/src/controllers/category.js
@@ -187,8 +187,11 @@ function addTags(categoryData, res) {
 	];
 
 	if (categoryData.backgroundImage) {
+		if (!categoryData.backgroundImage.startsWith('http')) {
+			categoryData.backgroundImage = nconf.get('url') + categoryData.backgroundImage;
+		}
 		res.locals.metaTags.push({
-			name: 'og:image',
+			property: 'og:image',
 			content: categoryData.backgroundImage,
 		});
 	}

From d37c0cfd6735bbfd6ddbea8a88975e7fd107879e Mon Sep 17 00:00:00 2001
From: Julian Lam <julian@nodebb.org>
Date: Tue, 10 Oct 2017 11:16:37 -0400
Subject: [PATCH 06/16] bumping themes again to remove changes for #5733

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

diff --git a/package.json b/package.json
index 19984ac8f6..3a7498ba45 100644
--- a/package.json
+++ b/package.json
@@ -65,10 +65,10 @@
     "nodebb-plugin-soundpack-default": "1.0.0",
     "nodebb-plugin-spam-be-gone": "0.5.1",
     "nodebb-rewards-essentials": "0.0.9",
-    "nodebb-theme-lavender": "4.1.0",
-    "nodebb-theme-persona": "6.1.0",
+    "nodebb-theme-lavender": "4.1.1",
+    "nodebb-theme-persona": "6.1.2",
     "nodebb-theme-slick": "1.1.1",
-    "nodebb-theme-vanilla": "7.1.0",
+    "nodebb-theme-vanilla": "7.1.1",
     "nodebb-widget-essentials": "3.0.6",
     "nodemailer": "4.1.1",
     "passport": "^0.4.0",

From 67ba6bb820fb6f689fe85b11ce03c02796232e35 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?=
 <baris@nodebb.org>
Date: Tue, 10 Oct 2017 11:26:37 -0400
Subject: [PATCH 07/16] closes #5977

---
 src/controllers/topics.js | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/controllers/topics.js b/src/controllers/topics.js
index 347ae8e847..d3a4846390 100644
--- a/src/controllers/topics.js
+++ b/src/controllers/topics.js
@@ -227,6 +227,8 @@ function addTags(topicData, req, res) {
 	var ogImageUrl = '';
 	if (topicData.thumb) {
 		ogImageUrl = topicData.thumb;
+	} else if (topicData.category.backgroundImage && (!postAtIndex || !postAtIndex.index)) {
+		ogImageUrl = topicData.category.backgroundImage;
 	} else if (postAtIndex && postAtIndex.user && postAtIndex.user.picture) {
 		ogImageUrl = postAtIndex.user.picture;
 	} else if (meta.config['og:image']) {

From 5863d64d270c65f4d5f10b4ffcb84db542285106 Mon Sep 17 00:00:00 2001
From: Julian Lam <julian@nodebb.org>
Date: Tue, 10 Oct 2017 11:34:04 -0400
Subject: [PATCH 08/16] prevent inline js payloads from executing in outgoing
 page

---
 src/controllers/index.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/controllers/index.js b/src/controllers/index.js
index dbd41d360c..aa3570b829 100644
--- a/src/controllers/index.js
+++ b/src/controllers/index.js
@@ -391,7 +391,7 @@ Controllers.manifest = function (req, res) {
 Controllers.outgoing = function (req, res, next) {
 	var url = req.query.url || '';
 
-	if (!url) {
+	if (!url || url.startsWith('javascript:')) {
 		return next();
 	}
 

From 72502ff9923ed7d467209bc398635f55bad4be2a Mon Sep 17 00:00:00 2001
From: Julian Lam <julian@nodebb.org>
Date: Tue, 10 Oct 2017 11:48:06 -0400
Subject: [PATCH 09/16] utilising whitelist instead of blacklisting javascript
 protocol

---
 src/controllers/index.js | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/controllers/index.js b/src/controllers/index.js
index aa3570b829..627107b920 100644
--- a/src/controllers/index.js
+++ b/src/controllers/index.js
@@ -390,8 +390,10 @@ Controllers.manifest = function (req, res) {
 
 Controllers.outgoing = function (req, res, next) {
 	var url = req.query.url || '';
+	var allowedProtocols = ['http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'svn', 'tel', 'fax', 'xmpp', 'webcal'];
+	var parsed = require('url').parse(url);
 
-	if (!url || url.startsWith('javascript:')) {
+	if (!url || !allowedProtocols.includes(parsed.protocol.slice(0, -1))) {
 		return next();
 	}
 

From df5178ce7880f0afcb07c53d1f3700881152f918 Mon Sep 17 00:00:00 2001
From: Julian Lam <julian@nodebb.org>
Date: Tue, 10 Oct 2017 12:17:39 -0400
Subject: [PATCH 10/16] fixed typo in outgoing route test, and added new test
 for javascript protocol

---
 test/controllers.js | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/test/controllers.js b/test/controllers.js
index 6f51ebf1ea..04343b6d18 100644
--- a/test/controllers.js
+++ b/test/controllers.js
@@ -216,7 +216,7 @@ describe('Controllers', function () {
 	});
 
 	it('should load /outgoing?url=<url>', function (done) {
-		request(nconf.get('url') + '/outgoing?url=http//youtube.com', function (err, res, body) {
+		request(nconf.get('url') + '/outgoing?url=http://youtube.com', function (err, res, body) {
 			assert.ifError(err);
 			assert.equal(res.statusCode, 200);
 			assert(body);
@@ -233,6 +233,15 @@ describe('Controllers', function () {
 		});
 	});
 
+	it('should 404 on /outgoing with javascript: protocol', function (done) {
+		request(nconf.get('url') + '/outgoing?url=javascript:alert(1);', function (err, res, body) {
+			assert.ifError(err);
+			assert.equal(res.statusCode, 404);
+			assert(body);
+			done();
+		});
+	});
+
 	it('should load /tos', function (done) {
 		meta.config.termsOfUse = 'please accept our tos';
 		request(nconf.get('url') + '/tos', function (err, res, body) {

From 91f385dc9436f117bc58a11cc8e7c87e1a76f434 Mon Sep 17 00:00:00 2001
From: "Misty (Bot)" <deploy@nodebb.org>
Date: Wed, 11 Oct 2017 16:21:50 +0000
Subject: [PATCH 11/16] Incremented version number - v1.6.1

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

diff --git a/package.json b/package.json
index 3a7498ba45..a5d8ec1f37 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
   "name": "nodebb",
   "license": "GPL-3.0",
   "description": "NodeBB Forum",
-  "version": "1.6.0",
+  "version": "1.6.1",
   "homepage": "http://www.nodebb.org",
   "repository": {
     "type": "git",

From 645410131dae0adb027e56503693e7358deb392c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?=
 <baris@nodebb.org>
Date: Wed, 11 Oct 2017 16:51:52 -0400
Subject: [PATCH 12/16] closes #5942

---
 package.json         |  2 +-
 src/widgets/index.js | 19 ++++++++++---------
 2 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/package.json b/package.json
index a5d8ec1f37..8a316d6b0a 100644
--- a/package.json
+++ b/package.json
@@ -69,7 +69,7 @@
     "nodebb-theme-persona": "6.1.2",
     "nodebb-theme-slick": "1.1.1",
     "nodebb-theme-vanilla": "7.1.1",
-    "nodebb-widget-essentials": "3.0.6",
+    "nodebb-widget-essentials": "3.0.7",
     "nodemailer": "4.1.1",
     "passport": "^0.4.0",
     "passport-local": "1.0.0",
diff --git a/src/widgets/index.js b/src/widgets/index.js
index 446174c907..30f2791afa 100644
--- a/src/widgets/index.js
+++ b/src/widgets/index.js
@@ -92,18 +92,19 @@ function renderWidget(widget, uid, options, callback) {
 			}
 
 			if (widget.data.container && widget.data.container.match('{body}')) {
-				translator.translate(widget.data.title, function (title) {
-					Benchpress.compileParse(widget.data.container, {
-						title: title,
-						body: html,
-					}, function (err, html) {
-						next(err, { html: html });
-					});
-				});
+				Benchpress.compileParse(widget.data.container, {
+					title: widget.data.title,
+					body: html,
+				}, next);
 			} else {
-				next(null, { html: html });
+				next(null, html);
 			}
 		},
+		function (html, next) {
+			translator.translate(html, function (translatedHtml) {
+				next(null, { html: translatedHtml });
+			});
+		},
 	], callback);
 }
 

From 410e825bc0c7f41f0a0ecad311ae0263bf4dd5a3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?=
 <baris@nodebb.org>
Date: Wed, 11 Oct 2017 17:52:03 -0400
Subject: [PATCH 13/16] fix upgrade script changing brand:logo to absolute path

---
 src/upgrades/1.6.0/generate-email-logo.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/upgrades/1.6.0/generate-email-logo.js b/src/upgrades/1.6.0/generate-email-logo.js
index 0e95c3b384..6115e773a1 100644
--- a/src/upgrades/1.6.0/generate-email-logo.js
+++ b/src/upgrades/1.6.0/generate-email-logo.js
@@ -45,7 +45,7 @@ module.exports = {
 				}
 
 				meta.configs.setMultiple({
-					'brand:logo': path.join(nconf.get('upload_path'), 'system', path.basename(meta.config['brand:logo'])),
+					'brand:logo': path.join('/assets/uploads/system', path.basename(meta.config['brand:logo'])),
 					'brand:emailLogo': '/assets/uploads/system/site-logo-x50.png',
 				}, next);
 			},

From 681e8074d270a7f989d918ea1be6e910e1c8f228 Mon Sep 17 00:00:00 2001
From: "Misty (Bot)" <deploy@nodebb.org>
Date: Thu, 12 Oct 2017 09:25:36 +0000
Subject: [PATCH 14/16] Latest translations and fallbacks

---
 public/language/fr/admin/settings/email.json    | 14 +++++++-------
 public/language/fr/admin/settings/general.json  |  4 ++--
 public/language/fr/admin/settings/post.json     |  4 ++--
 public/language/fr/error.json                   |  2 +-
 public/language/fr/notifications.json           |  2 +-
 public/language/fr/pages.json                   |  2 +-
 public/language/fr/success.json                 |  2 +-
 public/language/pt-BR/admin/settings/email.json |  6 +++---
 8 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/public/language/fr/admin/settings/email.json b/public/language/fr/admin/settings/email.json
index 06846b88cb..b965d5894b 100644
--- a/public/language/fr/admin/settings/email.json
+++ b/public/language/fr/admin/settings/email.json
@@ -5,20 +5,20 @@
 	"from": "Nom de l’expéditeur",
 	"from-help": "Le nom de l’expéditeur à afficher dans l'e-mail",
 
-	"smtp-transport": "SMTP Transport",
+	"smtp-transport": "Protocole SMTP",
 	"smtp-transport.enabled": "Utiliser un server extérieur pour envoyer les emails",
 	"smtp-transport-help": "Vous pouvez sélectionner depuis une liste de services ou entrer un service personnalisé.",
 	"smtp-transport.service": "Sélectionner un service",
 	"smtp-transport.service-custom": "Service personnalisé",
-	"smtp-transport.service-help": "S",
-	"smtp-transport.gmail-warning1": "There have been reports of the Gmail service not working on accounts with heightened security. In those scenarios, you will have to <a href=\"https://www.google.com/settings/security/lesssecureapps\">configure your GMail account to allow less secure apps</a>.",
-	"smtp-transport.gmail-warning2": "For more information about this workaround, <a href=\"https://nodemailer.com/usage/using-gmail/\">please consult this NodeMailer article on the issue.</a> An alternative would be to utilise a third-party emailer plugin such as SendGrid, Mailgun, etc. <a href=\"{config.relative_path}/admin/extend/plugins\">Browse available plugins here</a>.",
+	"smtp-transport.service-help": "Sélectionner un service ci-dessus afin de renseigner les champs. Sinon, sélectionner \"Service Personnalisé\" et ajouter les informations ci-dessous.",
+	"smtp-transport.gmail-warning1": "Vous pouvez rencontrer des difficultés avec le service Gmail pour les comptes ayant une sécurité élevée. Dans ce cas, vous devez configurer <a href=\"https://www.google.com/settings/security/lesssecureapps\">votre compte Gmail pour qu'il autorise les applications moins sécurisées</a>.",
+	"smtp-transport.gmail-warning2": "Pour plus d'informations à propos de cette solution, <a href=\"https://nodemailer.com/usage/using-gmail/\">consulter l'article sur le NodeMailer sur ce sujet.</a> Une alternative est d'utiliser un service tiers d'envoi d'email tels que SendGrid, Mailgun, etc. <a href=\"{config.relative_path}/admin/extend/plugins\">Consulter les plugins disponibles ici</a>.",
 	"smtp-transport.host": "Host SMTP",
 	"smtp-transport.port": "Port SMTP",
-	"smtp-transport.security": "Connection security",
-	"smtp-transport.security-encrypted": "Encrypted",
+	"smtp-transport.security": "Accès sécurisé",
+	"smtp-transport.security-encrypted": "Cryptage",
 	"smtp-transport.security-starttls": "StartTLS",
-	"smtp-transport.security-none": "None",
+	"smtp-transport.security-none": "Aucun",
 	"smtp-transport.username": "Nom d'utilisateur",
 	"smtp-transport.username-help": "<b>Pour Gmail,</b> entrer l’adresse e-mail complète ici, surtout si vous utilisez un domaine géré par Google Apps.",
 	"smtp-transport.password": "Mot de passe",
diff --git a/public/language/fr/admin/settings/general.json b/public/language/fr/admin/settings/general.json
index ee9c180412..5dd47e1379 100644
--- a/public/language/fr/admin/settings/general.json
+++ b/public/language/fr/admin/settings/general.json
@@ -2,8 +2,8 @@
 	"site-settings": "Réglages du site",
 	"title": "Titre du site",
 	"title.url": "URL",
-	"title.url-placeholder": "The URL of the site title",
-	"title.url-help": "When the title is clicked, send users to this address. If left blank, user will be sent to the forum index.",
+	"title.url-placeholder": "URL du titre du site",
+	"title.url-help": "Adresse à laquelle l'utilisateur est renvoyé lors du clic sur le titre. Si ce champ est vide, l'adresse est celle de l'index du forum.",
 	"title.name": "Nom de votre communauté",
 	"title.show-in-header": "Afficher le titre du site dans l'en-tête",
 	"browser-title": "Titre dans le navigateur",
diff --git a/public/language/fr/admin/settings/post.json b/public/language/fr/admin/settings/post.json
index 560883ff6d..3371e5b6d4 100644
--- a/public/language/fr/admin/settings/post.json
+++ b/public/language/fr/admin/settings/post.json
@@ -6,8 +6,8 @@
 	"sorting.most-votes": "Avec le plus de votes",
 	"sorting.topic-default": "Tri des sujets par défaut",
 	"restrictions": "Restrictions d'envoi",
-	"restrictions.post-queue": "Enable post queue",
-	"restrictions.post-queue-help": "Enabling post queue will put the posts of new users in a queue for approval.",
+	"restrictions.post-queue": "Activer la file d'attente des messages",
+	"restrictions.post-queue-help": "Activer la file d'attente des messages mettra automatiquement les messages des nouveaux utilisateurs dans la liste pour approbation.",
 	"restrictions.seconds-between": "Nombre de secondes entre chaque message",
 	"restrictions.seconds-between-new": "Nombre de secondes entre chaque message pour les nouveaux utilisateurs",
 	"restrictions.rep-threshold": "Seuil de réputation avant que cette restriction soit levée",
diff --git a/public/language/fr/error.json b/public/language/fr/error.json
index 80c2ba5573..f0989ca856 100644
--- a/public/language/fr/error.json
+++ b/public/language/fr/error.json
@@ -4,7 +4,7 @@
     "not-logged-in": "Vous ne semblez pas être connecté.",
     "account-locked": "Votre compte a été temporairement suspendu",
     "search-requires-login": "Rechercher nécessite d'avoir un compte. Veuillez vous identifier ou vous enregistrer.",
-    "goback": "Press back to return to the previous page",
+    "goback": "Appuyez sur retour pour revenir à la page précédente",
     "invalid-cid": "ID de catégorie invalide",
     "invalid-tid": "ID de sujet invalide",
     "invalid-pid": "ID de message invalide",
diff --git a/public/language/fr/notifications.json b/public/language/fr/notifications.json
index f24c13b434..4d34dd3593 100644
--- a/public/language/fr/notifications.json
+++ b/public/language/fr/notifications.json
@@ -41,7 +41,7 @@
     "new_register": "<strong>%1</strong> a envoyé une demande d'incription.",
     "new_register_multiple": "<strong>%1</strong> inscription(s) est en attente de validation.",
     "flag_assigned_to_you": "<strong>Drapeau %1</strong> vous a été assigné",
-    "post_awaiting_review": "Post awaiting review",
+    "post_awaiting_review": "Message en attente de validation",
     "email-confirmed": "Email vérifié",
     "email-confirmed-message": "Merci pour la validation de votre adresse email. Votre compte est désormais activé.",
     "email-confirm-error-message": "Il y a un un problème dans la vérification de votre adresse email. Le code est peut être invalide ou a expiré.",
diff --git a/public/language/fr/pages.json b/public/language/fr/pages.json
index 47b5dac051..820f197157 100644
--- a/public/language/fr/pages.json
+++ b/public/language/fr/pages.json
@@ -9,7 +9,7 @@
     "moderator-tools": "Outils de modération",
     "flagged-content": "Contenu signalé",
     "ip-blacklist": "Liste noire d'adresses IP",
-    "post-queue": "Post Queue",
+    "post-queue": "File d'attente des messages",
     "users/online": "Utilisateurs en ligne",
     "users/latest": "Derniers inscrits",
     "users/sort-posts": "Utilisateurs avec le plus de messages",
diff --git a/public/language/fr/success.json b/public/language/fr/success.json
index 6064afcc64..11894dcd3f 100644
--- a/public/language/fr/success.json
+++ b/public/language/fr/success.json
@@ -1,7 +1,7 @@
 {
     "success": "Terminé",
     "topic-post": "Le message a bien été envoyé.",
-    "post-queued": "Your post is queued for approval.",
+    "post-queued": "Votre message est en attente d'approbation.",
     "authentication-successful": "Authentification réussie",
     "settings-saved": "Paramètres enregistrés !"
 }
\ No newline at end of file
diff --git a/public/language/pt-BR/admin/settings/email.json b/public/language/pt-BR/admin/settings/email.json
index 4b1b67d94e..9a2a3d7a95 100644
--- a/public/language/pt-BR/admin/settings/email.json
+++ b/public/language/pt-BR/admin/settings/email.json
@@ -15,10 +15,10 @@
 	"smtp-transport.gmail-warning2": "Para mais informação sobre este workaround, <a href=\"https://nodemailer.com/usage/using-gmail/\">por gentileza consulte este artigo no NodeMailer sobre o assunto..</a> Uma alternativa seria utilizar um plugin de email terceirizado como o SendGrid, Maigun etc. . <a href=\"{config.relative_path}/admin/extend/plugins\">Explore pelos plugins disponíveis aqui</a>.",
 	"smtp-transport.host": "Host SMTP",
 	"smtp-transport.port": "Porta SMTP",
-	"smtp-transport.security": "Connection security",
-	"smtp-transport.security-encrypted": "Encrypted",
+	"smtp-transport.security": "Segurança da conexão",
+	"smtp-transport.security-encrypted": "Encriptada",
 	"smtp-transport.security-starttls": "StartTLS",
-	"smtp-transport.security-none": "None",
+	"smtp-transport.security-none": "Nenhuma",
 	"smtp-transport.username": "Nome de usuário",
 	"smtp-transport.username-help": "<b>Para o serviço do Gmail,</b> entre com o endereço de email completo aqui, especiamente se você estiver usando um domínio administrado pelo Google Apps.",
 	"smtp-transport.password": "Senha",

From 500c978a2694c43f86ba432580b44044e76eb544 Mon Sep 17 00:00:00 2001
From: Baris Usakli <barisusakli@gmail.com>
Date: Thu, 12 Oct 2017 13:03:43 -0400
Subject: [PATCH 15/16] closes #5944

---
 package.json                                  |   4 +-
 .../en-GB/admin/settings/pagination.json      |   2 +
 public/language/en-GB/user.json               |   1 +
 src/controllers/accounts/settings.js          | 117 +++++++++---------
 src/user/settings.js                          |  14 ++-
 src/views/admin/settings/pagination.tpl       |   4 +-
 6 files changed, 72 insertions(+), 70 deletions(-)

diff --git a/package.json b/package.json
index 8a316d6b0a..89456f495d 100644
--- a/package.json
+++ b/package.json
@@ -66,9 +66,9 @@
     "nodebb-plugin-spam-be-gone": "0.5.1",
     "nodebb-rewards-essentials": "0.0.9",
     "nodebb-theme-lavender": "4.1.1",
-    "nodebb-theme-persona": "6.1.2",
+    "nodebb-theme-persona": "6.1.3",
     "nodebb-theme-slick": "1.1.1",
-    "nodebb-theme-vanilla": "7.1.1",
+    "nodebb-theme-vanilla": "7.1.2",
     "nodebb-widget-essentials": "3.0.7",
     "nodemailer": "4.1.1",
     "passport": "^0.4.0",
diff --git a/public/language/en-GB/admin/settings/pagination.json b/public/language/en-GB/admin/settings/pagination.json
index 27d71b4de5..d565e2d446 100644
--- a/public/language/en-GB/admin/settings/pagination.json
+++ b/public/language/en-GB/admin/settings/pagination.json
@@ -3,7 +3,9 @@
 	"enable": "Paginate topics and posts instead of using infinite scroll.",
 	"topics": "Topic Pagination",
 	"posts-per-page": "Posts per Page",
+	"max-posts-per-page": "Maximum posts per page",
 	"categories": "Category Pagination",
 	"topics-per-page": "Topics per Page",
+	"max-topics-per-page": "Maximum topics per page",
 	"initial-num-load": "Initial Number of Topics to Load on Unread, Recent, and Popular"
 }
\ No newline at end of file
diff --git a/public/language/en-GB/user.json b/public/language/en-GB/user.json
index 2f5e588881..ba61113160 100644
--- a/public/language/en-GB/user.json
+++ b/public/language/en-GB/user.json
@@ -102,6 +102,7 @@
 	"paginate_description" : "Paginate topics and posts instead of using infinite scroll",
 	"topics_per_page": "Topics per Page",
 	"posts_per_page": "Posts per Page",
+	"max_items_per_page": "Maximum %1",
 
 	"notification_sounds" : "Play a sound when you receive a notification",
 	"notifications_and_sounds": "Notifications & Sounds",
diff --git a/src/controllers/accounts/settings.js b/src/controllers/accounts/settings.js
index 2285f5e2dc..515cb33a4e 100644
--- a/src/controllers/accounts/settings.js
+++ b/src/controllers/accounts/settings.js
@@ -12,9 +12,7 @@ var db = require('../../database');
 var helpers = require('../helpers');
 var accountHelpers = require('./helpers');
 
-
-var settingsController = {};
-
+var settingsController = module.exports;
 
 settingsController.get = function (req, res, callback) {
 	var userData;
@@ -91,67 +89,64 @@ settingsController.get = function (req, res, callback) {
 				next(err, data);
 			});
 		},
-		function (data, next) {
+		function (data) {
 			userData.customSettings = data.customSettings;
 			userData.disableEmailSubscriptions = parseInt(meta.config.disableEmailSubscriptions, 10) === 1;
-			next();
+
+			userData.dailyDigestFreqOptions = [
+				{ value: 'off', name: '[[user:digest_off]]', selected: userData.settings.dailyDigestFreq === 'off' },
+				{ value: 'day', name: '[[user:digest_daily]]', selected: userData.settings.dailyDigestFreq === 'day' },
+				{ value: 'week', name: '[[user:digest_weekly]]', selected: userData.settings.dailyDigestFreq === 'week' },
+				{ value: 'month', name: '[[user:digest_monthly]]', selected: userData.settings.dailyDigestFreq === 'month' },
+			];
+
+			userData.bootswatchSkinOptions = [
+				{ name: 'No skin', value: 'noskin' },
+				{ name: 'Default', value: 'default' },
+				{ name: 'Cerulean', value: 'cerulean' },
+				{ name: 'Cosmo', value: 'cosmo'	},
+				{ name: 'Cyborg', value: 'cyborg' },
+				{ name: 'Darkly', value: 'darkly' },
+				{ name: 'Flatly', value: 'flatly' },
+				{ name: 'Journal', value: 'journal'	},
+				{ name: 'Lumen', value: 'lumen' },
+				{ name: 'Paper', value: 'paper' },
+				{ name: 'Readable', value: 'readable' },
+				{ name: 'Sandstone', value: 'sandstone' },
+				{ name: 'Simplex', value: 'simplex' },
+				{ name: 'Slate', value: 'slate'	},
+				{ name: 'Spacelab', value: 'spacelab' },
+				{ name: 'Superhero', value: 'superhero' },
+				{ name: 'United', value: 'united' },
+				{ name: 'Yeti', value: 'yeti' },
+			];
+
+			userData.bootswatchSkinOptions.forEach(function (skin) {
+				skin.selected = skin.value === userData.settings.bootswatchSkin;
+			});
+
+			userData.languages.forEach(function (language) {
+				language.selected = language.code === userData.settings.userLang;
+			});
+
+			userData.disableCustomUserSkins = parseInt(meta.config.disableCustomUserSkins, 10) === 1;
+
+			userData.allowUserHomePage = parseInt(meta.config.allowUserHomePage, 10) === 1;
+
+			userData.hideFullname = parseInt(meta.config.hideFullname, 10) === 1;
+			userData.hideEmail = parseInt(meta.config.hideEmail, 10) === 1;
+
+			userData.inTopicSearchAvailable = plugins.hasListeners('filter:topic.search');
+
+			userData.maxTopicsPerPage = parseInt(meta.config.maxTopicsPerPage, 10) || 20;
+			userData.maxPostsPerPage = parseInt(meta.config.maxPostsPerPage, 10) || 20;
+
+			userData.title = '[[pages:account/settings]]';
+			userData.breadcrumbs = helpers.buildBreadcrumbs([{ text: userData.username, url: '/user/' + userData.userslug }, { text: '[[user:settings]]' }]);
+
+			res.render('account/settings', userData);
 		},
-	], function (err) {
-		if (err) {
-			return callback(err);
-		}
-
-		userData.dailyDigestFreqOptions = [
-			{ value: 'off', name: '[[user:digest_off]]', selected: userData.settings.dailyDigestFreq === 'off' },
-			{ value: 'day', name: '[[user:digest_daily]]', selected: userData.settings.dailyDigestFreq === 'day' },
-			{ value: 'week', name: '[[user:digest_weekly]]', selected: userData.settings.dailyDigestFreq === 'week' },
-			{ value: 'month', name: '[[user:digest_monthly]]', selected: userData.settings.dailyDigestFreq === 'month' },
-		];
-
-
-		userData.bootswatchSkinOptions = [
-			{ name: 'No skin', value: 'noskin' },
-			{ name: 'Default', value: 'default' },
-			{ name: 'Cerulean', value: 'cerulean' },
-			{ name: 'Cosmo', value: 'cosmo'	},
-			{ name: 'Cyborg', value: 'cyborg' },
-			{ name: 'Darkly', value: 'darkly' },
-			{ name: 'Flatly', value: 'flatly' },
-			{ name: 'Journal', value: 'journal'	},
-			{ name: 'Lumen', value: 'lumen' },
-			{ name: 'Paper', value: 'paper' },
-			{ name: 'Readable', value: 'readable' },
-			{ name: 'Sandstone', value: 'sandstone' },
-			{ name: 'Simplex', value: 'simplex' },
-			{ name: 'Slate', value: 'slate'	},
-			{ name: 'Spacelab', value: 'spacelab' },
-			{ name: 'Superhero', value: 'superhero' },
-			{ name: 'United', value: 'united' },
-			{ name: 'Yeti', value: 'yeti' },
-		];
-
-		userData.bootswatchSkinOptions.forEach(function (skin) {
-			skin.selected = skin.value === userData.settings.bootswatchSkin;
-		});
-
-		userData.languages.forEach(function (language) {
-			language.selected = language.code === userData.settings.userLang;
-		});
-
-		userData.disableCustomUserSkins = parseInt(meta.config.disableCustomUserSkins, 10) === 1;
-
-		userData.allowUserHomePage = parseInt(meta.config.allowUserHomePage, 10) === 1;
-
-		userData.hideFullname = parseInt(meta.config.hideFullname, 10) === 1;
-		userData.hideEmail = parseInt(meta.config.hideEmail, 10) === 1;
-
-		userData.inTopicSearchAvailable = plugins.hasListeners('filter:topic.search');
-
-		userData.title = '[[pages:account/settings]]';
-		userData.breadcrumbs = helpers.buildBreadcrumbs([{ text: userData.username, url: '/user/' + userData.userslug }, { text: '[[user:settings]]' }]);
-
-		res.render('account/settings', userData);
-	});
+	], callback);
 };
 
 
diff --git a/src/user/settings.js b/src/user/settings.js
index 42c78a54ba..6ab1ba6816 100644
--- a/src/user/settings.js
+++ b/src/user/settings.js
@@ -135,12 +135,14 @@ module.exports = function (User) {
 	}
 
 	User.saveSettings = function (uid, data, callback) {
-		if (!data.postsPerPage || parseInt(data.postsPerPage, 10) <= 1 || parseInt(data.postsPerPage, 10) > meta.config.postsPerPage) {
-			return callback(new Error('[[error:invalid-pagination-value, 2, ' + meta.config.postsPerPage + ']]'));
+		var maxPostsPerPage = meta.config.maxPostsPerPage || 20;
+		if (!data.postsPerPage || parseInt(data.postsPerPage, 10) <= 1 || parseInt(data.postsPerPage, 10) > maxPostsPerPage) {
+			return callback(new Error('[[error:invalid-pagination-value, 2, ' + maxPostsPerPage + ']]'));
 		}
 
-		if (!data.topicsPerPage || parseInt(data.topicsPerPage, 10) <= 1 || parseInt(data.topicsPerPage, 10) > meta.config.topicsPerPage) {
-			return callback(new Error('[[error:invalid-pagination-value, 2, ' + meta.config.topicsPerPage + ']]'));
+		var maxTopicsPerPage = meta.config.maxTopicsPerPage || 20;
+		if (!data.topicsPerPage || parseInt(data.topicsPerPage, 10) <= 1 || parseInt(data.topicsPerPage, 10) > maxTopicsPerPage) {
+			return callback(new Error('[[error:invalid-pagination-value, 2, ' + maxTopicsPerPage + ']]'));
 		}
 
 		data.userLang = data.userLang || meta.config.defaultLang;
@@ -153,8 +155,8 @@ module.exports = function (User) {
 			openOutgoingLinksInNewTab: data.openOutgoingLinksInNewTab,
 			dailyDigestFreq: data.dailyDigestFreq || 'off',
 			usePagination: data.usePagination,
-			topicsPerPage: Math.min(data.topicsPerPage, parseInt(meta.config.topicsPerPage, 10) || 20),
-			postsPerPage: Math.min(data.postsPerPage, parseInt(meta.config.postsPerPage, 10) || 20),
+			topicsPerPage: Math.min(data.topicsPerPage, parseInt(maxTopicsPerPage, 10) || 20),
+			postsPerPage: Math.min(data.postsPerPage, parseInt(maxPostsPerPage, 10) || 20),
 			userLang: data.userLang || meta.config.defaultLang,
 			followTopicsOnCreate: data.followTopicsOnCreate,
 			followTopicsOnReply: data.followTopicsOnReply,
diff --git a/src/views/admin/settings/pagination.tpl b/src/views/admin/settings/pagination.tpl
index 5caa8d99cd..5f4d77bde3 100644
--- a/src/views/admin/settings/pagination.tpl
+++ b/src/views/admin/settings/pagination.tpl
@@ -18,7 +18,8 @@
 	<div class="col-sm-2 col-xs-12 settings-header">[[admin/settings/pagination:topics]]</div>
 	<div class="col-sm-10 col-xs-12">
 		<form>
-			<strong>[[admin/settings/pagination:posts-per-page]]</strong><br /> <input type="text" class="form-control" value="20" data-field="postsPerPage">
+			<strong>[[admin/settings/pagination:posts-per-page]]</strong><br /> <input type="text" class="form-control" value="20" data-field="postsPerPage"><br/>
+			<strong>[[admin/settings/pagination:max-posts-per-page]]</strong><br /> <input type="text" class="form-control" value="20" data-field="maxPostsPerPage"><br/>
 		</form>
 	</div>
 </div>
@@ -28,6 +29,7 @@
 	<div class="col-sm-10 col-xs-12">
 		<form>
 			<strong>[[admin/settings/pagination:topics-per-page]]</strong><br /> <input type="text" class="form-control" value="20" data-field="topicsPerPage"><br />
+			<strong>[[admin/settings/pagination:max-topics-per-page]]</strong><br /> <input type="text" class="form-control" value="20" data-field="maxTopicsPerPage"><br/>
 			<strong>[[admin/settings/pagination:initial-num-load]]</strong><br /> <input type="text" class="form-control" value="20" data-field="topicsPerList">
 		</form>
 	</div>

From 68bcfb2883d8e2ec4df776467ffb3073fdf8ad06 Mon Sep 17 00:00:00 2001
From: Baris Usakli <barisusakli@gmail.com>
Date: Thu, 12 Oct 2017 13:54:53 -0400
Subject: [PATCH 16/16] closes #5975

---
 src/middleware/header.js |  1 +
 src/posts/user.js        | 19 ++++++++++++++-----
 src/topics.js            | 11 +++++++----
 src/user/settings.js     |  2 +-
 4 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/src/middleware/header.js b/src/middleware/header.js
index e35cc0e333..b9eacca002 100644
--- a/src/middleware/header.js
+++ b/src/middleware/header.js
@@ -82,6 +82,7 @@ module.exports = function (middleware) {
 							uid: 0,
 							username: '[[global:guest]]',
 							userslug: '',
+							fullname: '[[global:guest]]',
 							email: '',
 							picture: user.getDefaultAvatar(),
 							status: 'offline',
diff --git a/src/posts/user.js b/src/posts/user.js
index dd050ddd3e..2ada0b2dd3 100644
--- a/src/posts/user.js
+++ b/src/posts/user.js
@@ -12,12 +12,21 @@ module.exports = function (Posts) {
 	Posts.getUserInfoForPosts = function (uids, uid, callback) {
 		var groupsMap = {};
 		var userData;
+		var userSettings;
 		async.waterfall([
 			function (next) {
-				user.getUsersFields(uids, ['uid', 'username', 'fullname', 'userslug', 'reputation', 'postcount', 'picture', 'signature', 'banned', 'status', 'lastonline', 'groupTitle'], next);
+				async.parallel({
+					userData: function (next) {
+						user.getUsersFields(uids, ['uid', 'username', 'fullname', 'userslug', 'reputation', 'postcount', 'picture', 'signature', 'banned', 'status', 'lastonline', 'groupTitle'], next);
+					},
+					userSettings: function (next) {
+						user.getMultipleUserSettings(uids, next);
+					},
+				}, next);
 			},
-			function (_userData, next) {
-				userData = _userData;
+			function (results, next) {
+				userData = results.userData;
+				userSettings = results.userSettings;
 				var groupTitles = userData.map(function (userData) {
 					return userData && userData.groupTitle;
 				}).filter(function (groupTitle, index, array) {
@@ -38,7 +47,7 @@ module.exports = function (Posts) {
 					}
 				});
 
-				userData.forEach(function (userData) {
+				userData.forEach(function (userData, index) {
 					userData.uid = userData.uid || 0;
 					userData.username = userData.username || '[[global:guest]]';
 					userData.userslug = userData.userslug || '';
@@ -48,7 +57,7 @@ module.exports = function (Posts) {
 					userData.picture = userData.picture || '';
 					userData.status = user.getStatus(userData);
 					userData.signature = validator.escape(String(userData.signature || ''));
-					userData.fullname = validator.escape(String(userData.fullname || ''));
+					userData.fullname = userSettings[index].showfullname ? validator.escape(String(userData.fullname || '')) : undefined;
 					if (parseInt(meta.config.hideFullname, 10) === 1) {
 						userData.fullname = undefined;
 					}
diff --git a/src/topics.js b/src/topics.js
index d4f78801aa..5f744316c0 100644
--- a/src/topics.js
+++ b/src/topics.js
@@ -115,6 +115,9 @@ Topics.getTopicsByTids = function (tids, uid, callback) {
 				users: function (next) {
 					user.getUsersFields(uids, ['uid', 'username', 'fullname', 'userslug', 'reputation', 'postcount', 'picture', 'signature', 'banned', 'status'], next);
 				},
+				userSettings: function (next) {
+					user.getMultipleUserSettings(uids, next);
+				},
 				categories: function (next) {
 					categories.getCategoriesFields(cids, ['cid', 'name', 'slug', 'icon', 'image', 'bgColor', 'color', 'disabled'], next);
 				},
@@ -136,11 +139,11 @@ Topics.getTopicsByTids = function (tids, uid, callback) {
 			}, next);
 		},
 		function (results, next) {
-			if (parseInt(meta.config.hideFullname, 10) === 1) {
-				results.users.forEach(function (user) {
+			results.users.forEach(function (user, index) {
+				if (parseInt(meta.config.hideFullname, 10) === 1 || !results.userSettings[index].showfullname) {
 					user.fullname = undefined;
-				});
-			}
+				}
+			});
 
 			var users = _.zipObject(uids, results.users);
 			var categories = _.zipObject(cids, results.categories);
diff --git a/src/user/settings.js b/src/user/settings.js
index 6ab1ba6816..1a42222acf 100644
--- a/src/user/settings.js
+++ b/src/user/settings.js
@@ -12,7 +12,7 @@ var pubsub = require('../pubsub');
 var LRU = require('lru-cache');
 
 var cache = LRU({
-	max: 1000,
+	max: 2000,
 	length: function () { return 1; },
 	maxAge: 1000 * 60 * 60,
 });