anchor.diff:  
     int count = int.parse(options["count"]);
     final globs = new List<Glob>.from(
  -      options["bot"].map((String pattern) => new Glob(pattern)));
  +      options["builder"].map((String pattern) => new Glob(pattern)));
   
     // Download the most recent builds from buildbucket.
  -  int maxBuilds = 1000;
  -  final url = Uri.parse(
  -      "https://cr-buildbucket.appspot.com/_ah/api/buildbucket/v1/search"
  -      "?bucket=luci.dart.ci.sandbox"
  -      "&max_builds=$maxBuilds"
  -      "&status=COMPLETED"
  -      "&fields=builds(url%2Cparameters_json)");
  +  const maxBuilds = 1000;
  +  final url = Uri.parse("https://cr-buildbucket.appspot.com"
  +      "/prpc/buildbucket.v2.Builds/SearchBuilds");
     const maxRetries = 3;
     const timeout = const Duration(seconds: 30);
  -  Map<String, dynamic> object;
  +  final query = jsonEncode({
  +    "predicate": {
  +      "builder": {"project": "dart", "bucket": "ci.sandbox"},
  +      "status": "ENDED_MASK"
  +    },
  +    "pageSize": maxBuilds,
  +    "fields": "builds.*.builder.builder,builds.*.input"
  +  });
  +  late Map<String, dynamic> searchResult;
     for (int i = 1; i <= maxRetries; i++) {
       try {
         final client = new HttpClient();
  -      final request = await client.getUrl(url).timeout(timeout);
  +      final request = await client.postUrl(url).timeout(timeout)
  +        ..headers.contentType = ContentType.json
  +        ..headers.add(HttpHeaders.acceptHeader, ContentType.json)
  +        ..write(query);
         final response = await request.close().timeout(timeout);
  -      object = await response
  +      if (response.statusCode != 200) {
  +        print("Failed to search for builds: "
  +            "${response.statusCode}:${response.reasonPhrase}");
  +        exit(1);
  +      }
  +      const prefix = ")]}'";
  +      searchResult = await (response
             .cast<List<int>>()
             .transform(new Utf8Decoder())
  +          .map((event) =>
  +              event.startsWith(prefix) ? event.substring(prefix.length) : event)
             .transform(new JsonDecoder())
  +          .cast<Map<String, dynamic>>()
             .first
  -          .timeout(timeout);
  +          .timeout(timeout));
         client.close();
         break;
       } on TimeoutException catch (e) {
  -      final inSeconds = e.duration.inSeconds;
  +      final inSeconds = e.duration?.inSeconds;
         stderr.writeln(
             "Attempt $i of $maxRetries timed out after $inSeconds seconds");
         if (i == maxRetries) {
  
positive.code: 
  void main(List<String> args) async {
    final parser = new ArgParser();
    parser.addMultiOption("bot",
        abbr: "b",
        help: "Select the bots matching the glob pattern [option is repeatable]",
        splitCommas: false);
    parser.addOption("branch",
        abbr: "B",
        help: "Select the bots building this branch",
        defaultsTo: "master");
    parser.addOption("count",
        abbr: "c", help: "List this many commits", defaultsTo: "1");
  
negative.code:   }
  
    // Locate the builds we're interested in and map them to each commit. The
    // builds returned by the API are sorted with the newest first. Since builders
    // don't build back in time and always build the latest commit whenever they
    // can, the first time we see a commit, we know it's newer than all commits
    // we haven't seen yet. The insertion order into the buildersForCommits map
    // will then sorted with the newest commit first.
    final builds = searchResult["builds"];
    if (builds == null) {
      print("No builds found");
      exit(1);
    }
    final buildersForCommits = <String, Set<String>>{};
    for (final build in builds) {
      final builder = build["builder"]?["builder"];
      if (builder is! String ||
          builder.endsWith("-beta") ||
          builder.endsWith("-dev") ||
          builder.endsWith("-stable")) {
        // Ignore the release builders. The -try builders aren't in the
        // bucket we're reading.
        continue;
      }
      if (globs.isNotEmpty && !globs.any((glob) => glob.matches(builder))) {
        // Filter way builders we're not interested in.
        continue;
      }
      final input = build["input"]?["gitilesCommit"];
      if (input == null) {
        // Ignore builds not triggered by a commit, e.g. fuzz-linux.
        continue;
      }
      final ref = input["ref"];
      if (ref != "refs/heads/${options['branch']}") {
        // Ignore builds on the wrong branch.
        continue;
      }
      final commit = input["id"] as String;
      final buildersForCommit =
          buildersForCommits.putIfAbsent(commit, () => new Set<String>());
      buildersForCommit.add(builder);
    }
  
    if (buildersForCommits.isEmpty) {
      print("Failed to locate any commits having run on the builders");
      exitCode = 1;
      return;
    }
  
    int maxBots = 0;
    for (final builders in buildersForCommits.values) {
      maxBots = max(maxBots, builders.length);
    }
  
    // List commits run on the most builders.
    for (final commit in buildersForCommits.keys
        .where((commit) => buildersForCommits[commit]!.length == maxBots)
        .take(count)) {
      print(commit);
    }
  