code: public List<Integer> locationsToReadForDecode(List<Integer> erasedLocations)
        throws TooManyErasedLocations {
      List<Integer> locationsToRead = new ArrayList<Integer>(stripeSize());
      int limit = stripeSize() + paritySize();
      // Loop through all possible locations in the stripe.
      for (int loc = limit - 1; loc >= 0; loc--) {
        // Is the location good.
        if (erasedLocations.indexOf(loc) == -1) {
          locationsToRead.add(loc);
          if (stripeSize() == locationsToRead.size()) {
            break;
          }
        }
      }
      // If we are are not able to fill up the locationsToRead list,
      // we did not find enough good locations. Throw TooManyErasedLocations.
      if (locationsToRead.size() != stripeSize()) {
        String locationsStr = "";
        for (Integer erasedLocation : erasedLocations) {
          locationsStr += " " + erasedLocation;
        }
        throw new TooManyErasedLocations("Locations " + locationsStr);
      }
      return locationsToRead;
    }
docs: Figure out which locations need to be read to decode erased locations. The
  locations are specified as integers in the range [ 0, stripeSize() +
  paritySize() ). Values in the range [ 0, paritySize() ) represent parity
  data. Values in the range [ paritySize(), paritySize() + stripeSize() )
  represent message data.
  
  @param erasedLocations
  The erased locations.
  @return The locations to read.