content: import os
  import sys
  import json
  import sublime
  
  swi_folder = os.path.dirname(os.path.realpath(__file__))
  if not swi_folder in sys.path:
      sys.path.append(swi_folder)
  
  import threading
  import websocket
  import swi
  import utils
  
  class Protocol(object):
      """ Encapsulate websocket connection """
  
      def __init__(self):
          self.next_id = 0
          self.commands = {}
          self.notifications = {}
  
      def connect(self, url, on_open=None, on_close=None):
          """ Attempt to connect to the web socket """
          print (('SWI: Connecting to ' + url))
          websocket.enableTrace(False)
          self.last_break = None
          self.url = url
          self.on_open = on_open
          self.on_close = on_close
          thread = threading.Thread(target=self.thread_callback)
          thread.start()
  
      def thread_callback(self):
          """ Threadproc owning the socket.
              Sets up the callbacks for open, close, and message.
          """
          print ('SWI: Thread started')
          self.socket = websocket.WebSocketApp(self.url, on_message=self.message_callback, on_open=self.open_callback, on_close=self.close_callback)
          self.socket.run_forever()
          print ('SWI: Thread stopped')
  
      def send(self, command, callback=None, options=None):
          """ Send to web socket, with optional callback and options """
          command.id = self.next_id
          command.callback = callback
          command.options = options
          self.commands[command.id] = command
          self.next_id += 1
          if utils.get_setting('ws_debug_mode'):
              print ('SWI: ->> ' + json.dumps(command.request, sort_keys=True, indent=4, separators=(',', ': ')))
          self.socket.send(json.dumps(command.request))
  
      def subscribe(self, notification, callback):
          """ Subscribe to notification with callback """
          notification.callback = callback
          self.notifications[notification.name] = notification
  
      def unsubscribe(self, notification):
          """ Unsubscribe to notification """
          del self.notifications[notification.name]
  
      def message_callback(self, ws, message):
          """ Callback on any incoming packet.
              Parse it and call matching callback.
          """
          parsed = json.loads(message)
          if utils.get_setting('ws_debug_mode'):
              print ('SWI: <<- ' + json.dumps(parsed, sort_keys=True, indent=4, separators=(',', ': ')))
          if 'method' in parsed:
              if parsed['method'] in self.notifications:
                  notification = self.notifications[parsed['method']]
                  if 'params' in parsed:
                      data = notification.parser(parsed['params'])
                  else:
                      data = None
  
                  self.to_main_thread(notification.callback, (data, notification))
          else:
              if parsed['id'] in self.commands:
  
                  command = self.commands[parsed['id']]
                  del self.commands[parsed['id']]
  
                  if 'error' in parsed:
                      self.to_main_thread(print, ("Error from debuggee: " + parsed['error']['message'], )) # comma makes it a tuple
                  else:
                      if 'result' in parsed:
                          command.data = command.parser(parsed['result'])
                      else:
                          command.data = None
  
                      if command.callback:
                          self.to_main_thread(command.callback, (command, )) # comma makes it a tuple
  
      def open_callback(self, ws):
          if self.on_open:
              self.to_main_thread(self.on_open, ())
          print ('SWI: WebSocket opened')
  
      def close_callback(self, ws):
          if self.on_close:
              self.to_main_thread(self.on_close, ())
          print ('SWI: WebSocket closed')
  
      def to_main_thread(self, f, args):
          """ Call back on the main thread
              to simplify the called code
          """
          assert(f)
          if f:   # shutdown timing races
              sublime.set_timeout(lambda: f(*args))
  