def send(self, data, tx_id=None):
<EOL>if tx_id is None:<EOL><INDENT>tx_id = self.get_tx_id()<EOL><DEDENT>self._tx_buffer[tx_id] = data<EOL>while self._tx_next_id in self._tx_buffer:<EOL><INDENT>data = self._tx_buffer.pop(self._tx_next_id)<EOL>if self._tx_buffer:<EOL><INDENT>safe_call(self.logger.debug, '<STR_LIT>', self._tx_next_id)<EOL><DEDENT>self._tx_next_id = next(self._tx_next_id_gen)<EOL>if not isinstance(data, basestring):<EOL><INDENT>msg = data.get('<STR_LIT>', None)<EOL>if msg in (ADDED, CHANGED, REMOVED):<EOL><INDENT>ids = self.remote_ids[data['<STR_LIT>']]<EOL>meteor_id = data['<STR_LIT:id>']<EOL>if msg == ADDED:<EOL><INDENT>if meteor_id in ids:<EOL><INDENT>msg = data['<STR_LIT>'] = CHANGED<EOL><DEDENT>else:<EOL><INDENT>ids.add(meteor_id)<EOL><DEDENT><DEDENT>elif msg == CHANGED:<EOL><INDENT>if meteor_id not in ids:<EOL><INDENT>msg = data['<STR_LIT>'] = ADDED<EOL>ids.add(meteor_id)<EOL><DEDENT><DEDENT>elif msg == REMOVED:<EOL><INDENT>try:<EOL><INDENT>ids.remove(meteor_id)<EOL><DEDENT>except KeyError:<EOL><INDENT>continue  <EOL><DEDENT><DEDENT><DEDENT>data = '<STR_LIT>' % ejson.dumps([ejson.dumps(data)])<EOL><DEDENT>safe_call(self.logger.debug, '<STR_LIT>', self, data)<EOL>try:<EOL><INDENT>self.ws.send(data)<EOL><DEDENT>except geventwebsocket.WebSocketError:<EOL><INDENT>self.ws.close()<EOL>self._tx_buffer.clear()<EOL>break<EOL><DEDENT><DEDENT>num_waiting = len(self._tx_buffer)<EOL>if num_waiting > <NUM_LIT:10>:<EOL><INDENT>safe_call(<EOL>self.logger.warn,<EOL>'<STR_LIT>',<EOL>tx_id, self._tx_next_id, num_waiting, self._tx_buffer,<EOL>)<EOL><DEDENT>
Send `data` (raw string or EJSON payload) to WebSocket client.