'Serializes the given object to the output. Returns output.
If setReferencePosition is True, will set the position the
object was written.'

def writeObject(self, obj, output, setReferencePosition=False):

    def proc_variable_length(format, length):
        result = six.b('')
        if (length > 14):
            result += pack('!B', ((format << 4) | 15))
            result = self.writeObject(length, result)
        else:
            result += pack('!B', ((format << 4) | length))
        return result
    if (isinstance(obj, six.text_type) and (obj == six.u(''))):
        obj = six.b('')
    if setReferencePosition:
        self.referencePositions[obj] = len(output)
    if (obj is None):
        output += pack('!B', 0)
    elif isinstance(obj, BoolWrapper):
        if (obj.value is False):
            output += pack('!B', 8)
        else:
            output += pack('!B', 9)
    elif isinstance(obj, Uid):
        size = self.intSize(obj)
        output += pack('!B', ((8 << 4) | (size - 1)))
        output += self.binaryInt(obj)
    elif isinstance(obj, six.integer_types):
        bytes = self.intSize(obj)
        root = math.log(bytes, 2)
        output += pack('!B', ((1 << 4) | int(root)))
        output += self.binaryInt(obj)
    elif isinstance(obj, float):
        output += pack('!B', ((2 << 4) | 3))
        output += self.binaryReal(obj)
    elif isinstance(obj, datetime.datetime):
        timestamp = calendar.timegm(obj.utctimetuple())
        timestamp -= apple_reference_date_offset
        output += pack('!B', 51)
        output += pack('!d', float(timestamp))
    elif isinstance(obj, Data):
        output += proc_variable_length(4, len(obj))
        output += obj
    elif isinstance(obj, six.text_type):
        bytes = obj.encode('utf_16_be')
        output += proc_variable_length(6, (len(bytes) // 2))
        output += bytes
    elif isinstance(obj, six.binary_type):
        bytes = obj
        output += proc_variable_length(5, len(bytes))
        output += bytes
    elif isinstance(obj, HashableWrapper):
        obj = obj.value
        if isinstance(obj, (set, list, tuple)):
            if isinstance(obj, set):
                output += proc_variable_length(12, len(obj))
            else:
                output += proc_variable_length(10, len(obj))
            objectsToWrite = []
            for objRef in obj:
                (isNew, output) = self.writeObjectReference(objRef, output)
                if isNew:
                    objectsToWrite.append(objRef)
            for objRef in objectsToWrite:
                output = self.writeObject(objRef, output, setReferencePosition=True)
        elif isinstance(obj, dict):
            output += proc_variable_length(13, len(obj))
            keys = []
            values = []
            objectsToWrite = []
            for (key, value) in six.iteritems(obj):
                keys.append(key)
                values.append(value)
            for key in keys:
                (isNew, output) = self.writeObjectReference(key, output)
                if isNew:
                    objectsToWrite.append(key)
            for value in values:
                (isNew, output) = self.writeObjectReference(value, output)
                if isNew:
                    objectsToWrite.append(value)
            for objRef in objectsToWrite:
                output = self.writeObject(objRef, output, setReferencePosition=True)
    return output
