 
 SUBSCRIPTION_ID_REGEX = /_.+?$/
 
+subscriptionDataSet = (collection, connectionId, subscriptionDataId, path, value) ->
+  if Meteor.isClient
+    check connectionId, null
+    check subscriptionDataId, Match.DocumentId
+  else
+    check connectionId, Match.DocumentId
+    check subscriptionDataId, Match.Where checkSubscriptionDataId
+  check path, Match.Where checkPath
+  check value, Match.Any
+
+  if _.isString path
+    update = {}
+    if value is undefined
+      update.$unset = {}
+      update.$unset[path] = ''
+    else
+      update.$set = {}
+      update.$set[path] = value
+
+  # We checked that the "path" is an object.
+  else
+    # We are replacing the whole document, so we have to add
+    # "_connectionId", otherwise it will be removed.
+    update = _.extend path,
+      _connectionId: connectionId
+
+  # We make sure (on the server side) that "_connectionId" matches current
+  # connection to prevent malicious requests who guess the "subscriptionDataId"
+  # to modify the state of other subscriptions. This is not strictly needed
+  # though because on the server "subscriptionDataId" contains "connectionId".
+  collection.update
+    _id: subscriptionDataId
+    _connectionId: connectionId
+  ,
+    update
+
 share.handleMethods = (connection, collection, subscriptionDataId) ->
   dataFunction = (path, equalsFunc) ->
     getData = (fields) ->

      # anyway (it is not published), so {_connectionId: null} in fact does
      # exactly the right thing: finds documents without "_connectionId".
      connectionId = null
    else if @connection?.id
      # Server-side call from the client. "subscriptionDataId" is only
      # "subscriptionId" so we reconstruct whole "subscriptionDataId".
      connectionId = @connection?.id
      subscriptionDataId = "#{connectionId}_#{subscriptionDataId}"
    else
      # On the server side @connection does not exist when method is called
      # from the server side (for example, from the publish function) but
      # we can get "connectionId" from "subscriptionDataId".
      connectionId = subscriptionDataId.replace SUBSCRIPTION_ID_REGEX, ''

    if _.isString path
      update = {}
      if value is undefined
        update.$unset = {}
        update.$unset[path] = ''
      else
        update.$set = {}
        update.$set[path] = value

    # We checked that the "path" is an object.
    else
      # We are replacing the whole document, so we have to add
      # "_connectionId", otherwise it will be removed.
      update = _.extend path,
        _connectionId: connectionId

    # We make sure (on the server side) that "_connectionId" matches current
    # connection to prevent malicious requests who guess the "subscriptionDataId"
    # to modify the state of other subscriptions. This is not strictly needed
    # though because on the server "subscriptionDataId" contains "connectionId".
    collection.update
      _id: subscriptionDataId
      _connectionId: connectionId
    ,
      update

        _connectionId: 0

  setDataFunction = (path, value) ->
    oldValue = Tracker.nonreactive =>
      dataFunction path

    return if EJSON.equals value, oldValue

    if Meteor.isClient
      if value is undefined
        args = [subscriptionDataId, path]
      else
        args = [subscriptionDataId, path, value]

      connection.apply '_subscriptionDataSet', args, (error) =>
        console.error "_subscriptionDataSet error", error if error
    else
      connectionId = subscriptionDataId.replace SUBSCRIPTION_ID_REGEX, ''
      subscriptionDataSet collection, connectionId, subscriptionDataId, path, value

  {data: dataFunction, setData: setDataFunction}

share.subscriptionDataMethods = (collection) ->
  _subscriptionDataSet: (subscriptionDataId, path, value) ->
    check subscriptionDataId, Match.DocumentId
    check path, Match.Where checkPath
    check value, Match.Any

