anchor.diff:      } else {
         conversation.handle();
       }
  -  }
  -
  -  static ensureProjectWatcher() {
  -    if (projectChanges != null) return;
  -    String nativeDir = projectRoot.toFilePath();
  -    Directory dir = new Directory(nativeDir);
  -    projectChanges = dir.watch();
  -    projectChanges.listen(WatchHandler.onFileSystemEvent);
     }
   
     static onError(error) {
  
positive.code:     response.close();
    }
  
    bool validate(Map<String, String> parameters, Map<String, String> rules) {
      Iterable<String> problems = rules.keys
          .where((name) => !parameters.containsKey(name))
          .map((name) => "Missing parameter: '$name'.");
      if (!problems.isEmpty) {
        badRequest(problems.first);
        return false;
      }
      Set extra = new Set.from(parameters.keys)..removeAll(rules.keys);
      if (extra.isEmpty) return true;
      String extraString = (extra.toList()..sort()).join("', '");
      badRequest("Extra parameters: '$extraString'.");
      return false;
    }
  
    static Future<List<String>> listProjectFiles() {
      String nativeDir = projectRoot.toFilePath();
      Directory dir = new Directory(nativeDir);
      var future = dir.list(recursive: true, followLinks: false).toList();
      return future.then((List<FileSystemEntity> entries) {
        return entries
            .map((e) => e.path)
            .where((p) => p.endsWith('.dart') && p.startsWith(nativeDir))
            .map((p) => p.substring(nativeDir.length))
            .map((p) => new Uri.file(p).path).toList();
      });
    }
  
    static handleProjectList(Conversation self) {
      listProjectFiles().then((List<String> files) {
        self.response
            ..write(JSON.encode(files))
            ..close();
      });
    }
  
    handleProjectRequest() {
      Map<String, String> parameters = request.uri.queryParameters;
      for (ProjectCommand command in COMMANDS) {
        if (parameters.containsKey(command.name)) {
          if (validate(parameters, command.rules)) {
            (command.handle)(this);
          }
          return;
        }
      }
      String commands = COMMANDS.map((c) => c.name).join("', '");
      badRequest("Valid commands are: '$commands'");
    }
  
    handleSocket() {
      if (request.uri.path == '/ws/watch') {
        WebSocketTransformer.upgrade(request).then(WatchHandler.handleWebSocket);
      } else {
        response.done
            .then(onClosed)
  
negative.code:     });
    }
  
    static onRequest(HttpRequest request) {
      Conversation conversation = new Conversation(request, request.response);
      if (WebSocketTransformer.isUpgradeRequest(request)) {
  