import java.util.*;
import java.util.zip.*;
import java.util.List;
import java.util.regex.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.concurrent.locks.*;
import java.util.function.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.table.*;
import java.io.*;
import java.net.*;
import java.lang.reflect.*;
import java.lang.ref.*;
import java.lang.management.*;
import java.security.*;
import java.security.spec.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.geom.*;
import javax.imageio.*;
import java.math.*;
import java.time.Duration;
import java.lang.invoke.VarHandle;
import java.lang.invoke.MethodHandles;
// Abstract base class for finding all connected regions of same color
// in an image using flood filling
import java.text.NumberFormat;
import java.awt.geom.*;
import static x30_pkg.x30_util.DynamicObject;
import java.text.*;
import java.util.TimeZone;
class main {
abstract static class AbstractFastRegions implements Runnable, IImageRegions , IFieldsToList{
Img image;
AbstractFastRegions() {}
AbstractFastRegions(Img image) {
this.image = image;}public Object[] _fieldsToList() { return new Object[] {image}; }
int w, h; // Image size
int runner; // Position in image currently being scanned
final public int getSize(){ return size(); }
public int size() { return size; }
int size; // =w*h
IntBuffer stack = new IntBuffer(); // locations as y*w+x
final public int[] getRegionMatrix(){ return regionMatrix(); }
public int[] regionMatrix() { return regionMatrix; }
int[] regionMatrix; // for each pixel: region index (starting at 1)
IntBuffer regionPixels = new IntBuffer(); // collect all pixels for regions
final public AbstractFastRegions setWithDiagonals(boolean withDiagonals){ return withDiagonals(withDiagonals); }
public AbstractFastRegions withDiagonals(boolean withDiagonals) { this.withDiagonals = withDiagonals; return this; } final public boolean getWithDiagonals(){ return withDiagonals(); }
public boolean withDiagonals() { return withDiagonals; }
boolean withDiagonals = false; // also walk diagonally?
// initialize these to use them
IntBuffer regionFirstPixel = new IntBuffer(); // for each region: index of first pixel found in regionPixels
IntBuffer regionSize = new IntBuffer(); // for each region: number of pixels
IntBuffer regionBounds = new IntBuffer(); // for each region: bounds (x1, y1, x2, y2)
// index = dual log of region size, value = region index
List regionsBySize = new ArrayList();
int regionCounter;
boolean verbose = false;
// temporary
int currentColor;
double regionStep = .1; // for rendering in regionsImage
int x(int pos) { return pos % w; }
int y(int pos) { return pos / w; }
int pos(int x, int y) { return y*w+x; }
Pt pt(int pos) { return new Pt(x(pos), y(pos)); }
boolean validPos(int x, int y) { return x >= 0 && y >= 0 && x < w && y < h; }
abstract int getColor(int pos);
boolean initialized() { return regionMatrix != null; }
void init() {
if (initialized()) return;
w = image.getWidth(); h = image.getHeight();
size = w*h;
regionMatrix = new int[size];
// 0 entries are unused
{ if (regionFirstPixel != null) regionFirstPixel.add(0); }
{ if (regionSize != null) regionSize.add(0); }
{ if (regionPixels != null) regionPixels.setSize(size); }
}
// Search for all regions in scanline order
public void run() { try {
if (initialized()) return;
init();
while (runner < size) {
if (regionMatrix[runner] == 0)
makeRegion();
++runner;
}
} catch (Exception __e) { throw rethrow(__e); } }
// returns index of new region
int makeRegion() {
// make a new region, get color
int region = ++regionCounter;
{ if (regionFirstPixel != null) regionFirstPixel.add(regionPixels != null ? l(regionPixels) : runner); }
currentColor = getColor(runner);
stack.add(runner);
int rsize = 0, x1 = w, y1 = h, x2 = 0, y2 = 0;
// flood-fill region
while (nempty(stack)) {
int pos = stack.popLast();
if (regionMatrix[pos] != 0) continue; // check again if set in the meantime (color has been checked before)
// new pixel found!
int x = x(pos), y = y(pos);
// march to the left
int lineStart = pos-x;
int xLeft = x;
while (xLeft > 0 && addable(lineStart+xLeft-1))
--xLeft;
// march to the right
int xRight = x+1;
while (xRight < w && addable(lineStart+xRight))
++xRight;
// Now we know [xLeft; xRight) are our pixels
// mark them in matrix
for (x = xLeft; x < xRight; x++) {
regionMatrix[lineStart+x] = region;
{ if (regionPixels != null) regionPixels.add(lineStart+x); }
}
// increase region size
rsize += xRight-xLeft;
// update bounds
if (xLeft < x1) x1 = xLeft;
if (xRight-1 > x2) x2 = xRight-1;
if (y < y1) y1 = y;
if (y > y2) y2 = y;
// explore above & below
int xLeft2 = withDiagonals ? max(0, xLeft-1) : xLeft;
int xRight2 = withDiagonals ? min(w, xRight+1) : xRight;
if (y > 0)
addStreaks(lineStart-w, xLeft2, xRight2);
if (y < h-1)
addStreaks(lineStart+w, xLeft2, xRight2);
}
{ if (regionSize != null) regionSize.add(rsize); }
{ if (regionBounds != null) regionBounds.addAll(x1, y1, x2+1, y2+1); }
if (regionsBySize != null) {
int iBucket = dualLog(rsize);
var buffer = listGetOrCreate(regionsBySize, iBucket, () -> new IntBuffer());
buffer.add(region);
}
return region;
}
boolean addable(int pos) {
if (regionMatrix[pos] != 0) return false; // touching myself (or someone else)
if (getColor(pos) != currentColor) return false; // wrong color
return true;
}
boolean addToStack(int pos) {
if (!addable(pos)) return false;
stack.add(pos);
return true;
}
void addStreaks(int lineStart, int xLeft, int xRight) {
int x = xLeft;
while (x < xRight) {
if (addToStack(lineStart+x))
while (x+1 < xRight && addable(lineStart+x+1))
++x;
++x;
}
}
IBWImage regionsImage() {
return iBWImageFromFunction((x, y) -> {
var region = regionMatrix[pos(x, y)];
return ((region-1)*regionStep) % (1.0+regionStep-0.0001);
}, w, h);
}
final public int nRegions(){ return regionCount(); }
public int regionCount() { return regionCounter; }
abstract class RegionIterator {
int pos;
abstract boolean next();
int pos() { return pos; }
int x() { return AbstractFastRegions.this.x(pos); }
int y() { return AbstractFastRegions.this.y(pos); }
int[] pixelsAsIntArray() { throw todo(); }
}
// returns points in no particular order
class FloodRegionIterator extends RegionIterator {
int region;
IntBuffer stack = new IntBuffer(); // locations as y*w+x
BitSet seen = new BitSet(size);
FloodRegionIterator(int region) {
this.region = region;
int pos = regionFirstPixel.get(region);
printVars("region", region, "pos", pos);
seen.set(pos);
stack.add(pos);
}
// flood-fill region
boolean next() {
if (empty(stack)) return false;
pos = stack.popLast();
// explore neighborhood
int x = x(), y = y();
if (x > 0) tryPosition(pos-1);
if (x < w-1) tryPosition(pos+1);
if (y > 0) tryPosition(pos-w);
if (y < h-1) tryPosition(pos+w);
return true;
}
private void tryPosition(int p) {
if (!seen.get(p) && regionMatrix[p] == region) {
seen.set(p);
stack.add(p);
}
}
}
class CachedRegionIterator extends RegionIterator {
int i, to;
CachedRegionIterator(int region) {
i = regionFirstPixel.get(region);
to = region+1 < l(regionFirstPixel) ? regionFirstPixel.get(region+1) : l(regionPixels);
}
boolean next() {
if (i >= to) return false;
pos = regionPixels.get(i++);
return true;
}
int[] pixelsAsIntArray() {
return regionPixels.subArray(i, to);
}
}
int regionSize(int iRegion) { return regionSize.get(iRegion); }
final Pt firstPixel(int iRegion){ return samplePixel(iRegion); }
Pt samplePixel(int iRegion) {
return pt(firstPixelPos(iRegion));
}
int firstPixelPos(int iRegion) {
int i = regionFirstPixel.get(iRegion);
return regionPixels != null ? regionPixels.get(i) : i;
}
boolean inRegion(int iRegion, int x, int y) {
return validPos(x, y) && regionMatrix[pos(x, y)] == iRegion;
}
Rect regionBounds(int iRegion) { return rectFromPoints(
regionBounds.get((iRegion-1)*4),
regionBounds.get((iRegion-1)*4+1),
regionBounds.get((iRegion-1)*4+2),
regionBounds.get((iRegion-1)*4+3)); }
int regionAt(Pt p) { return regionAt(p.x, p.y); }
int regionAt(int x, int y) {
return !validPos(x, y) ? 0 : regionMatrix[pos(x, y)];
}
int regionAt(int pos) {
return regionMatrix[pos];
}
RegionIterator regionIterator(int iRegion) {
return regionPixels != null
? new CachedRegionIterator(iRegion)
: new FloodRegionIterator(iRegion);
}
List regionPixels(int iRegion) {
var it = regionIterator(iRegion);
List l = new ArrayList();
while (it.next())
l.add(new Pt(it.x(), it.y()));
return l;
}
// select extra features before regions are made
// (not necessary anymore)
void collectFirstPixels() { /*regionFirstPixel = new IntBuffer;*/ }
void collectBounds() { /*regionBounds = new IntBuffer;*/ }
Matrix regionBitMatrix(int iRegion) {
return new AbstractMatrix(w, h) {
public Boolean get(int x, int y) {
return inRegion(iRegion, x, y);
}
};
}
void markRegionInPixelArray(int[] pixels, int iRegion, int rgba) {
if (iRegion <= 0) return;
for (int i = 0; i < l(pixels); i++)
if (regionAt(i) == iRegion)
pixels[i] = rgba;
}
List regionIndices() { return virtualCountList(1, nRegions()+1); }
IterableIterator regionsRoughlyByDecreasingSize() {
return nestedIterator(countIterator_inclusive_backwards(regionsBySize.size()-1, 0),
iBucket -> iterator(regionsBySize.get(iBucket)));
}
final public IImageRegion get(int iRegion){ return getRegion(iRegion); }
public IImageRegion getRegion(int iRegion) {
return new ImageRegion(iRegion);
}
final public List> get(){ return regions(); }
public List> regions() {
run();
return listFromFunction(i -> getRegion(i+1), nRegions());
}
class ImageRegion implements IImageRegion , IFieldsToList{
int iRegion;
ImageRegion() {}
ImageRegion(int iRegion) {
this.iRegion = iRegion;}public Object[] _fieldsToList() { return new Object[] {iRegion}; }
public int hashCode() { return iRegion; }
public boolean equals(Object o) {
if (!(o instanceof AbstractFastRegions.ImageRegion)) return false;
return ((AbstractFastRegions.ImageRegion) o).creator() == creator()
&& ((AbstractFastRegions.ImageRegion) o).iRegion == iRegion;
}
public Img image() { return image; }
public Object creator() { return AbstractFastRegions.this; }
public int indexInCreator() { return iRegion; }
public Boolean createdWithDiagonals() { return withDiagonals; }
public Rect bounds() { return regionBounds(iRegion); }
public int numberOfPixels() { return regionSize(iRegion); }
public Pt firstPixel() { return pt(firstPixelPos()); }
public int firstPixelPos() { return AbstractFastRegions.this.firstPixelPos(iRegion); }
public IterableIterator pixelIterator() {
var it = regionIterator(iRegion);
return iteratorFromFunction(() -> it.next() ? pt(it.pos()) : null);
}
public int[] pixelsAsIntArray() {
return regionIterator(iRegion).pixelsAsIntArray();
}
public boolean contains(int x, int y) { return inRegion(iRegion, x, y); }
public Color color() {
return toColor(rgbForRegion(this));
}
final public int firstPixelLogicalColor(){ return brightness(); }
public int brightness() {
return getColor(firstPixelPos());
}
public String toString() {
return renderRecordVars("Region", "brightness", brightness(), "color", color(), "pixels" , numberOfPixels(), "bounds", bounds());
}
}
abstract RGB rgbForRegion(ImageRegion r);
public Img image() { return image; }
// called after scan was performed externally
void markDone() { runner = size; }
}
static RuntimeException rethrow(Throwable t) {
if (t instanceof Error)
_handleError((Error) t);
throw t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t);
}
static RuntimeException rethrow(String msg, Throwable t) {
throw new RuntimeException(msg, t);
}
static int l(Object[] a) { return a == null ? 0 : a.length; }
static int l(boolean[] a) { return a == null ? 0 : a.length; }
static int l(byte[] a) { return a == null ? 0 : a.length; }
static int l(short[] a) { return a == null ? 0 : a.length; }
static int l(long[] a) { return a == null ? 0 : a.length; }
static int l(int[] a) { return a == null ? 0 : a.length; }
static int l(float[] a) { return a == null ? 0 : a.length; }
static int l(double[] a) { return a == null ? 0 : a.length; }
static int l(char[] a) { return a == null ? 0 : a.length; }
static int l(Collection c) { return c == null ? 0 : c.size(); }
static int l(Iterator i) { return iteratorCount_int_close(i); } // consumes the iterator && closes it if possible
static int l(Map m) { return m == null ? 0 : m.size(); }
static int l(CharSequence s) { return s == null ? 0 : s.length(); }
static long l(File f) { return f == null ? 0 : f.length(); }
static int l(IMultiMap mm) { return mm == null ? 0 : mm.size(); }
static int l(IntBuffer b) { return b == null ? 0 : b.size(); }
static int l(LongBuffer b) { return b == null ? 0 : b.size(); }
static int l(IntSize o) { return o == null ? 0 : o.size(); }
static Color getColor(BufferedImage img, int x, int y) {
return colorFromRGBA(img.getRGB(x, y));
}
static Color getColor(BufferedImage img, Pt p) {
return colorFromRGBA(img.getRGB(p.x, p.y));
}
static boolean nempty(Collection c) {
return !empty(c);
}
static boolean nempty(CharSequence s) {
return !empty(s);
}
static boolean nempty(Object[] o) { return !empty(o); }
static boolean nempty(byte[] o) { return !empty(o); }
static boolean nempty(int[] o) { return !empty(o); }
static boolean nempty(BitSet bs) { return !empty(bs); }
static boolean nempty(Map m) {
return !empty(m);
}
static boolean nempty(Iterator i) {
return i != null && i.hasNext();
}
static boolean nempty(IMultiMap mm) { return mm != null && mm.size() != 0; }
static boolean nempty(Object o) { return !empty(o); }
static boolean nempty(IntBuffer b) { return b != null && !b.isEmpty(); }
static boolean nempty(LongBuffer b) { return b != null && !b.isEmpty(); }
static boolean nempty(Rect r) { return r != null && r.w != 0 && r.h != 0; }
static boolean nempty(IntSize l) { return l != null && l.size() != 0; }
static int max(int a, int b) { return Math.max(a, b); }
static int max(int a, int b, int c) { return max(max(a, b), c); }
static long max(int a, long b) { return Math.max((long) a, b); }
static long max(long a, long b) { return Math.max(a, b); }
static double max(int a, double b) { return Math.max((double) a, b); }
static float max(float a, float b) { return Math.max(a, b); }
static double max(double a, double b) { return Math.max(a, b); }
static > A max (Iterable l) {
A max = null;
var it = iterator(l);
if (it.hasNext()) {
max = it.next();
while (it.hasNext()) {
A a = it.next();
if (cmp(a, max) > 0)
max = a;
}
}
return max;
}
/*Nah.
static int max(Collection c) {
int x = Integer.MIN_VALUE;
for (int i : c) x = max(x, i);
ret x;
}*/
static double max(double[] c) {
if (c.length == 0) return Double.MIN_VALUE;
double x = c[0];
for (int i = 1; i < c.length; i++) x = Math.max(x, c[i]);
return x;
}
static float max(float[] c) {
if (c.length == 0) return Float.MAX_VALUE;
float x = c[0];
for (int i = 1; i < c.length; i++) x = Math.max(x, c[i]);
return x;
}
static byte max(byte[] c) {
byte x = -128;
for (byte d : c) if (d > x) x = d;
return x;
}
static short max(short[] c) {
short x = -0x8000;
for (short d : c) if (d > x) x = d;
return x;
}
static int max(int[] c) {
int x = Integer.MIN_VALUE;
for (int d : c) if (d > x) x = d;
return x;
}
static > A max(A a, A b) {
return cmp(a, b) >= 0 ? a : b;
}
static int min(int a, int b) {
return Math.min(a, b);
}
static long min(long a, long b) {
return Math.min(a, b);
}
static float min(float a, float b) { return Math.min(a, b); }
static float min(float a, float b, float c) { return min(min(a, b), c); }
static double min(double a, double b) {
return Math.min(a, b);
}
static double min(double[] c) {
double x = Double.MAX_VALUE;
for (double d : c) x = Math.min(x, d);
return x;
}
static float min(float[] c) {
float x = Float.MAX_VALUE;
for (float d : c) x = Math.min(x, d);
return x;
}
static byte min(byte[] c) {
byte x = 127;
for (byte d : c) if (d < x) x = d;
return x;
}
static short min(short[] c) {
short x = 0x7FFF;
for (short d : c) if (d < x) x = d;
return x;
}
static int min(int[] c) {
int x = Integer.MAX_VALUE;
for (int d : c) if (d < x) x = d;
return x;
}
static > A min(A a, A b) {
return cmp(a, b) <= 0 ? a : b;
}
static int dualLog(int i) {
return 32-Integer.numberOfLeadingZeros(max(0, i-1));
}
static A listGetOrCreate(List l, int i, Class extends A> c) {
return listGetOrCreate(l, i, () -> nuInstance(c));
}
static A listGetOrCreate(List l, int i, IF0 f) {
if (l == null) return null;
A a = get(l, i);
if (a == null)
listSet(l, i, a = f.get());
return a;
}
static A listGetOrCreate(Class extends A> c, List l, int i) {
return listGetOrCreate(l, i, c);
}
static IBWImage iBWImageFromFunction(IF2_IntInt_Double f, int w, int h) {
return new IBWImage() {
public int getWidth() { return w; }
public int getHeight() { return h; }
public float getFloatPixel(int x, int y) {
return (float) f.get(x, y);
}
};
}
static RuntimeException todo() {
throw new RuntimeException("TODO");
}
static RuntimeException todo(Object msg) {
throw new RuntimeException("TODO: " + msg);
}
// Use like this: printVars(+x, +y);
// Or: printVars("bla", +x);
// Or: printVars bla(, +x);
static void printVars(Object... params) {
printVars_str(params);
}
static boolean empty(Collection c) { return c == null || c.isEmpty(); }
static boolean empty(Iterable c) { return c == null || !c.iterator().hasNext(); }
static boolean empty(CharSequence s) { return s == null || s.length() == 0; }
static boolean empty(Map map) { return map == null || map.isEmpty(); }
static boolean empty(Object[] o) { return o == null || o.length == 0; }
static boolean empty(BitSet bs) { return bs == null || bs.isEmpty(); }
static boolean empty(Object o) {
if (o instanceof Collection) return empty((Collection) o);
if (o instanceof String) return empty((String) o);
if (o instanceof Map) return empty((Map) o);
if (o instanceof Object[]) return empty((Object[]) o);
if (o instanceof byte[]) return empty((byte[]) o);
if (o == null) return true;
throw fail("unknown type for 'empty': " + getType(o));
}
static boolean empty(Iterator i) { return i == null || !i.hasNext(); }
static boolean empty(double[] a) { return a == null || a.length == 0; }
static boolean empty(float[] a) { return a == null || a.length == 0; }
static boolean empty(int[] a) { return a == null || a.length == 0; }
static boolean empty(long[] a) { return a == null || a.length == 0; }
static boolean empty(byte[] a) { return a == null || a.length == 0; }
static boolean empty(short[] a) { return a == null || a.length == 0; }
static boolean empty(IMultiMap mm) { return mm == null || mm.size() == 0; }
static boolean empty(File f) { return getFileSize(f) == 0; }
static boolean empty(IntBuffer b) { return b == null || b.isEmpty(); }
static boolean empty(LongBuffer b) { return b == null || b.isEmpty(); }
static boolean empty(Rect r) { return !(r != null && r.w != 0 && r.h != 0); }
static boolean empty(Chain c) { return c == null; }
static boolean empty(AppendableChain c) { return c == null; }
static boolean empty(IntSize l) { return l == null || l.size() == 0; }
static Pt pt(int x, int y) {
return new Pt(x, y);
}
static Pt pt(int x) {
return new Pt(x, x);
}
static Rect rectFromPoints(int x1, int y1, int x2, int y2) {
return pointsRect(x1, y1, x2, y2);
}
static Rect rectFromPoints(Pt a, Pt b) {
return pointsRect(a.x, a.y, b.x, b.y);
}
// get purpose 1: access a list/array/map (safer version of x.get(y))
static A get(List l, int idx) {
return l != null && idx >= 0 && idx < l(l) ? l.get(idx) : null;
}
// seems to conflict with other signatures
/*static B get(Map map, A key) {
ret map != null ? map.get(key) : null;
}*/
static A get(A[] l, int idx) {
return idx >= 0 && idx < l(l) ? l[idx] : null;
}
// default to false
static boolean get(boolean[] l, int idx) {
return idx >= 0 && idx < l(l) ? l[idx] : false;
}
// get purpose 2: access a field by reflection or a map
static Object get(Object o, String field) {
try {
if (o == null) return null;
if (o instanceof Class) return get((Class) o, field);
if (o instanceof Map)
return ((Map) o).get(field);
Field f = getOpt_findField(o.getClass(), field);
if (f != null) {
makeAccessible(f);
return f.get(o);
}
if (o instanceof DynamicObject)
return getOptDynOnly(((DynamicObject) o), field);
} catch (Exception e) {
throw asRuntimeException(e);
}
throw new RuntimeException("Field '" + field + "' not found in " + o.getClass().getName());
}
static Object get_raw(String field, Object o) {
return get_raw(o, field);
}
static Object get_raw(Object o, String field) { try {
if (o == null) return null;
Field f = get_findField(o.getClass(), field);
makeAccessible(f);
return f.get(o);
} catch (Exception __e) { throw rethrow(__e); } }
static Object get(Class c, String field) {
try {
Field f = get_findStaticField(c, field);
makeAccessible(f);
return f.get(null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
static Field get_findStaticField(Class> c, String field) {
Class _c = c;
do {
for (Field f : _c.getDeclaredFields())
if (f.getName().equals(field) && (f.getModifiers() & java.lang.reflect.Modifier.STATIC) != 0)
return f;
_c = _c.getSuperclass();
} while (_c != null);
throw new RuntimeException("Static field '" + field + "' not found in " + c.getName());
}
static Field get_findField(Class> c, String field) {
Class _c = c;
do {
for (Field f : _c.getDeclaredFields())
if (f.getName().equals(field))
return f;
_c = _c.getSuperclass();
} while (_c != null);
throw new RuntimeException("Field '" + field + "' not found in " + c.getName());
}
static Object get(String field, Object o) {
return get(o, field);
}
static boolean get(BitSet bs, int idx) {
return bs != null && bs.get(idx);
}
static List virtualCountList(int n) {
return new RandomAccessAbstractList() {
public int size() { return n; }
public Integer get(int i) { return i; }
};
}
// to is exclusive
static List virtualCountList(int from, int to) {
int n = max(to-from, 0);
return new RandomAccessAbstractList() {
public int size() { return n; }
public Integer get(int i) { return from+i; }
};
}
static String nRegions(long n) { return n2(n, "region"); }
static String nRegions(Collection l) { return nRegions(l(l)); }
static String nRegions(Map map) { return nRegions(l(map)); }
// TODO: clean up these type signatures?
static > IterableIterator nestedIterator(Iterable c, final F1 makeInnerIterator) {
return nestedIterator(iterator(c), makeInnerIterator);
}
static > IterableIterator nestedIterator(Iterable c, IF1 makeInnerIterator) {
return nestedIterator(iterator(c), makeInnerIterator);
}
static > IterableIterator nestedIterator(IterableIterator c, IF1 makeInnerIterator) {
return nestedIterator((Iterator) c, makeInnerIterator);
}
static > IterableIterator nestedIterator(Iterator it1, IF1 makeInnerIterator) {
if (it1 == null || !it1.hasNext()) return emptyItIt();
return iff(new F0() {
A a;
Iterator innerIterator;
{ nextOuter(); }
void nextOuter() {
a = it1.next();
innerIterator = makeInnerIterator.get(a);
}
public Object get() {
while (true) { ping();
if (innerIterator != null && innerIterator.hasNext())
return innerIterator.next();
if (!it1.hasNext()) return endMarker();
nextOuter();
}
}
});
}
static > IterableIterator nestedIterator(final Iterator it1, F1 makeInnerIterator) {
if (it1 == null || !it1.hasNext()) return emptyItIt();
return iff(new F0() {
A a;
Iterator innerIterator;
{ nextOuter(); }
void nextOuter() {
a = it1.next();
innerIterator = makeInnerIterator.get(a);
}
public Object get() {
while (true) { ping();
if (innerIterator != null && innerIterator.hasNext())
return innerIterator.next();
if (!it1.hasNext()) return endMarker();
nextOuter();
}
}
});
}
static > IterableIterator nestedIterator(IF1 makeInnerIterator, Iterator it1) {
return nestedIterator(it1, makeInnerIterator);
}
static > IterableIterator nestedIterator(IF1 makeInnerIterator, Collection l) {
return nestedIterator(l, makeInnerIterator);
}
static IterableIterator countIterator_inclusive_backwards(int a, int b) {
return new IterableIterator() {
int i = a;
public boolean hasNext() { return i >= b; }
public Integer next() { return i--; }
};
}
static IterableIterator countIterator_inclusive_backwards(int a, int b, IF1 f) {
return mapI_if1(f, countIterator_inclusive_backwards(a, b));
}
static Iterator iterator(Iterable c) {
return c == null ? emptyIterator() : c.iterator();
}
static Class run(String progID, String... args) {
Class main = hotwire(progID);
callMain(main, args);
return main;
}
static class ListFromFunction extends RandomAccessAbstractList implements IFieldsToList{
int n;
IF1 f;
ListFromFunction() {}
ListFromFunction(int n, IF1 f) {
this.f = f;
this.n = n;}
public String toString() { return shortClassName_dropNumberPrefix(this) + "(" + n + ", " + f + ")"; }public Object[] _fieldsToList() { return new Object[] {n, f}; }
public int size() { return n; }
public A get(int i) { return f.get(i); }
}
static List listFromFunction(int n, IF1 f) {
return new ListFromFunction(n, f);
}
static List listFromFunction(IF1 f, int n) {
return new ListFromFunction(n, f);
}
static WeakReference