Coerce all of the repetitions and sort them into creations, edits and
        deletions.

        @rtype: L{ListChanges}
        @return: An object describing all of the creations, modifications, and
            deletions represented by C{dataSets}.

def coercer(self, dataSets):
        """
        Coerce all of the repetitions and sort them into creations, edits and
        deletions.

        @rtype: L{ListChanges}
        @return: An object describing all of the creations, modifications, and
            deletions represented by C{dataSets}.
        """
        # Xxx - This does a slightly complex (hey, it's like 20 lines, how
        # complex could it really be?) thing to figure out which elements are
        # newly created, which elements were edited, and which elements no
        # longer exist.  It might be simpler if the client kept track of this
        # and passed a three-tuple of lists (or whatever - some separate data
        # structures) to the server, so everything would be all figured out
        # already.  This would require the client
        # (Mantissa.LiveForm.RepeatableForm) to be more aware of what events
        # the user is triggering in the browser so that it could keep state for
        # adds/deletes/edits separately from DOM and widget objects.  This
        # would remove the need for RepeatedLiveFormWrapper.
        def makeSetter(identifier, values):
            def setter(defaultObject):
                self._idsToObjects[identifier] = defaultObject
                self._lastValues[identifier] = values
            return setter

        created = self._coerceAll(self._extractCreations(dataSets))
        edited = self._coerceAll(self._extractEdits(dataSets))

        coerceDeferred = gatherResults([created, edited])
        def cbCoerced((created, edited)):
            receivedIdentifiers = set()

            createObjects = []
            for (identifier, dataSet) in created:
                receivedIdentifiers.add(identifier)
                createObjects.append(
                    CreateObject(dataSet, makeSetter(identifier, dataSet)))

            editObjects = []
            for (identifier, dataSet) in edited:
                receivedIdentifiers.add(identifier)
                lastValues = self._lastValues[identifier]
                if dataSet != lastValues:
                    modelObject = self._objectFromID(identifier)
                    editObjects.append(EditObject(modelObject, dataSet))
                    self._lastValues[identifier] = dataSet

            deleted = []
            for identifier in set(self._idsToObjects) - receivedIdentifiers:
                existing = self._objectFromID(identifier)
                if existing is not self._NO_OBJECT_MARKER:
                    deleted.append(existing)
                self._idsToObjects.pop(identifier)

            return ListChanges(createObjects, editObjects, deleted)

        coerceDeferred.addCallback(cbCoerced)
        return coerceDeferred