| 
          package com.samsara; | 
        
        
           | 
          
 | 
        
        
           | 
          import java.util.ArrayList; | 
        
        
           | 
          import java.util.Arrays; | 
        
        
           | 
          import java.util.List; | 
        
        
           | 
          import org.junit.Assert; | 
        
        
           | 
          import org.junit.Test; | 
        
        
           | 
          
 | 
        
        
           | 
          public class FindAlertRanges { | 
        
        
           | 
          
 | 
        
        
           | 
            static class Interval { | 
        
        
           | 
          
 | 
        
        
           | 
              public final int timestamp; | 
        
        
           | 
              public final int value; | 
        
        
           | 
          
 | 
        
        
           | 
              public Interval(int timestamp, int value) { | 
        
        
           | 
                this.timestamp = timestamp; | 
        
        
           | 
                this.value = value; | 
        
        
           | 
              } | 
        
        
           | 
          
 | 
        
        
           | 
              @Override | 
        
        
           | 
              public String toString() { | 
        
        
           | 
                return String.format("(timestamp=%d, value=%d)", this.timestamp, this.value); | 
        
        
           | 
              } | 
        
        
           | 
            } | 
        
        
           | 
          
 | 
        
        
           | 
            static class Pair { | 
        
        
           | 
              private final int left; | 
        
        
           | 
              private final int right; | 
        
        
           | 
          
 | 
        
        
           | 
              public Pair(int left, int right) { | 
        
        
           | 
                this.left = left; | 
        
        
           | 
                this.right = right; | 
        
        
           | 
              } | 
        
        
           | 
          
 | 
        
        
           | 
              @Override | 
        
        
           | 
              public boolean equals(Object obj) { | 
        
        
           | 
                if (!(obj instanceof Pair)) { | 
        
        
           | 
                  return false; | 
        
        
           | 
                } | 
        
        
           | 
                Pair other = (Pair) obj; | 
        
        
           | 
                return this.left == other.left && this.right == other.right; | 
        
        
           | 
              } | 
        
        
           | 
          
 | 
        
        
           | 
              @Override | 
        
        
           | 
              public String toString() { | 
        
        
           | 
                return String.format("(%d, %d)", this.left, this.right); | 
        
        
           | 
              } | 
        
        
           | 
            } | 
        
        
           | 
          
 | 
        
        
           | 
            private static final int INFINITY = Integer.MIN_VALUE; | 
        
        
           | 
          
 | 
        
        
           | 
            public static List<Pair> findAlertRanges(List<Interval> list, int threshold) { | 
        
        
           | 
              List<Interval> intervals = new ArrayList<>() {{ | 
        
        
           | 
                addAll(list); | 
        
        
           | 
                // TRICK: add sentinel | 
        
        
           | 
                add(new Interval(INFINITY, INFINITY)); | 
        
        
           | 
              }}; | 
        
        
           | 
          
 | 
        
        
           | 
              List<Pair> ranges = new ArrayList<>(); | 
        
        
           | 
              for (int i = 0, j = i + 1; j < intervals.size(); i++, j++) { | 
        
        
           | 
                Interval a = intervals.get(i); | 
        
        
           | 
                Interval b = intervals.get(j); | 
        
        
           | 
          
 | 
        
        
           | 
                if (a.value < threshold) { | 
        
        
           | 
                  continue; | 
        
        
           | 
                } | 
        
        
           | 
          
 | 
        
        
           | 
                Pair current = null; | 
        
        
           | 
                if (a.value >= threshold) { | 
        
        
           | 
                  current = new Pair(a.timestamp, INFINITY); | 
        
        
           | 
                  i--; | 
        
        
           | 
                } | 
        
        
           | 
          
 | 
        
        
           | 
                if (current != null && b.value < threshold) { | 
        
        
           | 
                  ranges.add(new Pair(current.left, b.timestamp)); | 
        
        
           | 
                  i = j; | 
        
        
           | 
                  j = i + 1; | 
        
        
           | 
                } | 
        
        
           | 
              } | 
        
        
           | 
          
 | 
        
        
           | 
              if (ranges.isEmpty()) { | 
        
        
           | 
                return Arrays.asList(new Pair(INFINITY, INFINITY)); | 
        
        
           | 
              } | 
        
        
           | 
              return ranges; | 
        
        
           | 
            } | 
        
        
           | 
          
 | 
        
        
           | 
            @Test | 
        
        
           | 
            public void testUpperboundA() { | 
        
        
           | 
              Pair[] expected = new Pair[]{new Pair(1, INFINITY)}; | 
        
        
           | 
              Pair[] actual = testRange(Arrays.asList( | 
        
        
           | 
                  new Interval(1, 40), | 
        
        
           | 
                  new Interval(2, 40) | 
        
        
           | 
              ), 40); | 
        
        
           | 
              Assert.assertArrayEquals(expected, actual); | 
        
        
           | 
            } | 
        
        
           | 
          
 | 
        
        
           | 
            @Test | 
        
        
           | 
            public void testUpperboundB() { | 
        
        
           | 
              Pair[] expected = new Pair[]{new Pair(1, INFINITY)}; | 
        
        
           | 
              Pair[] actual = testRange(Arrays.asList( | 
        
        
           | 
                  new Interval(0, 0), | 
        
        
           | 
                  new Interval(1, 40) | 
        
        
           | 
              ), 40); | 
        
        
           | 
              Assert.assertArrayEquals(expected, actual); | 
        
        
           | 
            } | 
        
        
           | 
          
 | 
        
        
           | 
            @Test | 
        
        
           | 
            public void testEmpty() { | 
        
        
           | 
              Pair[] expected = new Pair[]{new Pair(INFINITY, INFINITY)}; | 
        
        
           | 
              Pair[] actual = testRange(Arrays.asList( | 
        
        
           | 
                  new Interval(1, 39), | 
        
        
           | 
                  new Interval(2, 20) | 
        
        
           | 
              ), 40); | 
        
        
           | 
              Assert.assertArrayEquals(expected, actual); | 
        
        
           | 
            } | 
        
        
           | 
          
 | 
        
        
           | 
            @Test | 
        
        
           | 
            public void testMultipleBounded() { | 
        
        
           | 
              Pair[] expected = new Pair[]{ | 
        
        
           | 
                  new Pair(1, 2), | 
        
        
           | 
                  new Pair(3, 4) | 
        
        
           | 
              }; | 
        
        
           | 
              Pair[] actual = testRange(Arrays.asList( | 
        
        
           | 
                  new Interval(1, 40), | 
        
        
           | 
                  new Interval(2, 0), | 
        
        
           | 
                  new Interval(3, 40), | 
        
        
           | 
                  new Interval(4, 0) | 
        
        
           | 
              ), 40); | 
        
        
           | 
              Assert.assertArrayEquals(expected, actual); | 
        
        
           | 
            } | 
        
        
           | 
          
 | 
        
        
           | 
            @Test | 
        
        
           | 
            public void testSinglePair() { | 
        
        
           | 
              Pair[] expected = new Pair[]{new Pair(1, 3)}; | 
        
        
           | 
              Pair[] actual = testRange(Arrays.asList( | 
        
        
           | 
                  new Interval(1, 40), | 
        
        
           | 
                  new Interval(2, 40), | 
        
        
           | 
                  new Interval(3, 0) | 
        
        
           | 
              ), 40); | 
        
        
           | 
              Assert.assertArrayEquals(expected, actual); | 
        
        
           | 
            } | 
        
        
           | 
          
 | 
        
        
           | 
            @Test | 
        
        
           | 
            public void testSingleIntervalA() { | 
        
        
           | 
              Pair[] expected = new Pair[]{new Pair(1, INFINITY)}; | 
        
        
           | 
              Pair[] actual = testRange(Arrays.asList( | 
        
        
           | 
                  new Interval(1, 40) | 
        
        
           | 
              ), 40); | 
        
        
           | 
              Assert.assertArrayEquals(expected, actual); | 
        
        
           | 
            } | 
        
        
           | 
          
 | 
        
        
           | 
            @Test | 
        
        
           | 
            public void testSingleIntervalB() { | 
        
        
           | 
              Pair[] expected = new Pair[]{new Pair(INFINITY, INFINITY)}; | 
        
        
           | 
              Pair[] actual = testRange(Arrays.asList( | 
        
        
           | 
                  new Interval(1, 39) | 
        
        
           | 
              ), 40); | 
        
        
           | 
              Assert.assertArrayEquals(expected, actual); | 
        
        
           | 
            } | 
        
        
           | 
          
 | 
        
        
           | 
            @Test | 
        
        
           | 
            public void testMultipleUnbounded() { | 
        
        
           | 
              Pair[] expected = new Pair[]{ | 
        
        
           | 
                  new Pair(1, 2), | 
        
        
           | 
                  new Pair(4, INFINITY) | 
        
        
           | 
              }; | 
        
        
           | 
              Pair[] actual = testRange(Arrays.asList( | 
        
        
           | 
                  new Interval(1, 40), | 
        
        
           | 
                  new Interval(2, 0), | 
        
        
           | 
                  new Interval(3, 0), | 
        
        
           | 
                  new Interval(4, 40) | 
        
        
           | 
              ), 40); | 
        
        
           | 
              Assert.assertArrayEquals(expected, actual); | 
        
        
           | 
            } | 
        
        
           | 
          
 | 
        
        
           | 
            private static Pair[] testRange(List<Interval> intervals, int threshold) { | 
        
        
           | 
              return findAlertRanges(intervals, threshold).toArray(new Pair[0]); | 
        
        
           | 
            } | 
        
        
           | 
          } |