anchor.diff:  
     lister.onFile = (String file) {
       if(file.endsWith('.dart')) {
  -      // excluded test because of issues with dartdoc and sdk libs
         // DARTBUG: http://code.google.com/p/dart/issues/detail?id=5460
  -      // in this case, unittest and args
  +      // exclude libs because of issues with dartdoc and sdk libs
  +      // in this case: unittest and args
         final forbidden = ['test', 'hop', 'tasks'].map((n) => '$n.dart');
         if(forbidden.every((f) => !file.endsWith(f))) {
           libs.add(file);
  
positive.code: 
    return completer.future;
  }
  
negative.code: part of hop_runner;
  
  Future<bool> _compileDocs(TaskContext ctx) {
    final targetBranch = 'gh-pages';
  
    _assertKnownPath();
    final dir = new Directory('');
    final tempDocsDirFuture = dir.createTemp()
        .transform((Directory dir) => dir.path);
    final tempGitDirFuture = dir.createTemp()
        .chain((Directory dir) => _doGitCheckout(ctx, '.', dir.path, targetBranch));
    final getLibsFuture = _getLibs();
  
    return Futures.wait([tempDocsDirFuture, getLibsFuture, tempGitDirFuture])
        .chain((values) {
          final outputDir = values[0];
          final libs = values[1];
          final gitDir = values[2];
          return _ensureProperBranch(ctx, gitDir, outputDir, targetBranch)
              .chain((obj) => _dartDoc(ctx, outputDir, libs))
              .chain((bool dartDocSuccess) {
                if(dartDocSuccess) {
                  return _doCommit(ctx, outputDir, gitDir);
                } else {
                  throw 'boo! docs failed...clean up';
                }
              })
              .chain((obj) => _doPush(ctx, outputDir, gitDir, targetBranch))
              .transform((obj) => true);
    });
  }
  
  Future<bool> _dartDoc(TaskContext ctx, String outputDir, List<String> libs) {
    final args = ['--omit-generation-time', '--out', outputDir, '--verbose'];
    args.addAll(libs);
    ctx.fine("Generating docs into: $outputDir");
    return startProcess(ctx, "dartdoc", args);
  }
  
  Future<String> _doGitCheckout(TaskContext ctx, String sourceGitPath,
      String targetGitPath, String sourceGitBranch) {
  
    return _gitRemoteHasHead(sourceGitPath, 'refs/heads/$sourceGitBranch')
        .chain((bool branchExists) => _doGitClone(ctx, sourceGitPath,
            targetGitPath, sourceGitBranch, branchExists))
        .transform((obj) => targetGitPath);
  }
  
  Future _doGitClone(TaskContext ctx, String sourceGitPath,
      String targetGitPath, String sourceGitBranch, bool doCheckout) {
    final args = ['clone', '--bare', '--shared', sourceGitPath, targetGitPath];
    if(doCheckout) {
      args.addAll(['--single-branch', '--branch', sourceGitBranch]);
    } else {
      args.addAll(['--no-checkout']);
    }
    return Process.run('git', args)
        .transform((ProcessResult pr) {
          _throwIfProcessFailed(ctx, pr);
          ctx.success("Created temp git repo at $targetGitPath");
        });
  }
  
  Future _ensureProperBranch(TaskContext ctx, String gitDir, String workTree,
                             String desiredBranch) {
    final args = _getGitArgs(gitDir, workTree);
    args.addAll(['rev-parse', '--abbrev-ref', 'HEAD']);
  
    return Process.run('git', args)
        .transform((ProcessResult pr) {
          _throwIfProcessFailed(ctx, pr);
          return pr.stdout.trim();
        })
        .chain((String currentBranch) {
          if(currentBranch == desiredBranch) {
            // we have the right branch, cool
            return new Future.immediate(null);
          } else {
            // do the actual checkout
            return _checkoutBare(ctx, gitDir, workTree, desiredBranch);
          }
        });
  }
  
  Future _checkoutBare(TaskContext ctx, String gitDir, String workTree,
                       String desiredBranch) {
    final args = _getGitArgs(gitDir, workTree);
    args.addAll(['checkout', '--orphan', desiredBranch]);
    return Process.run('git', args)
        .chain((ProcessResult pr) {
          _throwIfProcessFailed(ctx, pr);
          final args = _getGitArgs(gitDir, workTree);
          args.addAll(['rm', '-rf', '.']);
          return Process.run('git', args);
        })
        .transform((ProcessResult pr) {
          _throwIfProcessFailed(ctx, pr);
        });
  }
  
  Future _doCommit(TaskContext ctx, String workTree, String gitDir) {
    final args = _getGitArgs(gitDir, workTree);
    // TODO: need more info for commit message
    args.addAll(['add', '--all']);
    return Process.run('git', args)
        .chain((ProcessResult pr) {
          _throwIfProcessFailed(ctx, pr);
          final args = _getGitArgs(gitDir, workTree);
          // TODO: need more info for commit message
          args.addAll(['commit', '-m', 'new goodness', '.']);
  
          return Process.run('git', args);
        })
        .transform((ProcessResult pr) {
          if(pr.exitCode == 1) {
            // could be okay if nothing to commit. should check
            if(pr.stdout.contains("nothing to commit, working directory clean")) {
              // all good
              ctx.success("Nothing seems to have changed");
              return null;
            }
          }
          _throwIfProcessFailed(ctx, pr);
          return null;
        });
  }
  
  Future _doPush(TaskContext ctx, String workTree, String gitDir, String branchName) {
    final args = _getGitArgs(gitDir, workTree);
    args.addAll(['push', 'origin', branchName]);
    return Process.run('git', args)
        .transform((ProcessResult pr) {
          _throwIfProcessFailed(ctx, pr);
          return null;
        });
  }
  
  List<String> _getGitArgs(String gitDir, String workTree) =>
      ['--git-dir=$gitDir', '--work-tree=$workTree'];
  
  Future<bool> _cleanUpTemp(String tempDir, bool dartDocSuccess) {
    final dir = new Directory(tempDir);
    return dir.delete(recursive: true)
        .transform((d) => dartDocSuccess);
  }
  
  Future<List<String>> _getLibs() {
  