function SyncServer(port) {
    // This sample sync server works against a RAM database - an object of tables + an array of changes to the database

    // ----------------------------------------------------------------------------
    //
    //
    //
    //                               THE DATABASE
    //
    //
    //
    // ----------------------------------------------------------------------------
    var db = {
        tables: {},  // Tables: Each key is a table and its value is another object where each key is the primary key and value is the record / object that is stored in ram.
        changes: [], // Special table that records all changes made to the db. In this simple sample, we let it grow infinitly. In real world, we would have had a regular cleanup of old changes.
        uncommittedChanges: {}, // Map<clientID,Array<change>> Changes where partial=true buffered for being committed later on.
        revision: 0, // Current revision of the database.
        subscribers: [], // Subscribers to when database got changes. Used by server connections to be able to push out changes to their clients as they occur.

        create: function (table, key, obj, clientIdentity) {
            // Create table if it doesnt exist:
            db.tables[table] = db.tables[table] || {};
            // Put the obj into to table
            db.tables[table][key] = obj;
            // Register the change:
            db.changes.push({
                rev: ++db.revision,
                source: clientIdentity,
                type: CREATE,
                table: table,
                key: key,
                obj: obj
            });
            db.trigger();
        },
        update: function (table, key, modifications, clientIdentity) {
            if (db.tables[table]) {
                var obj = db.tables[table][key];
                if (obj) {
                    applyModifications(obj, modifications);
                    db.changes.push({
                        rev: ++db.revision,
                        source: clientIdentity,
                        type: UPDATE,
                        table: table,
                        key: key,
                        mods: modifications
                    });
                    db.trigger();
                }
            }
        },
        'delete': function (table, key, clientIdentity) {
            if (db.tables[table]) {
                if (db.tables[table][key]) {
                    delete db.tables[table][key];
                    db.changes.push({
                        rev: ++db.revision,
                        source: clientIdentity,
                        type: DELETE,
                        table: table,
                        key: key,
                    });
                    db.trigger();
                }
            }
        },
        trigger: function () {
            if (!db.trigger.delayedHandle) {
                // Delay the trigger so that it's only called once per bunch of changes instead of being called for each single change.
                db.trigger.delayedHandle = setTimeout(function () {
                    delete db.trigger.delayedHandle;
                    db.subscribers.forEach(function (subscriber) {
                        try { subscriber(); } catch (e) { }
                    });
                }, 0);
            }
        },
        subscribe: function (fn) {
            db.subscribers.push(fn);
        },
        unsubscribe: function (fn) {
            db.subscribers.splice(db.subscribers.indexOf(fn), 1);
        }
    };















    // ----------------------------------------------------------------------------
    //
    //
    //
    //                               THE SERVER
    //
    //
    //
    // ----------------------------------------------------------------------------

    var nextClientIdentity = 1;

    this.start = function () {
        ws.createServer(function (conn) {

            var syncedRevision = 0; // Used when sending changes to client. Only send changes above syncedRevision since client is already in sync with syncedRevision.

            function sendAnyChanges() {
                // Get all changes after syncedRevision that was not performed by the client we're talkin' to.
                var changes = db.changes.filter(function (change) { return change.rev > syncedRevision && change.source !== conn.clientIdentity; });
                // Compact changes so that multiple changes on same object is merged into a single change.
                var reducedSet = reduceChanges(changes, conn.clientIdentity);
                // Convert the reduced set into an array again.
                var reducedArray = Object.keys(reducedSet).map(function (key) { return reducedSet[key]; });
                // Notice the current revision of the database. We want to send it to client so it knows what to ask for next time.
                var currentRevision = db.revision;

                conn.sendText(JSON.stringify({
                    type: "changes",
                    changes: reducedArray,
                    currentRevision: currentRevision,
                    partial: false // Tell client that these are the only changes we are aware of. Since our mem DB is syncronous, we got all changes in one chunk.
                }));

                syncedRevision = currentRevision; // Make sure we only send revisions coming after this revision next time and not resend the above changes over and over.
            }

            conn.on("text", function (message) {
                var request = JSON.parse(message);
                var type = request.type;
                if (type == "clientIdentity") {
                    // Client Hello: Client says "Hello, My name is <clientIdentity>!" or "Hello, I'm newborn. Please give me a name!"
                    // Client identity is used for the following purpose:
                    //  * When client sends its changes, register the changes into server database and mark each change with the clientIdentity.
                    //  * When sending back changes to client, leave out those marked with the client id so that changes aren't echoed back.
                    // The client should initiate the connection by submitting or requesting a client identity.
                    // This should be done before sending any changes to us.

                    // Client submits his identity or requests one
                    if (request.clientIdentity) {
                        // Client has an identity that we have given earlier
                        conn.clientIdentity = request.clientIdentity;
                    } else {
                        // Client requests an identity. Provide one.
                        conn.clientIdentity = nextClientIdentity++;
                        conn.sendText(JSON.stringify({
                            type: "clientIdentity",
                            clientIdentity: conn.clientIdentity
                        }));
                    }
                } else if (type == "subscribe") {
                    // Client wants to subscribe to server changes happened or happening after given syncedRevision
                    syncedRevision = request.syncedRevision || 0;
                    // Send any changes we have currently:
                    sendAnyChanges();
                    // Start subscribing for additional changes:
                    db.subscribe(sendAnyChanges);

                } else if (type == "changes") {
                    // Client sends its changes to us.
                    var requestId = request.requestId;
                    try {
                        if (!request.changes instanceof Array) {
                            throw "Property 'changes' must be provided and must be an array";
                        }
                        if (!("baseRevision" in request)) {
                            throw "Property 'baseRevision' missing";
                        }
                        // First, if sent change set is partial. 
                        if (request.partial) {
                            // Don't commit changes just yet. Store it in the partialChanges table so far. (In real db, uncommittedChanges would be its own table with columns: {clientID, type, table, key, obj, mods}).
                            // Get or create db.uncommittedChanges array for current client
                            if (db.uncommittedChanges[conn.clientIdentity]) {
                                // Concat the changes to existing change set:
                                db.uncommittedChanges[conn.clientIdentity] = db.uncommittedChanges[conn.clientIdentity].concat(request.changes);
                            } else {
                                // Create the change set:
                                db.uncommittedChanges[conn.clientIdentity] = request.changes;
                            }
                        } else {
                            // This request is not partial. Time to commit.
                            // But first, check if we have previous changes from that client in uncommittedChanges because now is the time to commit them too.
                            if (db.uncommittedChanges[conn.clientIdentity]) {
                                request.changes = db.uncommittedChanges[conn.clientIdentity].concat(request.changes);
                                delete db.uncommittedChanges[conn.clientIdentity];
                            }

                            // ----------------------------------------------
                            //
                            //
                            //
                            // HERE COMES THE QUITE IMPORTANT SYNC ALGORITHM!
                            //
                            // 1. Reduce all server changes (not client changes) that have occurred after given
                            //    baseRevision (our changes) to a set (key/value object where key is the combination of table/primaryKey)
                            // 2. Check all client changes against reduced server
                            //    changes to detect conflict. Resolve conflicts:
                            //      If server created an object with same key as client creates, updates or deletes: Always discard client change.
                            //      If server deleted an object with same key as client creates, updates or deletes: Always discard client change.
                            //      If server updated an object with same key as client updates: Apply all properties the client updates unless they conflict with server updates
                            //      If server updated an object with same key as client creates: Apply the client create but apply the server update on top
                            //      If server updated an object with same key as client deletes: Let client win. Deletes always wins over Updates.
                            //
                            // 3. After resolving conflicts, apply client changes into server database.
                            // 4. Send an ack to the client that we have persisted its changes
                            //
                            //
                            // ----------------------------------------------
                            var baseRevision = request.baseRevision || 0;
                            var serverChanges = db.changes.filter(function (change) { return change.rev > baseRevision });
                            var reducedServerChangeSet = reduceChanges(serverChanges);
                            var resolved = resolveConflicts(request.changes, reducedServerChangeSet);

                            // Now apply the resolved changes:
                            resolved.forEach(function (change) {
                                switch (change.type) {
                                    case CREATE:
                                        db.create(change.table, change.key, change.obj, conn.clientIdentity);
                                        break;
                                    case UPDATE:
                                        db.update(change.table, change.key, change.mods, conn.clientIdentity);
                                        break;
                                    case DELETE:
                                        db.delete(change.table, change.key, conn.clientIdentity);
                                        break;
                                }
                            });
                        }

                        // Now ack client that we have recieved his changes. This should be done no matter if the're buffered into uncommittedChanges
                        // or if the're actually committed to db.
                        conn.sendText(JSON.stringify({
                            type: "ack",
                            requestId: requestId,
                        }));
                    } catch (e) {
                        conn.sendText(JSON.stringify({
                            type: "error",
                            requestId: requestId,
                            message: e.toString()
                        }));
                        conn.close();
                    }
                }

            });

            conn.on("close", function () {
                // When client disconnects, stop subscribing from db.
                db.unsubscribe(sendAnyChanges);
            });
        }).listen(port);
    }
}
WebSocketSyncServer.

    WebSocket server that can be used as a template for how to implement a sync server that interchange changes
    between a Dexie.Syncable client and a database of any kind.

    The code is only dependant on nodejs-websocket. For simplicity reasons, it uses a non-persistent RAM database. It handles conflicts according to
    the Dexie.Syncable specification; The rules of thumb for conflict handling is that:
        1. Client- and server state must be exact the same after a sync operation.
        2. Server changes are applied after client changes - thereby winning over the latter except when client
           already has deleted an object - then the server update wont affect any object since it doesnt exist
           on client.

    In this code, the resolveConflicts() function handles changes on the server AS IF the server changes where
    applied after client changes.