// Path: src/main/java/org/netmelody/cieye/core/domain/RunningBuild.java
// public final class RunningBuild {
//     
//     private final Percentage progress;
//     private final Status status;
// 
//     public RunningBuild() {
//         this(percentageOf(100), Status.GREEN);
//     }
// 
//     public RunningBuild(Percentage progress, Status status) {
//         this.progress = progress;
//         this.status = status;
//     }
//     
//     public static RunningBuild buildAt(Percentage progress) {
//         return buildAt(progress, Status.UNKNOWN);
//     }
//     
//     public static RunningBuild buildAt(Percentage progress, Status status) {
//         return new RunningBuild(progress, status);
//     }
//     
//     public Percentage progress() {
//         return progress;
//     }
//     
//     public Status status() {
//         return status;
//     }
// 
//     public RunningBuild advancedBy(int percentageIncrement) {
//         return new RunningBuild(percentageOf(Math.min(progress.value() + percentageIncrement, 100)), status);
//     }
// 
//     public RunningBuild withStatus(Status status) {
//         return new RunningBuild(progress, status);
//     }
// }
// 
// Path: src/main/java/org/netmelody/cieye/spies/jenkins/jsondomain/ChangeSetItem.java
// public final class ChangeSetItem {
//     //Date date;
//     public String msg;
//     public String comment;
//     public long revision;
//     public String user;
//     //paths
// }
// 
// Path: src/main/java/org/netmelody/cieye/spies/jenkins/jsondomain/User.java
// public final class User {
//     public String absoluteUrl;
//     public String fullName;
// }
// 
// Path: src/main/java/org/netmelody/cieye/core/domain/RunningBuild.java
// public static RunningBuild buildAt(Percentage progress) {
//     return buildAt(progress, Status.UNKNOWN);
// }


import com.google.common.base.Function;
import com.google.common.base.Predicate;
import org.netmelody.cieye.core.domain.RunningBuild;
import org.netmelody.cieye.core.domain.Sponsor;
import org.netmelody.cieye.core.domain.Status;
import org.netmelody.cieye.core.domain.TargetDetail;
import org.netmelody.cieye.core.observation.KnownOffendersDirectory;
import org.netmelody.cieye.spies.jenkins.jsondomain.Build;
import org.netmelody.cieye.spies.jenkins.jsondomain.BuildDetail;
import org.netmelody.cieye.spies.jenkins.jsondomain.ChangeSetItem;
import org.netmelody.cieye.spies.jenkins.jsondomain.Job;
import org.netmelody.cieye.spies.jenkins.jsondomain.JobDetail;
import org.netmelody.cieye.spies.jenkins.jsondomain.User;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.google.common.collect.Collections2.filter;
import static com.google.common.collect.Collections2.transform;
import static com.google.common.collect.Lists.newArrayList;
import static java.util.Collections.unmodifiableSet;
import static org.netmelody.cieye.core.domain.Percentage.percentageOf;
import static org.netmelody.cieye.core.domain.RunningBuild.buildAt;
            return sponsorCache.get(buildUrl);
        }
        
        final BuildDetail buildData = this.buildDetailFetcher.detailsOf(buildUrl);
        if (null == buildData) {
            return new HashSet<Sponsor>();
        }
        
        final Set<Sponsor> sponsors = new HashSet<Sponsor>(detective.search(commitMessagesOf(buildData)));
        
        if (sponsors.isEmpty()) {
            for (String upstreamBuildUrl : buildData.upstreamBuildUrls()) {
                sponsors.addAll(sponsorsOf(communicator.endpoint() + "/" + upstreamBuildUrl));
            }
        }
        
        final Set<Sponsor> result = unmodifiableSet(sponsors);
        if (!buildData.building) {
            sponsorCache.put(buildUrl, result);
        }
        
        return result;
    }
    
    private String commitMessagesOf(BuildDetail build) {
        if (null == build.changeSet || null == build.changeSet.items) {
            return "";
        }
        
        final StringBuilder result = new StringBuilder();
// Path: src/main/java/org/netmelody/cieye/core/domain/RunningBuild.java
// public final class RunningBuild {
//     
//     private final Percentage progress;
//     private final Status status;
// 
//     public RunningBuild() {
//         this(percentageOf(100), Status.GREEN);
//     }
// 
//     public RunningBuild(Percentage progress, Status status) {
//         this.progress = progress;
//         this.status = status;
//     }
//     
//     public static RunningBuild buildAt(Percentage progress) {
//         return buildAt(progress, Status.UNKNOWN);
//     }
//     
//     public static RunningBuild buildAt(Percentage progress, Status status) {
//         return new RunningBuild(progress, status);
//     }
//     
//     public Percentage progress() {
//         return progress;
//     }
//     
//     public Status status() {
//         return status;
//     }
// 
//     public RunningBuild advancedBy(int percentageIncrement) {
//         return new RunningBuild(percentageOf(Math.min(progress.value() + percentageIncrement, 100)), status);
//     }
// 
//     public RunningBuild withStatus(Status status) {
//         return new RunningBuild(progress, status);
//     }
// }
// 
// Path: src/main/java/org/netmelody/cieye/spies/jenkins/jsondomain/ChangeSetItem.java
// public final class ChangeSetItem {
//     //Date date;
//     public String msg;
//     public String comment;
//     public long revision;
//     public String user;
//     //paths
// }
// 
// Path: src/main/java/org/netmelody/cieye/spies/jenkins/jsondomain/User.java
// public final class User {
//     public String absoluteUrl;
//     public String fullName;
// }
// 
// Path: src/main/java/org/netmelody/cieye/core/domain/RunningBuild.java
// public static RunningBuild buildAt(Percentage progress) {
//     return buildAt(progress, Status.UNKNOWN);
// }


// Path: src/main/java/org/netmelody/cieye/spies/jenkins/JobAnalyser.java
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import org.netmelody.cieye.core.domain.RunningBuild;
import org.netmelody.cieye.core.domain.Sponsor;
import org.netmelody.cieye.core.domain.Status;
import org.netmelody.cieye.core.domain.TargetDetail;
import org.netmelody.cieye.core.observation.KnownOffendersDirectory;
import org.netmelody.cieye.spies.jenkins.jsondomain.Build;
import org.netmelody.cieye.spies.jenkins.jsondomain.BuildDetail;
import org.netmelody.cieye.spies.jenkins.jsondomain.ChangeSetItem;
import org.netmelody.cieye.spies.jenkins.jsondomain.Job;
import org.netmelody.cieye.spies.jenkins.jsondomain.JobDetail;
import org.netmelody.cieye.spies.jenkins.jsondomain.User;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.google.common.collect.Collections2.filter;
import static com.google.common.collect.Collections2.transform;
import static com.google.common.collect.Lists.newArrayList;
import static java.util.Collections.unmodifiableSet;
import static org.netmelody.cieye.core.domain.Percentage.percentageOf;
import static org.netmelody.cieye.core.domain.RunningBuild.buildAt;

            return sponsorCache.get(buildUrl);
        }
        
        final BuildDetail buildData = this.buildDetailFetcher.detailsOf(buildUrl);
        if (null == buildData) {
            return new HashSet<Sponsor>();
        }
        
        final Set<Sponsor> sponsors = new HashSet<Sponsor>(detective.search(commitMessagesOf(buildData)));
        
        if (sponsors.isEmpty()) {
            for (String upstreamBuildUrl : buildData.upstreamBuildUrls()) {
                sponsors.addAll(sponsorsOf(communicator.endpoint() + "/" + upstreamBuildUrl));
            }
        }
        
        final Set<Sponsor> result = unmodifiableSet(sponsors);
        if (!buildData.building) {
            sponsorCache.put(buildUrl, result);
        }
        
        return result;
    }
    
    private String commitMessagesOf(BuildDetail build) {
        if (null == build.changeSet || null == build.changeSet.items) {
            return "";
        }
        
        final StringBuilder result = new StringBuilder();
        for (ChangeSetItem changeSetItem : build.changeSet.items) {