docs: def update(session_token, testing = False):
      """ Compare changes on the client to changes on the server and update local files
      which have changed on the server. """
  
      conflict_comparison_file_dest = cpjoin(config['data_dir'], '.shttpfs', 'conflict_files')
      conflict_resolution_path = cpjoin(config['data_dir'], '.shttpfs', 'conflict_resolution.json')
      conflict_resolutions = file_or_default(conflict_resolution_path, [], json.loads)
  
      # Make sure that all conflicts have been resolved, reject if not
      if not all(len(c['4_resolution']) == 1 for c in conflict_resolutions): conflict_resolutions = []
  
      # Send the changes and the revision of the most recent update to the server to find changes
      manifest, client_changes = find_local_changes()
  
      req_result, headers = server_connection.request("find_changed", {
          "session_token"        : session_token,
          'repository'           : config['repository'],
          "previous_revision"    : manifest['have_revision'],
          }, {
              "client_changes"       : json.dumps(client_changes),
              "conflict_resolutions" : json.dumps(conflict_resolutions)})
  
      if headers['status'] != 'ok':
          if headers['msg'] == 'Please resolve conflicts':
              raise SystemExit('Server error: Please resolve conflicts in .shttpfs/conflict_resolution.json')
          else:
              raise SystemExit('Server error')
  
      result = json.loads(req_result)
      changes = result['sorted_changes']
  
      # Are there any changes?
      if all(v == [] for k,v in changes.iteritems()):
          print 'Nothing to update'
          return
  
      # Pull and delete from remote to local
      if changes['client_pull_files'] != []:
          # Filter out pull ignore files
          filtered_pull_files = []
          for fle in changes['client_pull_files']:
              if not next((True for flter in config['pull_ignore_filters'] if fnmatch.fnmatch(fle['path'], flter)), False):
                  filtered_pull_files.append(fle)
              else: # log ignored items to give the opportunity to pull them in the future
                  with open(cpjoin(working_copy_base_path, '.shttpfs', 'pull_ignored_items'), 'a') as pull_ignore_log:
                      pull_ignore_log.write(json.dumps((result['head'], fle)))
                      pull_ignore_log.flush()
  
          if filtered_pull_files != []:
              print 'Pulling files from server...'
  
          #----------
          for fle in filtered_pull_files:
              print 'Pulling file: ' + fle['path']
  
              req_result, headers = server_connection.request("pull_file", {
                  'session_token' : session_token,
                  'repository'    : config['repository'],
                  'path'          : fle['path']}, gen = True)
  
              if headers['status'] != 'ok':
                  raise SystemExit('Failed to pull file')
              else:
                  make_dirs_if_dont_exist(data_store.get_full_file_path(cpjoin(*fle['path'].split('/')[:-1]) + '/'))
                  data_store.fs_put(fle['path'], req_result)
  
      # Files which have been deleted on server and need deleting on client
      if changes['to_delete_on_client'] != []:
          print 'Removing files deleted on the server...'
  
          for fle in changes['to_delete_on_client']:
              print 'Deleting file: ' + fle['path']
  
              try: data_store.fs_delete(fle['path'])
              except OSError: print 'Warning: remote deleted file does not exist locally.'
  
              # Delete the folder if it is now empty
              try: os.removedirs(os.path.dirname(data_store.get_full_file_path(fle['path'])))
              except OSError as e:
                  if e.errno not in [errno.ENOTEMPTY, errno.ENOENT]: raise
  
      # Files which are in conflict
      if changes['conflict_files'] != []:
          print "There are conflicts!\n"
  
          out = []; server_versions = []
          for fle in changes['conflict_files']:
              fle['resolution'] = ['local', 'remote']
              print 'Path:          ' + fle['file_info']['path']
              print 'Client status: ' + fle['client_status']
              print 'Server status: ' + fle['server_status']
              print
              out.append({'1_path'          : fle['file_info']['path'],
                          '2_client_status' : fle['client_status'],
                          '3_server_status' : fle['server_status'],
                          '4_resolution'    : ['client', 'server']})
              if fle['server_status'] == 'Changed': server_versions.append(fle['file_info'])
  
          #===============
          if server_versions != []:
              choice = None
              if not testing:
                  while True:
                      print 'Download server versions for comparison? (Y/N)'
                      choice = raw_input()
                      if choice.lower() in ['y', 'n']: break
              else: choice = 'y'
  
              errors = []
              if choice == 'y':
                  for fle in server_versions:
                      print 'Pulling file: ' + fle['path']
  
                      result, headers = server_connection.request("pull_file", {
                          'session_token' : session_token,
                          'repository'    : config['repository'],
                          'path'          : fle['path']}, gen = True)
  
                      if headers['status'] != 'ok':
                          errors.append(fle['path'])
  
                      else:
                          make_dirs_if_dont_exist(cpjoin(conflict_comparison_file_dest, *fle['path'].split('/')[:-1]) + '/')
                          result(cpjoin(conflict_comparison_file_dest, fle['path']))
  
                  print 'Server versions of conflicting files written to .shttpfs/conflict_files\n'
  
              pprint(errors)
  
          # ====================
  
          file_put_contents(conflict_resolution_path, json.dumps(out, indent=4, sort_keys=True))
          raise SystemExit("Conflict resolution file written to .shttpfs/conflict_resolution.json\n" +
                           "Please edit this file removing 'client', or 'server' to choose which version to retain.")
  
      # Update the latest revision in the manifest only if there are no conflicts
      else:
          data_store.begin()
          manifest = data_store.read_local_manifest()
          manifest['have_revision'] = result['head']
          data_store.write_local_manifest(manifest)
          data_store.commit()
  
          #delete the conflicts resolution file and recursively delete any conflict files downloaded for comparison
          ignore(os.remove, conflict_resolution_path)
          ignore(shutil.rmtree, conflict_comparison_file_dest)
  
          if changes['to_delete_on_server'] != [] or changes['client_push_files'] != []:
              print 'There are local changes to commit'
          else:
              print 'Update OK'