<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:

def _map_value(self, value):
        ''' Maps a raw deserialized row to proper types '''
        # TODO: Once we've gotten here, we've done the following:
        # -> Recieve the full response, copy it from network buffer it into a ByteBuffer (copy 1)
        # -> Copy all the data into a String (copy 2)
        # -> Deserialize that string (copy 3)
        # -> Map the deserialized JSON to our response format (copy 4, what we are doing in this method)
        # This should not bee needed. Technically, this mapping from transport format to python types should require exactly one copy, 
        # from the network buffer into the python VM.
        if isinstance(value, list):
            out = []
            for c in value:
                out.append(self._map_value( c ))
            return out
        elif isinstance(value, dict) and 'metadata' in value and 'labels' in value['metadata'] and 'self' in value:
            return neo4j.Node(ustr(value['metadata']['id']), value['metadata']['labels'], value['data'])
        elif isinstance(value, dict) and 'metadata' in value and 'type' in value and 'self' in value:
            return neo4j.Relationship(ustr(value['metadata']['id']), value['type'], value['start'].split('/')[-1], value['end'].split('/')[-1], value['data'])
        elif isinstance(value, dict):
            out = {}
            for k,v in value.items():
                out[k] = self._map_value( v )
            return out
        elif isinstance(value, str):
            return ustr(value)
        else:
            return value