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 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 javax.imageio.*;
import java.math.*;
import java.awt.geom.*;
import javax.imageio.metadata.*;
import javax.imageio.stream.*;
import java.text.SimpleDateFormat;
import java.nio.charset.Charset;
import java.text.NumberFormat;
import static x30_pkg.x30_util.DynamicObject;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.DataFlavor;
import java.awt.image.DataBufferByte;
import javax.swing.event.AncestorListener;
import javax.swing.event.AncestorEvent;
import javax.swing.Timer;
import java.awt.datatransfer.StringSelection;
import javax.swing.undo.UndoManager;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.text.*;
import java.util.TimeZone;
class main {
static class IIImageSurface extends ImageSurface {
IBWIntegralImage ii;
IIImageSurface() {}
IIImageSurface(IBWIntegralImage ii) {
this.ii = ii;}
IIImageSurface(IBWIntegralImage ii, BufferedImage img) { super(img);
this.ii = ii; }
void drawImageItself(int w, int h, Graphics2D g) {
if (ii == null)
{ super.drawImageItself(w, h, g); return; }
int iw = getZoomedWidth(), ih = getZoomedHeight();
Rect r = toRect(getVisibleRect());
//_print(visibleRect := r);
// TODO: scale only the visible part
//var scaled = scaledGrayImageFromBWIntegralImage(ii, iw, ih);
var scaled = scaledGrayImageFromBWIntegralImage_clip(ii, doubleRatio(iw, ii.getWidth()), r);
g.drawImage(scaled, r.x, r.y, null);
}
public void setImage(BufferedImage img) {
ii = null;
super.setImage(img);
}
void setImage(BWIntegralImage ii) { setImage(ii, null); }
void setImage(BWIntegralImage ii, BufferedImage img) {
this.ii = ii;
super.setImage(img);
}
boolean hasImage() { return ii != null || image != null; }
int w() { return ii != null ? ii.getWidth() : super.w(); }
int h() { return ii != null ? ii.getHeight() : super.h(); }
}
static Rect toRect(Rectangle r) {
return r == null ? null : new Rect(r);
}
static Rect toRect(RectangularShape r) {
return r == null ? null : toRect(r.getBounds());
}
static Rect toRect(DoubleRect r) {
if (r == null) return null;
int x = iround(r.x), y = iround(r.y);
return new Rect(x, y, iround(r.x2())-x, iround(r.y2())-y);
}
static Rect toRect(Rect r) { return r; }
// clip is in output coordinates
static BufferedImage scaledGrayImageFromBWIntegralImage_clip(IBWIntegralImage img, double scalingFactor, Rect clip) {
int w = clip.w, h = clip.h;
int w1 = img.getWidth(), h1 = img.getHeight();
byte[] pixels = new byte[w*h];
int i = 0;
int xx2 = clip.x2(), yy2 = clip.y2();
for (int y = clip.y; y < yy2; y++)
for (int x = clip.x; x < xx2; x++) {
// TODO: optimize
double x1 = x/scalingFactor, x2 = (x+1)/scalingFactor;
double y1 = y/scalingFactor, y2 = (y+1)/scalingFactor;
int pixel = iround(img.getPixelAverage(x1, y1, x2, y2));
pixels[i++] = clampToUByte(pixel);
}
return newGrayBufferedImage(w, h, pixels);
}
// clip is in output coordinates
static BufferedImage scaledGrayImageFromBWIntegralImage_clip(BWIntegralImage img, double scalingFactor, Rect clip) {
int w = clip.w, h = clip.h;
int w1 = img.getWidth(), h1 = img.getHeight();
byte[] pixels = new byte[w*h];
int i = 0;
int xx2 = clip.x2(), yy2 = clip.y2();
for (int y = clip.y; y < yy2; y++)
for (int x = clip.x; x < xx2; x++) {
// TODO: optimize
double x1 = x/scalingFactor, x2 = (x+1)/scalingFactor;
double y1 = y/scalingFactor, y2 = (y+1)/scalingFactor;
int pixel = iround(img.getPixelAverage(x1, y1, x2, y2));
pixels[i++] = clampToUByte(pixel);
}
return newGrayBufferedImage(w, h, pixels);
}
static double doubleRatio(double x, double y) {
return y == 0 ? 0 : x/y;
}
static double doubleRatio(Seconds x, Seconds y) {
return doubleRatio(x.get(), y.get());
}
static JLabel setImage(final BufferedImage img, final JLabel lbl) {
if (lbl != null) { swing(new Runnable() { public void run() { try { lbl.setIcon(imageIcon(img));
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "lbl.setIcon(imageIcon(img));"; }}); }
return lbl;
}
static JLabel setImage(JLabel lbl, BufferedImage img) {
return setImage(img, lbl);
}
static JLabel setImage(final String imageID, final JLabel lbl) {
if (lbl != null) { swing(new Runnable() { public void run() { try { lbl.setIcon(imageIcon(imageID));
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "lbl.setIcon(imageIcon(imageID));"; }}); }
return lbl;
}
static JLabel setImage(JLabel lbl, String imageID) {
return setImage(imageID, lbl);
}
static int iround(double d) {
return (int) Math.round(d);
}
static int iround(Number n) {
return iround(toDouble(n));
}
static byte clampToUByte(long l) {
return (byte) clamp(l, 0, 255);
}
// undefined color, seems to be all black in practice
static BufferedImage newGrayBufferedImage(int w, int h) {
return new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
}
static BufferedImage newGrayBufferedImage(int w, int h, byte[] pixels) {
return byteArrayToGrayBufferedImage(pixels, w, h);
}
static Object swing(Object f) {
return swingAndWait(f);
}
static A swing(F0 f) {
return (A) swingAndWait(f);
}
static A swing(IF0 f) {
return (A) swingAndWait(f);
}
static int imageIcon_cacheSize = 10;
static boolean imageIcon_verbose = false;
static Map imageIcon_cache;
static Lock imageIcon_lock = lock();
static ThreadLocal imageIcon_fixGIF = new ThreadLocal();
// not going through BufferedImage preserves animations
static ImageIcon imageIcon(String imageID) { try {
if (imageID == null) return null;
Lock __0 = imageIcon_lock; lock(__0); try {
if (imageIcon_cache == null)
imageIcon_cache = new MRUCache(imageIcon_cacheSize);
imageID = fsI(imageID);
ImageIcon ii = imageIcon_cache.get(imageID);
if (ii == null) {
if (imageIcon_verbose) print("Loading image icon: " + imageID);
File f = loadBinarySnippet(imageID);
Boolean b = imageIcon_fixGIF.get();
if (!isFalse(b))
ii = new ImageIcon(loadBufferedImageFixingGIFs(f));
else
ii = new ImageIcon(f.toURI().toURL());
} else
imageIcon_cache.remove(imageID); // move to front of cache on access
imageIcon_cache.put(imageID, ii);
return ii;
} finally { unlock(__0); } } catch (Exception __e) { throw rethrow(__e); } }
// doesn't fix GIFs
static ImageIcon imageIcon(File f) { try {
return new ImageIcon(f.toURI().toURL());
} catch (Exception __e) { throw rethrow(__e); } }
static ImageIcon imageIcon(Image img) {
return new ImageIcon(img);
}
static ImageIcon imageIcon(RGBImage img) {
return imageIcon(img.getBufferedImage());
}
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 double toDouble(Object o) {
if (o instanceof Number)
return ((Number) o).doubleValue();
if (o instanceof BigInteger)
return ((BigInteger) o).doubleValue();
if (o instanceof String)
return parseDouble((String) o);
if (o == null) return 0.0;
throw fail(o);
}
static float clamp(float x, float a, float b) {
return x < a ? a : x > b ? b : x;
}
static double clamp(double x, double a, double b) {
return x < a ? a : x > b ? b : x;
}
static int clamp(int x, int a, int b) {
return x < a ? a : x > b ? b : x;
}
static long clamp(long x, long a, long b) {
return x < a ? a : x > b ? b : x;
}
static BufferedImage byteArrayToGrayBufferedImage(byte[] pixels, int w, int h) {
PixelInterleavedSampleModel sm = new PixelInterleavedSampleModel(
DataBuffer.TYPE_BYTE,
w,
h,
1, // pixelStride
w, // scanlineStride,
new int[] {0} // bandOffsets
);
DataBufferByte db = new DataBufferByte(pixels, pixels.length);
WritableRaster wr = Raster.createWritableRaster(sm, db, new Point());
return new BufferedImage(grayColorModel(), wr, false, null);
}
static void swingAndWait(Runnable r) { try {
if (isAWTThread())
r.run();
else
EventQueue.invokeAndWait(addThreadInfoToRunnable(r));
} catch (Exception __e) { throw rethrow(__e); } }
static Object swingAndWait(final Object f) {
if (isAWTThread())
return callF(f);
else {
final Var result = new Var();
swingAndWait(new Runnable() { public void run() { try {
result.set(callF(f));
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "result.set(callF(f));"; }});
return result.get();
}
}
static void lock(Lock lock) { try {
ping();
if (lock == null) return;
try {
vmBus_send("locking", lock, "thread" , currentThread());
lock.lockInterruptibly();
vmBus_send("locked", lock, "thread" , currentThread());
} catch (InterruptedException e) {
Object reason = vm_threadInterruptionReasonsMap().get(currentThread());
print("Locking interrupted! Reason: " + strOr(reason, "Unknown"));
printStackTrace(e);
rethrow(e);
}
// NO call to ping here! Make sure lock is always released.
} catch (Exception __e) { throw rethrow(__e); } }
static void lock(Lock lock, String msg) {
print("Locking: " + msg);
lock(lock);
}
static void lock(Lock lock, String msg, long timeout) {
print("Locking: " + msg);
lockOrFail(lock, timeout);
}
static ReentrantLock lock() {
return fairLock();
}
static String fsI(String id) {
return formatSnippetID(id);
}
static String fsI(long id) {
return formatSnippetID(id);
}
static volatile StringBuffer local_log = new StringBuffer(); // not redirected
static boolean printAlsoToSystemOut = true;
static volatile Appendable print_log = local_log; // might be redirected, e.g. to main bot
// in bytes - will cut to half that
static volatile int print_log_max = 1024*1024;
static volatile int local_log_max = 100*1024;
static boolean print_silent = false; // total mute if set
static Object print_byThread_lock = new Object();
static volatile ThreadLocal