// 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;
            builds.add(job.lastBuild);
        }
        
        final long duration = this.buildDurationFetcher.lastGoodDurationOf(job);
        return newArrayList(transform(filter(transform(builds, toBuildDetail()), building()), toRunningBuild(duration)));
    }
    
    private Predicate<Build> after(final long lastCompletedJobNumber) {
        return new Predicate<Build>() {
            @Override public boolean apply(Build build) { return build.number > lastCompletedJobNumber; }
        };
    }
    
    private Function<Build, BuildDetail> toBuildDetail() {
        return new Function<Build, BuildDetail>() {
            @Override public BuildDetail apply(Build build) {
                return buildDetailFetcher.detailsOf(build.url);
            }
        };
    }

    private Predicate<BuildDetail> building() {
        return new Predicate<BuildDetail>() {
            @Override public boolean apply(BuildDetail build) { return build.building; }
        };
    }
    
    private Function<BuildDetail, RunningBuild> toRunningBuild(final long duration) {
        return new Function<BuildDetail, RunningBuild>() {
            @Override public RunningBuild apply(BuildDetail buildDetail) {
// 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;

            builds.add(job.lastBuild);
        }
        
        final long duration = this.buildDurationFetcher.lastGoodDurationOf(job);
        return newArrayList(transform(filter(transform(builds, toBuildDetail()), building()), toRunningBuild(duration)));
    }
    
    private Predicate<Build> after(final long lastCompletedJobNumber) {
        return new Predicate<Build>() {
            @Override public boolean apply(Build build) { return build.number > lastCompletedJobNumber; }
        };
    }
    
    private Function<Build, BuildDetail> toBuildDetail() {
        return new Function<Build, BuildDetail>() {
            @Override public BuildDetail apply(Build build) {
                return buildDetailFetcher.detailsOf(build.url);
            }
        };
    }

    private Predicate<BuildDetail> building() {
        return new Predicate<BuildDetail>() {
            @Override public boolean apply(BuildDetail build) { return build.building; }
        };
    }
    
    private Function<BuildDetail, RunningBuild> toRunningBuild(final long duration) {
        return new Function<BuildDetail, RunningBuild>() {
            @Override public RunningBuild apply(BuildDetail buildDetail) {
                return buildAt(percentageOf(new Date().getTime() - buildDetail.timestamp, duration));