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 static x30_pkg.x30_util.DynamicObject;
import java.awt.geom.*;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
class main {
static BWImage gazelle22_borderImage(BWImage posterizedWithMeta) {
PosterizeBWImage op = (PosterizeBWImage) (getMetaSrc(posterizedWithMeta));
return gazelle22_borderImage(op.img, posterizedWithMeta, op.brightnessLevels);
}
static BWImage gazelle22_borderImage(BWImage unposterized, BWImage posterized, int brightnessLevels) {
assertSameSize(unposterized, posterized);
int w = posterized.getWidth(), h = posterized.getHeight();
BWImage out = new BWImage(w*2+1, h*2+1);
int singleStep = iceil(doubleRatio(255, brightnessLevels-1));
for (int y = 0; y < h; y++)
for (int x = 0; x < w; x++) {
if (x < w-1) {
// check border with right neighbor
int posterizedContrast = absDiff(posterized.getInt(x, y),
posterized.getInt(x+1, y));
float result;
if (posterizedContrast != 0) {
if (posterizedContrast > singleStep) result = 1f;
else {
int realContrast = absDiff(unposterized.getInt(x, y),
unposterized.getInt(x+1, y));
result = floatRatio(realContrast, singleStep);
}
out.setPixel(x*2+1, y*2, result);
out.setPixel(x*2+1, y*2+1, result);
}
}
if (y < h-1) {
// check border with bottom neighbor
int posterizedContrast = absDiff(posterized.getInt(x, y),
posterized.getInt(x, y+1));
float result;
if (posterizedContrast != 0) {
if (posterizedContrast > singleStep) result = 1f;
else {
int realContrast = absDiff(unposterized.getInt(x, y),
unposterized.getInt(x+1, y));
result = floatRatio(realContrast, singleStep);
}
out.setPixel(x*2, y*2+1, result);
out.setPixel(x*2+1, y*2+1, result);
}
}
}
return out;
}
static Object getMetaSrc(Object o) {
return metaGet("src", o);
}
static void assertSameSize(BufferedImage a, BufferedImage b) {
assertEquals(a.getWidth(), b.getWidth());
assertEquals(a.getHeight(), b.getHeight());
}
static void assertSameSize(WidthAndHeight a, WidthAndHeight b) {
assertEquals(a.getWidth(), b.getWidth());
assertEquals(a.getHeight(), b.getHeight());
}
static int iceil(double d) {
return (int) Math.ceil(d);
}
static double doubleRatio(double x, double y) {
return y == 0 ? 0 : x/y;
}
static int absDiff(int a, int b) {
return abs(a-b);
}
static float floatRatio(float x, float y) {
return y == 0 ? 0 : x/y;
}
static Object metaGet(IMeta o, Object key) {
return metaMapGet(o, key);
}
static Object metaGet(Object o, Object key) {
return metaMapGet(o, key);
}
static Object metaGet(String key, IMeta o) {
return metaMapGet(o, key);
}
static Object metaGet(String key, Object o) {
return metaMapGet(o, key);
}
static A assertEquals(Object x, A y) {
return assertEquals("", x, y);
}
static A assertEquals(String msg, Object x, A y) {
if (assertVerbose()) return assertEqualsVerbose(msg, x, y);
if (!(x == null ? y == null : x.equals(y)))
throw fail((msg != null ? msg + ": " : "") + y + " != " + x);
return y;
}
static float abs(float f) { return Math.abs(f); }
static int abs(int i) { return Math.abs(i); }
static double abs(double d) { return Math.abs(d); }
static Object metaMapGet(IMeta o, Object key) {
return o == null ? null : o.metaGet(key); // We now let the object itself do it (overridable!)
}
static Object metaMapGet(Object o, Object key) {
return metaMapGet(toIMeta(o), key);
}
static ThreadLocal assertVerbose_value = new ThreadLocal();
static void assertVerbose(boolean b) {
assertVerbose_value.set(b);
}
static boolean assertVerbose() { return isTrue(assertVerbose_value.get()); }
static A assertEqualsVerbose(Object x, A y) {
assertEqualsVerbose((String) null, x, y);
return y;
}
// x = expected, y = actual
static A assertEqualsVerbose(String msg, Object x, A y) {
if (!eq(x, y)) {
throw fail((nempty(msg) ? msg + ": " : "") + "expected: "+ x + ", got: " + y);
} else
print("OK" + (empty(msg) ? "" : " " + msg) + ": " + /*sfu*/(x));
return y;
}
static RuntimeException fail() { throw new RuntimeException("fail"); }
static RuntimeException fail(Throwable e) { throw asRuntimeException(e); }
static RuntimeException fail(Object msg) { throw new RuntimeException(String.valueOf(msg)); }
static RuntimeException fail(Object... objects) { throw new Fail(objects); }
static RuntimeException fail(String msg) { throw new RuntimeException(msg == null ? "" : msg); }
static RuntimeException fail(String msg, Throwable innerException) { throw new RuntimeException(msg, innerException); }
static boolean eq(Object a, Object b) {
return a == b || a != null && b != null && a.equals(b);
}
// a little kludge for stuff like eq(symbol, "$X")
static boolean eq(Symbol a, String b) {
return eq(str(a), b);
}
static String nullIfEmpty(String s) {
return isEmpty(s) ? null : s;
}
static Map nullIfEmpty(Map map) {
return isEmpty(map) ? null : map;
}
static List nullIfEmpty(List l) {
return isEmpty(l) ? null : l;
}
static IMeta toIMeta(Object o) {
if (o == null) return null;
if (o instanceof IMeta) return ((IMeta) o);
if (o instanceof JComponent) return initMetaOfJComponent((JComponent) o);
return null;
}
static boolean isTrue(Object o) {
if (o instanceof Boolean)
return ((Boolean) o).booleanValue();
if (o == null) return false;
if (o instanceof ThreadLocal) // TODO: remove this
return isTrue(((ThreadLocal) o).get());
throw fail(getClassName(o));
}
static boolean isTrue(Boolean b) {
return b != null && b.booleanValue();
}
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(MultiMap mm) { return mm != null && !mm.isEmpty(); }
static boolean nempty(Object o) { return !empty(o); }
static boolean nempty(IntRange r) { return !empty(r); }
static boolean nempty(Rect r) { return r != null && r.w != 0 && r.h != 0; }
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