anchor.diff:        env.dump(loupe: problemBoard.loupe);
       }
   
  +    Stopwatch watch = new Stopwatch();
  +    watch.start();
       searchSolution(problemBoard, env: env).forEach(print);
  +    watch.stop();
  +    if (time) stderr.writeln("Time took to solve: ${watch.elapsed}");
     },
   });
  +
  +void writeHelp(ArgParser parser, StringSink target) {
  +  target.write("Parameters: \n  ");
  +  target.writeln(parser.usage.replaceAll("\n", "\n  "));
  +  if (parser.commands.isNotEmpty) {
  +    target.writeln("\nCommand help: ");
  +    for (String cmd in parser.commands.keys.toList(growable: false)..sort())
  +      target.writeln("\tsudoku_cli.dart ${cmd} --help");
  +  }
  +}
   
   void main(List<String> args) {
     ArgParser parser = new ArgParser();
  
positive.code:   },
    "solve": (ArgResults result) {
      bool showSteps = result["steps"];
      String problem = result.rest[0];
      if (problem == "-") problem = stdin.readLineSync();
      SudokuBoard problemBoard = new SudokuBoard.fromString(problem);
  
negative.code: }
  
  Duration percentileDuration(Iterable<Duration> durations, double percentile) {
    if (durations.length == 1) return durations.first;
    double position = durations.length * percentile;
    double positionFraction = position % 1;
    if (positionFraction == 0) return durations.skip(position.floor()).first;
  