diff --git a/public/src/modules/settings.js b/public/src/modules/settings.js
new file mode 100644
index 0000000000..36195d58fb
--- /dev/null
+++ b/public/src/modules/settings.js
@@ -0,0 +1,53 @@
+"use strict";
+/* global define, socket, app */
+
+/*
+ settings.js 2.0, because version 1:
+ - saved everything in "config" hash
+ - was hand-rolled (mm, salmon hand roll)
+ - Relied on app.config (!!)
+ This module should:
+ - Allow you to save to any specified hash
+ - Rely on jQuery
+ - Use sockets
+ - Be more awesome
+*/
+
+define(function() {
+ var Settings = {};
+
+ Settings.load = function(hash, formEl) {
+ socket.emit('modules.settings.get', {
+ hash: hash
+ }, function(err, values) {
+ if (!err) {
+ $(formEl).deserialize(values);
+ } else {
+ console.log('[settings] Unable to load settings for hash: ', hash);
+ }
+ });
+ };
+
+ Settings.save = function(hash, formEl) {
+ var formEl = $(formEl);
+ if (formEl.length) {
+ var values = formEl.serializeObject();
+
+ socket.emit('modules.settings.set', {
+ hash: hash,
+ values: values
+ }, function(err) {
+ app.alert({
+ title: 'Settings Saved',
+ message: 'Restarting NodeBB ',
+ type: 'success',
+ timeout: 2500
+ });
+ });
+ } else {
+ console.log('[settings] Form not found.');
+ }
+ };
+
+ return Settings;
+});
\ No newline at end of file
diff --git a/public/vendor/jquery/deserialize/jquery.deserialize.min.js b/public/vendor/jquery/deserialize/jquery.deserialize.min.js
new file mode 100644
index 0000000000..a13a08e79c
--- /dev/null
+++ b/public/vendor/jquery/deserialize/jquery.deserialize.min.js
@@ -0,0 +1,8 @@
+/**
+ * @author Kyle Florence
+ * @website https://github.com/kflorence/jquery-deserialize/
+ * @version 1.2.1
+ *
+ * Dual licensed under the MIT and GPLv2 licenses.
+ */
+(function(i,b){var f=Array.prototype.push,a=/^(?:radio|checkbox)$/i,e=/\+/g,d=/^(?:option|select-one|select-multiple)$/i,g=/^(?:button|color|date|datetime|datetime-local|email|hidden|month|number|password|range|reset|search|submit|tel|text|textarea|time|url|week)$/i;function c(j){return j.map(function(){return this.elements?i.makeArray(this.elements):this}).filter(":input").get()}function h(j){var k,l={};i.each(j,function(n,m){k=l[m.name];l[m.name]=k===b?m:(i.isArray(k)?k.concat(m):[k,m])});return l}i.fn.deserialize=function(A,l){var y,n,q=c(this),t=[];if(!A||!q.length){return this}if(i.isArray(A)){t=A}else{if(i.isPlainObject(A)){var B,w;for(B in A){i.isArray(w=A[B])?f.apply(t,i.map(w,function(j){return{name:B,value:j}})):f.call(t,{name:B,value:w})}}else{if(typeof A==="string"){var v;A=A.split("&");for(y=0,n=A.length;y