content: import hashlib
  import functools
  import glob
  import sublime
  import sublime_plugin
  import urllib.request, urllib.parse, urllib.error
  import threading
  import json
  import types
  import os
  import re
  import time
  import sys
  import imp
  import re
  import logging
  
  swi_folder = os.path.dirname(os.path.realpath(__file__))
  if not swi_folder in sys.path:
      sys.path.append(swi_folder)
  
  import utils
  import webkit
  import projectsystem
  import protocol
  import views
  import styles
  
  from webkit import Console
  from webkit import Runtime
  from webkit import Debugger
  from webkit import Network
  from webkit import Page
  
  from projectsystem import DocumentMapping
  
  imp.reload(sys.modules['webkit.wkutils'])
  imp.reload(sys.modules['webkit.Console'])
  imp.reload(sys.modules['webkit.Runtime'])
  imp.reload(sys.modules['webkit.Debugger'])
  imp.reload(sys.modules['webkit.Network'])
  imp.reload(sys.modules['webkit.Page'])
  
  brk_object = {}
  channel = None
  original_layout = None
  window = None
  file_to_scriptId = []
  paused = False
  current_line = None
  set_script_source = False
  current_call_frame = None
  current_call_frame_position = None
  source_map_state = None
  hostname = utils.get_setting('hostname', 'localhost')
  port = str(utils.get_setting('chrome_remote_port'))
  
  breakpoint_active_icon = 'Packages/Web Inspector/icons/breakpoint_active.png'
  breakpoint_inactive_icon = 'Packages/Web Inspector/icons/breakpoint_inactive.png'
  breakpoint_current_icon = 'Packages/Web Inspector/icons/breakpoint_current.png'
  
  logger = logging.getLogger("SWI")
  logger.propagate = False
  
  def plugin_loaded():
  
      if not logger.handlers and utils.get_setting('debug_mode'):
          logger.addHandler(logging.StreamHandler())
          logger.setLevel(logging.INFO)
  
      close_all_our_windows()
      clear_all_views()
  
  ####################################################################################
  #   COMMANDS
  ####################################################################################
  
  class SwiDebugCommand(sublime_plugin.WindowCommand):
      """ The SWIdebug main quick panel menu 
      """
      
      def run(self):
          """ Called by Sublime to display the quick panel entries """
          mapping = []
  
          if chrome_launched():
              spacer = " " * 7
              if paused:
                  mapping.append(['swi_debug_step_into', 'Step in' + spacer + '    F11'])
                  mapping.append(['swi_debug_step_out', 'Step out' + spacer + ' Shift+F11'])
                  mapping.append(['swi_debug_step_over', 'Step over' + spacer + 'F10'])
                  mapping.append(['swi_debug_pause_resume', 'Resume' + spacer + '   F8'])
              elif channel:
                  mapping.append(['swi_debug_pause_resume', 'Pause' + spacer + '    F8'])
  
              if channel:
                  mapping.append(['swi_debug_evaluate', 'Evaluate selection'])
                  mapping.append(['swi_debug_clear_console', 'Clear console'])
                  mapping.append(['swi_debug_stop', 'Stop debugging'])
                  mapping.append(['swi_debug_reload', 'Reload page'])
              else:
                  mapping.append(['swi_debug_start', 'Start debugging'])
              
              mapping.append(['swi_debug_toggle_breakpoint', 'Toggle Breakpoint'])
  
              if channel:
                  if is_source_map_enabled:
                      mapping.append(['swi_toggle_authored_code', 'Toggle authored code'])
  
                  mapping.append(['swi_debug_clear_breakpoints', 'Clear all Breakpoints'])
                  mapping.append(['swi_dump_file_mappings', 'Dump file mappings'])
          else:
              mapping.append(['swi_debug_start_chrome', 'Start Google Chrome with remote debug port ' + port])
  
          self.cmds = [entry[0] for entry in mapping]
          self.items = [entry[1] for entry in mapping]
          self.window.show_quick_panel(self.items, self.command_selected)
  
      def command_selected(self, index):
          """ Called by Sublime when a quick panel entry is selected """
          utils.assert_main_thread()
          if index == -1:
              return
  
          command = self.cmds[index]
  
          if command == 'swi_dump_file_mappings':
              # we wrap this command so we can use the correct view
              print(command)
              v = views.find_or_create_view('mapping')
              v.run_command('swi_dump_file_mappings_internal')
              return
  
          self.window.run_command(command)
          
  def chrome_launched():
      if channel:
          return True
  
      try:
          proxy = urllib.request.ProxyHandler({})
          opener = urllib.request.build_opener(proxy)
          urllib.request.install_opener(opener)
          urllib.request.urlopen('http://' + hostname + ':' + port + '/json')
          return True
      except:
          pass
  
      return False
  
  class SwiDebugStartChromeCommand(sublime_plugin.WindowCommand):
      """ Represents the start chrome command """
  
      def run(self):
          utils.assert_main_thread()
  
          window = sublime.active_window()
          key = sublime.platform()
  
          # sublime.arch() is x86 on x64 Windows, presumably because it's a 32 bit app
          if key == "windows" and (sublime.arch() == "x64" or sublime.executable_path().find('(x86)') >= 0):
              key += "_x64"
  
          cmd = [os.getenv('GOOGLE_CHROME_PATH', '') + utils.get_setting('chrome_path')[key], '--remote-debugging-port=' + port]
  
          profile = utils.get_setting('chrome_profile') or ''
          if profile:
              profile = '--user-data-dir=' + profile
              cmd.append(profile)
          
          url = utils.get_setting('chrome_url') or ''
          cmd.append(url)        
  
          self.window.run_command('exec', {
              "cmd": cmd
          })
  
  
  class SwiDebugStartCommand(sublime_plugin.WindowCommand):
      """ Connect to the socket. """
  
      def run(self):
          utils.assert_main_thread()
          proxy = urllib.request.ProxyHandler({})
          opener = urllib.request.build_opener(proxy)
          urllib.request.install_opener(opener)
          response = urllib.request.urlopen('http://' + hostname + ':' + port + '/json')
          pages = json.loads(response.read().decode('utf-8'))
          mapping = {}
          for page in pages:
              if 'webSocketDebuggerUrl' in page:
                  url = page['url']
                  if (url.find('chrome-extension://') == 0 or
                          url.find('about:blank') == 0 or
                          url.find('res:') == 0 or
                          url.find('x-mvwit:') == 0 or # seen this on a Windows machine
                          url.lower().find('windows/inetcache') != -1):  # some Outlook goo exposed by IE adapter
                      continue
  
                  mapping[page['webSocketDebuggerUrl']] = page['url']
  
          self.urls = list(mapping.keys())
          items = list(mapping.values())
  
          if len(self.urls) == 0:
              print('No urls proferred by debuggee. Cannot start debugging')
          elif len(self.urls) == 1:
              # just one URL - pick it automatically
              print('Connecting to ' + str(items[0]) + " as it's the only URL offered by the debuggee")
              self.remote_debug_url_selected(0)
          else:
              self.window.show_quick_panel(items, self.remote_debug_url_selected)
  
      def remote_debug_url_selected(self, index):
          utils.assert_main_thread()
          if index == -1:
              return
  
          url = self.urls[index]
  
          global window
          window = sublime.active_window()
  
          global original_layout
          original_layout = window.get_layout()
  
          window.set_layout(utils.get_setting('console_layout'))
  
          load_breaks()
  
          global debugger_enabled
          debugger_enabled = False
          global file_to_scriptId
          file_to_scriptId = []
  
          # Look in the folders opened in Sublime first
          folders = [s.lower() for s in self.window.folders()]
          [logger.info('====Currently open folder is %s, will search there' % s) for s in folders]
  
          # Then also look at the folders containing currently open files
          for v in window.views():
              file = v.file_name()
              if file and os.path.isfile(file): 
                  dir = os.path.dirname(file).lower()
                  logger.info('====Currently open file is in folder %s, will search there' % dir)
                  folders.append(dir)
  
          # Remove redundant folders. Eg., c:\a\b would be redundant if we also have c:\a
          folders.sort(key=len)  # now c:\a is before (and adjacent to) c:\a\b
          for i, s in reversed(list(enumerate(folders))):  # go from long to short entries
              if i - 1 >= 0:
                  if folders[i].find(folders[i-1]) == 0:  # if current contains (or matches) immediately previous
                      folders[i] = None                   # remove current 
  
          folders = [s for s in folders if s and len(s) > 3]  # filter out removed entries, and drive roots like "c:\"  (we're going to recurse..)
  
          [logger.info('====Using folder %s' % s) for s in folders]
  
          self.project_folders = folders
          self.url = url
  
          global channel
          if channel:
              print ('SWI: Socket closed')
              channel.socket.close()
          else:
              channel = protocol.Protocol()
              channel.connect(self.url, self.connected, self.disconnected)
  
          global set_script_source
          set_script_source = utils.get_setting('set_script_source')
  
      def connected(self):
          """ Callback when socket connects """ 
          utils.assert_main_thread()
          channel.subscribe(webkit.Console.messageAdded(), self.messageAdded)
          channel.subscribe(webkit.Console.messageRepeatCountUpdated(), self.messageRepeatCountUpdated)
          channel.subscribe(webkit.Console.messagesCleared(), self.messagesCleared)
          channel.subscribe(webkit.Debugger.scriptParsed(), self.scriptParsed)
          channel.subscribe(webkit.Debugger.paused(), self.paused)
          channel.subscribe(webkit.Debugger.resumed(), self.resumed)
          channel.subscribe(webkit.Debugger.globalObjectCleared(), self.globalObjectCleared)
  
          channel.send(webkit.Debugger.enable(), self.enabled)
          channel.send(webkit.Debugger.setPauseOnExceptions(utils.get_setting('pause_on_exceptions')))
          channel.send(webkit.Console.enable())
          channel.send(webkit.Debugger.canSetScriptSource(), self.canSetScriptSource)
  
          #self.window.run_command('swi_styles_window')
  
          if utils.get_setting('user_agent') is not "":
              channel.send(webkit.Network.setUserAgentOverride(utils.get_setting('user_agent')))
  
          if utils.get_setting('reload_on_start'):
              channel.send(webkit.Network.clearBrowserCache())
              channel.send(webkit.Page.reload(), on_reload)
  
      def disconnected(self):
          """ Notification when socket disconnects """
          utils.assert_main_thread()
          self.window.run_command('swi_debug_stop')
  
      def messageAdded(self, data, notification):
          """ Notification when console message """
          utils.assert_main_thread()
          console_add_message(data)
  
      def messageRepeatCountUpdated(self, data, notification):
          """  Notification when repeated messages """
          utils.assert_main_thread()
          console_repeat_message(data['count'])
  
      def messagesCleared(self, data, notification):
          """ Notification when console cleared (by navigate or on request) """
          utils.assert_main_thread()
          views.clear_view('console')
  
      # build table of mappings from local to server
      def scriptParsed(self, data, notification):
          """ Notification when a script is parsed (loaded).
              Attempts to map it to a local file.
          """
          utils.assert_main_thread()
          url = data['url']
          if url != '':
              url_parts = url.split("/")
              url_parts = list(filter(None, url_parts)) # remove empty entries so we have eg ['http:', 'foo.com', 'bar', 'baz.biz']
              scriptId = str(data['scriptId'])
              file_name = ''
              script = get_script(data['url'])
  
              logger.info('====Notified of url %s====' % url)
  
              if script:
                  if int(scriptId) > int(script['scriptId']):
                      script['scriptId'] = str(scriptId)
                  file_name = script['file']
  
                  # Create a file mapping to look for mapped source code 
                  projectsystem.DocumentMapping.MappingsManager.create_mapping(file_name)
              else:
                  del url_parts[0:2] # remove protocol and domain
                  while len(url_parts) > 0:
                      for folder in self.project_folders:
                          if sublime.platform() == "windows":
                              # eg., folder is c:\site and url is http://localhost/app.js
                              # glob for c:\site\app.js (primary) and c:\site\*\app.js (fallback only - there may be a c:\site\foo\app.js)
                              try:
                                  glob1 = folder + "\\" + "\\".join(url_parts)
                                  if os.path.exists(glob1) and os.path.isfile(glob1): # literal match (url is directly relative to project folder root)
                                      files = [ glob1 ]
                                  else:
                                      glob2 = folder + "\\*\\" + "\\".join(url_parts)
                                      logger.info('    Glob in %s and %s' % (glob1, glob2))
                                      files =  glob.glob(glob1) + glob.glob(glob2)
                              except:
                                  pass
                          else:
                              glob1 = folder + "/" + "/".join(url_parts)
                              glob2 = folder + "/*/" + "/".join(url_parts)
                              logger.info('    Glob in %s and %s' % (glob1, glob2))
                              files = glob.glob(glob1) + glob.glob(glob2)
  
                          if len(files) > 0 and files[0] != '':
                              file_name = files[0]
  
                              if (file_name):
                                  logger.info('    Matched %s' % file_name)
                                  # Create a file mapping to look for mapped source code 
                                  projectsystem.DocumentMapping.MappingsManager.create_mapping(file_name)
  
                                  file_to_scriptId.append({'file': file_name, 'scriptId': str(scriptId), 'url': data['url']})
  
                                  # don't try to match shorter fragments, we already found a match
                                  url_parts = []
                                  break
  
                      if len(url_parts) > 0:
                          del url_parts[0]
  
              if not file_name:
                  logger.info('    Found no local match')
  
              if debugger_enabled and file_name:
                  self.add_breakpoints_to_file(file_name)
  
      def paused(self, data, notification):
          """ Notification that a break was hit.
              Draw an overlay, display the callstack
              and locals, and navigate to the break.
          """
          utils.assert_main_thread()
          
          global paused
          paused = True
  
          update_stack(data)
  
      def resumed(self, data, notification):
          """ Notification that execution resumed.
              Clear the overlay, callstack, and locals,
              and remove the highlight.
          """
          utils.assert_main_thread()
  
          views.clear_view('stack')
          views.clear_view('scope')
          views.clear_view('styles')
  
          channel.send(webkit.Debugger.setOverlayMessage())
  
          global current_file
          current_file = None
  
          global current_line
          current_line = None
  
          global current_call_frame
          current_call_frame = None
  
          global current_call_frame_position
          current_call_frame_position = None
          
          global paused
          paused = False
  
          update_overlays()
  
      def globalObjectCleared(self, data, notification):
          projectsystem.DocumentMapping.MappingsManager.delete_all_mappings()
  
      def enabled(self, command):
          """ Notification that debugging was enabled """
          utils.assert_main_thread()
          global debugger_enabled
          debugger_enabled = True
          for file_to_script_object in file_to_scriptId:
              self.add_breakpoints_to_file(file_to_script_object['file'])
  
      def add_breakpoints_to_file(self, file):
          """ Apply any existing breakpoints.
              Called when debugging starts, and when a new script
              is loaded.
          """
  
          if not file:
              return
  
          found_authored_file = False
  
          scriptId = find_script(file)
  
          # Authored files preferred
          if is_source_map_enabled():
              mapping = projectsystem.DocumentMapping.MappingsManager.get_mapping(file)
              authored_files = mapping.get_authored_files()
              if authored_files:
                  found_authored_file = True
  
              for file_name in authored_files:
                   breakpoints = get_breakpoints_by_full_path(file_name)
                   if breakpoints:
                       for line in list(breakpoints.keys()):
                           column = 0
                           if 'column' in breakpoints[line] and int(breakpoints[line]['column']) >= 0:
                               column = int(breakpoints[line]['column'])
  
                           position = mapping.get_generated_position(file_name, int(line), column)
                           if position:
                               location = webkit.Debugger.Location({'lineNumber': position.zero_based_line(), 'columnNumber': position.zero_based_column(), 'scriptId': scriptId})
                               params = {'authoredLocation': { 'lineNumber': line, 'columnNumber': column, 'file': file_name }}
                               logger.info('Setting breakpoint in %s at %s,%s mapped from %s at %s,%s' % (scriptId, position.file_name, location.lineNumber, location.columnNumber, file_name, line, column))
                               channel.send(webkit.Debugger.setBreakpoint(location), self.breakpointAdded, params)
  
          # Fall back to raw file
          if not found_authored_file:
              breakpoints = get_breakpoints_by_full_path(file)
              if breakpoints:
                  for line in list(breakpoints.keys()):
                      column = 0
                      if 'column' in breakpoints[line] and int(breakpoints[line]['column']) >= 0:
                          column = int(breakpoints[line]['column'])
                      
                      location = webkit.Debugger.Location({'lineNumber': int(line), 'columnNumber': int(column), 'scriptId': scriptId})
                      logger.info('Setting breakpoint in %s %s at %s,%s' % (scriptId, file, line, column))
                      channel.send(webkit.Debugger.setBreakpoint(location), self.breakpointAdded)
  
      def updateAuthoredDocument(self, command):
          save_breaks()
          update_overlays()
  
      def breakpointAdded(self, command):
          """ Notification that a breakpoint was set.
              Gives us the ID and specific location.
          """
          utils.assert_main_thread()
  
          breakpointId = command.data['breakpointId']
          scriptId = command.data['actualLocation'].scriptId
          file = find_script(str(scriptId))
  
          lineNumberActual = str(command.data['actualLocation'].lineNumber)
          columnNumberActual = str(command.data['actualLocation'].columnNumber)
  
          # we persist in terms of the authored file if any, so translate
          positionActual = get_authored_position_if_necessary(file, lineNumberActual, columnNumberActual)
          if positionActual:
              file = positionActual.file_name()
              lineNumberActual = str(positionActual.zero_based_line())
              columnNumberActual = str(positionActual.zero_based_column())
  
          # the breakpoint might have been set before debugging starts
          # in that case it might be stored under a different line number
          # to the true actual number we get back. check both.
  
          lineNumberSent = str(command.params['location']['lineNumber'])
          columnNumberSent = str(command.params['location']['columnNumber'])
  
          # again, prefer the authored location.
          # we could use the source maps again to get it, but those don't
          # always round trip to the original location. instead, pass them through
          if command.options and 'authoredLocation' in command.options:
              assert(file == command.options['authoredLocation']['file'])
              lineNumberSent = str(command.options['authoredLocation']['lineNumber'])
              columnNumberSent = str(command.options['authoredLocation']['columnNumber'])
  
          breakpoints = get_breakpoints_by_full_path(file)
  
          # delete anything persisted under the original line number and
          # move it to the correct line number
          if lineNumberSent != lineNumberActual:
              if lineNumberSent in breakpoints:
                  breakpoints[lineNumberActual] = breakpoints[lineNumberSent].copy()
                  del breakpoints[lineNumberSent]
  
          # finish updating the persisted breakpoint
          breakpoints[lineNumberActual]['status'] = 'enabled'
          breakpoints[lineNumberActual]['breakpointId'] = str(breakpointId)
  
          save_breaks()
          update_overlays()
  
      def canSetScriptSource(self, command):
          """ Notification that script can be edited
              during debugging
          """
          utils.assert_main_thread()
          global set_script_source 
          set_script_source = False
          if 'result' in command.data:
              set_script_source = command.data['result']
  
  class SwiDebugPauseResumeCommand(sublime_plugin.WindowCommand):
      def run(self):
          utils.assert_main_thread()
          # As a convenience, we'll set up the connection
          # if there isn't one. So F5 (etc) can be hit 
          # to get started.
          if not channel:
              if not chrome_launched():
                  SwiDebugStartChromeCommand.run(self)
              else:
                  self.window.run_command('swi_debug_start')
          elif paused:
              logger.info('Resuming...')
              channel.send(webkit.Debugger.resume())
          else:
              logger.info('Pausing...')
              channel.send(webkit.Debugger.setSkipAllPauses(False))
              channel.send(webkit.Debugger.pause())
  
  class SwiDebugStepIntoCommand(sublime_plugin.WindowCommand):
      def run(self):
          if paused:
              channel.send(webkit.Debugger.stepInto())
  
  
  class SwiDebugStepOutCommand(sublime_plugin.WindowCommand):
      def run(self):
          if paused:
              channel.send(webkit.Debugger.stepOut())
  
  
  class SwiDebugStepOverCommand(sublime_plugin.WindowCommand):
      def run(self):
          if paused:
              channel.send(webkit.Debugger.stepOver())
  
  
  class SwiDebugClearConsoleCommand(sublime_plugin.WindowCommand):
      def run(self):
          views.clear_view('console')
  
  
  class SwiDebugEvaluateCommand(sublime_plugin.WindowCommand):
      def run(self):
          utils.assert_main_thread()
          active_view = self.window.active_view()
          regions = active_view.sel()
          for i in range(len(regions)):
              title = active_view.substr(regions[i])
              if paused:
                  if current_call_frame_position:
                      title = "%s on %s" % (active_view.substr(regions[i]), current_call_frame_position)
                  channel.send(webkit.Debugger.evaluateOnCallFrame(current_call_frame, active_view.substr(regions[i])), self.evaluated, {'name': title})
              else:
                  channel.send(webkit.Runtime.evaluate(active_view.substr(regions[i])), self.evaluated, {'name': title})
  
      def evaluated(self, command):
          if command.data.type == 'object':
              channel.send(webkit.Runtime.getProperties(command.data.objectId, True), console_add_properties, command.options)
          else:
              console_add_evaluate(command.data)
  
  class SwiDebugClearBreakpointsCommand(sublime_plugin.WindowCommand):
      def run(self):
          # we choose to remove breakpoints only for active files, so not for unrelated sites
          # so we need to be debugging a site
          for file_to_script_object in file_to_scriptId:
              file_name = file_to_script_object['file']
              breaks = get_breakpoints_by_full_path(file_name)
  
              if breaks:
                  for row in breaks:
                      if 'breakpointId' in breaks[row]:
                          channel.send(webkit.Debugger.removeBreakpoint(breaks[row]['breakpointId']))
  
                  del brk_object[file_name.lower()];
  
          save_breaks()
          update_overlays()
  
  class SwiDebugToggleBreakpointCommand(sublime_plugin.WindowCommand):
      def run(self):
          utils.assert_main_thread()
          active_view = self.window.active_view()
  
          v = views.wrap_view(active_view)
          view_name = v.file_name()
  
          if not view_name: # eg file mapping pane
              return
  
          row = str(v.rows(v.lines())[0])
          init_breakpoint_for_file(view_name)
          breaks = get_breakpoints_by_full_path(view_name)
          if row in breaks:
              if channel:
                  if row in breaks:
                      try:
                          logger.info('Removing breakpoint in %s at %s' % (view_name, row))
                          channel.send(webkit.Debugger.removeBreakpoint(breaks[row]['breakpointId']))
                      except KeyError:
                          print("SWI: A key error occurred while removing the breakpoint")
  
              del_breakpoint_by_full_path(view_name, row)
          else:
              if channel:
                  scriptUrl = ''
                  if projectsystem.DocumentMapping.MappingsManager.is_authored_file(view_name):
                      mapping = projectsystem.DocumentMapping.MappingsManager.get_mapping(view_name)
                      sel = active_view.sel()[0]
                      start = active_view.rowcol(sel.begin())
          
                      position = mapping.get_generated_position(view_name, start[0], start[1])
                      scriptUrl = find_script_url(position.file_name())
                      row = str(position.zero_based_line())
  
                  if not scriptUrl:
                      scriptUrl = find_script_url(view_name)
  
                  if scriptUrl:
                      logger.info('Setting breakpoint by url for %s at %s' % (scriptUrl, row))
                      channel.send(webkit.Debugger.setBreakpointByUrl(int(row), scriptUrl), self.breakpointAdded, view_name)
              else:
                  logger.info('Pending breakpoint for %s at %s' % (view_name, row))
                  record_breakpoint_by_full_path(view_name, row)
  
          update_overlays()
  
      def breakpointAdded(self, command):
          """ Notification that a breakpoint was added successfully """
          utils.assert_main_thread()
          active_view = self.window.active_view()
  
          breakpointId = command.data['breakpointId']
          init_breakpoint_for_file(command.options)
          locations = command.data['locations']
  
          for location in locations:
              scriptId = location.scriptId
              lineNumber = location.lineNumber
              columnNumber = location.columnNumber
  
              file_name = find_script(str(scriptId))
              if projectsystem.DocumentMapping.MappingsManager.is_generated_file(file_name):
                  position = get_authored_position_if_necessary(file_name, lineNumber, columnNumber)
  
                  if position:
                      lineNumber = position.zero_based_line()
                      columnNumber = position.zero_based_column()
                      file_name = position.file_name()
                      init_breakpoint_for_file(file_name)
  
              # If this breakpoint is in TS file, then store the column number as well for future restoration
              if projectsystem.DocumentMapping.MappingsManager.is_generated_file(file_name):
                  record_breakpoint_by_full_path(file_name, str(lineNumber), -1, 'enabled', breakpointId)
              else:
                  record_breakpoint_by_full_path(file_name, str(lineNumber), columnNumber, 'enabled', breakpointId)
  
              logger.info('Breakpoint set in %s %s at (%s,%s)' % (scriptId, file_name, lineNumber, columnNumber))
  
          update_overlays()
  
  class SwiDebugStopCommand(sublime_plugin.WindowCommand):
  
      def run(self):
          active_view = self.window.active_view()
  
          close_all_our_windows()
          clear_all_views()
  
          disable_all_breakpoints()
  
          global paused
          paused = False
  
          global debugger_enabled
          debugger_enabled = False
  
          global current_file
          current_file = None
  
          global current_line
          current_line = None
  
          update_overlays()
          
          global channel
          if channel:
              try:
                  channel.socket.close()
              except:
                  print ('SWI: Can\'t close socket')
              finally:
                  channel = None
  
  
  class SwiDebugReloadCommand(sublime_plugin.WindowCommand):
      def run(self):
          if channel:
              logger.info('Reloading page')
              channel.send(webkit.Network.clearBrowserCache())
              channel.send(webkit.Page.reload(), on_reload)
  
  class SwiDumpFileMappingsInternalCommand(sublime_plugin.TextCommand):
      """ Called internally on the file mapping view """
      def run(self, edit):
          
          views.clear_view('mapping')
  
          dump = lambda obj: json.dumps(obj, sort_keys=True, indent=4, separators=(',', ': '))
  
          text = "File to URL mappings:\n\n"
          text += dump(file_to_scriptId) + "\n\n"
          text += "Authored to source mappings:\n\n"
          text += dump(projectsystem.DocumentMapping.MappingsManager.get_all_source_file_mappings()) + "\n\n"
          text += "Breakpoints:\n\n"
          text += dump(brk_object) + "\n\n"
  
          self.view.insert(edit, 0, text)
  
  
  class SwiToggleAuthoredCodeCommand(sublime_plugin.TextCommand):
      """ This is a TextCommand because it specifically applies only
          to the active view
      """
      def run(self, edit):
          utils.assert_main_thread()
          view = views.wrap_view(self.view)
          view_name = view.file_name();
          if not view_name: # eg file mapping pane
              return
  
          file_mapping = projectsystem.DocumentMapping.MappingsManager.get_mapping(view_name)
          if file_mapping:
              is_authored_file = projectsystem.DocumentMapping.MappingsManager.is_authored_file(view_name)
   
              sel = view.sel()[0]
              start = view.rowcol(sel.begin())
              end = view.rowcol(sel.end())
  
              mapped_start = file_mapping.get_generated_position(view_name, start[0], start[1]) \
                                          if is_authored_file \
                                          else file_mapping.get_authored_position(start[0], start[1])
  
              if (start != end):
                  mapped_end = file_mapping.get_generated_position(view_name, end[0], end[1]) \
                                            if is_authored_file \
                                            else file_mapping.get_authored_position(end[0], end[1])
              else:
                  mapped_end = mapped_start
  
              window = sublime.active_window()
              window.focus_group(0)
              view = window.open_file(mapped_start.file_name())
              
              do_when(lambda: not view.is_loading(), lambda: set_selection(view,
                                                                           mapped_start.zero_based_line(),
                                                                           mapped_start.zero_based_column(),
                                                                           mapped_end.zero_based_line(),
                                                                           mapped_end.zero_based_column()))
  
  def update_overlays():
  
      # loop over all views, identifying the files
      # we need to draw into
      for v in window.views():
          v = views.wrap_view(v)
  
          if not v.file_name():
              continue
  
          v.erase_regions('swi_breakpoint_inactive')
          v.erase_regions('swi_breakpoint_active')
          v.erase_regions('swi_breakpoint_current')
  
          breaks = get_breakpoints_by_full_path(v.file_name()) or {}
  
          enabled = []
          disabled = []
  
          for key in list(breaks.keys()):
              if breaks[key]['status'] == 'enabled':
                  enabled.append(key)
  