private void processResponse(final String line) {
      try {
        final ProtocolFrame frame = new ProtocolFrame(line);
        logFrame(frame, false);

        if (AbstractThreadCommand.isThreadCommand(frame.getCommand())) {
          processThreadEvent(frame);
        } else if (AbstractCommand.isWriteToConsole(frame.getCommand())) {
          writeToConsole(ProtocolParser.parseIo(frame.getPayload()));
        } else if (AbstractCommand.isExitEvent(frame.getCommand())) {
          fireCommunicationError();
        } else if (AbstractCommand.isCallSignatureTrace(frame.getCommand())) {
          recordCallSignature(ProtocolParser.parseCallSignature(frame.getPayload()));
        } else {
          placeResponse(frame.getSequence(), frame);
        }
      } catch (Throwable t) {
        // shouldn't interrupt reader thread
        LOG.error(t);
      }
    }
 private PyThreadInfo parseThreadEvent(ProtocolFrame frame) throws PyDebuggerException {
   return ProtocolParser.parseThread(frame.getPayload(), myDebugProcess.getPositionConverter());
 }
 // todo: extract response processing
 private void processThreadEvent(ProtocolFrame frame) throws PyDebuggerException {
   switch (frame.getCommand()) {
     case AbstractCommand.CREATE_THREAD:
       {
         final PyThreadInfo thread = parseThreadEvent(frame);
         if (!thread.isPydevThread()) { // ignore pydevd threads
           myThreads.put(thread.getId(), thread);
         }
         break;
       }
     case AbstractCommand.SUSPEND_THREAD:
       {
         final PyThreadInfo event = parseThreadEvent(frame);
         PyThreadInfo thread = myThreads.get(event.getId());
         if (thread == null) {
           LOG.error(
               "Trying to stop on non-existent thread: "
                   + event.getId()
                   + ", "
                   + event.getStopReason()
                   + ", "
                   + event.getMessage());
           myThreads.put(event.getId(), event);
           thread = event;
         }
         thread.updateState(PyThreadInfo.State.SUSPENDED, event.getFrames());
         thread.setStopReason(event.getStopReason());
         thread.setMessage(event.getMessage());
         myDebugProcess.threadSuspended(thread);
         break;
       }
     case AbstractCommand.RESUME_THREAD:
       {
         final String id = ProtocolParser.getThreadId(frame.getPayload());
         final PyThreadInfo thread = myThreads.get(id);
         if (thread != null) {
           thread.updateState(PyThreadInfo.State.RUNNING, null);
           myDebugProcess.threadResumed(thread);
         }
         break;
       }
     case AbstractCommand.KILL_THREAD:
       {
         final String id = frame.getPayload();
         final PyThreadInfo thread = myThreads.get(id);
         if (thread != null) {
           thread.updateState(PyThreadInfo.State.KILLED, null);
           myThreads.remove(id);
         }
         break;
       }
     case AbstractCommand.SHOW_CONSOLE:
       {
         final PyThreadInfo event = parseThreadEvent(frame);
         PyThreadInfo thread = myThreads.get(event.getId());
         if (thread == null) {
           myThreads.put(event.getId(), event);
           thread = event;
         }
         thread.updateState(PyThreadInfo.State.SUSPENDED, event.getFrames());
         thread.setStopReason(event.getStopReason());
         thread.setMessage(event.getMessage());
         myDebugProcess.showConsole(thread);
         break;
       }
   }
 }