// Path: src/main/java/uk/me/mjt/ch/Preconditions.java
// public class Preconditions {
//     public static void checkNoneNull(Object... args) {
//         for (int i=0 ; i<args.length ; i++) {
//             if (args[i] == null) {
//                 throw new IllegalArgumentException("Argument index " + i + " was null?");
//             }
//         }
//     }
//     
//     public static void require(boolean... args) {
//         for (int i=0 ; i<args.length ; i++) {
//             if (args[i] == false) {
//                 throw new IllegalArgumentException("Argument index " + i + " was false?");
//             }
//         }
//     }
// 
// }


import java.util.Arrays;
import uk.me.mjt.ch.Preconditions;
            if (toCheck[i] < 0)
                throw new IllegalArgumentException("Invalid array - negative");
            
            int delta = toCheck[i]-lastVal;
            
            if (delta < -SEGMENT_WIDTH_MS) {
                throw new IllegalArgumentException("Invalid array - profile to steep");
            }
        }
    }
    
    @Override
    public int transitTimeAt(int milliseconds) {
        if (milliseconds < SEGMENT_MIDPOINT_MS) {
            return transitDurationMs[0]; 
        } else if (milliseconds > SEGMENT_WIDTH_MS*(ARRAY_LENGTH_SEGMENTS-1)) {
            return transitDurationMs[ARRAY_LENGTH_SEGMENTS-1];
        }
        
        int firstBlock = (milliseconds-SEGMENT_MIDPOINT_MS)/SEGMENT_WIDTH_MS;
        int remainder = (milliseconds-SEGMENT_MIDPOINT_MS)%SEGMENT_WIDTH_MS;
        
        int firstTransitDuration = transitDurationMs[firstBlock];
        int secondTransitDuration = transitDurationMs[firstBlock+1];
        
        long numerator = secondTransitDuration*(long)remainder + firstTransitDuration*(long)(SEGMENT_WIDTH_MS-remainder);
        return (int)(numerator/SEGMENT_WIDTH_MS);
    }
    
    public ArrayTimeProfile followedBy(ArrayTimeProfile after) {
// Path: src/main/java/uk/me/mjt/ch/Preconditions.java
// public class Preconditions {
//     public static void checkNoneNull(Object... args) {
//         for (int i=0 ; i<args.length ; i++) {
//             if (args[i] == null) {
//                 throw new IllegalArgumentException("Argument index " + i + " was null?");
//             }
//         }
//     }
//     
//     public static void require(boolean... args) {
//         for (int i=0 ; i<args.length ; i++) {
//             if (args[i] == false) {
//                 throw new IllegalArgumentException("Argument index " + i + " was false?");
//             }
//         }
//     }
// 
// }


// Path: src/main/java/uk/me/mjt/ch/profile/ArrayTimeProfile.java
import java.util.Arrays;
import uk.me.mjt.ch.Preconditions;

            if (toCheck[i] < 0)
                throw new IllegalArgumentException("Invalid array - negative");
            
            int delta = toCheck[i]-lastVal;
            
            if (delta < -SEGMENT_WIDTH_MS) {
                throw new IllegalArgumentException("Invalid array - profile to steep");
            }
        }
    }
    
    @Override
    public int transitTimeAt(int milliseconds) {
        if (milliseconds < SEGMENT_MIDPOINT_MS) {
            return transitDurationMs[0]; 
        } else if (milliseconds > SEGMENT_WIDTH_MS*(ARRAY_LENGTH_SEGMENTS-1)) {
            return transitDurationMs[ARRAY_LENGTH_SEGMENTS-1];
        }
        
        int firstBlock = (milliseconds-SEGMENT_MIDPOINT_MS)/SEGMENT_WIDTH_MS;
        int remainder = (milliseconds-SEGMENT_MIDPOINT_MS)%SEGMENT_WIDTH_MS;
        
        int firstTransitDuration = transitDurationMs[firstBlock];
        int secondTransitDuration = transitDurationMs[firstBlock+1];
        
        long numerator = secondTransitDuration*(long)remainder + firstTransitDuration*(long)(SEGMENT_WIDTH_MS-remainder);
        return (int)(numerator/SEGMENT_WIDTH_MS);
    }
    
    public ArrayTimeProfile followedBy(ArrayTimeProfile after) {
        Preconditions.checkNoneNull(after);