anchor.diff:      String path = uri.path;
       Uri root = documentRoot;
       String dartType = 'application/dart';
  -    if (path.startsWith('/project/packages/')) {
  -      root = packageRoot;
  -      path = path.substring('/project/packages'.length);
  -    } else if (path.startsWith('${PROJECT_PATH}/')) {
  -      root = projectRoot;
  -      path = path.substring(PROJECT_PATH.length);
  -      dartType = 'text/plain';
  -    } else if (path.startsWith('${PACKAGES_PATH}/')) {
  +    if (path.startsWith('${PACKAGES_PATH}/')) {
         root = packageRoot;
         path = path.substring(PACKAGES_PATH.length);
       }
  
positive.code:     JSON,
      UTF8;
  
  class WatchHandler {
    final WebSocket socket;
  
    final Set<String> watchedFiles;
  
    static final Set<WatchHandler> handlers = new Set<WatchHandler>();
  
    static const Map<int, String> fsEventNames = const <int, String>{
      FileSystemEvent.CREATE: 'create',
      FileSystemEvent.DELETE: 'delete',
      FileSystemEvent.MODIFY: 'modify',
      FileSystemEvent.MOVE: 'move',
    };
  
    WatchHandler(this.socket, Iterable<String> watchedFiles)
        : this.watchedFiles = watchedFiles.toSet();
  
    handleFileSystemEvent(FileSystemEvent event) {
      if (event.isDirectory) return;
      String type = fsEventNames[event.type];
      if (type == null) type = 'unknown';
      String path = new Uri.file(event.path).pathSegments.last;
      shouldIgnore(type, path).then((bool ignored) {
        if (ignored) return;
        socket.add(JSON.encode({type: [path]}));
      });
    }
  
    Future<bool> shouldIgnore(String type, String path) {
      switch (type) {
        case 'create':
          return new Future<bool>.value(!watchedFiles.contains(path));
        case 'delete':
          return Conversation.listProjectFiles().then((List<String> files) {
            watchedFiles
                ..retainAll(files)
                ..addAll(files);
            return watchedFiles.contains(path);
          });
        case 'modify':
          return new Future<bool>.value(false);
        default:
          print('Unhandled fs-event for $path ($type).');
          return new Future<bool>.value(true);
      }
    }
  
    onData(_) {
      // TODO(ahe): Move POST code here?
    }
  
    onDone() {
      handlers.remove(this);
    }
  
    static handleWebSocket(WebSocket socket) {
      Conversation.ensureProjectWatcher();
      Conversation.listProjectFiles().then((List<String> files) {
        socket.add(JSON.encode({'create': files}));
        WatchHandler handler = new WatchHandler(socket, files);
        handlers.add(handler);
        socket.listen(
            handler.onData, cancelOnError: true, onDone: handler.onDone);
      });
    }
  
    static onFileSystemEvent(FileSystemEvent event) {
      for (WatchHandler handler in handlers) {
        handler.handleFileSystemEvent(event);
      }
    }
  }
  
  /// Represents a "project" command. These commands are accessed from the URL
  /// "/project?name".
  class ProjectCommand {
    final String name;
  
    /// For each query parameter, this map describes rules for validating them.
    final Map<String, String> rules;
  
    final Function handle;
  
    const ProjectCommand(this.name, this.rules, this.handle);
  }
  
  class Conversation {
    HttpRequest request;
    HttpResponse response;
  
    static const String PROJECT_PATH = '/project';
  
    static const String PACKAGES_PATH = '/packages';
  
    static const String CONTENT_TYPE = HttpHeaders.CONTENT_TYPE;
  
    static const String GIT_TAG = 'try_dart_backup';
  
    static const String COMMIT_MESSAGE = """
  Automated backup.
  
  It is safe to delete tag '$GIT_TAG' if you don't need the backup.""";
  
    static Uri documentRoot = Uri.base;
  
    static Uri projectRoot = Uri.base.resolve('site/try/src/');
  
    static Uri packageRoot = Uri.base.resolve('sdk/lib/_internal/');
  
    static const List<ProjectCommand> COMMANDS = const <ProjectCommand>[
        const ProjectCommand('list', const {'list': null}, handleProjectList),
    ];
  
    static Stream<FileSystemEvent> projectChanges;
  
    static final Map<String, String> gitEnv = computeGitEnv();
  
    Conversation(this.request, this.response);
  
  
negative.code:       .catchError(onError);
  
      Uri uri = request.uri;
      if (uri.path.endsWith('/')) {
        uri = uri.resolve('index.html');
      }
      if (uri.path.contains('..') || uri.path.contains('%')) {
        return notFound(uri.path);
  