+
+sub dbg ($$) {
+ print { $_[0]->{out} } $_[1], "\n" or ERR($_[0], "print(dbg): $!");
+}
+
+sub done ($$) {
+ my ($self, $res) = @_;
+ my $ucb = delete($self->{user_cb}) or return;
+ $ucb->($res, $self->{uarg});
+}
+
+sub ERR ($$) {
+ my ($self, $err) = @_;
+ print { $self->{out} } $err, "\n";
+ eval { done($self, $err) };
+ die $err;
+}
+
+# look for existing objects already in git repos, returns arrayref
+# if found, number of remaining git coderepos to try if not.
+sub solve_existing ($$) {
+ my ($self, $want) = @_;
+ my $try = $want->{try_gits} //= [ @{$self->{gits}} ]; # array copy
+ my $git = shift @$try or die 'BUG {try_gits} empty';
+ my $oid_b = $want->{oid_b};
+ my ($oid_full, $type, $size) = $git->check($oid_b);
+
+ # other than {oid_b, try_gits, try_ibxs}
+ my $have_hints = scalar keys %$want > 3;
+ if (defined($type) && (!$have_hints || $type eq 'blob')) {
+ delete $want->{try_gits};
+ return [ $git, $oid_full, $type, int($size) ]; # done, success
+ }
+
+ # TODO: deal with 40-char "abbreviations" with future SHA-256 git
+ return scalar(@$try) if length($oid_b) >= 40;
+
+ # parse stderr of "git cat-file --batch-check"
+ my $err = $git->last_check_err;
+ my (@oids) = ($err =~ /\b([a-f0-9]{40,})\s+blob\b/g);
+ return scalar(@$try) unless scalar(@oids);
+
+ # TODO: do something with the ambiguous array?
+ # push @ambiguous, [ $git, @oids ];
+
+ dbg($self, "`$oid_b' ambiguous in " .
+ join("\n\t", $git->pub_urls($self->{psgi_env}))
+ . "\n" .
+ join('', map { "$_ blob\n" } @oids));
+ scalar(@$try);
+}
+
+sub extract_diff ($$) {
+ my ($p, $arg) = @_;
+ my ($self, $want, $smsg) = @$arg;