Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

20985
LINES

< > BotCompany Repo | #1033636 // Gazelle 22 Standalone [stable version]

JavaX source code (desktop) [tags: jar-with-libs no-compiler standalone use-pretranspiled]

Download Jar. Uses 2032K of libraries. Click here for Pure Java version (21422L/120K).

lib 1033505
lib 1400521

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 x30_pkg.x30_util;
import static x30_pkg.x30_util.VF1;
import static x30_pkg.x30_util.indexOf;
import static x30_pkg.x30_util.getOpt;
import static x30_pkg.x30_util.setOpt;
import static x30_pkg.x30_util.callOpt;
import static x30_pkg.x30_util.newWeakHashMap;
import static x30_pkg.x30_util.newDangerousWeakHashMap;
import static x30_pkg.x30_util.get;
import static x30_pkg.x30_util.get_raw;
import static x30_pkg.x30_util.assertTrue;
import static x30_pkg.x30_util.isHeadless;
import static x30_pkg.x30_util.isAndroid;
import static x30_pkg.x30_util.isTrue;
import x30_pkg.x30_util.DynamicObject;
import loadableUtils.utils;
import static loadableUtils.utils._threadInfo;
import static loadableUtils.utils._threadInheritInfo;
import static loadableUtils.utils.dm_current_mandatory;
import static loadableUtils.utils.match;
import static loadableUtils.utils.setOpt_raw;
import static loadableUtils.utils.fieldType;
import static loadableUtils.utils.format3;
import static loadableUtils.utils.vm_generalIdentityHashSet;
import static loadableUtils.utils.vm_generalHashMap;
import static loadableUtils.utils.vm_generalWeakSubMap;
import static loadableUtils.utils.bindToComponent;
import static loadableUtils.utils.struct;
import static loadableUtils.utils.structure;
import static loadableUtils.utils.loadPage;
import static loadableUtils.utils.loadPage_utf8;
import static loadableUtils.utils.loadPageSilently;
import static loadableUtils.utils.loadSnippet;
import static loadableUtils.utils.componentPopupMenu;
import static loadableUtils.utils.tablePopupMenu;
import static loadableUtils.utils.tablePopupMenuFirst;
import static loadableUtils.utils.sexyTableWithoutDrag;
import static loadableUtils.utils.dm_current_generic;
import static loadableUtils.utils.cset;
import static loadableUtils.utils.DynamicObject_loading;
import static loadableUtils.utils.concepts_unlisted;
import static loadableUtils.utils.dynamicObjectIsLoading;
import static loadableUtils.utils.rethrow;
import loadableUtils.utils.F0;
import loadableUtils.utils.F1;
import loadableUtils.utils.IF0;
import loadableUtils.utils.IF1;
import loadableUtils.utils.IVF1;
import loadableUtils.utils.IVF2;
import loadableUtils.utils.Matches;
import loadableUtils.utils.SingleComponentPanel;
import loadableUtils.utils.ImageSurface;
import loadableUtils.utils.structure_Data;
import loadableUtils.utils.RGBImage;
import loadableUtils.utils.RGB;
import loadableUtils.utils.BWImage;
import loadableUtils.utils.MakesBufferedImage;
import loadableUtils.utils.MultiSet;
import loadableUtils.utils.Concept;
import loadableUtils.utils.Concepts;
import loadableUtils.utils.IterableIterator;
import loadableUtils.utils.IFieldIndex;
import loadableUtils.utils.PersistableThrowable;
import loadableUtils.utils.DynModule;
import loadableUtils.utils.DynPrintLog;
import loadableUtils.utils.GlobalID;
import loadableUtils.utils.Rect;
import loadableUtils.utils.Pt;
import loadableUtils.utils.SecretValue;
import static loadableUtils.utils.fixNewLines;
import static loadableUtils.utils.getExceptionCause;
import static loadableUtils.utils.joinWithSpace;
import static loadableUtils.utils.callF;
import static loadableUtils.utils.javaTok;
import static loadableUtils.utils.jlabel;
import static loadableUtils.utils.nohupJavax;
import static loadableUtils.utils.withDBLock;
import static loadableUtils.utils.join;
import static loadableUtils.utils.isAWTThread;
import static loadableUtils.utils.set;
import static loadableUtils.utils.call;
import static loadableUtils.utils.fail;
import static loadableUtils.utils.print;
import static loadableUtils.utils.printAlsoToSystemOut;
import static loadableUtils.utils.cget;
import static loadableUtils.utils.newTypeWriterTextArea;
import static loadableUtils.utils.db;
import loadableUtils.utils.LongRange;
import loadableUtils.utils.IntRange;
import loadableUtils.utils.MultiMap;
import loadableUtils.utils.Meta;
import loadableUtils.utils.ITokCondition;
import loadableUtils.utils.PingSource;
import loadableUtils.utils.ThreadPool;
import loadableUtils.utils.SimpleLiveValue;
import loadableUtils.utils.Matrix;
import loadableUtils.utils.Best;
import loadableUtils.utils.IRef;
import loadableUtils.utils.F2;
import loadableUtils.utils.RandomAccessAbstractList;
import loadableUtils.utils.IBWIntegralImage;
import loadableUtils.utils.Producer;
import loadableUtils.utils.IntBuffer;
import loadableUtils.utils.AbstractMatrix;
import loadableUtils.utils.WithTimestamp;
import loadableUtils.utils.IMeta;
import loadableUtils.utils.LiveValue;
import loadableUtils.utils.Timestamp;
import loadableUtils.utils.DoubleRect;
import loadableUtils.utils.Complex;
import loadableUtils.utils.Either;
import loadableUtils.utils.Steppable;
import loadableUtils.utils.T3;
import loadableUtils.utils.Swingable;
import loadableUtils.utils.Average;
import loadableUtils.utils.BWIntegralImage;
import loadableUtils.utils.DoubleRange;
import loadableUtils.utils.Seconds;
import static loadableUtils.utils.withTimestamp;
import static loadableUtils.utils.score;
import static loadableUtils.utils.stepAll;
import static loadableUtils.utils.infoMessage;
import static loadableUtils.utils.brightnessToRGBA;
import static loadableUtils.utils.withBorder;
import static loadableUtils.utils.getPlural;
import static loadableUtils.utils.rcallOpt;
import static loadableUtils.utils.childrenOfType;
import static loadableUtils.utils.nanoTime;
import static loadableUtils.utils.activateFrame_v3;
import static loadableUtils.utils.b;
import static loadableUtils.utils.ewicOneOf;
import static loadableUtils.utils.n;
import static loadableUtils.utils.abs;
import static loadableUtils.utils.callMain;
import static loadableUtils.utils.caseInsensitiveComparator;
import static loadableUtils.utils.getComponents;
import static loadableUtils.utils.rep;
import static loadableUtils.utils.area;
import static loadableUtils.utils.add;
import static loadableUtils.utils.singleComponentPanel;
import static loadableUtils.utils.withMargin;
import static loadableUtils.utils.addActionListener;
import static loadableUtils.utils.hasMethod;
import static loadableUtils.utils.containsOneOf;
import static loadableUtils.utils.intersectRects;
import static loadableUtils.utils.setSCPComponent;
import static loadableUtils.utils.hideWindow;
import static loadableUtils.utils.ymdMinusHMS;
import static loadableUtils.utils.jPopDownButton_noText;
import static loadableUtils.utils.swingLater;
import static loadableUtils.utils.currentImage;
import static loadableUtils.utils._defaultClassFinder;
import static loadableUtils.utils.boolOptParam;
import static loadableUtils.utils.getOptMC;
import static loadableUtils.utils.setImage;
import static loadableUtils.utils.regexp;
import static loadableUtils.utils.alwaysOnTop;
import static loadableUtils.utils.setFrameTitle;
import static loadableUtils.utils.getScreenWidth;
import static loadableUtils.utils.tsNow;
import static loadableUtils.utils.jfind_preprocess;
import static loadableUtils.utils.dm_reload;
import static loadableUtils.utils.getDBProgramID;
import static loadableUtils.utils.setFrameIcon;
import static loadableUtils.utils.isIdentifier;
import static loadableUtils.utils.getSnippetTitle;
import static loadableUtils.utils.jFullCenter;
import static loadableUtils.utils.dm_fieldCheckBox;
import static loadableUtils.utils.indent;
import static loadableUtils.utils.infoBox;
import static loadableUtils.utils.toSeconds;
import static loadableUtils.utils.rect;
import static loadableUtils.utils.cleanUp;
import static loadableUtils.utils.forEach;
import static loadableUtils.utils.disposeWindow;
import static loadableUtils.utils.textFieldFromComboBox;
import static loadableUtils.utils.getScore;
import static loadableUtils.utils.containsNewLines;
import static loadableUtils.utils.stdcompare;
import static loadableUtils.utils.centerAndEast;
import static loadableUtils.utils.metaMapPut;
import static loadableUtils.utils.makeFrame;
import static loadableUtils.utils.setDoubleBuffered;
import static loadableUtils.utils.asVirtualList;
import static loadableUtils.utils.javaTokForJFind_array;
import static loadableUtils.utils.withLeftAndRightMargin;
import static loadableUtils.utils.dm_doEvery;
import static loadableUtils.utils.childOfType;
import static loadableUtils.utils.hgrid;
import static loadableUtils.utils.getFieldType;
import static loadableUtils.utils.ping_v3;
import static loadableUtils.utils.flattenArray2;
import static loadableUtils.utils.getParent;
import static loadableUtils.utils.strOrEmpty;
import static loadableUtils.utils.pqO;
import static loadableUtils.utils.run;
import static loadableUtils.utils.has;
import static loadableUtils.utils.last;
import static loadableUtils.utils.warn;
import static loadableUtils.utils.distance;
import static loadableUtils.utils.jrightAlignedLine;
import static loadableUtils.utils.toRect;
import static loadableUtils.utils.installWindowDragger;
import static loadableUtils.utils.addIfNotNull;
import static loadableUtils.utils.installTimer;
import static loadableUtils.utils.clipBufferedImage;
import static loadableUtils.utils.setText;
import static loadableUtils.utils.findButton;
import static loadableUtils.utils.splitAtSpace;
import static loadableUtils.utils.getBounds;
import static loadableUtils.utils.northAndCenterWithMargin;
import static loadableUtils.utils.renderUserThreadsWithStackTraces;
import static loadableUtils.utils.newConceptsWithClassFinder;
import static loadableUtils.utils.replaceSublist;
import static loadableUtils.utils.selectedItem;
import static loadableUtils.utils.joinSubList;
import static loadableUtils.utils.onSelectedItem;
import static loadableUtils.utils.muricaCredentials;
import static loadableUtils.utils.onUpdate;
import static loadableUtils.utils.activateFrame;
import static loadableUtils.utils.replace;
import static loadableUtils.utils.profileToConsole;
import static loadableUtils.utils.myLibraryFiles;
import static loadableUtils.utils.findCodeTokens;
import static loadableUtils.utils.withTypeWriterFont;
import static loadableUtils.utils.printWithMS;
import static loadableUtils.utils.format;
import static loadableUtils.utils.heightForWidth;
import static loadableUtils.utils.onEnter;
import static loadableUtils.utils.hsplit;
import static loadableUtils.utils.containsNewLine;
import static loadableUtils.utils.centerAndEastWithMargin;
import static loadableUtils.utils.getFrame;
import static loadableUtils.utils.countIterator_exclusive;
import static loadableUtils.utils.centerAndSouth;
import static loadableUtils.utils.dm_fieldLiveValue;
import static loadableUtils.utils.isLetter;
import static loadableUtils.utils.toObjectArray;
import static loadableUtils.utils.rectFromPoints;
import static loadableUtils.utils.runnableThread;
import static loadableUtils.utils.toolTip;
import static loadableUtils.utils.firstToUpper;
import static loadableUtils.utils.allScreenBounds;
import static loadableUtils.utils.findClass_fullName;
import static loadableUtils.utils.copyLocalLog;
import static loadableUtils.utils.jscroll_centered;
import static loadableUtils.utils.parentFile;
import static loadableUtils.utils.gazelle_wavySpacer;
import static loadableUtils.utils.callOnLoadMethods;
import static loadableUtils.utils.dm_rEnter;
import static loadableUtils.utils.toString;
import static loadableUtils.utils.mapI_if1;
import static loadableUtils.utils.getProgramTitle;
import static loadableUtils.utils.renameFile;
import static loadableUtils.utils.isDigit;
import static loadableUtils.utils.regionMatches;
import static loadableUtils.utils.warnIfOddCount;
import static loadableUtils.utils.synchronizedMRUCache;
import static loadableUtils.utils.printFileInfo;
import static loadableUtils.utils.bindLiveValueListenerToComponent;
import static loadableUtils.utils.screenBounds;
import static loadableUtils.utils.myFrames;
import static loadableUtils.utils.callStringifier;
import static loadableUtils.utils.toRectangle;
import static loadableUtils.utils.widthForHeight;
import static loadableUtils.utils.javaxCodeDir;
import static loadableUtils.utils.jLiveValueLabel;
import static loadableUtils.utils.shortClassName_dropNumberPrefix;
import static loadableUtils.utils.minimizeWindow;
import static loadableUtils.utils.appendToFileBaseName;
import static loadableUtils.utils.jbutton;
import static loadableUtils.utils.setEnabled;
import static loadableUtils.utils.functionCall;
import static loadableUtils.utils.javaTokForStructure;
import static loadableUtils.utils.northAndCenter;
import static loadableUtils.utils.jline;
import static loadableUtils.utils.toMS;
import static loadableUtils.utils.creator;
import static loadableUtils.utils.vmBus_query;
import static loadableUtils.utils.change;
import static loadableUtils.utils.assertEquals;
import static loadableUtils.utils.getPreferredSize;
import static loadableUtils.utils.md5;
import static loadableUtils.utils.renderFileInfo;
import static loadableUtils.utils.jCheckBoxMenuItem;
import static loadableUtils.utils.find;
import static loadableUtils.utils.jenableUndoRedo;
import static loadableUtils.utils.setChecked;
import static loadableUtils.utils.setFont;
import static loadableUtils.utils.syncList;
import static loadableUtils.utils.takeFirst;
import static loadableUtils.utils.isEditableComboBox;
import static loadableUtils.utils.numberOfCores;
import static loadableUtils.utils.showWindow;
import static loadableUtils.utils.plus;
import static loadableUtils.utils.dm_watchField;
import static loadableUtils.utils.codeTokensAsStringArray;
import static loadableUtils.utils.ifloor;
import static loadableUtils.utils.hmsWithColonsAndMS;
import static loadableUtils.utils.smartIndexOf;
import static loadableUtils.utils.repeat;
import static loadableUtils.utils.structureForUser;
import static loadableUtils.utils.ok;
import static loadableUtils.utils.nohup;
import static loadableUtils.utils.jCheckBox;
import static loadableUtils.utils.onWindowClosing;
import static loadableUtils.utils.asArray;
import static loadableUtils.utils.pt;
import static loadableUtils.utils.showText;
import static loadableUtils.utils.setDefaultClassFinder;
import static loadableUtils.utils.getBytecodePathForClass;
import static loadableUtils.utils.standardCredentials;
import static loadableUtils.utils.installWindowResizeDraggerOnBorder;
import static loadableUtils.utils.singular;
import static loadableUtils.utils.minus;
import static loadableUtils.utils.syncAddOrCreate;
import static loadableUtils.utils.keysList;
import static loadableUtils.utils.intRange;
import static loadableUtils.utils.getScreenHeight;
import static loadableUtils.utils.boolPar;
import static loadableUtils.utils.fillRect;
import static loadableUtils.utils.westCenterAndEastWithMargin;
import static loadableUtils.utils.indentx;
import static loadableUtils.utils.getSelectedItem;
import static loadableUtils.utils.loadAllClassesInByteCodePath;
import static loadableUtils.utils.isChecked;
import static loadableUtils.utils.similarEmptyMap;
import static loadableUtils.utils.toFile;
import static loadableUtils.utils.tempAdd;
import static loadableUtils.utils.appendToBaseName;
import static loadableUtils.utils.dropFirst;
import static loadableUtils.utils.nClasses;
import static loadableUtils.utils.mod;
import static loadableUtils.utils.makeUndecoratedFrame;
import static loadableUtils.utils.findClass;
import static loadableUtils.utils.humanizeFormLabel;
import static loadableUtils.utils.wrapForSmartAdd;
import static loadableUtils.utils.asSet;
import static loadableUtils.utils.autoFrameTitle;
import static loadableUtils.utils.restart;
import static loadableUtils.utils.installTrayIcon;
import static loadableUtils.utils.shootScreen2;
import static loadableUtils.utils.filter;
import static loadableUtils.utils.mapPut;
import static loadableUtils.utils.onChange;
import static loadableUtils.utils.pingSource;
import static loadableUtils.utils.mapToParams;
import static loadableUtils.utils.isNonEmptySingleZip_byMagicHeader;
import static loadableUtils.utils.withTopMargin;
import static loadableUtils.utils.error;
import static loadableUtils.utils.setBackground;
import static loadableUtils.utils.sysNow;
import static loadableUtils.utils.elapsedSeconds;
import static loadableUtils.utils.hotwire;
import static loadableUtils.utils.heldInstance;
import static loadableUtils.utils.getProgramName;
import static loadableUtils.utils.trayIcon_imageAutoSize;
import loadableUtils.utils.Pair;
import loadableUtils.utils.IBWImage;
import loadableUtils.utils.WidthAndHeight;
import loadableUtils.utils.Enterable;
import loadableUtils.utils.G2Drawable;
import static loadableUtils.utils.getPrintLog;
import static loadableUtils.utils.unstructure;
import static loadableUtils.utils.StefansOS_ConnectToServer;
import static loadableUtils.utils._MethodCache;
import static loadableUtils.utils.defaultMargin;
import static loadableUtils.utils.preferredScreen;
import javax.swing.border.*;
import java.text.NumberFormat;
import javax.imageio.metadata.*;
import javax.imageio.stream.*;
import java.awt.geom.*;
import java.text.SimpleDateFormat;
import java.nio.charset.Charset;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.*;

class main {

  static public String programID;

  static public void _onLoad_initUtils() {
    utils.__javax = javax();
  }

  static public void _onLoad_defaultClassFinder() {
    setDefaultClassFinder(new F1<String, Class>() {

      public Class get(String name) {
        name = replacePrefix("loadableUtils.utils$", "main$", name);
        print("_onLoad_defaultClassFinder " + name);
        Class c = findClass_fullName(name);
        if (c != null)
          return c;
        if (name.startsWith("main$"))
          return loadableUtils.utils.findClass_fullName("loadableUtils.utils" + name.substring(4));
        return null;
      }
    });
  }

  static public ThreadLocal<Boolean> dynamicObjectIsLoading_threadLocal() {
    return DynamicObject_loading;
  }

  static public class GazelleScreenCam extends DynModule {

    volatile public boolean enabled = true;

    transient public JPanel buttons;

    public void setEnabled(boolean b) {
      setField("enabled", b);
    }

    public JComponent visualize_enabled() {
      return dm_checkBox("enabled");
    }

    public int pixelRows = 128, colors = 8;

    public String script, testScreenScript;

    public boolean animate = true;

    public boolean horizontalLayout = false;

    public WatchTarget watchTarget;

    transient public ImageSurface isPosterized, isRegions, isTestScreen;

    transient public ScreenCamStream images = new ScreenCamStream();

    transient public BWIntegralImageStream integralImages = new BWIntegralImageStream();

    transient public SourceTriggeredStream<BWImage> scaledAndPosterizedImages = new SourceTriggeredStream();

    transient public DoubleFPSCounter fpsCounter = new DoubleFPSCounter();

    transient public int fps;

    transient public WatchTargetSelector watchTargetSelector;

    transient public RollingAverage remainingMSPerFrame = new RollingAverage();

    transient public int remainingMS;

    transient public FunctionTimings<String> functionTimings = new FunctionTimings();

    transient public ReliableSingleThread rstRunScript = dm_rst(me(), new Runnable() {

      public void run() {
        try {
          _runScript();
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "_runScript();";
      }
    });

    transient public JGazelleVScriptRunner scriptRunner;

    transient public JGazelleVScriptRunner testScreenScriptRunner;

    transient public Animation animation;

    transient public FastRegions_BWImage mainScreenRegions;

    transient public ImageSurface_HighlightRegion regionHighlighter;

    transient public UIURLSystem uiURLs;

    transient public Concepts concepts;

    public String uiURL;

    public void start() {
      try {
        super.start();
        dm_onFieldChange("horizontalLayout", new Runnable() {

          public void run() {
            try {
              dm_reload();
            } catch (Exception __e) {
              throw rethrow(__e);
            }
          }

          public String toString() {
            return "dm_reload();";
          }
        });
        if (concepts == null) {
          db();
          concepts = db_mainConcepts();
        }
        uiURLs = new UIURLSystem(me(), dm_fieldLiveValue("uiURL"));
        scriptRunner = new JGazelleVScriptRunner(dm_fieldLiveValue("script", me()));
        testScreenScriptRunner = new JGazelleVScriptRunner(dm_fieldLiveValue("testScreenScript", me()));
        images.directlyFeedInto(integralImages);
        integralImages.onNewElement(ii -> scaledAndPosterizedImages.newElement(posterizeBWImage_withMeta(colors, scaledBWImageFromBWIntegralImage_withMeta_height(pixelRows, ii))));
        integralImages.onNewElement(new Runnable() {

          public void run() {
            try {
              if (shouldRunScript())
                rstRunScript.go();
            } catch (Exception __e) {
              throw rethrow(__e);
            }
          }

          public String toString() {
            return "if (shouldRunScript()) rstRunScript.go();";
          }
        });
        scaledAndPosterizedImages.onNewElement(img -> {
          fpsCounter.inc();
          setField("fps", iround(fpsCounter.get()));
          {
            if (isPosterized != null)
              isPosterized.setImage_thisThread(img);
          }
          floodFill(img);
        });
        dm_doEvery(1000 / 20, new Runnable() {

          public void run() {
            try {
              if (enabled) {
                {
                  if (watchTargetSelector != null)
                    watchTargetSelector.updateScreenCount();
                }
                Timestamp deadline = tsNowPlusMS(1000 / 20);
                if (watchTarget instanceof WatchScreen)
                  images.useScreen(((WatchScreen) watchTarget).screenNr - 1);
                else if (watchTarget instanceof WatchMouse)
                  images.area(mouseArea(((WatchMouse) watchTarget).width, ((WatchMouse) watchTarget).height));
                images.step();
                long remaining = deadline.minus(tsNow());
                remainingMSPerFrame.add(remaining);
                setField("remainingMS", iround(remainingMSPerFrame.get()));
              }
            } catch (Exception __e) {
              throw rethrow(__e);
            }
          }

          public String toString() {
            return "if (enabled) {\r\n        watchTargetSelector?.updateScreenCount();\r\n        Ti...";
          }
        });
      } catch (Exception __e) {
        throw rethrow(__e);
      }
    }

    public ImageSurface stdImageSurface() {
      return pixelatedImageSurface().setAutoZoomToDisplay(true).repaintInThread(false);
    }

    public JComponent visualize() {
      isPosterized = stdImageSurface();
      regionHighlighter = new ImageSurface_HighlightRegion(isPosterized);
      regionHighlighter.regionPainter(new RegionFillPainter());
      isRegions = stdImageSurface();
      isTestScreen = stdImageSurface();
      awtEvery(isTestScreen, 1000 / 20, new Runnable() {

        public void run() {
          try {
            stepAnimation();
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "stepAnimation();";
        }
      });
      JTextArea taTimings = jTextArea_noUndo();
      awtEveryAndNow(taTimings, .5, new Runnable() {

        public void run() {
          try {
            setText(taTimings, renderFunctionTimings());
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "setText(taTimings, renderFunctionTimings())";
        }
      });
      var jSpeedInfo = dm_transientCalculatedToolTip(() -> speedInfo_long(), rightAlignLabel(dm_transientCalculatedLabel(() -> speedInfo())));
      print("Labels: " + list(concepts, Label.class));
      SimpleCRUD_v2 labelCRUD = new SimpleCRUD_v2(concepts, Label.class);
      labelCRUD.hideFields("globalID");
      labelCRUD.addCountToEnclosingTab(true);
      SimpleCRUD_v2 imageCRUD = new SimpleCRUD_v2(concepts, SavedImage.class);
      imageCRUD.addCountToEnclosingTab(true);
      var tabs = scrollingTabs(jTopOrLeftTabs(horizontalLayout, "Posterized", withTools(isPosterized), "Regions", jscroll_centered_borderless(isRegions), "Labels", labelCRUD.make_dontStartBots(), "Saved Images", imageCRUD.make_dontStartBots(), "Script", scriptRunner.scriptAndResultPanel(), "Test Screen", testScreenPanel(), "Timings", withRightAlignedButtons(taTimings, "Reset", new Runnable() {

        public void run() {
          try {
            resetTimings();
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "resetTimings();";
        }
      })));
      labelCRUD.update();
      imageCRUD.update();
      watchTargetSelector = new WatchTargetSelector();
      var vis = northAndCenter(withSideAndTopMargin(uiURLs.urlBar()), centerAndSouthOrEast(horizontalLayout, horizontalLayout ? withMargin(tabs) : withSideMargin(tabs), (borderlessScrollPane(jHigherScrollPane(jfullcenter(vstack(withLeftAndRightMargin(hstack(dm_rcheckBox("enabled", "Watch"), watchTargetSelector.visualize(), jlabel(" in "), withLabelToTheRight("colors @ ", dm_spinner("colors", 2, 256)), withLabelToTheRight("p", dm_powersOfTwoSpinner("pixelRows", 512)))), verticalStrut(2), withRightMargin(jSpeedInfo))))))));
      setHorizontalMarginForAllButtons(vis, 4);
      return vis;
    }

    public String speedInfo() {
      return "FPS " + fps + " idle " + remainingMS + " ms";
    }

    public String speedInfo_long() {
      return "Screen cam running at " + nFrames(fps) + "/second. " + n2(remainingMS) + " ms remaining per frame in first core.";
    }

    public void floodFill(BWImage img) {
      FastRegions_BWImage ff = new FastRegions_BWImage(img);
      ff.collectBounds();
      functionTimings.time("Regions", ff);
      mainScreenRegions = ff;
      {
        if (regionHighlighter != null)
          regionHighlighter.setRegions(ff);
      }
      if (isRegions != null && isRegions.isShowing_quick()) {
        isRegions.setImage_thisThread(ff.regionsImage());
      }
      setEnclosingTabTitle(isRegions, nRegions(ff.regionCount()));
    }

    public boolean useErrorHandling() {
      return false;
    }

    public String renderFunctionTimings() {
      return lines(ciSorted(map(functionTimings.get(), (f, avg) -> firstToUpper(f) + ": " + n2(iround(nsToMicroseconds(avg.get()))) + " " + microSymbol() + "s (" + n2(iround(avg.n())) + ")")));
    }

    transient public long _runScript_idx;

    public void _runScript() {
      long n = integralImages.elementCount();
      if (n > _runScript_idx) {
        _runScript_idx = n;
        scriptRunner.parseAndRunOn(integralImages.get());
      }
    }

    public boolean shouldRunScript() {
      return isShowing(scriptRunner.scpScriptResult);
    }

    public void stepAnimation() {
      if (!animate)
        return;
      if (animation == null) {
        animation = new AnimatedLine();
        animation.start();
      }
      animation.nextFrame();
      var img = whiteImage(animation.w, animation.h);
      animation.setGraphics(createGraphics(img));
      animation.paint();
      {
        if (isTestScreen != null)
          isTestScreen.setImage(img);
      }
      var ii = bwIntegralImage_withMeta(img);
      testScreenScriptRunner.parseAndRunOn(ii);
    }

    public JComponent testScreenPanel() {
      return centerAndSouthWithMargin(hsplit(northAndCenterWithMargin(centerAndEastWithMargin(jlabel("Input"), dm_fieldCheckBox("animate")), jscroll_centered_borderless(isTestScreen)), northAndCenterWithMargin(centerAndEastWithMargin(jlabel("Output"), testScreenScriptRunner.lblScore), testScreenScriptRunner.scpScriptResult)), testScreenScriptRunner.scriptInputField());
    }

    public List popDownItems() {
      return ll(jCheckBoxMenuItem_dyn("Horizontal Layout", () -> horizontalLayout, b -> setField("horizontalLayout", b)));
    }

    public void unvisualize() {
    }

    public void resetTimings() {
      functionTimings.reset();
    }

    public JComponent withTools(ImageSurface is) {
      new ImageSurface_PositionToolTip(is);
      return centerAndEastWithMargin(jscroll_centered_borderless(is), vstackWithSpacing(3, jbutton("A"), jbutton("B"), jbutton("C")));
    }

    public class WatchTargetSelector {

      public JComboBox<WatchTarget> cb = jComboBox();

      public int screenCount;

      public JComponent visualize() {
        updateList();
        print("Selecting watchTarget: " + watchTarget);
        selectItem(cb, watchTarget);
        loadableUtils.utils.onChange(cb, watchTarget -> {
          setField("watchTarget", watchTarget);
          print("Chose watchTarget: " + GazelleScreenCam.this.watchTarget);
        });
        return cb;
      }

      public void updateScreenCount() {
        if (screenCount != screenCount())
          updateList();
      }

      public void updateList() {
        swing(() -> {
          setComboBoxItems(cb, makeWatchTargets());
        });
      }

      public List<WatchTarget> makeWatchTargets() {
        return flattenToList(countIteratorAsList_incl(1, screenCount = screenCount(), i -> new WatchScreen(i)), new WatchMouse());
      }
    }
  }

  static public boolean _moduleClass_GazelleScreenCam = true;

  static public class Label extends ConceptWithGlobalID {

    public String name;

    public String toString() {
      return "Label " + name;
    }
  }

  static public class SavedImage extends Concept {

    public File path;
  }

  static public class SavedRegion extends Concept {

    static final public String _fieldOrder = "image area";

    public Concept image;

    public Rect area;
  }

  static public class ExampleForLabel extends Concept {

    static final public String _fieldOrder = "label example confidence";

    public Ref<Label> label = new Ref();

    public Ref example = new Ref();

    public double confidence = 1;
  }

  static public class IfThenTheory extends Concept {

    public Ref if_ = new Ref();

    public Ref then = new Ref();
  }

  static public class WatchTarget {
  }

  static public class WatchScreen extends WatchTarget implements IFieldsToList {

    public int screenNr;

    public WatchScreen() {
    }

    public WatchScreen(int screenNr) {
      this.screenNr = screenNr;
    }

    public boolean equals(Object o) {
      if (!(o instanceof WatchScreen))
        return false;
      WatchScreen __1 = (WatchScreen) o;
      return screenNr == __1.screenNr;
    }

    public int hashCode() {
      int h = -1787428357;
      h = boostHashCombine(h, _hashCode(screenNr));
      return h;
    }

    public Object[] _fieldsToList() {
      return new Object[] { screenNr };
    }

    public String toString() {
      return "Screen " + screenNr;
    }
  }

  static public class WatchMouse extends WatchTarget implements IFieldsToList {

    static final public String _fieldOrder = "width height";

    public int width;

    public int height;

    public WatchMouse(int width, int height) {
      this.height = height;
      this.width = width;
    }

    public boolean equals(Object o) {
      if (!(o instanceof WatchMouse))
        return false;
      WatchMouse __2 = (WatchMouse) o;
      return width == __2.width && height == __2.height;
    }

    public int hashCode() {
      int h = 1876823350;
      h = boostHashCombine(h, _hashCode(width));
      h = boostHashCombine(h, _hashCode(height));
      return h;
    }

    public Object[] _fieldsToList() {
      return new Object[] { width, height };
    }

    public WatchMouse() {
      height = 256;
      width = iround(height * 16.0 / 9);
    }

    public String toString() {
      return "Mouse";
    }
  }

  static public void standaloneInit() {
    __javax = x30.class;
    x30.__javax = x30.class;
    x30_pkg.x30_util.__setJavaX(x30.class);
    x30.cleanKillMsg = "";
    callOnLoadMethods(mc());
  }

  static public class PrintLogModule extends DynPrintLog {

    public PrintLogModule() {
      setModuleName("Print Log");
    }

    public String getPrintLog() {
      return printLog();
    }

    public boolean useErrorHandling() {
      return false;
    }
  }

  static public class Stem extends Concept {

    static final public String _fieldOrder = "host module frameRect maximized alwaysOnTop autoUpdate window btnMax";

    transient public GazelleHost host;

    public DynModule module;

    public Rect frameRect;

    public boolean maximized, alwaysOnTop, autoUpdate;

    transient public JFrame window;

    transient public JButton btnMax;

    public Stem() {
    }

    public Stem(GazelleHost host) {
      this.host = host;
    }

    public Stem(GazelleHost host, DynModule module) {
      this.module = module;
      this.host = host;
    }

    public Rect getFrameRect() {
      return toRect(getBounds(window));
    }

    public void saveFrameRect() {
      setField("frameRect", getFrameRect());
    }

    public void setAlwaysOnTop(boolean alwaysOnTop) {
      this.alwaysOnTop = alwaysOnTop;
      change();
      alwaysOnTop(window, alwaysOnTop);
    }

    public void setWindow(JFrame window) {
      this.window = window;
      if (frameRect != null)
        setBounds(window, frameRect);
      onBoundsChange(window, new Runnable() {

        public void run() {
          try {
            saveFrameRect();
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "saveFrameRect();";
        }
      });
      alwaysOnTop(window, alwaysOnTop);
    }

    public boolean isMain() {
      return this == host.stem;
    }

    public void minimize() {
      if (host.trayIcon == null || !isMain())
        minimizeWindow(window);
      else
        hideWindow(window);
    }

    public void deleteMe() {
      printAlsoToSystemOut = true;
      print("deleteMe " + isMain());
      if (isMain()) {
        host.cleanExit();
      } else {
        disposeWindow(window);
        {
          cleanUp(module);
          module = null;
        }
        cdelete(this);
      }
    }

    public void grabWindowState() {
      setField("maximized", !isExtendedStateNormal(window));
    }

    public void updateBtnMax() {
      if (!isShowing(btnMax))
        return;
      grabWindowState();
      setText(btnMax, maximized ? "NORM" : "MAX");
    }

    public JComponent makeWindowBorderAndTitle(JComponent contents, String title) {
      var icons = jline();
      if (host.allowFrameMaximization) {
        icons.add(btnMax = jbutton("", runnableThread(new Runnable() {

          public void run() {
            try {
              maximizeOrRestoreFrame(window);
              updateBtnMax();
            } catch (Exception __e) {
              throw rethrow(__e);
            }
          }

          public String toString() {
            return "maximizeOrRestoreFrame(window);\r\n        updateBtnMax();";
          }
        })));
        onFirstShowing(btnMax, new Runnable() {

          public void run() {
            try {
              updateBtnMax();
            } catch (Exception __e) {
              throw rethrow(__e);
            }
          }

          public String toString() {
            return "updateBtnMax();";
          }
        });
      }
      icons.add(jbutton("MIN", new Runnable() {

        public void run() {
          try {
            minimize();
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "minimize();";
        }
      }));
      icons.add(jbutton("QUIT", runnableThread(new Runnable() {

        public void run() {
          try {
            if (swingConfirm("Really quit Gazelle?"))
              deleteMe();
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "if (swingConfirm(\"Really quit Gazelle?\"))\r\n        deleteMe();";
        }
      })));
      setHorizontalMarginForAllButtons(icons, 4);
      icons.add(jPopDownButton_noText(flattenToList(!isMain() ? null : ll("Restart", runnableThread(new Runnable() {

        public void run() {
          try {
            host.restart();
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "host.restart()";
        }
      }), "Update Gazelle", runnableThread(new Runnable() {

        public void run() {
          try {
            host.upgradeGazelle();
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "host.upgradeGazelle()";
        }
      }), jCheckBoxMenuItem_dyn("Auto-Update", () -> autoUpdate, b -> cset(Stem.this, "autoUpdate", b))), "---", jCheckBoxMenuItem_dyn("Always on top", () -> alwaysOnTop, alwaysOnTop -> setAlwaysOnTop(alwaysOnTop)), "---", !isMain() ? null : ll("Screenshoot this window", runnableThread(new Runnable() {

        public void run() {
          try {
            shootWindow();
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "shootWindow();";
        }
      }), "Dump threads", runnableThread(new Runnable() {

        public void run() {
          try {
            showText("User threads", renderUserThreadsWithStackTraces());
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "showText(\"User threads\", renderUserThreadsWithStackTraces());";
        }
      }), !isMain() ? null : "Print log", !isMain() ? null : runnableThread(new Runnable() {

        public void run() {
          try {
            host.showPrintLog();
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "host.showPrintLog()";
        }
      })), ccallOpt(module, "popDownItems"))));
      JComponent actualTitle = fontSizePlus(7, jCenteredLabel(title));
      installWindowDragger(actualTitle);
      if (isMain() && haveMuricaPassword())
        actualTitle = centerAndEastWithMargin(actualTitle, compileButton());
      var spacer = gazelle_wavySpacer();
      var titleBarMain = setOpaqueBackground(host.color1, jtransparent_recursive(westCenterAndEastWithMargin(jImage_scaledToHeight(24, host.trayIconImageID), actualTitle, setOpaqueBackground(host.color2, spacer))));
      installWindowDragger(spacer);
      var titleBar = setBackground(host.color2, centerAndEast(titleBarMain, icons));
      var border = BorderFactory.createLineBorder(host.color1, host.borderSize);
      var outerPanel = withBorder(border, northAndCenter(titleBar, contents));
      installWindowResizeDraggerOnBorder(outerPanel);
      return outerPanel;
    }

    public JComponent compileButton() {
      return jimageButton(scaleImageToWidth(16, "#1101268"), "Compile & update", disableButtonWhileCalcing3(() -> compile()));
    }

    public void compile() {
      transpileOnServerWithErrorWindow(programID, true, null);
    }

    public void startAndShow() {
      module._host = this;
      setOpt_raw(module, "threadPool", threadPool);
      setOpt_raw(module, "concepts", host.concepts);
      copyLocalLog(module, mc());
      var __15 = makeVisAndTitle();
      var vis = __15.a;
      var title = __15.b;
      printWithMS("Show frame");
      JFrame frame = makeUndecoratedFrame(title, vis);
      setFrameIcon(frame, host.trayIconImageID);
      setWindow(frame);
      showWindow(window);
      if (maximized && host.allowFrameMaximization)
        maximizeFrame(window);
    }

    public Pair<JComponent, String> makeVisAndTitle() {
      JComponent vis;
      {
        AutoCloseable __13 = module.enter();
        try {
          module.start();
          printWithMS("Visualize");
          vis = swing(() -> {
            AutoCloseable __14 = module.enter();
            try {
              return module.visualize();
            } finally {
              _close(__14);
            }
          });
        } finally {
          _close(__13);
        }
      }
      String title = host.windowTitle;
      if (!isMain())
        title += appendWithColon(module.moduleName());
      vis = makeWindowBorderAndTitle(vis, title);
      return pair(vis, title);
    }

    public void revisualize() {
      if (window == null)
        return;
      try {
        module.unvisualize();
      } catch (Throwable __e) {
        printStackTrace(__e);
      }
      var __16 = makeVisAndTitle();
      var vis = __16.a;
      var title = __16.b;
      setFrameContents(window, vis);
    }

    public void shootWindow() {
      var img = renderComponentToImage(window);
      copyImageToClipboard(img);
      saveInImageDirectoryWithCounter("Gazelle/Gazelle", img);
    }
  }

  static public class GazelleHost {

    public boolean _isTransient() {
      return true;
    }

    public Stem stem;

    public DynModule gazelle;

    transient public String windowTitle = "November Gazelle v1";

    transient public String trayIconImageID = "#1103047";

    transient public int borderSize = 5;

    transient public Color color1 = awtColor("ADD8E6");

    transient public Color color2 = awtColor("EEEEEE");

    transient public Color color3 = awtColor("A3C0AA");

    transient public IF0<DynModule> moduleMaker;

    transient public ThreadPool threadPool;

    transient public TrayIcon trayIcon;

    transient public TrayIconLastPosition trayIconLastPosition;

    transient public Set<String> argsSet;

    transient public Concepts concepts;

    transient public boolean allowFrameMaximization = false;

    public GazelleHost(ThreadPool threadPool, IF0<DynModule> moduleMaker) {
      this.moduleMaker = moduleMaker;
      this.threadPool = threadPool;
    }

    public void trayIconLeftClick() {
      activateFrame_v3(mainWindow());
    }

    public void makeTrayIcon() {
      try {
        trayIcon_imageAutoSize = false;
        trayIcon = installTrayIcon(trayIconImageID, windowTitle, new Runnable() {

          public void run() {
            try {
              trayIconLeftClick();
            } catch (Exception __e) {
              throw rethrow(__e);
            }
          }

          public String toString() {
            return "trayIconLeftClick();";
          }
        }, "Show Gazelle", new Runnable() {

          public void run() {
            try {
              trayIconLeftClick();
            } catch (Exception __e) {
              throw rethrow(__e);
            }
          }

          public String toString() {
            return "trayIconLeftClick();";
          }
        }, "Exit Gazelle", new Runnable() {

          public void run() {
            try {
              cleanExit();
            } catch (Exception __e) {
              throw rethrow(__e);
            }
          }

          public String toString() {
            return "cleanExit();";
          }
        });
        trayIconLastPosition = new TrayIconLastPosition(trayIcon);
      } catch (Throwable __e) {
        print(exceptionToStringShort(__e));
      }
    }

    public void run(String[] args) {
      try {
        run2(args);
      } catch (Throwable e) {
        printStackTrace(e);
        hideTrayIcon(trayIcon);
        onWindowClosing(() -> systemExit(1), getWindow(showText_fast_noWrap("Gazelle Error", renderStackTrace(e))));
      }
    }

    public void run2(String[] args) {
      argsSet = asSet(args);
      if (!argsSet.contains("noflatlaf"))
        com.formdev.flatlaf.FlatLightLaf.setup();
      if (contains(args, "profile"))
        profileToConsole(() -> actualMain(args));
      else
        actualMain(args);
      if (argsSet.contains("brexit"))
        System.exit(0);
    }

    public void actualMain(String... args) {
      vm_generalMap_put("stefansOS", this);
      System.out.println(hmsWithColonsAndMS() + ": Init");
      if (containsOneOf(argsSet, "upgrade", "update")) {
        upgradeGazelle();
        return;
      }
      makeTrayIcon();
      initAutoUpdate();
      assertEquals(callF(_defaultClassFinder(), "main$Stem"), Stem.class);
      concepts = newConceptsWithClassFinder(programID);
      concepts.makeStructureData = () -> {
        structure_Data data = concepts.makeStructureData_base();
        data.mcDollar = mcDollar();
        return data;
      };
      concepts.fileLock().lockOrFail();
      concepts.fileLock().deleteOnExit();
      concepts.persist();
      print("Concepts loaded: " + map(__33 -> className(__33), allConcepts(concepts)));
      var stems = findConcepts(concepts, Stem.class);
      print("Stems in DB: " + l(stems));
      stem = first(stems);
      if (stem == null) {
        print("Starting new module");
        makeModule();
        stem = registerConcept(concepts, new Stem(this, gazelle));
      }
      gazelle = stem.module;
      for (var stem : list(Stem.class, concepts)) {
        stem.host = this;
        stem.startAndShow();
      }
      printWithMS("Dudadoneski");
    }

    public void showPrintLog() {
      registerConcept(concepts, new Stem(this, new PrintLogModule())).startAndShow();
    }

    public JFrame mainWindow() {
      return stem == null ? null : stem.window;
    }

    public Object dm_getStem(Object moduleOrID) {
      return stem;
    }

    public Object resolveModule(Object moduleOrID) {
      return moduleOrID == stem ? gazelle : moduleOrID;
    }

    public void cleanExit() {
      {
        startThread(new Runnable() {

          public void run() {
            try {
              print("Saving DB for exit");
              {
                cleanUp(concepts);
                concepts = null;
              }
              System.exit(0);
            } catch (Exception __e) {
              throw rethrow(__e);
            }
          }

          public String toString() {
            return "print(\"Saving DB for exit\");\r\n      { cleanUp(concepts); concepts = null; }\r\n...";
          }
        });
      }
    }

    public File myJar() {
      return getBytecodePathForClass(this);
    }

    public void upgradeGazelle() {
      File myJar = myJar();
      print("myJar", myJar);
      String date = ymdMinusHMS();
      File f = javaxCodeDir("Downloaded Updates/" + "gazelle-" + date + ".jar");
      infoBox("Downloading Update...");
      loadBinaryPageToFile(downloadURL(), f);
      printFileInfo(f);
      if (!isNonEmptySingleZip_byMagicHeader(f)) {
        infoBox("Bad file downloaded... :(");
        return;
      }
      boolean replaced = false;
      if (isFile(myJar)) {
        print("Loaded " + nClasses(loadAllClassesInByteCodePath(myJar)));
        print("Replacing with new version: " + myJar);
        renameFile(myJar, appendToBaseName(myJar, ".bak." + date));
        copyFile(f, myJar);
        printFileInfo(myJar);
        replaced = true;
      }
      infoBox(replaced ? "Installed update, replaced " + f2s(myJar) + " - now starting" : "Starting update, but could not replace originally downloaded jar");
      restart(replaced ? myJar : f);
    }

    public void restart() {
      restart(myJar());
    }

    public void restart(File jar) {
      String javaCmd = or2(currentProcessCommand(), "java");
      String cmd = pqO(javaCmd) + " -jar " + pqO(jar);
      print(cmd);
      nohup(cmd);
      cleanExit();
    }

    public void makeModule() {
      if (gazelle == null)
        gazelle = callF(moduleMaker);
    }

    public void reloadModuleInBackground(Stem mod) {
      restart();
    }

    public void initAutoUpdate() {
      print("Making SnippetUpdateConnector.");
      snippetUpdateConnector("verbose", true);
      vmBus_onMessage("snippetUpdate", new VF1<List>() {

        public void get(List l) {
          try {
            String uri = getString(l, 1);
            Matches m = new Matches();
            if (swic(uri, "/transpileOK/", m))
              if (sameSnippetID(programID(), firstIntAsString(m.rest()))) {
                if (stem.autoUpdate)
                  upgradeGazelle();
              }
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "S uri = getString(l, 1);\r\n      new Matches m;\r\n      if (swic(uri, \"/transpi...";
        }
      });
    }

    public String downloadURL() {
      return "https://botcompany.de/jar/" + psI(programID()) + "?withLibs=1&noCompiler=1" + (downloadUncompressedJAR() ? "&uncompressed=1" : "");
    }

    public boolean downloadUncompressedJAR() {
      return false;
    }

    public void revisualizeModule(Stem stem) {
      stem.revisualize();
    }
  }

  static public String windowTitle = "Gazelle 22";

  static public String progIDForDBAndAutoUpdate = "#1033636";

  static public boolean pingSourceStrictMode = false;

  static public GazelleHost host;

  static public GazelleScreenCam client;

  static public ThreadPool threadPool;

  public static void main(final String[] args) throws Exception {
    loadableUtils.utils.__setJavaX(main.class);
    standaloneInit();
    ping_v3_setPingSourceMaker(() -> {
      System.out.println("pingSourceMaker");
      if (pingSourceStrictMode)
        throw fail("Strict mode - make a ping source first!!");
      return new PingSource(threadPool, "legacy");
    });
    threadPool = new ThreadPool(findIntArg("cores", args, numberOfCores()));
    print(threadPool);
    PingSource ps = new PingSource(threadPool, print("Starting Gazelle"));
    ps.dO(() -> {
      System.out.println("Pinging");
      ping();
      print("Pinged");
      programID = progIDForDBAndAutoUpdate;
      preferredScreen = () -> {
        if (host == null)
          return 0;
        var stem = host.stem;
        if (stem == null)
          return 0;
        int screen = max(0, screenNrOfWindow(stem.window));
        print("preferredScreen", screen);
        return screen;
      };
      if (cic(args, "delete-session")) {
        print("Deleting session (" + programDir(programID) + ")");
        clearConceptsOf(programID);
      }
      host = new GazelleHost(threadPool, () -> {
        return client = new GazelleScreenCam();
      });
      if (sameSnippetID(programID, "#1033860"))
        windowTitle += " dev";
      host.windowTitle = windowTitle;
      host.run(args);
      if (!cic(args, "console")) {
        print("Stopping System.out");
        printAlsoToSystemOut = false;
      }
    });
    print("aha.");
  }

  static public Map generalMap = syncMap();

  static volatile public Concepts mainConcepts;

  static public Concepts db_mainConcepts() {
    if (mainConcepts == null)
      mainConcepts = newConceptsWithClassFinder(getDBProgramID());
    return mainConcepts;
  }

  static public void cleanMeUp_concepts() {
    if (db_mainConcepts() != null)
      db_mainConcepts().cleanMeUp();
  }

  static public Class javax() {
    return getJavaX();
  }

  static public String replacePrefix(String prefix, String replacement, String s) {
    if (!startsWith(s, prefix))
      return s;
    return replacement + substring(s, l(prefix));
  }

  static public JCheckBox dm_checkBox(String field) {
    return dm_fieldCheckBox(field);
  }

  static public JCheckBox dm_checkBox(String text, String field) {
    return dm_fieldCheckBox(text, field);
  }

  static public ReliableSingleThread dm_rst(Runnable r) {
    return dm_rst(dm_current_mandatory(), r);
  }

  static public ReliableSingleThread dm_rst(DynModule mod, Runnable r) {
    return dm_rst(mod, new ReliableSingleThread(r));
  }

  static public ReliableSingleThread dm_rst(DynModule mod, ReliableSingleThread rst) {
    rst.enter = dm_rEnter(mod);
    return rst;
  }

  static public void dm_onFieldChange(String field, Runnable onChange) {
    dm_watchField(field, onChange);
  }

  static public void dm_onFieldChange(Collection<String> fields, Runnable onChange) {
    dm_watchFields(fields, onChange);
  }

  static public BWImage posterizeBWImage_withMeta(int brightnessLevels, BWImage img) {
    return setMetaSrcUnlessSame(img, posterizeBWImage(brightnessLevels, img), functionCall("posterizeBWImage", brightnessLevels, img));
  }

  static public BWImage scaledBWImageFromBWIntegralImage_withMeta(int w, BWIntegralImage img) {
    return scaledBWImageFromBWIntegralImage(img, w);
  }

  static public BWImage scaledBWImageFromBWIntegralImage_withMeta_height(int h, BWIntegralImage img) {
    return scaledBWImageFromBWIntegralImage(img, widthForHeight(img, h), h);
  }

  static public BWImage scaledBWImageFromBWIntegralImage_withMeta(BWIntegralImage img, int w) {
    return scaledBWImageFromBWIntegralImage_withMeta(img, w, heightForWidth(img, w));
  }

  static public BWImage scaledBWImageFromBWIntegralImage_withMeta(BWIntegralImage img, int w, int h) {
    return setMetaSrc(scaledBWImageFromBWIntegralImage(img, w, h), functionCall("scaledBWImageFromBWIntegralImage", img, w, h));
  }

  static public BWImage scaledBWImageFromBWIntegralImage_withMeta(int w, IBWIntegralImage img) {
    return scaledBWImageFromBWIntegralImage(img, w);
  }

  static public BWImage scaledBWImageFromBWIntegralImage_withMeta_height(int h, IBWIntegralImage img) {
    return scaledBWImageFromBWIntegralImage(img, widthForHeight(img, h), h);
  }

  static public BWImage scaledBWImageFromBWIntegralImage_withMeta(IBWIntegralImage img, int w) {
    return scaledBWImageFromBWIntegralImage_withMeta(img, w, heightForWidth(img, w));
  }

  static public BWImage scaledBWImageFromBWIntegralImage_withMeta(IBWIntegralImage img, int w, int h) {
    return setMetaSrc(scaledBWImageFromBWIntegralImage(img, w, h), functionCall("scaledBWImageFromBWIntegralImage", img, w, h));
  }

  static public int iround(double d) {
    return (int) Math.round(d);
  }

  static public int iround(Number n) {
    return iround(toDouble(n));
  }

  static public Timestamp tsNowPlusMS(long ms) {
    return tsNow().plus(msToSeconds(ms));
  }

  static public Rect mouseArea(int w) {
    return mouseArea(w, w);
  }

  static public Rect mouseArea(int w, int h) {
    Point p = mouseLocation();
    return new Rect(p.x - w / 2, p.y - h / 2, w, h);
  }

  static public ImageSurface pixelatedImageSurface() {
    var is = imageSurface();
    imageSurface_pixelated(is);
    return is;
  }

  static public ImageSurface pixelatedImageSurface(MakesBufferedImage img) {
    return pixelatedImageSurface(toBufferedImage(img));
  }

  static public ImageSurface pixelatedImageSurface(BufferedImage img) {
    var is = pixelatedImageSurface();
    is.setImage(img);
    return is;
  }

  static public <A extends JComponent> A awtEvery(A component, long delay, Object r) {
    swingEvery(component, delay, r);
    return component;
  }

  static public <A extends JComponent> A awtEvery(A component, long delay, long firstDelay, Object r) {
    swingEvery(component, delay, firstDelay, r);
    return component;
  }

  static public void awtEvery(RootPaneContainer frame, long delay, Object r) {
    swingEvery(frame, delay, r);
  }

  static public <A extends JComponent> A awtEvery(A component, double delaySeconds, Object r) {
    return awtEvery(component, toMS(delaySeconds), r);
  }

  static public JTextArea jTextArea_noUndo() {
    return jTextArea_noUndo("");
  }

  static public JTextArea jTextArea_noUndo(final String text) {
    return swingNu(JTextArea.class, text);
  }

  static public <A extends JComponent> A awtEveryAndNow(A component, long delay, Object r) {
    swingEvery(component, delay, 0, r);
    return component;
  }

  static public <A extends JComponent> A awtEveryAndNow(A component, double delaySeconds, Object r) {
    return awtEveryAndNow(component, toMS(delaySeconds), r);
  }

  static public void awtEveryAndNow(RootPaneContainer frame, long delay, Object r) {
    swingEvery(frame, delay, 0, r);
  }

  static public <A extends JComponent> A dm_transientCalculatedToolTip(IF0<Object> calc, A component) {
    return toolTipFromLiveValue(dm_transientCalculatedLiveValue(Object.class, calc), component);
  }

  static public <A extends JLabel> A rightAlignLabel(final A a) {
    return setHorizontalAlignment(JLabel.RIGHT, a);
  }

  static public JLabel dm_transientCalculatedLabel(IF0<Object> calc) {
    return jLiveValueLabel(dm_transientCalculatedLiveValue(Object.class, calc));
  }

  static public <A extends Concept> List<A> list(Class<A> type) {
    return list(type, db_mainConcepts());
  }

  static public <A extends Concept> List<A> list(Class<A> type, Concepts cc) {
    return cc.list(type);
  }

  static public <A extends Concept> List<A> list(Concepts concepts, Class<A> type) {
    return concepts.list(type);
  }

  static public List<Concept> list(String type) {
    return db_mainConcepts().list(type);
  }

  static public List<Concept> list(Concepts concepts, String type) {
    return concepts.list(type);
  }

  static public JTabbedPane scrollingTabs(JTabbedPane pane) {
    if (pane != null) {
      swing(() -> {
        pane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
      });
    }
    return pane;
  }

  static public JTabbedPane jTopOrLeftTabs(boolean horizontal, Object... x) {
    return jLeftOrTopTabs(horizontal, x);
  }

  static public JTabbedPane jTopOrLeftTabs(boolean horizontal, Collection c) {
    return jLeftOrTopTabs(horizontal, c);
  }

  static public JScrollPane jscroll_centered_borderless(Component c) {
    return borderlessScrollPane(jscroll_centered(c));
  }

  static public JPanel withRightAlignedButtons(JComponent center, Object... params) {
    return centerAndSouth(center, withMargin(jRightAlignedButtons(params)));
  }

  static public JPanel withRightAlignedButtons(Swingable center, Object... params) {
    return withRightAlignedButtons(wrap(center), params);
  }

  static public JPanel withSideAndTopMargin(Component c) {
    return withSideAndTopMargin(defaultMargin(), c);
  }

  static public JPanel withSideAndTopMargin(int w, Component c) {
    return swing(() -> {
      JPanel p = marginPanel();
      p.setBorder(BorderFactory.createEmptyBorder(w, w, 0, w));
      p.add(c);
      return p;
    });
  }

  static public JPanel centerAndSouthOrEast(boolean horizontal, Component c, Component s) {
    return horizontal ? centerAndEast(c, s) : centerAndSouth(c, s);
  }

  static public JPanel withSideMargin(Component c) {
    return withLeftAndRightMargin(c);
  }

  static public JPanel withSideMargin(int w, Component c) {
    return withLeftAndRightMargin(w, c);
  }

  static public JPanel withSideMargin(int w1, int w2, Component c) {
    return withLeftAndRightMargin(w1, w2, c);
  }

  static public JScrollPane borderlessScrollPane(JScrollPane sp) {
    return setBorder(null, withoutViewportBorder(sp));
  }

  static public JScrollPane jHigherScrollPane(final JComponent c) {
    return swing(new F0<JScrollPane>() {

      public JScrollPane get() {
        try {
          return new JScrollPane(c) {

            public Dimension getPreferredSize() {
              Component view = getViewport().getView();
              if (view == null)
                return super.getPreferredSize();
              int pref_width = view.getPreferredSize().width;
              setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
              Dimension dim = new Dimension(pref_width, super.getPreferredSize().height + getHorizontalScrollBar().getSize().height);
              setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
              return dim;
            }
          };
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret new JScrollPane(c) {\r\n    public Dimension getPreferredSize() {\r\n      Co...";
      }
    });
  }

  static public JPanel jfullcenter(Component c) {
    return jFullCenter(c);
  }

  static public JPanel vstack(Object... parts) {
    return vstack2(parts);
  }

  static public JPanel vstack(List parts) {
    return vstack(toObjectArray(parts));
  }

  static public JPanel hstack(Object... parts) {
    JPanel panel = new JPanel(new GridBagLayout());
    GridBagConstraints gbc = new GridBagConstraints();
    gbc.weighty = 1;
    gbc.fill = GridBagConstraints.VERTICAL;
    gbc.gridheight = GridBagConstraints.REMAINDER;
    smartAddWithLayout(panel, gbc, parts);
    gbc.weightx = 1;
    panel.add(jrigid(), gbc);
    return panel;
  }

  static public JCheckBox dm_rcheckBox(String field) {
    return dm_fieldCheckBox(field);
  }

  static public JCheckBox dm_rcheckBox(String field, String text) {
    return dm_fieldCheckBox(text, field);
  }

  static public JComponent withLabelToTheRight(JComponent component, String label) {
    return centerAndEast(component, jlabel(" " + label));
  }

  static public JComponent withLabelToTheRight(String label, JComponent component) {
    return withLabelToTheRight(component, label);
  }

  static public JSpinner dm_spinner(String field, int min, int max) {
    return liveValueSpinner(dm_fieldLiveValue(field), min, max);
  }

  static public JSpinner dm_powersOfTwoSpinner(String field, int max) {
    SimpleLiveValue<Integer> lv = dm_fieldLiveValue(field);
    return bindLiveValueToSpinner(lv, jPowersOfTwoSpinner(max, lv.get()));
  }

  static public Component verticalStrut(int height) {
    return Box.createVerticalStrut(height);
  }

  static public int withRightMargin_defaultWidth = 6;

  static public JPanel withRightMargin(Component c) {
    return withRightMargin(withRightMargin_defaultWidth, c);
  }

  static public JPanel withRightMargin(final int w, final Component c) {
    return swing(new F0<JPanel>() {

      public JPanel get() {
        try {
          JPanel p = marginPanel();
          p.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, w));
          p.add(c);
          return p;
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "JPanel p = marginPanel();\r\n    p.setBorder(BorderFactory.createEmptyBorder(0,...";
      }
    });
  }

  static public void setHorizontalMarginForAllButtons(int margin, Component c) {
    for (var btn : allButtons(c)) setHorizontalMargin(btn, margin);
  }

  static public void setHorizontalMarginForAllButtons(Component c, int margin) {
    setHorizontalMarginForAllButtons(margin, c);
  }

  static public String nFrames(long n) {
    return n2(n, "frame");
  }

  static public String nFrames(Collection l) {
    return nFrames(l(l));
  }

  static public String nFrames(Map map) {
    return nFrames(l(map));
  }

  static public String n2(long l) {
    return formatWithThousands(l);
  }

  static public String n2(AtomicLong l) {
    return n2(l.get());
  }

  static public String n2(Collection l) {
    return n2(l(l));
  }

  static public String n2(Map map) {
    return n2(l(map));
  }

  static public String n2(double l, String singular) {
    return empty(singular) ? str(l) : n2(l, singular, singular + "s");
  }

  static public String n2(double l, String singular, String plural) {
    if (fraction(l) == 0)
      return n2((long) l, singular, plural);
    else
      return l + " " + plural;
  }

  static public String n2(long l, String singular, String plural) {
    return n_fancy2(l, singular, plural);
  }

  static public String n2(long l, String singular) {
    return empty(singular) ? n2(l) : n_fancy2(l, singular, singular + "s");
  }

  static public String n2(Collection l, String singular) {
    return n2(l(l), singular);
  }

  static public String n2(Collection l, String singular, String plural) {
    return n_fancy2(l, singular, plural);
  }

  static public String n2(Map m, String singular, String plural) {
    return n_fancy2(m, singular, plural);
  }

  static public String n2(Map m, String singular) {
    return n2(l(m), singular);
  }

  static public String n2(long[] a, String singular) {
    return n2(l(a), singular);
  }

  static public String n2(Object[] a, String singular) {
    return n2(l(a), singular);
  }

  static public String n2(Object[] a, String singular, String plural) {
    return n_fancy2(a, singular, plural);
  }

  static public String n2(MultiSet ms, String singular, String plural) {
    return n_fancy2(ms, singular, plural);
  }

  static public void setEnclosingTabTitle(JComponent c, String title) {
    swing(() -> {
      Pair<JTabbedPane, Integer> p = enclosingTab(c);
      if (p == null)
        return;
      setTabTitle(p.a, p.b, title);
    });
  }

  static public String nRegions(long n) {
    return n2(n, "region");
  }

  static public String nRegions(Collection l) {
    return nRegions(l(l));
  }

  static public String nRegions(Map map) {
    return nRegions(l(map));
  }

  static public String lines(Iterable lines) {
    return fromLines(lines);
  }

  static public String lines(Object[] lines) {
    return fromLines(asList(lines));
  }

  static public List<String> lines(String s) {
    return toLines(s);
  }

  static public <A> String lines(Iterable<A> l, IF1<A, String> f) {
    return mapToLines(l, f);
  }

  static public List<String> ciSorted(Collection<String> c) {
    return sortedIgnoreCase(c);
  }

  static public List map(Iterable l, Object f) {
    return map(f, l);
  }

  static public List map(Object f, Iterable l) {
    List x = emptyList(l);
    if (l != null)
      for (Object o : l) {
        ping();
        x.add(callF(f, o));
      }
    return x;
  }

  static public <A, B> List<B> map(Iterable<A> l, F1<A, B> f) {
    return map(f, l);
  }

  static public <A, B> List<B> map(F1<A, B> f, Iterable<A> l) {
    List x = emptyList(l);
    if (l != null)
      for (A o : l) {
        ping();
        x.add(callF(f, o));
      }
    return x;
  }

  static public <A, B> List<B> map(IF1<A, B> f, Iterable<A> l) {
    return map(l, f);
  }

  static public <A, B> List<B> map(Iterable<A> l, IF1<A, B> f) {
    List x = emptyList(l);
    if (l != null)
      for (A o : l) {
        ping();
        x.add(f.get(o));
      }
    return x;
  }

  static public <A, B> List<B> map(IF1<A, B> f, A[] l) {
    return map(l, f);
  }

  static public <A, B> List<B> map(A[] l, IF1<A, B> f) {
    List x = emptyList(l);
    if (l != null)
      for (A o : l) {
        ping();
        x.add(f.get(o));
      }
    return x;
  }

  static public List map(Object f, Object[] l) {
    return map(f, asList(l));
  }

  static public List map(Object[] l, Object f) {
    return map(f, l);
  }

  static public List map(Object f, Map map) {
    return map(map, f);
  }

  static public List map(Map map, Object f) {
    List x = new ArrayList();
    if (map != null)
      for (Object _e : map.entrySet()) {
        ping();
        Map.Entry e = (Map.Entry) _e;
        x.add(callF(f, e.getKey(), e.getValue()));
      }
    return x;
  }

  static public <A, B, C> List<C> map(Map<A, B> map, IF2<A, B, C> f) {
    return map(map, (Object) f);
  }

  static public <A, B> List<A> map(IF1<A, B> f, A data1, A... moreData) {
    List x = emptyList(l(moreData) + 1);
    x.add(f.get(data1));
    if (moreData != null)
      for (A o : moreData) {
        ping();
        x.add(f.get(o));
      }
    return x;
  }

  static public double nsToMicroseconds(double ns) {
    return nanosToMicroseconds(ns);
  }

  static public String microSymbol() {
    return "\u00B5";
  }

  static public boolean isShowing(Component c) {
    return isComponentShowing(c);
  }

  static public BufferedImage whiteImage(int w, int h) {
    return newBufferedImage(w, h, Color.white);
  }

  static public BufferedImage whiteImage(int size) {
    return whiteImage(size, size);
  }

  static public Map<BufferedImage, Object> createGraphics_modulators = synchroIdentityHashMap();

  static public Graphics2D createGraphics(BufferedImage img) {
    Graphics2D g = img.createGraphics();
    Object mod = createGraphics_modulators.get(img);
    if (mod != null)
      callF(mod, g);
    return g;
  }

  static public void createGraphics_modulate(BufferedImage img, Object mod) {
    mapPut2(createGraphics_modulators, img, mod);
  }

  static public BWIntegralImage bwIntegralImage_withMeta(BufferedImage img) {
    return setMetaSrc(bwIntegralImage(img), img);
  }

  static public BWIntegralImage bwIntegralImage_withMeta(BWImage img) {
    return setMetaSrc(bwIntegralImage(img), img);
  }

  static public JPanel centerAndSouthWithMargin(Component c, Component s) {
    return centerAndSouth(c, withTopMargin(s));
  }

  static public JPanel centerAndSouthWithMargin(int margin, Component c, Component s) {
    return centerAndSouth(c, withTopMargin(margin, s));
  }

  static public <A> List<A> ll(A... a) {
    ArrayList l = new ArrayList(a.length);
    if (a != null)
      for (A x : a) l.add(x);
    return l;
  }

  static public JCheckBoxMenuItem jCheckBoxMenuItem_dyn(String text, IF0<Boolean> checked, Object r) {
    JCheckBoxMenuItem mi = jCheckBoxMenuItem(text, false, r);
    if (checked != null)
      bindToComponent(mi, new Runnable() {

        public void run() {
          try {
            boolean b = isTrue(checked.get());
            setChecked(mi, b);
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "boolean b = isTrue(checked!);\r\n    ifdef jCheckBoxMenuItem_dyn_debug\r\n      p...";
        }
      }, new Runnable() {

        public void run() {
          try {
            ;
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "ifdef jCheckBoxMenuItem_dyn_debug\r\n      print(\"jCheckBoxMenuItem_dyn: hiding...";
        }
      });
    return mi;
  }

  static public JCheckBoxMenuItem jCheckBoxMenuItem_dyn(String text, IF0<Boolean> checked, IVF1<Boolean> r) {
    return jCheckBoxMenuItem_dyn(text, checked, (Object) r);
  }

  static public int vstackWithSpacing_default = 10;

  static public JPanel vstackWithSpacing(final List parts) {
    return vstackWithSpacing(parts, vstackWithSpacing_default);
  }

  static public JPanel vstackWithSpacing(final List parts, final int spacing) {
    return swing(new F0<JPanel>() {

      public JPanel get() {
        try {
          JPanel panel = new JPanel(new GridBagLayout());
          GridBagConstraints gbc = new GridBagConstraints();
          gbc.weightx = 1;
          gbc.fill = GridBagConstraints.HORIZONTAL;
          gbc.gridwidth = GridBagConstraints.REMAINDER;
          gbc.insets = new Insets(spacing / 2, 0, (spacing + 1) / 2, 0);
          smartAddWithLayout(panel, gbc, toObjectArray(nonNulls(parts)));
          gbc.weighty = 1;
          gbc.insets = new Insets(0, 0, 0, 0);
          panel.add(jrigid(), gbc);
          return panel;
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "JPanel panel = new JPanel(new GridBagLayout);\r\n    new GridBagConstraints gbc...";
      }
    });
  }

  static public JPanel vstackWithSpacing(Component... parts) {
    return vstackWithSpacing(asList(parts), vstackWithSpacing_default);
  }

  static public JPanel vstackWithSpacing(int spacing, Component... parts) {
    return vstackWithSpacing(asList(parts), spacing);
  }

  static public JComboBox jComboBox(final String... items) {
    return jcombobox(items);
  }

  static public JComboBox jComboBox(Collection<String> items) {
    return jcombobox(items);
  }

  static public JComboBox jComboBox(Collection<String> items, String selectedItem) {
    return jcombobox(items, selectedItem);
  }

  static public <A> JComboBox<A> selectItem(A item, JComboBox<A> cb) {
    if (cb != null) {
      swing(() -> {
        cb.setSelectedItem(item);
      });
    }
    return cb;
  }

  static public <A> JComboBox<A> selectItem(JComboBox<A> cb, A item) {
    return selectItem(item, cb);
  }

  static public <A> JList<A> selectItem(JList<A> list, A item) {
    {
      swing(() -> {
        selectRow(list, jlist_indexOf(list, item));
      });
    }
    return list;
  }

  static public int screenCount() {
    return l(GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices());
  }

  static public Object swing(Object f) {
    return swingAndWait(f);
  }

  static public void swing(Runnable f) {
    swingAndWait(f);
  }

  static public <A> A swing(F0<A> f) {
    return (A) swingAndWait(f);
  }

  static public <A> A swing(IF0<A> f) {
    return (A) swingAndWait(f);
  }

  static public <A> void setComboBoxItems(JComboBox<A> cb, Collection<A> items) {
    if (cb != null) {
      swing(() -> {
        cb.setModel(new DefaultComboBoxModel(new Vector(items)));
      });
    }
  }

  static public List flattenToList(Object... l) {
    Flattener f = new Flattener();
    f.add(l);
    return f.toList();
  }

  static public List<Integer> countIteratorAsList_incl(int b) {
    return countIteratorAsList_incl(0, b);
  }

  static public List<Integer> countIteratorAsList_incl(int a, int b) {
    return countIteratorToList_inclusive(a, b);
  }

  static public <A> List<A> countIteratorAsList_incl(int b, IF1<Integer, A> f) {
    return countIteratorAsList_incl(0, b, f);
  }

  static public <A> List<A> countIteratorAsList_incl(int a, int b, IF1<Integer, A> f) {
    return countIteratorToList_inclusive(a, b, f);
  }

  static public List<Integer> countIteratorAsList_incl(int a, int b, int step) {
    return countIteratorToList_inclusive(a, b, step);
  }

  static public <A> List<A> countIteratorAsList_incl(double a, double b, double step, IF1<Double, A> f) {
    return countIteratorToList_inclusive(a, b, step, f);
  }

  static public <A> List<Double> countIteratorAsList_incl(double a, double b, double step) {
    return countIteratorToList_inclusive(a, b, step);
  }

  static public <A> List<A> countIteratorAsList_incl(IF1<Double, A> f, double a, double b, double step) {
    return countIteratorToList_inclusive(f, a, b, step);
  }

  static public <A> List<A> countIteratorAsList_incl(IF1<Integer, A> f, int a, int b) {
    return countIteratorAsList_incl(f, a, b, 1);
  }

  static public <A> List<A> countIteratorAsList_incl(IF1<Integer, A> f, int a, int b, int step) {
    return countIteratorToList_inclusive(f, a, b, step);
  }

  static public int boostHashCombine(int a, int b) {
    return a ^ (b + 0x9e3779b9 + (a << 6) + (a >> 2));
  }

  static public int _hashCode(Object a) {
    return a == null ? 0 : a.hashCode();
  }

  static public Class mc() {
    return main.class;
  }

  static public String printLog() {
    return getPrintLog();
  }

  static public <A extends Component> A setBounds(final int x, final int y, final int w, final int h, final A a) {
    if (a != null) {
      swing(() -> {
        a.setBounds(x, y, w, h);
      });
    }
    return a;
  }

  static public <A extends Component> A setBounds(A a, Rect r) {
    if (a != null && r != null) {
      swing(() -> {
        a.setBounds(toRectangle(r));
      });
    }
    return a;
  }

  static public <A extends Component> A setBounds(Rect r, A a) {
    return setBounds(a, r);
  }

  static public <A extends Component> A setBounds(A a, int x, int y, int w, int h) {
    return setBounds(x, y, w, h, a);
  }

  static public <A extends Component> A onBoundsChange(A c, final Object r) {
    if (c != null && r != null) {
      swing(() -> {
        c.addComponentListener(new ComponentAdapter() {

          public void componentResized(ComponentEvent e) {
            pcallF(r);
          }

          public void componentMoved(ComponentEvent e) {
            pcallF(r);
          }
        });
      });
    }
    return c;
  }

  static public <A extends Component> A onBoundsChange(Object r, A c) {
    return onBoundsChange(c, r);
  }

  static public boolean isMain() {
    return isMainProgram();
  }

  static public <A extends Concept> List<A> cdelete(Class<A> c, Object... params) {
    return deleteConcepts(c, params);
  }

  static public void cdelete(Concept c) {
    deleteConcept(c);
  }

  static public <A extends Concept> void cdelete(Collection<A> c) {
    for (A a : cloneList(c)) cdelete(a);
  }

  static public boolean isExtendedStateNormal(JFrame f) {
    return f != null && swing(() -> f.getExtendedState() == JFrame.NORMAL);
  }

  static public void maximizeOrRestoreFrame(JFrame f) {
    if (f == null)
      return;
    if (!isExtendedStateNormal(f)) {
      swing(() -> {
        f.setExtendedState(JFrame.NORMAL);
      });
    } else
      maximizeFrame(f);
  }

  static public <A extends JComponent> A onFirstShowing(A component, Runnable onShow) {
    return onFirstComponentShow(component, onShow);
  }

  static public boolean swingConfirm(Component owner, String msg) {
    return confirmOKCancel(owner, msg);
  }

  static public boolean swingConfirm(String msg) {
    return confirmOKCancel(msg);
  }

  static public <A extends Component> A setAlwaysOnTop(A c) {
    return alwaysOnTop(c);
  }

  static public BufferedImage shootWindow(Window w) {
    w.toFront();
    sleep(50);
    return shootScreen2(w.getBounds());
  }

  static public Object ccallOpt(Concept.Ref ref, String method, Object... args) {
    return callOptWithEnter(cDeref(ref), method, args);
  }

  static public Object ccallOpt(Object object, String method, Object... args) {
    return callOptWithEnter(object, method, args);
  }

  static public <A extends JComponent> A fontSizePlus(final int delta, final A c) {
    if (c != null) {
      swing(() -> {
        Font font = c.getFont();
        c.setFont(font.deriveFont(font.getSize2D() + delta));
      });
    }
    return c;
  }

  static public JLabel jCenteredLabel(String text) {
    return jcenteredLabel(text);
  }

  static public JLabel jCenteredLabel() {
    return jcenteredLabel();
  }

  static public boolean haveMuricaPassword() {
    return nempty(muricaPassword());
  }

  static public <A extends JComponent> A setOpaqueBackground(final Color color, final A a) {
    if (a != null) {
      swing(() -> {
        a.setBackground(color);
        a.setOpaque(true);
        a.putClientProperty("substancelaf.colorizationFactor", 1.0);
      });
    }
    return a;
  }

  static public <A extends Component> A jtransparent_recursive(A a) {
    if (a instanceof JPanel) {
      ((JPanel) a).setOpaque(false);
      for (Component c : getSwingChildren(a)) jtransparent_recursive(c);
    }
    return a;
  }

  static public JLabel jImage_scaledToHeight(String imageID, int height) {
    return jImage(resizeImageToHeight_bilinear(loadImage2(imageID), height));
  }

  static public JLabel jImage_scaledToHeight(int height, String imageID) {
    return jImage_scaledToHeight(imageID, height);
  }

  static public JButton jimageButton(String imageID, Object action) {
    JButton btn = jbutton("", action);
    btn.setIcon(imageIcon(imageID));
    return btn;
  }

  static public JButton jimageButton(String imageID) {
    return jimageButton(imageID, null);
  }

  static public JButton jimageButton(BufferedImage img, String toolTip, Runnable action) {
    var btn = jbutton("", action);
    setButtonImage(btn, img);
    return setToolTip(toolTip, btn);
  }

  static public BufferedImage scaleImageToWidth(BufferedImage img, int newW) {
    return resizeImage(img, newW);
  }

  static public BufferedImage scaleImageToWidth(int newW, BufferedImage img) {
    return scaleImageToWidth(img, newW);
  }

  static public BufferedImage scaleImageToWidth(int newW, String imageID) {
    return scaleImageToWidth(newW, loadImage2(imageID));
  }

  static public Runnable disableButtonWhileCalcing3(final Runnable r) {
    return new Runnable() {

      public void run() {
        try {
          disableButtonWhileCalcing2(r);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "disableButtonWhileCalcing2(r)";
      }
    };
  }

  static public class transpileOnServerWithErrorWindow_DaClass {

    public String snippetID;

    public JFastLogView_noWrap transpilationErrorBox;

    public Runnable onSuccess;

    public Object onError;

    public void go(boolean medium) {
      infoBox("Transpiling " + snippetID);
      final Pair<Boolean, String> p = transpileOnBestServer(snippetID, medium ? "medium" : "quick");
      swingLater(new Runnable() {

        public void run() {
          try {
            if (p.a) {
              infoBox("Transpiled OK!");
              hideWindow(transpilationErrorBox);
              transpilationErrorBox = null;
              callFInNewThread(onSuccess);
            } else {
              infoBox("Transpilation error. " + p.b);
              boolean first = transpilationErrorBox == null;
              transpilationErrorBox = maximizeFrame(scrollAllTheWayDown(showText_fast_noWrap(transpilationErrorBox, "Transpilation Error", p.b)));
              if (first) {
                setFrameIcon("#1101268", transpilationErrorBox);
                addButtonsToWindow(transpilationErrorBox, "Medium transpile", runnableThread(new Runnable() {

                  public void run() {
                    try {
                      go(true);
                    } catch (Exception __e) {
                      throw rethrow(__e);
                    }
                  }

                  public String toString() {
                    return "go(true)";
                  }
                }));
              }
              callFInNewThread(onError, p.b);
            }
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "if (p.a) {\r\n        infoBox(\"Transpiled OK!\");\r\n        hideWindow(transpilat...";
        }
      });
    }
  }

  static public void transpileOnServerWithErrorWindow(String snippetID, boolean medium, final Runnable onSuccess, Object... __) {
    nu(transpileOnServerWithErrorWindow_DaClass.class, paramsPlus(__, "snippetID", snippetID, "onSuccess", onSuccess)).go(medium);
  }

  static public <A extends Component> A maximizeFrame(A c) {
    JFrame f = swing(new F0<JFrame>() {

      public JFrame get() {
        try {
          JFrame f = getFrame(c);
          if (f != null)
            f.setExtendedState(JFrame.MAXIMIZED_BOTH);
          return f;
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "JFrame f = getFrame(c);\r\n    if (f != null)\r\n      f.setExtendedState(JFrame....";
      }
    });
    if (f != null && !isAWTThread()) {
      Dimension d = maximumWindowBounds().getSize();
      long start = sysNow();
      while (licensed()) {
        try {
          if (f.getWidth() >= d.getWidth() - 100 && f.getHeight() >= d.getHeight() - 100)
            break;
          if (sysNow() >= start + 100) {
            warn("maximizeFrame timeout");
            break;
          }
        } catch (Throwable __e) {
          printStackTrace(__e);
        }
        sleep(1);
      }
    }
    return c;
  }

  static public void _close(AutoCloseable c) {
    if (c != null)
      try {
        c.close();
      } catch (Throwable e) {
        if (c instanceof javax.imageio.stream.ImageOutputStream)
          return;
        else
          throw rethrow(e);
      }
  }

  static public String appendWithColon(String s) {
    return prependColonSpaceIfNempty(s);
  }

  static public <A, B> Pair<A, B> pair(A a, B b) {
    return new Pair(a, b);
  }

  static public <A> Pair<A, A> pair(A a) {
    return new Pair(a, a);
  }

  static public <A extends Throwable> A printStackTrace(A e) {
    if (e != null)
      print(getStackTrace(e));
    return e;
  }

  static public void printStackTrace() {
    printStackTrace(new Throwable());
  }

  static public void printStackTrace(String msg) {
    printStackTrace(new Throwable(msg));
  }

  static public void printStackTrace(String msg, Throwable e) {
    printStackTrace(new Throwable(msg, e));
  }

  static public void setFrameContents(final Component c, final Object contents) {
    swing(() -> {
      JFrame frame = getFrame(c);
      if (frame == null)
        return;
      frame.getContentPane().removeAll();
      frame.getContentPane().setLayout(new BorderLayout());
      frame.getContentPane().add(wrap(contents));
      revalidate(frame);
    });
  }

  static public BufferedImage renderComponentToImage(final Component c) {
    if (c == null)
      return null;
    return swing(new F0<BufferedImage>() {

      public BufferedImage get() {
        try {
          int w = getWidth(c), h = getHeight(c);
          BufferedImage img = newBufferedImage(w, h);
          c.paint(createGraphics(img));
          return img;
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "int w = getWidth(c), h = getHeight(c);\r\n    BufferedImage img = newBufferedIm...";
      }
    });
  }

  static public <A extends Image> A copyImageToClipboard(A img) {
    TransferableImage trans = new TransferableImage(img);
    Toolkit.getDefaultToolkit().getSystemClipboard().setContents(trans, null);
    vmBus_send("newClipboardContents", img);
    print("Copied image to clipboard (" + img.getWidth(null) + "*" + img.getHeight(null) + " px)");
    return img;
  }

  static public File saveInImageDirectoryWithCounter(String subPath, BufferedImage img) {
    if (img == null)
      return null;
    assertNempty(subPath);
    File dir = imagesDir();
    if (!isImageFileName(subPath))
      subPath += ".png";
    File f = makeFileNameUnique_beforeExtension_startWith1_noDot(newFile(dir, subPath));
    saveImage(f, img);
    infoBox("Saved image " + appendBracketed(img.getWidth(null) + "*" + img.getHeight(null)) + ": " + fileInfo(f));
    return f;
  }

  static public java.awt.Color awtColor(String hex) {
    byte[] b = bytesFromHex(dropPrefix("#", hex));
    return new Color(ubyteToInt(b[0]), ubyteToInt(b[1]), ubyteToInt(b[2]));
  }

  static public CleanExit cleanExit(String msg) {
    throw new CleanExit(msg);
  }

  static public CleanExit cleanExit() {
    throw new CleanExit();
  }

  static public String exceptionToStringShort(Throwable e) {
    lastException(e);
    e = getInnerException(e);
    String msg = hideCredentials(unnull(e.getMessage()));
    if (msg.indexOf("Error") < 0 && msg.indexOf("Exception") < 0)
      return baseClassName(e) + prependIfNempty(": ", msg);
    else
      return msg;
  }

  static public void hideTrayIcon(TrayIcon t) {
    removeTrayIcon(t);
  }

  static public void systemExit(int code) {
    System.exit(code);
  }

  static public Window getWindow(Object o) {
    if (!(o instanceof Component))
      return null;
    return swing(() -> {
      Component c = (Component) o;
      while (c != null) {
        if (c instanceof Window)
          return ((Window) c);
        c = c.getParent();
      }
      return null;
    });
  }

  static public JFastLogView_noWrap showText_fast_noWrap(String title, Object text) {
    return showText_fast_noWrap(null, title, text);
  }

  static public JFastLogView_noWrap showText_fast_noWrap(JFastLogView_noWrap view, String title, Object text) {
    if (view != null) {
      view.setText(str(text));
      return view;
    }
    view = jFastLogView_noWrap(str(text));
    makeFrame(title, jscroll_copyBackground(view));
    return view;
  }

  static public JFastLogView_noWrap showText_fast_noWrap(Object text) {
    return showText_fast_noWrap(autoFrameTitle(), text);
  }

  static public String renderStackTrace(StackTraceElement[] st) {
    return stackTraceToString(st);
  }

  static public String renderStackTrace(Throwable e) {
    return stackTraceToString(e);
  }

  static public String renderStackTrace(String msg) {
    return renderStackTrace(new Throwable(msg));
  }

  static public boolean contains(Collection c, Object o) {
    return c != null && c.contains(o);
  }

  static public boolean contains(Iterable it, Object a) {
    if (it != null)
      for (Object o : it) if (eq(a, o))
        return true;
    return false;
  }

  static public boolean contains(Object[] x, Object o) {
    if (x != null)
      for (Object a : x) if (eq(a, o))
        return true;
    return false;
  }

  static public boolean contains(String s, char c) {
    return s != null && s.indexOf(c) >= 0;
  }

  static public boolean contains(String s, String b) {
    return s != null && s.indexOf(b) >= 0;
  }

  static public boolean contains(BitSet bs, int i) {
    return bs != null && bs.get(i);
  }

  static public <A> boolean contains(Producer<A> p, A a) {
    if (p != null && a != null)
      while (true) {
        A x = p.next();
        if (x == null)
          break;
        if (eq(x, a))
          return true;
      }
    return false;
  }

  static public Object vm_generalMap_put(Object key, Object value) {
    return mapPutOrRemove(vm_generalMap(), key, value);
  }

  static public String mcDollar() {
    return mcName() + "$";
  }

  static public String className(Object o) {
    return getClassName(o);
  }

  static public Collection<Concept> allConcepts() {
    return db_mainConcepts().allConcepts();
  }

  static public Collection<Concept> allConcepts(Concepts concepts) {
    return concepts.allConcepts();
  }

  static public <A extends Concept> Collection<A> findConcepts(Class<A> c, Object... params) {
    return findConceptsWhere(c, params);
  }

  static public Collection<Concept> findConcepts(String c, Object... params) {
    return findConceptsWhere(c, params);
  }

  static public <A extends Concept> Collection<A> findConcepts(Concepts concepts, Class<A> c, Object... params) {
    return findConceptsWhere(concepts, c, params);
  }

  static public Collection<Concept> findConcepts(Concepts concepts, String c, Object... params) {
    return findConceptsWhere(concepts, c, params);
  }

  static public int l(Object[] a) {
    return a == null ? 0 : a.length;
  }

  static public int l(boolean[] a) {
    return a == null ? 0 : a.length;
  }

  static public int l(byte[] a) {
    return a == null ? 0 : a.length;
  }

  static public int l(short[] a) {
    return a == null ? 0 : a.length;
  }

  static public int l(long[] a) {
    return a == null ? 0 : a.length;
  }

  static public int l(int[] a) {
    return a == null ? 0 : a.length;
  }

  static public int l(float[] a) {
    return a == null ? 0 : a.length;
  }

  static public int l(double[] a) {
    return a == null ? 0 : a.length;
  }

  static public int l(char[] a) {
    return a == null ? 0 : a.length;
  }

  static public int l(Collection c) {
    return c == null ? 0 : c.size();
  }

  static public int l(Iterator i) {
    return iteratorCount_int_close(i);
  }

  static public int l(Map m) {
    return m == null ? 0 : m.size();
  }

  static public int l(CharSequence s) {
    return s == null ? 0 : s.length();
  }

  static public long l(File f) {
    return f == null ? 0 : f.length();
  }

  static public int l(Object o) {
    return o == null ? 0 : o instanceof String ? l((String) o) : o instanceof Map ? l((Map) o) : o instanceof Collection ? l((Collection) o) : o instanceof Object[] ? l((Object[]) o) : o instanceof boolean[] ? l((boolean[]) o) : o instanceof byte[] ? l((byte[]) o) : o instanceof char[] ? l((char[]) o) : o instanceof short[] ? l((short[]) o) : o instanceof int[] ? l((int[]) o) : o instanceof float[] ? l((float[]) o) : o instanceof double[] ? l((double[]) o) : o instanceof long[] ? l((long[]) o) : (Integer) call(o, "size");
  }

  static public int l(MultiSet ms) {
    return ms == null ? 0 : ms.size();
  }

  static public int l(IntRange r) {
    return r == null ? 0 : r.length();
  }

  static public long l(LongRange r) {
    return r == null ? 0 : r.length();
  }

  static public double l(DoubleRange r) {
    return r == null ? 0 : r.length();
  }

  static public int l(IntBuffer b) {
    return b == null ? 0 : b.size();
  }

  static public Object first(Object list) {
    return first((Iterable) list);
  }

  static public <A> A first(List<A> list) {
    return empty(list) ? null : list.get(0);
  }

  static public <A> A first(A[] bla) {
    return bla == null || bla.length == 0 ? null : bla[0];
  }

  static public <A, B> Pair<A, B> first(Map<A, B> map) {
    return mapEntryToPair(first(entrySet(map)));
  }

  static public <A, B> Pair<A, B> first(MultiMap<A, B> mm) {
    if (mm == null)
      return null;
    var e = first(mm.data.entrySet());
    if (e == null)
      return null;
    return pair(e.getKey(), first(e.getValue()));
  }

  static public <A> A first(IterableIterator<A> i) {
    return first((Iterator<A>) i);
  }

  static public <A> A first(Iterator<A> i) {
    return i == null || !i.hasNext() ? null : i.next();
  }

  static public <A> A first(Iterable<A> i) {
    if (i == null)
      return null;
    Iterator<A> it = i.iterator();
    return it.hasNext() ? it.next() : null;
  }

  static public Character first(String s) {
    return empty(s) ? null : s.charAt(0);
  }

  static public Character first(CharSequence s) {
    return empty(s) ? null : s.charAt(0);
  }

  static public <A, B> A first(Pair<A, B> p) {
    return p == null ? null : p.a;
  }

  static public <A, B, C> A first(T3<A, B, C> t) {
    return t == null ? null : t.a;
  }

  static public Byte first(byte[] l) {
    return empty(l) ? null : l[0];
  }

  static public int first(IntBuffer buf) {
    return buf.get(0);
  }

  static public <A> A first(A[] l, IF1<A, Boolean> pred) {
    return firstThat(l, pred);
  }

  static public <A> A first(Iterable<A> l, IF1<A, Boolean> pred) {
    return firstThat(l, pred);
  }

  static public <A> A first(IF1<A, Boolean> pred, Iterable<A> l) {
    return firstThat(pred, l);
  }

  static public <A extends Concept> A registerConcept(A c) {
    return registerConcept(db_mainConcepts(), c);
  }

  static public <A extends Concept> A registerConcept(Concepts cc, A c) {
    {
      if (cc != null)
        cc.register(c);
    }
    return c;
  }

  static public Thread startThread(Object runnable) {
    return startThread(defaultThreadName(), runnable);
  }

  static public Thread startThread(String name, Runnable runnable) {
    runnable = wrapAsActivity(runnable);
    return startThread(newThread(runnable, name));
  }

  static public Thread startThread(String name, Object runnable) {
    runnable = wrapAsActivity(runnable);
    return startThread(newThread(toRunnable(runnable), name));
  }

  static public Thread startThread(Thread t) {
    _registerThread(t);
    t.start();
    return t;
  }

  static public File myJar() {
    return first(myLibraryFiles());
  }

  static public void loadBinaryPageToFile(String url, File file) {
    try {
      print("Loading " + url);
      loadBinaryPageToFile(openConnection(new URL(url)), file);
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public void loadBinaryPageToFile(URLConnection con, File file) {
    try {
      setHeaders(con);
      loadBinaryPageToFile_noHeaders(con, file);
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public void loadBinaryPageToFile_noHeaders(URLConnection con, File file) {
    try {
      File ftemp = new File(f2s(file) + "_temp");
      FileOutputStream buf = newFileOutputStream(mkdirsFor(ftemp));
      try {
        InputStream inputStream = con.getInputStream();
        long len = 0;
        try {
          len = con.getContentLength();
        } catch (Throwable e) {
          printStackTrace(e);
        }
        String pat = "  {*}" + (len != 0 ? "/" + len : "") + " bytes loaded.";
        copyStreamWithPrints(inputStream, buf, pat);
        inputStream.close();
        buf.close();
        file.delete();
        renameFile_assertTrue(ftemp, file);
      } finally {
        if (buf != null)
          buf.close();
      }
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public boolean isFile(File f) {
    return f != null && f.isFile();
  }

  static public boolean isFile(String path) {
    return isFile(newFile(path));
  }

  static public File copyFile(File src, File dest) {
    try {
      FileInputStream inputStream = new FileInputStream(src.getPath());
      FileOutputStream outputStream = newFileOutputStream(dest.getPath());
      try {
        copyStream(inputStream, outputStream);
        inputStream.close();
      } finally {
        outputStream.close();
      }
      return dest;
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public String f2s(File f) {
    return f == null ? null : f.getAbsolutePath();
  }

  static public String f2s(String s) {
    return f2s(newFile(s));
  }

  static public String f2s(java.nio.file.Path p) {
    return p == null ? null : f2s(p.toFile());
  }

  static public String or2(String a, String b) {
    return nempty(a) ? a : b;
  }

  static public String or2(String a, String b, String c) {
    return or2(or2(a, b), c);
  }

  static public String currentProcessCommand() {
    ProcessHandle processHandle = ProcessHandle.current();
    return getVar(processHandle.info().command());
  }

  static public StefansOS_ConnectToServer snippetUpdateConnector(Object... __) {
    boolean verbose = boolPar("verbose", __);
    StefansOS_ConnectToServer connector = new StefansOS_ConnectToServer();
    connector.onLine = new VF1<String>() {

      public void get(String line) {
        try {
          Matches m = new Matches();
          if (startsWith(line, "snippetUpdates:", m)) {
            if (verbose)
              print(line);
            String msg = m.rest();
            vmBus_send("snippetUpdate", safeUnstruct(msg));
          }
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "new Matches m;\r\n    if (startsWith(line, \"snippetUpdates:\", m)) {\r\n      if (...";
      }
    };
    connector.startWithSubs("snippetUpdates");
    return connector;
  }

  static public <A> AutoCloseable vmBus_onMessage(String msg, IVF1<A> onMessage) {
    return vmBus_onMessage(msg, ivf1ToVF1(onMessage));
  }

  static public <A> AutoCloseable vmBus_onMessage(final String msg, final VF1<A> onMessage) {
    Map<String, Set> map = vm_busListenersByMessage_live();
    synchronized (map) {
      Set listeners = map.get(msg);
      if (listeners == null)
        map.put(msg, listeners = syncIdentityHashSet());
      return tempAdd(listeners, new VF2<String, Object>() {

        public void get(String _msg, Object arg) {
          try {
            callF(onMessage, arg);
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "callF(onMessage, arg)";
        }
      });
    }
  }

  static public <A, B> AutoCloseable vmBus_onMessage(String msg, final VF2<A, B> onMessage) {
    return vmBus_onMessage(msg, new VF1<Object[]>() {

      public void get(Object[] o) {
        try {
          callF(onMessage, first(o), second(o));
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "callF(onMessage, first(o), second(o));";
      }
    });
  }

  static public <A, B> AutoCloseable vmBus_onMessage(String msg, final IVF2<A, B> onMessage) {
    return vmBus_onMessage(msg, new VF1<Object[]>() {

      public void get(Object[] o) {
        try {
          callF(onMessage, first(o), second(o));
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "callF(onMessage, first(o), second(o));";
      }
    });
  }

  static public AutoCloseable vmBus_onMessage(String msg, Runnable onMessage) {
    return vmBus_onMessage(msg, runnableToVF1(onMessage));
  }

  static public String getString(Map map, Object key) {
    return map == null ? null : (String) map.get(key);
  }

  static public String getString(List l, int idx) {
    return (String) get(l, idx);
  }

  static public String getString(Object o, Object key) {
    if (o instanceof Map)
      return getString((Map) o, key);
    if (key instanceof String)
      return (String) getOpt(o, (String) key);
    throw fail("Not a string key: " + getClassName(key));
  }

  static public String getString(String key, Object o) {
    return getString(o, (Object) key);
  }

  static public boolean swic(String a, String b) {
    return startsWithIgnoreCase(a, b);
  }

  static public boolean swic(String a, String b, Matches m) {
    if (!swic(a, b))
      return false;
    m.m = new String[] { substring(a, l(b)) };
    return true;
  }

  static public boolean sameSnippetID(String a, String b) {
    if (!isSnippetID(a) || !isSnippetID(b))
      return false;
    return parseSnippetID(a) == parseSnippetID(b);
  }

  static public String programID() {
    return getProgramID();
  }

  static public String programID(Object o) {
    return getProgramID(o);
  }

  static public String firstIntAsString(String s) {
    return jextract("<int>", s);
  }

  static public long psI(String snippetID) {
    return parseSnippetID(snippetID);
  }

  static public void ping_v3_setPingSourceMaker(IF0<PingSource> pingMaker) {
    vm_generalMap_set("ping_v3_pingSourceMaker", pingMaker);
  }

  static public int findIntArg(String name, String[] args, int defaultValue) {
    int i = indexOfIC(args, name);
    return i >= 0 && i + 1 < l(args) ? parseInt(args[i + 1]) : defaultValue;
  }

  static public int cores() {
    return numberOfCores();
  }

  static public boolean ping() {
    return ping(pingSource());
  }

  static public boolean ping(PingSource source) {
    ping_v3(source);
    return true;
  }

  static public boolean ping_impl(boolean okInCleanUp) {
    return ping();
  }

  static volatile public boolean ping_pauseAll = false;

  static public int max(int a, int b) {
    return Math.max(a, b);
  }

  static public int max(int a, int b, int c) {
    return max(max(a, b), c);
  }

  static public long max(int a, long b) {
    return Math.max((long) a, b);
  }

  static public long max(long a, long b) {
    return Math.max(a, b);
  }

  static public double max(int a, double b) {
    return Math.max((double) a, b);
  }

  static public float max(float a, float b) {
    return Math.max(a, b);
  }

  static public double max(double a, double b) {
    return Math.max(a, b);
  }

  static public int max(Collection<Integer> c) {
    int x = Integer.MIN_VALUE;
    for (int i : c) x = max(x, i);
    return x;
  }

  static public 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 public 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 public byte max(byte[] c) {
    byte x = -128;
    for (byte d : c) if (d > x)
      x = d;
    return x;
  }

  static public short max(short[] c) {
    short x = -0x8000;
    for (short d : c) if (d > x)
      x = d;
    return x;
  }

  static public int max(int[] c) {
    int x = Integer.MIN_VALUE;
    for (int d : c) if (d > x)
      x = d;
    return x;
  }

  static public <A extends Comparable<A>> A max(A a, A b) {
    return cmp(a, b) >= 0 ? a : b;
  }

  static public int screenNrOfWindow(Window w) {
    if (w == null)
      return -1;
    Rect bounds = boundsAsRect(w);
    return indexOfMax(allScreenBounds(), screen -> area(intersectRects(bounds, screen)));
  }

  static public boolean cic(Collection<String> l, String s) {
    return containsIgnoreCase(l, s);
  }

  static public boolean cic(String[] l, String s) {
    return containsIgnoreCase(l, s);
  }

  static public boolean cic(String s, char c) {
    return containsIgnoreCase(s, c);
  }

  static public boolean cic(String a, String b) {
    return containsIgnoreCase(a, b);
  }

  static public File programDir_mine;

  static public File programDir() {
    return programDir(getProgramID());
  }

  static public File programDir(String snippetID) {
    boolean me = sameSnippetID(snippetID, programID());
    if (programDir_mine != null && me)
      return programDir_mine;
    File dir = new File(javaxDataDir(), formatSnippetIDOpt(snippetID));
    if (me) {
      String c = caseID();
      if (nempty(c))
        dir = newFile(dir, c);
    }
    return dir;
  }

  static public File programDir(String snippetID, String subPath) {
    return new File(programDir(snippetID), subPath);
  }

  static public void clearConceptsOf(String progID) {
    getProgramFile(progID, "concepts.structure").delete();
    getProgramFile(progID, "concepts.structure.gz").delete();
    getProgramFile(progID, "idCounter.structure").delete();
  }

  static public List syncMap(Object f, Map map) {
    return syncMap(map, f);
  }

  static public List syncMap(Map map, Object f) {
    return map(cloneLinkedHashMap(map), f);
  }

  static public <A, B> Map<A, B> syncMap() {
    return synchroHashMap();
  }

  static public <A, B> Map<A, B> syncMap(Map map) {
    return synchronizedMap(map);
  }

  static public Class __javax;

  static public Class getJavaX() {
    try {
      return __javax;
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public void __setJavaX(Class j) {
    __javax = j;
    _onJavaXSet();
  }

  static public boolean startsWith(String a, String b) {
    return a != null && a.startsWith(unnull(b));
  }

  static public boolean startsWith(String a, char c) {
    return nemptyString(a) && a.charAt(0) == c;
  }

  static public boolean startsWith(String a, String b, Matches m) {
    if (!startsWith(a, b))
      return false;
    if (m != null)
      m.m = new String[] { substring(a, strL(b)) };
    return true;
  }

  static public boolean startsWith(List a, List b) {
    if (a == null || listL(b) > listL(a))
      return false;
    for (int i = 0; i < listL(b); i++) if (neq(a.get(i), b.get(i)))
      return false;
    return true;
  }

  static public String substring(String s, int x) {
    return substring(s, x, strL(s));
  }

  static public String substring(String s, int x, int y) {
    if (s == null)
      return null;
    if (x < 0)
      x = 0;
    int n = s.length();
    if (y < x)
      y = x;
    if (y > n)
      y = n;
    if (x >= y)
      return "";
    return s.substring(x, y);
  }

  static public String substring(String s, IntRange r) {
    return r == null ? null : substring(s, r.start, r.end);
  }

  static public String substring(String s, CharSequence l) {
    return substring(s, lCharSequence(l));
  }

  static public void dm_watchFields(Collection<String> fields, Runnable onChange) {
    for (String field : unnullForIteration(fields)) dm_watchField(field, onChange);
  }

  static public <A extends IMeta> A setMetaSrcUnlessSame(Object b, A a, Object src) {
    if (a != b)
      setMeta(a, "src", src);
    return a;
  }

  static public BWImage posterizeBWImage(int brightnessLevels, BWImage img) {
    if (brightnessLevels >= 256 || img == null)
      return img;
    byte[] pixels = img.getBytes();
    int w = img.getWidth(), h = img.getHeight(), n = pixels.length;
    byte[] pixels2 = new byte[n];
    double factor1 = doubleRatio(brightnessLevels, 256);
    double factor2 = doubleRatio(255, brightnessLevels - 1);
    for (int i = 0; i < n; i++) pixels2[i] = (byte) iround(ifloor(ubyteToInt(pixels[i]) * factor1) * factor2);
    return new BWImage(w, h, pixels2);
  }

  static public BWImage scaledBWImageFromBWIntegralImage(int w, BWIntegralImage img) {
    return scaledBWImageFromBWIntegralImage(img, w);
  }

  static public BWImage scaledBWImageFromBWIntegralImage(BWIntegralImage img, int w) {
    return scaledBWImageFromBWIntegralImage(img, w, heightForWidth(img, w));
  }

  static public BWImage scaledBWImageFromBWIntegralImage(BWIntegralImage img, int w, int h) {
    byte[] pixels = scaledGrayBytesFromBWIntegralImage(img, w, h);
    return new BWImage(w, h, pixels);
  }

  static public BWImage scaledBWImageFromBWIntegralImage(int w, IBWIntegralImage img) {
    return scaledBWImageFromBWIntegralImage(img, w);
  }

  static public BWImage scaledBWImageFromBWIntegralImage(IBWIntegralImage img, int w) {
    return scaledBWImageFromBWIntegralImage(img, w, heightForWidth(img, w));
  }

  static public BWImage scaledBWImageFromBWIntegralImage(IBWIntegralImage img, int w, int h) {
    byte[] pixels = scaledGrayBytesFromBWIntegralImage(img, w, h);
    return new BWImage(w, h, pixels);
  }

  static public <A extends IMeta> A setMetaSrc(A a, Object src) {
    setMeta(a, "src", src);
    return a;
  }

  static public 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 public double msToSeconds(long ms) {
    return toSeconds(ms);
  }

  static public Point mouseLocation() {
    return getMouseLocation();
  }

  static public ImageSurface imageSurface(BufferedImage img) {
    return swingNu(ImageSurface.class, img);
  }

  static public ImageSurface imageSurface(MakesBufferedImage img) {
    return swingNu(ImageSurface.class, img);
  }

  static public ImageSurface imageSurface() {
    return swingNu(ImageSurface.class);
  }

  static public void imageSurface_pixelated(ImageSurface imageSurface) {
    if (imageSurface == null)
      return;
    imageSurface.setDoubleBuffered(true);
    imageSurface.noAlpha = true;
    imageSurface.interpolationMode = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
    repaint(imageSurface);
  }

  static public void imageSurface_pixelated(ImageSurface imageSurface, boolean pixelated) {
    if (pixelated)
      imageSurface_pixelated(imageSurface);
    else
      imageSurface_unpixelated(imageSurface);
  }

  static public BufferedImage toBufferedImage(Object o) {
    return toBufferedImageOpt(o);
  }

  static public void swingEvery(JComponent component, long delay, Object r) {
    installTimer(component, delay, r);
  }

  static public void swingEvery(JComponent component, long delay, long firstDelay, Object r) {
    installTimer(component, r, delay, firstDelay);
  }

  static public void swingEvery(RootPaneContainer frame, long delay, Object r) {
    installTimer(frame, delay, r);
  }

  static public void swingEvery(RootPaneContainer frame, long delay, long firstDelay, Object r) {
    installTimer(frame, delay, firstDelay, r);
  }

  static public <A> A swingNu(final Class<A> c, final Object... args) {
    return swingConstruct(c, args);
  }

  static public <A extends JComponent> A toolTipFromLiveValue(LiveValue lv, A c) {
    return bindToolTipToLiveValue(lv, c);
  }

  static public <A> LiveValue<A> dm_transientCalculatedLiveValue(Class type, IF0<A> calc) {
    return dm_transientCalculatedLiveValue(dm_current_mandatory(), type, calc);
  }

  static public <A> LiveValue<A> dm_transientCalculatedLiveValue(DynModule mod, Class type, IF0<A> calc) {
    Lock __0 = mod.lock;
    lock(__0);
    try {
      SimpleLiveValue value = new SimpleLiveValue(type, calc.get());
      mod.onFieldChange(new VF1<String>() {

        public void get(String field) {
          try {
            value.set(calc.get());
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "value.set(calc!)";
        }
      });
      return value;
    } finally {
      unlock(__0);
    }
  }

  static public LiveValue<Object> dm_transientCalculatedLiveValue(IF0<Object> calc) {
    return dm_transientCalculatedLiveValue(Object.class, calc);
  }

  static public <A extends JLabel> A setHorizontalAlignment(final int pos, final A a) {
    swingCall(a, "setHorizontalAlignment", pos);
    return a;
  }

  static public <A extends AbstractButton> A setHorizontalAlignment(final int pos, final A a) {
    swingCall(a, "setHorizontalAlignment", pos);
    return a;
  }

  static public <A extends JTextField> A setHorizontalAlignment(final int pos, final A a) {
    swingCall(a, "setHorizontalAlignment", pos);
    return a;
  }

  static public JTabbedPane jLeftOrTopTabs(boolean horizontal, Object... x) {
    return horizontal ? jLeftTabs(x) : jtabs(x);
  }

  static public JTabbedPane jLeftOrTopTabs(boolean horizontal, Collection c) {
    return horizontal ? jLeftTabs(c) : jtabs(c);
  }

  static public JPanel jRightAlignedButtons(Object... params) {
    List<JComponent> l = new ArrayList();
    for (int i = 0; i < l(params); i += 2) if (params[i] != null)
      if (params[i] instanceof JComponent)
        l.add((JComponent) params[i--]);
      else
        l.add(jbutton((String) params[i], params[i + 1]));
    return jRightAlignedLine(l);
  }

  static public JComponent wrap(Object swingable) {
    return _recordNewSwingComponent(wrap_2(swingable));
  }

  static public JComponent wrap_2(Object swingable) {
    if (swingable == null)
      return null;
    JComponent c;
    if (swingable instanceof Component)
      c = componentToJComponent((Component) swingable);
    else if (swingable instanceof Swingable)
      c = componentToJComponent(((Swingable) swingable).visualize());
    else
      c = componentToJComponent((Component) callOpt(swingable, "swing"));
    if (c instanceof JTable || c instanceof JList || c instanceof JTextArea || c instanceof JEditorPane || c instanceof JTextPane || c instanceof JTree)
      return jscroll(c);
    return c == null ? jlabel(str(swingable)) : c;
  }

  static public JPanel marginPanel() {
    return jtransparent(borderLayoutPanel());
  }

  static public <A extends JComponent> A setBorder(Border border, A c) {
    if (c != null) {
      swing(() -> {
        c.setBorder(border);
      });
    }
    return c;
  }

  static public JScrollPane withoutViewportBorder(JScrollPane sp) {
    if (sp != null) {
      swing(() -> {
        sp.setViewportBorder(null);
      });
    }
    return sp;
  }

  static public JPanel vstack2(final Object... parts) {
    return swing(new F0<JPanel>() {

      public JPanel get() {
        try {
          JPanel panel = new JPanel(new GridBagLayout());
          GridBagConstraints gbc = new GridBagConstraints();
          gbc.weightx = 1;
          gbc.fill = GridBagConstraints.HORIZONTAL;
          gbc.gridwidth = GridBagConstraints.REMAINDER;
          smartAddWithLayout(panel, gbc, parts);
          gbc.weighty = 1;
          panel.add(jrigid(), gbc);
          return panel;
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "JPanel panel = new JPanel(new GridBagLayout);\r\n    new GridBagConstraints gbc...";
      }
    });
  }

  static public JPanel smartAddWithLayout(JPanel panel, Object layout, List parts) {
    for (Object o : parts) panel.add(wrapForSmartAdd(o), layout);
    return panel;
  }

  static public JPanel smartAddWithLayout(JPanel panel, Object layout, Object... parts) {
    return smartAddWithLayout(panel, layout, asList(flattenArray2(parts)));
  }

  static public Component jrigid() {
    return javax.swing.Box.createRigidArea(new Dimension(0, 0));
  }

  static public JSpinner liveValueSpinner(SimpleLiveValue<Integer> lv, int min, int max) {
    JSpinner spinner = jSpinner(lv.get(), min, max);
    return bindLiveValueToSpinner(lv, spinner);
  }

  static public JSpinner bindLiveValueToSpinner(SimpleLiveValue<Integer> lv, JSpinner spinner) {
    onChange(spinner, new Runnable() {

      public void run() {
        try {
          lv.set(intFromSpinner(spinner));
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "lv.set(intFromSpinner(spinner))";
      }
    });
    lv.onChange(new Runnable() {

      public void run() {
        try {
          setSpinnerValue(spinner, lv.get());
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "setSpinnerValue(spinner, lv!)";
      }
    });
    return spinner;
  }

  static public <A> JSpinner jPowersOfTwoSpinner(int max, int defaultValue) {
    return rightAlignSpinner(jListSpinner(powersOfTwoUpTo(max), defaultValue));
  }

  static public List<JButton> allButtons(Component c) {
    return childrenOfType(c, JButton.class);
  }

  static public <A extends AbstractButton> A setHorizontalMargin(final int margin, final A a) {
    {
      swing(() -> {
        Insets i = a.getMargin();
        a.setMargin(new Insets(i.top, margin, i.bottom, margin));
      });
    }
    return a;
  }

  static public <A extends AbstractButton> A setHorizontalMargin(A a, int margin) {
    return setHorizontalMargin(margin, a);
  }

  static public String formatWithThousands(long l) {
    return formatWithThousandsSeparator(l);
  }

  static public boolean empty(Collection c) {
    return c == null || c.isEmpty();
  }

  static public boolean empty(Iterable c) {
    return c == null || !c.iterator().hasNext();
  }

  static public boolean empty(CharSequence s) {
    return s == null || s.length() == 0;
  }

  static public boolean empty(Map map) {
    return map == null || map.isEmpty();
  }

  static public boolean empty(Object[] o) {
    return o == null || o.length == 0;
  }

  static public boolean empty(BitSet bs) {
    return bs == null || bs.isEmpty();
  }

  static public 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 public boolean empty(Iterator i) {
    return i == null || !i.hasNext();
  }

  static public boolean empty(double[] a) {
    return a == null || a.length == 0;
  }

  static public boolean empty(float[] a) {
    return a == null || a.length == 0;
  }

  static public boolean empty(int[] a) {
    return a == null || a.length == 0;
  }

  static public boolean empty(long[] a) {
    return a == null || a.length == 0;
  }

  static public boolean empty(byte[] a) {
    return a == null || a.length == 0;
  }

  static public boolean empty(short[] a) {
    return a == null || a.length == 0;
  }

  static public boolean empty(MultiSet ms) {
    return ms == null || ms.isEmpty();
  }

  static public boolean empty(MultiMap mm) {
    return mm == null || mm.isEmpty();
  }

  static public boolean empty(File f) {
    return getFileSize(f) == 0;
  }

  static public boolean empty(IntRange r) {
    return r == null || r.empty();
  }

  static public boolean empty(DoubleRange r) {
    return r == null || r.isEmpty();
  }

  static public boolean empty(IntBuffer b) {
    return b == null || b.isEmpty();
  }

  static public boolean empty(Rect r) {
    return !(r != null && r.w != 0 && r.h != 0);
  }

  static public String str(Object o) {
    return o == null ? "null" : o.toString();
  }

  static public String str(char[] c) {
    return new String(c);
  }

  static public double fraction(double d) {
    return d % 1;
  }

  static public String n_fancy2(long l, String singular, String plural) {
    return formatWithThousandsSeparator(l) + " " + trim(l == 1 ? singular : plural);
  }

  static public String n_fancy2(Collection l, String singular, String plural) {
    return n_fancy2(l(l), singular, plural);
  }

  static public String n_fancy2(Map m, String singular, String plural) {
    return n_fancy2(l(m), singular, plural);
  }

  static public String n_fancy2(Object[] a, String singular, String plural) {
    return n_fancy2(l(a), singular, plural);
  }

  static public String n_fancy2(MultiSet ms, String singular, String plural) {
    return n_fancy2(l(ms), singular, plural);
  }

  static public Pair<JTabbedPane, Integer> enclosingTab(Component _c) {
    return swing(() -> {
      Component c = _c;
      while (c != null) {
        Container p = c.getParent();
        if (p instanceof JTabbedPane)
          return pair(((JTabbedPane) p), ((JTabbedPane) p).indexOfComponent(c));
        c = c.getParent();
      }
      return null;
    });
  }

  static public void setTabTitle(JTabbedPane tabs, int idx, String title) {
    if (tabs != null && idx >= 0) {
      swing(() -> {
        if (idx < tabs.getTabCount())
          tabs.setTitleAt(idx, title);
      });
    }
  }

  static public String fromLines(Iterable lines) {
    StringBuilder buf = new StringBuilder();
    if (lines != null)
      for (Object line : lines) buf.append(str(line)).append('\n');
    return buf.toString();
  }

  static public String fromLines(String... lines) {
    return fromLines(asList(lines));
  }

  static public <A> ArrayList<A> asList(A[] a) {
    return a == null ? new ArrayList<A>() : new ArrayList<A>(Arrays.asList(a));
  }

  static public ArrayList<Integer> asList(int[] a) {
    if (a == null)
      return null;
    ArrayList<Integer> l = emptyList(a.length);
    for (int i : a) l.add(i);
    return l;
  }

  static public ArrayList<Long> asList(long[] a) {
    if (a == null)
      return null;
    ArrayList<Long> l = emptyList(a.length);
    for (long i : a) l.add(i);
    return l;
  }

  static public ArrayList<Float> asList(float[] a) {
    if (a == null)
      return null;
    ArrayList<Float> l = emptyList(a.length);
    for (float i : a) l.add(i);
    return l;
  }

  static public ArrayList<Double> asList(double[] a) {
    if (a == null)
      return null;
    ArrayList<Double> l = emptyList(a.length);
    for (double i : a) l.add(i);
    return l;
  }

  static public ArrayList<Short> asList(short[] a) {
    if (a == null)
      return null;
    ArrayList<Short> l = emptyList(a.length);
    for (short i : a) l.add(i);
    return l;
  }

  static public <A> ArrayList<A> asList(Iterator<A> it) {
    ArrayList l = new ArrayList();
    if (it != null)
      while (it.hasNext()) l.add(it.next());
    return l;
  }

  static public <A> ArrayList<A> asList(IterableIterator<A> s) {
    return asList((Iterator) s);
  }

  static public <A> ArrayList<A> asList(Iterable<A> s) {
    if (s instanceof ArrayList)
      return (ArrayList) s;
    ArrayList l = new ArrayList();
    if (s != null)
      for (A a : s) l.add(a);
    return l;
  }

  static public <A> ArrayList<A> asList(Producer<A> p) {
    ArrayList l = new ArrayList();
    A a;
    if (p != null)
      while ((a = p.next()) != null) l.add(a);
    return l;
  }

  static public <A> ArrayList<A> asList(Enumeration<A> e) {
    ArrayList l = new ArrayList();
    if (e != null)
      while (e.hasMoreElements()) l.add(e.nextElement());
    return l;
  }

  static public <A> List<A> asList(Pair<A, A> p) {
    return p == null ? null : ll(p.a, p.b);
  }

  static public IterableIterator<String> toLines(File f) {
    return linesFromFile(f);
  }

  static public List<String> toLines(String s) {
    List<String> lines = new ArrayList<String>();
    if (s == null)
      return lines;
    int start = 0;
    while (true) {
      int i = toLines_nextLineBreak(s, start);
      if (i < 0) {
        if (s.length() > start)
          lines.add(s.substring(start));
        break;
      }
      lines.add(s.substring(start, i));
      if (s.charAt(i) == '\r' && i + 1 < s.length() && s.charAt(i + 1) == '\n')
        i += 2;
      else
        ++i;
      start = i;
    }
    return lines;
  }

  static public int toLines_nextLineBreak(String s, int start) {
    int n = s.length();
    for (int i = start; i < n; i++) {
      char c = s.charAt(i);
      if (c == '\r' || c == '\n')
        return i;
    }
    return -1;
  }

  static public List<String> mapToLines(Map map) {
    List<String> l = new ArrayList();
    for (Object key : keys(map)) l.add(str(key) + " = " + str(map.get(key)));
    return l;
  }

  static public String mapToLines(Map map, Object f) {
    return lines(map(map, f));
  }

  static public String mapToLines(Object f, Map map) {
    return lines(map(map, f));
  }

  static public String mapToLines(Object f, Iterable l) {
    return lines(map(f, l));
  }

  static public <A> String mapToLines(Iterable<A> l, IF1<A, String> f) {
    return mapToLines((Object) f, l);
  }

  static public <A> String mapToLines(IF1<A, String> f, Iterable<A> l) {
    return mapToLines((Object) f, l);
  }

  static public <A, B> String mapToLines(Map<A, B> map, IF2<A, B, String> f) {
    return lines(map(map, f));
  }

  static public <A> String mapToLines(IF1<A, String> f, A data1, A... moreData) {
    return lines(map(f, data1, moreData));
  }

  static public List<String> sortedIgnoreCase(Collection<String> c) {
    List<String> l = cloneList(c);
    Collections.sort(l, caseInsensitiveComparator());
    return l;
  }

  static public ArrayList emptyList() {
    return new ArrayList();
  }

  static public ArrayList emptyList(int capacity) {
    return new ArrayList(max(0, capacity));
  }

  static public ArrayList emptyList(Iterable l) {
    return l instanceof Collection ? emptyList(((Collection) l).size()) : emptyList();
  }

  static public ArrayList emptyList(Object[] l) {
    return emptyList(l(l));
  }

  static public <A> ArrayList<A> emptyList(Class<A> c) {
    return new ArrayList();
  }

  static public double nanosToMicroseconds(double ns) {
    return ns / 1000;
  }

  static public boolean isComponentShowing(final Component c) {
    return c != null && swing(new F0<Boolean>() {

      public Boolean get() {
        try {
          return c.isShowing();
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret c.isShowing();";
      }
    });
  }

  static public BufferedImage newBufferedImage(int w, int h) {
    return new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
  }

  static public BufferedImage newBufferedImage(int w, int h, RGB rgb) {
    return newBufferedImage(w, h, rgb.getColor());
  }

  static public BufferedImage newBufferedImage(int w, int h, Color color) {
    BufferedImage img = newBufferedImage(w, h);
    Graphics2D g = img.createGraphics();
    g.setColor(or(color, Color.white));
    g.fillRect(0, 0, w, h);
    return img;
  }

  static public BufferedImage newBufferedImage(Pt p, Color color) {
    return newBufferedImage(p.x, p.y, color);
  }

  static public BufferedImage newBufferedImage(int w, int h, int[] pixels) {
    return intArrayToBufferedImage(pixels, w, h);
  }

  static public <A, B> Map<A, B> synchroIdentityHashMap() {
    return synchroMap(new IdentityHashMap());
  }

  static public <A, B> void mapPut2(Map<A, B> map, A key, B value) {
    if (map != null && key != null)
      if (value != null)
        map.put(key, value);
      else
        map.remove(key);
  }

  static public BWIntegralImage bwIntegralImage(BufferedImage img) {
    return img == null ? null : new BWIntegralImage(img);
  }

  static public BWIntegralImage bwIntegralImage(BWImage img) {
    return img == null ? null : new BWIntegralImage(img);
  }

  static public <A> List<A> nonNulls(Iterable<A> l) {
    return withoutNulls(l);
  }

  static public <A> List<A> nonNulls(A[] l) {
    return withoutNulls(l);
  }

  static public <A, B> Map<A, B> nonNulls(Map<A, B> map) {
    return withoutNulls(map);
  }

  static public JComboBox jcombobox(final String... items) {
    return swing(new F0<JComboBox>() {

      public JComboBox get() {
        try {
          return new JComboBox(items);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret new JComboBox(items);";
      }
    });
  }

  static public JComboBox jcombobox(Collection<String> items) {
    return jcombobox(toStringArray(items));
  }

  static public JComboBox jcombobox(Collection<String> items, String selectedItem) {
    return selectItem(selectedItem, jcombobox(items));
  }

  static public void selectRow(final JTable table, final int i) {
    if (table != null) {
      swing(() -> {
        if (i >= 0 && i < table.getRowCount()) {
          table.setRowSelectionInterval(i, i);
          scrollRowToVisible(table, i);
        } else
          table.clearSelection();
      });
    }
  }

  static public void selectRow(final JList list, final int i) {
    if (list != null) {
      swing(() -> {
        if (i >= 0 && i < listRowCount(list))
          list.setSelectedIndex(i);
        else
          list.clearSelection();
      });
    }
  }

  static public <A> int jlist_indexOf(JList<A> list, A item) {
    return swing(new F0<Integer>() {

      public Integer get() {
        try {
          ListModel<A> model = list.getModel();
          int n = model.getSize();
          for (int i = 0; i < n; i++) if (eq(model.getElementAt(i), item))
            return i;
          return -1;
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ListModel<A> model = list.getModel();\r\n    int n = model.getSize();\r\n    for ...";
      }
    });
  }

  static public void swingAndWait(Runnable r) {
    try {
      if (isAWTThread())
        r.run();
      else
        EventQueue.invokeAndWait(addThreadInfoToRunnable(r));
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public 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 public List<Integer> countIteratorToList_inclusive(int b) {
    return countIteratorToList_inclusive(0, b);
  }

  static public List<Integer> countIteratorToList_inclusive(int a, int b) {
    return asList(countIterator_inclusive(a, b));
  }

  static public <A> List<A> countIteratorToList_inclusive(int b, IF1<Integer, A> f) {
    return countIteratorToList_inclusive(0, b, f);
  }

  static public <A> List<A> countIteratorToList_inclusive(int a, int b, IF1<Integer, A> f) {
    return asList(countIterator_inclusive(a, b, f));
  }

  static public List<Integer> countIteratorToList_inclusive(int a, int b, int step) {
    return asList(countIterator_inclusive_step(a, b, step));
  }

  static public <A> List<A> countIteratorToList_inclusive(double a, double b, double step, IF1<Double, A> f) {
    return asList(countIterator_inclusive(a, b, step, f));
  }

  static public <A> List<Double> countIteratorToList_inclusive(double a, double b, double step) {
    return asList(countIterator_inclusive_step(a, b, step));
  }

  static public <A> List<A> countIteratorToList_inclusive(IF1<Double, A> f, double a, double b, double step) {
    return asList(countIterator_inclusive_step(a, b, step, f));
  }

  static public <A> List<A> countIteratorToList_inclusive(IF1<Integer, A> f, int a, int b) {
    return countIteratorToList_inclusive(f, a, b, 1);
  }

  static public <A> List<A> countIteratorToList_inclusive(IF1<Integer, A> f, int a, int b, int step) {
    return asList(countIterator_inclusive(a, b, step, f));
  }

  static public Object pcallF(Object f, Object... args) {
    return pcallFunction(f, args);
  }

  static public <A> A pcallF(F0<A> f) {
    try {
      return f == null ? null : f.get();
    } catch (Throwable __e) {
      return null;
    }
  }

  static public <A, B> B pcallF(F1<A, B> f, A a) {
    try {
      return f == null ? null : f.get(a);
    } catch (Throwable __e) {
      return null;
    }
  }

  static public <A> void pcallF(VF1<A> f, A a) {
    try {
      {
        if (f != null)
          f.get(a);
      }
    } catch (Throwable __e) {
      printStackTrace(__e);
    }
  }

  static public Object pcallF(Runnable r) {
    try {
      {
        if (r != null)
          r.run();
      }
      return null;
    } catch (Throwable __e) {
      return null;
    }
  }

  static public <A> A pcallF(IF0<A> f) {
    try {
      return f == null ? null : f.get();
    } catch (Throwable __e) {
      return null;
    }
  }

  static public <A, B> B pcallF(IF1<A, B> f, A a) {
    try {
      return f == null ? null : f.get(a);
    } catch (Throwable __e) {
      return null;
    }
  }

  static public boolean isMainProgram() {
    return creator() == null;
  }

  static public void deleteConcepts(Collection conceptsOrIDs) {
    db_mainConcepts().deleteConcepts(asList(conceptsOrIDs));
  }

  static public <A extends Concept> List<A> deleteConcepts(Class<A> c, Object... params) {
    return deleteConcepts(db_mainConcepts(), c, params);
  }

  static public <A extends Concept> List<A> deleteConcepts(Concepts cc, Class<A> c, Object... params) {
    List<A> l = asList(findConceptsWhere(cc, c, params));
    deleteConcepts(l);
    return l;
  }

  static public <A extends Concept> void deleteConcepts(Class<A> c, IF1<A, Boolean> pred) {
    deleteConcepts(db_mainConcepts(), c, pred);
  }

  static public <A extends Concept> void deleteConcepts(Concepts cc, Class<A> c, IF1<A, Boolean> pred) {
    deleteConcepts(filter(list(cc, c), pred));
  }

  static public List<Concept> deleteConcepts(Concepts cc) {
    return deleteConcepts(cc, Concept.class);
  }

  static public void deleteConcept(long id) {
    db_mainConcepts().deleteConcept(id);
  }

  static public void deleteConcept(Concepts concepts, long id) {
    concepts.deleteConcept(id);
  }

  static public void deleteConcept(Concept c) {
    if (c != null)
      c.delete();
  }

  static public void deleteConcept(Concept.Ref ref) {
    if (ref != null)
      deleteConcept(ref.get());
  }

  static public <A> ArrayList<A> cloneList(Iterable<A> l) {
    return l instanceof Collection ? cloneList((Collection) l) : asList(l);
  }

  static public <A> ArrayList<A> cloneList(Collection<A> l) {
    if (l == null)
      return new ArrayList();
    synchronized (collectionMutex(l)) {
      return new ArrayList<A>(l);
    }
  }

  static public <A extends JComponent> A onFirstComponentShow(final A component, final Runnable onShow) {
    {
      swing(() -> {
        component.addAncestorListener(new AncestorListener() {

          public void ancestorAdded(AncestorEvent event) {
            component.removeAncestorListener(this);
            pcallF(onShow);
          }

          public void ancestorRemoved(AncestorEvent event) {
          }

          public void ancestorMoved(AncestorEvent event) {
          }
        });
      });
    }
    return component;
  }

  static public boolean confirmOKCancel(final Component owner, final String msg) {
    return isTrue(swingAndWait(new F0<Object>() {

      public Object get() {
        try {
          return JOptionPane.showConfirmDialog(owner, msg, "JavaX", JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION;
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret JOptionPane.showConfirmDialog(owner,\r\n      msg, \"JavaX\", JOptionPane.OK_...";
      }
    }));
  }

  static public boolean confirmOKCancel(String msg) {
    return confirmOKCancel(null, msg);
  }

  static volatile public boolean sleep_noSleep = false;

  static public void sleep(long ms) {
    ping();
    if (ms < 0)
      return;
    if (isAWTThread() && ms > 100)
      throw fail("Should not sleep on AWT thread");
    try {
      Thread.sleep(ms);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  static public void sleep() {
    try {
      if (sleep_noSleep)
        throw fail("nosleep");
      print("Sleeping.");
      sleepQuietly();
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public Object callOptWithEnter(Object o, String method, String[] arg) {
    return callOptWithEnter(o, method, new Object[] { arg });
  }

  static public Object callOptWithEnter(Object o, String method, Object... args) {
    if (o == null)
      return null;
    AutoCloseable __1 = tempEnter(o);
    try {
      return callOpt_withVarargs(o, method, args);
    } finally {
      _close(__1);
    }
  }

  static public <A extends Concept> A cDeref(Concept.Ref<A> ref) {
    return ref == null ? null : ref.get();
  }

  static public JLabel jcenteredLabel(String text) {
    return setHorizontalAlignment(JLabel.CENTER, jLabel(text));
  }

  static public JLabel jcenteredLabel() {
    return jcenteredLabel(" ");
  }

  static public boolean nempty(Collection c) {
    return !empty(c);
  }

  static public boolean nempty(CharSequence s) {
    return !empty(s);
  }

  static public boolean nempty(Object[] o) {
    return !empty(o);
  }

  static public boolean nempty(byte[] o) {
    return !empty(o);
  }

  static public boolean nempty(int[] o) {
    return !empty(o);
  }

  static public boolean nempty(BitSet bs) {
    return !empty(bs);
  }

  static public boolean nempty(Map m) {
    return !empty(m);
  }

  static public boolean nempty(Iterator i) {
    return i != null && i.hasNext();
  }

  static public boolean nempty(MultiMap mm) {
    return mm != null && !mm.isEmpty();
  }

  static public boolean nempty(Object o) {
    return !empty(o);
  }

  static public boolean nempty(IntRange r) {
    return !empty(r);
  }

  static public boolean nempty(IntBuffer b) {
    return b != null && !b.isEmpty();
  }

  static public boolean nempty(Rect r) {
    return r != null && r.w != 0 && r.h != 0;
  }

  static public boolean nempty(MultiSet ms) {
    return ms != null && !ms.isEmpty();
  }

  static volatile public boolean muricaPassword_pretendNotAuthed = false;

  static public String muricaPassword() {
    if (muricaPassword_pretendNotAuthed)
      return null;
    return trim(loadTextFile(muricaPasswordFile()));
  }

  static public List<Component> getSwingChildren(Component c) {
    if (c instanceof Container)
      return asList(((Container) c).getComponents());
    return emptyList();
  }

  static public JLabel jImage(Image img) {
    return jimage(img);
  }

  static public JLabel jImage(String imageID) {
    return jimage(imageID);
  }

  static public BufferedImage resizeImageToHeight_bilinear(BufferedImage img, int newH) {
    return scaleImage_bilinear(doubleRatio(newH, img.getHeight()), img);
  }

  static public BufferedImage loadImage2(String snippetIDOrURL) {
    return loadBufferedImage(snippetIDOrURL);
  }

  static public BufferedImage loadImage2(File file) {
    return loadBufferedImage(file);
  }

  static public int imageIcon_cacheSize = 10;

  static public boolean imageIcon_verbose = false;

  static public Map<String, ImageIcon> imageIcon_cache;

  static public Lock imageIcon_lock = lock();

  static public ThreadLocal<Boolean> imageIcon_fixGIF = new ThreadLocal();

  static public 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);
        imageIcon_cache.put(imageID, ii);
        return ii;
      } finally {
        unlock(__0);
      }
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public ImageIcon imageIcon(File f) {
    try {
      return new ImageIcon(f.toURI().toURL());
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public ImageIcon imageIcon(Image img) {
    return new ImageIcon(img);
  }

  static public ImageIcon imageIcon(RGBImage img) {
    return imageIcon(img.getBufferedImage());
  }

  static public JButton setButtonImage(BufferedImage img, JButton btn) {
    btn.setIcon(imageIcon(img));
    return btn;
  }

  static public JButton setButtonImage(JButton btn, BufferedImage img) {
    return setButtonImage(img, btn);
  }

  static public <A extends JComponent> A setToolTip(A c, Object toolTip) {
    return setToolTipText(c, toolTip);
  }

  static public <A extends JComponent> A setToolTip(Object toolTip, A c) {
    return setToolTipText(c, toolTip);
  }

  static public void setToolTip(TrayIcon trayIcon, String toolTip) {
    setTrayIconToolTip(trayIcon, toolTip);
  }

  static public BufferedImage resizeImage(BufferedImage img, int newW, int newH) {
    return resizeImage(img, newW, newH, Image.SCALE_SMOOTH);
  }

  static public BufferedImage resizeImage(BufferedImage img, int newW, int newH, int scaleType) {
    if (newW == img.getWidth() && newH == img.getHeight())
      return img;
    Image tmp = img.getScaledInstance(newW, newH, scaleType);
    BufferedImage dimg = new BufferedImage(newW, newH, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2d = dimg.createGraphics();
    g2d.drawImage(tmp, 0, 0, null);
    g2d.dispose();
    return dimg;
  }

  static public BufferedImage resizeImage(BufferedImage img, int newW) {
    int newH = iround(img.getHeight() * (double) newW / img.getWidth());
    return resizeImage(img, newW, newH);
  }

  static public BufferedImage resizeImage(int newW, BufferedImage img) {
    return resizeImage(img, newW);
  }

  static public void disableButtonWhileCalcing2(final Object f) {
    final JButton button = heldInstance(JButton.class);
    disableButton(button);
    {
      startThread(new Runnable() {

        public void run() {
          try {
            try {
              boolean ok = isTrue(callF(f));
              if (ok)
                disposePossiblyInternalFrame(button);
            } finally {
              enableButton(button);
            }
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "try {\r\n      boolean ok = isTrue(callF(f));\r\n      if (ok) disposePossiblyInt...";
        }
      });
    }
  }

  static public Pair<Boolean, String> transpileOnBestServer(String snippetID, String mode) {
    try {
      return haveMuricaPassword() ? transpileOnNewServer(snippetID, mode) : transpileOnServer(snippetID, mode);
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public Pair<Boolean, String> transpileOnBestServer(String snippetID) {
    return transpileOnBestServer(snippetID, "quick");
  }

  static public void callFInNewThread(Object f, Object... args) {
    callF_thread(f, args);
  }

  static public boolean scrollAllTheWayDown_bruteForce = true;

  static public <A extends JComponent> A scrollAllTheWayDown(A c) {
    if (c != null) {
      swing(() -> {
        int h = c.getHeight() - 1;
        if (scrollAllTheWayDown_bruteForce)
          h = max(h, 100000);
        c.scrollRectToVisible(new Rectangle(0, h, 1, 1));
      });
    }
    return c;
  }

  static public void addButtonsToWindow(Component c, Object... buttonParams) {
    addToWindowWithMargin(c, jcenteredbuttons(buttonParams));
  }

  static public <A> A nu(Class<A> c, Object... values) {
    A a = nuObject(c);
    setAll(a, values);
    return a;
  }

  static public Object[] paramsPlus(Object[] a1, Object... a2) {
    if (a2 == null)
      return a1;
    if (a1 == null)
      return a2;
    if (l(a1) == 1 && a1[0] instanceof Map)
      return new Object[] { mapPlus((Map) a1[0], a2) };
    assertEvenLength(a1);
    assertEvenLength(a2);
    Map map = paramsToOrderedMap(a1);
    int n = l(a2);
    for (int i = 0; i < n; i += 2) {
      Object key = a2[i];
      if (key != null)
        map.put(key, a2[i + 1]);
    }
    return mapToParams(map);
  }

  static public Object[] paramsPlus(Map a1, Object... a2) {
    return paramsPlus(new Object[] { a1 }, a2);
  }

  static public Rectangle maximumWindowBounds() {
    return maxWindowBounds();
  }

  static volatile public boolean licensed_yes = true;

  static public boolean licensed() {
    if (!licensed_yes)
      return false;
    ping_okInCleanUp();
    return true;
  }

  static public void licensed_off() {
    licensed_yes = false;
  }

  static public String prependColonSpaceIfNempty(String s) {
    return empty(s) ? "" : ": " + s;
  }

  static public String getStackTrace(Throwable throwable) {
    lastException(throwable);
    return getStackTrace_noRecord(throwable);
  }

  static public String getStackTrace_noRecord(Throwable throwable) {
    StringWriter writer = new StringWriter();
    throwable.printStackTrace(new PrintWriter(writer));
    return hideCredentials(writer.toString());
  }

  static public String getStackTrace() {
    return getStackTrace_noRecord(new Throwable());
  }

  static public String getStackTrace(String msg) {
    return getStackTrace_noRecord(new Throwable(msg));
  }

  static public <A extends Component> A revalidate(final A c) {
    if (c == null || !c.isShowing())
      return c;
    {
      swing(() -> {
        c.revalidate();
        c.repaint();
      });
    }
    return c;
  }

  static public void revalidate(JFrame f) {
    revalidate((Component) f);
  }

  static public void revalidate(JInternalFrame f) {
    revalidate((Component) f);
  }

  static public int getWidth(Component c) {
    return c == null ? 0 : (int) swingCall(c, "getWidth");
  }

  static public int getHeight(Component c) {
    return c == null ? 0 : (int) swingCall(c, "getHeight");
  }

  static public void vmBus_send(String msg, Object... args) {
    Object arg = vmBus_wrapArgs(args);
    pcallFAll_minimalExceptionHandling(vm_busListeners_live(), msg, arg);
    pcallFAll_minimalExceptionHandling(vm_busListenersByMessage_live().get(msg), msg, arg);
  }

  static public void vmBus_send(String msg) {
    vmBus_send(msg, (Object) null);
  }

  static public <A> A assertNempty(A a) {
    return assertNempty("empty", a);
  }

  static public <A> A assertNempty(String msg, A a) {
    if (empty(a))
      throw fail(msg + ": " + a);
    return a;
  }

  static public File imagesDir() {
    return userDir_oneOf_createIfNone("Pictures", "OneDrive/Pictures", "OneDrive/Bilder", "Pictures", "Bilder");
  }

  static public File imagesDir(String sub) {
    return newFile(imagesDir(), sub);
  }

  static public boolean isImageFileName(String s) {
    return eqicOneOf(fileExtension(s), ".png", ".jpg", ".jpeg", ".gif");
  }

  static public File makeFileNameUnique_beforeExtension_startWith1_noDot(File f) {
    File orig = f;
    int n = 1;
    do {
      f = appendToFileBaseName(orig, str(n++));
    } while (f.exists());
    return f;
  }

  static public File newFile(File base, String... names) {
    for (String name : names) base = new File(base, name);
    return base;
  }

  static public File newFile(String name) {
    return name == null ? null : new File(name);
  }

  static public File newFile(String base, String... names) {
    return newFile(newFile(base), names);
  }

  static public void saveImage(File f, BufferedImage img) {
    if (hasJPEGExtension(f))
      saveJPG(f, img);
    else
      savePNG(f, img);
  }

  static public String appendBracketed(Object o) {
    String b = strOrNull(o);
    return empty(b) ? "" : "" + " (" + b + ")";
  }

  static public String appendBracketed(String a, String b) {
    return a + appendBracketed(b);
  }

  static public String fileInfo(File f) {
    return renderFileInfo(f);
  }

  static public String fileInfo(String f) {
    return renderFileInfo(newFile(f));
  }

  static public byte[] bytesFromHex(String s) {
    return hexToBytes(s);
  }

  static public String dropPrefix(String prefix, String s) {
    return s == null ? null : s.startsWith(prefix) ? s.substring(l(prefix)) : s;
  }

  static public int ubyteToInt(byte b) {
    return b & 0x0FF;
  }

  static public int ubyteToInt(char c) {
    return c & 0x0FF;
  }

  static volatile public PersistableThrowable lastException_lastException;

  static public PersistableThrowable lastException() {
    return lastException_lastException;
  }

  static public void lastException(Throwable e) {
    lastException_lastException = persistableThrowable(e);
  }

  static public Throwable getInnerException(Throwable e) {
    if (e == null)
      return null;
    while (e.getCause() != null) e = e.getCause();
    return e;
  }

  static public Throwable getInnerException(Runnable r) {
    return getInnerException(getException(r));
  }

  static public String hideCredentials(URL url) {
    return url == null ? null : hideCredentials(str(url));
  }

  static public String hideCredentials(String url) {
    try {
      if (startsWithOneOf(url, "http://", "https://") && isAGIBlueDomain(hostNameFromURL(url)))
        return url;
    } catch (Throwable e) {
      print("HideCredentials", e);
    }
    return url.replaceAll("([&?])(_pass|key|cookie)=[^&\\s\"]*", "$1$2=<hidden>");
  }

  static public String hideCredentials(Object o) {
    return hideCredentials(str(o));
  }

  static public String unnull(String s) {
    return s == null ? "" : s;
  }

  static public <A> Collection<A> unnull(Collection<A> l) {
    return l == null ? emptyList() : l;
  }

  static public <A> List<A> unnull(List<A> l) {
    return l == null ? emptyList() : l;
  }

  static public int[] unnull(int[] l) {
    return l == null ? emptyIntArray() : l;
  }

  static public char[] unnull(char[] l) {
    return l == null ? emptyCharArray() : l;
  }

  static public double[] unnull(double[] l) {
    return l == null ? emptyDoubleArray() : l;
  }

  static public <A, B> Map<A, B> unnull(Map<A, B> l) {
    return l == null ? emptyMap() : l;
  }

  static public <A> Iterable<A> unnull(Iterable<A> i) {
    return i == null ? emptyList() : i;
  }

  static public <A> A[] unnull(A[] a) {
    return a == null ? (A[]) emptyObjectArray() : a;
  }

  static public BitSet unnull(BitSet b) {
    return b == null ? new BitSet() : b;
  }

  static public Pt unnull(Pt p) {
    return p == null ? new Pt() : p;
  }

  static public <A, B> Pair<A, B> unnull(Pair<A, B> p) {
    return p != null ? p : new Pair(null, null);
  }

  static public int unnull(Integer i) {
    return i == null ? 0 : i;
  }

  static public long unnull(Long l) {
    return l == null ? 0L : l;
  }

  static public double unnull(Double l) {
    return l == null ? 0.0 : l;
  }

  static public String baseClassName(String className) {
    return substring(className, className.lastIndexOf('.') + 1);
  }

  static public String baseClassName(Object o) {
    return baseClassName(getClassName(o));
  }

  static public String prependIfNempty(String prefix, String s) {
    return empty(s) ? unnull(s) : prefix + s;
  }

  static public void removeTrayIcon(final TrayIcon t) {
    if (t != null) {
      swing(() -> {
        SystemTray.getSystemTray().remove(t);
      });
    }
  }

  static public JFastLogView_noWrap jFastLogView_noWrap() {
    return jFastLogView_noWrap("");
  }

  static public JFastLogView_noWrap jFastLogView_noWrap(String text) {
    return withTypeWriterFont(swingNu(JFastLogView_noWrap.class, text));
  }

  static public JScrollPane jscroll_copyBackground(Component c) {
    return setScrollPaneBackground(getBackground(c), jscroll(c));
  }

  static public String stackTraceToString(StackTraceElement[] st) {
    return lines(st);
  }

  static public String stackTraceToString(Throwable e) {
    return getStackTrace_noRecord(e);
  }

  static public boolean eq(Object a, Object b) {
    return a == b || a != null && b != null && a.equals(b);
  }

  static public <A, B> B mapPutOrRemove(Map<A, B> map, A key, B value) {
    if (map != null && key != null)
      if (value != null)
        return map.put(key, value);
      else
        return map.remove(key);
    return null;
  }

  static public Map vm_generalMap_map;

  static public Map vm_generalMap() {
    if (vm_generalMap_map == null)
      vm_generalMap_map = (Map) get(javax(), "generalMap");
    return vm_generalMap_map;
  }

  static public String mcName() {
    return mc().getName();
  }

  static public String getClassName(Object o) {
    return o == null ? "null" : o instanceof Class ? ((Class) o).getName() : o.getClass().getName();
  }

  static public <A extends Concept> Collection<A> findConceptsWhere(Class<A> c, Object... params) {
    return findConceptsWhere(db_mainConcepts(), c, params);
  }

  static public Collection<Concept> findConceptsWhere(String c, Object... params) {
    return findConceptsWhere(db_mainConcepts(), c, params);
  }

  static public <A extends Concept> Collection<A> findConceptsWhere(Concepts concepts, Class<A> c, Object... params) {
    ping();
    params = expandParams(c, params);
    if (concepts.fieldIndices != null)
      for (int i = 0; i < l(params); i += 2) {
        IFieldIndex<A, Object> index = concepts.getFieldIndex(c, (String) params[i]);
        if (index != null) {
          Collection<A> rawList = index.getAll(params[i + 1]);
          params = dropEntryFromParams(params, i);
          if (params == null)
            return rawList;
          List<A> l = new ArrayList();
          for (A x : rawList) if (checkConceptFields(x, params))
            l.add(x);
          return l;
        }
      }
    return filterConcepts(concepts.list(c), params);
  }

  static public Collection<Concept> findConceptsWhere(Concepts concepts, String c, Object... params) {
    return filterConcepts(concepts.list(c), params);
  }

  static public <A> int iteratorCount_int_close(Iterator<A> i) {
    try {
      int n = 0;
      if (i != null)
        while (i.hasNext()) {
          i.next();
          ++n;
        }
      if (i instanceof AutoCloseable)
        ((AutoCloseable) i).close();
      return n;
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public <A, B> Pair<A, B> mapEntryToPair(Map.Entry<A, B> e) {
    return e == null ? null : pair(e.getKey(), e.getValue());
  }

  static public <A, B> Set<Map.Entry<A, B>> entrySet(Map<A, B> map) {
    return _entrySet(map);
  }

  static public <A> A firstThat(Iterable<A> l, IF1<A, Boolean> pred) {
    for (A a : unnullForIteration(l)) if (pred.get(a))
      return a;
    return null;
  }

  static public <A> A firstThat(A[] l, IF1<A, Boolean> pred) {
    for (A a : unnullForIteration(l)) if (pred.get(a))
      return a;
    return null;
  }

  static public <A> A firstThat(IF1<A, Boolean> pred, Iterable<A> l) {
    return firstThat(l, pred);
  }

  static public <A> A firstThat(IF1<A, Boolean> pred, A[] l) {
    return firstThat(l, pred);
  }

  static public String defaultThreadName_name;

  static public String defaultThreadName() {
    if (defaultThreadName_name == null)
      defaultThreadName_name = "A thread by " + programID();
    return defaultThreadName_name;
  }

  static public Runnable wrapAsActivity(Object r) {
    if (r == null)
      return null;
    Runnable r2 = toRunnable(r);
    Object mod = dm_current_generic();
    if (mod == null)
      return r2;
    return new Runnable() {

      public void run() {
        try {
          AutoCloseable c = (AutoCloseable) (rcall("enter", mod));
          AutoCloseable __1 = c;
          try {
            r2.run();
          } finally {
            _close(__1);
          }
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "AutoCloseable c =  (AutoCloseable) (rcall enter(mod));\r\n    temp c;\r\n    r2.r...";
      }
    };
  }

  static public Thread newThread(Object runnable) {
    return new BetterThread(_topLevelErrorHandling(toRunnable(runnable)));
  }

  static public Thread newThread(Object runnable, String name) {
    if (name == null)
      name = defaultThreadName();
    return new BetterThread(_topLevelErrorHandling(toRunnable(runnable)), name);
  }

  static public Thread newThread(String name, Object runnable) {
    return newThread(runnable, name);
  }

  static public Runnable toRunnable(final Object o) {
    if (o instanceof Runnable)
      return (Runnable) o;
    if (o instanceof String)
      throw fail("callF_legacy");
    return new Runnable() {

      public void run() {
        try {
          callF(o);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "callF(o)";
      }
    };
  }

  static public Map<Thread, Boolean> _registerThread_threads;

  static public Object _onRegisterThread;

  static public Thread _registerThread(Thread t) {
    if (_registerThread_threads == null)
      _registerThread_threads = newWeakHashMap();
    _registerThread_threads.put(t, true);
    vm_generalWeakSubMap("thread2mc").put(t, weakRef(mc()));
    callF(_onRegisterThread, t);
    return t;
  }

  static public void _registerThread() {
    _registerThread(Thread.currentThread());
  }

  static public URLConnection openConnection(String url) {
    try {
      return openConnection(new URL(url));
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public URLConnection openConnection(URL url) {
    try {
      ping();
      callOpt(javax(), "recordOpenURLConnection", str(url));
      return url.openConnection();
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public void setHeaders(URLConnection con) throws IOException {
    String computerID = getComputerID_quick();
    if (computerID != null)
      try {
        con.setRequestProperty("X-ComputerID", computerID);
        con.setRequestProperty("X-OS", System.getProperty("os.name") + " " + System.getProperty("os.version"));
      } catch (Throwable e) {
      }
  }

  static public FileOutputStream newFileOutputStream(File path) throws IOException {
    return newFileOutputStream(path.getPath());
  }

  static public FileOutputStream newFileOutputStream(String path) throws IOException {
    return newFileOutputStream(path, false);
  }

  static public FileOutputStream newFileOutputStream(File path, boolean append) throws IOException {
    return newFileOutputStream(path.getPath(), append);
  }

  static public FileOutputStream newFileOutputStream(String path, boolean append) throws IOException {
    mkdirsForFile(path);
    FileOutputStream f = new FileOutputStream(path, append);
    _registerIO(f, path, true);
    return f;
  }

  public static File mkdirsFor(File file) {
    return mkdirsForFile(file);
  }

  static public void copyStreamWithPrints(InputStream in, OutputStream out, String pat) {
    try {
      byte[] buf = new byte[65536];
      int total = 0;
      while (true) {
        int n = in.read(buf);
        if (n <= 0)
          return;
        out.write(buf, 0, n);
        if ((total + n) / 100000 > total / 100000)
          print(pat.replace("{*}", str(roundDownTo(100000, total))));
        total += n;
      }
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public File renameFile_assertTrue(File a, File b) {
    try {
      if (a.equals(b))
        return b;
      if (!a.exists())
        throw fail("Source file not found: " + f2s(a));
      if (b.exists())
        throw fail("Target file exists: " + f2s(b));
      mkdirsForFile(b);
      if (!a.renameTo(b))
        throw fail("Can't rename " + f2s(a) + " to " + f2s(b));
      return b;
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public void copyStream(InputStream in, OutputStream out) {
    try {
      byte[] buf = new byte[65536];
      while (true) {
        int n = in.read(buf);
        if (n <= 0)
          return;
        out.write(buf, 0, n);
      }
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public <A> A getVar(IF0<A> v) {
    return v == null ? null : v.get();
  }

  static public <A> A getVar(Optional<A> v) {
    return v == null ? null : v.orElse(null);
  }

  static public Object safeUnstruct(String s) {
    return unstructure(s, true);
  }

  static public <A> VF1<A> ivf1ToVF1(IVF1<A> f) {
    return f == null ? null : new VF1<A>() {

      public void get(A a) {
        try {
          f.get(a);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "f.get(a)";
      }
    };
  }

  static public Map<String, Set> vm_busListenersByMessage_live_cache;

  static public Map<String, Set> vm_busListenersByMessage_live() {
    if (vm_busListenersByMessage_live_cache == null)
      vm_busListenersByMessage_live_cache = vm_busListenersByMessage_live_load();
    return vm_busListenersByMessage_live_cache;
  }

  static public Map<String, Set> vm_busListenersByMessage_live_load() {
    return vm_generalHashMap("busListenersByMessage");
  }

  static public <A> Set<A> syncIdentityHashSet() {
    return (Set) synchronizedSet(identityHashSet());
  }

  static public <A> A second(List<A> l) {
    return get(l, 1);
  }

  static public <A> A second(Iterable<A> l) {
    if (l == null)
      return null;
    Iterator<A> it = iterator(l);
    if (!it.hasNext())
      return null;
    it.next();
    return it.hasNext() ? it.next() : null;
  }

  static public <A> A second(A[] bla) {
    return bla == null || bla.length <= 1 ? null : bla[1];
  }

  static public <A, B> B second(Pair<A, B> p) {
    return p == null ? null : p.b;
  }

  static public <A, B, C> B second(T3<A, B, C> t) {
    return t == null ? null : t.b;
  }

  static public <A> A second(Producer<A> p) {
    if (p == null)
      return null;
    if (p.next() == null)
      return null;
    return p.next();
  }

  static public char second(String s) {
    return charAt(s, 1);
  }

  static public <A, B> B second(Either<A, B> e) {
    return e == null ? null : e.bOpt();
  }

  static public <A> A third(List<A> l) {
    return _get(l, 2);
  }

  static public <A> A third(Iterable<A> l) {
    if (l == null)
      return null;
    Iterator<A> it = iterator(l);
    for (int _repeat_0 = 0; _repeat_0 < 2; _repeat_0++) {
      if (!it.hasNext())
        return null;
      it.next();
    }
    return it.hasNext() ? it.next() : null;
  }

  static public <A> A third(Producer<A> p) {
    if (p == null)
      return null;
    for (int _repeat_1 = 0; _repeat_1 < 2; _repeat_1++) {
      if (p.next() == null)
        return null;
    }
    return p.next();
  }

  static public <A> A third(A[] bla) {
    return bla == null || bla.length <= 2 ? null : bla[2];
  }

  static public <A, B, C> C third(T3<A, B, C> t) {
    return t == null ? null : t.c;
  }

  static public <A> VF1<A> runnableToVF1(final Runnable r) {
    return r == null ? null : new VF1<A>() {

      public void get(A a) {
        try {
          r.run();
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "r.run()";
      }
    };
  }

  static public boolean startsWithIgnoreCase(String a, String b) {
    return regionMatchesIC(a, 0, b, 0, b.length());
  }

  public static boolean isSnippetID(String s) {
    try {
      parseSnippetID(s);
      return true;
    } catch (RuntimeException e) {
      return false;
    }
  }

  public static long parseSnippetID(String snippetID) {
    long id = Long.parseLong(shortenSnippetID(snippetID));
    if (id == 0)
      throw fail("0 is not a snippet ID");
    return id;
  }

  static public String getProgramID() {
    return nempty(programID) ? formatSnippetIDOpt(programID) : "?";
  }

  static public String getProgramID(Class c) {
    String id = (String) getOpt(c, "programID");
    if (nempty(id))
      return formatSnippetID(id);
    return "?";
  }

  static public String getProgramID(Object o) {
    return getProgramID(getMainClass(o));
  }

  static public String jextract(String pat, String s) {
    return jextract(pat, javaTok(s));
  }

  static public String jextract(String pat, List<String> tok) {
    List<String> tokpat = javaTok(pat);
    jfind_preprocess(tokpat);
    int i = jfind(tok, tokpat);
    if (i < 0)
      return null;
    int j = i + l(tokpat) - 2;
    return joinSubList(tok, i, j);
  }

  static public Object vm_generalMap_set(Object key, Object value) {
    return vm_generalMap_put(key, value);
  }

  static public int indexOfIC(List<String> a, String b) {
    return indexOfIgnoreCase(a, b);
  }

  static public int indexOfIC(List<String> a, String b, int i) {
    return indexOfIgnoreCase(a, b, i);
  }

  static public int indexOfIC(String[] a, String b) {
    return indexOfIC(a, b, 0);
  }

  static public int indexOfIC(String[] a, String b, int i) {
    return indexOfIgnoreCase(a, b, i);
  }

  static public int indexOfIC(String a, String b) {
    return indexOfIgnoreCase(a, b);
  }

  static public int indexOfIC(String a, String b, int i) {
    return indexOfIgnoreCase(a, b, i);
  }

  static public int parseInt(String s) {
    return emptyString(s) ? 0 : Integer.parseInt(s);
  }

  static public int parseInt(char c) {
    return Integer.parseInt(str(c));
  }

  static public int cmp(Number a, Number b) {
    return a == null ? b == null ? 0 : -1 : cmp(a.doubleValue(), b.doubleValue());
  }

  static public int cmp(double a, double b) {
    return a < b ? -1 : a == b ? 0 : 1;
  }

  static public int cmp(int a, int b) {
    return a < b ? -1 : a == b ? 0 : 1;
  }

  static public int cmp(long a, long b) {
    return a < b ? -1 : a == b ? 0 : 1;
  }

  static public int cmp(Object a, Object b) {
    if (a == null)
      return b == null ? 0 : -1;
    if (b == null)
      return 1;
    return ((Comparable) a).compareTo(b);
  }

  static public Rect boundsAsRect(Component c) {
    return boundsRect(c);
  }

  static public <A> int indexOfMax(List<A> l, IF1<A, Comparable> f) {
    Best_comparable<Integer> best = new Best_comparable();
    for (int i = 0; i < l(l); i++) best.put(i, f.get(l.get(i)));
    return or(best.get(), -1);
  }

  static public boolean containsIgnoreCase(Collection<String> l, String s) {
    if (l != null)
      for (String x : l) if (eqic(x, s))
        return true;
    return false;
  }

  static public boolean containsIgnoreCase(String[] l, String s) {
    if (l != null)
      for (String x : l) if (eqic(x, s))
        return true;
    return false;
  }

  static public boolean containsIgnoreCase(String s, char c) {
    return indexOfIgnoreCase(s, String.valueOf(c)) >= 0;
  }

  static public boolean containsIgnoreCase(String a, String b) {
    return indexOfIgnoreCase(a, b) >= 0;
  }

  static public File javaxDataDir_dir;

  static public File javaxDataDir() {
    return javaxDataDir_dir != null ? javaxDataDir_dir : new File(userHome(), "JavaX-Data");
  }

  static public File javaxDataDir(String... subs) {
    return newFile(javaxDataDir(), subs);
  }

  static public String formatSnippetIDOpt(String s) {
    return isSnippetID(s) ? formatSnippetID(s) : s;
  }

  static volatile public String caseID_caseID;

  static public String caseID() {
    return caseID_caseID;
  }

  static public void caseID(String id) {
    caseID_caseID = id;
  }

  static public File getProgramFile(String progID, String fileName) {
    if (new File(fileName).isAbsolute())
      return new File(fileName);
    return new File(getProgramDir(progID), fileName);
  }

  static public File getProgramFile(String fileName) {
    return getProgramFile(getProgramID(), fileName);
  }

  static public <A, B> LinkedHashMap<A, B> cloneLinkedHashMap(Map<A, B> map) {
    return map == null ? new LinkedHashMap() : new LinkedHashMap(map);
  }

  static public Map synchroHashMap() {
    return synchronizedMap(new HashMap());
  }

  static public Map synchronizedMap() {
    return synchroMap();
  }

  static public <A, B> Map<A, B> synchronizedMap(Map<A, B> map) {
    return synchroMap(map);
  }

  static public void _onJavaXSet() {
  }

  static public boolean nemptyString(String s) {
    return s != null && s.length() > 0;
  }

  static public int strL(String s) {
    return s == null ? 0 : s.length();
  }

  static public int listL(Collection l) {
    return l == null ? 0 : l.size();
  }

  static public boolean neq(Object a, Object b) {
    return !eq(a, b);
  }

  static public int lCharSequence(CharSequence s) {
    return s == null ? 0 : s.length();
  }

  static public String unnullForIteration(String s) {
    return s == null ? "" : s;
  }

  static public <A> Collection<A> unnullForIteration(Collection<A> l) {
    return l == null ? immutableEmptyList() : l;
  }

  static public <A> List<A> unnullForIteration(List<A> l) {
    return l == null ? immutableEmptyList() : l;
  }

  static public int[] unnullForIteration(int[] l) {
    return l == null ? emptyIntArray() : l;
  }

  static public char[] unnullForIteration(char[] l) {
    return l == null ? emptyCharArray() : l;
  }

  static public double[] unnullForIteration(double[] l) {
    return l == null ? emptyDoubleArray() : l;
  }

  static public short[] unnullForIteration(short[] l) {
    return l == null ? emptyShortArray() : l;
  }

  static public <A, B> Map<A, B> unnullForIteration(Map<A, B> l) {
    return l == null ? immutableEmptyMap() : l;
  }

  static public <A> Iterable<A> unnullForIteration(Iterable<A> i) {
    return i == null ? immutableEmptyList() : i;
  }

  static public <A> A[] unnullForIteration(A[] a) {
    return a == null ? (A[]) emptyObjectArray() : a;
  }

  static public BitSet unnullForIteration(BitSet b) {
    return b == null ? new BitSet() : b;
  }

  static public Pt unnullForIteration(Pt p) {
    return p == null ? new Pt() : p;
  }

  static public <A, B> Pair<A, B> unnullForIteration(Pair<A, B> p) {
    return p != null ? p : new Pair(null, null);
  }

  static public long unnullForIteration(Long l) {
    return l == null ? 0L : l;
  }

  static public void setMeta(IMeta o, Object key, Object value) {
    metaMapPut(o, key, value);
  }

  static public double doubleRatio(double x, double y) {
    return y == 0 ? 0 : x / y;
  }

  static public double doubleRatio(Seconds x, Seconds y) {
    return doubleRatio(x.get(), y.get());
  }

  static public byte[] scaledGrayBytesFromBWIntegralImage(int w, BWIntegralImage img) {
    return scaledGrayBytesFromBWIntegralImage(img, w);
  }

  static public byte[] scaledGrayBytesFromBWIntegralImage(BWIntegralImage img, int w) {
    return scaledGrayBytesFromBWIntegralImage(img, w, heightForWidth(img, w));
  }

  static public byte[] scaledGrayBytesFromBWIntegralImage(BWIntegralImage img, int w, int h) {
    int w1 = img.getWidth(), h1 = img.getHeight();
    double stepX = doubleRatio(w1, w), stepY = doubleRatio(h1, h);
    byte[] pixels = new byte[w * h];
    int i = 0;
    double srcY = 0;
    for (int y = 0; y < h; y++) {
      double srcX = 0, nextSrcY = srcY + stepY;
      for (int x = 0; x < w; x++) {
        double nextSrcX = srcX + stepX;
        int pixel = iround(img.getPixelAverage(srcX, srcY, nextSrcX, nextSrcY));
        pixels[i++] = clampToUByte(pixel);
        srcX = nextSrcX;
      }
      srcY = nextSrcY;
    }
    return pixels;
  }

  static public byte[] scaledGrayBytesFromBWIntegralImage(int w, IBWIntegralImage img) {
    return scaledGrayBytesFromBWIntegralImage(img, w);
  }

  static public byte[] scaledGrayBytesFromBWIntegralImage(IBWIntegralImage img, int w) {
    return scaledGrayBytesFromBWIntegralImage(img, w, heightForWidth(img, w));
  }

  static public byte[] scaledGrayBytesFromBWIntegralImage(IBWIntegralImage img, int w, int h) {
    int w1 = img.getWidth(), h1 = img.getHeight();
    double stepX = doubleRatio(w1, w), stepY = doubleRatio(h1, h);
    byte[] pixels = new byte[w * h];
    int i = 0;
    double srcY = 0;
    for (int y = 0; y < h; y++) {
      double srcX = 0, nextSrcY = srcY + stepY;
      for (int x = 0; x < w; x++) {
        double nextSrcX = srcX + stepX;
        int pixel = iround(img.getPixelAverage(srcX, srcY, nextSrcX, nextSrcY));
        pixels[i++] = clampToUByte(pixel);
        srcX = nextSrcX;
      }
      srcY = nextSrcY;
    }
    return pixels;
  }

  static public double parseDouble(String s) {
    return empty(s) ? 0.0 : Double.parseDouble(s);
  }

  static public Point getMouseLocation() {
    return MouseInfo.getPointerInfo().getLocation();
  }

  static public <A extends Component> A repaint(A c) {
    if (c != null)
      c.repaint();
    return c;
  }

  static public void imageSurface_unpixelated(ImageSurface imageSurface) {
    if (imageSurface == null)
      return;
    imageSurface.interpolationMode = RenderingHints.VALUE_INTERPOLATION_BILINEAR;
    repaint(imageSurface);
  }

  static public BufferedImage toBufferedImageOpt(Object o) {
    if (o instanceof BufferedImage)
      return ((BufferedImage) o);
    if (o instanceof Image)
      return copyImage((Image) o);
    if (o instanceof MakesBufferedImage)
      return ((MakesBufferedImage) o).getBufferedImage();
    if (o instanceof File)
      if (isImageFile((File) o))
        return loadBufferedImageFile((File) o);
    String c = getClassName(o);
    if (eqOneOf(c, "main$BWImage", "main$RGBImage"))
      return (BufferedImage) call(o, "getBufferedImage");
    if (eq(c, "main$PNGFile"))
      return (BufferedImage) call(o, "getImage");
    return null;
  }

  static public <A> A swingConstruct(final Class<A> c, final Object... args) {
    return swing(new F0<A>() {

      public A get() {
        try {
          return nuObject(c, args);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret nuObject(c, args);";
      }
    });
  }

  static public <A extends JComponent> A bindToolTipToLiveValue(LiveValue lv, A c) {
    bindLiveValueListenerToComponent(c, lv, new Runnable() {

      public void run() {
        try {
          setToolTipText(c, strOrNull(lv.get()));
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "setToolTipText(c, strOrNull(lv!))";
      }
    });
    return c;
  }

  static public 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);
      }
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public void lock(Lock lock, String msg) {
    print("Locking: " + msg);
    lock(lock);
  }

  static public void lock(Lock lock, String msg, long timeout) {
    print("Locking: " + msg);
    lockOrFail(lock, timeout);
  }

  static public ReentrantLock lock() {
    return fairLock();
  }

  static public void unlock(Lock lock, String msg) {
    if (lock == null)
      return;
    lock.unlock();
    vmBus_send("unlocked", lock, "thread", currentThread());
    print("Unlocked: " + msg);
  }

  static public void unlock(Lock lock) {
    if (lock == null)
      return;
    lock.unlock();
    vmBus_send("unlocked", lock, "thread", currentThread());
  }

  static public Object swingCall(final Object o, final String method, final Object... args) {
    return swing(new F0<Object>() {

      public Object get() {
        try {
          return call(o, method, args);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret call(o, method, args);";
      }
    });
  }

  static public JTabbedPane jLeftTabs(Object... x) {
    JTabbedPane tabs = jtabs(x);
    tabs.setTabPlacement(JTabbedPane.LEFT);
    return tabs;
  }

  static public JTabbedPane jLeftTabs(Collection c) {
    return jLeftTabs(toObjectArray(c));
  }

  static public JTabbedPane jtabs(Object... x) {
    return fillJTabs(swingNu(JTabbedPane.class), x);
  }

  static public JPanel jRightAlignedLine(Component... components) {
    return jrightAlignedLine(components);
  }

  static public JPanel jRightAlignedLine(List<? extends Component> components) {
    return jrightAlignedLine(components);
  }

  static public <A extends Component> A _recordNewSwingComponent(A c) {
    if (c != null)
      callF((Object) vm_generalMap_get("newSwingComponentRegistry"), (Object) c);
    return c;
  }

  static public JComponent componentToJComponent(Component c) {
    if (c instanceof JComponent)
      return (JComponent) c;
    if (c instanceof JFrame)
      return ((JFrame) c).getRootPane();
    if (c == null)
      return null;
    throw fail("boohoo " + getClassName(c));
  }

  static public JScrollPane jscroll(final Component c) {
    return swing(new F0<JScrollPane>() {

      public JScrollPane get() {
        try {
          return new JScrollPane(c);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret new JScrollPane(c);";
      }
    });
  }

  static public <A extends JComponent> A jtransparent(final A a) {
    {
      swing(() -> {
        a.setOpaque(false);
      });
    }
    return a;
  }

  static public JPanel borderLayoutPanel() {
    return jpanel(new BorderLayout());
  }

  static public JSpinner jSpinner(final int value) {
    return swing(new F0<JSpinner>() {

      public JSpinner get() {
        try {
          JSpinner s = new JSpinner();
          s.setValue(value);
          return jSpinnerCommitOnValidEdit(s);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "new JSpinner s;\r\n    s.setValue(value);\r\n    ret jSpinnerCommitOnValidEdit(s);";
      }
    });
  }

  static public JSpinner jSpinner(final int value, final int min, final int max) {
    return swing(new F0<JSpinner>() {

      public JSpinner get() {
        try {
          return jSpinnerCommitOnValidEdit(new JSpinner(new SpinnerNumberModel(value, min, max, 1)));
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret jSpinnerCommitOnValidEdit(new JSpinner(new SpinnerNumberModel(value, min,...";
      }
    });
  }

  static public int intFromSpinner(JSpinner s) {
    return toInt(s.getValue());
  }

  static public void setSpinnerValue(JSpinner s, int value) {
    setSpinnerValue(s, (Integer) value);
  }

  static public void setSpinnerValue(JSpinner s, Object value) {
    try {
      if (s != null) {
        swing(() -> {
          s.setValue(value);
        });
      }
    } catch (Throwable __e) {
      printStackTrace(__e);
    }
  }

  static public JSpinner rightAlignSpinner(JSpinner spinner) {
    setHorizontalAlignment(JTextField.RIGHT, getTextFieldFromSpinner(spinner));
    return spinner;
  }

  static public <A> JSpinner jListSpinner(List<A> entries, A defaultValue) {
    return swing(() -> {
      JSpinner s = new JSpinner();
      s.setModel(new SpinnerListModel(entries));
      if (contains(entries, defaultValue))
        setSpinnerValue(s, defaultValue);
      return s;
    });
  }

  static public List<Integer> powersOfTwoUpTo(int n) {
    IntBuffer l = new IntBuffer();
    int i = 1;
    while (i <= n && i > 0) {
      l.add(i);
      i *= 2;
    }
    return l.asVirtualList();
  }

  static public String formatWithThousandsSeparator(long l) {
    return NumberFormat.getInstance(new Locale("en_US")).format(l);
  }

  static public String getType(Object o) {
    return getClassName(o);
  }

  static public long getFileSize(String path) {
    return path == null ? 0 : new File(path).length();
  }

  static public long getFileSize(File f) {
    return f == null ? 0 : f.length();
  }

  static public String trim(String s) {
    return s == null ? null : s.trim();
  }

  static public String trim(StringBuilder buf) {
    return buf.toString().trim();
  }

  static public String trim(StringBuffer buf) {
    return buf.toString().trim();
  }

  static public CloseableIterableIterator<String> linesFromFile(File f) {
    return linesFromFile(f, null);
  }

  static public CloseableIterableIterator<String> linesFromFile(File f, IResourceHolder resourceHolder) {
    try {
      if (!f.exists())
        return emptyCloseableIterableIterator();
      if (ewic(f.getName(), ".gz"))
        return linesFromReader(utf8bufferedReader(newGZIPInputStream(f)), resourceHolder);
      return linesFromReader(utf8bufferedReader(f), resourceHolder);
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public CloseableIterableIterator<String> linesFromFile(String path) {
    return linesFromFile(path, null);
  }

  static public CloseableIterableIterator<String> linesFromFile(String path, IResourceHolder resourceHolder) {
    return linesFromFile(newFile(path), resourceHolder);
  }

  static public <A, B> Set<A> keys(Map<A, B> map) {
    return map == null ? new HashSet() : map.keySet();
  }

  static public Set keys(Object map) {
    return keys((Map) map);
  }

  static public <A> Set<A> keys(MultiSet<A> ms) {
    return ms.keySet();
  }

  static public <A, B> Set<A> keys(MultiMap<A, B> mm) {
    return mm.keySet();
  }

  static public <A> A or(A a, A b) {
    return a != null ? a : b;
  }

  static public BufferedImage intArrayToBufferedImage(int[] pixels, int w, int h) {
    int[] bitMasks = new int[] { 0xFF0000, 0xFF00, 0xFF, 0xFF000000 };
    SinglePixelPackedSampleModel sm = new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, w, h, bitMasks);
    DataBufferInt db = new DataBufferInt(pixels, pixels.length);
    WritableRaster wr = Raster.createWritableRaster(sm, db, new Point());
    return new BufferedImage(ColorModel.getRGBdefault(), wr, false, null);
  }

  static public Map synchroMap() {
    return synchroHashMap();
  }

  static public <A, B> Map<A, B> synchroMap(Map<A, B> map) {
    return new SynchronizedMap(map);
  }

  static public <A> List<A> withoutNulls(Iterable<A> l) {
    if (l instanceof List)
      if (!containsNulls((List) l))
        return ((List) l);
    List<A> l2 = new ArrayList();
    for (A a : l) if (a != null)
      l2.add(a);
    return l2;
  }

  static public <A, B> Map<A, B> withoutNulls(Map<A, B> map) {
    Map<A, B> map2 = similarEmptyMap(map);
    for (A a : keys(map)) if (a != null) {
      B b = map.get(a);
      if (b != null)
        map2.put(a, b);
    }
    return map2;
  }

  static public <A> List<A> withoutNulls(A[] l) {
    List<A> l2 = new ArrayList();
    if (l != null)
      for (A a : l) if (a != null)
        l2.add(a);
    return l2;
  }

  static public String[] toStringArray(Collection<String> c) {
    String[] a = new String[l(c)];
    Iterator<String> it = c.iterator();
    for (int i = 0; i < l(a); i++) a[i] = it.next();
    return a;
  }

  static public String[] toStringArray(Object o) {
    if (o instanceof String[])
      return (String[]) o;
    else if (o instanceof Collection)
      return toStringArray((Collection<String>) o);
    else
      throw fail("Not a collection or array: " + getClassName(o));
  }

  static public void scrollRowToVisible(JTable t, int rowIndex) {
    int colIndex = 0;
    if (!(t.getParent() instanceof JViewport))
      return;
    JViewport viewport = (JViewport) t.getParent();
    Rectangle rect = t.getCellRect(rowIndex, colIndex, true);
    Rectangle viewRect = viewport.getViewRect();
    int x = viewRect.x;
    int y = viewRect.y;
    if (rect.x >= viewRect.x && rect.x <= (viewRect.x + viewRect.width - rect.width)) {
    } else if (rect.x < viewRect.x) {
      x = rect.x;
    } else if (rect.x > (viewRect.x + viewRect.width - rect.width)) {
      x = rect.x - viewRect.width + rect.width;
    }
    if (rect.y >= viewRect.y && rect.y <= (viewRect.y + viewRect.height - rect.height)) {
    } else if (rect.y < viewRect.y) {
      y = rect.y;
    } else if (rect.y > (viewRect.y + viewRect.height - rect.height)) {
      y = rect.y - viewRect.height + rect.height;
    }
    viewport.setViewPosition(new Point(x, y));
  }

  static public int listRowCount(JList list) {
    return list == null ? 0 : swing(new F0<Integer>() {

      public Integer get() {
        try {
          return list.getModel().getSize();
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret list.getModel().getSize();";
      }
    });
  }

  static public Runnable addThreadInfoToRunnable(final Object r) {
    final Object info = _threadInfo();
    return info == null ? asRunnable(r) : new Runnable() {

      public void run() {
        try {
          _inheritThreadInfo(info);
          callF(r);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "_inheritThreadInfo(info); callF(r);";
      }
    };
  }

  static public IterableIterator<Integer> countIterator_inclusive(final int a, final int b) {
    return countIterator_exclusive(a, b + 1);
  }

  static public <A> IterableIterator<A> countIterator_inclusive(int a, int b, IF1<Integer, A> f) {
    return countIterator_inclusive(a, b, 1, f);
  }

  static public <A> IterableIterator<A> countIterator_inclusive(int a, int b, int step, IF1<Integer, A> f) {
    return countIterator_inclusive_step(a, b, 1, f);
  }

  static public <A> IterableIterator<A> countIterator_inclusive(double a, double b, double step, IF1<Double, A> f) {
    return countIterator_inclusive_step(a, b, step, f);
  }

  static public IterableIterator<Integer> countIterator_inclusive_step(int a, final int b, int step) {
    assertTrue("step > 0", step > 0);
    return new IterableIterator<Integer>() {

      public int i = a;

      public boolean hasNext() {
        return i <= b;
      }

      public Integer next() {
        var j = i;
        i += step;
        return j;
      }
    };
  }

  static public IterableIterator<Double> countIterator_inclusive_step(double a, double b, double step) {
    assertTrue("step > 0", step > 0);
    return new IterableIterator<Double>() {

      public double i = a;

      public boolean hasNext() {
        return i <= b;
      }

      public Double next() {
        var j = i;
        i += step;
        return j;
      }
    };
  }

  static public <A> IterableIterator<A> countIterator_inclusive_step(double a, double b, double step, IF1<Double, A> f) {
    return mapI_if1(f, countIterator_inclusive_step(a, b, step));
  }

  static public <A> IterableIterator<A> countIterator_inclusive_step(int a, int b, int step, IF1<Integer, A> f) {
    return mapI_if1(f, countIterator_inclusive_step(a, b, step));
  }

  static public Object pcallFunction(Object f, Object... args) {
    try {
      return callFunction(f, args);
    } catch (Throwable __e) {
      printStackTrace(__e);
    }
    return null;
  }

  static public Object collectionMutex(List l) {
    return l;
  }

  static public Object collectionMutex(Object o) {
    if (o instanceof List)
      return o;
    String c = className(o);
    if (eq(c, "java.util.TreeMap$KeySet"))
      c = className(o = getOpt(o, "m"));
    else if (eq(c, "java.util.HashMap$KeySet"))
      c = className(o = get_raw(o, "this$0"));
    if (eqOneOf(c, "java.util.TreeMap$AscendingSubMap", "java.util.TreeMap$DescendingSubMap"))
      c = className(o = get_raw(o, "m"));
    return o;
  }

  static public Object sleepQuietly_monitor = new Object();

  static public void sleepQuietly() {
    try {
      assertFalse(isAWTThread());
      synchronized (sleepQuietly_monitor) {
        sleepQuietly_monitor.wait();
      }
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public AutoCloseable tempEnter(Object o) {
    return o == null ? null : optCast(AutoCloseable.class, rcallOpt("enter", o));
  }

  static public AutoCloseable tempEnter(Enterable o) {
    return o == null ? null : o.enter();
  }

  static public Object callOpt_withVarargs(Object o, String method, Object... args) {
    try {
      if (o == null)
        return null;
      if (o instanceof Class) {
        Class c = (Class) o;
        _MethodCache cache = callOpt_getCache(c);
        Method me = cache.findMethod(method, args);
        if (me == null) {
          return null;
        }
        if ((me.getModifiers() & Modifier.STATIC) == 0)
          return null;
        return invokeMethod(me, null, args);
      } else {
        Class c = o.getClass();
        _MethodCache cache = callOpt_getCache(c);
        Method me = cache.findMethod(method, args);
        if (me != null)
          return invokeMethod(me, o, args);
        List<Method> methods = cache.cache.get(method);
        if (methods != null)
          methodSearch: for (Method m : methods) {
            {
              if (!(m.isVarArgs()))
                continue;
            }
            Object[] newArgs = massageArgsForVarArgsCall(m, args);
            if (newArgs != null)
              return invokeMethod(m, o, newArgs);
          }
        return null;
      }
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public JLabel jLabel(String text) {
    return jlabel(text);
  }

  static public JLabel jLabel() {
    return jlabel();
  }

  static public String loadTextFile(String fileName) {
    return loadTextFile(fileName, null);
  }

  static public String loadTextFile(File f, String defaultContents) {
    return loadTextFile(f, defaultContents, "UTF-8");
  }

  static public String loadTextFile(File f, String defaultContents, String encoding) {
    try {
      checkFileNotTooBigToRead(f);
      if (f == null || !f.exists())
        return defaultContents;
      FileInputStream fileInputStream = new FileInputStream(f);
      InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, encoding);
      return loadTextFile(inputStreamReader);
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  public static String loadTextFile(File fileName) {
    return loadTextFile(fileName, null);
  }

  static public String loadTextFile(String fileName, String defaultContents) {
    return fileName == null ? defaultContents : loadTextFile(newFile(fileName), defaultContents);
  }

  static public String loadTextFile(Reader reader) throws IOException {
    StringBuilder builder = new StringBuilder();
    try {
      char[] buffer = new char[1024];
      int n;
      while (-1 != (n = reader.read(buffer))) builder.append(buffer, 0, n);
    } finally {
      reader.close();
    }
    return str(builder);
  }

  static public File muricaPasswordFile() {
    return new File(javaxSecretDir(), "murica/muricaPasswordFile");
  }

  static public JLabel jimage(Image img) {
    return jImageLabel(img);
  }

  static public JLabel jimage(String imageID) {
    return jImageLabel(imageID);
  }

  static public BufferedImage scaleImage_bilinear(BufferedImage before, double scaleX) {
    return scaleImage_bilinear(before, scaleX, scaleX);
  }

  static public BufferedImage scaleImage_bilinear(BufferedImage before, double scaleX, double scaleY) {
    return scaleImageWithOp(before, scaleX, scaleY, AffineTransformOp.TYPE_BILINEAR);
  }

  static public BufferedImage scaleImage_bilinear(double scale, BufferedImage before) {
    return scaleImage_bilinear(before, scale);
  }

  static public boolean loadBufferedImage_useImageCache = true;

  static public BufferedImage loadBufferedImage(String snippetIDOrURLOrFile) {
    try {
      ping();
      if (snippetIDOrURLOrFile == null)
        return null;
      if (isURL(snippetIDOrURLOrFile))
        return imageIO_readURL(snippetIDOrURLOrFile);
      if (isSnippetID(snippetIDOrURLOrFile)) {
        String snippetID = "" + parseSnippetID(snippetIDOrURLOrFile);
        IResourceLoader rl = vm_getResourceLoader();
        if (rl != null)
          return loadBufferedImage(rl.loadLibrary(snippetID));
        File dir = imageSnippetsCacheDir();
        if (loadBufferedImage_useImageCache) {
          dir.mkdirs();
          File file = new File(dir, snippetID + ".png");
          if (file.exists() && file.length() != 0)
            try {
              return ImageIO.read(file);
            } catch (Throwable e) {
              e.printStackTrace();
            }
        }
        String imageURL = snippetImageURL_http(snippetID);
        print("Loading image: " + imageURL);
        BufferedImage image = imageIO_readURL(imageURL);
        if (loadBufferedImage_useImageCache) {
          File tempFile = new File(dir, snippetID + ".tmp." + System.currentTimeMillis());
          ImageIO.write(image, "png", tempFile);
          tempFile.renameTo(new File(dir, snippetID + ".png"));
        }
        return image;
      } else
        return loadBufferedImage(new File(snippetIDOrURLOrFile));
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public BufferedImage loadBufferedImage(File file) {
    return loadBufferedImageFile(file);
  }

  static public String fsI(String id) {
    return formatSnippetID(id);
  }

  static public String fsI(long id) {
    return formatSnippetID(id);
  }

  static public File loadBinarySnippet(String snippetID) {
    IResourceLoader rl = vm_getResourceLoader();
    if (rl != null)
      return rl.loadLibrary(snippetID);
    return loadBinarySnippet_noResourceLoader(snippetID);
  }

  static public File loadBinarySnippet_noResourceLoader(String snippetID) {
    try {
      long id = parseSnippetID(snippetID);
      if (isImageServerSnippet(id))
        return loadImageAsFile(snippetID);
      File f = DiskSnippetCache_getLibrary(id);
      if (fileSize(f) == 0)
        f = loadDataSnippetToFile_noResourceLoader(snippetID);
      return f;
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public boolean isFalse(Object o) {
    return eq(false, o);
  }

  static public boolean loadBufferedImageFixingGIFs_debug = false;

  static public ThreadLocal<Var<byte[]>> loadBufferedImageFixingGIFs_output = new ThreadLocal();

  static public Image loadBufferedImageFixingGIFs(File file) {
    try {
      if (!file.exists())
        return null;
      if (!isGIF(file))
        return ImageIO.read(file);
      if (loadBufferedImageFixingGIFs_debug)
        print("loadBufferedImageFixingGIFs" + ": checking gif");
      ImageReader reader = ImageIO.getImageReadersByFormatName("gif").next();
      reader.setInput(ImageIO.createImageInputStream(file));
      int numImages = reader.getNumImages(true);
      IIOMetadata imageMetaData = reader.getImageMetadata(0);
      String metaFormatName = imageMetaData.getNativeMetadataFormatName();
      boolean foundBug = false;
      for (int i = 0; i < numImages && !foundBug; i++) {
        IIOMetadataNode root = (IIOMetadataNode) reader.getImageMetadata(i).getAsTree(metaFormatName);
        int nNodes = root.getLength();
        for (int j = 0; j < nNodes; j++) {
          org.w3c.dom.Node node = root.item(j);
          if (node.getNodeName().equalsIgnoreCase("GraphicControlExtension")) {
            String delay = ((IIOMetadataNode) node).getAttribute("delayTime");
            if (Integer.parseInt(delay) == 0) {
              foundBug = true;
            }
            break;
          }
        }
      }
      if (loadBufferedImageFixingGIFs_debug)
        print("loadBufferedImageFixingGIFs" + ": " + f2s(file) + " foundBug=" + foundBug);
      Image image;
      if (!foundBug) {
        image = Toolkit.getDefaultToolkit().createImage(f2s(file));
      } else {
        ByteArrayOutputStream baoStream = new ByteArrayOutputStream();
        {
          ImageOutputStream ios = ImageIO.createImageOutputStream(baoStream);
          try {
            ImageWriter writer = ImageIO.getImageWriter(reader);
            writer.setOutput(ios);
            writer.prepareWriteSequence(null);
            for (int i = 0; i < numImages; i++) {
              BufferedImage frameIn = reader.read(i);
              IIOMetadataNode root = (IIOMetadataNode) reader.getImageMetadata(i).getAsTree(metaFormatName);
              int nNodes = root.getLength();
              for (int j = 0; j < nNodes; j++) {
                org.w3c.dom.Node node = root.item(j);
                if (node.getNodeName().equalsIgnoreCase("GraphicControlExtension")) {
                  String delay = ((IIOMetadataNode) node).getAttribute("delayTime");
                  if (Integer.parseInt(delay) == 0) {
                    ((IIOMetadataNode) node).setAttribute("delayTime", "10");
                  }
                  break;
                }
              }
              IIOMetadata metadata = writer.getDefaultImageMetadata(new ImageTypeSpecifier(frameIn), null);
              metadata.setFromTree(metadata.getNativeMetadataFormatName(), root);
              IIOImage frameOut = new IIOImage(frameIn, null, metadata);
              writer.writeToSequence(frameOut, writer.getDefaultWriteParam());
            }
            writer.endWriteSequence();
          } finally {
            _close(ios);
          }
        }
        byte[] data = baoStream.toByteArray();
        setVar(loadBufferedImageFixingGIFs_output.get(), data);
        if (loadBufferedImageFixingGIFs_debug)
          print("Data size: " + l(data));
        image = Toolkit.getDefaultToolkit().createImage(data);
      }
      return image;
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public <A extends JComponent> A setToolTipText(final A c, final Object toolTip) {
    if (c == null)
      return null;
    {
      swing(() -> {
        String s = nullIfEmpty(str(toolTip));
        if (neq(s, c.getToolTipText()))
          c.setToolTipText(s);
      });
    }
    return c;
  }

  static public <A extends JComponent> A setToolTipText(Object toolTip, A c) {
    return setToolTipText(c, toolTip);
  }

  static public void setTrayIconToolTip(TrayIcon trayIcon, String toolTip) {
    if (trayIcon != null)
      trayIcon.setToolTip(toolTip);
  }

  static public JButton disableButton(final JButton b) {
    if (b != null) {
      swing(() -> {
        b.setEnabled(false);
      });
    }
    return b;
  }

  static public void disableButton() {
    disableButton(heldInstance(JButton.class));
  }

  static public void disposePossiblyInternalFrame(Component c) {
    Container f = (Container) (getPossiblyInternalFrame(c));
    if (f instanceof JInternalFrame)
      disposeInternalFrame((JInternalFrame) f);
    else if (f instanceof Window)
      disposeWindow(f);
  }

  static public JButton enableButton(JButton b) {
    return enableButton(b, true);
  }

  static public JButton enableButton(JButton b, boolean enable) {
    if (b != null) {
      swing(() -> {
        b.setEnabled(enable);
      });
    }
    return b;
  }

  static public Pair<Boolean, String> transpileOnNewServer(String snippetID) {
    return transpileOnNewServer(snippetID, "quick");
  }

  static public Pair<Boolean, String> transpileOnNewServer(long snippetID) {
    return transpileOnNewServer(fsI(snippetID));
  }

  static public Pair<Boolean, String> transpileOnNewServer(long snippetID, String mode) {
    return transpileOnNewServer(fsI(snippetID), mode);
  }

  static public Pair<Boolean, String> transpileOnNewServer(String snippetID, String mode) {
    try {
      print("Transpiling " + formatSnippetID(snippetID));
      String url = "https://botcompany.de/1018308/raw/" + psI(snippetID);
      url = appendParamsToURL(url, "medium", eq(mode, "medium") ? "1" : null, "fresh", eq(mode, "fresh") ? "1" : null);
      String result = postPage(url, muricaCredentials());
      print(result);
      boolean ok = cic(htmlDecode(result), "Transpiled & uploaded");
      return pair(ok, result);
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public Pair<Boolean, String> transpileOnServer(String snippetID) {
    return transpileOnServer(snippetID, "quick");
  }

  static public Pair<Boolean, String> transpileOnServer(long snippetID) {
    return transpileOnServer(fsI(snippetID));
  }

  static public Pair<Boolean, String> transpileOnServer(long snippetID, String mode) {
    return transpileOnServer(fsI(snippetID), mode);
  }

  static public Pair<Boolean, String> transpileOnServer(String snippetID, String mode) {
    try {
      print("Transpiling " + formatSnippetID(snippetID));
      String url = tb_mainServer() + "/tb/transpile.php";
      String modeStr = "&quick=1";
      if (eq(mode, "medium"))
        modeStr += "&medium=1";
      if (eq(mode, "fresh"))
        modeStr += "&fresh=1";
      String query = "id=" + parseSnippetID(snippetID) + modeStr + standardCredentials();
      String result = loadPage(url + "?" + query);
      print(result);
      Matcher m = regexp("URL=/(dexcompile\\.php.*?)'", result);
      if (!m.find())
        return pair(false, result);
      url = tb_mainServer() + "/" + m.group(1) + standardCredentials();
      result = loadPage(url);
      boolean ok = result.contains("SUCCESS");
      return pair(ok, result);
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public void callF_thread(final Object f, final Object... args) {
    if (f != null) {
      startThread(new Runnable() {

        public void run() {
          try {
            callF(f, args);
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "callF(f, args);";
        }
      });
    }
  }

  static public Component addToWindowWithMargin(final Component c, final Component toAdd) {
    if (toAdd != null)
      addToWindowAndGrow(c, withMargin(toAdd));
    return c;
  }

  static public JPanel jcenteredbuttons(Object... params) {
    return jcenteredline(paramsToButtons(params));
  }

  static public Object nuObject(String className, Object... args) {
    try {
      return nuObject(classForName(className), args);
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public <A> A nuObject(Class<A> c, Object... args) {
    try {
      if (args.length == 0)
        return nuObjectWithoutArguments(c);
      Constructor m = nuObject_findConstructor(c, args);
      makeAccessible(m);
      return (A) m.newInstance(args);
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public Constructor nuObject_findConstructor(Class c, Object... args) {
    for (Constructor m : c.getDeclaredConstructors()) {
      if (!nuObject_checkArgs(m.getParameterTypes(), args, false))
        continue;
      return m;
    }
    throw fail("Constructor " + c.getName() + getClasses(args) + " not found" + (args.length == 0 && (c.getModifiers() & java.lang.reflect.Modifier.STATIC) == 0 ? " - hint: it's a non-static class!" : ""));
  }

  static public boolean nuObject_checkArgs(Class[] types, Object[] args, boolean debug) {
    if (types.length != args.length) {
      if (debug)
        System.out.println("Bad parameter length: " + args.length + " vs " + types.length);
      return false;
    }
    for (int i = 0; i < types.length; i++) if (!(args[i] == null || isInstanceX(types[i], args[i]))) {
      if (debug)
        System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]);
      return false;
    }
    return true;
  }

  static public <A> A setAll(A o, Map<String, Object> fields) {
    if (fields == null)
      return o;
    for (String field : keys(fields)) set(o, field, fields.get(field));
    return o;
  }

  static public <A> A setAll(A o, Object... values) {
    failIfOddCount(values);
    for (int i = 0; i + 1 < l(values); i += 2) {
      String field = (String) values[i];
      Object value = values[i + 1];
      set(o, field, value);
    }
    return o;
  }

  static public <A, B> Map<A, B> mapPlus(Map<A, B> m, Object... data) {
    m = cloneMap(m);
    litmap_impl(m, data);
    return m;
  }

  static public Object[] assertEvenLength(Object[] a) {
    assertTrue(even(l(a)));
    return a;
  }

  static public LinkedHashMap paramsToOrderedMap(Object... params) {
    return asLinkedHashMap(paramsToMap(params));
  }

  static public Rectangle maxWindowBounds() {
    return GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
  }

  static public void ping_okInCleanUp() {
  }

  static public Object vmBus_wrapArgs(Object... args) {
    return empty(args) ? null : l(args) == 1 ? args[0] : args;
  }

  static public void pcallFAll_minimalExceptionHandling(Collection l, Object... args) {
    if (l != null)
      for (Object f : cloneList(l)) {
        ping();
        pcallF_minimalExceptionHandling(f, args);
      }
  }

  static public void pcallFAll_minimalExceptionHandling(Iterator it, Object... args) {
    while (it.hasNext()) {
      ping();
      pcallF_minimalExceptionHandling(it.next(), args);
    }
  }

  static public Set vm_busListeners_live_cache;

  static public Set vm_busListeners_live() {
    if (vm_busListeners_live_cache == null)
      vm_busListeners_live_cache = vm_busListeners_live_load();
    return vm_busListeners_live_cache;
  }

  static public Set vm_busListeners_live_load() {
    return vm_generalIdentityHashSet("busListeners");
  }

  static public File userDir_oneOf_createIfNone(String ifNone, String... names) {
    return or(userDir_oneOf(names), userDir(ifNone));
  }

  static public boolean eqicOneOf(String s, String... l) {
    for (String x : l) if (eqic(s, x))
      return true;
    return false;
  }

  static public String fileExtension(File f) {
    if (f == null)
      return null;
    return fileExtension(f.getName());
  }

  static public String fileExtension(String s) {
    return substring(s, smartLastIndexOf(s, '.'));
  }

  static public boolean hasJPEGExtension(File f) {
    return ewicOneOf(fileName(f), ".jpg", ".jpeg");
  }

  static public void saveJPG(BufferedImage img, File file) {
    try {
      if (!ImageIO.write(img, "jpeg", mkdirsFor(file))) {
        print("Reconstructing image for saving JPEG");
        img = reconstructBufferedImage(img);
        if (!ImageIO.write(img, "jpeg", file))
          throw fail("Couldn't write JPEG: " + file + " (" + img + ")");
      }
      vmBus_send("wroteFile", file);
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public void saveJPG(File file, BufferedImage img) {
    try {
      saveJPG(img, file);
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public void savePNG(BufferedImage img, File file) {
    try {
      File tempFile = new File(file.getPath() + "_temp");
      CriticalAction ca = beginCriticalAction("Save " + f2s(file));
      try {
        ImageIO.write(img, "png", mkdirsFor(tempFile));
        file.delete();
        tempFile.renameTo(file);
      } finally {
        ca.done();
      }
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public void savePNG(String file, BufferedImage img) {
    savePNG(toFile(file), img);
  }

  static public void savePNG(File file, BufferedImage img) {
    savePNG(img, file);
  }

  static public void savePNG(File file, RGBImage img) {
    savePNG(file, img.getBufferedImage());
  }

  static public String strOrNull(Object o) {
    return o == null ? null : str(o);
  }

  static public byte[] hexToBytes(String s) {
    if (odd(l(s)))
      throw fail("Hex string has odd length: " + quote(shorten(10, s)));
    int n = l(s) / 2;
    byte[] bytes = new byte[n];
    for (int i = 0; i < n; i++) {
      int a = parseHexChar(s.charAt(i * 2));
      int b = parseHexChar(s.charAt(i * 2 + 1));
      if (a < 0 || b < 0)
        throw fail("Bad hex byte: " + quote(substring(s, i * 2, i * 2 + 2)) + " at " + i * 2 + "/" + l(s));
      bytes[i] = (byte) ((a << 4) | b);
    }
    return bytes;
  }

  static public PersistableThrowable persistableThrowable(Throwable e) {
    return e == null ? null : new PersistableThrowable(e);
  }

  static public Throwable getException(Runnable r) {
    try {
      callF(r);
      return null;
    } catch (Throwable e) {
      return e;
    }
  }

  static public boolean startsWithOneOf(String s, String... l) {
    for (String x : l) if (startsWith(s, x))
      return true;
    return false;
  }

  static public boolean startsWithOneOf(String s, Matches m, String... l) {
    for (String x : l) if (startsWith(s, x, m))
      return true;
    return false;
  }

  static public boolean isAGIBlueDomain(String domain) {
    return domainIsUnder(domain, theAGIBlueDomain());
  }

  static public String hostNameFromURL(String url) {
    try {
      return empty(url) ? null : new URL(url).getHost();
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public int[] emptyIntArray_a = new int[0];

  static public int[] emptyIntArray() {
    return emptyIntArray_a;
  }

  static public char[] emptyCharArray = new char[0];

  static public char[] emptyCharArray() {
    return emptyCharArray;
  }

  static public double[] emptyDoubleArray = new double[0];

  static public double[] emptyDoubleArray() {
    return emptyDoubleArray;
  }

  static public Map emptyMap() {
    return new HashMap();
  }

  static public Object[] emptyObjectArray_a = new Object[0];

  static public Object[] emptyObjectArray() {
    return emptyObjectArray_a;
  }

  static public JScrollPane setScrollPaneBackground(Color c, JScrollPane sp) {
    if (sp != null && c != null) {
      swing(() -> {
        sp.getViewport().setBackground(c);
      });
    }
    return sp;
  }

  static public Color getBackground(final Component c) {
    return c == null ? null : swing(new F0<Color>() {

      public Color get() {
        try {
          return c.getBackground();
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret c.getBackground();";
      }
    });
  }

  static public <A extends Concept> Object[] expandParams(Class<A> c, Object[] params) {
    if (l(params) == 1)
      params = new Object[] { singleFieldName(c), params[0] };
    else
      warnIfOddCount(params);
    return params;
  }

  static public Object[] dropEntryFromParams(Object[] params, int i) {
    int n = l(params);
    if (i < 0 || i >= n)
      return params;
    if (n == 2)
      return null;
    Object[] p = new Object[n - 2];
    System.arraycopy(params, 0, p, 0, i);
    System.arraycopy(params, i + 2, p, i, n - i - 2);
    return p;
  }

  static public boolean checkConceptFields(Concept x, Object... data) {
    for (int i = 0; i < l(data); i += 2) if (neq(cget(x, (String) data[i]), deref(data[i + 1])))
      return false;
    return true;
  }

  static public <A extends Concept> List<A> filterConcepts(List<A> list, Object... params) {
    if (empty(params))
      return list;
    List<A> l = new ArrayList();
    for (A x : list) if (checkConceptFields(x, params))
      l.add(x);
    return l;
  }

  static public <A, B> Set<Map.Entry<A, B>> _entrySet(Map<A, B> map) {
    return map == null ? Collections.EMPTY_SET : map.entrySet();
  }

  static public Object rcall(String method, Object o, Object... args) {
    return call_withVarargs(o, method, args);
  }

  static public Runnable _topLevelErrorHandling(Runnable r) {
    if (r == null)
      return null;
    Object info = _threadInfo();
    Object mod = dm_current_generic();
    if (info == null && mod == null)
      return r;
    return new Runnable() {

      public void run() {
        try {
          AutoCloseable __1 = (AutoCloseable) (rcall("enter", mod));
          try {
            _threadInheritInfo(info);
            r.run();
          } finally {
            _close(__1);
          }
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "temp (AutoCloseable) rcall enter(mod);\r\n    _threadInheritInfo(info);\r\n    r....";
      }
    };
  }

  static public <A> WeakReference<A> weakRef(A a) {
    return newWeakReference(a);
  }

  static public String getComputerID_quick() {
    return computerID();
  }

  public static File mkdirsForFile(File file) {
    File dir = file.getParentFile();
    if (dir != null) {
      dir.mkdirs();
      if (!dir.isDirectory())
        if (dir.isFile())
          throw fail("Please delete the file " + f2s(dir) + " - it is supposed to be a directory!");
        else
          throw fail("Unknown IO exception during mkdirs of " + f2s(file));
    }
    return file;
  }

  public static String mkdirsForFile(String path) {
    mkdirsForFile(new File(path));
    return path;
  }

  static public void _registerIO(Object object, String path, boolean opened) {
  }

  static public int roundDownTo(int n, int x) {
    return x / n * n;
  }

  static public long roundDownTo(long n, long x) {
    return x / n * n;
  }

  static public <A> Set<A> synchronizedSet() {
    return synchroHashSet();
  }

  static public <A> Set<A> synchronizedSet(Set<A> set) {
    return new SynchronizedSet(set);
  }

  static public <A> Set<A> identityHashSet() {
    return Collections.newSetFromMap(new IdentityHashMap());
  }

  static public <A> Iterator<A> iterator(Iterable<A> c) {
    return c == null ? emptyIterator() : c.iterator();
  }

  static public char charAt(String s, int i) {
    return s != null && i >= 0 && i < s.length() ? s.charAt(i) : '\0';
  }

  static public <A> A _get(List<A> l, int idx) {
    return l != null && idx >= 0 && idx < l(l) ? l.get(idx) : null;
  }

  static public Object _get(Object o, String field) {
    return get(o, field);
  }

  static public Object _get(String field, Object o) {
    return get(o, field);
  }

  static public <A> A _get(A[] l, int idx) {
    return idx >= 0 && idx < l(l) ? l[idx] : null;
  }

  static public boolean regionMatchesIC(String a, int offsetA, String b, int offsetB, int len) {
    return a != null && a.regionMatches(true, offsetA, b, offsetB, len);
  }

  static public String shortenSnippetID(String snippetID) {
    if (snippetID.startsWith("#"))
      snippetID = snippetID.substring(1);
    String httpBlaBla = "http://tinybrain.de/";
    if (snippetID.startsWith(httpBlaBla))
      snippetID = snippetID.substring(httpBlaBla.length());
    return "" + parseLong(snippetID);
  }

  static public String formatSnippetID(String id) {
    return "#" + parseSnippetID(id);
  }

  static public String formatSnippetID(long id) {
    return "#" + id;
  }

  static public Class getMainClass() {
    return mc();
  }

  static public Class getMainClass(Object o) {
    try {
      if (o == null)
        return null;
      if (o instanceof Class && eq(((Class) o).getName(), "x30"))
        return (Class) o;
      ClassLoader cl = (o instanceof Class ? (Class) o : o.getClass()).getClassLoader();
      if (cl == null)
        return null;
      String name = mainClassNameForClassLoader(cl);
      return loadClassFromClassLoader_orNull(cl, name);
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public int jfind(String s, String in) {
    return jfind(javaTok(s), in);
  }

  static public int jfind(List<String> tok, String in) {
    return jfind(tok, 1, in);
  }

  static public int jfind(List<String> tok, int startIdx, String in) {
    return jfind(tok, startIdx, in, null);
  }

  static public int jfind(List<String> tok, String in, Object condition) {
    return jfind(tok, 1, in, condition);
  }

  static public int jfind(List<String> tok, String in, ITokCondition condition) {
    return jfind(tok, 1, in, condition);
  }

  static public int jfind(List<String> tok, int startIndex, String in, ITokCondition condition) {
    return jfind(tok, startIndex, in, (Object) condition);
  }

  static public int jfind(List<String> tok, int startIdx, String in, Object condition) {
    return jfind(tok, startIdx, javaTokForJFind_array(in), condition);
  }

  static public int jfind(List<String> tok, List<String> tokin) {
    return jfind(tok, 1, tokin);
  }

  static public int jfind(List<String> tok, int startIdx, List<String> tokin) {
    return jfind(tok, startIdx, tokin, null);
  }

  static public int jfind(List<String> tok, int startIdx, String[] tokinC, Object condition) {
    return findCodeTokens(tok, startIdx, false, tokinC, condition);
  }

  static public int jfind(List<String> tok, int startIdx, List<String> tokin, Object condition) {
    return jfind(tok, startIdx, codeTokensAsStringArray(tokin), condition);
  }

  static public List<String> jfind_preprocess(List<String> tok) {
    for (String type : litlist("quoted", "id", "int")) replaceSublist(tok, ll("<", "", type, "", ">"), ll("<" + type + ">"));
    replaceSublist(tok, ll("\\", "", "*"), ll("\\*"));
    return tok;
  }

  static public int indexOfIgnoreCase(List<String> a, String b) {
    return indexOfIgnoreCase(a, b, 0);
  }

  static public int indexOfIgnoreCase(List<String> a, String b, int i) {
    int n = a == null ? 0 : a.size();
    for (; i < n; i++) if (eqic(a.get(i), b))
      return i;
    return -1;
  }

  static public int indexOfIgnoreCase(String[] a, String b) {
    return indexOfIgnoreCase(a, b, 0);
  }

  static public int indexOfIgnoreCase(String[] a, String b, int i) {
    int n = a == null ? 0 : a.length;
    for (; i < n; i++) if (eqic(a[i], b))
      return i;
    return -1;
  }

  static public int indexOfIgnoreCase(String a, String b) {
    return indexOfIgnoreCase_manual(a, b);
  }

  static public int indexOfIgnoreCase(String a, String b, int i) {
    return indexOfIgnoreCase_manual(a, b, i);
  }

  static public boolean emptyString(String s) {
    return s == null || s.length() == 0;
  }

  static public Rect boundsRect(Component c) {
    return toRect(getBounds(c));
  }

  static public boolean eqic(String a, String b) {
    if ((a == null) != (b == null))
      return false;
    if (a == null)
      return true;
    return a.equalsIgnoreCase(b);
  }

  static public boolean eqic(char a, char b) {
    if (a == b)
      return true;
    char u1 = Character.toUpperCase(a);
    char u2 = Character.toUpperCase(b);
    if (u1 == u2)
      return true;
    return Character.toLowerCase(u1) == Character.toLowerCase(u2);
  }

  static public String _userHome;

  static public String userHome() {
    if (_userHome == null)
      return actualUserHome();
    return _userHome;
  }

  static public File userHome(String path) {
    return new File(userDir(), path);
  }

  static public File getProgramDir() {
    return programDir();
  }

  static public File getProgramDir(String snippetID) {
    return programDir(snippetID);
  }

  static public <A> List<A> immutableEmptyList() {
    return Collections.emptyList();
  }

  static public short[] emptyShortArray = new short[0];

  static public short[] emptyShortArray() {
    return emptyShortArray;
  }

  static public <A, B> Map<A, B> immutableEmptyMap() {
    return Collections.emptyMap();
  }

  static public byte clampToUByte(long l) {
    return (byte) clamp(l, 0, 255);
  }

  static public BufferedImage copyImage(Image img) {
    if (img == null)
      return null;
    if (img instanceof BufferedImage)
      return copyImage((BufferedImage) img);
    int w = img.getWidth(null), h = img.getHeight(null);
    BufferedImage bi = newBufferedImage(w, h);
    drawImage(bi, img);
    return bi;
  }

  static public BufferedImage copyImage(BufferedImage bi) {
    if (bi == null)
      return null;
    ColorModel cm = bi.getColorModel();
    boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
    WritableRaster raster = bi.copyData(bi.getRaster().createCompatibleWritableRaster());
    return new BufferedImage(cm, raster, isAlphaPremultiplied, null);
  }

  static public boolean isImageFile(File f) {
    return isImageFileName(fileName(f));
  }

  static public BufferedImage loadBufferedImageFile(File file) {
    try {
      return isFile(file) ? ImageIO.read(file) : null;
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public boolean eqOneOf(Object o, Object... l) {
    for (Object x : l) if (eq(o, x))
      return true;
    return false;
  }

  static public Thread currentThread() {
    return Thread.currentThread();
  }

  static public Map<Thread, Object> vm_threadInterruptionReasonsMap() {
    return vm_generalWeakSubMap("Thread interruption reasons");
  }

  static public String strOr(Object o, String ifNull) {
    return o == null ? ifNull : str(o);
  }

  static public void lockOrFail(Lock lock, long timeout) {
    try {
      ping();
      vmBus_send("locking", lock, "thread", currentThread());
      if (!lock.tryLock(timeout, TimeUnit.MILLISECONDS)) {
        String s = "Couldn't acquire lock after " + timeout + " ms.";
        if (lock instanceof ReentrantLock) {
          ReentrantLock l = (ReentrantLock) lock;
          s += " Hold count: " + l.getHoldCount() + ", owner: " + call(l, "getOwner");
        }
        throw fail(s);
      }
      vmBus_send("locked", lock, "thread", currentThread());
      ping();
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public ReentrantLock fairLock() {
    return new ReentrantLock(true);
  }

  static public JTabbedPane fillJTabs(final JTabbedPane tabs, final Object... _x) {
    if (tabs == null)
      return null;
    clearTabs(tabs);
    Object[] x = flattenArray2(_x);
    int idx = 0;
    if (get(x, 0) instanceof Integer) {
      idx = asInt(get(x, 0));
      x = dropFirst(x);
      if (empty(x)) {
        x = arrayrep(null, idx);
        idx = 0;
      }
    }
    int n = 0;
    for (int i = 0; i < l(x); i++) {
      ++n;
      if (isComponentOrSwingable(x[i]))
        addTab(tabs, "Tab " + n, wrap(x[i]));
      else {
        String name = str(or(x[i], "Tab " + n));
        Component c;
        if (isComponentOrSwingable(get(x, i + 1)))
          c = wrap(get(x, ++i));
        else
          c = new JPanel();
        addTab(tabs, name, wrap(c));
      }
    }
    if (idx != 0)
      tabs.setSelectedIndex(min(tabs.getTabCount() - 1, idx));
    return tabs;
  }

  static public Object vm_generalMap_get(Object key) {
    return vm_generalMap().get(key);
  }

  static public JPanel jpanel(LayoutManager layout) {
    return swingNu(JPanel.class, layout);
  }

  static public JPanel jpanel() {
    return swingNu(JPanel.class);
  }

  static public JSpinner jSpinnerCommitOnValidEdit(JSpinner spinner) {
    var tf = getTextFieldFromSpinner(spinner);
    if (tf != null) {
      swing(() -> {
        DefaultFormatter formatter = (DefaultFormatter) (tf.getFormatter());
        if (formatter != null)
          formatter.setCommitsOnValidEdit(true);
      });
    }
    return spinner;
  }

  static public int toInt(Object o) {
    if (o == null)
      return 0;
    if (o instanceof Number)
      return ((Number) o).intValue();
    if (o instanceof String)
      return parseInt((String) o);
    if (o instanceof Boolean)
      return boolToInt((Boolean) o);
    throw fail("woot not int: " + getClassName(o));
  }

  static public int toInt(long l) {
    if (l != (int) l)
      throw fail("Too large for int: " + l);
    return (int) l;
  }

  static public JFormattedTextField getTextFieldFromSpinner(JSpinner spinner) {
    return spinner == null ? null : swing(() -> ((JSpinner.DefaultEditor) spinner.getEditor()).getTextField());
  }

  static public CloseableIterableIterator emptyCloseableIterableIterator_instance = new CloseableIterableIterator() {

    public Object next() {
      throw fail();
    }

    public boolean hasNext() {
      return false;
    }
  };

  static public <A> CloseableIterableIterator<A> emptyCloseableIterableIterator() {
    return emptyCloseableIterableIterator_instance;
  }

  static public boolean ewic(String a, String b) {
    return endsWithIgnoreCase(a, b);
  }

  static public boolean ewic(String a, String b, Matches m) {
    return endsWithIgnoreCase(a, b, m);
  }

  static public CloseableIterableIterator<String> linesFromReader(Reader r) {
    return linesFromReader(r, null);
  }

  static public CloseableIterableIterator<String> linesFromReader(Reader r, IResourceHolder resourceHolder) {
    final BufferedReader br = bufferedReader(r);
    return holdResource(resourceHolder, iteratorFromFunction_f0_autoCloseable(new F0<String>() {

      public String get() {
        try {
          return readLineFromReaderWithClose(br);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret readLineFromReaderWithClose(br);";
      }
    }, _wrapIOCloseable(r)));
  }

  static public BufferedReader utf8bufferedReader(InputStream in) {
    try {
      return in == null ? null : bufferedReader(_registerIOWrap(new InputStreamReader(in, "UTF-8"), in));
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public BufferedReader utf8bufferedReader(File f) {
    try {
      return utf8bufferedReader(newFileInputStream(f));
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public GZIPInputStream newGZIPInputStream(File f) {
    return gzInputStream(f);
  }

  static public GZIPInputStream newGZIPInputStream(InputStream in) {
    return gzInputStream(in);
  }

  static public boolean containsNulls(Collection c) {
    return contains(c, null);
  }

  static public Runnable asRunnable(Object o) {
    return toRunnable(o);
  }

  static public void _inheritThreadInfo(Object info) {
    _threadInheritInfo(info);
  }

  static public Object callFunction(Object f, Object... args) {
    return callF(f, args);
  }

  static public void assertFalse(Object o) {
    if (!(eq(o, false)))
      throw fail(str(o));
  }

  static public boolean assertFalse(boolean b) {
    if (b)
      throw fail("oops");
    return b;
  }

  static public boolean assertFalse(String msg, boolean b) {
    if (b)
      throw fail(msg);
    return b;
  }

  static public <A> A optCast(Class<A> c, Object o) {
    return isInstance(c, o) ? (A) o : null;
  }

  static final public Map<Class, _MethodCache> callOpt_cache = newDangerousWeakHashMap();

  static public Object callOpt_cached(Object o, String methodName, Object... args) {
    try {
      if (o == null)
        return null;
      if (o instanceof Class) {
        Class c = (Class) o;
        _MethodCache cache = callOpt_getCache(c);
        Method me = cache.findMethod(methodName, args);
        if (me == null || (me.getModifiers() & Modifier.STATIC) == 0)
          return null;
        return invokeMethod(me, null, args);
      } else {
        Class c = o.getClass();
        _MethodCache cache = callOpt_getCache(c);
        Method me = cache.findMethod(methodName, args);
        if (me == null)
          return null;
        return invokeMethod(me, o, args);
      }
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public _MethodCache callOpt_getCache(Class c) {
    _MethodCache cache = callOpt_cache.get(c);
    if (cache == null)
      callOpt_cache.put(c, cache = new _MethodCache(c));
    return cache;
  }

  static public Object invokeMethod(Method m, Object o, Object... args) {
    try {
      try {
        return m.invoke(o, args);
      } catch (InvocationTargetException e) {
        throw rethrow(getExceptionCause(e));
      } catch (IllegalArgumentException e) {
        throw new IllegalArgumentException(e.getMessage() + " - was calling: " + m + ", args: " + joinWithSpace(classNames(args)));
      }
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public Object[] massageArgsForVarArgsCall(Method m, Object[] args) {
    Class<?>[] types = m.getParameterTypes();
    int n = types.length - 1, nArgs = args.length;
    if (nArgs < n)
      return null;
    for (int i = 0; i < n; i++) if (!argumentCompatibleWithType(args[i], types[i]))
      return null;
    Class varArgType = types[n].getComponentType();
    for (int i = n; i < nArgs; i++) if (!argumentCompatibleWithType(args[i], varArgType))
      return null;
    Object[] newArgs = new Object[n + 1];
    arraycopy(args, 0, newArgs, 0, n);
    Object[] varArgs = arrayOfType(varArgType, nArgs - n);
    arraycopy(args, n, varArgs, 0, nArgs - n);
    newArgs[n] = varArgs;
    return newArgs;
  }

  static public ThreadLocal<VF1<File>> checkFileNotTooBigToRead_tl = new ThreadLocal();

  static public void checkFileNotTooBigToRead(File f) {
    callF(checkFileNotTooBigToRead_tl.get(), f);
  }

  static public File javaxSecretDir_dir;

  static public File javaxSecretDir() {
    return javaxSecretDir_dir != null ? javaxSecretDir_dir : new File(userHome(), "JavaX-Secret");
  }

  static public File javaxSecretDir(String sub) {
    return newFile(javaxSecretDir(), sub);
  }

  static public JLabel jImageLabel(Image img) {
    return swingNu(JLabel.class, imageIcon(img));
  }

  static public JLabel jImageLabel(javax.swing.Icon icon) {
    return swingNu(JLabel.class, icon);
  }

  static public JLabel jImageLabel(String imageID) {
    return jImageLabel(imageIcon(imageID));
  }

  static public JLabel jImageLabel(String text, String imageID) {
    final JLabel l = swingNu(JLabel.class, text, imageIcon(imageID), JLabel.CENTER);
    {
      swing(() -> {
        l.setVerticalTextPosition(SwingConstants.BOTTOM);
        l.setHorizontalTextPosition(SwingConstants.CENTER);
      });
    }
    return l;
  }

  static public BufferedImage scaleImageWithOp(BufferedImage before, double scaleX, int affineTransformOpType) {
    return scaleImageWithOp(before, scaleX, scaleX, affineTransformOpType);
  }

  static public BufferedImage scaleImageWithOp(BufferedImage before, double scaleX, double scaleY, int affineTransformOpType) {
    if (scaleX == 1 && scaleY == 1)
      return before;
    int w = before.getWidth();
    int h = before.getHeight();
    int neww = max(1, iround(w * scaleX)), newh = max(1, iround(h * scaleY));
    BufferedImage after = new BufferedImage(neww, newh, BufferedImage.TYPE_INT_ARGB);
    AffineTransform at = new AffineTransform();
    at.scale(scaleX, scaleY);
    AffineTransformOp scaleOp = new AffineTransformOp(at, affineTransformOpType);
    return scaleOp.filter(before, after);
  }

  static public boolean isURL(String s) {
    return startsWithOneOf(s, "http://", "https://", "file:");
  }

  static public BufferedImage imageIO_readURL(String url) {
    try {
      return ImageIO.read(new URL(url));
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public IResourceLoader vm_getResourceLoader() {
    return proxy(IResourceLoader.class, vm_generalMap_get("_officialResourceLoader"));
  }

  static public File imageSnippetsCacheDir() {
    return javaxCachesDir("Image-Snippets");
  }

  static public String snippetImageURL_http(String snippetID) {
    return snippetImageURL_http(snippetID, "png");
  }

  static public String snippetImageURL_http(String snippetID, String contentType) {
    return replacePrefix("https://", "http://", snippetImageURL(snippetID, contentType)).replace(":8443", ":8080");
  }

  static public boolean isImageServerSnippet(long id) {
    return id >= 1100000 && id < 1200000;
  }

  static public File loadImageAsFile(String snippetIDOrURL) {
    try {
      if (isURL(snippetIDOrURL))
        throw fail("not implemented");
      if (!isSnippetID(snippetIDOrURL))
        throw fail("Not a URL or snippet ID: " + snippetIDOrURL);
      String snippetID = "" + parseSnippetID(snippetIDOrURL);
      File file = imageSnippetCacheFile(snippetID);
      if (fileSize(file) > 0)
        return file;
      String imageURL = snippetImageURL_noHttps(snippetID);
      System.err.println("Loading image: " + imageURL);
      byte[] data = loadBinaryPage(imageURL);
      saveBinaryFile(file, data);
      return file;
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public File DiskSnippetCache_file(long snippetID) {
    return new File(getGlobalCache(), "data_" + snippetID + ".jar");
  }

  public static File DiskSnippetCache_getLibrary(long snippetID) throws IOException {
    File file = DiskSnippetCache_file(snippetID);
    return file.exists() ? file : null;
  }

  public static void DiskSnippetCache_putLibrary(long snippetID, byte[] data) throws IOException {
    saveBinaryFile(DiskSnippetCache_file(snippetID), data);
  }

  static public byte[] loadDataSnippetImpl(String snippetID) throws IOException {
    byte[] data;
    try {
      URL url = new URL(dataSnippetLink(snippetID));
      print("Loading library: " + hideCredentials(url));
      try {
        data = loadBinaryPage(url.openConnection());
      } catch (RuntimeException e) {
        data = null;
      }
      if (data == null || data.length == 0) {
        url = new URL(tb_mainServer() + "/blobs/" + parseSnippetID(snippetID));
        print("Loading library: " + hideCredentials(url));
        data = loadBinaryPage(url.openConnection());
      }
      print("Bytes loaded: " + data.length);
    } catch (FileNotFoundException e) {
      throw new IOException("Binary snippet #" + snippetID + " not found or not public");
    }
    return data;
  }

  static public long fileSize(String path) {
    return getFileSize(path);
  }

  static public long fileSize(File f) {
    return getFileSize(f);
  }

  static public File loadDataSnippetToFile(String snippetID) {
    try {
      IResourceLoader rl = vm_getResourceLoader();
      if (rl != null)
        return rl.loadLibrary(snippetID);
      return loadDataSnippetToFile_noResourceLoader(snippetID);
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public File loadDataSnippetToFile_noResourceLoader(String snippetID) {
    try {
      snippetID = fsI(snippetID);
      File f = DiskSnippetCache_file(parseSnippetID(snippetID));
      List<URL> urlsTried = new ArrayList();
      List<Throwable> errors = new ArrayList();
      try {
        URL url = addAndReturn(urlsTried, new URL(dataSnippetLink(snippetID)));
        print("Loading library: " + hideCredentials(url));
        try {
          loadBinaryPageToFile(openConnection(url), f);
          if (fileSize(f) == 0)
            throw fail();
        } catch (Throwable e) {
          errors.add(e);
          url = addAndReturn(urlsTried, new URL(tb_mainServer() + "/blobs/" + psI(snippetID)));
          print(e);
          print("Trying other server: " + hideCredentials(url));
          loadBinaryPageToFile(openConnection(url), f);
          print("Got bytes: " + fileSize(f));
        }
        if (fileSize(f) == 0)
          throw fail();
        System.err.println("Bytes loaded: " + fileSize(f));
      } catch (Throwable e) {
        errors.add(e);
        throw fail("Binary snippet " + snippetID + " not found or not public. URLs tried: " + allToString(urlsTried) + ", errors: " + allToString(errors));
      }
      return f;
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public byte[] isGIF_magic = bytesFromHex("47494638");

  static public boolean isGIF(byte[] data) {
    return byteArrayStartsWith(data, isGIF_magic);
  }

  static public boolean isGIF(File f) {
    return isGIF(loadBeginningOfBinaryFile(f, l(isGIF_magic)));
  }

  static public <A> void setVar(IVar<A> v, A value) {
    if (v != null)
      v.set(value);
  }

  static public <A> IVF1<A> setVar(IVar<A> v) {
    return a -> {
      if (v != null)
        v.set(a);
    };
  }

  static public String nullIfEmpty(String s) {
    return isEmpty(s) ? null : s;
  }

  static public <A, B> Map<A, B> nullIfEmpty(Map<A, B> map) {
    return isEmpty(map) ? null : map;
  }

  static public <A> List<A> nullIfEmpty(List<A> l) {
    return isEmpty(l) ? null : l;
  }

  static public RootPaneContainer getPossiblyInternalFrame(Component c) {
    JInternalFrame f = getInternalFrame(c);
    if (f != null)
      return f;
    return optCast(RootPaneContainer.class, getWindow(c));
  }

  static public void disposeInternalFrame(Component c) {
    final JInternalFrame f = getInternalFrame(c);
    if (f != null) {
      swing(() -> {
        vmBus_send("disposingInternalFrame", f);
        f.dispose();
      });
    }
  }

  static public String appendParamsToURL(String url, Map params) {
    return appendQueryToURL(url, params);
  }

  static public String appendParamsToURL(String url, Object... data) {
    return appendQueryToURL(url, data);
  }

  static public String postPage(String url, Object... params) {
    return doPost(litmap(params), url);
  }

  static public String htmlDecode(String input) {
    return htmldecode(input);
  }

  static public String tb_mainServer_default = "https://code.botcompany.de:9898";

  static public Object tb_mainServer_override;

  static public String tb_mainServer() {
    if (tb_mainServer_override != null)
      return (String) callF(tb_mainServer_override);
    return trim(loadTextFile(tb_mainServer_file(), tb_mainServer_default));
  }

  static public File tb_mainServer_file() {
    return getProgramFile("#1001638", "mainserver.txt");
  }

  static public boolean tb_mainServer_isDefault() {
    return eq(tb_mainServer(), tb_mainServer_default);
  }

  static public Component addToWindowAndGrow(final Component c, final Component toAdd) {
    {
      swing(() -> {
        int h = getMinimumHeight(toAdd);
        addToWindow(c, toAdd);
        growWindowSouth(c, h);
      });
    }
    return c;
  }

  static public JPanel jcenteredline(final Component... components) {
    return swing(new F0<JPanel>() {

      public JPanel get() {
        try {
          return jFullCenter(hstackWithSpacing(components));
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret jFullCenter(hstackWithSpacing(components));";
      }
    });
  }

  static public JPanel jcenteredline(List<? extends Component> components) {
    return jcenteredline(asArray(Component.class, components));
  }

  static public List<JComponent> paramsToButtons(Object... params) {
    List<JComponent> l = new ArrayList();
    for (int i = 0; i < l(params); i += 2) if (params[i] != null)
      if (params[i] instanceof JComponent)
        l.add((JComponent) params[i--]);
      else
        l.add(jbutton((String) params[i], params[i + 1]));
    return l;
  }

  static public Map<String, Class> classForName_cache = synchroHashMap();

  static public Class classForName(String name) {
    return classForName(name, null);
  }

  static public Class classForName(String name, Object classFinder) {
    if (classForName_cache == null || classFinder != null)
      return classForName_uncached(name, classFinder);
    Class c = classForName_cache.get(name);
    if (c == null)
      classForName_cache.put(name, c = classForName_uncached(name, null));
    return c;
  }

  static public Class classForName_uncached(String name, Object classFinder) {
    try {
      if (classFinder != null)
        return (Class) callF(classFinder, name);
      return Class.forName(name);
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public Map<Class, Constructor> nuObjectWithoutArguments_cache = newDangerousWeakHashMap();

  static public Object nuObjectWithoutArguments(String className) {
    try {
      return nuObjectWithoutArguments(classForName(className));
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public <A> A nuObjectWithoutArguments(Class<A> c) {
    try {
      if (nuObjectWithoutArguments_cache == null)
        return (A) nuObjectWithoutArguments_findConstructor(c).newInstance();
      Constructor m = nuObjectWithoutArguments_cache.get(c);
      if (m == null)
        nuObjectWithoutArguments_cache.put(c, m = nuObjectWithoutArguments_findConstructor(c));
      return (A) m.newInstance();
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public Constructor nuObjectWithoutArguments_findConstructor(Class c) {
    for (Constructor m : c.getDeclaredConstructors()) if (empty(m.getParameterTypes())) {
      makeAccessible(m);
      return m;
    }
    throw fail("No default constructor found in " + c.getName());
  }

  static public Field makeAccessible(Field f) {
    try {
      f.setAccessible(true);
    } catch (Throwable e) {
      vmBus_send("makeAccessible_error", e, f);
    }
    return f;
  }

  static public Method makeAccessible(Method m) {
    try {
      m.setAccessible(true);
    } catch (Throwable e) {
      vmBus_send("makeAccessible_error", e, m);
    }
    return m;
  }

  static public Constructor makeAccessible(Constructor c) {
    try {
      c.setAccessible(true);
    } catch (Throwable e) {
      vmBus_send("makeAccessible_error", e, c);
    }
    return c;
  }

  static public List<Class> getClasses(Object[] array) {
    List<Class> l = emptyList(l(array));
    for (Object o : array) l.add(_getClass(o));
    return l;
  }

  static public boolean isInstanceX(Class type, Object arg) {
    if (type == boolean.class)
      return arg instanceof Boolean;
    if (type == int.class)
      return arg instanceof Integer;
    if (type == long.class)
      return arg instanceof Long;
    if (type == float.class)
      return arg instanceof Float;
    if (type == short.class)
      return arg instanceof Short;
    if (type == char.class)
      return arg instanceof Character;
    if (type == byte.class)
      return arg instanceof Byte;
    if (type == double.class)
      return arg instanceof Double;
    return type.isInstance(arg);
  }

  static public void failIfOddCount(Object... list) {
    if (odd(l(list)))
      throw fail("Odd list size: " + list);
  }

  static public <A, B> Map<A, B> cloneMap(Map<A, B> map) {
    if (map == null)
      return new HashMap();
    synchronized (map) {
      return map instanceof TreeMap ? new TreeMap((TreeMap) map) : map instanceof LinkedHashMap ? new LinkedHashMap(map) : new HashMap(map);
    }
  }

  static public <A, B> List<B> cloneMap(Iterable<A> l, IF1<A, B> f) {
    List x = emptyList(l);
    if (l != null)
      for (A o : cloneList(l)) x.add(f.get(o));
    return x;
  }

  static public HashMap litmap(Object... x) {
    HashMap map = new HashMap();
    litmap_impl(map, x);
    return map;
  }

  static public void litmap_impl(Map map, Object... x) {
    if (x != null)
      for (int i = 0; i < x.length - 1; i += 2) if (x[i + 1] != null)
        map.put(x[i], x[i + 1]);
  }

  static public boolean even(int i) {
    return (i & 1) == 0;
  }

  static public boolean even(long i) {
    return (i & 1) == 0;
  }

  static public boolean even(BigInteger n) {
    return even(n.intValue());
  }

  static public <A, B> LinkedHashMap<A, B> asLinkedHashMap(Map<A, B> map) {
    if (map instanceof LinkedHashMap)
      return (LinkedHashMap) map;
    LinkedHashMap<A, B> m = new LinkedHashMap();
    if (map != null)
      synchronized (collectionMutex(map)) {
        m.putAll(map);
      }
    return m;
  }

  static public Map paramsToMap(Object... params) {
    int n = l(params);
    if (l(params) == 1 && params[0] instanceof Map)
      return (Map) params[0];
    LinkedHashMap map = new LinkedHashMap();
    for (int i = 0; i + 1 < n; i += 2) mapPut(map, params[i], params[i + 1]);
    return map;
  }

  static public Object pcallF_minimalExceptionHandling(Object f, Object... args) {
    try {
      return callFunction(f, args);
    } catch (Throwable e) {
      System.out.println(getStackTrace(e));
      _storeException(e);
    }
    return null;
  }

  static public File userDir_oneOf(String... names) {
    return oneOfTheFilesInDir(userDir(), names);
  }

  static public File userDir() {
    return new File(userHome());
  }

  static public File userDir(String path) {
    return new File(userHome(), path);
  }

  static public int smartLastIndexOf(String s, char c) {
    if (s == null)
      return 0;
    int i = s.lastIndexOf(c);
    return i >= 0 ? i : l(s);
  }

  static public <A> int smartLastIndexOf(List<A> l, A sub) {
    int i = lastIndexOf(l, sub);
    return i < 0 ? l(l) : i;
  }

  static public String fileName(File f) {
    return f == null ? null : f.getName();
  }

  static public BufferedImage reconstructBufferedImage(BufferedImage img) {
    if (img == null)
      return null;
    RGBImage rgb = new RGBImage(img);
    rgb.uncacheBufferedImage();
    return rgb.getBufferedImage();
  }

  static public List<CriticalAction> beginCriticalAction_inFlight = synchroList();

  static public class CriticalAction {

    public String description;

    public CriticalAction() {
    }

    public CriticalAction(String description) {
      this.description = description;
    }

    public void done() {
      beginCriticalAction_inFlight.remove(this);
    }
  }

  static public CriticalAction beginCriticalAction(String description) {
    ping();
    CriticalAction c = new CriticalAction(description);
    beginCriticalAction_inFlight.add(c);
    return c;
  }

  static public void cleanMeUp_beginCriticalAction() {
    int n = 0;
    while (nempty(beginCriticalAction_inFlight)) {
      int m = l(beginCriticalAction_inFlight);
      if (m != n) {
        n = m;
        try {
          print("Waiting for " + n2(n, "critical actions") + ": " + join(", ", collect(beginCriticalAction_inFlight, "description")));
        } catch (Throwable __e) {
          printStackTrace(__e);
        }
      }
      sleepInCleanUp(10);
    }
  }

  static public boolean odd(int i) {
    return (i & 1) != 0;
  }

  static public boolean odd(long i) {
    return (i & 1) != 0;
  }

  static public boolean odd(BigInteger i) {
    return odd(toInt(i));
  }

  static public String quote(Object o) {
    if (o == null)
      return "null";
    return quote(str(o));
  }

  static public String quote(String s) {
    if (s == null)
      return "null";
    StringBuilder out = new StringBuilder((int) (l(s) * 1.5 + 2));
    quote_impl(s, out);
    return out.toString();
  }

  static public void quote_impl(String s, StringBuilder out) {
    out.append('"');
    int l = s.length();
    for (int i = 0; i < l; i++) {
      char c = s.charAt(i);
      if (c == '\\' || c == '"')
        out.append('\\').append(c);
      else if (c == '\r')
        out.append("\\r");
      else if (c == '\n')
        out.append("\\n");
      else if (c == '\t')
        out.append("\\t");
      else if (c == '\0')
        out.append("\\0");
      else
        out.append(c);
    }
    out.append('"');
  }

  static public int shorten_default = 100;

  static public String shorten(CharSequence s) {
    return shorten(s, shorten_default);
  }

  static public String shorten(CharSequence s, int max) {
    return shorten(s, max, "...");
  }

  static public String shorten(CharSequence s, int max, String shortener) {
    if (s == null)
      return "";
    if (max < 0)
      return str(s);
    return s.length() <= max ? str(s) : subCharSequence(s, 0, min(s.length(), max - l(shortener))) + shortener;
  }

  static public String shorten(int max, CharSequence s) {
    return shorten(s, max);
  }

  static public int parseHexChar(char c) {
    if (c >= '0' && c <= '9')
      return charDiff(c, '0');
    if (c >= 'a' && c <= 'f')
      return charDiff(c, 'a') + 10;
    if (c >= 'A' && c <= 'F')
      return charDiff(c, 'A') + 10;
    return -1;
  }

  static public boolean domainIsUnder(String domain, String mainDomain) {
    return eqic(domain, mainDomain) || ewic(domain, "." + mainDomain);
  }

  static public String theAGIBlueDomain() {
    return "agi.blue";
  }

  static public String singleFieldName(Class c) {
    Set<String> l = listFields(c);
    if (l(l) != 1)
      throw fail("No single field found in " + c + " (have " + n(l(l), "fields") + ")");
    return first(l);
  }

  static public Object deref(Object o) {
    if (o instanceof IRef)
      return ((IRef) o).get();
    return o;
  }

  static public Object call_withVarargs(Object o, String method, Object... args) {
    try {
      if (o == null)
        return null;
      if (o instanceof Class) {
        Class c = (Class) o;
        _MethodCache cache = callOpt_getCache(c);
        Method me = cache.findStaticMethod(method, args);
        if (me != null)
          return invokeMethod(me, null, args);
        List<Method> methods = cache.cache.get(method);
        if (methods != null)
          methodSearch: for (Method m : methods) {
            {
              if (!(m.isVarArgs()))
                continue;
            }
            {
              if (!(isStaticMethod(m)))
                continue;
            }
            Object[] newArgs = massageArgsForVarArgsCall(m, args);
            if (newArgs != null)
              return invokeMethod(m, null, newArgs);
          }
        throw fail("Method " + c.getName() + "." + method + "(" + joinWithComma(classNames(args)) + ") not found");
      } else {
        Class c = o.getClass();
        _MethodCache cache = callOpt_getCache(c);
        Method me = cache.findMethod(method, args);
        if (me != null)
          return invokeMethod(me, o, args);
        List<Method> methods = cache.cache.get(method);
        if (methods != null)
          methodSearch: for (Method m : methods) {
            {
              if (!(m.isVarArgs()))
                continue;
            }
            Object[] newArgs = massageArgsForVarArgsCall(m, args);
            if (newArgs != null)
              return invokeMethod(m, o, newArgs);
          }
        throw fail("Method " + c.getName() + "." + method + "(" + joinWithComma(classNames(args)) + ") not found");
      }
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public <A> WeakReference<A> newWeakReference(A a) {
    return a == null ? null : new WeakReference(a);
  }

  static public String _computerID;

  static public Lock computerID_lock = lock();

  public static String computerID() {
    if (_computerID == null) {
      Lock __0 = computerID_lock;
      lock(__0);
      try {
        if (_computerID != null)
          return _computerID;
        File file = computerIDFile();
        _computerID = loadTextFile(file.getPath());
        if (_computerID == null) {
          _computerID = loadTextFile(userDir(".tinybrain/computer-id"));
          if (_computerID == null)
            _computerID = makeRandomID(12, new SecureRandom());
          saveTextFile(file, _computerID);
        }
      } finally {
        unlock(__0);
      }
    }
    return _computerID;
  }

  static public <A> Set<A> synchroHashSet() {
    return synchronizedSet(new HashSet<A>());
  }

  static public Iterator emptyIterator() {
    return Collections.emptyIterator();
  }

  static public long parseLong(String s) {
    if (empty(s))
      return 0;
    return Long.parseLong(dropSuffix("L", s));
  }

  static public long parseLong(Object s) {
    return Long.parseLong((String) s);
  }

  static public String mainClassNameForClassLoader(ClassLoader cl) {
    return or((String) callOpt(cl, "mainClassName"), "main");
  }

  static public Class loadClassFromClassLoader_orNull(ClassLoader cl, String name) {
    try {
      return cl == null ? null : cl.loadClass(name);
    } catch (ClassNotFoundException e) {
      return null;
    }
  }

  static public <A> ArrayList<A> litlist(A... a) {
    ArrayList l = new ArrayList(a.length);
    for (A x : a) l.add(x);
    return l;
  }

  static public int indexOfIgnoreCase_manual(String a, String b) {
    return indexOfIgnoreCase_manual(a, b, 0);
  }

  static public int indexOfIgnoreCase_manual(String a, String b, int i) {
    int la = strL(a), lb = strL(b);
    if (la < lb)
      return -1;
    int n = la - lb;
    loop: for (; i <= n; i++) {
      for (int j = 0; j < lb; j++) {
        char c1 = a.charAt(i + j), c2 = b.charAt(j);
        if (!eqic(c1, c2))
          continue loop;
      }
      return i;
    }
    return -1;
  }

  static public String asString(Object o) {
    return o == null ? null : o.toString();
  }

  static public String actualUserHome_value;

  static public String actualUserHome() {
    if (actualUserHome_value == null) {
      if (isAndroid())
        actualUserHome_value = "/storage/emulated/0/";
      else
        actualUserHome_value = System.getProperty("user.home");
    }
    return actualUserHome_value;
  }

  static public File actualUserHome(String sub) {
    return newFile(new File(actualUserHome()), sub);
  }

  static public float clamp(float x, float a, float b) {
    return x < a ? a : x > b ? b : x;
  }

  static public double clamp(double x, double a, double b) {
    return x < a ? a : x > b ? b : x;
  }

  static public int clamp(int x, int a, int b) {
    return x < a ? a : x > b ? b : x;
  }

  static public long clamp(long x, long a, long b) {
    return x < a ? a : x > b ? b : x;
  }

  static public BufferedImage drawImage(BufferedImage canvas, Image img, Pt p) {
    return drawImageOnImage(img, canvas, p.x, p.y);
  }

  static public void drawImage(BufferedImage g, Image img) {
    drawImage(graphics(g), img);
  }

  static public void drawImage(Graphics2D g, Image img) {
    drawImage(g, img, 0, 0);
  }

  static public void drawImage(Graphics2D g, Image img, Pt p) {
    drawImage(g, img, p.x, p.y);
  }

  static public void drawImage(Graphics2D g, Image img, int x, int y) {
    {
      if (g != null)
        g.drawImage(img, x, y, null);
    }
  }

  static public void clearTabs(final JTabbedPane tabs) {
    if (tabs != null) {
      swing(() -> {
        tabs.removeAll();
      });
    }
  }

  static public int asInt(Object o) {
    return toInt(o);
  }

  static public Object[] arrayrep(Object a, int n) {
    return asArray(repeat(a, n));
  }

  static public boolean isComponentOrSwingable(Object o) {
    if (o instanceof Swingable)
      return true;
    return o instanceof Component;
  }

  static public void addTab(JTabbedPane tabs, String title, Component c) {
    if (tabs != null) {
      swing(() -> {
        tabs.add(title, wrap(c));
      });
    }
  }

  static public void addTab(JTabbedPane tabs, String title, Swingable c) {
    if (tabs != null) {
      swing(() -> {
        tabs.add(title, wrap(c));
      });
    }
  }

  static public int min(int a, int b) {
    return Math.min(a, b);
  }

  static public long min(long a, long b) {
    return Math.min(a, b);
  }

  static public float min(float a, float b) {
    return Math.min(a, b);
  }

  static public float min(float a, float b, float c) {
    return min(min(a, b), c);
  }

  static public double min(double a, double b) {
    return Math.min(a, b);
  }

  static public double min(double[] c) {
    double x = Double.MAX_VALUE;
    for (double d : c) x = Math.min(x, d);
    return x;
  }

  static public float min(float[] c) {
    float x = Float.MAX_VALUE;
    for (float d : c) x = Math.min(x, d);
    return x;
  }

  static public byte min(byte[] c) {
    byte x = 127;
    for (byte d : c) if (d < x)
      x = d;
    return x;
  }

  static public short min(short[] c) {
    short x = 0x7FFF;
    for (short d : c) if (d < x)
      x = d;
    return x;
  }

  static public int min(int[] c) {
    int x = Integer.MAX_VALUE;
    for (int d : c) if (d < x)
      x = d;
    return x;
  }

  static public int boolToInt(boolean b) {
    return b ? 1 : 0;
  }

  static public boolean endsWithIgnoreCase(String a, String b) {
    int la = l(a), lb = l(b);
    return la >= lb && regionMatchesIC(a, la - lb, b, 0, lb);
  }

  static public boolean endsWithIgnoreCase(String a, String b, Matches m) {
    if (!endsWithIgnoreCase(a, b))
      return false;
    if (m != null)
      m.m = new String[] { substring(a, 0, l(a) - l(b)) };
    return true;
  }

  static public BufferedReader bufferedReader(Reader r) {
    return bufferedReader(r, 8192);
  }

  static public BufferedReader bufferedReader(Reader r, int bufSize) {
    if (r == null)
      return null;
    return r instanceof BufferedReader ? (BufferedReader) r : _registerIOWrap(new BufferedReader(r, bufSize), r);
  }

  static public <A extends AutoCloseable> A holdResource(IResourceHolder holder, A a) {
    {
      if (holder != null)
        holder.add(a);
    }
    return a;
  }

  static public <A> CloseableIterableIterator<A> iteratorFromFunction_f0_autoCloseable(final F0<A> f, final AutoCloseable closeable) {
    class IFF2 extends CloseableIterableIterator<A> {

      public A a;

      public boolean done = false;

      public boolean hasNext() {
        getNext();
        return !done;
      }

      public A next() {
        getNext();
        if (done)
          throw fail();
        A _a = a;
        a = null;
        return _a;
      }

      public void getNext() {
        if (done || a != null)
          return;
        a = f.get();
        done = a == null;
      }

      public void close() throws Exception {
        if (closeable != null)
          closeable.close();
      }
    }
    ;
    return new IFF2();
  }

  static public String readLineFromReaderWithClose(BufferedReader r) {
    try {
      String s = r.readLine();
      if (s == null)
        r.close();
      return s;
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public AutoCloseable _wrapIOCloseable(final AutoCloseable c) {
    return c == null ? null : new AutoCloseable() {

      public String toString() {
        return "c.close();\r\n    _registerIO(c, null, false);";
      }

      public void close() throws Exception {
        c.close();
        _registerIO(c, null, false);
      }
    };
  }

  static public <A> A _registerIOWrap(A wrapper, Object wrapped) {
    return wrapper;
  }

  static public FileInputStream newFileInputStream(File path) throws IOException {
    return newFileInputStream(path.getPath());
  }

  static public FileInputStream newFileInputStream(String path) throws IOException {
    FileInputStream f = new FileInputStream(path);
    _registerIO(f, path, true);
    return f;
  }

  static public int gzInputStream_defaultBufferSize = 65536;

  static public GZIPInputStream gzInputStream(File f) {
    try {
      return gzInputStream(new FileInputStream(f));
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public GZIPInputStream gzInputStream(File f, int bufferSize) {
    try {
      return gzInputStream(new FileInputStream(f), bufferSize);
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public GZIPInputStream gzInputStream(InputStream in) {
    return gzInputStream(in, gzInputStream_defaultBufferSize);
  }

  static public GZIPInputStream gzInputStream(InputStream in, int bufferSize) {
    try {
      return _registerIOWrap(new GZIPInputStream(in, gzInputStream_defaultBufferSize), in);
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public boolean isInstance(Class type, Object arg) {
    return type.isInstance(arg);
  }

  static public List<String> classNames(Collection l) {
    return getClassNames(l);
  }

  static public List<String> classNames(Object[] l) {
    return getClassNames(Arrays.asList(l));
  }

  static public boolean argumentCompatibleWithType(Object arg, Class type) {
    return arg == null ? !type.isPrimitive() : isInstanceX(type, arg);
  }

  static public void arraycopy(Object[] a, Object[] b) {
    if (a != null && b != null)
      arraycopy(a, 0, b, 0, Math.min(a.length, b.length));
  }

  static public void arraycopy(Object src, int srcPos, int destPos, int n) {
    arraycopy(src, srcPos, src, destPos, n);
  }

  static public void arraycopy(Object src, int srcPos, Object dest, int destPos, int n) {
    if (n != 0)
      System.arraycopy(src, srcPos, dest, destPos, n);
  }

  static public <A> A[] arrayOfType(Class<A> type, int n) {
    return makeArray(type, n);
  }

  static public <A> A[] arrayOfType(int n, Class<A> type) {
    return arrayOfType(type, n);
  }

  static public <A> A proxy(Class<A> intrface, final Object target) {
    if (target == null)
      return null;
    if (isInstance(intrface, target))
      return (A) target;
    return (A) java.lang.reflect.Proxy.newProxyInstance(intrface.getClassLoader(), new Class[] { intrface }, new proxy_InvocationHandler(target));
  }

  static public <A> A proxy(Object target, Class<A> intrface) {
    return proxy(intrface, target);
  }

  static public File javaxCachesDir_dir;

  static public File javaxCachesDir() {
    return javaxCachesDir_dir != null ? javaxCachesDir_dir : new File(userHome(), "JavaX-Caches");
  }

  static public File javaxCachesDir(String sub) {
    return newFile(javaxCachesDir(), sub);
  }

  static public String snippetImageURL(long snippetID) {
    return snippetImageURL(fsI(snippetID));
  }

  static public String snippetImageURL(String snippetID) {
    return snippetImageURL(snippetID, "png");
  }

  static public String snippetImageURL(String snippetID, String contentType) {
    if (snippetID == null || isURL(snippetID))
      return snippetID;
    long id = parseSnippetID(snippetID);
    String url;
    if (isImageServerSnippet(id))
      url = imageServerLink(id);
    else
      url = "https://botcompany.de/img/" + id;
    return url;
  }

  static public File imageSnippetCacheFile(String snippetID) {
    File dir = imageSnippetsCacheDir();
    if (!loadBufferedImage_useImageCache)
      return null;
    return new File(dir, parseSnippetID(snippetID) + ".png");
  }

  static public String snippetImageURL_noHttps(String snippetID) {
    return snippetImageURL_noHttps(snippetID, "png");
  }

  static public String snippetImageURL_noHttps(String snippetID, String contentType) {
    return snippetImageURL(snippetID, contentType).replace("https://www.botcompany.de:8443/", "http://www.botcompany.de:8080/").replace("https://botcompany.de/", "http://botcompany.de/");
  }

  static public ThreadLocal<Map<String, List<String>>> loadBinaryPage_responseHeaders = new ThreadLocal();

  static public ThreadLocal<Map<String, String>> loadBinaryPage_extraHeaders = new ThreadLocal();

  static public byte[] loadBinaryPage(String url) {
    try {
      print("Loading " + url);
      return loadBinaryPage(loadPage_openConnection(new URL(url)));
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public byte[] loadBinaryPage(URLConnection con) {
    try {
      Map<String, String> extraHeaders = getAndClearThreadLocal(loadBinaryPage_extraHeaders);
      setHeaders(con);
      for (String key : keys(extraHeaders)) con.setRequestProperty(key, extraHeaders.get(key));
      return loadBinaryPage_noHeaders(con);
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public byte[] loadBinaryPage_noHeaders(URLConnection con) {
    try {
      ByteArrayOutputStream buf = new ByteArrayOutputStream();
      InputStream inputStream = con.getInputStream();
      loadBinaryPage_responseHeaders.set(con.getHeaderFields());
      long len = 0;
      try {
        len = con.getContentLength();
      } catch (Throwable e) {
        printStackTrace(e);
      }
      int n = 0;
      while (true) {
        int ch = inputStream.read();
        if (ch < 0)
          break;
        buf.write(ch);
        if (++n % 100000 == 0)
          println("  " + n + (len != 0 ? "/" + len : "") + " bytes loaded.");
      }
      inputStream.close();
      return buf.toByteArray();
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  public static byte[] saveBinaryFile(String fileName, byte[] contents) {
    try {
      File file = new File(fileName);
      File parentFile = file.getParentFile();
      if (parentFile != null)
        parentFile.mkdirs();
      String tempFileName = fileName + "_temp";
      FileOutputStream fileOutputStream = newFileOutputStream(tempFileName);
      fileOutputStream.write(contents);
      fileOutputStream.close();
      if (file.exists() && !file.delete())
        throw new IOException("Can't delete " + fileName);
      if (!new File(tempFileName).renameTo(file))
        throw new IOException("Can't rename " + tempFileName + " to " + fileName);
      vmBus_send("wroteFile", file);
      return contents;
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public byte[] saveBinaryFile(File fileName, byte[] contents) {
    return saveBinaryFile(fileName.getPath(), contents);
  }

  static public File getGlobalCache() {
    File file = new File(javaxCachesDir(), "Binary Snippets");
    file.mkdirs();
    return file;
  }

  static public String dataSnippetLink(String snippetID) {
    long id = parseSnippetID(snippetID);
    if (id >= 1100000 && id < 1200000)
      return imageServerURL() + id;
    if (id >= 1200000 && id < 1300000) {
      String pw = muricaPassword();
      if (empty(pw))
        throw fail("Please set 'murica password by running #1008829");
      return "https://botcompany.de/files/" + id + "?_pass=" + pw;
    }
    return fileServerURL() + "/" + id;
  }

  static public <B, A extends B> A addAndReturn(Collection<B> c, A a) {
    if (c != null)
      c.add(a);
    return a;
  }

  static public List<String> allToString(Iterable c) {
    List<String> l = new ArrayList();
    for (Object o : unnull(c)) l.add(str(o));
    return l;
  }

  static public List<String> allToString(Object[] c) {
    List<String> l = new ArrayList();
    for (Object o : unnull(c)) l.add(str(o));
    return l;
  }

  static public boolean byteArrayStartsWith(byte[] a, byte[] b) {
    if (a == null || b == null)
      return false;
    if (a.length < b.length)
      return false;
    for (int i = 0; i < b.length; i++) if (a[i] != b[i])
      return false;
    return true;
  }

  static public byte[] loadBeginningOfBinaryFile(File file, int maxBytes) {
    return loadBinaryFilePart(file, 0, maxBytes);
  }

  static public boolean isEmpty(Collection c) {
    return c == null || c.isEmpty();
  }

  static public boolean isEmpty(CharSequence s) {
    return s == null || s.length() == 0;
  }

  static public boolean isEmpty(Object[] a) {
    return a == null || a.length == 0;
  }

  static public boolean isEmpty(byte[] a) {
    return a == null || a.length == 0;
  }

  static public boolean isEmpty(Map map) {
    return map == null || map.isEmpty();
  }

  static public boolean isEmpty(DoubleRange r) {
    return r == null || r.isEmpty();
  }

  static public JInternalFrame getInternalFrame(final Object _o) {
    return _o == null ? null : swing(new F0<JInternalFrame>() {

      public JInternalFrame get() {
        try {
          Object o = _o;
          if (o instanceof ButtonGroup)
            o = first(buttonsInGroup((ButtonGroup) o));
          if (!(o instanceof Component))
            return null;
          Component c = (Component) o;
          while (c != null) {
            if (c instanceof JInternalFrame)
              return (JInternalFrame) c;
            c = c.getParent();
          }
          return null;
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "O o = _o;\r\n    if (o instanceof ButtonGroup) o = first(buttonsInGroup((Button...";
      }
    });
  }

  static public String appendQueryToURL(String url, Map params) {
    if (url == null)
      return null;
    String data = makePostData(params);
    if (empty(data))
      return url;
    int idx = smartIndexOf(url, '#');
    String url2 = takeFirst(url, idx);
    return url2 + (url2.contains("?") ? "&" : "?") + data + substring(url, idx);
  }

  static public String appendQueryToURL(String url, Object... data) {
    return appendQueryToURL(url, paramsToMap(data));
  }

  static public ThreadLocal<Boolean> doPost_silently = new ThreadLocal();

  static public ThreadLocal<Long> doPost_timeout = new ThreadLocal();

  static public ThreadLocal<Map<String, String>> doPost_extraHeaders = new ThreadLocal();

  static public String doPost(String url, Map urlParameters) {
    return doPost(urlParameters, url);
  }

  static public String doPost(Map urlParameters, String url) {
    return doPost(makePostData(urlParameters), url);
  }

  static public String doPost(String urlParameters, String url) {
    try {
      URL _url = new URL(url);
      ping();
      return doPost(urlParameters, _url.openConnection(), _url);
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public String doPost(String urlParameters, URLConnection conn, URL url) {
    try {
      boolean silently = isTrue(optParam(doPost_silently));
      Long timeout = optParam(doPost_timeout);
      Map<String, String> extraHeaders = optPar(doPost_extraHeaders);
      setHeaders(conn);
      for (String key : keys(extraHeaders)) {
        conn.setRequestProperty(key, extraHeaders.get(key));
      }
      int l = lUtf8(urlParameters);
      if (!silently)
        print("Sending POST request: " + hideCredentials(url) + " (" + l + " bytes)");
      if (timeout != null)
        setURLConnectionTimeouts(conn, timeout);
      ((HttpURLConnection) conn).setRequestMethod("POST");
      conn.setDoOutput(true);
      conn.setRequestProperty("Content-Length", str(l));
      OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
      writer.write(urlParameters);
      writer.flush();
      String contents = loadPage_utf8(conn, url, false);
      writer.close();
      return contents;
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public String htmldecode(final String input) {
    if (input == null)
      return null;
    final int MIN_ESCAPE = 2;
    final int MAX_ESCAPE = 6;
    StringWriter writer = null;
    int len = input.length();
    int i = 1;
    int st = 0;
    while (true) {
      while (i < len && input.charAt(i - 1) != '&') i++;
      if (i >= len)
        break;
      int j = i;
      while (j < len && j < i + MAX_ESCAPE + 1 && input.charAt(j) != ';') j++;
      if (j == len || j < i + MIN_ESCAPE || j == i + MAX_ESCAPE + 1) {
        i++;
        continue;
      }
      if (input.charAt(i) == '#') {
        int k = i + 1;
        int radix = 10;
        final char firstChar = input.charAt(k);
        if (firstChar == 'x' || firstChar == 'X') {
          k++;
          radix = 16;
        }
        try {
          int entityValue = Integer.parseInt(input.substring(k, j), radix);
          if (writer == null)
            writer = new StringWriter(input.length());
          writer.append(input.substring(st, i - 1));
          if (entityValue > 0xFFFF) {
            final char[] chrs = Character.toChars(entityValue);
            writer.write(chrs[0]);
            writer.write(chrs[1]);
          } else {
            writer.write(entityValue);
          }
        } catch (NumberFormatException ex) {
          i++;
          continue;
        }
      } else {
        CharSequence value = htmldecode_lookupMap().get(input.substring(i, j));
        if (value == null) {
          i++;
          continue;
        }
        if (writer == null)
          writer = new StringWriter(input.length());
        writer.append(input.substring(st, i - 1));
        writer.append(value);
      }
      st = j + 1;
      i = st;
    }
    if (writer != null) {
      writer.append(input.substring(st, len));
      return writer.toString();
    }
    return input;
  }

  static public HashMap<String, CharSequence> htmldecode_lookupMap_cache;

  static public HashMap<String, CharSequence> htmldecode_lookupMap() {
    if (htmldecode_lookupMap_cache == null)
      htmldecode_lookupMap_cache = htmldecode_lookupMap_load();
    return htmldecode_lookupMap_cache;
  }

  static public HashMap<String, CharSequence> htmldecode_lookupMap_load() {
    var map = new HashMap<String, CharSequence>();
    for (CharSequence[] seq : htmldecode_escapes()) map.put(seq[1].toString(), seq[0]);
    return map;
  }

  static public int getMinimumHeight(final Component c) {
    return getMinimumSize(c).height;
  }

  static public Component addToWindow(final Component c, final Component toAdd) {
    if (toAdd != null) {
      swing(() -> {
        JFrame frame = getFrame(c);
        if (frame == null)
          return;
        setContentPane(frame, centerAndSouth(frame.getContentPane(), toAdd));
      });
    }
    return c;
  }

  static public void growWindowSouth(Component c, final int howMuch) {
    final Window w = getWindow(c);
    if (w != null) {
      swing(() -> {
        Rectangle r = w.getBounds();
        w.setBounds(r.x, r.y, r.width, r.height + howMuch);
      });
    }
  }

  static public int hstackWithSpacing_spacing = 10;

  static public JPanel hstackWithSpacing(Object... parts) {
    parts = flattenArray2(parts);
    int spacing = hstackWithSpacing_spacing;
    int i = 0;
    if (first(parts) instanceof Integer) {
      spacing = toInt(first(parts));
      ++i;
    }
    JPanel panel = new JPanel(new GridBagLayout());
    GridBagConstraints gbc = new GridBagConstraints();
    gbc.weighty = 1;
    gbc.fill = GridBagConstraints.VERTICAL;
    gbc.gridheight = GridBagConstraints.REMAINDER;
    for (; i < l(parts); i++) {
      if (i != 0)
        panel.add(javax.swing.Box.createRigidArea(new Dimension(spacing, 0)), gbc);
      panel.add(wrapForSmartAdd(parts[i]), gbc);
    }
    gbc.weightx = 1;
    panel.add(jrigid(), gbc);
    return panel;
  }

  static public Class<?> _getClass(String name) {
    try {
      return Class.forName(name);
    } catch (ClassNotFoundException e) {
      return null;
    }
  }

  static public Class _getClass(Object o) {
    return o == null ? null : o instanceof Class ? (Class) o : o.getClass();
  }

  static public Class _getClass(Object realm, String name) {
    try {
      return classLoaderForObject(realm).loadClass(classNameToVM(name));
    } catch (ClassNotFoundException e) {
      return null;
    }
  }

  static public Throwable _storeException_value;

  static public void _storeException(Throwable e) {
    _storeException_value = e;
  }

  static public File oneOfTheFilesInDir(File dir, String... names) {
    return oneOfTheFiles(map(names, name -> newFile(dir, name)));
  }

  static public int lastIndexOf(String a, String b) {
    return a == null || b == null ? -1 : a.lastIndexOf(b);
  }

  static public int lastIndexOf(String a, char b) {
    return a == null ? -1 : a.lastIndexOf(b);
  }

  static public <A> int lastIndexOf(List<A> l, int i, A a) {
    if (l == null)
      return -1;
    for (i = min(l(l), i) - 1; i >= 0; i--) if (eq(l.get(i), a))
      return i;
    return -1;
  }

  static public <A> int lastIndexOf(List<A> l, A a) {
    if (l == null)
      return -1;
    for (int i = l(l) - 1; i >= 0; i--) if (eq(l.get(i), a))
      return i;
    return -1;
  }

  static public <A> List<A> synchroList() {
    return synchroList(new ArrayList<A>());
  }

  static public <A> List<A> synchroList(List<A> l) {
    return new SynchronizedList(l);
  }

  static public List collect(Iterable c, String field) {
    return collectField(c, field);
  }

  static public List collect(String field, Iterable c) {
    return collectField(c, field);
  }

  static public void sleepInCleanUp(long ms) {
    try {
      if (ms < 0)
        return;
      Thread.sleep(ms);
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public CharSequence subCharSequence(CharSequence s, int x) {
    return subCharSequence(s, x, s == null ? 0 : s.length());
  }

  static public CharSequence subCharSequence(CharSequence s, int x, int y) {
    if (s == null)
      return null;
    if (x < 0)
      x = 0;
    if (x >= s.length())
      return "";
    if (y < x)
      y = x;
    if (y > s.length())
      y = s.length();
    return s.subSequence(x, y);
  }

  static public int charDiff(char a, char b) {
    return (int) a - (int) b;
  }

  static public int charDiff(String a, char b) {
    return charDiff(stringToChar(a), b);
  }

  static public Set<String> listFields(Object c) {
    TreeSet<String> fields = new TreeSet();
    for (Field f : _getClass(c).getDeclaredFields()) fields.add(f.getName());
    return fields;
  }

  static public boolean isStaticMethod(Method m) {
    return methodIsStatic(m);
  }

  static public <A> String joinWithComma(Collection<A> c) {
    return join(", ", c);
  }

  static public String joinWithComma(Object... c) {
    return join(", ", c);
  }

  static public String joinWithComma(String... c) {
    return join(", ", c);
  }

  static public String joinWithComma(Pair p) {
    return p == null ? "" : joinWithComma(str(p.a), str(p.b));
  }

  static public File computerIDFile() {
    return javaxDataDir("Basic Info/computer-id.txt");
  }

  static public String makeRandomID(int length) {
    return makeRandomID(length, defaultRandomGenerator());
  }

  static public String makeRandomID(int length, Random random) {
    char[] id = new char[length];
    for (int i = 0; i < id.length; i++) id[i] = (char) ((int) 'a' + random.nextInt(26));
    return new String(id);
  }

  static public String makeRandomID(Random r, int length) {
    return makeRandomID(length, r);
  }

  static public File saveTextFile(String fileName, String contents) throws IOException {
    CriticalAction action = beginCriticalAction("Saving file " + fileName + " (" + l(contents) + " chars)");
    try {
      File file = new File(fileName);
      mkdirsForFile(file);
      String tempFileName = fileName + "_temp";
      File tempFile = new File(tempFileName);
      if (contents != null) {
        if (tempFile.exists())
          try {
            String saveName = tempFileName + ".saved." + now();
            copyFile(tempFile, new File(saveName));
          } catch (Throwable e) {
            printStackTrace(e);
          }
        FileOutputStream fileOutputStream = newFileOutputStream(tempFile.getPath());
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "UTF-8");
        PrintWriter printWriter = new PrintWriter(outputStreamWriter);
        printWriter.print(contents);
        printWriter.close();
      }
      if (file.exists() && !file.delete())
        throw new IOException("Can't delete " + fileName);
      if (contents != null)
        if (!tempFile.renameTo(file))
          throw new IOException("Can't rename " + tempFile + " to " + file);
      vmBus_send("wroteFile", file);
      return file;
    } finally {
      action.done();
    }
  }

  static public File saveTextFile(File fileName, String contents) {
    try {
      saveTextFile(fileName.getPath(), contents);
      return fileName;
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public String dropSuffix(String suffix, String s) {
    return nempty(suffix) && endsWith(s, suffix) ? s.substring(0, l(s) - l(suffix)) : s;
  }

  static public BufferedImage drawImageOnImage(Image img, BufferedImage canvas, int x, int y) {
    createGraphics(canvas).drawImage(img, x, y, null);
    return canvas;
  }

  static public Graphics2D graphics(BufferedImage img) {
    return imageGraphics(img);
  }

  static public List<String> getClassNames(Collection l) {
    List<String> out = new ArrayList();
    if (l != null)
      for (Object o : l) out.add(o == null ? null : getClassName(o));
    return out;
  }

  static public <A> A[] makeArray(Class<A> type, int n) {
    return (A[]) Array.newInstance(type, n);
  }

  static public String imageServerLink(String md5OrID) {
    if (possibleMD5(md5OrID))
      return "https://botcompany.de/images/md5/" + md5OrID;
    return imageServerLink(parseSnippetID(md5OrID));
  }

  static public String imageServerLink(long id) {
    return "https://botcompany.de/images/" + id;
  }

  static public int loadPage_defaultTimeout = 60000;

  static public ThreadLocal<String> loadPage_charset = new ThreadLocal();

  static public boolean loadPage_allowGzip = true, loadPage_debug;

  static public boolean loadPage_anonymous = false;

  static public int loadPage_verboseness = 100000;

  static public int loadPage_retries = 1;

  static public ThreadLocal<Boolean> loadPage_silent = new ThreadLocal();

  static volatile public int loadPage_forcedTimeout;

  static public ThreadLocal<Integer> loadPage_forcedTimeout_byThread = new ThreadLocal();

  static public ThreadLocal<Map<String, List<String>>> loadPage_responseHeaders = new ThreadLocal();

  static public ThreadLocal<Map<String, String>> loadPage_extraHeaders = new ThreadLocal();

  static public ThreadLocal<Long> loadPage_sizeLimit = new ThreadLocal();

  public static String loadPageSilently(String url) {
    try {
      return loadPageSilently(new URL(loadPage_preprocess(url)));
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  public static String loadPageSilently(URL url) {
    try {
      if (!networkAllowanceTest(str(url)))
        throw fail("Not allowed: " + url);
      IOException e = null;
      for (int tries = 0; tries < loadPage_retries; tries++) try {
        URLConnection con = loadPage_openConnection(url);
        return loadPage(con, url);
      } catch (IOException _e) {
        e = _e;
        if (loadPage_debug)
          print(exceptionToStringShort(e));
        if (tries < loadPage_retries - 1)
          sleepSeconds(1);
      }
      throw e;
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public String loadPage_preprocess(String url) {
    if (url.startsWith("tb/"))
      url = tb_mainServer() + "/" + url;
    if (url.indexOf("://") < 0)
      url = "http://" + url;
    return url;
  }

  static public String loadPage(String url) {
    try {
      url = loadPage_preprocess(url);
      if (!isTrue(loadPage_silent.get()))
        printWithTime("Loading: " + hideCredentials(url));
      return loadPageSilently(new URL(url));
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public String loadPage(URL url) {
    return loadPage(url.toExternalForm());
  }

  static public String loadPage(URLConnection con, URL url) throws IOException {
    return loadPage(con, url, true);
  }

  static public String loadPage(URLConnection con, URL url, boolean addHeaders) throws IOException {
    Map<String, String> extraHeaders = getAndClearThreadLocal(loadPage_extraHeaders);
    Long limit = optPar(loadPage_sizeLimit);
    if (addHeaders)
      try {
        if (!loadPage_anonymous)
          setHeaders(con);
        if (loadPage_allowGzip)
          con.setRequestProperty("Accept-Encoding", "gzip");
        con.setRequestProperty("X-No-Cookies", "1");
        for (String key : keys(extraHeaders)) con.setRequestProperty(key, extraHeaders.get(key));
      } catch (Throwable e) {
      }
    vm_generalSubMap("URLConnection per thread").put(currentThread(), con);
    loadPage_responseHeaders.set(con.getHeaderFields());
    InputStream in = null;
    try {
      in = urlConnection_getInputStream(con);
      if (loadPage_debug)
        print("Put stream in map: " + currentThread());
      String contentType = con.getContentType();
      if (contentType == null) {
        throw new IOException("Page could not be read: " + hideCredentials(url));
      }
      String charset = loadPage_charset == null ? null : loadPage_charset.get();
      if (charset == null)
        charset = loadPage_guessCharset(contentType);
      if ("gzip".equals(con.getContentEncoding())) {
        if (loadPage_debug)
          print("loadPage: Using gzip.");
        in = newGZIPInputStream(in);
      }
      Reader r;
      try {
        r = new InputStreamReader(in, unquote(charset));
      } catch (UnsupportedEncodingException e) {
        print(toHex(utf8(charset)));
        throw e;
      }
      boolean silent = isTrue(loadPage_silent.get());
      StringBuilder buf = new StringBuilder();
      int n = 0;
      while (limit == null || n < limit) {
        ping();
        int ch = r.read();
        if (ch < 0)
          break;
        buf.append((char) ch);
        ++n;
        if (!silent && (n % loadPage_verboseness) == 0)
          print("  " + n + " chars read");
      }
      return buf.toString();
    } finally {
      if (loadPage_debug)
        print("loadPage done");
      vm_generalSubMap("URLConnection per thread").remove(currentThread());
      if (in != null)
        in.close();
    }
  }

  static public String loadPage_guessCharset(String contentType) {
    Matcher m = regexpMatcher("text/[a-z]+;\\s*charset=([^\\s]+)\\s*", contentType);
    String match = m.matches() ? m.group(1) : null;
    if (loadPage_debug)
      print("loadPage: contentType=" + contentType + ", match: " + match);
    return or(match, "UTF-8");
  }

  static public URLConnection loadPage_openConnection(URL url) {
    URLConnection con = openConnection(url);
    int timeout = toInt(loadPage_forcedTimeout_byThread.get());
    if (timeout == 0)
      timeout = loadPage_forcedTimeout;
    if (timeout != 0)
      setURLConnectionTimeouts(con, loadPage_forcedTimeout);
    else
      setURLConnectionDefaultTimeouts(con, loadPage_defaultTimeout);
    return con;
  }

  static public <A> A getAndClearThreadLocal(ThreadLocal<A> tl) {
    A a = tl.get();
    tl.set(null);
    return a;
  }

  static public <A> A println(A a) {
    return print(a);
  }

  static public String imageServerURL() {
    return or2(trim(loadTextFile(javaxDataDir("image-server-url.txt"))), "http://botcompany.de/images/raw/");
  }

  static public String fileServerURL() {
    return "https://botcompany.de/files";
  }

  static public byte[] loadBinaryFilePart(File file, long start, long end) {
    try {
      RandomAccessFile raf = new RandomAccessFile(file, "r");
      int n = toInt(min(raf.length(), end - start));
      byte[] buffer = new byte[n];
      try {
        raf.seek(start);
        raf.readFully(buffer, 0, n);
        return buffer;
      } finally {
        raf.close();
      }
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public List<AbstractButton> buttonsInGroup(ButtonGroup g) {
    if (g == null)
      return ll();
    return asList(g.getElements());
  }

  static public String makePostData(Map map) {
    StringBuilder buf = new StringBuilder();
    for (Map.Entry<Object, Object> e : castMapToMapO(map).entrySet()) {
      String key = (String) (e.getKey());
      Object val = e.getValue();
      if (val != null) {
        String value = str(val);
        if (nempty(buf))
          buf.append("&");
        buf.append(urlencode(key)).append("=").append(urlencode((value)));
      }
    }
    return str(buf);
  }

  static public String makePostData(Object... params) {
    StringBuilder buf = new StringBuilder();
    int n = l(params);
    for (int i = 0; i + 1 < n; i += 2) {
      String key = (String) (params[i]);
      Object val = params[i + 1];
      if (val != null) {
        String value = str(val);
        if (nempty(buf))
          buf.append("&");
        buf.append(urlencode(key)).append("=").append(urlencode((value)));
      }
    }
    return str(buf);
  }

  static public <A> A optParam(ThreadLocal<A> tl, A defaultValue) {
    return optPar(tl, defaultValue);
  }

  static public <A> A optParam(ThreadLocal<A> tl) {
    return optPar(tl);
  }

  static public Object optParam(String name, Map params) {
    return mapGet(params, name);
  }

  static public <A> A optParam(Object[] opt, String name, A defaultValue) {
    int n = l(opt);
    if (n == 1 && opt[0] instanceof Map) {
      Map map = (Map) (opt[0]);
      return map.containsKey(name) ? (A) map.get(name) : defaultValue;
    }
    if (!even(l(opt)))
      throw fail("Odd parameter length");
    for (int i = 0; i < l(opt); i += 2) if (eq(opt[i], name))
      return (A) opt[i + 1];
    return defaultValue;
  }

  static public Object optParam(Object[] opt, String name) {
    return optParam(opt, name, null);
  }

  static public Object optParam(String name, Object[] params) {
    return optParam(params, name);
  }

  static public <A> A optPar(ThreadLocal<A> tl, A defaultValue) {
    A a = tl.get();
    if (a != null) {
      tl.set(null);
      return a;
    }
    return defaultValue;
  }

  static public <A> A optPar(ThreadLocal<A> tl) {
    return optPar(tl, null);
  }

  static public Object optPar(Object[] params, String name) {
    return optParam(params, name);
  }

  static public Object optPar(String name, Object[] params) {
    return optParam(params, name);
  }

  static public Object optPar(String name, Map params) {
    return optParam(name, params);
  }

  static public <A> A optPar(Object[] params, String name, A defaultValue) {
    return optParam(params, name, defaultValue);
  }

  static public <A> A optPar(String name, Object[] params, A defaultValue) {
    return optParam(params, name, defaultValue);
  }

  static public int lUtf8(String s) {
    return l(utf8(s));
  }

  static public URLConnection setURLConnectionTimeouts(URLConnection con, long timeout) {
    con.setConnectTimeout(toInt(timeout));
    con.setReadTimeout(toInt(timeout));
    if (con.getConnectTimeout() != timeout || con.getReadTimeout() != timeout)
      print("Warning: Timeouts not set by JDK.");
    return con;
  }

  static public String[][] htmldecode_escapes() {
    return htmldecode_ESCAPES;
  }

  static final public String[][] htmldecode_ESCAPES = { { "\"", "quot" }, { "&", "amp" }, { "<", "lt" }, { ">", "gt" }, { "\u00A0", "nbsp" }, { "\u00A1", "iexcl" }, { "\u00A2", "cent" }, { "\u00A3", "pound" }, { "\u00A4", "curren" }, { "\u00A5", "yen" }, { "\u00A6", "brvbar" }, { "\u00A7", "sect" }, { "\u00A8", "uml" }, { "\u00A9", "copy" }, { "\u00AA", "ordf" }, { "\u00AB", "laquo" }, { "\u00AC", "not" }, { "\u00AD", "shy" }, { "\u00AE", "reg" }, { "\u00AF", "macr" }, { "\u00B0", "deg" }, { "\u00B1", "plusmn" }, { "\u00B2", "sup2" }, { "\u00B3", "sup3" }, { "\u00B4", "acute" }, { "\u00B5", "micro" }, { "\u00B6", "para" }, { "\u00B7", "middot" }, { "\u00B8", "cedil" }, { "\u00B9", "sup1" }, { "\u00BA", "ordm" }, { "\u00BB", "raquo" }, { "\u00BC", "frac14" }, { "\u00BD", "frac12" }, { "\u00BE", "frac34" }, { "\u00BF", "iquest" }, { "\u00C0", "Agrave" }, { "\u00C1", "Aacute" }, { "\u00C2", "Acirc" }, { "\u00C3", "Atilde" }, { "\u00C4", "Auml" }, { "\u00C5", "Aring" }, { "\u00C6", "AElig" }, { "\u00C7", "Ccedil" }, { "\u00C8", "Egrave" }, { "\u00C9", "Eacute" }, { "\u00CA", "Ecirc" }, { "\u00CB", "Euml" }, { "\u00CC", "Igrave" }, { "\u00CD", "Iacute" }, { "\u00CE", "Icirc" }, { "\u00CF", "Iuml" }, { "\u00D0", "ETH" }, { "\u00D1", "Ntilde" }, { "\u00D2", "Ograve" }, { "\u00D3", "Oacute" }, { "\u00D4", "Ocirc" }, { "\u00D5", "Otilde" }, { "\u00D6", "Ouml" }, { "\u00D7", "times" }, { "\u00D8", "Oslash" }, { "\u00D9", "Ugrave" }, { "\u00DA", "Uacute" }, { "\u00DB", "Ucirc" }, { "\u00DC", "Uuml" }, { "\u00DD", "Yacute" }, { "\u00DE", "THORN" }, { "\u00DF", "szlig" }, { "\u00E0", "agrave" }, { "\u00E1", "aacute" }, { "\u00E2", "acirc" }, { "\u00E3", "atilde" }, { "\u00E4", "auml" }, { "\u00E5", "aring" }, { "\u00E6", "aelig" }, { "\u00E7", "ccedil" }, { "\u00E8", "egrave" }, { "\u00E9", "eacute" }, { "\u00EA", "ecirc" }, { "\u00EB", "euml" }, { "\u00EC", "igrave" }, { "\u00ED", "iacute" }, { "\u00EE", "icirc" }, { "\u00EF", "iuml" }, { "\u00F0", "eth" }, { "\u00F1", "ntilde" }, { "\u00F2", "ograve" }, { "\u00F3", "oacute" }, { "\u00F4", "ocirc" }, { "\u00F5", "otilde" }, { "\u00F6", "ouml" }, { "\u00F7", "divide" }, { "\u00F8", "oslash" }, { "\u00F9", "ugrave" }, { "\u00FA", "uacute" }, { "\u00FB", "ucirc" }, { "\u00FC", "uuml" }, { "\u00FD", "yacute" }, { "\u00FE", "thorn" }, { "\u00FF", "yuml" }, { "\u2013", "ndash" }, { "\u2018", "lsquo" }, { "\u2019", "rsquo" }, { "\u201D", "rdquo" }, { "\u201C", "ldquo" }, { "\u2014", "mdash" }, { "'", "apos" } };

  static public Dimension getMinimumSize(final Component c) {
    return c == null ? null : swing(new F0<Dimension>() {

      public Dimension get() {
        try {
          return c.getMinimumSize();
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret c.getMinimumSize();";
      }
    });
  }

  static public void setContentPane(final JFrame frame, final Container c) {
    {
      swing(() -> {
        frame.setContentPane(c);
        revalidate(frame);
      });
    }
  }

  static public ClassLoader classLoaderForObject(Object o) {
    if (o instanceof ClassLoader)
      return ((ClassLoader) o);
    if (o == null)
      return null;
    return _getClass(o).getClassLoader();
  }

  static public String classNameToVM(String name) {
    return name.replace(".", "$");
  }

  static public File oneOfTheFiles(String... paths) {
    if (paths != null)
      for (String path : paths) if (fileExists(path))
        return newFile(path);
    return null;
  }

  static public File oneOfTheFiles(File... files) {
    return oneOfTheFiles(asList(files));
  }

  static public File oneOfTheFiles(Iterable<File> files) {
    if (files != null)
      for (File f : files) if (fileExists(f))
        return f;
    return null;
  }

  static public List collectField(Iterable c, String field) {
    List l = new ArrayList();
    if (c != null)
      for (Object a : c) l.add(getOpt(a, field));
    return l;
  }

  static public List collectField(String field, Iterable c) {
    return collectField(c, field);
  }

  static public char stringToChar(String s) {
    if (l(s) != 1)
      throw fail("bad stringToChar: " + s);
    return firstChar(s);
  }

  static public boolean methodIsStatic(Method m) {
    return (m.getModifiers() & Modifier.STATIC) != 0;
  }

  static public Random defaultRandomGenerator() {
    return ThreadLocalRandom.current();
  }

  static public long now_virtualTime;

  static public long now() {
    return now_virtualTime != 0 ? now_virtualTime : System.currentTimeMillis();
  }

  static public boolean endsWith(String a, String b) {
    return a != null && a.endsWith(b);
  }

  static public boolean endsWith(String a, char c) {
    return nempty(a) && lastChar(a) == c;
  }

  static public boolean endsWith(String a, String b, Matches m) {
    if (!endsWith(a, b))
      return false;
    m.m = new String[] { dropLast(l(b), a) };
    return true;
  }

  static public ThreadLocal<Boolean> imageGraphics_antiAlias = new ThreadLocal();

  static public Graphics2D imageGraphics(BufferedImage img) {
    return !isFalse(imageGraphics_antiAlias.get()) ? antiAliasGraphics(img) : createGraphics(img);
  }

  static public boolean possibleMD5(String s) {
    return isMD5(s);
  }

  static public boolean networkAllowanceTest(String url) {
    return isAllowed("networkAllowanceTest", url);
  }

  static public void sleepSeconds(double s) {
    if (s > 0)
      sleep(round(s * 1000));
  }

  static public <A> A printWithTime(A a) {
    return printWithTime("", a);
  }

  static public <A> A printWithTime(String s, A a) {
    print(hmsWithColons() + ": " + s, a);
    return a;
  }

  static public Map vm_generalSubMap(Object name) {
    synchronized (vm_generalMap()) {
      Map map = (Map) (vm_generalMap_get(name));
      if (map == null)
        vm_generalMap_put(name, map = synchroMap());
      return map;
    }
  }

  static public InputStream urlConnection_getInputStream(URLConnection con) throws IOException {
    return con.getInputStream();
  }

  static public String unquote(String s) {
    if (s == null)
      return null;
    if (startsWith(s, '[')) {
      int i = 1;
      while (i < s.length() && s.charAt(i) == '=') ++i;
      if (i < s.length() && s.charAt(i) == '[') {
        String m = s.substring(1, i);
        if (s.endsWith("]" + m + "]"))
          return s.substring(i + 1, s.length() - i - 1);
      }
    }
    if (s.length() > 1) {
      char c = s.charAt(0);
      if (c == '\"' || c == '\'') {
        int l = endsWith(s, c) ? s.length() - 1 : s.length();
        StringBuilder sb = new StringBuilder(l - 1);
        for (int i = 1; i < l; i++) {
          char ch = s.charAt(i);
          if (ch == '\\') {
            char nextChar = (i == l - 1) ? '\\' : s.charAt(i + 1);
            if (nextChar >= '0' && nextChar <= '7') {
              String code = "" + nextChar;
              i++;
              if ((i < l - 1) && s.charAt(i + 1) >= '0' && s.charAt(i + 1) <= '7') {
                code += s.charAt(i + 1);
                i++;
                if ((i < l - 1) && s.charAt(i + 1) >= '0' && s.charAt(i + 1) <= '7') {
                  code += s.charAt(i + 1);
                  i++;
                }
              }
              sb.append((char) Integer.parseInt(code, 8));
              continue;
            }
            switch(nextChar) {
              case '\"':
                ch = '\"';
                break;
              case '\\':
                ch = '\\';
                break;
              case 'b':
                ch = '\b';
                break;
              case 'f':
                ch = '\f';
                break;
              case 'n':
                ch = '\n';
                break;
              case 'r':
                ch = '\r';
                break;
              case 't':
                ch = '\t';
                break;
              case '\'':
                ch = '\'';
                break;
              case 'u':
                if (i >= l - 5) {
                  ch = 'u';
                  break;
                }
                int code = Integer.parseInt("" + s.charAt(i + 2) + s.charAt(i + 3) + s.charAt(i + 4) + s.charAt(i + 5), 16);
                sb.append(Character.toChars(code));
                i += 5;
                continue;
              default:
                ch = nextChar;
            }
            i++;
          }
          sb.append(ch);
        }
        return sb.toString();
      }
    }
    return s;
  }

  static public String toHex(byte[] bytes) {
    return bytesToHex(bytes);
  }

  static public String toHex(byte[] bytes, int ofs, int len) {
    return bytesToHex(bytes, ofs, len);
  }

  static public byte[] utf8(String s) {
    return toUtf8(s);
  }

  static public Matcher regexpMatcher(String pat, String s) {
    return compileRegexp(pat).matcher(unnull(s));
  }

  static public URLConnection setURLConnectionDefaultTimeouts(URLConnection con, long timeout) {
    if (con.getConnectTimeout() == 0) {
      con.setConnectTimeout(toInt(timeout));
      if (con.getConnectTimeout() != timeout)
        print("Warning: URL connect timeout not set by JDK.");
    }
    if (con.getReadTimeout() == 0) {
      con.setReadTimeout(toInt(timeout));
      if (con.getReadTimeout() != timeout)
        print("Warning: URL read timeout not set by JDK.");
    }
    return con;
  }

  static public Map<Object, Object> castMapToMapO(Map map) {
    return map;
  }

  static public String urlencode(String x) {
    try {
      return URLEncoder.encode(unnull(x), "UTF-8");
    } catch (UnsupportedEncodingException e) {
      throw new RuntimeException(e);
    }
  }

  static public <A, B> B mapGet(Map<A, B> map, A a) {
    return map == null || a == null ? null : map.get(a);
  }

  static public <A, B> B mapGet(A a, Map<A, B> map) {
    return map == null || a == null ? null : map.get(a);
  }

  static public boolean fileExists(String path) {
    return path != null && new File(path).exists();
  }

  static public boolean fileExists(File f) {
    return f != null && f.exists();
  }

  static public char firstChar(String s) {
    return s.charAt(0);
  }

  static public char lastChar(String s) {
    return empty(s) ? '\0' : s.charAt(l(s) - 1);
  }

  static public <A> A[] dropLast(A[] a) {
    return dropLast(a, 1);
  }

  static public <A> A[] dropLast(A[] a, int n) {
    if (a == null)
      return null;
    n = Math.min(n, a.length);
    A[] b = arrayOfSameType(a, a.length - n);
    System.arraycopy(a, 0, b, 0, b.length);
    return b;
  }

  static public <A> List<A> dropLast(List<A> l) {
    return subList(l, 0, l(l) - 1);
  }

  static public <A> List<A> dropLast(int n, List<A> l) {
    return subList(l, 0, l(l) - n);
  }

  static public <A> List<A> dropLast(Iterable<A> l) {
    return dropLast(asList(l));
  }

  static public String dropLast(String s) {
    return substring(s, 0, l(s) - 1);
  }

  static public String dropLast(String s, int n) {
    return substring(s, 0, l(s) - n);
  }

  static public String dropLast(int n, String s) {
    return dropLast(s, n);
  }

  static public Graphics2D antiAliasGraphics(BufferedImage img) {
    return antiAliasOn(createGraphics(img));
  }

  static public boolean isMD5(String s) {
    return l(s) == 32 && isLowerHexString(s);
  }

  static volatile public Object isAllowed_function;

  static volatile public boolean isAllowed_all = true;

  static public boolean isAllowed(String askingMethod, Object... args) {
    Object f = vm_generalMap_get("isAllowed_function");
    if (f != null && !isTrue(callF(f, askingMethod, args)))
      return false;
    return isAllowed_all || isTrue(callF(isAllowed_function, askingMethod, args));
  }

  static public long round(double d) {
    return Math.round(d);
  }

  static public String round(String s) {
    return roundBracket(s);
  }

  static public Complex round(Complex c) {
    return new Complex(round(c.re), round(c.im));
  }

  static public String hmsWithColons() {
    return hmsWithColons(now());
  }

  static public String hmsWithColons(long time) {
    return new SimpleDateFormat("HH:mm:ss").format(time);
  }

  public static String bytesToHex(byte[] bytes) {
    return bytesToHex(bytes, 0, bytes.length);
  }

  public static String bytesToHex(byte[] bytes, int ofs, int len) {
    StringBuilder stringBuilder = new StringBuilder(len * 2);
    for (int i = 0; i < len; i++) {
      String s = "0" + Integer.toHexString(bytes[ofs + i]);
      stringBuilder.append(s.substring(s.length() - 2, s.length()));
    }
    return stringBuilder.toString();
  }

  static public byte[] toUtf8(String s) {
    try {
      return s.getBytes(utf8charset());
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public Map<String, java.util.regex.Pattern> compileRegexp_cache = syncMRUCache(10);

  static public java.util.regex.Pattern compileRegexp(String pat) {
    java.util.regex.Pattern p = compileRegexp_cache.get(pat);
    if (p == null) {
      compileRegexp_cache.put(pat, p = java.util.regex.Pattern.compile(pat));
    }
    return p;
  }

  static public <A> A[] arrayOfSameType(A[] a, int n) {
    return newObjectArrayOfSameType(a, n);
  }

  static public <A> List<A> subList(List<A> l, int startIndex) {
    return subList(l, startIndex, l(l));
  }

  static public <A> List<A> subList(int startIndex, List<A> l) {
    return subList(l, startIndex);
  }

  static public <A> List<A> subList(int startIndex, int endIndex, List<A> l) {
    return subList(l, startIndex, endIndex);
  }

  static public <A> List<A> subList(List<A> l, int startIndex, int endIndex) {
    if (l == null)
      return null;
    int n = l(l);
    startIndex = Math.max(0, startIndex);
    endIndex = Math.min(n, endIndex);
    if (startIndex > endIndex)
      return ll();
    if (startIndex == 0 && endIndex == n)
      return l;
    return l.subList(startIndex, endIndex);
  }

  static public <A> List<A> subList(List<A> l, IntRange r) {
    return subList(l, r.start, r.end);
  }

  static public Graphics2D antiAliasOn(Graphics2D g) {
    g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    return g;
  }

  static public boolean isLowerHexString(String s) {
    for (int i = 0; i < l(s); i++) {
      char c = s.charAt(i);
      if (c >= '0' && c <= '9' || c >= 'a' && c <= 'f') {
      } else
        return false;
    }
    return true;
  }

  static public String roundBracket(String s) {
    return "(" + s + ")";
  }

  static public String roundBracket(Object s) {
    return roundBracket(str(s));
  }

  static public Charset utf8charset_cache;

  static public Charset utf8charset() {
    if (utf8charset_cache == null)
      utf8charset_cache = utf8charset_load();
    return utf8charset_cache;
  }

  static public Charset utf8charset_load() {
    return Charset.forName("UTF-8");
  }

  static public <A, B> Map<A, B> syncMRUCache(int size) {
    return synchroMap(new MRUCache(size));
  }

  static public <A> A[] newObjectArrayOfSameType(A[] a) {
    return newObjectArrayOfSameType(a, a.length);
  }

  static public <A> A[] newObjectArrayOfSameType(A[] a, int n) {
    return (A[]) Array.newInstance(a.getClass().getComponentType(), n);
  }

  static abstract public class VF2<A, B> {

    abstract public void get(A a, B b);
  }

  static public class ConceptWithGlobalID extends Concept implements IHasGlobalID {

    public GlobalID globalID = aGlobalIDObjUnlessLoading();

    public GlobalID globalID() {
      return globalID;
    }

    public String globalIDStr() {
      return strOrNull(globalID);
    }

    public String prependGlobalID(String s) {
      return globalID == null ? s : "[" + globalID + "] " + s;
    }
  }

  static public class RollingAverage {

    public int windowSize = 50;

    public int recalcEvery = 1000;

    public int nRecalc;

    public double sum;

    public double[] list;

    public int start, len;

    public RollingAverage() {
    }

    public RollingAverage(int windowSize) {
      this.windowSize = windowSize;
    }

    synchronized public void add(double d) {
      init();
      if (++nRecalc >= recalcEvery) {
        nRecalc = 0;
        sum = 0;
        for (int i = 0; i < len; i++) sum += _get(i);
      }
      if (len == windowSize) {
        sum -= _get(0);
        len--;
        start = (start + 1) % windowSize;
      }
      list[(start + len) % windowSize] = d;
      ++len;
      sum += d;
    }

    public double _get(int i) {
      return list[(start + i) % windowSize];
    }

    synchronized public double get() {
      init();
      return doubleRatio(sum, len);
    }

    public void init() {
      if (list == null)
        list = new double[windowSize];
    }
  }

  static public class ImageSurface_HighlightRegion extends ImageSurfaceMouseHandler implements G2Drawable {

    final public ImageSurface_HighlightRegion setRegionPainter(RegionPainter regionPainter) {
      return regionPainter(regionPainter);
    }

    public ImageSurface_HighlightRegion regionPainter(RegionPainter regionPainter) {
      this.regionPainter = regionPainter;
      return this;
    }

    final public RegionPainter getRegionPainter() {
      return regionPainter();
    }

    public RegionPainter regionPainter() {
      return regionPainter;
    }

    public RegionPainter regionPainter = new RegionBoundingBoxPainter();

    public FastRegions_BWImage regions;

    public int iHighlightedRegion;

    public Pt lastPt;

    public ImageSurface_HighlightRegion(ImageSurface is) {
      if (containsInstance(is.tools, getClass()))
        return;
      register(is);
      is.overlays.add(this);
    }

    public void close() {
      super.close();
      is.overlays.remove(this);
    }

    final public void mouseEntered(MouseEvent e) {
      mouseMoved(e);
    }

    public void mouseMoved(MouseEvent e) {
      lastPt = getPt(e);
      update();
    }

    public void mouseExited(MouseEvent e) {
      lastPt = null;
      update();
    }

    public int newRegion() {
      if (lastPt == null || regions == null)
        return 0;
      return regions.regionAt(lastPt.x, lastPt.y);
    }

    public void update() {
      int r = newRegion();
      if (iHighlightedRegion != r) {
        iHighlightedRegion = r;
        is.repaint();
      }
    }

    public void setRegions(FastRegions_BWImage regions) {
      this.regions = regions;
      iHighlightedRegion = -abs(iHighlightedRegion);
      update();
    }

    public void drawOn(Graphics2D g) {
      if (iHighlightedRegion == 0 || regionPainter == null)
        return;
      regionPainter.zoomX(is.getZoomX());
      regionPainter.zoomY(is.getZoomY());
      regionPainter.g(g);
      AutoCloseable __1 = tempAfterwards(new Runnable() {

        public void run() {
          try {
            regionPainter.g(null);
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "regionPainter.g(null);";
        }
      });
      try {
        regionPainter.regions(regions).iRegion(iHighlightedRegion);
        regionPainter.drawRegion();
      } finally {
        _close(__1);
      }
    }
  }

  static public class Var<A> implements IVar<A>, ISetter<A> {

    public Var() {
    }

    public Var(A v) {
      this.v = v;
    }

    public A v;

    public synchronized void set(A a) {
      if (v != a) {
        v = a;
        notifyAll();
      }
    }

    public synchronized A get() {
      return v;
    }

    public synchronized boolean has() {
      return v != null;
    }

    public void clear() {
      set(null);
    }

    public String toString() {
      return str(this.get());
    }
  }

  static public class Best_comparable<A> {

    public A best;

    public Comparable score;

    public boolean verboseNewBest, replaceIfSameScore;

    transient public Object onChange;

    transient public Object stringifier;

    synchronized public boolean isNewBest(Comparable score) {
      return this.score == null || (replaceIfSameScore ? cmp(score, this.score) >= 0 : cmp(score, this.score) > 0);
    }

    synchronized public Comparable bestScore() {
      return score;
    }

    public Comparable score() {
      return bestScore();
    }

    public Comparable getScore() {
      return bestScore();
    }

    synchronized public float floatScoreOr(float defaultValue) {
      return best == null ? defaultValue : (float) score;
    }

    public boolean put(Pair<? extends A, Comparable> p) {
      return p != null && put(p.a, p.b);
    }

    public boolean put(Best<? extends A> b) {
      return b != null && put(b.get(), b.score);
    }

    public boolean put(A a, Comparable score) {
      ping();
      boolean change = false;
      if (a != null)
        synchronized (this) {
          if (isNewBest(score)) {
            best = a;
            this.score = score;
            change = true;
          }
        }
      if (change) {
        if (verboseNewBest)
          print("New best! " + this);
        pcallF(onChange);
      }
      return change;
    }

    synchronized public A get() {
      return best;
    }

    synchronized public boolean has() {
      return best != null;
    }

    synchronized public Pair<A, Comparable> pair() {
      return main.pair(best, bestScore());
    }

    synchronized public A getIfScoreAbove(Comparable x) {
      return cmp(x, score()) >= 0 ? best : null;
    }

    public String toString() {
      return !has() ? "-" : "Score " + score + ": " + callStringifier(stringifier, best);
    }

    public boolean putAndPrintIfNewBest(A a, Comparable score) {
      if (!put(a, score))
        return false;
      {
        print(this);
        return true;
      }
    }

    synchronized public void clear() {
      best = null;
      score = 0;
    }
  }

  static public class RegionFillPainter extends RegionPainter {

    public void drawRegion() {
      Area area = regionToArea(regions, iRegion);
      g.setColor(withOpacity(.5, Color.green));
      g.scale(zoomX, zoomY);
      fillShape(g, area);
    }
  }

  static public boolean SimpleCRUD_searcher = true;

  static public class SimpleCRUD_v2<A extends Concept> extends JConceptsTable<A> {

    public JPanel buttons, panel;

    public Set<String> unshownFields;

    public Set<String> excludeFieldsFromEditing;

    public String modifiedField;

    public TableSearcher tableSearcher;

    public Set<String> multiLineFields;

    public Set<String> dontDuplicateFields;

    public int formFixer = 12;

    public boolean showBackRefs = false;

    public int maxRefsToShow = 3;

    public boolean showClassNameSelectors = false;

    public boolean allowNewFields = false;

    public int newFieldsToShow = 3;

    public boolean emptyStringsToNull = false;

    public int formLabelsWidth = 100;

    public SimpleCRUD_v2(Class<A> conceptClass) {
      super(conceptClass);
    }

    public SimpleCRUD_v2(Concepts concepts, Class<A> conceptClass) {
      super(concepts, conceptClass);
    }

    public SimpleCRUD_v2<A> show(String frameTitle) {
      make();
      showFrame(frameTitle, panel);
      return this;
    }

    public SimpleCRUD_v2<A> show() {
      return show(plural(shortClassName(conceptClass)));
    }

    public SimpleCRUD_v2<A> showMaximized() {
      show();
      maximizeFrame(panel);
      return this;
    }

    public JPanel makePanel() {
      return make();
    }

    public JPanel make() {
      db();
      framesBot();
      return make_dontStartBots();
    }

    transient public IF1<A, Map<String, Object>> itemToMap_inner;

    public Map<String, Object> itemToMap_inner(A a) {
      return itemToMap_inner != null ? itemToMap_inner.get(a) : itemToMap_inner_base(a);
    }

    final public Map<String, Object> itemToMap_inner_fallback(IF1<A, Map<String, Object>> _f, A a) {
      return _f != null ? _f.get(a) : itemToMap_inner_base(a);
    }

    public Map<String, Object> itemToMap_inner_base(A a) {
      return super.itemToMap_base(a);
    }

    public Map<String, Object> itemToMap_base(A a) {
      Map<String, Object> map = itemToMap_inner(a);
      if (map == null)
        return null;
      return putAll(map, moreSpecialFieldsForItem(a));
    }

    transient public IF1<A, Map<String, Object>> moreSpecialFieldsForItem;

    public Map<String, Object> moreSpecialFieldsForItem(A a) {
      return moreSpecialFieldsForItem != null ? moreSpecialFieldsForItem.get(a) : moreSpecialFieldsForItem_base(a);
    }

    final public Map<String, Object> moreSpecialFieldsForItem_fallback(IF1<A, Map<String, Object>> _f, A a) {
      return _f != null ? _f.get(a) : moreSpecialFieldsForItem_base(a);
    }

    public Map<String, Object> moreSpecialFieldsForItem_base(A a) {
      Map<String, Object> map = litorderedmap();
      if (showBackRefs) {
        Collection<Concept> refs = allBackRefs(a);
        if (nempty(refs)) {
          refs = sortedByConceptID(refs);
          int more = l(refs) - maxRefsToShow;
          map.put("Referenced by", joinWithComma(takeFirst(maxRefsToShow, refs)) + (more > 0 ? ", " + more + " more" : ""));
        }
      }
      return map;
    }

    public JPanel make_dontStartBots() {
      dropFields = asList(unshownFields);
      makeTable();
      {
        swing(() -> {
          buttons = jRightAlignedLine(jbutton("Add...", new Runnable() {

            public void run() {
              try {
                newConcept();
              } catch (Exception __e) {
                throw rethrow(__e);
              }
            }

            public String toString() {
              return "newConcept()";
            }
          }), tableDependButton(table, jbutton("Edit", new Runnable() {

            public void run() {
              try {
                editConcept(selectedConcept());
              } catch (Exception __e) {
                throw rethrow(__e);
              }
            }

            public String toString() {
              return "editConcept(selectedConcept())";
            }
          })), tableDependButton(table, jbutton("Delete", new Runnable() {

            public void run() {
              try {
                final List<A> l = selectedConcepts();
                withDBLock(concepts, new Runnable() {

                  public void run() {
                    try {
                      for (A c : l) c.delete();
                    } catch (Exception __e) {
                      throw rethrow(__e);
                    }
                  }

                  public String toString() {
                    return "for (A c : l) c.delete()";
                  }
                });
              } catch (Exception __e) {
                throw rethrow(__e);
              }
            }

            public String toString() {
              return "final List<A> l = selectedConcepts();\r\n          withDBLock(concepts, r { for...";
            }
          })), tableDependButton(table, jbutton("Duplicate...", new Runnable() {

            public void run() {
              try {
                duplicateConcept(selectedConcept());
              } catch (Exception __e) {
                throw rethrow(__e);
              }
            }

            public String toString() {
              return "duplicateConcept(selectedConcept())";
            }
          })));
          if (SimpleCRUD_searcher) {
            tableSearcher = tableWithSearcher2(table, "withMargin", true);
            panel = centerAndSouthWithMargin(tableSearcher.panel, buttons);
          } else
            panel = centerAndSouthWithMargin(table, buttons);
          Object fEdit = new VF1<Integer>() {

            public void get(Integer row) {
              try {
                editConcept(getItem(row));
              } catch (Exception __e) {
                throw rethrow(__e);
              }
            }

            public String toString() {
              return "editConcept(getItem(row))";
            }
          };
          tablePopupMenuItem(table, "Edit...", fEdit);
          onDoubleClick(table, fEdit);
          tablePopupMenuFirst(table, (menu, row) -> {
            Concept c = getItem(row);
            if (c != null)
              addMenuItem(menu, "Delete " + quote(shorten(str(c))), runnableThread(new Runnable() {

                public void run() {
                  try {
                    deleteConcept(c);
                  } catch (Exception __e) {
                    throw rethrow(__e);
                  }
                }

                public String toString() {
                  return "deleteConcept(c);";
                }
              }));
          });
        });
      }
      return panel;
    }

    public void newConcept() {
      duplicateConcept(null);
    }

    public void duplicateConcept(A oldConcept) {
      EditWindow ew = new EditWindow();
      ew.item = (A) unlisted(oldConcept == null ? conceptClass : _getClass(oldConcept));
      ccopyFieldsExcept(oldConcept, ew.item, dontDuplicateFields);
      makeComponents(ew);
      F0<Boolean> r = new F0<Boolean>() {

        public Boolean get() {
          try {
            try {
              concepts.register(ew.item);
              saveData(ew);
            } catch (Throwable e) {
              printStackTrace(e);
              infoBox(e);
              return false;
            }
            return true;
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "try {\r\n        concepts.register(ew.item);\r\n        saveData(ew);\r\n      } ca...";
        }
      };
      AutoCloseable __2 = tempSetMCOpt("formLayouter1_fixer2", formFixer);
      try {
        renameSubmitButton("Create", showAForm("New " + shortClassName(conceptClass), toObjectArray(listPlus(ew.matrix, r))));
      } finally {
        _close(__2);
      }
    }

    public void editConcept(A c) {
      if (c == null)
        return;
      EditWindow ew = new EditWindow();
      ew.item = c;
      makeComponents(ew);
      F0<Boolean> r = new F0<Boolean>() {

        public Boolean get() {
          try {
            try {
              if (ew.item != c) {
                print("Replacing object: " + c + " => " + ew.item);
                replaceConceptAndUpdateRefs(c, ew.item);
              }
              saveData(ew);
            } catch (Throwable e) {
              printStackTrace(e);
              infoBox(e);
              return false;
            }
            return true;
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "try {\r\n        // concept class was changed, replace object\r\n        if (ew.i...";
        }
      };
      AutoCloseable __3 = tempSetMCOpt("formLayouter1_fixer2", formFixer);
      try {
        renameSubmitButton("Save", showAForm("Edit " + shortClassName(conceptClass) + " #" + c.id, toObjectArray(listPlus(ew.matrix, r))));
      } finally {
        _close(__3);
      }
    }

    public JComponent fieldComponent(A c, String field) {
      Class type = getFieldType(conceptClass, field);
      Object value = cget(c, field);
      if (type == null)
        type = _getClass(value);
      print("Field type: " + field + " => " + type);
      if (type == boolean.class)
        return jCenteredCheckBox(isTrue(value));
      else if (contains(multiLineFields, field) || containsNewLines(optCast(String.class, value)))
        return typeWriterTextArea((String) value);
      else if (isSubtype(type, Concept.class))
        return jcomboboxFromConcepts_str(concepts, type, (Concept) value);
      else if (type == SecretValue.class)
        return jpassword(strOrEmpty(getVar(((SecretValue) value))));
      else if (isUneditableFieldType(type))
        return jlabel(structureOrText_crud(value));
      else
        try {
          return autoComboBox(structureOrText_crud(value), new TreeSet<String>(map(__34 -> structureOrText_crud(__34), collect(list(concepts, conceptClass), field))));
        } catch (Throwable e) {
          printException(e);
          return jTextField(structureOrText_crud(value));
        }
    }

    public void saveComponent(A c, String field, JComponent comp) {
      comp = unwrap(comp);
      Class type = fieldType(c, field);
      if (type == SecretValue.class) {
        String text = getTextTrim((JPasswordField) comp);
        cset(c, field, empty(text) ? null : new SecretValue(text));
      } else if (comp instanceof JTextComponent) {
        String text = trimIf(!(comp instanceof JTextArea), getText((JTextComponent) comp));
        Object value = postProcessValue(text);
        Object converted = convertToField(value, conceptClass, field);
        cset(c, field, converted);
      } else if (comp instanceof JComboBox) {
        String text = getTextTrim((JComboBox) comp);
        if (isSubtype(type, Concept.class))
          cset(c, field, getConcept(concepts, parseFirstLong(text)));
        else {
          Object value = postProcessValue(text);
          cset(c, field, convertToField(value, conceptClass, field));
        }
      } else if (comp instanceof JCheckBox)
        cset(c, field, isChecked((JCheckBox) comp));
      else if (comp instanceof ImageChooser)
        cUpdatePNGFile(c, field, ((ImageChooser) comp).getImage(), false);
    }

    public List<String> fieldsForItem(A c) {
      if (excludeFieldsFromEditing != null && modifiedField != null)
        excludeFieldsFromEditing.add(modifiedField);
      return listWithoutSet(filter(conceptFields(c), new F1<String, Boolean>() {

        public Boolean get(String field) {
          try {
            return fieldType(conceptClass, field) != Concept.Ref.class;
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "fieldType(conceptClass, field) != Concept.Ref.class";
        }
      }), joinSets(excludeFieldsFromEditing, unshownFields));
    }

    public void excludeFieldsFromEditing(String... fields) {
      excludeFieldsFromEditing = setPlus(excludeFieldsFromEditing, fields);
    }

    public Collection<Class<? extends A>> possibleClasses() {
      return (Collection) moveItemFirst(conceptClass, dropTypeParameter(sortClassesByNameIC(myNonAbstractClassesImplementing(conceptClass))));
    }

    public JComboBox<Class<? extends A>> classSelectorComponent(A c) {
      return setComboBoxRenderer(jTypedComboBox(possibleClasses(), _getClass(c)), customToStringListCellRenderer(__51 -> shortClassName(__51)));
    }

    public class NewField {

      public JTextField tfName = jtextfield();

      public JTextField tfValue = jtextfield();

      public JComboBox cbRef = jcomboboxFromConcepts_str(concepts, conceptClass);

      public JComboBox cbType = jcombobox("String", "Reference");

      public SingleComponentPanel scpValue = singleComponentPanel();

      public JPanel panel() {
        onChangeAndNow(cbType, new Runnable() {

          public void run() {
            try {
              updateSCP();
            } catch (Exception __e) {
              throw rethrow(__e);
            }
          }

          public String toString() {
            return "updateSCP();";
          }
        });
        return jhgridWithSpacing(withToolTip("Name for new field", withLabel("Name", tfName)), withLabel("Value", westAndCenterWithMargin(cbType, scpValue)));
      }

      public String typeStr() {
        return getText(cbType);
      }

      public void updateSCP() {
        scpValue.setComponent(eqic(typeStr(), "Reference") ? cbRef : withToolTip("Contents of new field", tfValue));
      }

      public String field() {
        return gtt(tfName);
      }

      public Object value() {
        return eqic(typeStr(), "Reference") ? getConcept(concepts, parseFirstLong(getText(cbRef))) : gtt(tfValue);
      }
    }

    public class EditWindow {

      public A item;

      public Map<String, JComponent> componentsByField = litorderedmap();

      public List matrix = new ArrayList();

      public JComboBox<Class<? extends A>> classSelector;

      public List<NewField> newFields = new ArrayList();
    }

    public void makeComponents(EditWindow ew) {
      if (showClassNameSelectors) {
        addAll(ew.matrix, makeLabel("Java Class"), ew.classSelector = classSelectorComponent(ew.item));
        onChange(ew.classSelector, new Runnable() {

          public void run() {
            try {
              Class<? extends A> oldClass = _getClass(ew.item);
              Class<? extends A> newClass = getSelectedItem_typed(ew.classSelector);
              if (oldClass == newClass)
                return;
              A oldItem = ew.item;
              ew.item = unlisted(newClass);
              ccopyFields(oldItem, ew.item);
            } catch (Exception __e) {
              throw rethrow(__e);
            }
          }

          public String toString() {
            return "Class<? extends A> oldClass = _getClass(ew.item);\r\n        Class<? extends A>...";
          }
        });
      }
      for (String field : fieldsForItem(ew.item)) {
        JComponent c = fieldComponent(ew.item, field);
        ew.componentsByField.put(field, c);
        addAll(ew.matrix, makeLabel(field), c);
      }
      if (allowNewFields && newFieldsToShow > 0) {
        addAll(ew.matrix, " ", jlabel());
        for (int i = 0; i < newFieldsToShow; i++) {
          NewField nf = new NewField();
          ew.newFields.add(nf);
          addAll(ew.matrix, makeLabel(""), nf.panel());
        }
      }
    }

    public void saveData(EditWindow ew) {
      for (Map.Entry<? extends String, ? extends JComponent> __0 : _entrySet(ew.componentsByField)) {
        String field = __0.getKey();
        JComponent component = __0.getValue();
        if (isIdentifier(field))
          saveComponent(ew.item, field, component);
      }
      for (NewField nf : ew.newFields) {
        String field = nf.field();
        Object value = nf.value();
        if (nempty(field) && notNullOrEmptyString(value))
          cset(ew.item, field, value);
      }
      if (modifiedField != null)
        cset(ew.item, modifiedField, now());
    }

    public Object postProcessValue(Object o) {
      if (emptyStringsToNull && eq(o, ""))
        return null;
      return o;
    }

    public JComponent makeLabel(String label) {
      return jMinWidthAtLeast(formLabelsWidth, jlabel(label));
    }

    transient public IF2<String, Object[], JComponent> showAForm;

    public JComponent showAForm(String title, Object... parts) {
      return showAForm != null ? showAForm.get(title, parts) : showAForm_base(title, parts);
    }

    final public JComponent showAForm_fallback(IF2<String, Object[], JComponent> _f, String title, Object... parts) {
      return _f != null ? _f.get(title, parts) : showAForm_base(title, parts);
    }

    public JComponent showAForm_base(String title, Object... parts) {
      return showFormTitled2(title, parts);
    }

    public boolean isUneditableFieldType(Class type) {
      return isSubclassOfAny(type, Map.class, List.class, Pair.class);
    }

    public void hideFields(String... fields) {
      unshownFields = createOrAddToSet(unshownFields, fields);
    }
  }

  static public class BetterThread extends Thread {

    public Runnable target;

    public BetterThread(Runnable target) {
      this.target = target;
      _created();
    }

    public BetterThread(Runnable target, String name) {
      super(name);
      this.target = target;
      _created();
    }

    public void _created() {
      vmBus_send("threadCreated", this);
    }

    public void run() {
      try {
        try {
          vmBus_send("threadStarted", this);
          if (target != null)
            target.run();
        } finally {
          vmBus_send("threadEnded", this);
        }
      } catch (Exception __e) {
        throw rethrow(__e);
      }
    }

    public Runnable getTarget() {
      return target;
    }
  }

  static public class AnimatedLine extends Animation {

    public int maxSpeed = 1;

    public int y, speed;

    public void start() {
      y = random(h);
      newSpeed();
    }

    public void newSpeed() {
      speed = random_incl(-maxSpeed, maxSpeed);
    }

    public void paint() {
      fillRect(g, 0, 0, w, h, Color.white);
      drawLine(g, 0, y, w, y, Color.black);
    }

    public void nextFrame() {
      if (oneIn(20))
        newSpeed();
      y = clamp(y + speed, 0, h - 1);
    }
  }

  static public class SynchronizedSet<E> extends SynchronizedCollection<E> implements Set<E> {

    public SynchronizedSet() {
    }

    public SynchronizedSet(Set<E> s) {
      super(s);
    }

    public SynchronizedSet(Set<E> s, Object mutex) {
      super(s, mutex);
    }

    public boolean equals(Object o) {
      if (this == o)
        return true;
      synchronized (mutex) {
        return c.equals(o);
      }
    }

    public int hashCode() {
      synchronized (mutex) {
        return c.hashCode();
      }
    }
  }

  static public class SynchronizedMap<K, V> implements Map<K, V>, Serializable {

    public SynchronizedMap() {
    }

    public Map<K, V> m;

    public Object mutex;

    public SynchronizedMap(Map<K, V> m) {
      this.m = Objects.requireNonNull(m);
      mutex = this;
    }

    public SynchronizedMap(Map<K, V> m, Object mutex) {
      this.m = m;
      this.mutex = mutex;
    }

    public int size() {
      synchronized (mutex) {
        return m.size();
      }
    }

    public boolean isEmpty() {
      synchronized (mutex) {
        return m.isEmpty();
      }
    }

    public boolean containsKey(Object key) {
      synchronized (mutex) {
        return m.containsKey(key);
      }
    }

    public boolean containsValue(Object value) {
      synchronized (mutex) {
        return m.containsValue(value);
      }
    }

    public V get(Object key) {
      synchronized (mutex) {
        return m.get(key);
      }
    }

    public V put(K key, V value) {
      synchronized (mutex) {
        return m.put(key, value);
      }
    }

    public V remove(Object key) {
      synchronized (mutex) {
        return m.remove(key);
      }
    }

    public void putAll(Map<? extends K, ? extends V> map) {
      synchronized (mutex) {
        m.putAll(map);
      }
    }

    public void clear() {
      synchronized (mutex) {
        m.clear();
      }
    }

    transient public Set<K> keySet;

    transient public Set<Map.Entry<K, V>> entrySet;

    transient public Collection<V> values;

    public Set<K> keySet() {
      synchronized (mutex) {
        if (keySet == null)
          keySet = new SynchronizedSet<>(m.keySet(), mutex);
        return keySet;
      }
    }

    public Set<Map.Entry<K, V>> entrySet() {
      synchronized (mutex) {
        if (entrySet == null)
          entrySet = new SynchronizedSet<>(m.entrySet(), mutex);
        return entrySet;
      }
    }

    public Collection<V> values() {
      synchronized (mutex) {
        if (values == null)
          values = new SynchronizedCollection<>(m.values(), mutex);
        return values;
      }
    }

    public boolean equals(Object o) {
      if (this == o)
        return true;
      synchronized (mutex) {
        return m.equals(o);
      }
    }

    public int hashCode() {
      synchronized (mutex) {
        return m.hashCode();
      }
    }

    public String toString() {
      synchronized (mutex) {
        return m.toString();
      }
    }

    @Override
    public V getOrDefault(Object k, V defaultValue) {
      synchronized (mutex) {
        return m.getOrDefault(k, defaultValue);
      }
    }

    @Override
    public void forEach(BiConsumer<? super K, ? super V> action) {
      synchronized (mutex) {
        m.forEach(action);
      }
    }

    @Override
    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
      synchronized (mutex) {
        m.replaceAll(function);
      }
    }

    @Override
    public V putIfAbsent(K key, V value) {
      synchronized (mutex) {
        return m.putIfAbsent(key, value);
      }
    }

    @Override
    public boolean remove(Object key, Object value) {
      synchronized (mutex) {
        return m.remove(key, value);
      }
    }

    @Override
    public boolean replace(K key, V oldValue, V newValue) {
      synchronized (mutex) {
        return m.replace(key, oldValue, newValue);
      }
    }

    @Override
    public V replace(K key, V value) {
      synchronized (mutex) {
        return m.replace(key, value);
      }
    }

    @Override
    public V computeIfAbsent(K key, java.util.function.Function<? super K, ? extends V> mappingFunction) {
      synchronized (mutex) {
        return m.computeIfAbsent(key, mappingFunction);
      }
    }

    @Override
    public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
      synchronized (mutex) {
        return m.computeIfPresent(key, remappingFunction);
      }
    }

    @Override
    public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
      synchronized (mutex) {
        return m.compute(key, remappingFunction);
      }
    }

    @Override
    public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
      synchronized (mutex) {
        return m.merge(key, value, remappingFunction);
      }
    }

    @java.io.Serial
    final public void writeObject(ObjectOutputStream s) throws IOException {
      synchronized (mutex) {
        s.defaultWriteObject();
      }
    }
  }

  static public class CleanExit extends RuntimeException {

    public CleanExit() {
    }

    public CleanExit(String msg) {
      super(msg);
    }
  }

  static public class ImageSurface_PositionToolTip extends ImageSurfaceMouseHandler {

    public ImageSurface_PositionToolTip(ImageSurface is) {
      if (containsInstance(is.tools, ImageSurface_PositionToolTip.class))
        return;
      register(is);
    }

    final public void mouseDragged(MouseEvent e) {
      mouseMoved(e);
    }

    public void mouseMoved(MouseEvent e) {
      setToolTip(is, getPt(e));
    }
  }

  static public interface IResourceLoader {

    public String loadSnippet(String snippetID);

    public String getTranspiled(String snippetID);

    public int getSnippetType(String snippetID);

    public String getSnippetTitle(String snippetID);

    public File loadLibrary(String snippetID);

    default public File pathToJavaXJar() {
      return pathToJavaxJar_noResourceLoader();
    }

    default public File getSnippetJar(String snippetID, String transpiledSrc) {
      return null;
    }
  }

  static public class ReliableSingleThread implements Runnable {

    public boolean _isTransient() {
      return true;
    }

    public Object runnable;

    public String name = "Single Thread";

    public boolean cancelBeforeTrigger = false;

    public boolean waitBetweenCancelAndTrigger = false;

    public F0<AutoCloseable> enter;

    public int cancelTimeOut = 10000;

    public boolean trigger = false;

    public Thread thread;

    public WeakReference<Thread> threadBeingCancelled;

    public List<Runnable> inserts = syncL();

    public ReliableSingleThread(Object runnable) {
      this.runnable = runnable;
    }

    public void trigger() {
      go();
    }

    synchronized public void go() {
      if (cancelBeforeTrigger)
        cancelAndPossiblyWait();
      trigger = true;
      if (!running()) {
        AutoCloseable __1 = callF(enter);
        try {
          thread = startThread(name, new Runnable() {

            public void run() {
              try {
                AutoCloseable __2 = callF(enter);
                try {
                  _run();
                } finally {
                  _close(__2);
                }
              } catch (Exception __e) {
                throw rethrow(__e);
              }
            }

            public String toString() {
              return "temp callF(enter);\r\n        _run();";
            }
          });
        } finally {
          _close(__1);
        }
      }
    }

    public void run() {
      go();
    }

    public void get() {
      go();
    }

    synchronized public boolean running() {
      return thread != null;
    }

    public void triggerAndWait() {
      trigger();
      waitUntilDone();
    }

    public void waitUntilDone() {
      while (running()) sleep(1);
    }

    public void _run() {
      try {
        while (licensed()) {
          Thread oldThread;
          synchronized (this) {
            var currentInserts = syncGetAndClear(inserts);
            pcallFAll(currentInserts);
            if (!trigger) {
              thread = null;
              break;
            }
            oldThread = getWeakRef(threadBeingCancelled);
            trigger = false;
          }
          if (oldThread != null && oldThread != currentThread())
            oldThread.join(cancelTimeOut);
          pcallF(runnable);
        }
      } catch (Exception __e) {
        throw rethrow(__e);
      }
    }

    synchronized public void cancel() {
      if (thread == null)
        return;
      threadBeingCancelled = new WeakReference(thread);
      cancelAndInterruptThread(thread);
      thread = null;
    }

    public void cancelAndWait() {
      Thread _thread;
      synchronized (this) {
        if (thread == null)
          return;
        _thread = thread;
        threadBeingCancelled = new WeakReference(thread);
        thread = null;
      }
      cancelAndInterruptThread(_thread);
    }

    public void cancelAndTrigger() {
      cancelAndPossiblyWait();
      trigger();
    }

    synchronized public boolean triggered() {
      return trigger;
    }

    public void cleanMeUp() {
      cancel();
    }

    public ReliableSingleThread cancelBeforeTrigger() {
      cancelBeforeTrigger = true;
      return this;
    }

    public void cancelAndPossiblyWait() {
      if (waitBetweenCancelAndTrigger)
        cancel();
    }

    public void insert(Runnable r) {
      inserts.add(r);
      trigger();
    }
  }

  static public class JFastLogView_noWrap extends JComponent implements Scrollable {

    public List<String> lines = syncList();

    public boolean endsWithNewLine, verbose;

    public Dimension getPreferredScrollableViewportSize() {
      return getPreferredSize();
    }

    public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
      return 20;
    }

    public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
      return (direction == SwingConstants.HORIZONTAL ? visibleRect.width : visibleRect.height) * 5 / 6;
    }

    public boolean getScrollableTracksViewportWidth() {
      return false;
    }

    public boolean getScrollableTracksViewportHeight() {
      return false;
    }

    public void paint(Graphics g) {
      int w = getWidth(), h = getHeight();
      g.setColor(getBackground());
      g.fillRect(0, 0, w, h);
      g.setColor(getForeground());
      FontMetrics fm = componentFontMetrics(this);
      int fh = fm.getHeight();
      Rectangle clip = g.getClipBounds();
      int start, end;
      if (clip == null) {
        start = 0;
        end = l(lines);
      } else {
        start = max(0, clip.y / fh);
        end = min(l(lines), idiv_ceil(clip.y + clip.height, fh));
      }
      int y = fm.getAscent() + start * fh;
      for (int i = start; i < end; i++) {
        String s = get(lines, i);
        if (s != null)
          g.drawString(s, 0, y);
        y += fh;
      }
    }

    public Dimension getPreferredSize() {
      FontMetrics fm = componentFontMetrics(this);
      if (fm == null)
        return new Dimension(50, 50);
      int fh = fm.getHeight();
      int w = 0;
      for (int i = 0; i < l(lines); i++) {
        String s = get(lines, i);
        w = max(w, fm.stringWidth(unnull(s)));
      }
      return new Dimension(w, fh * l(lines));
    }

    public JFastLogView_noWrap() {
    }

    public JFastLogView_noWrap(String text) {
      setText(text);
    }

    {
      componentPopupMenuItem(this, "Copy full text", new Runnable() {

        public void run() {
          try {
            copyFullText();
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "copyFullText();";
        }
      });
    }

    public boolean setLines(Collection<String> lines) {
      List<String> newList = asSyncList(lines);
      if (eq(this.lines, newList))
        return false;
      this.lines = newList;
      _revalidate(this);
      return true;
    }

    public boolean setText(String text) {
      endsWithNewLine = endsWithNewLine(text);
      return setLines(lines(text));
    }

    public void append(String text) {
      if (nempty(text))
        setText(getText() + text);
    }

    public String getText() {
      return lines_rtrimIf(!endsWithNewLine, cloneList(lines));
    }

    public void copyFullText() {
      copyTextToClipboard(getText());
    }
  }

  static public class proxy_InvocationHandler implements InvocationHandler {

    public Object target;

    public proxy_InvocationHandler() {
    }

    public proxy_InvocationHandler(Object target) {
      this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) {
      return call(target, method.getName(), unnull(args));
    }
  }

  static public class UIURLSystem implements IFieldsToList {

    public Enterable owner;

    public SimpleLiveValue<String> uiURL;

    public UIURLSystem() {
    }

    public UIURLSystem(Enterable owner, SimpleLiveValue<String> uiURL) {
      this.uiURL = uiURL;
      this.owner = owner;
    }

    public String toString() {
      return shortClassName_dropNumberPrefix(this) + "(" + owner + ", " + uiURL + ")";
    }

    public Object[] _fieldsToList() {
      return new Object[] { owner, uiURL };
    }

    transient public Map<String, IF0<? extends JComponent>> uiMap = syncCIMap();

    final public UIURLSystem setScp(SingleComponentPanel scp) {
      return scp(scp);
    }

    public UIURLSystem scp(SingleComponentPanel scp) {
      this.scp = scp;
      return this;
    }

    final public SingleComponentPanel getScp() {
      return scp();
    }

    public SingleComponentPanel scp() {
      return scp;
    }

    transient public SingleComponentPanel scp;

    public JComponent urlBar() {
      return withLabel("Show", comboBoxAndButton(onSelectedItem(bindComboBoxToLiveValue(centerComboBox(autoComboBox(url(), cloneKeys(uiMap))), uiURL), url -> showUIURL(url)), "Go", url -> showUIURL(url)));
    }

    final public JComponent renderUIURL(String url) {
      return renderUIUrl(url);
    }

    final public JComponent uiGet(String url) {
      return renderUIUrl(url);
    }

    public JComponent renderUIUrl(String url) {
      var maker = uiMap.get(url);
      var component = callF(maker);
      if (component != null)
        return component;
      return jCenteredLabel("URL not found: " + url);
    }

    public void showUIURL(String url) {
      AutoCloseable __1 = tempEnter(owner);
      try {
        setURL(trim(url));
        go();
      } finally {
        _close(__1);
      }
    }

    public void go() {
      setComponent(scp, renderUIUrl(url()));
    }

    public String url() {
      return uiURL.get();
    }

    public void setURL(String url) {
      uiURL.set(url);
    }

    public UIURLSystem put(String url, IF0<? extends JComponent> maker) {
      uiMap.put(url, maker);
      return this;
    }
  }

  static public class ScreenCamStream extends SourceTriggeredStream<BufferedImage> implements Steppable {

    final public ScreenCamStream setArea(Rect area) {
      return area(area);
    }

    public ScreenCamStream area(Rect area) {
      this.area = area;
      return this;
    }

    final public Rect getArea() {
      return area();
    }

    public Rect area() {
      return area;
    }

    volatile public Rect area = screenBounds(0);

    public boolean step() {
      if (ended())
        return false;
      catchError(() -> shootImpl());
      return true;
    }

    public long frameCount() {
      return elementCount();
    }

    public void shootImpl() {
      newElement(shootScreen2(area));
    }

    public void useScreen(int iScreen) {
      area = screenBounds_safe(iScreen);
    }
  }

  static public interface IResourceHolder {

    public <A extends AutoCloseable> A add(A a);

    public Collection<AutoCloseable> takeAll();
  }

  static public class FunctionTimings<A> {

    public Map<A, Average> data = syncMap();

    public void time(A function, Runnable r) {
      if (r == null)
        return;
      Average avg = syncMapGetOrCreate(data, function, () -> new Average());
      long time = nanoTime();
      try {
        r.run();
      } finally {
        time = nanoTime() - time;
        avg.add(time);
      }
    }

    public Map<A, Average> get() {
      return cloneMap(data);
    }

    final public void clear() {
      reset();
    }

    public void reset() {
      data.clear();
    }

    public String render() {
      return lines(ciSorted(map(get(), (f, avg) -> functionToString(f) + ": " + n2(iround(nsToMicroseconds(avg.get()))) + " " + microSymbol() + "s (" + n2(iround(avg.n())) + ")")));
    }

    public String functionToString(A f) {
      return firstToUpper(str(f));
    }
  }

  static public class Flattener {

    public List out = new ArrayList();

    public Flattener() {
    }

    public Flattener(Object... l) {
      add(l);
    }

    public void add(Object o) {
      if (o instanceof Object[])
        for (var x : ((Object[]) o)) add(x);
      else if (o instanceof Iterable)
        for (var x : ((Iterable) o)) add(x);
      else if (o != null)
        out.add(o);
    }

    public void add(Object... l) {
      add((Object) l);
    }

    public List toList() {
      return out;
    }

    public Object[] toArray() {
      return toObjectArray(out);
    }
  }

  static public class TrayIconLastPosition {

    public TrayIcon trayIcon;

    public WithTimestamp<Pt> lastPosition;

    public TrayIconLastPosition(TrayIcon trayIcon) {
      this.trayIcon = trayIcon;
      {
        if (trayIcon != null)
          trayIcon.addMouseMotionListener(new MouseMotionAdapter() {

            @Override
            public void mouseMoved(MouseEvent e) {
              lastPosition = withTimestamp(pt(e.getX(), e.getY()));
            }
          });
      }
    }
  }

  static public class MRUCache<A, B> extends LinkedHashMap<A, B> {

    public int maxSize = 10;

    public MRUCache() {
    }

    public MRUCache(int maxSize) {
      this.maxSize = maxSize;
    }

    public boolean removeEldestEntry(Map.Entry eldest) {
      return size() > maxSize;
    }

    public Object _serialize() {
      return ll(maxSize, cloneLinkedHashMap(this));
    }

    static public MRUCache _deserialize(List l) {
      MRUCache m = new MRUCache();
      m.maxSize = (int) first(l);
      m.putAll((LinkedHashMap) second(l));
      return m;
    }
  }

  static public class TransferableImage implements Transferable {

    public Image i;

    public TransferableImage(Image i) {
      this.i = i;
    }

    public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
      if (flavor.equals(DataFlavor.imageFlavor) && i != null) {
        return i;
      } else {
        throw new UnsupportedFlavorException(flavor);
      }
    }

    public DataFlavor[] getTransferDataFlavors() {
      DataFlavor[] flavors = new DataFlavor[1];
      flavors[0] = DataFlavor.imageFlavor;
      return flavors;
    }

    public boolean isDataFlavorSupported(DataFlavor flavor) {
      DataFlavor[] flavors = getTransferDataFlavors();
      for (int i = 0; i < flavors.length; i++) {
        if (flavor.equals(flavors[i])) {
          return true;
        }
      }
      return false;
    }
  }

  static public class JGazelleVScriptRunner implements IFieldsToList {

    public SimpleLiveValue<String> lvScript;

    public JGazelleVScriptRunner() {
    }

    public JGazelleVScriptRunner(SimpleLiveValue<String> lvScript) {
      this.lvScript = lvScript;
    }

    public Object[] _fieldsToList() {
      return new Object[] { lvScript };
    }

    public GazelleVScript parsedScript;

    public GazelleVScript.Run run;

    public Object result;

    public SingleComponentPanel scpScriptResult = singleComponentPanel();

    public WeakVar<ImageSurface> isScriptResult = new WeakVar();

    public WeakVar<JTextArea> taResult = new WeakVar();

    public JLabel lblScore = jlabel();

    public JComponent scriptAndResultPanel() {
      return northAndCenter(scriptInputField(), scpScriptResult = singleComponentPanel());
    }

    public JComponent scriptInputField() {
      return withMargin(centerAndEastWithMargin(withLabel("Gazelle V Script:", jLiveTextField(lvScript)), jPopDownButton_noText("Show Scripting Help", runnableThread(new Runnable() {

        public void run() {
          try {
            showText("Gazelle V Scripting Help", GazelleVScript.helpText);
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "showText(\"Gazelle V Scripting Help\", GazelleVScript.helpText)";
        }
      }))));
    }

    public void showScriptOutput() {
      if (result instanceof BWImage) {
        showImageResult((BWImage) result);
      } else if (result instanceof BufferedImage) {
        showImageResult((BufferedImage) result);
      } else if (result instanceof Animation) {
        showImageResult(((Animation) result).toImage());
      } else {
        showTextResult(str(result));
      }
    }

    public void showTextResult(String text) {
      text = shorten(1000, text);
      if (isShowing(taResult.get())) {
        setTextKeepCaret(taResult.get(), text);
      } else {
        var ta = jTextArea_noUndo(text);
        scpScriptResult.set(jscroll(ta));
        taResult.set(ta);
      }
    }

    public void showImageResult(MakesBufferedImage img) {
      showImageResult(toBufferedImage(img));
    }

    public void showImageResult(BufferedImage img) {
      if (img == null)
        return;
      if (isShowing(isScriptResult.get())) {
        isScriptResult.get().setImage(img);
      } else {
        var is = stdImageSurface();
        is.setImage(img);
        scpScriptResult.set(jscroll_centered(is));
        isScriptResult.set(is);
      }
      if (isShowing(lblScore)) {
        String score = "";
        if (sameSize(run.inputImage, img)) {
          double distance = bwDistance(toBWImage(run.inputImage), toBWImage(img));
          score = "Score: " + formatDoubleX(100 * (1 - distance), 1);
        }
        setText(lblScore, score);
      }
    }

    public ImageSurface stdImageSurface() {
      return pixelatedImageSurface().setAutoZoomToDisplay(true).repaintInThread(false);
    }

    public void parse() {
      parsedScript = new GazelleVScript(lvScript.get());
    }

    public void runOn(IBWIntegralImage ii) {
      run = parsedScript.new Run();
      run.setInputImage(ii);
      run.setIntegralImage(ii);
      run.run();
      result = run.result();
    }

    public void parseAndRunOn(IBWIntegralImage ii) {
      try {
        parse();
        runOn(ii);
      } catch (Throwable e) {
        result = exceptionToStringShort(e);
        printStackTrace(e);
      }
      showScriptOutput();
    }
  }

  static abstract public class CloseableIterableIterator<A> extends IterableIterator<A> implements AutoCloseable {

    public void close() throws Exception {
    }
  }

  static public class BWIntegralImageStream extends SourceTriggeredStream<BWIntegralImage> implements Consumer<BufferedImage> {

    public void accept(BufferedImage image) {
      catchError(() -> newElement(bwIntegralImage_withMeta(image)));
    }

    public long frameCount() {
      return elementCount();
    }
  }

  static public interface IFieldsToList {

    public Object[] _fieldsToList();
  }

  static public interface IF2<A, B, C> {

    public C get(A a, B b);
  }

  abstract static public class Animation {

    public int w = 128, h = 128;

    public double fps = 20;

    public Graphics2D g;

    public Animation() {
    }

    public Animation(int w, int h) {
      this.h = h;
      this.w = w;
    }

    public void setSize(int w, int h) {
      this.w = w;
      this.h = h;
    }

    public void setGraphics(Graphics2D g) {
      this.g = g;
    }

    public void start() {
    }

    public void paint() {
    }

    public void nextFrame() {
    }

    public BufferedImage toImage() {
      var img = whiteImage(w, h);
      setGraphics(createGraphics(img));
      paint();
      return img;
    }
  }

  static public class DoubleFPSCounter {

    public FPSCounter counter = new FPSCounter();

    volatile public double value;

    public void inc() {
      if (counter.secondsSinceStart() >= 1) {
        value = counter.get();
        counter = new FPSCounter();
      }
      counter.inc();
    }

    public double get() {
      return value;
    }
  }

  static public class SourceTriggeredStream<A> extends Meta {

    public DoneFlag ended = new DoneFlag(true);

    volatile public A lastElement;

    public AtomicLong elementCount = new AtomicLong();

    transient public List<IVF1<A>> onNewElement;

    public SourceTriggeredStream<A> onNewElement(IVF1<A> f) {
      onNewElement = syncAddOrCreate(onNewElement, f);
      return this;
    }

    public void newElement(A a) {
      lastElement = a;
      inc(elementCount);
      pcallFAll(onNewElement, a);
    }

    public void onNewElement(Runnable r) {
      onNewElement(runnableToIVF1(r));
    }

    public A get() {
      return lastElement;
    }

    public long elementCount() {
      return elementCount.get();
    }

    public void end() {
      ended.raise();
    }

    public boolean ended() {
      return ended.isUp();
    }

    public void catchError(Runnable r) {
      main.catchError(ended, r);
    }

    public void directlyFeedInto(Consumer<A> consumer) {
      if (consumer != null)
        onNewElement(a -> consumer.accept(a));
    }
  }

  static public interface IVar<A> extends IF0<A> {

    public void set(A a);

    public A get();

    default public boolean has() {
      return get() != null;
    }

    default public void clear() {
      set(null);
    }
  }

  static public class SynchronizedList<E> extends SynchronizedCollection<E> implements List<E> {

    public SynchronizedList() {
    }

    public List<E> list;

    public SynchronizedList(List<E> list) {
      super(list);
      this.list = list;
    }

    public SynchronizedList(List<E> list, Object mutex) {
      super(list, mutex);
      this.list = list;
    }

    public boolean equals(Object o) {
      if (this == o)
        return true;
      synchronized (mutex) {
        return list.equals(o);
      }
    }

    public int hashCode() {
      synchronized (mutex) {
        return list.hashCode();
      }
    }

    public E get(int index) {
      synchronized (mutex) {
        return list.get(index);
      }
    }

    public E set(int index, E element) {
      synchronized (mutex) {
        return list.set(index, element);
      }
    }

    public void add(int index, E element) {
      synchronized (mutex) {
        list.add(index, element);
      }
    }

    public E remove(int index) {
      synchronized (mutex) {
        return list.remove(index);
      }
    }

    public int indexOf(Object o) {
      synchronized (mutex) {
        return list.indexOf(o);
      }
    }

    public int lastIndexOf(Object o) {
      synchronized (mutex) {
        return list.lastIndexOf(o);
      }
    }

    public boolean addAll(int index, Collection<? extends E> c) {
      synchronized (mutex) {
        return list.addAll(index, c);
      }
    }

    public ListIterator<E> listIterator() {
      return list.listIterator();
    }

    public ListIterator<E> listIterator(int index) {
      return list.listIterator(index);
    }

    public List<E> subList(int fromIndex, int toIndex) {
      synchronized (mutex) {
        return new SynchronizedList<>(list.subList(fromIndex, toIndex), mutex);
      }
    }

    @Override
    public void replaceAll(java.util.function.UnaryOperator<E> operator) {
      synchronized (mutex) {
        list.replaceAll(operator);
      }
    }

    @Override
    public void sort(Comparator<? super E> c) {
      synchronized (mutex) {
        list.sort(c);
      }
    }

    @java.io.Serial
    final public Object readResolve() {
      return (list instanceof RandomAccess ? new SynchronizedRandomAccessList<>(list) : this);
    }
  }

  static public class JConceptsTable<A extends Concept> implements Swingable {

    public Class<? extends A> conceptClass;

    public Concepts concepts;

    public JTable table;

    public String hID = "ID";

    final public JConceptsTable<A> setDropFields(List<String> dropFields) {
      return dropFields(dropFields);
    }

    public JConceptsTable<A> dropFields(List<String> dropFields) {
      this.dropFields = dropFields;
      return this;
    }

    final public List<String> getDropFields() {
      return dropFields();
    }

    public List<String> dropFields() {
      return dropFields;
    }

    public List<String> dropFields;

    public IF1<List, List> postProcess;

    public Runnable afterUpdate;

    public boolean latestFirst = false;

    public IF1<Collection<A>, Collection<A>> sorter = __1 -> defaultSort(__1);

    public int idWidth = 50;

    public int updateInterval = 100;

    public int firstUpdateInterval = 100;

    public boolean humanizeFieldNames = true;

    public Float tableFontSize;

    public Integer tableRowHeight;

    final public JConceptsTable<A> setAddCountToEnclosingTab(boolean addCountToEnclosingTab) {
      return addCountToEnclosingTab(addCountToEnclosingTab);
    }

    public JConceptsTable<A> addCountToEnclosingTab(boolean addCountToEnclosingTab) {
      this.addCountToEnclosingTab = addCountToEnclosingTab;
      return this;
    }

    final public boolean getAddCountToEnclosingTab() {
      return addCountToEnclosingTab();
    }

    public boolean addCountToEnclosingTab() {
      return addCountToEnclosingTab;
    }

    public boolean addCountToEnclosingTab = false;

    public AWTOnConceptChanges changeHandler;

    public JConceptsTable() {
    }

    public JConceptsTable(Class<? extends A> conceptClass) {
      this.conceptClass = conceptClass;
    }

    public JConceptsTable(Concepts concepts, Class<? extends A> conceptClass) {
      this.conceptClass = conceptClass;
      this.concepts = concepts;
    }

    transient public IF1<A, Map<String, Object>> itemToMap;

    public Map<String, Object> itemToMap(A a) {
      return itemToMap != null ? itemToMap.get(a) : itemToMap_base(a);
    }

    final public Map<String, Object> itemToMap_fallback(IF1<A, Map<String, Object>> _f, A a) {
      return _f != null ? _f.get(a) : itemToMap_base(a);
    }

    public Map<String, Object> itemToMap_base(A a) {
      return putAll(specialFieldsForItem(a), mapValues(__52 -> renderForTable_noStruct(__52), itemToMap_inner2(a)));
    }

    transient public IF1<A, Map<String, Object>> itemToMap_inner2;

    public Map<String, Object> itemToMap_inner2(A a) {
      return itemToMap_inner2 != null ? itemToMap_inner2.get(a) : itemToMap_inner2_base(a);
    }

    final public Map<String, Object> itemToMap_inner2_fallback(IF1<A, Map<String, Object>> _f, A a) {
      return _f != null ? _f.get(a) : itemToMap_inner2_base(a);
    }

    public Map<String, Object> itemToMap_inner2_base(A a) {
      return allConceptFieldsAsMapExcept(a, dropFields);
    }

    transient public IF1<A, Map<String, Object>> specialFieldsForItem;

    public Map<String, Object> specialFieldsForItem(A a) {
      return specialFieldsForItem != null ? specialFieldsForItem.get(a) : specialFieldsForItem_base(a);
    }

    final public Map<String, Object> specialFieldsForItem_fallback(IF1<A, Map<String, Object>> _f, A a) {
      return _f != null ? _f.get(a) : specialFieldsForItem_base(a);
    }

    public Map<String, Object> specialFieldsForItem_base(A a) {
      Map<String, Object> map = litorderedmap(hID, str(a.id));
      mapPut(map, "Java Class", javaClassDescForItem(a));
      return map;
    }

    public String javaClassDescForItem(A a) {
      String className = dynShortClassName(a);
      if (neq(className, shortClassName(conceptClass))) {
        String text = className;
        String realClass = shortClassName(a);
        if (neq(className, realClass))
          text += " as " + realClass;
        return text;
      }
      return null;
    }

    public String defaultTitle() {
      return plural(shortClassName(conceptClass));
    }

    public void showAsFrame() {
      showAsFrame(defaultTitle());
    }

    public void showAsFrame(String title) {
      makeTable();
      showFrame(title, table);
    }

    public void makeTable() {
      if (table != null)
        return;
      if (concepts == null)
        concepts = db_mainConcepts();
      table = sexyTable();
      if (tableFontSize != null) {
        setTableFontSizes(tableFontSize, table);
        if (tableRowHeight == null)
          tableRowHeight = iround(tableFontSize * 1.5);
      }
      if (tableRowHeight != null)
        setRowHeight(table, tableRowHeight);
      changeHandler = new AWTOnConceptChanges(concepts, table, () -> _update()).delay(updateInterval).firstDelay(firstUpdateInterval);
      changeHandler.install();
    }

    public void update() {
      {
        swing(() -> {
          _update();
        });
      }
    }

    public void _update() {
      List<Map> data = new ArrayList();
      Collection<? extends A> l = list(concepts, conceptClass);
      l = postProcess(sorter, l);
      for (A c : l) addIfNotNull(data, itemToMap(c));
      if (latestFirst)
        reverseInPlace(data);
      data = (List) postProcess(postProcess, data);
      dataToTable_uneditable(data, table);
      if (humanizeFieldNames)
        humanizeTableColumns();
      tableColumnMaxWidth(table, 0, idWidth);
      if (addCountToEnclosingTab)
        updateEnclosingTabTitleWithCount(table, l(data));
      pcallF(afterUpdate);
    }

    public void humanizeTableColumns() {
      int n = tableColumnCount(table);
      for (int i = 0; i < n; i++) setColumnName(table, i, humanizeFormLabel(getColumnName(table, i)));
    }

    public JComponent visualize() {
      return table();
    }

    public JTable table() {
      makeTable();
      return table;
    }

    public A selectedConcept() {
      return (A) concepts.getConcept(toLong(selectedTableCell(table, 0)));
    }

    public A selected() {
      return selectedConcept();
    }

    public A getItem(int row) {
      return (A) concepts.getConcept(toLong(getTableCell(table, row, 0)));
    }

    public int indexOfConcept(final A c) {
      if (c == null)
        return -1;
      return swing(new F0<Integer>() {

        public Integer get() {
          try {
            int n = tableRowCount(table);
            for (int row = 0; row < n; row++) if (toLong(getTableCell(table, row, 0)) == c.id)
              return row;
            return -1;
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "int n = tableRowCount(table);\r\n      for row to n:\r\n        if (toLong(getTab...";
        }
      });
    }

    public List<A> selectedConcepts() {
      int[] rows = table.getSelectedRows();
      List<A> l = new ArrayList();
      for (int row : rows) l.add(getItem(row));
      return l;
    }

    public Collection<A> defaultSort(Collection<A> l) {
      return sortByConceptID(l);
    }
  }

  abstract static public class RegionPainter {

    final public RegionPainter setZoomX(double zoomX) {
      return zoomX(zoomX);
    }

    public RegionPainter zoomX(double zoomX) {
      this.zoomX = zoomX;
      return this;
    }

    final public double getZoomX() {
      return zoomX();
    }

    public double zoomX() {
      return zoomX;
    }

    public double zoomX;

    final public RegionPainter setZoomY(double zoomY) {
      return zoomY(zoomY);
    }

    public RegionPainter zoomY(double zoomY) {
      this.zoomY = zoomY;
      return this;
    }

    final public double getZoomY() {
      return zoomY();
    }

    public double zoomY() {
      return zoomY;
    }

    public double zoomY;

    final public RegionPainter setRegions(FastRegions_BWImage regions) {
      return regions(regions);
    }

    public RegionPainter regions(FastRegions_BWImage regions) {
      this.regions = regions;
      return this;
    }

    final public FastRegions_BWImage getRegions() {
      return regions();
    }

    public FastRegions_BWImage regions() {
      return regions;
    }

    public FastRegions_BWImage regions;

    final public RegionPainter setIRegion(int iRegion) {
      return iRegion(iRegion);
    }

    public RegionPainter iRegion(int iRegion) {
      this.iRegion = iRegion;
      return this;
    }

    final public int getIRegion() {
      return iRegion();
    }

    public int iRegion() {
      return iRegion;
    }

    public int iRegion;

    final public RegionPainter setG(Graphics2D g) {
      return g(g);
    }

    public RegionPainter g(Graphics2D g) {
      this.g = g;
      return this;
    }

    final public Graphics2D getG() {
      return g();
    }

    public Graphics2D g() {
      return g;
    }

    public Graphics2D g;

    abstract public void drawRegion();
  }

  static public class FastRegions_BWImage implements Runnable, IFieldsToList {

    public BWImage image;

    public FastRegions_BWImage() {
    }

    public FastRegions_BWImage(BWImage image) {
      this.image = image;
    }

    public String toString() {
      return shortClassName_dropNumberPrefix(this) + "(" + image + ")";
    }

    public Object[] _fieldsToList() {
      return new Object[] { image };
    }

    public int w, h, runner;

    final public int getSize() {
      return size();
    }

    public int size() {
      return size;
    }

    public int size;

    public IntBuffer stack = new IntBuffer();

    public int[] regionMatrix;

    public IntBuffer regionPixels = new IntBuffer();

    public IntBuffer regionFirstPixel;

    public IntBuffer regionSize;

    public IntBuffer regionBounds;

    public int regionCounter;

    public boolean verbose = false;

    public double regionStep = .1;

    public int x(int pos) {
      return pos % w;
    }

    public int y(int pos) {
      return pos / w;
    }

    public int pos(int x, int y) {
      return y * w + x;
    }

    public Pt pt(int pos) {
      return new Pt(x(pos), y(pos));
    }

    public boolean validPos(int x, int y) {
      return x >= 0 && y >= 0 && x < w && y < h;
    }

    public int getColor(int pos) {
      return image.getInt(x(pos), y(pos));
    }

    public FastRegions_BWImage(BufferedImage img) {
      this(toBWImage(img));
    }

    public void run() {
      try {
        w = image.getWidth();
        h = image.getHeight();
        size = w * h;
        regionMatrix = new int[size];
        {
          if (regionFirstPixel != null)
            regionFirstPixel.add(0);
        }
        {
          if (regionPixels != null)
            regionPixels.setSize(size);
        }
        while (runner < size) {
          if (regionMatrix[runner] == 0) {
            int region = ++regionCounter;
            {
              if (regionFirstPixel != null)
                regionFirstPixel.add(regionPixels != null ? l(regionPixels) : runner);
            }
            stack.add(runner);
            int color = getColor(runner);
            int rsize = 0, x1 = w, y1 = h, x2 = 0, y2 = 0;
            while (nempty(stack)) {
              int pos = stack.popLast();
              if (regionMatrix[pos] != 0)
                continue;
              if (getColor(pos) != color)
                continue;
              regionMatrix[pos] = region;
              ++rsize;
              {
                if (regionPixels != null)
                  regionPixels.add(pos);
              }
              int x = x(pos), y = y(pos);
              if (x < x1)
                x1 = x;
              if (x > x2)
                x2 = x;
              if (y < y1)
                y1 = y;
              if (y > y2)
                y2 = y;
              if (x > 0)
                stack.add(pos - 1);
              if (x < w - 1)
                stack.add(pos + 1);
              if (y > 0)
                stack.add(pos - w);
              if (y < h - 1)
                stack.add(pos + w);
            }
            {
              if (regionSize != null)
                regionSize.add(rsize);
            }
            {
              if (regionBounds != null)
                regionBounds.addAll(x1, y1, x2, y2);
            }
          }
          ++runner;
        }
      } catch (Exception __e) {
        throw rethrow(__e);
      }
    }

    public 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 public class RegionIterator {

      public int pos;

      abstract public boolean next();

      public int pos() {
        return pos;
      }

      public int x() {
        return FastRegions_BWImage.this.x(pos);
      }

      public int y() {
        return FastRegions_BWImage.this.y(pos);
      }
    }

    public class FloodRegionIterator extends RegionIterator {

      public int region;

      public IntBuffer stack = new IntBuffer();

      public BitSet seen = new BitSet(size);

      public FloodRegionIterator(int region) {
        this.region = region;
        int pos = regionFirstPixel.get(region);
        printVars("region", region, "pos", pos);
        seen.set(pos);
        stack.add(pos);
      }

      public boolean next() {
        if (empty(stack))
          return false;
        pos = stack.popLast();
        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;
      }

      final public void tryPosition(int p) {
        if (!seen.get(p) && regionMatrix[p] == region) {
          seen.set(p);
          stack.add(p);
        }
      }
    }

    public class CachedRegionIterator extends RegionIterator {

      public int i, to;

      public CachedRegionIterator(int region) {
        i = regionFirstPixel.get(region);
        to = region + 1 < l(regionFirstPixel) ? regionFirstPixel.get(region + 1) : l(regionPixels);
      }

      public boolean next() {
        if (i >= to)
          return false;
        pos = regionPixels.get(i++);
        return true;
      }
    }

    public int regionSize(int iRegion) {
      return regionSize.get(iRegion);
    }

    final public Pt firstPixel(int iRegion) {
      return samplePixel(iRegion);
    }

    public Pt samplePixel(int iRegion) {
      int i = regionFirstPixel.get(iRegion);
      return pt(regionPixels != null ? regionPixels.get(i) : i);
    }

    public boolean inRegion(int iRegion, int x, int y) {
      return validPos(x, y) && regionMatrix[pos(x, y)] == iRegion;
    }

    public 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));
    }

    public int regionAt(int x, int y) {
      return !validPos(x, y) ? 0 : regionMatrix[pos(x, y)];
    }

    public RegionIterator regionIterator(int iRegion) {
      return regionPixels != null ? new FloodRegionIterator(iRegion) : new CachedRegionIterator(iRegion);
    }

    public void collectFirstPixels() {
      regionFirstPixel = new IntBuffer();
    }

    public void collectBounds() {
      regionBounds = new IntBuffer();
    }

    public Matrix<Boolean> regionBitMatrix(int iRegion) {
      return new AbstractMatrix<Boolean>(w, h) {

        public Boolean get(int x, int y) {
          return inRegion(iRegion, x, y);
        }
      };
    }
  }

  static public interface ISetter<A> {

    public void set(A a);
  }

  static public class DoneFlag extends Flag {

    transient volatile public Object error;

    transient public boolean printErrors = false;

    public DoneFlag() {
    }

    public DoneFlag(boolean printErrors) {
      this.printErrors = printErrors;
    }

    public void done() {
      raise();
    }

    final public void setError(Object error) {
      done(error);
    }

    public void done(Object error) {
      this.error = error;
      if (printErrors)
        printStackTrace_gen(error);
      raise();
    }

    public boolean hasError() {
      return error != null;
    }

    public boolean isDone() {
      return isUp();
    }
  }

  static public class WeakVar<A> implements IVar<A> {

    public WeakReference<A> ref;

    public synchronized void set(A a) {
      ref = weakRef(a);
    }

    public synchronized A get() {
      if (ref == null)
        return null;
      A value = ref.get();
      if (value == null)
        ref = null;
      return value;
    }
  }

  static public class RegionBoundingBoxPainter extends RegionPainter {

    final public RegionBoundingBoxPainter setLineWidth(int lineWidth) {
      return lineWidth(lineWidth);
    }

    public RegionBoundingBoxPainter lineWidth(int lineWidth) {
      this.lineWidth = lineWidth;
      return this;
    }

    final public int getLineWidth() {
      return lineWidth();
    }

    public int lineWidth() {
      return lineWidth;
    }

    public int lineWidth = 3;

    public void drawRegion() {
      Rect r = regions.regionBounds(iRegion);
      g.setColor(withOpacity(.75, Color.red));
      AutoCloseable __1 = tempSetStroke(g, new BasicStroke(lineWidth));
      try {
        drawRect(g, growRectTopAndLeft(scaleRect_floor(growRectRightAndBottom(r), zoomX, zoomY)));
      } finally {
        _close(__1);
      }
    }
  }

  static public interface IHasGlobalID {

    public GlobalID globalID();
  }

  static public class SynchronizedRandomAccessList<E> extends SynchronizedList<E> implements RandomAccess {

    public SynchronizedRandomAccessList() {
    }

    public SynchronizedRandomAccessList(List<E> list) {
      super(list);
    }

    public SynchronizedRandomAccessList(List<E> list, Object mutex) {
      super(list, mutex);
    }

    public List<E> subList(int fromIndex, int toIndex) {
      synchronized (mutex) {
        return new SynchronizedRandomAccessList<>(list.subList(fromIndex, toIndex), mutex);
      }
    }

    @java.io.Serial
    static final public long serialVersionUID = 1530674583602358482L;

    @java.io.Serial
    final public Object writeReplace() {
      return new SynchronizedList<>(list);
    }
  }

  static public class SynchronizedCollection<E> implements Collection<E>, Serializable {

    public SynchronizedCollection() {
    }

    @java.io.Serial
    static final public long serialVersionUID = 3053995032091335093L;

    @SuppressWarnings("serial")
    public Collection<E> c;

    @SuppressWarnings("serial")
    public Object mutex;

    public SynchronizedCollection(Collection<E> c) {
      this.c = Objects.requireNonNull(c);
      mutex = this;
    }

    public SynchronizedCollection(Collection<E> c, Object mutex) {
      this.c = Objects.requireNonNull(c);
      this.mutex = Objects.requireNonNull(mutex);
    }

    public int size() {
      synchronized (mutex) {
        return c.size();
      }
    }

    public boolean isEmpty() {
      synchronized (mutex) {
        return c.isEmpty();
      }
    }

    public boolean contains(Object o) {
      synchronized (mutex) {
        return c.contains(o);
      }
    }

    public Object[] toArray() {
      synchronized (mutex) {
        return c.toArray();
      }
    }

    public <T> T[] toArray(T[] a) {
      synchronized (mutex) {
        return c.toArray(a);
      }
    }

    public <T> T[] toArray(java.util.function.IntFunction<T[]> f) {
      synchronized (mutex) {
        return c.toArray(f);
      }
    }

    public Iterator<E> iterator() {
      return c.iterator();
    }

    public boolean add(E e) {
      synchronized (mutex) {
        return c.add(e);
      }
    }

    public boolean remove(Object o) {
      synchronized (mutex) {
        return c.remove(o);
      }
    }

    public boolean containsAll(Collection<?> coll) {
      synchronized (mutex) {
        return c.containsAll(coll);
      }
    }

    public boolean addAll(Collection<? extends E> coll) {
      synchronized (mutex) {
        return c.addAll(coll);
      }
    }

    public boolean removeAll(Collection<?> coll) {
      synchronized (mutex) {
        return c.removeAll(coll);
      }
    }

    public boolean retainAll(Collection<?> coll) {
      synchronized (mutex) {
        return c.retainAll(coll);
      }
    }

    public void clear() {
      synchronized (mutex) {
        c.clear();
      }
    }

    public String toString() {
      synchronized (mutex) {
        return c.toString();
      }
    }

    @Override
    public void forEach(java.util.function.Consumer<? super E> consumer) {
      synchronized (mutex) {
        c.forEach(consumer);
      }
    }

    @Override
    public boolean removeIf(java.util.function.Predicate<? super E> filter) {
      synchronized (mutex) {
        return c.removeIf(filter);
      }
    }

    @Override
    public Spliterator<E> spliterator() {
      return c.spliterator();
    }

    @Override
    public java.util.stream.Stream<E> stream() {
      return c.stream();
    }

    @Override
    public java.util.stream.Stream<E> parallelStream() {
      return c.parallelStream();
    }

    @java.io.Serial
    final public void writeObject(ObjectOutputStream s) throws IOException {
      synchronized (mutex) {
        s.defaultWriteObject();
      }
    }
  }

  static public class FPSCounter {

    public Timestamp started = new Timestamp();

    public double counter;

    synchronized public void inc() {
      counter++;
    }

    synchronized public double get() {
      return doubleRatio(counter, secondsSinceStart());
    }

    public double secondsSinceStart() {
      return elapsedSeconds(started);
    }

    synchronized public void reset() {
      started = tsNow();
      counter = 0;
    }
  }

  static public class GazelleVScript implements IFieldsToList {

    public String text;

    public GazelleVScript() {
    }

    public GazelleVScript(String text) {
      this.text = text;
    }

    public String toString() {
      return shortClassName_dropNumberPrefix(this) + "(" + text + ")";
    }

    public Object[] _fieldsToList() {
      return new Object[] { text };
    }

    public List<String> tok;

    static public String helpText = "Gazelle V Script\r\n----------------\r\n\r\nSeparate commands with spaces. Language is case-insensitive.\r\nComments like in Java with /* */ or //\r\n\r\n1p, 2p etc: Scale image down to x pixels\r\n1c, 2c, ..., 256c: Reduce gray scale levels\r\n1w, 2w etc: Scale image width only to x pixels\r\nstruct: show object structure\r\nniceStruct: show object structure indented\r\nrasters: reproduce horizontal bars\r\nclassName: show type of object on stack\r\nq1...q4: select quadrant\r\noriginal: show input image in color\r\n";

    public class Sequence {

      public Map<String, Object> vars = new HashMap();
    }

    public class Run implements Steppable {

      public ListAndIndex<String> ptr;

      public String token;

      public Stack stack = new Stack();

      final public Run setInputImage(IBWIntegralImage inputImage) {
        return inputImage(inputImage);
      }

      public Run inputImage(IBWIntegralImage inputImage) {
        this.inputImage = inputImage;
        return this;
      }

      final public IBWIntegralImage getInputImage() {
        return inputImage();
      }

      public IBWIntegralImage inputImage() {
        return inputImage;
      }

      public IBWIntegralImage inputImage;

      public IBWIntegralImage integralImage;

      final public Run setBwImage(BWImage bwImage) {
        return bwImage(bwImage);
      }

      public Run bwImage(BWImage bwImage) {
        this.bwImage = bwImage;
        return this;
      }

      final public BWImage getBwImage() {
        return bwImage();
      }

      public BWImage bwImage() {
        return bwImage;
      }

      public BWImage bwImage;

      public Run setIntegralImage(IBWIntegralImage ii) {
        push(integralImage = ii);
        return this;
      }

      public Run() {
        parse();
        ptr = new ListAndIndex(tok, 1);
      }

      public void push(Object o) {
        stack.add(o);
      }

      public Object value() {
        return last(stack);
      }

      public boolean step() {
        token = ptr.get();
        if (token == null)
          return false;
        next();
        if (isInteger(token)) {
          int i = parseInt(token);
          token = tpp();
          if (is("p"))
            scaleToHeight(i);
          else if (is("c"))
            posterize(i);
          else if (is("w"))
            scaleWidthOnly(i);
          else
            warn("Unknown token: " + token);
        } else if (is("rasters"))
          push(reproduceRasterBars(bwIntegralImage()));
        else if (is("struct"))
          push(struct(value()));
        else if (is("niceStruct"))
          push(sfuIndent(value()));
        else if (is("className"))
          push(className(value()));
        else if (is("q1"))
          clip(0, .5, 0, .5);
        else if (is("q2"))
          clip(.5, 1, 0, .5);
        else if (is("q3"))
          clip(0, .5, .5, 1);
        else if (is("q4"))
          clip(.5, 1, .5, 1);
        else if (is("original"))
          push(toBufferedImage(inputImage));
        else {
          warn("Unknown token: " + token);
        }
        return true;
      }

      public boolean is(String t) {
        return eqic(token, t);
      }

      public String tpp() {
        var token = ptr.get();
        next();
        return token;
      }

      public void next() {
        if (!ptr.atEnd())
          ptr = ptr.plus(2);
      }

      public void scaleToHeight(int pixelRows) {
        pixelRows = min(pixelRows, 512);
        if (integralImage == null) {
          warn("No integral image to scale down");
          return;
        }
        push(bwImage = scaledBWImageFromBWIntegralImage_withMeta_height(pixelRows, integralImage));
      }

      public void posterize(int colors) {
        colors = clamp(colors, 2, 256);
        if (bwImage == null) {
          warn("No image to posterize");
          return;
        } else
          push(bwImage = posterizeBWImage_withMeta(colors, bwImage));
      }

      public IBWIntegralImage bwIntegralImage() {
        Object val = value();
        if (val instanceof IBWIntegralImage)
          return ((IBWIntegralImage) val);
        if (val instanceof BWImage) {
          var ii = main.bwIntegralImage((BWImage) val);
          setIntegralImage(ii);
          return ii;
        }
        throw fail("Not an image on stack");
      }

      public void scaleWidthOnly(int w) {
        var ii = bwIntegralImage();
        push(bwImage = scaledBWImageFromBWIntegralImage_withMeta(ii, w, ii.getHeight()));
      }

      public void clip(double x1, double x2, double y1, double y2) {
        Object val = value();
        if (val instanceof IBWIntegralImage) {
          int w = ((IBWIntegralImage) val).getWidth(), h = ((IBWIntegralImage) val).getHeight();
          Rect r = toRect_round(scaleRect(w, h, doubleRectFromPoints(x1, y1, x2, y2)));
          setIntegralImage(new IIBWVirtualClip(((IBWIntegralImage) val), r));
        } else if (val instanceof BWImage)
          throw todo();
        else
          throw fail("Not an image on stack");
      }

      public Object result() {
        return last(stack);
      }

      public void run() {
        try {
          stepAll(this);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }
    }

    public void parse() {
      if (tok == null)
        tok = javaTok(text);
    }
  }

  abstract static public class ImageSurfaceMouseHandler extends MouseAdapter implements AutoCloseable {

    public ImageSurface is;

    public void register(ImageSurface is) {
      this.is = is;
      is.tools.add(this);
      is.addMouseListener(this);
      is.addMouseMotionListener(this);
    }

    public void close() {
      try {
        if (is == null)
          return;
        is.tools.remove(this);
        is.removeMouseListener(this);
        is.removeMouseMotionListener(this);
        is = null;
      } catch (Exception __e) {
        throw rethrow(__e);
      }
    }

    public Pt getPt(MouseEvent e) {
      return toPt(getPoint(e));
    }

    public Point getPoint(MouseEvent e) {
      return new Point((int) (e.getX() / is.getZoomX()), (int) (e.getY() / is.getZoomY()));
    }
  }

  static public class ListAndIndex<A> implements IFieldsToList {

    static final public String _fieldOrder = "list idx";

    public List<A> list;

    public int idx;

    public ListAndIndex() {
    }

    public ListAndIndex(List<A> list, int idx) {
      this.idx = idx;
      this.list = list;
    }

    public boolean equals(Object o) {
      if (!(o instanceof ListAndIndex))
        return false;
      ListAndIndex __1 = (ListAndIndex) o;
      return eq(list, __1.list) && idx == __1.idx;
    }

    public int hashCode() {
      int h = 276903961;
      h = boostHashCombine(h, _hashCode(list));
      h = boostHashCombine(h, _hashCode(idx));
      return h;
    }

    public Object[] _fieldsToList() {
      return new Object[] { list, idx };
    }

    public boolean atEnd() {
      return idx >= l(list);
    }

    public A get() {
      return _get(list, idx);
    }

    public int size() {
      return l(list);
    }

    public String toString() {
      return subList(list, 0, idx) + ", then " + subList(list, idx);
    }

    public ListAndIndex<A> plus(int ofs) {
      return new ListAndIndex(list, idx + ofs);
    }
  }

  static public class IIBWVirtualClip extends Meta implements IBWIntegralImage {

    public IBWIntegralImage fullImage;

    public int x1, y1, w, h;

    public IIBWVirtualClip() {
    }

    public IIBWVirtualClip(IBWIntegralImage fullImage, Rect r) {
      this(fullImage, r.x, r.y, r.w, r.h);
    }

    public IIBWVirtualClip(IBWIntegralImage fullImage, int x1, int y1, int w, int h) {
      this.h = h;
      this.w = w;
      this.y1 = y1;
      this.x1 = x1;
      this.fullImage = fullImage;
      optimize();
    }

    public int getWidth() {
      return w;
    }

    public int getHeight() {
      return h;
    }

    public int getIIValue(int x, int y) {
      return fullImage.getIIValue(x + x1, y + y1);
    }

    public double getIIValue(double x, double y) {
      return fullImage.getIIValue(x + x1, y + y1);
    }

    public BufferedImage getBufferedImage() {
      return clipBufferedImage(fullImage.getBufferedImage(), x1, y1, w, h);
    }

    public void optimize() {
      if (fullImage instanceof IIBWVirtualClip) {
        x1 += ((IIBWVirtualClip) fullImage).x1;
        y1 += ((IIBWVirtualClip) fullImage).y1;
        fullImage = ((IIBWVirtualClip) fullImage).fullImage;
      }
    }
  }

  static public class Flag implements Runnable {

    public boolean up = false;

    public synchronized boolean raise() {
      if (!up) {
        up = true;
        notifyAll();
        return true;
      } else
        return false;
    }

    public synchronized void waitUntilUp() {
      while (!up) {
        try {
          wait();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }

    public boolean waitUntilUp(double timeout) {
      return waitUntilUp(toMS(timeout));
    }

    public synchronized boolean waitUntilUp(long timeout) {
      if (!up) {
        try {
          wait(timeout);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
      return isUp();
    }

    public synchronized boolean isUp() {
      return up;
    }

    public boolean get() {
      return isUp();
    }

    public String toString() {
      return isUp() ? "up" : "down";
    }

    public void waitForThisOr(Flag otherFlag) {
      try {
        while (!isUp() && !otherFlag.isUp()) Thread.sleep(50);
      } catch (Exception __e) {
        throw rethrow(__e);
      }
    }

    public void run() {
      raise();
    }
  }

  static public class AWTOnConceptChanges implements AutoCloseable {

    final public AWTOnConceptChanges setComponent(JComponent component) {
      return component(component);
    }

    public AWTOnConceptChanges component(JComponent component) {
      this.component = component;
      return this;
    }

    final public JComponent getComponent() {
      return component();
    }

    public JComponent component() {
      return component;
    }

    public JComponent component;

    final public AWTOnConceptChanges setAction(Runnable action) {
      return action(action);
    }

    public AWTOnConceptChanges action(Runnable action) {
      this.action = action;
      return this;
    }

    final public Runnable getAction() {
      return action();
    }

    public Runnable action() {
      return action;
    }

    public Runnable action;

    final public AWTOnConceptChanges setConcepts(Concepts concepts) {
      return concepts(concepts);
    }

    public AWTOnConceptChanges concepts(Concepts concepts) {
      this.concepts = concepts;
      return this;
    }

    final public Concepts getConcepts() {
      return concepts();
    }

    public Concepts concepts() {
      return concepts;
    }

    public Concepts concepts;

    final public AWTOnConceptChanges setFirstDelay(int firstDelay) {
      return firstDelay(firstDelay);
    }

    public AWTOnConceptChanges firstDelay(int firstDelay) {
      this.firstDelay = firstDelay;
      return this;
    }

    final public int getFirstDelay() {
      return firstDelay();
    }

    public int firstDelay() {
      return firstDelay;
    }

    public int firstDelay;

    final public AWTOnConceptChanges setDelay(int delay) {
      return delay(delay);
    }

    public AWTOnConceptChanges delay(int delay) {
      this.delay = delay;
      return this;
    }

    final public int getDelay() {
      return delay();
    }

    public int delay() {
      return delay;
    }

    public int delay = 500;

    public long changes = -1;

    public javax.swing.Timer timer;

    public AWTOnConceptChanges(Concepts concepts, JComponent component, Runnable action) {
      this.action = action;
      this.component = component;
      this.concepts = concepts;
    }

    public void install() {
      assertNotNull(concepts);
      timer = installTimer(component, delay, firstDelay, new Runnable() {

        public void run() {
          try {
            _trigger();
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "_trigger();";
        }
      });
    }

    public void _trigger() {
      long c = concepts.changes;
      if (changes != c) {
        changes = c;
        {
          if (action != null)
            action.run();
        }
      }
    }

    public void close() {
      try {
        {
          cleanUp(timer);
          timer = null;
        }
      } catch (Exception __e) {
        throw rethrow(__e);
      }
    }
  }

  static public boolean containsInstance(Iterable i, Class c) {
    if (i != null)
      for (Object o : i) if (isInstanceX(c, o))
        return true;
    return false;
  }

  static public Class<?> getClass(String name) {
    return _getClass(name);
  }

  static public Class getClass(Object o) {
    return _getClass(o);
  }

  static public Class getClass(Object realm, String name) {
    return _getClass(realm, name);
  }

  static public void register(Concept c) {
    registerConcept(c);
  }

  static public AutoCloseable tempAfterwards(final Object r) {
    return new AutoCloseable() {

      public void close() {
        callF(r);
      }
    };
  }

  static public <A, B> void put(Map<A, B> map, A a, B b) {
    if (map != null)
      map.put(a, b);
  }

  static public <A> void put(List<A> l, int i, A a) {
    if (l != null && i >= 0 && i < l(l))
      l.set(i, a);
  }

  static public Area regionToArea(FastRegions_BWImage regions, int iRegion) {
    return bitMatrixToArea(regions.regionBitMatrix(iRegion));
  }

  static public Color withOpacity(Color c, double alpha) {
    return colorWithAlpha(c, alpha);
  }

  static public Color withOpacity(double alpha, Color c) {
    return colorWithAlpha(alpha, c);
  }

  static public void fillShape(Graphics2D g, Shape shape) {
    if (g != null && shape != null)
      g.fill(shape);
  }

  static public JFrame showFrame() {
    return makeFrame();
  }

  static public JFrame showFrame(Object content) {
    return makeFrame(content);
  }

  static public JFrame showFrame(String title) {
    return makeFrame(title);
  }

  static public JFrame showFrame(String title, Object content) {
    return makeFrame(title, content);
  }

  static public JFrame showFrame(final JFrame f) {
    if (f != null) {
      swing(() -> {
        if (frameTooSmall(f))
          frameStandardSize(f);
        if (!f.isVisible())
          f.setVisible(true);
        if (f.getState() == Frame.ICONIFIED)
          f.setState(Frame.NORMAL);
      });
    }
    return f;
  }

  static public JFrame showFrame(String title, Object content, JFrame frame) {
    if (frame == null)
      return showFrame(title, content);
    else {
      frame.setTitle(title);
      setFrameContents(frame, content);
      return frame;
    }
  }

  static public String plural(String s) {
    return getPlural(s);
  }

  static public String shortClassName(Object o) {
    if (o == null)
      return null;
    Class c = o instanceof Class ? (Class) o : o.getClass();
    String name = c.getName();
    return shortenClassName(name);
  }

  static volatile public boolean framesBot_has = false;

  static public Android3 framesBot() {
    if (framesBot_has)
      return null;
    framesBot_has = true;
    Android3 android = new Android3();
    android.greeting = programIDPlusHome() + " Frames.";
    android.console = false;
    android.responder = new Responder() {

      public String answer(String s, List<String> history) {
        if (match("activate frames", s)) {
          swingLater(new Runnable() {

            public void run() {
              try {
                activateMyFrames();
              } catch (Exception __e) {
                throw rethrow(__e);
              }
            }

            public String toString() {
              return "// prevent blocking when called from same program's AWT thread\r\n          act...";
            }
          });
          return "OK, activating " + programName();
        }
        return null;
      }
    };
    return makeBot(android);
  }

  static public <A, B> Map<A, B> putAll(Map<A, B> a, Map<? extends A, ? extends B> b) {
    if (a != null && b != null)
      a.putAll(b);
    return a;
  }

  static public <A, B> MultiMap<A, B> putAll(MultiMap<A, B> a, Map<? extends A, ? extends B> b) {
    if (a != null)
      a.putAll((Map) b);
    return a;
  }

  static public <A, B> Map<A, B> putAll(Map<A, B> a, Object... b) {
    if (a != null)
      litmap_impl(a, b);
    return a;
  }

  static public LinkedHashMap litorderedmap(Object... x) {
    LinkedHashMap map = new LinkedHashMap();
    litmap_impl(map, x);
    return map;
  }

  static public List<Concept> allBackRefs(Concept c) {
    IdentityHashMap<Concept, Boolean> l = new IdentityHashMap();
    if (c != null && c.backRefs != null)
      for (Concept.Ref r : cloneList(c.backRefs)) l.put(r.concept(), true);
    return keysList(l);
  }

  static public <A extends Concept> List<A> sortedByConceptID(Collection<A> c) {
    return sortedByCalculatedField(__53 -> conceptID(__53), c);
  }

  static public JButton tableDependButton(JTable tbl, JButton b) {
    tableDependButtons(tbl, ll(b));
    return b;
  }

  static public JButton tableDependButton(JTable tbl, String text, Object action) {
    return tableDependButton(tbl, jbutton(text, action));
  }

  static public <A extends Concept> A selectedConcept(JTable table, Class<A> cc) {
    return (A) getConcept(toLong(selectedTableCell(table, 0)));
  }

  static public class TableSearcher {

    public JTable table;

    public JTextField tfInput;

    public JComponent searchPanel, panel;

    public F2<String, Map, Boolean> rowTester;

    public List<Integer> rowIndices;

    public String input() {
      return gtt(tfInput);
    }
  }

  static public TableSearcher tableWithSearcher2(final JTable t, Object... __) {
    final TableSearcher s = new TableSearcher();
    final boolean precise = true;
    s.table = t;
    s.tfInput = jtextfield();
    s.rowTester = new F2<String, Map, Boolean>() {

      public Boolean get(String pat, Map row) {
        try {
          return anyValueContainsIgnoreCase(row, pat);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "anyValueContainsIgnoreCase(row, pat)";
      }
    };
    onUpdate(s.tfInput, new Runnable() {

      public List lastFiltered, lastOriginal;

      public void run() {
        String pat = s.input();
        List<Map<String, Object>> data = rawTableData(t);
        if (eq(lastFiltered, data))
          data = lastOriginal;
        List data2 = new ArrayList();
        List<Integer> rowIndices = new ArrayList();
        for (int i = 0; i < l(data); i++) {
          Map<String, Object> map = data.get(i);
          if (isTrue(callF(s.rowTester, pat, map))) {
            data2.add(map);
            rowIndices.add(i);
          }
        }
        lastFiltered = data2;
        lastOriginal = data;
        dataToTable(t, data2);
        if (precise)
          lastFiltered = rawTableData(t);
        s.rowIndices = rowIndices;
      }
    });
    s.searchPanel = withLabel("Search:", s.tfInput);
    JComponent top = s.searchPanel;
    s.panel = boolOptPar(__, "withMargin") ? northAndCenterWithMargin(top, t) : northAndCenter(top, t);
    return s;
  }

  static public void tablePopupMenuItem(JTable table, String name, Object action) {
    tablePopupMenu(table, new VF2<JPopupMenu, Integer>() {

      public void get(JPopupMenu menu, final Integer row) {
        try {
          addMenuItem(menu, name, new Runnable() {

            public void run() {
              try {
                pcallF(action, row);
              } catch (Exception __e) {
                throw rethrow(__e);
              }
            }

            public String toString() {
              return "pcallF(action, row)";
            }
          });
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "addMenuItem(menu, name, r { pcallF(action, row) });";
      }
    });
  }

  static public void tablePopupMenuItem(JTable table, String name, IVF1<Integer> action) {
    tablePopupMenuItem(table, name, (Object) action);
  }

  static public JList onDoubleClick(final JList list, final Object runnable) {
    {
      swing(() -> {
        list.addMouseListener(new MouseAdapter() {

          public void mouseClicked(MouseEvent evt) {
            if (evt.getClickCount() == 2) {
              int idx = list.locationToIndex(evt.getPoint());
              Object item = list.getModel().getElementAt(idx);
              list.setSelectedIndex(idx);
              callF(runnable, item);
            }
          }
        });
      });
    }
    return list;
  }

  static public JTable onDoubleClick(final JTable table, final Object runnable) {
    {
      swing(() -> {
        table.addMouseListener(new MouseAdapter() {

          public void mouseClicked(MouseEvent evt) {
            if (evt.getClickCount() == 2) {
              int idx = table.rowAtPoint(evt.getPoint());
              table.setRowSelectionInterval(idx, idx);
              callF(runnable, idx);
            }
          }
        });
      });
    }
    return table;
  }

  static public void onDoubleClick(final JComponent c, final Object runnable) {
    {
      swing(() -> {
        c.addMouseListener(new MouseAdapter() {

          public void mouseClicked(MouseEvent evt) {
            if (evt.getButton() == 1 && evt.getClickCount() == 2)
              callF(runnable, evt.getPoint());
          }
        });
      });
    }
  }

  static public void addMenuItem(JPopupMenu menu, String text, Object action) {
    menu.add(jmenuItem(text, action));
  }

  static public void addMenuItem(JPopupMenu menu, JMenuItem menuItem) {
    menu.add(menuItem);
  }

  static public void addMenuItem(JMenu menu, String text, Object action) {
    menu.add(jmenuItem(text, action));
  }

  static public void addMenuItem(Menu menu, String text, Object action) {
    menu.add(menuItem(text, action));
  }

  static public void addMenuItem(JMenu menu, JMenuItem menuItem) {
    menu.add(menuItem);
  }

  static public void addMenuItem(JMenuBar menuBar, String text, Runnable action) {
    addMenuItem(menuBar, jmenuItem(text, action));
  }

  static public void addMenuItem(JMenuBar menuBar, JMenuItem menuItem) {
    addDirectMenuItem(menuBar, menuItem);
  }

  static public <A extends Concept> A unlisted(Class<A> c, Object... args) {
    concepts_unlisted.set(true);
    try {
      return nuObject(c, args);
    } finally {
      concepts_unlisted.set(null);
    }
  }

  static public Concept unlisted(String name, Object... args) {
    Class<? extends Concept> cc = findClass(name);
    concepts_unlisted.set(true);
    try {
      return cc != null ? nuObject(cc) : new Concept(name);
    } finally {
      concepts_unlisted.set(null);
    }
  }

  static public <A extends Concept> A ccopyFieldsExcept(Concept x, A y, Set<String> dontCopyFields) {
    if (x == null || y == null)
      return y;
    return ccopyFields2(x, y, setMinusSet(conceptFields(x), dontCopyFields));
  }

  static public AutoCloseable tempSetMCOpt(final String field, Object value) {
    final Object oldValue = getMCOpt(field);
    setMCOpt(field, value);
    return new AutoCloseable() {

      public String toString() {
        return "setMCOpt(field, oldValue);";
      }

      public void close() throws Exception {
        setMCOpt(field, oldValue);
      }
    };
  }

  static public <A extends JComponent> A renameSubmitButton(A form, String newName) {
    renameButton(form, showFormSubmitButtonName(), newName);
    return form;
  }

  static public <A extends JComponent> A renameSubmitButton(String newName, A form) {
    return renameSubmitButton(form, newName);
  }

  static public <A> List<A> listPlus(Collection<A> l, A... more) {
    return concatLists(l, asList(more));
  }

  static public <A extends Concept> A replaceConceptAndUpdateRefs(Concept a, A b) {
    assertTrue("object to replace with must be unlisted", isUnlisted(b));
    Concepts cc = a.concepts();
    assertTrue("object to replace must be listed", cc != null);
    List<Concept.Ref> refs = allBackRefObjects(a);
    b.id = a.id;
    deleteConcept(a);
    cc.register_phase2(b);
    cset(a, "meta_migratedTo", b);
    for (Concept.Ref ref : refs) ref.set(b);
    return b;
  }

  static public JCheckBox jCenteredCheckBox() {
    return centerCheckBox(new JCheckBox());
  }

  static public JCheckBox jCenteredCheckBox(boolean checked) {
    return centerCheckBox(new JCheckBox("", checked));
  }

  static public JCheckBox jCenteredCheckBox(String text, boolean checked) {
    return centerCheckBox(new JCheckBox(text, checked));
  }

  static public JCheckBox jCenteredCheckBox(String text) {
    return centerCheckBox(new JCheckBox(text));
  }

  static public JCheckBox jCenteredCheckBox(String text, boolean checked, final Object onChange) {
    return centerCheckBox(jCheckBox(text, checked, onChange));
  }

  static public JCheckBox jCenteredCheckBox(boolean checked, final Object onChange) {
    return centerCheckBox(jCheckBox(checked, onChange));
  }

  static public JTextArea typeWriterTextArea() {
    return newTypeWriterTextArea();
  }

  static public JTextArea typeWriterTextArea(String text) {
    return newTypeWriterTextArea(text);
  }

  static public boolean isSubtype(Class a, Class b) {
    return isSubclass(a, b);
  }

  static public JComboBox jcomboboxFromConcepts_str(Class<? extends Concept> cc) {
    return jcomboboxFromConcepts_str(db_mainConcepts(), cc);
  }

  static public JComboBox jcomboboxFromConcepts_str(Concepts concepts, Class<? extends Concept> cc) {
    return jcomboboxFromConcepts_str(concepts, cc, null);
  }

  static public JComboBox jcomboboxFromConcepts_str(Concepts concepts, Class<? extends Concept> cc, Concept selected) {
    List<String> items = ll("");
    String selectedItem = null;
    for (Concept c : list(concepts, cc)) {
      String item = c.id + " - " + c;
      if (c == selected)
        selectedItem = item;
      items.add(item);
    }
    return jcombobox(items, selectedItem);
  }

  static public JPasswordField jpassword() {
    return jpassword("");
  }

  static public JPasswordField jpassword(final String pw) {
    return swing(new F0<JPasswordField>() {

      public JPasswordField get() {
        try {
          return new JPasswordField(pw);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret new JPasswordField(pw);";
      }
    });
  }

  static public String structureOrText_crud(Object o) {
    if (o == null)
      return "";
    if (o instanceof Long)
      return str(o);
    if (o instanceof File)
      return ((File) o).getAbsolutePath();
    return str(o);
  }

  static public AutoComboBox autoComboBox() {
    return autoComboBox(new ArrayList());
  }

  static public AutoComboBox autoComboBox(final Collection<String> items) {
    return swing(new F0<AutoComboBox>() {

      public AutoComboBox get() {
        try {
          AutoComboBox cb = new AutoComboBox();
          cb.setKeyWord(items);
          return cb;
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "new AutoComboBox cb;\r\n    cb.setKeyWord(items);\r\n    ret cb;";
      }
    });
  }

  static public AutoComboBox autoComboBox(String value, Collection<String> items) {
    return setText(autoComboBox(items), value);
  }

  static public <A extends Throwable> A printException(A e) {
    printStackTrace(e);
    return e;
  }

  static public JTextField jTextField() {
    return jTextField("");
  }

  static public JTextField jTextField(final String text) {
    return swing(new F0<JTextField>() {

      public JTextField get() {
        try {
          JTextField tf = new JTextField(unnull(text));
          standardTextFieldPopupMenu(tf);
          jenableUndoRedo(tf);
          tf.selectAll();
          return tf;
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "JTextField tf = new JTextField(unnull(text));\r\n    standardTextFieldPopupMenu...";
      }
    });
  }

  static public JTextField jTextField(Object o) {
    return jTextField(strOrEmpty(o));
  }

  static public JComponent unwrap(JComponent c) {
    return c instanceof JScrollPane ? unwrapScrollPane((JScrollPane) c) : c;
  }

  static public String getTextTrim(JTextComponent c) {
    return trim(getText(c));
  }

  static public String getTextTrim(JComboBox cb) {
    return trim(getText(cb));
  }

  static public String getTextTrim(JComponent c) {
    if (c instanceof JLabel)
      return trim(((JLabel) c).getText());
    if (c instanceof JComboBox)
      return getTextTrim((JComboBox) c);
    return getTextTrim((JTextComponent) c);
  }

  static public String trimIf(boolean b, String s) {
    return b ? trim(s) : s;
  }

  static public String getText(final AbstractButton c) {
    return c == null ? "" : (String) swingAndWait(new F0<Object>() {

      public Object get() {
        try {
          return c.getText();
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret c.getText();";
      }
    });
  }

  static public String getText(final JTextComponent c) {
    return c == null ? "" : (String) swingAndWait(new F0<Object>() {

      public Object get() {
        try {
          return c.getText();
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret c.getText();";
      }
    });
  }

  static public String getText(final JLabel l) {
    return l == null ? "" : (String) swingAndWait(new F0<Object>() {

      public Object get() {
        try {
          return l.getText();
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret l.getText();";
      }
    });
  }

  static public String getText(final JComboBox cb) {
    if (cb == null)
      return null;
    if (isEditableComboBox(cb))
      return unnull((String) cb.getEditor().getItem());
    else
      return str(cb.getSelectedItem());
  }

  static public Object convertToField(Object o, Class c, String field) {
    Field f = setOpt_findField(c, field);
    if (f == null)
      return o;
    Class t = f.getType();
    if (t == Long.class || t == long.class)
      return toLong(o);
    else if (t == Integer.class || t == int.class)
      return toInt(o);
    else if (t == Float.class || t == float.class)
      return toFloat(o);
    else if (t == Double.class || t == double.class)
      return toDouble(o);
    else if (t == String.class)
      return o instanceof String ? (String) o : str(o);
    else if (t == File.class) {
      if (o instanceof String)
        return new File((String) o).getAbsoluteFile();
    } else if (t == GlobalID.class && o instanceof String)
      return new GlobalID((String) o);
    return o;
  }

  static public Concept getConcept(long id) {
    return db_mainConcepts().getConcept(id);
  }

  static public Concept getConcept(Concepts concepts, long id) {
    return concepts.getConcept(id);
  }

  static public <A extends Concept> A getConcept(Class<A> cc, long id) {
    return getConcept(db_mainConcepts(), cc, id);
  }

  static public <A extends Concept> A getConcept(Concepts concepts, Class<A> cc, long id) {
    Concept c = concepts.getConcept(id);
    if (c == null)
      return null;
    if (!isInstance(cc, c))
      throw fail("Can't convert concept: " + getClassName(c) + " -> " + getClassName(cc) + " (" + id + ")");
    return (A) c;
  }

  static public long parseFirstLong(String s) {
    return parseLong(jextract("<int>", s));
  }

  static public void cUpdatePNGFile(Concept c, String field, BufferedImage image, boolean deleteOldFile) {
    PNGFile png = (PNGFile) (cget(c, field));
    if (image == null && png != null)
      cset(c, field, null);
    else if (image != null && (png == null || !imagesIdentical(png.getImage(), image))) {
      if (png != null && deleteOldFile)
        png.delete();
      cset(c, field, new PNGFile(image));
    }
  }

  static public <A> List<A> listWithoutSet(Collection<A> l, Collection<A> stuff) {
    return listMinusSet(l, stuff);
  }

  static public String[] conceptFields_drop = { "className", "fieldValues", "id", "created", "_modified", "refs", "backRefs", "_concepts" };

  static public Set<String> conceptFields(Concept c) {
    return setMinus(mergeSets(allNonStaticNonTransientFields(c), keys(c.fieldValues)), conceptFields_drop);
  }

  static public Set<String> conceptFields(Class<? extends Concept> c) {
    return setMinus(allNonStaticNonTransientFields(c), conceptFields_drop);
  }

  static public <A> Set<A> joinSets(Collection<A>... l) {
    Set<A> set = similarEmptySet(first(l));
    for (Collection<A> o : l) if (o != null)
      set.addAll(o);
    return set;
  }

  static public <A> Set<A> setPlus(Collection<A> l, A... more) {
    Set<A> set = similarEmptySet(l);
    addAll(set, l);
    for (A a : more) set.add(a);
    return set;
  }

  static public <A> List<A> moveItemFirst(A item, Collection<A> l) {
    if (!contains(l, item))
      return asList(l);
    List<A> out = emptyList(l(l));
    out.add(item);
    for (A a : l) if (!eq(a, item))
      out.add(a);
    return out;
  }

  static public <A> List dropTypeParameter(List<A> l) {
    return l;
  }

  static public <A> Collection dropTypeParameter(Collection<A> l) {
    return l;
  }

  static public <A> List<Class<? extends A>> sortClassesByNameIC(Collection<Class<? extends A>> l) {
    return sortedByCalculatedFieldIC(__54 -> shortClassName(__54), l);
  }

  static public <A> List<Class<? extends A>> myNonAbstractClassesImplementing(Class<A> base) {
    List<Class<? extends A>> l = new ArrayList();
    for (String name : myInnerClasses()) {
      Class c = _getClass(mcName() + "$" + name);
      if (c != null && !isAbstract(c) && isSubtypeOf(c, base))
        l.add(c);
    }
    return l;
  }

  static public <A> JComboBox<A> setComboBoxRenderer(JComboBox<A> cb, ListCellRenderer renderer) {
    if (cb != null) {
      swing(() -> {
        cb.setRenderer(renderer);
      });
    }
    return cb;
  }

  static public <A> JComboBox<A> jTypedComboBox(Collection<A> items) {
    return swing(() -> new JComboBox<A>(toVector(items)));
  }

  static public <A> JComboBox<A> jTypedComboBox(Collection<A> items, A selectedItem) {
    return selectItem(selectedItem, jTypedComboBox(items));
  }

  static public <A> ListCellRenderer<A> customToStringListCellRenderer(IF1<A, String> toString) {
    return (ListCellRenderer) new DefaultListCellRenderer() {

      @Override
      public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
        return super.getListCellRendererComponent(list, toString.get((A) value), index, isSelected, cellHasFocus);
      }
    };
  }

  static public JTextField jtextfield() {
    return jTextField();
  }

  static public JTextField jtextfield(String text) {
    return jTextField(text);
  }

  static public JTextField jtextfield(Object o) {
    return jTextField(o);
  }

  static public void onChangeAndNow(JComponent c, Object r) {
    onUpdateAndNow(c, r);
  }

  static public void onChangeAndNow(List<? extends JComponent> l, Object r) {
    onUpdateAndNow(l, r);
  }

  static public JPanel jhgridWithSpacing(Object... parts) {
    return hgridWithSpacing(parts);
  }

  static public <A extends JComponent> A withToolTip(A c, final Object toolTip) {
    return setToolTipText(c, toolTip);
  }

  static public <A extends JComponent> A withToolTip(Object toolTip, A c) {
    return setToolTipText(toolTip, c);
  }

  static public JComponent withLabel(String label, JComponent component) {
    return westAndCenter(jlabel(label + " "), component);
  }

  static public JComponent withLabel(JComponent label, JComponent component) {
    return westAndCenterWithMargin(label, component);
  }

  static public JPanel westAndCenterWithMargin(Component w, Component c) {
    return westAndCenter(withRightMargin(w), c);
  }

  static public JPanel westAndCenterWithMargin(int margin, Component w, Component c) {
    return westAndCenter(withRightMargin(margin, w), c);
  }

  static public String gtt(JTextComponent c) {
    return getTextTrim(c);
  }

  static public String gtt(JComboBox cb) {
    return getTextTrim(cb);
  }

  static public <A, B extends A> void addAll(Collection<A> c, Iterable<B> b) {
    if (c != null && b != null)
      for (A a : b) c.add(a);
  }

  static public <A, B extends A> boolean addAll(Collection<A> c, Collection<B> b) {
    return c != null && b != null && c.addAll(b);
  }

  static public <A, B extends A> boolean addAll(Collection<A> c, B... b) {
    return c != null && b != null && c.addAll(Arrays.asList(b));
  }

  static public <A, B> Map<A, B> addAll(Map<A, B> a, Map<? extends A, ? extends B> b) {
    if (a != null && b != null)
      a.putAll(b);
    return a;
  }

  static public <A> A getSelectedItem_typed(JList<A> l) {
    return swing(() -> l.getSelectedValue());
  }

  static public <A> A getSelectedItem_typed(JComboBox<A> cb) {
    return swing(() -> (A) cb.getSelectedItem());
  }

  static public <A extends Concept> A ccopyFields(Concept x, A y, String... fields) {
    if (x == null || y == null)
      return y;
    if (empty(fields)) {
      for (String field : conceptFields(x)) cset(y, field, cget(x, field));
    } else
      for (String field : fields) {
        Object o = cget(x, field);
        if (o != null)
          cset(y, field, o);
      }
    return y;
  }

  static public boolean notNullOrEmptyString(Object o) {
    return o != null && !eq(o, "");
  }

  static public <A extends Component> A jMinWidthAtLeast(int w, final A c) {
    if (c == null)
      return null;
    return swing(new F0<A>() {

      public A get() {
        try {
          Dimension size = c.getMinimumSize();
          Dimension d = new Dimension(max(w, size.width), size.height);
          c.setMinimumSize(d);
          return jPreferWidth(d.width, c);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "Dimension size = c.getMinimumSize();\r\n    Dimension d = new Dimension(max(w, ...";
      }
    });
  }

  static public JPanel showFormTitled2(String title, Object... parts) {
    return showFormTitled_customLayout(formLayouter1(), title, parts);
  }

  static public boolean isSubclassOfAny(Class a, Collection<Class> b) {
    return any(b, x -> isSubclass(a, x));
  }

  static public boolean isSubclassOfAny(Class a, Class... b) {
    return any(b, x -> isSubclass(a, x));
  }

  static public <A> Set<A> createOrAddToSet(Set<A> set, A a) {
    if (set == null)
      set = new HashSet();
    set.add(a);
    return set;
  }

  static public <A> Set<A> createOrAddToSet(Set<A> set, A... l) {
    for (A a : unnullForIteration(l)) set = createOrAddToSet(set, a);
    return set;
  }

  static public Random random_random = new Random();

  static public int random(int n) {
    return random(random_random, n);
  }

  static public int random(int n, Random r) {
    return random(r, n);
  }

  static public int random(Random r, int n) {
    return n <= 0 ? 0 : getRandomizer(r).nextInt(n);
  }

  static public double random(double max) {
    return random() * max;
  }

  static public double random() {
    return random_random.nextInt(100001) / 100000.0;
  }

  static public double random(double min, double max) {
    return min + random() * (max - min);
  }

  static public int random(int min, int max) {
    return min + random(max - min);
  }

  static public int random(int min, int max, Random r) {
    return random(r, min, max);
  }

  static public int random(Random r, int min, int max) {
    return min + random(r, max - min);
  }

  static public <A> A random(List<A> l) {
    return oneOf(l);
  }

  static public <A> A random(Collection<A> c) {
    if (c instanceof List)
      return random((List<A>) c);
    int i = random(l(c));
    return collectionGet(c, i);
  }

  static public int random(IntRange r) {
    return random(r.start, r.end);
  }

  static public <A, B> Pair<A, B> random(Map<A, B> map) {
    return entryToPair(random(entries(map)));
  }

  static public int random_incl(int min, int max) {
    return random_incl(min, max, defaultRandomizer());
  }

  static public int random_incl(int min, int max, Random random) {
    return random(min, max + 1, random);
  }

  static public int random_incl(int max) {
    return random(0, max + 1);
  }

  static public void drawLine(BufferedImage image, int x1, int y1, int x2, int y2, Color color) {
    drawLine(imageGraphics(image), x1, y1, x2, y2, color);
  }

  static public void drawLine(Graphics2D g, int x1, int y1, int x2, int y2, Color color) {
    g.setColor(color);
    g.drawLine(x1, y1, x2, y2);
  }

  static public void drawLine(BufferedImage image, Pt a, Pt b, Color color) {
    drawLine(imageGraphics(image), a, b, color);
  }

  static public void drawLine(Graphics2D g, Pt a, Pt b, Color color) {
    drawLine(g, a.x, a.y, b.x, b.y, color);
  }

  static public boolean oneIn(int n) {
    return random(n) == 0;
  }

  static public boolean oneIn(int n, Random random) {
    return random(random, n) == 0;
  }

  static public boolean oneIn(Random random, int n) {
    return oneIn(n, random);
  }

  static public <A> void remove(List<A> l, int i) {
    if (l != null && i >= 0 && i < l(l))
      l.remove(i);
  }

  static public <A> void remove(Collection<A> l, A a) {
    if (l != null)
      l.remove(a);
  }

  static public <A, B> B remove(Map<A, B> map, Object a) {
    return map == null ? null : map.remove(a);
  }

  static public void remove(BitSet bs, int i) {
    bs.clear(i);
  }

  static public <A, B> Set<A> keySet(Map<A, B> map) {
    return map == null ? new HashSet() : map.keySet();
  }

  static public Set keySet(Object map) {
    return keys((Map) map);
  }

  static public <A> Set<A> keySet(MultiSet<A> ms) {
    return ms.keySet();
  }

  static public <A, B> Set<A> keySet(MultiMap<A, B> mm) {
    return mm.keySet();
  }

  static public <A, B> Collection<B> values(Map<A, B> map) {
    return map == null ? emptyList() : map.values();
  }

  static public Collection values(Object map) {
    return values((Map) map);
  }

  static public <A, B> Collection<B> values(MultiMap<A, B> mm) {
    return mm == null ? emptyList() : concatLists(values(mm.data));
  }

  static public File loadLibrary(String snippetID) {
    return loadBinarySnippet(snippetID);
  }

  static public File pathToJavaxJar() {
    return null;
  }

  static public File pathToJavaxJar_noResourceLoader() {
    try {
      return null;
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public int syncL(Collection l) {
    if (l == null)
      return 0;
    synchronized (collectionMutex(l)) {
      return l.size();
    }
  }

  static public int syncL(Map map) {
    if (map == null)
      return 0;
    synchronized (collectionMutex(map)) {
      return map.size();
    }
  }

  static public <A> List<A> syncL() {
    return syncList();
  }

  static public Class _run(String progID, String... args) {
    Class main = hotwire(progID);
    callMain(main, args);
    return main;
  }

  static public <A> List<A> syncGetAndClear(Collection<A> l) {
    return syncCloneAndClearList(l);
  }

  static public void pcallFAll(Collection l, Object... args) {
    if (l != null)
      for (Object f : cloneList(l)) pcallF(f, args);
  }

  static public void pcallFAll(Iterator it, Object... args) {
    while (it.hasNext()) pcallF(it.next(), args);
  }

  static public <A> A getWeakRef(Reference<A> ref) {
    return ref == null ? null : ref.get();
  }

  static public void cancelAndInterruptThread(Thread t) {
    if (t == null)
      return;
    cancelThread(t);
    t.interrupt();
  }

  static public FontMetrics componentFontMetrics(JComponent c) {
    Font font = getFont(c);
    return font == null ? null : swing(new F0<FontMetrics>() {

      public FontMetrics get() {
        try {
          return c.getFontMetrics(font);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret c.getFontMetrics(font);";
      }
    });
  }

  static public int idiv_ceil(int a, int b) {
    return (a + b - 1) / b;
  }

  static public int idiv_ceil(long a, long b) {
    return toInt_checked((a + b - 1) / b);
  }

  static public <A extends JComponent> A componentPopupMenuItem(A c, final String name, final Object action) {
    componentPopupMenu(c, new VF1<JPopupMenu>() {

      public void get(JPopupMenu menu) {
        try {
          addMenuItem(menu, name, action);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "addMenuItem(menu, name, action);";
      }
    });
    return c;
  }

  static public void componentPopupMenuItem(JComponent c, final JMenuItem menuItem) {
    componentPopupMenu(c, new VF1<JPopupMenu>() {

      public void get(JPopupMenu menu) {
        try {
          addMenuItem(menu, menuItem);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "addMenuItem(menu, menuItem);";
      }
    });
  }

  static public <A> List<A> asSyncList(Iterable<A> l) {
    return asSynchroList(l);
  }

  static public <A extends Component> A _revalidate(A c) {
    return revalidate(c);
  }

  static public void _revalidate(JFrame f) {
    revalidate(f);
  }

  static public void _revalidate(JInternalFrame f) {
    revalidate(f);
  }

  static public boolean endsWithNewLine(String s) {
    return endsWith(s, "\n");
  }

  static public String lines_rtrimIf(boolean rtrim, List<String> lines) {
    return rtrim ? lines_rtrim(lines) : lines(lines);
  }

  static public String copyTextToClipboard(Object _text) {
    String text = str(_text);
    StringSelection selection = new StringSelection(text);
    Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, selection);
    vmBus_send("newClipboardContents", text);
    return text;
  }

  static public <A> Map<String, A> syncCIMap() {
    return (Map) synchroMap(caseInsensitiveMap());
  }

  static public JPanel comboBoxAndButton(JComboBox cb, String buttonText, IVF1<String> onEnter) {
    Runnable r = new Runnable() {

      public void run() {
        try {
          callF(onEnter, getText(cb));
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "callF(onEnter, getText(cb))";
      }
    };
    return centerAndEastWithMargin(onEnter(cb, r), jbutton(buttonText, r));
  }

  static public ThreadLocal<Boolean> bindComboBoxToLiveValue_debug = new ThreadLocal();

  static public <A extends JComboBox> A bindComboBoxToLiveValue(final A cb, final SimpleLiveValue<String> lv) {
    final boolean debug = isTrue(bindComboBoxToLiveValue_debug.get());
    bindLiveValueListenerToComponent(cb, lv, new Runnable() {

      public void run() {
        try {
          selectItem(cb, lv.get());
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "selectItem(cb, lv!)";
      }
    });
    onChange(cb, new Runnable() {

      public void run() {
        try {
          String s = getText(cb);
          if (debug)
            print("ComboBox: " + s);
          lv.set(s);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "String s = getText(cb); // also works on editable combo boxes\r\n    if (debug)...";
      }
    });
    return cb;
  }

  static public JComboBox centerComboBox(JComboBox cb) {
    centerTextField(textFieldFromComboBox(cb));
    return cb;
  }

  static public <A, B> List<A> cloneKeys(Map<A, B> map) {
    return cloneList(keys(map));
  }

  static public void setComponent(SingleComponentPanel scp, Component c) {
    setSCPComponent(scp, c);
  }

  static public void setComponent(SingleComponentPanel scp, IF0<Component> c) {
    if (scp != null)
      setComponent(scp, callF(c));
  }

  static public void catchError(DoneFlag doneFlag, Runnable r) {
    try {
      {
        if (r != null)
          r.run();
      }
    } catch (Throwable e) {
      doneFlag.setError(e);
    }
  }

  static public Rect screenBounds_safe(int iScreen) {
    return screenBounds(min(iScreen, screenCount() - 1));
  }

  static public <A, B> B syncMapGetOrCreate(Map<A, B> map, A key, Class<? extends B> c) {
    return syncGetOrCreate(map, key, c);
  }

  static public <A, B> B syncMapGetOrCreate(Map<A, B> map, A key, Object f) {
    return syncGetOrCreate(map, key, f);
  }

  static public <A, B> B syncMapGetOrCreate(Class<? extends B> c, Map<A, B> map, A key) {
    return syncGetOrCreate(c, map, key);
  }

  static public <A, B> B syncMapGetOrCreate(Map<A, B> map, A key, IF0<B> f) {
    return syncGetOrCreate(map, key, f);
  }

  static public <A> ArrayList<A> toList(A[] a) {
    return asList(a);
  }

  static public ArrayList<Integer> toList(int[] a) {
    return asList(a);
  }

  static public <A> ArrayList<A> toList(Set<A> s) {
    return asList(s);
  }

  static public <A> ArrayList<A> toList(Iterable<A> s) {
    return asList(s);
  }

  static public JTextField jLiveTextField(SimpleLiveValue<String> lv) {
    return jLiveValueTextField_bothWays(lv);
  }

  static public <A extends JTextComponent> A setTextKeepCaret(final String text, final A c) {
    if (c != null) {
      swing(() -> {
        int caret = c.getCaretPosition();
        setText(c, text);
        setCaretPosition(c, caret);
      });
    }
    return c;
  }

  static public <A extends JTextComponent> A setTextKeepCaret(A c, String text) {
    return setTextKeepCaret(text, c);
  }

  static public boolean sameSize(WidthAndHeight a, BufferedImage b) {
    return a != null && b != null && a.getWidth() == b.getWidth() && a.getHeight() == b.getHeight();
  }

  static public float bwDistance(BWImage a, BWImage b, float maxDistance) {
    return 1f - bwImageSimilarityResized(a, b, 1f - maxDistance);
  }

  static public float bwDistance(BWImage a, BWImage b) {
    return bwDistance(a, b, 1f);
  }

  static public BWImage toBWImage(RGBImage img) {
    return toBW(img);
  }

  static public BWImage toBWImage(BufferedImage img) {
    return img == null ? null : new BWImage(img);
  }

  static public BWImage toBWImage(MakesBufferedImage img) {
    if (img == null)
      return null;
    if (img instanceof BWImage)
      return ((BWImage) img);
    return new BWImage(toBufferedImage(img));
  }

  static public String formatDoubleX(double d, int digits) {
    return formatDoubleFull(d, digits);
  }

  static public int inc(AtomicInteger i) {
    return incAtomicInt(i);
  }

  static public int inc(AtomicInteger i, int delta) {
    return incAtomicInt(i, delta);
  }

  static public long inc(AtomicLong l) {
    return incAtomicLong(l);
  }

  static public long inc(AtomicLong l, long b) {
    return l.addAndGet(b);
  }

  static public int inc(IntVar v) {
    synchronized (v) {
      int val = v.get() + 1;
      v.set(val);
      return val;
    }
  }

  static public <A> IVF1<A> runnableToIVF1(Runnable r) {
    return r == null ? null : a -> r.run();
  }

  static public <A> ListIterator<A> listIterator(List<A> l) {
    return l == null ? emptyListIterator() : l.listIterator();
  }

  static public Map mapValues(Object func, Map map) {
    Map m = similarEmptyMap(map);
    for (Object key : keys(map)) m.put(key, callF(func, map.get(key)));
    return m;
  }

  static public <A, B, C> Map<A, C> mapValues(Map<A, B> map, IF1<B, C> f) {
    return mapValues(f, map);
  }

  static public <A, B, C> Map<A, C> mapValues(IF1<B, C> f, Map<A, B> map) {
    Map m = similarEmptyMap(map);
    for (Map.Entry<? extends A, ? extends B> __0 : _entrySet(map)) {
      A key = __0.getKey();
      B val = __0.getValue();
      m.put(key, f.get(val));
    }
    return m;
  }

  static public Map mapValues(Map map, Object func) {
    return mapValues(func, map);
  }

  static public Object renderForTable_noStruct(Object o) {
    {
      Object __1 = toBufferedImageOpt(o);
      if (__1 != null)
        return __1;
    }
    if (o instanceof String && containsNewLine((String) o))
      return escapeNewLines(dropTrailingNewLine((String) o));
    return strOrNull(o);
  }

  static public Map<String, Object> allConceptFieldsAsMapExcept(Concept c, Collection<String> excludedFields) {
    Map<String, Object> map = new HashMap();
    for (String field : unnullForIteration(listMinusSet(conceptFields(c), excludedFields))) map.put(field, cget(c, field));
    return map;
  }

  static public String dynShortClassName(Object o) {
    return shortDynamicClassName(o);
  }

  static public boolean sexyTable_drag = false;

  static public JTable sexyTable() {
    final JTable table = sexyTableWithoutDrag();
    if (sexyTable_drag)
      tableEnableTextDrag(table);
    return table;
  }

  static public JTable setTableFontSizes(float size, JTable table) {
    if (table == null)
      return null;
    {
      swing(() -> {
        setFontSize(table.getTableHeader(), size);
        setFontSize(table, size);
      });
    }
    return table;
  }

  static public JTable setTableFontSizes(JTable table, float size) {
    return setTableFontSizes(size, table);
  }

  static public JTable setRowHeight(final int h, final JTable t) {
    if (t != null) {
      swing(() -> {
        t.setRowHeight(h);
      });
    }
    return t;
  }

  static public JTable setRowHeight(JTable t, int h) {
    return setRowHeight(h, t);
  }

  static public <A> A postProcess(Object f, A a) {
    return callPostProcessor(f, a);
  }

  static public <A> A postProcess(IF1<A, A> f, A a) {
    return callPostProcessor(f, a);
  }

  static public <A> List<A> reverseInPlace(List<A> l) {
    return reverseList(l);
  }

  static public JTable dataToTable_uneditable(Object data, final JTable table) {
    return dataToTable_uneditable(table, data);
  }

  static public JTable dataToTable_uneditable(final JTable table, final Object data) {
    if (table != null) {
      swing(() -> {
        dataToTable(table, data, true);
        makeTableUneditable(table);
      });
    }
    return table;
  }

  static public JTable dataToTable_uneditable(final Object data) {
    return dataToTable_uneditable(showTable(), data);
  }

  static public JTable dataToTable_uneditable(Object data, String title) {
    return dataToTable_uneditable(showTable(title), data);
  }

  static public void tableColumnMaxWidth(final JTable table, final int columnIdx, final int width) {
    {
      swing(() -> {
        try {
          if (inRange(columnIdx, table.getColumnCount()))
            table.getColumnModel().getColumn(columnIdx).setMaxWidth(width);
        } catch (Throwable __e) {
          printStackTrace(__e);
        }
      });
    }
  }

  static public void updateEnclosingTabTitleWithCount(JComponent c, int n) {
    Pair<JTabbedPane, Integer> p = enclosingTab(c);
    if (p == null)
      return;
    setTabTitle(p.a, p.b, appendBracketedCount(dropTrailingBracketedCount(getTabTitle(p.a, p.b)), n));
  }

  static public int tableColumnCount(JTable table) {
    return tableNumColumns(table);
  }

  static public void setColumnName(final JTable table, final int idx, final String name) {
    if (table != null) {
      swing(() -> {
        if (table.getColumnCount() > idx)
          table.getColumnModel().getColumn(idx).setHeaderValue(name);
      });
    }
  }

  static public String getColumnName(final JTable table, final int idx) {
    return table == null ? null : swing(new F0<String>() {

      public String get() {
        try {
          return table.getColumnCount() <= idx ? null : str(table.getColumnModel().getColumn(idx).getHeaderValue());
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret table.getColumnCount() <= idx ? null\r\n      : str(table.getColumnModel()....";
      }
    });
  }

  static public long toLong(Object o) {
    if (o instanceof Number)
      return ((Number) o).longValue();
    if (o instanceof String)
      return parseLong((String) o);
    return 0;
  }

  static public Object selectedTableCell(JTable t, int col) {
    return getTableCell(t, selectedTableRow(t), col);
  }

  static public Object selectedTableCell(final JTable t) {
    return swing(new F0<Object>() {

      public Object get() {
        try {
          return selectedTableCell(t, t.getSelectedColumn());
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret selectedTableCell(t, t.getSelectedColumn());";
      }
    });
  }

  static public Object selectedTableCell(final JTable t, final String colName) {
    return swing(new F0<Object>() {

      public Object get() {
        try {
          return selectedTableCell(t, tableColumnViewIndex(t, colName));
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret selectedTableCell(t, tableColumnViewIndex(t, colName));";
      }
    });
  }

  static public Object getTableCell(JTable tbl, int row, int col) {
    if (row >= 0 && row < tbl.getModel().getRowCount())
      return tbl.getModel().getValueAt(row, col);
    return null;
  }

  static public int tableRowCount(JTable table) {
    return tableRows(table);
  }

  static public <A extends Concept> List<A> sortByConceptID(Collection<A> l) {
    return sortConceptsByID(l);
  }

  static public 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 public void printVars(Object... params) {
    printVars_str(params);
  }

  static public int done_minPrint = 10;

  static public long done(long startTime, String desc) {
    long time = now() - startTime;
    if (time >= done_minPrint)
      print(desc + " [" + time + " ms]");
    return time;
  }

  static public long done(String desc, long startTime) {
    return done(startTime, desc);
  }

  static public long done(long startTime) {
    return done(startTime, "");
  }

  static public <A> A printStackTrace_gen(A e) {
    if (e instanceof Throwable)
      printStackTrace((Throwable) e);
    else
      print(e);
    return e;
  }

  static public AutoCloseable tempSetStroke(Graphics2D g, Stroke s) {
    Stroke oldStroke = g.getStroke();
    g.setStroke(s);
    return () -> g.setStroke(oldStroke);
  }

  static public void drawRect(BufferedImage image, int x, int y, int w, int h, Color color) {
    Graphics2D g = imageGraphics(image);
    drawRect(g, x, y, w, h, color);
    g.dispose();
  }

  static public void drawRect(Graphics2D g, int x, int y, int w, int h, Color color) {
    g.setColor(color);
    g.drawRect(x, y, w, h);
  }

  static public void drawRect(Graphics2D g, Rect r) {
    g.drawRect(r.x, r.y, r.w, r.h);
  }

  static public void drawRect(int x, int y, int w, int h, Color color) {
    drawRect(currentImage(), x, y, w, h, color);
  }

  static public void drawRect(Rect r, Color color) {
    drawRect(r.x, r.y, r.w, r.h, color);
  }

  static public void drawRect(BufferedImage image, Rect r, Color c) {
    if (r != null)
      drawRect(image, r.x, r.y, r.w, r.h, c);
  }

  static public Rect growRectTopAndLeft(Rect r) {
    return growRectTopAndLeft(r, 1);
  }

  static public Rect growRectTopAndLeft(Rect r, int pixels) {
    return new Rect(r.x - pixels, r.y - pixels, r.w + pixels, r.h + pixels);
  }

  static public Rect scaleRect_floor(Rect r, double factorX) {
    return scaleRect_floor(r, factorX, factorX);
  }

  static public Rect scaleRect_floor(Rect r, double factorX, double factorY) {
    return rectFromPoints(ifloor(r.x * factorX), ifloor(r.y * factorY), ifloor(r.x2() * factorX), ifloor(r.y2() * factorY));
  }

  static public Rect scaleRect_floor(double factor, Rect r) {
    return scaleRect_floor(r, factor);
  }

  static public Rect scaleRect_floor(DoubleRect r, double factorX) {
    return scaleRect_floor(r, factorX, factorX);
  }

  static public Rect scaleRect_floor(DoubleRect r, double factorX, double factorY) {
    return rect(ifloor(r.x * factorX), ifloor(r.y * factorY), ifloor(r.w * factorX), ifloor(r.h * factorY));
  }

  static public Rect growRectRightAndBottom(Rect r, int x, int y) {
    return new Rect(r.x, r.y, r.w + x, r.h + y);
  }

  static public Rect growRectRightAndBottom(Rect r) {
    return growRectRightAndBottom(r, 1, 1);
  }

  static public BufferedImage inputImage_image;

  static public BufferedImage inputImage() {
    if (inputImage_image != null)
      return inputImage_image;
    final ImageChooser ic = new ImageChooser();
    if (!showTitledForm_blocking("Please Choose Image To Work On", "", ic))
      throw fail("No input image selected");
    return ic.getImage();
  }

  static public boolean isInteger(String s) {
    int n = l(s);
    if (n == 0)
      return false;
    int i = 0;
    if (s.charAt(0) == '-')
      if (++i >= n)
        return false;
    while (i < n) {
      char c = s.charAt(i);
      if (c < '0' || c > '9')
        return false;
      ++i;
    }
    return true;
  }

  static public boolean is(String a, String b) {
    return false;
  }

  static public RasterBars reproduceRasterBars(IBWIntegralImage ii) {
    var thinImage = scaledBWImageFromBWIntegralImage_withMeta(ii, 1, ii.getHeight());
    var streaks = streaksOfRepeatingElements(listFromFunction(thinImage.getHeight(), y -> thinImage.getInt(0, y)));
    return new RasterBars(ii.getWidth(), ii.getHeight(), streaks);
  }

  static public <A> Value<A> value(A a) {
    return new Value<A>(a);
  }

  static public String sfuIndent(Object o) {
    return sfuIndent(Integer.MAX_VALUE, o);
  }

  static public String sfuIndent(int levels, Object o) {
    return indentedStructureForUser(levels, o);
  }

  static public Rect toRect_round(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 public Rect scaleRect(Rect r, double factorX, double factorY) {
    return rectFromPoints(iround(r.x * factorX), iround(r.y * factorY), iround(r.x2() * factorX), iround(r.y2() * factorY));
  }

  static public Rect scaleRect(Rect r, double factor) {
    return scaleRect(r, factor, factor);
  }

  static public Rect scaleRect(double factor, Rect r) {
    return scaleRect(r, factor);
  }

  static public DoubleRect scaleRect(DoubleRect r, double factorX, double factorY) {
    return doubleRect(r.x * factorX, r.y * factorY, r.w * factorX, r.h * factorY);
  }

  static public DoubleRect scaleRect(double factorX, double factorY, DoubleRect r) {
    return scaleRect(r, factorX, factorY);
  }

  static public DoubleRect doubleRectFromPoints(double x1, double y1, double x2, double y2) {
    return new DoubleRect(x1, y1, x2 - x1, y2 - y1);
  }

  static public RuntimeException todo() {
    throw new RuntimeException("TODO");
  }

  static public RuntimeException todo(Object msg) {
    throw new RuntimeException("TODO: " + msg);
  }

  static public Pt toPt(Point p) {
    return p == null ? null : new Pt(p.x, p.y);
  }

  static public Pt toPt(Dimension d) {
    return d == null ? null : new Pt(d.width, d.width);
  }

  static public <A> A assertNotNull(A a) {
    assertTrue(a != null);
    return a;
  }

  static public <A> A assertNotNull(String msg, A a) {
    assertTrue(msg, a != null);
    return a;
  }

  static public Area bitMatrixToArea(Matrix<Boolean> m) {
    return scanlineBitMatrixToArea(toScanlineBitMatrix(m));
  }

  static public Color colorWithAlpha(Color c, double alpha) {
    return new Color(c.getRed() / 255f, c.getGreen() / 255f, c.getBlue() / 255f, (float) clampZeroToOne(alpha));
  }

  static public Color colorWithAlpha(double alpha, Color c) {
    return colorWithAlpha(c, alpha);
  }

  static public boolean frameTooSmall(JFrame frame) {
    return frame.getWidth() < 100 || frame.getHeight() < 50;
  }

  static public void frameStandardSize(JFrame frame) {
    frame.setBounds(300, 100, 500, 400);
  }

  static public String shortenClassName(String name) {
    if (name == null)
      return null;
    int i = lastIndexOf(name, "$");
    if (i < 0)
      i = lastIndexOf(name, ".");
    return i < 0 ? name : substring(name, i + 1);
  }

  static public String programIDPlusHome() {
    return programIDPlusHome(programID(), userHomeIfNotActual());
  }

  static public String programIDPlusHome(String programID, File home) {
    return programIDPlusHome(programID, f2s(home));
  }

  static public String programIDPlusHome(String programID, String home) {
    if (home != null)
      programID += " " + quote(home);
    return programID;
  }

  static public List<JFrame> activateMyFrames() {
    final List<JFrame> l = myFrames();
    {
      swing(() -> {
        for (JFrame f : l) activateFrame(f);
      });
    }
    return l;
  }

  static public String programName() {
    return getProgramName();
  }

  static public int makeBot(String greeting) {
    return makeAndroid3(greeting).port;
  }

  static public Android3 makeBot(Android3 a) {
    makeAndroid3(a);
    return a;
  }

  static public Android3 makeBot(String greeting, Object responder) {
    Android3 a = new Android3(greeting);
    a.responder = makeResponder(responder);
    makeBot(a);
    return a;
  }

  static public Android3 makeBot() {
    return makeAndroid3(defaultBotName());
  }

  static public <A> List<A> sortedByCalculatedField(Iterable<A> c, Object f) {
    return sortByCalculatedField(c, f);
  }

  static public <A> List<A> sortedByCalculatedField(Object f, Iterable<A> c) {
    return sortedByCalculatedField(c, f);
  }

  static public <A, B> List<A> sortedByCalculatedField(IF1<A, B> f, Iterable<A> c) {
    return sortedByCalculatedField(c, f);
  }

  static public <A, B> List<A> sortedByCalculatedField(Iterable<A> c, IF1<A, B> f) {
    List<A> l = cloneList(c);
    sort(l, new Comparator<A>() {

      public int compare(A a, A b) {
        return stdcompare(f.get(a), f.get(b));
      }
    });
    return l;
  }

  static public long conceptID(Concept c) {
    return c == null ? 0 : c.id;
  }

  static public long conceptID(Concept.Ref ref) {
    return conceptID(cDeref(ref));
  }

  static public void tableDependButtons(final JTable table, List<? extends Component> buttons) {
    for (Component c : buttons) if (c instanceof JButton) {
      final JButton b = (JButton) c;
      table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {

        public void valueChanged(ListSelectionEvent e) {
          b.setEnabled(table.getSelectedRow() >= 0);
        }
      });
      b.setEnabled(table.getSelectedRow() >= 0);
    }
  }

  static public boolean anyValueContainsIgnoreCase(Map map, String pat) {
    for (Object val : values(map)) if (val instanceof String && containsIgnoreCase((String) val, pat))
      return true;
    return false;
  }

  static public List<Map<String, Object>> rawTableData(JTable t) {
    int n = tableRows(t);
    List l = new ArrayList();
    for (int i = 0; i < n; i++) l.add(rawTableLineAsMap(t, i));
    return l;
  }

  static public JTable dataToTable(Object data) {
    return dataToTable(showTable(), data);
  }

  static public JTable dataToTable(Object data, String title) {
    return dataToTable(showTable(title), data);
  }

  static public JTable dataToTable(JTable table, Object data) {
    return dataToTable(table, data, false);
  }

  static public JTable dataToTable(JTable table, Object data, boolean now) {
    List<List> rows = new ArrayList();
    List<String> cols = new ArrayList();
    if (data instanceof List) {
      for (Object x : (List) data) {
        try {
          rows.add(dataToTable_makeRow(x, cols));
        } catch (Throwable __e) {
          printStackTrace(__e);
        }
      }
    } else if (data instanceof Map) {
      Map map = (Map) data;
      for (Object key : map.keySet()) {
        Object value = map.get(key);
        rows.add(litlist(structureOrTextForUser(key), structureOrTextForUser(value)));
      }
    } else if (data != null)
      print("Unknown data type: " + data);
    fillTableWithData(table, rows, cols);
    return table;
  }

  static public boolean boolOptPar(ThreadLocal<Boolean> tl) {
    return boolOptParam(tl);
  }

  static public boolean boolOptPar(Object[] __, String name) {
    return boolOptParam(__, name);
  }

  static public boolean boolOptPar(String name, Object[] __) {
    return boolOptParam(__, name);
  }

  static public boolean jmenuItem_newThreads = false;

  static public JMenuItem jmenuItem(final String text) {
    return jMenuItem(text, null);
  }

  static public JMenuItem jmenuItem(final String text, final Object r) {
    return swing(new F0<JMenuItem>() {

      public JMenuItem get() {
        try {
          Pair<String, Integer> p = jmenu_autoMnemonic(dropPrefix("[disabled] ", text));
          JMenuItem mi = new JMenuItem(p.a);
          if (startsWith(text, "[disabled] "))
            disableMenuItem(mi);
          if (p.b != 0)
            mi.setMnemonic(p.b);
          mi.addActionListener(jmenuItem_newThreads ? actionListenerInNewThread(r) : actionListener(r));
          return mi;
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "Pair<S, Int> p = jmenu_autoMnemonic(dropPrefix(\"[disabled] \", text));\r\n    JM...";
      }
    });
  }

  static public MenuItem menuItem(String text, final Object r) {
    MenuItem mi = new MenuItem(text);
    mi.addActionListener(actionListener(r));
    return mi;
  }

  static public void addDirectMenuItem(JMenuBar mb, String text, Object action) {
    if (mb != null) {
      swing(() -> {
        addDirectMenuItem(mb, directJMenuItem(text, action));
      });
    }
  }

  static public void addDirectMenuItem(Component c, String text, Object action) {
    addDirectMenuItem(addMenuBar(c), text, action);
  }

  static public void addDirectMenuItem(JMenuBar mb, JMenuItem menuItem) {
    if (mb != null) {
      swing(() -> {
        mb.add(menuItem);
        revalidate(mb);
      });
    }
  }

  static public <A extends Concept> A ccopyFields2(Concept x, A y, Iterable<String> fields) {
    if (x == null || y == null)
      return y;
    for (String field : unnull(fields)) {
      Object o = cget(x, field);
      if (o != null)
        cset(y, field, o);
    }
    return y;
  }

  static public <A, B extends A> Set<A> setMinusSet(Set<A> l, Collection<B> stuff) {
    if (empty(stuff))
      return l;
    Set<B> set = asSet(stuff);
    Set<A> l2 = similarEmptySet(l);
    for (A a : l) if (!set.contains(a))
      l2.add(a);
    return l2;
  }

  static public <A, B extends A> Set<A> setMinusSet(Collection<A> l, Collection<B> stuff) {
    return setMinusSet(asSet(l), stuff);
  }

  static public Object getMCOpt(String field) {
    return getOptMC(field);
  }

  static public void setMCOpt(String field, Object value) {
    setOptMC(field, value);
  }

  static public JButton renameButton(JComponent c, String name) {
    JButton b = first(childrenOfType(c, JButton.class));
    if (b != null)
      b.setText(name);
    return b;
  }

  static public JButton renameButton(JComponent c, String oldName, String newName) {
    JButton b = findButton(c, oldName);
    if (b != null)
      b.setText(newName);
    return b;
  }

  static public String showFormSubmitButtonName() {
    return "Submit";
  }

  static public <A> List<A> concatLists(Iterable<A>... lists) {
    List<A> l = new ArrayList();
    if (lists != null)
      for (Iterable<A> list : lists) addAll(l, list);
    return l;
  }

  static public <A> List<A> concatLists(Collection<? extends Iterable<A>> lists) {
    List<A> l = new ArrayList();
    if (lists != null)
      for (Iterable<A> list : lists) addAll(l, list);
    return l;
  }

  static public boolean isUnlisted(Concept c) {
    return c != null && c.concepts() == null;
  }

  static public List<Concept.Ref> allBackRefObjects(Concept c) {
    return cloneList(c == null ? null : c.backRefs);
  }

  static public JCheckBox centerCheckBox(JCheckBox cb) {
    return setHorizontalAlignment(SwingConstants.CENTER, cb);
  }

  static public boolean isSubclass(Class a, Class b) {
    return a != null && b != null && b.isAssignableFrom(a);
  }

  static public JTextField standardTextFieldPopupMenu(final JTextField tf) {
    final WeakReference<JTextField> ref = weakRef(tf);
    componentPopupMenuItem(tf, "Copy text to clipboard", new Runnable() {

      public void run() {
        try {
          copyTextToClipboard(ref.get().getText());
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "copyTextToClipboard(ref.get().getText())";
      }
    });
    componentPopupMenuItem(tf, "Paste", new Runnable() {

      public void run() {
        try {
          ref.get().paste();
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ref.get().paste()";
      }
    });
    return tf;
  }

  static public JComponent unwrapScrollPane(JScrollPane sp) {
    return sp == null ? null : (JComponent) sp.getViewport().getView();
  }

  static public Field setOpt_findField(Class c, String field) {
    HashMap<String, Field> map;
    synchronized (getOpt_cache) {
      map = getOpt_cache.get(c);
      if (map == null)
        map = getOpt_makeCache(c);
    }
    return map.get(field);
  }

  static public void setOpt(Object o, String field, Object value) {
    try {
      if (o == null)
        return;
      Class c = o.getClass();
      HashMap<String, Field> map;
      if (getOpt_cache == null)
        map = getOpt_makeCache(c);
      else
        synchronized (getOpt_cache) {
          map = getOpt_cache.get(c);
          if (map == null)
            map = getOpt_makeCache(c);
        }
      if (map == getOpt_special) {
        if (o instanceof Class) {
          setOpt((Class) o, field, value);
          return;
        }
        setOpt_raw(o, field, value);
        return;
      }
      Field f = map.get(field);
      if (f != null) {
        smartSet(f, o, value);
        return;
      }
      if (o instanceof DynamicObject) {
        setDyn(((DynamicObject) o), field, value);
        return;
      }
      if (o instanceof IMeta)
        setDyn(((IMeta) o), field, value);
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public void setOpt(Class c, String field, Object value) {
    if (c == null)
      return;
    try {
      Field f = setOpt_findStaticField(c, field);
      if (f != null)
        smartSet(f, null, value);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  static public Field setOpt_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) {
        makeAccessible(f);
        return f;
      }
      _c = _c.getSuperclass();
    } while (_c != null);
    return null;
  }

  static public float toFloat(Object o) {
    if (o == null)
      return 0f;
    if (o instanceof Number)
      return ((Number) o).floatValue();
    if (o instanceof Boolean)
      return ((Boolean) o).booleanValue() ? 1f : 0f;
    throw fail("Not convertible to float: " + _getClass(o));
  }

  static public boolean imagesIdentical(BufferedImage img1, BufferedImage img2) {
    if (img1 == null)
      return img2 == null;
    if (img2 == null)
      return false;
    int w = img1.getWidth(), h = img1.getHeight();
    if (w != img2.getWidth() || h != img2.getHeight())
      return false;
    for (int y = 0; y < h; y++) for (int x = 0; x < w; x++) if (img1.getRGB(x, y) != img2.getRGB(x, y))
      return false;
    return true;
  }

  static public <A> List<A> listMinusSet(Iterable<A> l, Collection<? extends A> stuff) {
    if (l == null)
      return null;
    if (empty(stuff))
      return asList(l);
    Set<? extends A> set = asSet(stuff);
    List<A> l2 = new ArrayList();
    for (A a : l) if (!set.contains(a))
      l2.add(a);
    return l2;
  }

  static public <A> List<A> listMinusSet(Iterable<A> l, Collection<A> stuff, Collection<? extends A> stuff2) {
    return listMinusSet(listMinusSet(l, stuff), stuff2);
  }

  static public <A> Set<A> setMinus(Set<A> set, Object... stuff) {
    Set s2 = cloneSet(set);
    for (Object o : stuff) s2.remove(o);
    return s2;
  }

  static public <A> Set<A> mergeSets(Collection<A>... l) {
    return joinSets(l);
  }

  static public Set<String> allNonStaticNonTransientFields(Object o) {
    TreeSet<String> fields = new TreeSet();
    Class _c = _getClass(o);
    do {
      for (Field f : _c.getDeclaredFields()) if ((f.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) == 0)
        fields.add(f.getName());
      _c = _c.getSuperclass();
    } while (_c != null);
    return fields;
  }

  static public Set similarEmptySet(Iterable m) {
    if (m instanceof TreeSet)
      return new TreeSet(((TreeSet) m).comparator());
    if (m instanceof LinkedHashSet)
      return new LinkedHashSet();
    return new HashSet();
  }

  static public Set similarEmptySet(Map m) {
    if (m instanceof TreeMap)
      return new TreeSet(((TreeMap) m).comparator());
    if (m instanceof LinkedHashMap)
      return new LinkedHashSet();
    return new HashSet();
  }

  static public <A> List<A> sortedByCalculatedFieldIC(Iterable<A> c, Object f) {
    return sortByCalculatedFieldIC(c, f);
  }

  static public <A> List<A> sortedByCalculatedFieldIC(Object f, Iterable<A> c) {
    return sortedByCalculatedFieldIC(c, f);
  }

  static public <A, B> List<A> sortedByCalculatedFieldIC(IF1<A, B> f, Iterable<A> c) {
    return sortedByCalculatedFieldIC((Object) f, c);
  }

  static public <A, B> List<A> sortedByCalculatedFieldIC(Iterable<A> c, IF1<A, B> f) {
    return sortedByCalculatedFieldIC((Object) f, c);
  }

  static public List<String> myInnerClasses_list = litlist(null, "transpileOnServerWithErrorWindow_DaClass", "VF2", "TableSearcher", "FastRegions_BWImage", "Var", "Best_comparable", "RegionFillPainter", "SimpleCRUD_v2", "Label", "WatchScreen", "IntVar", "SavedImage", "ScanlineBitMatrix", "AnimatedLine", "SynchronizedRandomAccessList", "SynchronizedCollection", "PrintLogModule", "CleanExit", "ReliableSingleThread", "ListAndIndex", "JFastLogView_noWrap", "IF2_IntInt_Double", "ScreenCamStream", "ExampleForLabel", "FunctionTimings", "JConceptsTable", "AutoComboBox", "ISetter", "DoneFlag", "AbstractLayoutManager", "TrayIconLastPosition", "Flag", "WatchTarget", "RegionBoundingBoxPainter", "IHasGlobalID", "CloseableIterableIterator", "PNGFile", "BWIntegralImageStream", "IFieldsToList", "IF2", "getOpt_Map", "Value", "FPSCounter", "GazelleHost", "SourceTriggeredStream", "IVar", "SynchronizedList", "ConceptWithGlobalID", "RegionPainter", "RollingAverage", "ImageChooser", "ImageSurface_HighlightRegion", "BetterThread", "GazelleScreenCam", "SavedRegion", "IfThenTheory", "Stem", "AWTOnConceptChanges", "WeakVar", "RasterBars", "SynchronizedSet", "CriticalAction", "SynchronizedMap", "DialogHandler", "ImageSurface_PositionToolTip", "IResourceLoader", "proxy_InvocationHandler", "UIURLSystem", "ImageSurfaceMouseHandler", "IResourceHolder", "DialogIO", "Flattener", "WatchMouse", "MRUCache", "TransferableImage", "JGazelleVScriptRunner", "Animation", "DoubleFPSCounter", "IIBWVirtualClip", "Android3", "GazelleVScript", "Responder");

  static public List<String> myInnerClasses() {
    return myInnerClasses_list;
  }

  static public boolean isAbstract(Class c) {
    return (c.getModifiers() & Modifier.ABSTRACT) != 0;
  }

  static public boolean isAbstract(Method m) {
    return (m.getModifiers() & Modifier.ABSTRACT) != 0;
  }

  static public boolean isSubtypeOf(Class a, Class b) {
    return a != null && b != null && b.isAssignableFrom(a);
  }

  static public <A> Vector<A> toVector(A[] array) {
    return new Vector(toList(array));
  }

  static public <A> Vector<A> toVector(Collection<A> l) {
    return l == null ? null : new Vector(l);
  }

  static public void onUpdateAndNow(JComponent c, final Object r) {
    onUpdate(c, r);
    callF(r);
  }

  static public void onUpdateAndNow(List<? extends JComponent> l, Object r) {
    for (JComponent c : l) onUpdate(c, r);
    callF(r);
  }

  static public JPanel hgridWithSpacing(Object... _parts) {
    return swing(() -> {
      int spacing = 6;
      Object[] parts = _parts;
      if (first(parts) instanceof Integer) {
        spacing = (Integer) first(parts);
        parts = dropFirst(parts);
      }
      JPanel panel = hgrid(parts);
      GridLayout gl = (GridLayout) (panel.getLayout());
      gl.setHgap(spacing);
      gl.setVgap(spacing);
      return panel;
    });
  }

  static public JPanel westAndCenter(final Component w, final Component c) {
    return swing(new F0<JPanel>() {

      public JPanel get() {
        try {
          JPanel panel = new JPanel(new BorderLayout());
          panel.add(BorderLayout.WEST, wrap(w));
          panel.add(BorderLayout.CENTER, wrap(c));
          return panel;
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "JPanel panel = new JPanel(new BorderLayout);\r\n    panel.add(BorderLayout.WEST...";
      }
    });
  }

  static public <A extends Component> A jPreferWidth(int w, A c) {
    Dimension size = c.getPreferredSize();
    c.setPreferredSize(new Dimension(w, size.height));
    return c;
  }

  static public JPanel showFormTitled_customLayout(final F1<Container, Dimension> layouter, final String title, final Object... parts) {
    return showFormTitled_customArrangement(false, new F1<List<JComponent>, JPanel>() {

      public JPanel get(List<JComponent> components) {
        try {
          return customLayoutPanel(layouter, components);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "customLayoutPanel(layouter, components)";
      }
    }, title, parts);
  }

  static public int formLayouter1_yPlus = 5;

  static public int formLayouter1_fixer2 = 0;

  static public F1<Container, Dimension> formLayouter1() {
    final int yplus = formLayouter1_yPlus, fixer2 = formLayouter1_fixer2;
    return new F1<Container, Dimension>() {

      public Dimension get(Container parent) {
        try {
          List<Component> l = getComponents(parent);
          BitSet bigOnes = new BitSet();
          for (int i = 0; i < l(l); i++) if (containsATextArea(l.get(i)))
            add(bigOnes, i);
          int nBigOnes = bigOnes.cardinality();
          int mandatoryHeight = totalPreferredHeight(listWithoutIndicesInBitSet(l, bigOnes));
          int gap = 4, outerSpacing = 5;
          Dimension size = parent.getSize();
          int gapsAndMargins = outerSpacing * 2 - (l(l) - 1) * gap;
          int totalSpace = size.height - gapsAndMargins - fixer2;
          int liberalSpace = totalSpace - mandatoryHeight;
          double perBigOne = doubleRatio(liberalSpace, nBigOnes);
          double y = outerSpacing;
          for (int i = 0; i < l(l); i++) {
            Component c = l.get(i);
            boolean big = contains(bigOnes, i);
            double h = big ? perBigOne : c.getPreferredSize().height;
            int actualY = iround(y);
            c.setBounds(10, actualY, size.width - outerSpacing * 2, iround(y + h) - actualY);
            y += h + gap;
          }
          Dimension pref = componentsBoundingSize(parent, outerSpacing);
          if (parent.getHeight() <= 0) {
            int tph = totalPreferredHeight(l);
            pref.height = tph + gapsAndMargins + yplus;
          }
          return pref;
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "L<Component> l = getComponents(parent);\r\n    new BitSet bigOnes;\r\n    for i o...";
      }
    };
  }

  static public <A> boolean any(Object pred, Iterable<A> l) {
    if (l != null)
      for (A a : l) if (isTrue(callF(pred, a)))
        return true;
    return false;
  }

  static public <A> boolean any(IF1<A, Boolean> pred, Iterable<A> l) {
    return any((Object) pred, l);
  }

  static public <A> boolean any(Iterable<A> l, IF1<A, Boolean> pred) {
    return any(pred, l);
  }

  static public <A> boolean any(A[] l, IF1<A, Boolean> pred) {
    if (l != null)
      for (A a : l) if (pred.get(a))
        return true;
    return false;
  }

  static public boolean any(Iterable<Boolean> l) {
    if (l != null)
      for (Boolean a : l) if (isTrue(a))
        return true;
    return false;
  }

  static public Random getRandomizer(Random r) {
    return r != null ? r : defaultRandomGenerator();
  }

  static public <A> A oneOf(List<A> l) {
    return empty(l) ? null : l.get(new Random().nextInt(l.size()));
  }

  static public char oneOf(String s) {
    return empty(s) ? '?' : s.charAt(random(l(s)));
  }

  static public String oneOf(String... l) {
    return oneOf(asList(l));
  }

  static public <A> A collectionGet(Collection<A> c, int idx) {
    if (c == null || idx < 0 || idx >= l(c))
      return null;
    if (c instanceof List)
      return listGet((List<A>) c, idx);
    Iterator<A> it = c.iterator();
    for (int i = 0; i < idx; i++) if (it.hasNext())
      it.next();
    else
      return null;
    return it.hasNext() ? it.next() : null;
  }

  static public <A, B> Pair<A, B> entryToPair(Map.Entry<A, B> e) {
    return mapEntryToPair(e);
  }

  static public <A, B> Set<Map.Entry<A, B>> entries(Map<A, B> map) {
    return _entrySet(map);
  }

  static public Random defaultRandomizer() {
    return defaultRandomGenerator();
  }

  static public <A> List<A> syncCloneAndClearList(Collection<A> l) {
    if (l == null)
      return emptyList();
    synchronized (collectionMutex(l)) {
      List<A> l2 = cloneList(l);
      l.clear();
      return l2;
    }
  }

  static public void cancelThread(Thread t) {
    if (t == null)
      return;
    ping();
    var ps = pingSource(t);
    if (ps == null)
      warn("No ping source for thread " + t + ", can't cancel");
    else
      ps.cancel();
  }

  static public Font getFont(JComponent c) {
    return c == null ? null : swing(new F0<Font>() {

      public Font get() {
        try {
          return c.getFont();
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret c.getFont();";
      }
    });
  }

  static public int toInt_checked(long l) {
    if (l != (int) l)
      throw fail("Too large for int: " + l);
    return (int) l;
  }

  static public <A> List<A> asSynchroList(Iterable<A> l) {
    return syncList(cloneList(l));
  }

  static public String lines_rtrim(Collection lines) {
    return rtrim_fromLines(lines);
  }

  static public <A> TreeMap<String, A> caseInsensitiveMap() {
    return new TreeMap(caseInsensitiveComparator());
  }

  static public <A extends JTextField> A centerTextField(A tf) {
    tf.setHorizontalAlignment(JTextField.CENTER);
    return tf;
  }

  static public <A, B> B syncGetOrCreate(Map<A, B> map, A key, Class<? extends B> c) {
    try {
      synchronized (map) {
        return getOrCreate(map, key, c);
      }
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public <A, B> B syncGetOrCreate(Map<A, B> map, A key, Object f) {
    synchronized (map) {
      return getOrCreate(map, key, f);
    }
  }

  static public <A, B> B syncGetOrCreate(Class<? extends B> c, Map<A, B> map, A key) {
    return syncGetOrCreate(map, key, c);
  }

  static public <A, B> B syncGetOrCreate(Map<A, B> map, A key, IF0<B> f) {
    synchronized (map) {
      return getOrCreate(map, key, f);
    }
  }

  static public JTextField jLiveValueTextField_bothWays(final SimpleLiveValue<String> lv) {
    final JTextField ta = jTextField();
    bindTextComponentToLiveValue_bothWays(ta, lv);
    return ta;
  }

  static public void setCaretPosition(final JTextComponent c, final int pos) {
    if (c != null) {
      swing(() -> {
        try {
          int _pos = max(0, min(l(c.getText()), pos));
          c.setCaretPosition(_pos);
        } catch (Throwable __e) {
          printStackTrace(__e);
        }
      });
    }
  }

  static public float bwImageSimilarityResized(BWImage a, BWImage b, float similarityRequired) {
    int aw = a.w(), ah = a.h();
    int bw = b.w(), bh = b.h();
    int wp = max(aw, bw), hp = max(ah, bh);
    float ratio1 = ((float) aw) / ah, ratio2 = ((float) bw) / bh;
    float mismatch = ratio1 / ratio2;
    if (mismatch < 1f)
      mismatch = 1f / mismatch;
    float factor = wp * hp / mismatch;
    float maxError = (1f - similarityRequired) * factor;
    float diff = 0;
    for (int y = 0; y < hp; y++) for (int x = 0; x < wp; x++) {
      diff += Math.abs(a.getPixel(x * aw / wp, y * ah / hp) - b.getPixel(x * bw / wp, y * bh / hp));
      if (diff > maxError)
        return similarityRequired - 0.001f;
    }
    return 1f - diff / factor;
  }

  static public BWImage toBW(RGBImage img) {
    return img == null ? null : new BWImage(img);
  }

  static public String formatDoubleFull(double d, int digits) {
    String format = digits <= 0 ? "0" : "0." + rep(digits, '0');
    return new java.text.DecimalFormat(format, new java.text.DecimalFormatSymbols(Locale.ENGLISH)).format(d);
  }

  static public int incAtomicInt(AtomicInteger i) {
    return i.incrementAndGet();
  }

  static public int incAtomicInt(AtomicInteger i, int delta) {
    return i.addAndGet(delta);
  }

  static public long incAtomicLong(AtomicLong l) {
    return l.incrementAndGet();
  }

  static public ListIterator emptyListIterator() {
    return Collections.emptyListIterator();
  }

  static public String escapeNewLines(String s) {
    return s == null ? null : fixNewLines(s).replace("\n", " | ");
  }

  static public String dropTrailingNewLine(String s) {
    int l = l(s);
    if (l > 0 && s.charAt(l - 1) == '\n')
      --l;
    if (l > 0 && s.charAt(l - 1) == '\r')
      --l;
    return takeFirst(s, l);
  }

  static public String shortDynamicClassName(Object o) {
    if (o instanceof DynamicObject && ((DynamicObject) o).className != null)
      return ((DynamicObject) o).className;
    return shortClassName(o);
  }

  static public void tableEnableTextDrag(final JTable table) {
    TransferHandler th = new TransferHandler() {

      @Override
      public int getSourceActions(JComponent c) {
        return COPY;
      }

      @Override
      public Transferable createTransferable(JComponent c) {
        Object o = selectedTableCell(table);
        return new StringSelection(str(o));
      }
    };
    tableEnableDrag(table, th);
  }

  static public <A extends JComponent> A setFontSize(final float size, final A a) {
    if (a == null)
      return a;
    {
      swing(() -> {
        a.setFont(a.getFont().deriveFont((float) size));
        if (a instanceof JComboBox) {
          Component _a = ((JComboBox) a).getEditor().getEditorComponent();
          if (_a instanceof JComponent)
            ((JComponent) _a).setFont(((JComponent) _a).getFont().deriveFont((float) size));
        }
      });
    }
    return a;
  }

  static public <A extends JComponent> A setFontSize(A a, float size) {
    return setFontSize(size, a);
  }

  static public <A> A callPostProcessor(Object f, A a) {
    return f == null ? a : (A) callF(f, a);
  }

  static public <A> A callPostProcessor(IF1<A, A> f, A a) {
    return f == null ? a : f.get(a);
  }

  static public <A> List<A> reverseList(List<A> l) {
    Collections.reverse(l);
    return l;
  }

  static public void makeTableUneditable(JTable table) {
    for (int c = 0; c < table.getColumnCount(); c++) {
      Class<?> col_class = table.getColumnClass(c);
      table.setDefaultEditor(col_class, null);
    }
  }

  static public boolean showTable_searcher = true;

  static public JTable showTable(Object data) {
    return dataToTable_uneditable(data);
  }

  static public JTable showTable(String title, Object data) {
    return showTable(data, title);
  }

  static public JTable showTable(Object data, String title) {
    return dataToTable_uneditable(data, title);
  }

  static public JTable showTable(JTable table, Object data) {
    return showTable(table, data, autoFrameTitle());
  }

  static public JTable showTable(Object data, JTable table) {
    return showTable(table, data);
  }

  static public JTable showTable(JTable table, Object data, String title) {
    if (table == null)
      table = showTable(data, title);
    else {
      setFrameTitle(table, title);
      dataToTable_uneditable(table, data);
    }
    return table;
  }

  static public JTable showTable() {
    return showTable(new ArrayList<List<String>>(), new ArrayList<String>());
  }

  static public JTable showTable(String title) {
    return showTable(new ArrayList<List<String>>(), new ArrayList<String>(), title);
  }

  static public JTable showTable(List<List<String>> rows, List<String> cols) {
    return showTable(rows, cols, autoFrameTitle());
  }

  static public JTable showTable(List<List<String>> rows, List<String> cols, String title) {
    JTable tbl = sexyTable();
    fillTableWithStrings(tbl, rows, cols);
    showFrame(title, tbl);
    return tbl;
  }

  static public boolean inRange(int x, int n) {
    return x >= 0 && x < n;
  }

  static public boolean inRange(int x, int a, int b) {
    return x >= a && x < b;
  }

  static public String appendBracketedCount(int n, String a) {
    return appendBracketed(a, str(n));
  }

  static public String appendBracketedCount(String a, int n) {
    return appendBracketedCount(n, a);
  }

  static public String dropTrailingBracketedCount(String s) {
    return replaceAll(s, "\\s?\\(\\d+\\)$", "");
  }

  static public String getTabTitle(JTabbedPane tabs, int idx) {
    return tabs == null || idx < 0 ? null : swing(() -> idx < tabs.getTabCount() ? tabs.getTitleAt(idx) : null);
  }

  static public int tableNumColumns(final JTable table) {
    return swing(new F0<Integer>() {

      public Integer get() {
        try {
          return table.getColumnCount();
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret table.getColumnCount();";
      }
    });
  }

  static public int selectedTableRow(final JTable t) {
    return t == null ? -1 : swing(new F0<Integer>() {

      public Integer get() {
        try {
          return t.getSelectedRow();
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret t.getSelectedRow();";
      }
    });
  }

  static public int tableColumnViewIndex(final JTable t, final String colName) {
    return swing(new F0<Integer>() {

      public Integer get() {
        try {
          return t.convertColumnIndexToView(t.getColumn(colName).getModelIndex());
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "ret t.convertColumnIndexToView(t.getColumn(colName).getModelIndex());";
      }
    });
  }

  static public int tableRows(JTable table) {
    return (int) swingCall(table, "getRowCount");
  }

  static public <A extends Concept> List<A> sortConceptsByID(Collection<A> l) {
    return sortedByCalculatedField(l, c -> c.id);
  }

  static public void printVars_str(Object... params) {
    print(renderVars_str(params));
  }

  static public boolean showTitledForm_blocking(String title, Object... _parts) {
    assertNotOnAWTThread();
    final Var<Boolean> var = new Var();
    onFrameClose(showFormTitled(title, arrayPlus(_parts, new Runnable() {

      public void run() {
        try {
          var.set(true);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "var.set(true)";
      }
    })), new Runnable() {

      public void run() {
        try {
          if (!var.has())
            var.set(false);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "if (!var.has()) var.set(false)";
      }
    });
    waitUntilVarSet(var);
    return var.get();
  }

  static public <A> List<Pair<IntRange, A>> streaksOfRepeatingElements(List<A> l) {
    List<Pair<IntRange, A>> out = new ArrayList();
    int i = 0, n = l(l);
    while (i < n) {
      A a = l.get(i);
      int j = i + 1;
      while (j < n && eq(a, l.get(j))) ++j;
      out.add(pair(intRange(i, j), a));
      i = j;
    }
    return out;
  }

  static public <A> List<A> listFromFunction(int n, IF1<Integer, A> f) {
    return new RandomAccessAbstractList<A>() {

      public int size() {
        return n;
      }

      public A get(int i) {
        return f.get(i);
      }
    };
  }

  static public <A> List<A> listFromFunction(IF1<Integer, A> f, int n) {
    return listFromFunction(n, f);
  }

  static public String indentedStructureForUser(Object o) {
    return indentedStructureForUser(Integer.MAX_VALUE, o);
  }

  static public String indentedStructureForUser(int levels, Object o) {
    return indentStructureString(levels, structForUser(o));
  }

  static public DoubleRect doubleRect(double w, double h) {
    return new DoubleRect(0, 0, w, h);
  }

  static public DoubleRect doubleRect(double x, double y, double w, double h) {
    return new DoubleRect(x, y, w, h);
  }

  static public class getOpt_Map extends WeakHashMap {

    public getOpt_Map() {
      if (getOpt_special == null)
        getOpt_special = new HashMap();
      clear();
    }

    public void clear() {
      super.clear();
      put(Class.class, getOpt_special);
      put(String.class, getOpt_special);
    }
  }

  static final public Map<Class, HashMap<String, Field>> getOpt_cache = _registerDangerousWeakMap(synchroMap(new getOpt_Map()));

  static public HashMap getOpt_special;

  static public Map<String, Field> getOpt_getFieldMap(Object o) {
    Class c = _getClass(o);
    HashMap<String, Field> map = getOpt_cache.get(c);
    if (map == null)
      map = getOpt_makeCache(c);
    return map;
  }

  static public Object getOpt_cached(Object o, String field) {
    try {
      if (o == null)
        return null;
      Map<String, Field> map = getOpt_getFieldMap(o);
      if (map == getOpt_special) {
        if (o instanceof Class)
          return getOpt((Class) o, field);
        if (o instanceof Map)
          return ((Map) o).get(field);
      }
      Field f = map.get(field);
      if (f != null)
        return f.get(o);
      if (o instanceof DynamicObject)
        return syncMapGet2(((DynamicObject) o).fieldValues, field);
      return null;
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public HashMap<String, Field> getOpt_makeCache(Class c) {
    HashMap<String, Field> map;
    if (isSubtypeOf(c, Map.class))
      map = getOpt_special;
    else {
      map = new HashMap();
      if (!reflection_classesNotToScan().contains(c.getName())) {
        Class _c = c;
        do {
          for (Field f : _c.getDeclaredFields()) {
            makeAccessible(f);
            String name = f.getName();
            if (!map.containsKey(name))
              map.put(name, f);
          }
          _c = _c.getSuperclass();
        } while (_c != null);
      }
    }
    if (getOpt_cache != null)
      getOpt_cache.put(c, map);
    return map;
  }

  static public Area scanlineBitMatrixToArea(ScanlineBitMatrix m) {
    return joinAreas(map(__55 -> toRectangle(__55), m.runs()));
  }

  static public ScanlineBitMatrix toScanlineBitMatrix(Matrix<Boolean> m) {
    if (m == null)
      return null;
    if (m instanceof ScanlineBitMatrix)
      return ((ScanlineBitMatrix) m);
    return new ScanlineBitMatrix(m);
  }

  static public float clampZeroToOne(float x) {
    return x < 0 ? 0 : x > 1 ? 1 : x;
  }

  static public double clampZeroToOne(double x) {
    return x < 0 ? 0 : x > 1 ? 1 : x;
  }

  static public String userHomeIfNotActual() {
    String home = userHome();
    return eq(home, actualUserHome()) ? null : home;
  }

  static public boolean makeAndroid3_disable = false;

  static public class Android3 implements AutoCloseable {

    public String greeting;

    public boolean publicOverride = false;

    public int startPort = 5000;

    public Responder responder;

    public boolean console = true;

    public boolean quiet = false;

    public boolean daemon = false;

    public boolean incomingSilent = false;

    public int incomingPrintLimit = 200;

    public boolean useMultiPort = true;

    public boolean recordHistory = false;

    public boolean verbose = false;

    public int answerPrintLimit = 500;

    public boolean newLineAboveAnswer, newLineBelowAnswer;

    public int port;

    public long vport;

    public DialogHandler handler;

    public ServerSocket server;

    public Android3(String greeting) {
      this.greeting = greeting;
    }

    public Android3() {
    }

    public void close() {
      dispose();
    }

    synchronized public void dispose() {
      if (server != null) {
        try {
          server.close();
        } catch (IOException e) {
          print("[internal] " + e);
        }
        server = null;
      }
      if (vport != 0) {
        try {
          print("Disposing " + this);
          removeFromMultiPort(vport);
          vport = 0;
        } catch (Throwable __e) {
          printStackTrace(__e);
        }
      }
    }

    public String toString() {
      return "Bot: " + greeting + " [vport " + vport + "]";
    }
  }

  static abstract public class Responder {

    abstract public String answer(String s, List<String> history);
  }

  static public Android3 makeAndroid3(final String greeting) {
    return makeAndroid3(new Android3(greeting));
  }

  static public Android3 makeAndroid3(final String greeting, Responder responder) {
    Android3 android = new Android3(greeting);
    android.responder = responder;
    return makeAndroid3(android);
  }

  static public Android3 makeAndroid3(final Android3 a) {
    if (makeAndroid3_disable)
      return a;
    if (a.responder == null)
      a.responder = new Responder() {

        public String answer(String s, List<String> history) {
          return callStaticAnswerMethod(s, history);
        }
      };
    if (!a.quiet)
      print("[bot] " + a.greeting);
    if (a.console && (readLine_noReadLine || makeAndroid3_consoleInUse()))
      a.console = false;
    record(a);
    if (a.useMultiPort)
      a.vport = addToMultiPort(a.greeting, makeAndroid3_verboseResponder(a));
    if (a.console)
      makeAndroid3_handleConsole(a);
    if (a.useMultiPort)
      return a;
    a.handler = makeAndroid3_makeDialogHandler(a);
    if (a.quiet)
      startDialogServer_quiet.set(true);
    try {
      a.port = a.daemon ? startDialogServerOnPortAboveDaemon(a.startPort, a.handler) : startDialogServerOnPortAbove(a.startPort, a.handler);
    } finally {
      startDialogServer_quiet.set(null);
    }
    a.server = startDialogServer_serverSocket;
    return a;
  }

  static public void makeAndroid3_handleConsole(final Android3 a) {
    if (!a.quiet)
      print("You may also type on this console.");
    {
      startThread(new Runnable() {

        public void run() {
          try {
            List<String> history = new ArrayList();
            while (licensed()) {
              String line;
              try {
                line = readLine();
              } catch (Throwable e) {
                print(getInnerMessage(e));
                break;
              }
              if (line == null)
                break;
              {
                history.add(line);
                history.add(makeAndroid3_getAnswer(line, history, a));
              }
            }
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "List<String> history = new ArrayList();\r\n    while (licensed()) {\r\n      Stri...";
        }
      });
    }
  }

  static public DialogHandler makeAndroid3_makeDialogHandler(final Android3 a) {
    return new DialogHandler() {

      public void run(final DialogIO io) {
        if (!a.publicOverride && !(publicCommOn() || io.isLocalConnection())) {
          io.sendLine("Sorry, not allowed");
          return;
        }
        String dialogID = randomID(8);
        io.sendLine(a.greeting + " / Your ID: " + dialogID);
        List<String> history = new ArrayList();
        while (io.isStillConnected()) {
          if (io.waitForLine()) {
            final String line = io.readLineNoBlock();
            String s = dialogID + " at " + now() + ": " + quote(line);
            if (!a.incomingSilent)
              print(shorten(s, a.incomingPrintLimit));
            if (eq(line, "bye")) {
              io.sendLine("bye stranger");
              return;
            }
            Matches m = new Matches();
            if (a.recordHistory)
              history.add(line);
            String answer;
            if (match3("this is a continuation of talk *", s, m) || match3("hello bot! this is a continuation of talk *", s, m)) {
              dialogID = unquote(m.m[0]);
              answer = "ok";
            } else
              try {
                makeAndroid3_io.set(io);
                answer = makeAndroid3_getAnswer(line, history, a);
              } finally {
                makeAndroid3_io.set(null);
              }
            if (a.recordHistory)
              history.add(answer);
            io.sendLine(answer);
          }
        }
      }
    };
  }

  static public String makeAndroid3_getAnswer(String line, List<String> history, Android3 a) {
    String answer, originalAnswer;
    try {
      originalAnswer = a.responder.answer(line, history);
      answer = makeAndroid3_fallback(line, history, originalAnswer);
    } catch (Throwable e) {
      e = getInnerException(e);
      printStackTrace(e);
      originalAnswer = answer = e.toString();
    }
    if (!a.incomingSilent) {
      if (originalAnswer == null)
        originalAnswer = "?";
      if (a.newLineAboveAnswer)
        print();
      print(">" + dropFirst(indentx(2, shorten(rtrim(originalAnswer), a.answerPrintLimit))));
      if (a.newLineBelowAnswer)
        print();
    }
    return answer;
  }

  static public String makeAndroid3_fallback(String s, List<String> history, String answer) {
    if (answer == null && match3("what is your pid", s))
      return getPID();
    if (answer == null && match3("what is your program id", s))
      return getProgramID();
    if (match3("get injection id", s))
      return getInjectionID();
    if (answer == null)
      answer = "?";
    if (answer.indexOf('\n') >= 0 || answer.indexOf('\r') >= 0)
      answer = quote(answer);
    return answer;
  }

  static public boolean makeAndroid3_consoleInUse() {
    if (isTrue(vm_generalMap_get("consoleInUse")))
      return true;
    for (Object o : record_list) if (o instanceof Android3 && ((Android3) o).console)
      return true;
    return false;
  }

  static public Responder makeAndroid3_verboseResponder(final Android3 a) {
    return new Responder() {

      public String answer(String s, List<String> history) {
        if (a.verbose)
          print("> " + shorten(s, a.incomingPrintLimit));
        String answer = a.responder.answer(s, history);
        if (a.verbose)
          print("< " + shorten(answer, a.incomingPrintLimit));
        return answer;
      }
    };
  }

  static public ThreadLocal<DialogIO> makeAndroid3_io = new ThreadLocal();

  static public Android3 makeAndroid3() {
    return makeAndroid3(getProgramTitle() + ".");
  }

  static public String makeResponder_callAnswerMethod(Object bot, String s, List<String> history) {
    String answer = (String) callOpt(bot, "answer", s, history);
    if (answer == null)
      answer = (String) callOpt(bot, "answer", s);
    return answer;
  }

  static public Responder makeResponder(final Object bot) {
    if (bot instanceof Responder)
      return (Responder) bot;
    if (bot instanceof String) {
      String f = (String) bot;
      return new Responder() {

        public String answer(String s, List<String> history) {
          String answer = (String) callOptMC((String) bot, s, history);
          if (answer == null)
            answer = (String) callOptMC((String) bot, s);
          return answer;
        }
      };
    }
    return new Responder() {

      public String answer(String s, List<String> history) {
        return makeResponder_callAnswerMethod(bot, s, history);
      }
    };
  }

  static public String defaultBotName() {
    return getProgramTitle() + ".";
  }

  static public <A> List<A> sortByCalculatedField(Iterable<A> c, final Object f) {
    List<A> l = cloneList(c);
    sort(l, new Comparator<A>() {

      public int compare(A a, A b) {
        return stdcompare(callF(f, a), callF(f, b));
      }
    });
    return l;
  }

  static public <T> void sort(T[] a, Comparator<? super T> c) {
    if (a != null)
      Arrays.sort(a, c);
  }

  static public <T> void sort(T[] a) {
    if (a != null)
      Arrays.sort(a);
  }

  static public void sort(int[] a) {
    if (a != null)
      Arrays.sort(a);
  }

  static public <T> void sort(List<T> a, Comparator<? super T> c) {
    if (a != null)
      Collections.sort(a, c);
  }

  static public void sort(List a) {
    if (a != null)
      Collections.sort(a);
  }

  static public Map<String, Object> rawTableLineAsMap(JTable tbl, int row) {
    if (row >= 0 && row < tbl.getModel().getRowCount()) {
      Map<String, Object> map = litorderedmap();
      for (int i = 0; i < tbl.getModel().getColumnCount(); i++) mapPut(map, tbl.getModel().getColumnName(i), tbl.getModel().getValueAt(row, i));
      return map;
    }
    return null;
  }

  static public ThreadLocal<Boolean> dataToTable_useStruct = threadLocalWithDefault(true);

  static public void dataToTable_dynSet(List l, int i, Object s) {
    while (i >= l.size()) l.add("");
    l.set(i, s);
  }

  static public List dataToTable_makeRow(Object x, List<String> cols) {
    if (instanceOf(x, "DynamicObject"))
      x = get_raw(x, "fieldValues");
    if (x instanceof Map) {
      Map m = (Map) x;
      List row = new ArrayList();
      for (Object _field : keysWithoutHidden(m)) {
        String field = (String) _field;
        Object value = m.get(field);
        int col = cols.indexOf(field);
        if (col < 0) {
          cols.add(field);
          col = cols.size() - 1;
        }
        dataToTable_dynSet(row, col, dataToTable_wrapValue(value));
      }
      return row;
    }
    if (x instanceof List)
      return allToString((List) x);
    return litlist(structureOrText(x));
  }

  static public Object dataToTable_wrapValue(Object o) {
    if (o instanceof BufferedImage)
      return o;
    if (o instanceof MakesBufferedImage)
      return ((MakesBufferedImage) o).getBufferedImage();
    if (o instanceof RGBImage)
      return o;
    if (o instanceof Boolean)
      return o;
    return dataToTable_useStruct.get() ? structureOrTextForUser(o) : strOrNull(o);
  }

  static public String structureOrTextForUser(Object o) {
    return o == null ? "" : o instanceof String ? (String) o : structureForUser(o);
  }

  static public void fillTableWithData(final JTable table, List<List> rows, List<String> colNames) {
    fillTableWithData(table, rows, toStringArray(colNames));
  }

  static public void fillTableWithData(final JTable table, List<List> rows, String... colNames) {
    final DefaultTableModel model = fillTableWithData_makeModel(rows, colNames);
    setTableModel(table, model);
  }

  static public DefaultTableModel fillTableWithData_makeModel(List<List> rows, String... colNames) {
    Pair<Object[][], Object[]> p = fillTableWithData_makeData(rows, colNames);
    return new DefaultTableModel(p.a, p.b) {

      public Class getColumnClass(int column) {
        return or(_getClass(getValueAt(0, column)), String.class);
      }

      public boolean isCellEditable(int rowIndex, int columnIndex) {
        return false;
      }
    };
  }

  static public JMenuItem jMenuItem(final String text) {
    return jmenuItem(text);
  }

  static public JMenuItem jMenuItem(String text, Object r) {
    return jmenuItem(text, r);
  }

  static public Pair<String, Integer> jmenu_autoMnemonic(String s) {
    int i = indexOf(s, '&');
    if (i >= 0 && i < l(s) && isLetterOrDigit(s.charAt(i + 1)))
      return pair(substring(s, 0, i) + substring(s, i + 1), (int) s.charAt(i + 1));
    return pair(s, 0);
  }

  static public JMenuItem disableMenuItem(final JMenuItem mi) {
    if (mi != null) {
      swing(() -> {
        mi.setEnabled(false);
      });
    }
    return mi;
  }

  static public ActionListener actionListenerInNewThread(final Object runnable) {
    return actionListenerInNewThread(runnable, null);
  }

  static public ActionListener actionListenerInNewThread(final Object runnable, final Object instanceToHold) {
    if (runnable instanceof ActionListener)
      return (ActionListener) runnable;
    return new java.awt.event.ActionListener() {

      public void actionPerformed(java.awt.event.ActionEvent _evt) {
        try {
          startThread("Action Listener", new Runnable() {

            public void run() {
              try {
                AutoCloseable __1 = holdInstance(instanceToHold);
                try {
                  callF(runnable);
                } finally {
                  _close(__1);
                }
              } catch (Exception __e) {
                throw rethrow(__e);
              }
            }

            public String toString() {
              return "AutoCloseable __1 = holdInstance(instanceToHold); try {\r\n      callF(runnable...";
            }
          });
        } catch (Throwable __e) {
          messageBox(__e);
        }
      }
    };
  }

  static public ActionListener actionListener(final Object runnable) {
    return actionListener(runnable, null);
  }

  static public ActionListener actionListener(final Object runnable, final Object instanceToHold) {
    if (runnable instanceof ActionListener)
      return (ActionListener) runnable;
    final Object info = _threadInfo();
    return new java.awt.event.ActionListener() {

      public void actionPerformed(java.awt.event.ActionEvent _evt) {
        try {
          _threadInheritInfo(info);
          AutoCloseable __1 = holdInstance(instanceToHold);
          try {
            pcallF(runnable);
          } finally {
            _close(__1);
          }
        } catch (Throwable __e) {
          messageBox(__e);
        }
      }
    };
  }

  static public JMenuItem directJMenuItem(Action a) {
    return new JMenuItem(a) {

      public Dimension getMaximumSize() {
        return new Dimension(super.getPreferredSize().width, super.getMaximumSize().height);
      }
    };
  }

  static public JMenuItem directJMenuItem(String text, Object action) {
    return directJMenuItem(abstractAction(text, action));
  }

  static public JMenuBar addMenuBar(final Component c) {
    return swing(new F0<JMenuBar>() {

      public JMenuBar get() {
        try {
          RootPaneContainer f = getPossiblyInternalFrame(c);
          if (f == null)
            return null;
          JMenuBar bar = (JMenuBar) (call(f, "getJMenuBar"));
          if (bar == null) {
            setMenuBar(f, bar = new JMenuBar());
            revalidate((Component) f);
          }
          return bar;
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "RootPaneContainer f = getPossiblyInternalFrame(c);\r\n    if (f == null) null;\r...";
      }
    });
  }

  static public void setOptMC(String field, Object value) {
    setOpt(mc(), field, value);
  }

  static public void smartSet(Field f, Object o, Object value) throws Exception {
    try {
      f.set(o, value);
    } catch (Exception e) {
      Class type = f.getType();
      if (type == int.class && value instanceof Long) {
        f.set(o, ((Long) value).intValue());
        return;
      }
      if (type == boolean.class && value instanceof String) {
        f.set(o, isTrueOrYes(((String) value)));
        return;
      }
      if (type == LinkedHashMap.class && value instanceof Map) {
        f.set(o, asLinkedHashMap((Map) value));
        return;
      }
      try {
        if (f.getType() == Concept.Ref.class) {
          f.set(o, ((Concept) o).new Ref((Concept) value));
          return;
        }
        if (o instanceof Concept.Ref) {
          f.set(o, ((Concept.Ref) o).get());
          return;
        }
      } catch (Throwable _e) {
      }
      throw e;
    }
  }

  static public <A extends DynamicObject> A setDyn(A o, String key, Object value) {
    setDynObjectValue(o, key, value);
    return o;
  }

  static public void setDyn(IMeta o, String key, Object value) {
    metaMapPut(o, key, value);
  }

  static public <A> Set<A> cloneSet(Collection<A> set) {
    if (set == null)
      return new HashSet();
    synchronized (collectionMutex(set)) {
      Set<A> s = similarEmptySet(set);
      s.addAll(set);
      return s;
    }
  }

  static public <A> List<A> sortByCalculatedFieldIC(Iterable<A> c, final Object f) {
    List<A> l = cloneList(c);
    sort(l, new Comparator<A>() {

      public int compare(A a, A b) {
        return compareIC((String) callF(f, a), (String) callF(f, b));
      }
    });
    return l;
  }

  static public JPanel showFormTitled_customArrangement(final boolean internalFrame, final F1<List<JComponent>, JPanel> arrange, final String title, final Object... _parts) {
    return swing(new F0<JPanel>() {

      public JPanel get() {
        try {
          List<JComponent> out = showForm_arrange1(showForm_makeComponents(internalFrame, _parts));
          JPanel panel = callF(arrange, out);
          showForm_makeFrame(title, panel);
          return panel;
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "L<JComponent> out = showForm_arrange1(showForm_makeComponents(internalFrame, ...";
      }
    });
  }

  static public JPanel customLayoutPanel(final Object layouter) {
    return jpanel(layoutManagerFromFunction(layouter));
  }

  static public JPanel customLayoutPanel(final Object layouter, final List<? extends Component> components) {
    return addAllComponents(customLayoutPanel(layouter), components);
  }

  static public boolean containsATextArea(Component c) {
    return childOfType(c, JTextArea.class) != null;
  }

  static public int totalPreferredHeight(List<Component> l) {
    int h = 0;
    for (Component c : unnull(l)) h += c.getPreferredSize().height;
    return h;
  }

  static public <A> List<A> listWithoutIndicesInBitSet(List<A> l, BitSet bs) {
    List<A> out = new ArrayList();
    for (int i = 0; i < l(l); i++) if (!bs.get(i))
      out.add(l.get(i));
    return out;
  }

  static public Dimension componentsBoundingSize(Container container, int insetBottomRight) {
    Rectangle r = new Rectangle(0, 0, 0, 0);
    for (Component c : container.getComponents()) r = rectangleUnion(r, c.getBounds());
    return new Dimension(r.x + r.width + insetBottomRight, r.y + r.height + insetBottomRight);
  }

  static public <A> A listGet(List<A> l, int idx) {
    return l != null && idx >= 0 && idx < l(l) ? l.get(idx) : null;
  }

  static public String rtrim_fromLines(Collection lines) {
    StringBuilder buf = new StringBuilder();
    if (lines != null) {
      boolean first = true;
      for (Object line : lines) {
        if (first)
          first = false;
        else
          buf.append('\n');
        buf.append(str(line));
      }
    }
    return buf.toString();
  }

  static public <A, B> B getOrCreate(Map<A, B> map, A key, Class<? extends B> c) {
    try {
      B b = map.get(key);
      if (b == null)
        map.put(key, b = c.newInstance());
      return b;
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public <A, B> B getOrCreate(Map<A, B> map, A key, Object f) {
    try {
      B b = map.get(key);
      if (b == null)
        map.put(key, b = (B) callF(f));
      return b;
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public <A, B> B getOrCreate(IF0<B> f, Map<A, B> map, A key) {
    return getOrCreate(map, key, f);
  }

  static public <A, B> B getOrCreate(Map<A, B> map, A key, IF0<B> f) {
    B b = map.get(key);
    if (b == null)
      map.put(key, b = f.get());
    return b;
  }

  static public <A, B> B getOrCreate(Class<? extends B> c, Map<A, B> map, A key) {
    return getOrCreate(map, key, c);
  }

  static public <A extends JTextComponent> A bindTextComponentToLiveValue_bothWays(final A tc, final SimpleLiveValue<String> lv) {
    bindLiveValueListenerToComponent(tc, lv, new Runnable() {

      public void run() {
        try {
          setTextKeepCaret(tc, lv.get());
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "setTextKeepCaret(tc, lv!)";
      }
    });
    onChange(tc, new Runnable() {

      public void run() {
        try {
          lv.set(getText(tc));
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "lv.set(getText(tc))";
      }
    });
    return tc;
  }

  static public void tableEnableDrag(final JTable table, TransferHandler th) {
    if (table.getDragEnabled()) {
      print("Table drag already enabled");
      return;
    }
    table.setDragEnabled(true);
    table.setTransferHandler(th);
    table.addMouseListener(new MouseAdapter() {

      @Override
      public void mousePressed(MouseEvent e) {
        if (e.getButton() == 1 && e.getClickCount() == 1)
          table.getTransferHandler().exportAsDrag(table, e, TransferHandler.COPY);
      }
    });
  }

  static public void fillTableWithStrings(final JTable table, List<List<String>> rows, List<String> colNames) {
    fillTableWithStrings(table, rows, toStringArray(colNames));
  }

  static public void fillTableWithStrings(final JTable table, List<List<String>> rows, String... colNames) {
    final DefaultTableModel model = fillTableWithStrings_makeModel(rows, colNames);
    swingNowOrLater(new Runnable() {

      public void run() {
        try {
          setTableModel(table, model);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "setTableModel(table, model);";
      }
    });
  }

  static public DefaultTableModel fillTableWithStrings_makeModel(List<List<String>> rows, String... colNames) {
    Object[][] data = new Object[rows.size()][];
    int w = 0;
    for (int i = 0; i < rows.size(); i++) {
      List<String> l = rows.get(i);
      Object[] r = new Object[l.size()];
      for (int j = 0; j < l.size(); j++) r[j] = l.get(j);
      data[i] = r;
      w = Math.max(w, l.size());
    }
    Object[] columnNames = new Object[w];
    for (int i = 0; i < w; i++) columnNames[i] = i < l(colNames) ? colNames[i] : "?";
    return new DefaultTableModel(data, columnNames);
  }

  static public <A> List<A> replaceAll(List<A> l, final A a, final A b) {
    return map(l, new F1<A, A>() {

      public A get(A x) {
        try {
          return eq(x, a) ? b : x;
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "eq(x, a) ? b : x";
      }
    });
  }

  static public String replaceAll(String s, String a, String b) {
    return s == null ? null : s.replaceAll(a, b);
  }

  static public String renderVars_str(Object... params) {
    List<String> l = new ArrayList();
    int i = 0;
    if (odd(l(params))) {
      l.add(strOrNull(first(params)));
      ++i;
    }
    for (; i + 1 < l(params); i += 2) l.add(params[i] + "=" + params[i + 1]);
    return trim(joinWithComma(l));
  }

  static public void assertNotOnAWTThread() {
    assertFalse("Can't do this in AWT thread", isAWTThread());
  }

  static public void onFrameClose(Component c, final Runnable r) {
    JFrame f = getFrame(c);
    if (f != null)
      f.addWindowListener(new WindowAdapter() {

        public void windowClosing(WindowEvent e) {
          try {
            r.run();
          } catch (Throwable __e) {
            messageBox(__e);
          }
        }
      });
  }

  static public int showForm_defaultGap = 4;

  static public int showForm_gapBetweenColumns = 10;

  static public JPanel showFormTitled(final String title, final Object... _parts) {
    JDesktopPane desktop = mainDesktopPane();
    if (desktop != null)
      return showInternalFrameFormTitled(desktop, title, _parts);
    return swing(new F0<JPanel>() {

      public JPanel get() {
        try {
          final Var<JFrame> frame = new Var();
          JPanel panel = showForm_makePanel(false, _parts);
          frame.set(showForm_makeFrame(title, panel));
          return panel;
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "final new Var<JFrame> frame;\r\n    JPanel panel = showForm_makePanel(false, _p...";
      }
    });
  }

  static public JPanel showForm_makePanel(Boolean internalFrame, Object... _parts) {
    List<JComponent> out = showForm_arrange1(showForm_makeComponents(internalFrame, _parts));
    return vstackWithSpacing(out, showForm_defaultGap);
  }

  static public Object[] arrayPlus(Object[] a1, Object... a2) {
    return concatArrays(a1, a2);
  }

  static public <A> A waitUntilVarSet(Var<A> v) {
    try {
      synchronized (v) {
        while (!v.has()) v.wait();
        return v.get();
      }
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public <A> A waitUntilVarSet(Var<A> v, int timeout) {
    try {
      synchronized (v) {
        long time = nanoTime();
        while (!v.has() && (nanoTime() - time) < timeout * 900000) v.wait(timeout);
        return v.get();
      }
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public String indentStructureString(String s) {
    return indentStructureString(100, s);
  }

  static public String indentStructureString(int levels, String s) {
    if (s == null)
      return null;
    List<String> tok = javaTokForStructure(s);
    StringBuilder buf = new StringBuilder();
    int indent = 0;
    levels = clampToInt(levels * 2L);
    for (int i = 0; i < l(tok); i++) {
      String t = tok.get(i);
      if (isOpeningBracket(t)) {
        int j = i + 5;
        if (containsClosingBracket(subList(tok, i + 2, i + 5))) {
          buf.append(joinSubList(tok, i, j));
          i = j - 1;
        } else {
          indent += 2;
          buf.append(t);
          if (indent <= levels)
            buf.append("\n").append(spaces(indent));
        }
      } else if (isClosingBracket(t)) {
        indent -= 2;
        if (indent < levels)
          buf.append("\n").append(spaces(indent));
        buf.append(t);
      } else if (indent <= levels && eq(t, ",")) {
        buf.append(t).append("\n").append(spaces(indent));
        i++;
      } else
        buf.append(t);
    }
    return str(buf);
  }

  static public String structForUser(Object o) {
    return structureForUser(o);
  }

  static public void clear(Collection c) {
    if (c != null)
      c.clear();
  }

  static public void clear(Map map) {
    if (map != null)
      map.clear();
  }

  static public List<Pair> _registerDangerousWeakMap_preList;

  static public <A> A _registerDangerousWeakMap(A map) {
    return _registerDangerousWeakMap(map, null);
  }

  static public <A> A _registerDangerousWeakMap(A map, Object init) {
    callF(init, map);
    if (init instanceof String) {
      final String f = (String) init;
      init = new VF1<Map>() {

        public void get(Map map) {
          try {
            callMC(f, map);
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "callMC(f, map)";
        }
      };
    }
    if (javax() == null) {
      if (_registerDangerousWeakMap_preList == null)
        _registerDangerousWeakMap_preList = synchroList();
      _registerDangerousWeakMap_preList.add(pair(map, init));
      return map;
    }
    call(javax(), "_registerDangerousWeakMap", map, init);
    return map;
  }

  static public void _onLoad_registerDangerousWeakMap() {
    assertNotNull(javax());
    if (_registerDangerousWeakMap_preList == null)
      return;
    for (Pair p : _registerDangerousWeakMap_preList) _registerDangerousWeakMap(p.a, p.b);
    _registerDangerousWeakMap_preList = null;
  }

  static public <A, B> B syncMapGet2(Map<A, B> map, A a) {
    if (map == null)
      return null;
    synchronized (collectionMutex(map)) {
      return map.get(a);
    }
  }

  static public <A, B> B syncMapGet2(A a, Map<A, B> map) {
    return syncMapGet2(map, a);
  }

  static public Set<String> reflection_classesNotToScan_value = litset("jdk.internal.loader.URLClassPath");

  static public Set<String> reflection_classesNotToScan() {
    return reflection_classesNotToScan_value;
  }

  static public Area joinAreas(Collection<? extends Shape> l) {
    if (empty(l))
      return null;
    Area a = new Area();
    for (var b : l) a.add(toArea(b));
    return a;
  }

  static public void removeFromMultiPort(long vport) {
    if (vport == 0)
      return;
    for (Object port : getMultiPorts()) call(port, "removePort", vport);
  }

  static public String callStaticAnswerMethod(List bots, String s) {
    for (Object c : bots) try {
      String answer = callStaticAnswerMethod(c, s);
      if (!empty(answer))
        return answer;
    } catch (Throwable e) {
      print("Error calling " + getProgramID(c));
      e.printStackTrace();
    }
    return null;
  }

  static public String callStaticAnswerMethod(Object c, String s) {
    String answer = (String) callOpt(c, "answer", s, litlist(s));
    if (answer == null)
      answer = (String) callOpt(c, "answer", s);
    return emptyToNull(answer);
  }

  static public String callStaticAnswerMethod(String s) {
    return callStaticAnswerMethod(mc(), s);
  }

  static public String callStaticAnswerMethod(String s, List<String> history) {
    return callStaticAnswerMethod(mc(), s, history);
  }

  static public String callStaticAnswerMethod(Object c, String s, List<String> history) {
    String answer = (String) callOpt(c, "answer", s, history);
    if (answer == null)
      answer = (String) callOpt(c, "answer", s);
    return emptyToNull(answer);
  }

  static public List<Object> record_list = synchroList();

  static public void record(Object o) {
    record_list.add(o);
  }

  static public Object addToMultiPort_responder;

  static public long addToMultiPort(final String botName) {
    return addToMultiPort(botName, new Object() {

      public String answer(String s, List<String> history) {
        String answer = (String) (callOpt(getMainClass(), "answer", s, history));
        if (answer != null)
          return answer;
        answer = (String) callOpt(getMainClass(), "answer", s);
        if (answer != null)
          return answer;
        if (match3("get injection id", s))
          return getInjectionID();
        return null;
      }
    });
  }

  static public long addToMultiPort(final String botName, final Object responder) {
    addToMultiPort_responder = responder;
    startMultiPort();
    List ports = getMultiPorts();
    if (ports == null)
      return 0;
    if (ports.isEmpty())
      throw fail("No multiports!");
    if (ports.size() > 1)
      print("Multiple multi-ports. Using last one.");
    Object port = last(ports);
    Object responder2 = new Object() {

      public String answer(String s, List<String> history) {
        if (match3("get injection id", s))
          return getInjectionID();
        if (match3("your name", s))
          return botName;
        return (String) call(responder, "answer", s, history);
      }
    };
    record(responder2);
    return (Long) call(port, "addResponder", botName, responder2);
  }

  static public AtomicInteger dialogServer_clients = new AtomicInteger();

  static public boolean dialogServer_printConnects = false;

  static public ThreadLocal<Boolean> startDialogServer_quiet = new ThreadLocal();

  static public Set<String> dialogServer_knownClients = synchroTreeSet();

  static public int startDialogServerOnPortAbove(int port, DialogHandler handler) {
    while (!forbiddenPort(port) && !startDialogServerIfPortAvailable(port, handler)) ++port;
    return port;
  }

  static public int startDialogServerOnPortAboveDaemon(int port, DialogHandler handler) {
    while (!forbiddenPort(port) && !startDialogServerIfPortAvailable(port, handler, true)) ++port;
    return port;
  }

  static public void startDialogServer(int port, DialogHandler handler) {
    if (!startDialogServerIfPortAvailable(port, handler))
      throw fail("Can't start dialog server on port " + port);
  }

  static public boolean startDialogServerIfPortAvailable(int port, final DialogHandler handler) {
    return startDialogServerIfPortAvailable(port, handler, false);
  }

  static public ServerSocket startDialogServer_serverSocket;

  static public boolean startDialogServerIfPortAvailable(int port, final DialogHandler handler, boolean daemon) {
    ServerSocket serverSocket = null;
    try {
      serverSocket = new ServerSocket(port);
    } catch (IOException e) {
      return false;
    }
    final ServerSocket _serverSocket = serverSocket;
    startDialogServer_serverSocket = serverSocket;
    Thread thread = new Thread("Socket accept port " + port) {

      public void run() {
        try {
          while (true) {
            try {
              final Socket s = _serverSocket.accept();
              String client = s.getInetAddress().toString();
              if (!dialogServer_knownClients.contains(client) && neq(client, "/127.0.0.1")) {
                print("connect from " + client + " - clients: " + dialogServer_clients.incrementAndGet());
                dialogServer_knownClients.add(client);
              }
              String threadName = "Handling client " + s.getInetAddress();
              Thread t2 = new Thread(threadName) {

                public void run() {
                  try {
                    final Writer w = new OutputStreamWriter(s.getOutputStream(), "UTF-8");
                    final BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8"));
                    DialogIO io = new DialogIO() {

                      public boolean isLocalConnection() {
                        return s.getInetAddress().isLoopbackAddress();
                      }

                      public boolean isStillConnected() {
                        return !(eos || s.isClosed());
                      }

                      public void sendLine(String line) {
                        try {
                          w.write(line + "\n");
                          w.flush();
                        } catch (Exception __e) {
                          throw rethrow(__e);
                        }
                      }

                      public String readLineImpl() {
                        try {
                          return in.readLine();
                        } catch (Exception __e) {
                          throw rethrow(__e);
                        }
                      }

                      public void close() {
                        try {
                          s.close();
                        } catch (IOException e) {
                        }
                      }

                      public Socket getSocket() {
                        return s;
                      }
                    };
                    try {
                      handler.run(io);
                    } finally {
                      if (!io.noClose)
                        s.close();
                    }
                  } catch (IOException e) {
                    print("[internal] " + e);
                  } finally {
                  }
                }
              };
              t2.setDaemon(true);
              t2.start();
            } catch (SocketTimeoutException e) {
            }
          }
        } catch (IOException e) {
          print("[internal] " + e);
        }
      }
    };
    if (daemon)
      thread.setDaemon(true);
    thread.start();
    if (!isTrue(getAndClearThreadLocal(startDialogServer_quiet)))
      print("Dialog server on port " + port + " started.");
    return true;
  }

  static volatile public boolean readLine_noReadLine = false;

  static public String readLine_lastInput;

  static public String readLine_prefix = "[] ";

  static public String readLine() {
    if (readLine_noReadLine)
      return null;
    String s = readLineHidden();
    if (s != null) {
      readLine_lastInput = s;
      print(readLine_prefix + s);
    }
    return s;
  }

  static public String getInnerMessage(Throwable e) {
    if (e == null)
      return null;
    return getInnerException(e).getMessage();
  }

  static public boolean publicCommOn() {
    return "1".equals(loadTextFile(new File(userHome(), ".javax/public-communication")));
  }

  static public int randomID_defaultLength = 12;

  static public String randomID(int length) {
    return makeRandomID(length);
  }

  static public String randomID(Random r, int length) {
    return makeRandomID(r, length);
  }

  static public String randomID() {
    return randomID(randomID_defaultLength);
  }

  static public String randomID(Random r) {
    return randomID(r, randomID_defaultLength);
  }

  static public boolean match3(String pat, String s) {
    return match3(pat, s, null);
  }

  static public boolean match3(String pat, String s, Matches matches) {
    if (pat == null || s == null)
      return false;
    return match3(pat, parse3_cachedInput(s), matches);
  }

  static public boolean match3(String pat, List<String> toks, Matches matches) {
    List<String> tokpat = parse3_cachedPattern(pat);
    return match3(tokpat, toks, matches);
  }

  static public boolean match3(List<String> tokpat, List<String> toks, Matches matches) {
    String[] m = match2(tokpat, toks);
    if (m == null)
      return false;
    if (matches != null)
      matches.m = m;
    return true;
  }

  public static String rtrim(String s) {
    if (s == null)
      return null;
    int i = s.length();
    while (i > 0 && " \t\r\n".indexOf(s.charAt(i - 1)) >= 0) --i;
    return i < s.length() ? s.substring(0, i) : s;
  }

  static public String processID_cached;

  static public String getPID() {
    if (processID_cached == null) {
      String name = ManagementFactory.getRuntimeMXBean().getName();
      processID_cached = name.replaceAll("@.*", "");
    }
    return processID_cached;
  }

  static public String getInjectionID() {
    return (String) call(getJavaX(), "getInjectionID", getMainClass());
  }

  static public Object callOptMC(String method, Object... args) {
    return callOpt(mc(), method, args);
  }

  static public <A> ThreadLocal<A> threadLocalWithDefault(A defaultValue) {
    return new ThreadLocal<A>() {

      public A initialValue() {
        return defaultValue;
      }
    };
  }

  static public boolean instanceOf(Object o, String className) {
    if (o == null)
      return false;
    String c = o.getClass().getName();
    return eq(c, className) || eq(c, "main$" + className);
  }

  static public boolean instanceOf(Object o, Class c) {
    if (c == null)
      return false;
    return c.isInstance(o);
  }

  static public boolean instanceOf(Class c, Object o) {
    return instanceOf(o, c);
  }

  static public <A, B> List<A> keysWithoutHidden(Map<A, B> map) {
    return filter(keys(map), new F1<Object, Boolean>() {

      public Boolean get(Object o) {
        try {
          return !eq(o, "[hidden]") && !isStringStartingWith(o, "[hidden] ");
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "!eq(o, \"[hidden]\") && !isStringStartingWith(o, \"[hidden] \")";
      }
    });
  }

  static public String structureOrText(Object o) {
    return o instanceof String ? (String) o : structure(o);
  }

  static public Map<JTable, VF1<JTable>> setTableModel_after = weakHashMap();

  static public Map<JTable, VF2<JTable, RowSorter>> setTableModel_fixSorter = weakHashMap();

  static public void setTableModel(final JTable table, final TableModel model) {
    {
      swing(() -> {
        Map<String, Integer> widths = tableColumnWidthsByName(table);
        int[] i = table.getSelectedRows();
        TableRowSorter sorter = model.getColumnCount() == tableColumnCount(table) ? (TableRowSorter) table.getRowSorter() : null;
        List<? extends RowSorter.SortKey> sortKeys = sorter == null ? null : sorter.getSortKeys();
        table.setModel(model);
        int n = model.getRowCount();
        ListSelectionModel sel = table.getSelectionModel();
        for (int j = 0; j < i.length; j++) if (i[j] < n)
          sel.addSelectionInterval(i[j], i[j]);
        tableSetColumnPreferredWidths(table, widths);
        if (sorter != null) {
          sorter.setModel(model);
          callF(setTableModel_fixSorter.get(table), table, sorter);
          if (sortKeys != null)
            sorter.setSortKeys(sortKeys);
        }
        table.setRowSorter(sorter);
        callF(setTableModel_after.get(table), table);
      });
    }
  }

  static public Pair<Object[][], Object[]> fillTableWithData_makeData(List<List> rows, List<String> colNames) {
    return fillTableWithData_makeData(rows, asStringArray(colNames));
  }

  static public Pair<Object[][], Object[]> fillTableWithData_makeData(List<List> rows, String... colNames) {
    Object[][] data = new Object[rows.size()][];
    int w = 0;
    for (int i = 0; i < rows.size(); i++) {
      List l = rows.get(i);
      Object[] r = new Object[l.size()];
      for (int j = 0; j < l.size(); j++) {
        Object o = l.get(j);
        if (o instanceof BufferedImage)
          o = imageIcon((BufferedImage) o);
        if (o instanceof RGBImage)
          o = imageIcon((RGBImage) o);
        r[j] = o;
      }
      data[i] = r;
      w = Math.max(w, l.size());
    }
    Object[] columnNames = new Object[w];
    for (int i = 0; i < w; i++) columnNames[i] = i < l(colNames) ? colNames[i] : "?";
    return pair(data, columnNames);
  }

  static public boolean isLetterOrDigit(char c) {
    return Character.isLetterOrDigit(c);
  }

  static public ThreadLocal<List<Object>> holdInstance_l = new ThreadLocal();

  static public AutoCloseable holdInstance(Object o) {
    if (o == null)
      return null;
    listThreadLocalAdd(holdInstance_l, o);
    return new AutoCloseable() {

      public void close() {
        listThreadLocalPopLast(holdInstance_l);
      }
    };
  }

  static public void messageBox(final String msg) {
    if (headless())
      print(msg);
    else {
      swing(() -> {
        JOptionPane.showMessageDialog(null, msg, "JavaX", JOptionPane.INFORMATION_MESSAGE);
      });
    }
  }

  static public void messageBox(Throwable e) {
    printStackTrace(e);
    messageBox(hideCredentials(innerException2(e)));
  }

  static public AbstractAction abstractAction(String name, final Object runnable) {
    return new AbstractAction(name) {

      public void actionPerformed(ActionEvent evt) {
        pcallF(runnable);
      }
    };
  }

  static public void setMenuBar(final JMenuBar mb, final RootPaneContainer f) {
    {
      swing(() -> {
        call(f, "setJMenuBar", mb);
        revalidate((Component) f);
      });
    }
  }

  static public void setMenuBar(RootPaneContainer f, JMenuBar mb) {
    setMenuBar(mb, f);
  }

  static public boolean isTrueOrYes(Object o) {
    return isTrueOpt(o) || o instanceof String && (eqicOneOf(((String) o), "1", "t", "true") || isYes(((String) o)));
  }

  static public void setDynObjectValue(DynamicObject o, String field, Object value) {
    dynamicObject_setRawFieldValue(o, field, value);
  }

  static public int compareIC(String s1, String s2) {
    return compareIgnoreCase_jdk(s1, s2);
  }

  static public List<JComponent> showForm_arrange1(List<List<JComponent>> l) {
    int minW = showForm_leftWidth(l);
    List<JComponent> out = new ArrayList();
    for (List<JComponent> row : l) out.add(westAndCenter(withRightMargin(showForm_gapBetweenColumns, jMinWidthAtLeast(minW, first(row))), second(row)));
    return out;
  }

  static public List<List<JComponent>> showForm_makeComponents(final Boolean internalFrame, Object... _parts) {
    List<List<JComponent>> l = new ArrayList();
    List parts = asList(_parts);
    JButton submitButton = null;
    for (int i = 0; i < l(parts); i++) {
      final Object o = parts.get(i), next = get(parts, i + 1);
      if (o instanceof String && next instanceof Component)
        setComponentID((Component) next, (String) o);
      if (o instanceof Component || o instanceof String || next instanceof Component) {
        l.add(mapLL(__56 -> wrapForSmartAdd_jComponent(__56), o == null ? new JPanel() : o instanceof String ? humanizeFormLabel((String) o) : o, next));
        if (next instanceof JButton && submitButton == null)
          submitButton = (JButton) next;
        i++;
      } else if (isRunnable(o))
        l.add(mapLL(__57 -> wrapForSmartAdd_jComponent(__57), null, submitButton = jbutton(showFormSubmitButtonName(), new Runnable() {

          public void run() {
            try {
              Object result = call(o);
              print("Result of form runnable: " + result + ". Button:  " + heldInstance(JButton.class));
              if (neq(Boolean.FALSE, result)) {
                if (isTrue(internalFrame))
                  disposeInternalFrame(heldInstance(JButton.class));
                else if (isFalse(internalFrame))
                  disposeFrame(heldInstance(JButton.class));
              }
            } catch (Exception __e) {
              throw rethrow(__e);
            }
          }

          public String toString() {
            return "Object result = call(o);\r\n        print(\"Result of form runnable: \" + result ...";
          }
        })));
      else
        print("showForm: Unknown element type: " + getClassName(o));
    }
    if (submitButton != null) {
      final JButton _submitButton = submitButton;
      onEnterInAllTextFields(concatLists(l), new Runnable() {

        public void run() {
          try {
            clickButton(_submitButton);
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "clickButton(_submitButton)";
        }
      });
    }
    for (List<JComponent> row : l) {
      JComponent left = first(row);
      if (left instanceof JLabel)
        makeBold((JLabel) left).setVerticalAlignment(JLabel.TOP);
    }
    return l;
  }

  static public JFrame showForm_makeFrame(String title, JPanel panel) {
    return handleEscapeKey(minFrameWidth(showPackedFrame(title, withMargin(panel)), 400));
  }

  static public LayoutManager layoutManagerFromFunction(final Object layouter) {
    return new AbstractLayoutManager() {

      public void layoutContainer(Container parent) {
        Object size = pcallF(layouter, parent);
        if (size instanceof Dimension)
          preferredSize = (Dimension) size;
        else if (size instanceof Pair) {
          preferredSize = (Dimension) ((Pair) size).a;
          minimumSize = (Dimension) ((Pair) size).b;
        }
      }
    };
  }

  static public <A extends Container> A addAllComponents(final A c, final List<? extends Component> components) {
    if (nempty(components)) {
      swing(() -> {
        for (Component x : components) c.add(x);
        revalidate(c);
      });
    }
    return c;
  }

  static public Rectangle rectangleUnion(Rectangle a, Rectangle b) {
    return a == null ? b : b == null ? a : a.union(b);
  }

  static public void swingNowOrLater(Runnable r) {
    if (isAWTThread())
      r.run();
    else
      swingLater(r);
  }

  static public JDesktopPane mainDesktopPane_value;

  static public JDesktopPane mainDesktopPane() {
    return mainDesktopPane_value;
  }

  static public JPanel showInternalFrameFormTitled(final JDesktopPane desktop, final String title, final Object... _parts) {
    JPanel panel = showForm_makePanel(true, _parts);
    showForm_makeInternalFrame(desktop, title, panel);
    return panel;
  }

  static public Object[] concatArrays(Object[]... arrays) {
    int l = 0;
    for (Object[] a : arrays) l += l(a);
    Object[] x = new Object[l];
    int i = 0;
    for (Object[] a : arrays) if (a != null) {
      System.arraycopy(a, 0, x, i, l(a));
      i += l(a);
    }
    return x;
  }

  static public int clampToInt(long l) {
    return (int) clamp(l, Integer.MIN_VALUE, Integer.MAX_VALUE);
  }

  static public boolean isOpeningBracket(String s) {
    return eqOneOf(s, "(", "{", "[");
  }

  static public boolean containsClosingBracket(List<String> l) {
    return any(__58 -> isClosingBracket(__58), l);
  }

  static public String spaces(int n) {
    return rep(' ', n);
  }

  static public boolean isClosingBracket(String s) {
    return eqOneOf(s, ")", "}", "]");
  }

  static public Object callF(Object f, Object... args) {
    try {
      if (f instanceof String)
        return callMC((String) f, args);
      return x30_util.callF(f, args);
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public <A> A callF(F0<A> f) {
    return f == null ? null : f.get();
  }

  static public <A> A callF(IF0<A> f) {
    return f == null ? null : f.get();
  }

  static public <A, B> B callF(F1<A, B> f, A a) {
    return f == null ? null : f.get(a);
  }

  static public <A, B> B callF(IF1<A, B> f, A a) {
    return f == null ? null : f.get(a);
  }

  static public <A, B, C> C callF(F2<A, B, C> f, A a, B b) {
    return f == null ? null : f.get(a, b);
  }

  static public <A> void callF(VF1<A> f, A a) {
    if (f != null)
      f.get(a);
  }

  static public Object callMC(String method, Object... args) {
    return call(mc(), method, args);
  }

  static public Object call(Object o) {
    return callF(o);
  }

  static public Object call(Object o, String method, Object... args) {
    return call_withVarargs(o, method, args);
  }

  static public <A> HashSet<A> litset(A... items) {
    return lithashset(items);
  }

  static public Area toArea(Shape s) {
    if (s == null)
      return null;
    if (s instanceof Area)
      return ((Area) s);
    return new Area(s);
  }

  static public List<Object> getMultiPorts() {
    return (List) callOpt(getJavaX(), "getMultiPorts");
  }

  static public String emptyToNull(String s) {
    return eq(s, "") ? null : s;
  }

  static public <A, B> Map<A, B> emptyToNull(Map<A, B> map) {
    return empty(map) ? null : map;
  }

  static public void startMultiPort() {
    List mp = getMultiPorts();
    if (mp != null && mp.isEmpty()) {
      nohupJavax("#1001639");
      throw fail("Upgrading JavaX, please restart this program afterwards.");
    }
  }

  static public <A> Set<A> synchroTreeSet() {
    return Collections.synchronizedSet(new TreeSet<A>());
  }

  static public <A> Set<A> synchroTreeSet(TreeSet<A> set) {
    return Collections.synchronizedSet(set);
  }

  static public boolean forbiddenPort(int port) {
    return port == 5037;
  }

  static public String readLineHidden() {
    try {
      if (get(javax(), "readLine_reader") == null)
        set(javax(), "readLine_reader", new BufferedReader(new InputStreamReader(System.in, "UTF-8")));
      try {
        return ((BufferedReader) get(javax(), "readLine_reader")).readLine();
      } finally {
        consoleClearInput();
      }
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public Map<String, List<String>> parse3_cachedInput_cache = synchronizedMRUCache(1000);

  static public List<String> parse3_cachedInput(String s) {
    List<String> tok = parse3_cachedInput_cache.get(s);
    if (tok == null)
      parse3_cachedInput_cache.put(s, tok = parse3(s));
    return tok;
  }

  static public Map<String, List<String>> parse3_cachedPattern_cache = synchronizedMRUCache(1000);

  static synchronized public List<String> parse3_cachedPattern(String s) {
    List<String> tok = parse3_cachedPattern_cache.get(s);
    if (tok == null)
      parse3_cachedPattern_cache.put(s, tok = parse3(s));
    return tok;
  }

  static public String[] match2(List<String> pat, List<String> tok) {
    int i = pat.indexOf("...");
    if (i < 0)
      return match2_match(pat, tok);
    pat = new ArrayList<String>(pat);
    pat.set(i, "*");
    while (pat.size() < tok.size()) {
      pat.add(i, "*");
      pat.add(i + 1, "");
    }
    return match2_match(pat, tok);
  }

  static public String[] match2_match(List<String> pat, List<String> tok) {
    List<String> result = new ArrayList<String>();
    if (pat.size() != tok.size()) {
      return null;
    }
    for (int i = 1; i < pat.size(); i += 2) {
      String p = pat.get(i), t = tok.get(i);
      if (eq(p, "*"))
        result.add(t);
      else if (!equalsIgnoreCase(unquote(p), unquote(t)))
        return null;
    }
    return result.toArray(new String[result.size()]);
  }

  static public boolean isStringStartingWith(Object o, String prefix) {
    return o instanceof String && ((String) o).startsWith(prefix);
  }

  static public <A, B> Map<A, B> weakHashMap() {
    return newWeakHashMap();
  }

  static public Map<String, Integer> tableColumnWidthsByName(JTable table) {
    TableColumnModel tcm = table.getColumnModel();
    if (tcm == null)
      return null;
    int n = tcm.getColumnCount();
    TreeMap<String, Integer> map = new TreeMap();
    for (int i = 0; i < n; i++) {
      TableColumn tc = tcm.getColumn(i);
      map.put(str(tc.getHeaderValue()), tc.getWidth());
    }
    return map;
  }

  static public boolean tableSetColumnPreferredWidths_debug = false;

  static public void tableSetColumnPreferredWidths(final JTable table, final Map<String, Integer> widths) {
    if (table == null || widths == null)
      return;
    {
      swing(() -> {
        try {
          TableColumnModel tcm = table.getColumnModel();
          int n = tcm.getColumnCount();
          for (int i = 0; i < n; i++) {
            TableColumn tc = tcm.getColumn(i);
            Integer w = widths.get(str(tc.getHeaderValue()));
            if (w != null) {
              tc.setPreferredWidth(w);
              if (tableSetColumnPreferredWidths_debug)
                print("Setting preferred width of column " + i + " to " + w);
            }
          }
        } catch (Throwable __e) {
          printStackTrace(__e);
        }
      });
    }
  }

  static public void tableSetColumnPreferredWidths(JTable table, Object... widths) {
    tableSetColumnPreferredWidths(table, litorderedmap(widths));
  }

  static public String[] asStringArray(Collection<String> c) {
    return toStringArray(c);
  }

  static public String[] asStringArray(Object o) {
    return toStringArray(o);
  }

  static public <A> void listThreadLocalAdd(ThreadLocal<List<A>> tl, A a) {
    List<A> l = tl.get();
    if (l == null)
      tl.set(l = new ArrayList());
    l.add(a);
  }

  static public <A> A listThreadLocalPopLast(ThreadLocal<List<A>> tl) {
    List<A> l = tl.get();
    if (l == null)
      return null;
    A a = popLast(l);
    if (empty(l))
      tl.set(null);
    return a;
  }

  static public boolean headless() {
    return isHeadless();
  }

  static public Throwable innerException2(Throwable e) {
    if (e == null)
      return null;
    while (empty(e.getMessage()) && e.getCause() != null) e = e.getCause();
    return e;
  }

  static public boolean isTrueOpt(Object o) {
    if (o instanceof Boolean)
      return ((Boolean) o).booleanValue();
    return false;
  }

  static public boolean isTrueOpt(String field, Object o) {
    return isTrueOpt(getOpt(field, o));
  }

  static public List<String> isYes_yesses = litlist("y", "yes", "yeah", "y", "yup", "yo", "corect", "sure", "ok", "afirmative");

  static public boolean isYes(String s) {
    return isYes_yesses.contains(collapseWord(toLowerCase(firstWord2(s))));
  }

  static public void dynamicObject_setRawFieldValue(DynamicObject o, Object key, Object value) {
    if (o == null)
      return;
    synchronized (o) {
      o.fieldValues = syncMapPut2_createLinkedHashMap((LinkedHashMap) o.fieldValues, key, value);
    }
  }

  static public int compareIgnoreCase_jdk(String s1, String s2) {
    if (s1 == null)
      return s2 == null ? 0 : -1;
    if (s2 == null)
      return 1;
    int n1 = s1.length();
    int n2 = s2.length();
    int min = Math.min(n1, n2);
    for (int i = 0; i < min; i++) {
      char c1 = s1.charAt(i);
      char c2 = s2.charAt(i);
      if (c1 != c2) {
        c1 = Character.toUpperCase(c1);
        c2 = Character.toUpperCase(c2);
        if (c1 != c2) {
          c1 = Character.toLowerCase(c1);
          c2 = Character.toLowerCase(c2);
          if (c1 != c2)
            return c1 - c2;
        }
      }
    }
    return n1 - n2;
  }

  static public int showForm_leftWidth_safetyMargin = 10;

  static public int showForm_leftWidth(List<List<JComponent>> l) {
    forEachLevel2(l, x -> vmBus_send("updateLayoutNow", x));
    int minW = 0;
    for (List<JComponent> row : l) minW = max(minW, getMinimumSize(first(row)).width);
    return minW + or((Integer) vmBus_query("formSafetyMargin"), showForm_leftWidth_safetyMargin);
  }

  static public void setComponentID(Component c, String id) {
    if (c != null)
      componentID_map.put(c, id);
  }

  static public List mapLL(Object f, Object... data) {
    return map(f, ll(data));
  }

  static public <A, B> List<B> mapLL(IF1<A, B> f, A... data) {
    return map(f, ll(data));
  }

  static public JComponent wrapForSmartAdd_jComponent(Object o) {
    return componentToJComponent(wrapForSmartAdd(o));
  }

  static public boolean isRunnable(Object o) {
    return o instanceof Runnable || hasMethod(o, "get");
  }

  static public void disposeFrame(final Component c) {
    disposeWindow(c);
  }

  static public void onEnterInAllTextFields(JComponent c, Object action) {
    if (action == null)
      return;
    for (Component tf : allChildren(c)) onEnterIfTextField(tf, action);
  }

  static public void onEnterInAllTextFields(List c, Object action) {
    for (Object o : unnull(c)) if (o instanceof JComponent)
      onEnterInAllTextFields((JComponent) o, action);
  }

  static public void clickButton(final JButton b) {
    if (b != null) {
      swing(() -> {
        if (b.isEnabled())
          b.doClick();
      });
    }
  }

  static public <A extends JComponent> A makeBold(final A c) {
    if (c != null) {
      swing(() -> {
        c.setFont(c.getFont().deriveFont(java.awt.Font.BOLD));
      });
    }
    return c;
  }

  static public JFrame handleEscapeKey(final JFrame frame) {
    KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
    frame.getRootPane().registerKeyboardAction(new ActionListener() {

      public void actionPerformed(ActionEvent actionEvent) {
        frame.dispose();
      }
    }, stroke, JComponent.WHEN_IN_FOCUSED_WINDOW);
    return frame;
  }

  static public JFrame minFrameWidth(JFrame frame, int w) {
    if (frame != null && frame.getWidth() < w)
      frame.setSize(w, frame.getHeight());
    return frame;
  }

  static public JFrame minFrameWidth(int w, JFrame frame) {
    return minFrameWidth(frame, w);
  }

  static public JFrame showPackedFrame(String title, Component contents) {
    return packFrame(showFrame(title, contents));
  }

  static public JFrame showPackedFrame(Component contents) {
    return packFrame(showFrame(contents));
  }

  static public JInternalFrame showForm_makeInternalFrame(JDesktopPane desktop, String title, JPanel panel) {
    JInternalFrame f = addInternalFrame(desktop, title, withMargin(panel));
    minInternalFrameWidth(f, 400);
    packInternalFrameVertically(f);
    centerInternalFrame(f);
    return f;
  }

  static public Map<Component, String> componentID_map = weakHashMap();

  static public String componentID(Component c) {
    return c == null ? null : componentID_map.get(c);
  }

  static public <A> HashSet<A> lithashset(A... items) {
    HashSet<A> set = new HashSet();
    for (A a : items) set.add(a);
    return set;
  }

  static public void consoleClearInput() {
    consoleSetInput("");
  }

  static public List<String> parse3(String s) {
    return dropPunctuation(javaTokPlusPeriod(s));
  }

  static public boolean equalsIgnoreCase(String a, String b) {
    return eqic(a, b);
  }

  static public boolean equalsIgnoreCase(char a, char b) {
    return eqic(a, b);
  }

  static public <A> A popLast(List<A> l) {
    return liftLast(l);
  }

  static public <A> List<A> popLast(int n, List<A> l) {
    return liftLast(n, l);
  }

  static public String collapseWord(String s) {
    if (s == null)
      return "";
    StringBuilder buf = new StringBuilder();
    for (int i = 0; i < l(s); i++) if (i == 0 || !charactersEqualIC(s.charAt(i), s.charAt(i - 1)))
      buf.append(s.charAt(i));
    return buf.toString();
  }

  static public List<String> toLowerCase(List<String> strings) {
    List<String> x = new ArrayList();
    for (String s : strings) x.add(s.toLowerCase());
    return x;
  }

  static public String[] toLowerCase(String[] strings) {
    String[] x = new String[l(strings)];
    for (int i = 0; i < l(strings); i++) x[i] = strings[i].toLowerCase();
    return x;
  }

  static public String toLowerCase(String s) {
    return s == null ? "" : s.toLowerCase();
  }

  static public String firstWord2(String s) {
    s = xltrim(s);
    if (empty(s))
      return "";
    if (isLetterOrDigit(first(s)))
      return takeCharsWhile(__59 -> isLetterOrDigit(__59), s);
    else
      return "" + first(s);
  }

  static public <A, B> LinkedHashMap<A, B> syncMapPut2_createLinkedHashMap(LinkedHashMap<A, B> map, A key, B value) {
    if (key != null)
      if (value != null) {
        if (map == null)
          map = new LinkedHashMap();
        synchronized (collectionMutex(map)) {
          map.put(key, value);
        }
      } else if (map != null)
        synchronized (collectionMutex(map)) {
          map.remove(key);
        }
    return map;
  }

  static public <A, B extends Collection<A>> void forEachLevel2(Iterable<B> l, IVF1<A> f) {
    if (l != null)
      for (B b : l) forEach(b, f);
  }

  static public <A, B extends Collection<A>> void forEachLevel2(IVF1<A> f, Iterable<B> l) {
    forEachLevel2(f, l);
  }

  static public List<Component> allChildren(Component c) {
    return childrenOfType(c, Component.class);
  }

  static public void onEnterIfTextField(Component c, Object action) {
    if (action == null)
      return;
    if (c instanceof JTextField)
      onEnter((JTextField) c, action);
    else if (c instanceof JComboBox)
      onEnter((JComboBox) c, action);
  }

  static public int packFrame_minw = 150, packFrame_minh = 50;

  static public <A extends Component> A packFrame(final A c) {
    {
      swing(() -> {
        Window w = getWindow(c);
        if (w != null) {
          w.pack();
          int maxW = getScreenWidth() - 50, maxH = getScreenHeight() - 50;
          w.setSize(min(maxW, max(w.getWidth(), packFrame_minw)), min(maxH, max(w.getHeight(), packFrame_minh)));
        }
      });
    }
    return c;
  }

  static public JFrame packFrame(ButtonGroup g) {
    return packFrame(getFrame(g));
  }

  static public ThreadLocal<Boolean> addInternalFrame_dontSelect = new ThreadLocal();

  static public ThreadLocal<Integer> addInternalFrame_layer = new ThreadLocal();

  static public ThreadLocal<Boolean> addInternalFrame_toBack = new ThreadLocal();

  static public JInternalFrame addInternalFrame(final JDesktopPane desktop, final String title, final int x, final int y, final int w, final int h) {
    return addInternalFrame(desktop, title, x, y, w, h, null);
  }

  static public JInternalFrame addInternalFrame(final JDesktopPane desktop, final String title, final int x, final int y, final int w, final int h, final Component contents) {
    return addInternalFrame(desktop, title, rect(x, y, w, h), contents);
  }

  static public JInternalFrame addInternalFrame(final JDesktopPane desktop, final String title, final Component contents) {
    return addInternalFrame(desktop, title, null, contents);
  }

  static public JInternalFrame addInternalFrame(final JDesktopPane desktop, final String title, final Rect r, final Component contents) {
    final boolean dontSelect = isTrue(optParam(addInternalFrame_dontSelect));
    final boolean toBack = isTrue(optParam(addInternalFrame_toBack));
    final Integer layer = optParam(addInternalFrame_layer);
    return swing(new F0<JInternalFrame>() {

      public JInternalFrame get() {
        try {
          JInternalFrame frame;
          if (contents instanceof JInternalFrame)
            frame = (JInternalFrame) contents;
          else {
            frame = jInternalFrame(title);
            setInternalFrameContents(frame, contents);
          }
          frame.setVisible(true);
          desktop.add(frame, layer);
          if (r != null)
            setBounds(frame, r);
          else
            internalFrameDefaultPosition(frame);
          if (dontSelect)
            if (toBack)
              frame.toBack();
            else
              frame.toFront();
          else
            frame.setSelected(true);
          return fixInternalFrame(frame);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "JInternalFrame frame;\r\n    if (contents instanceof JInternalFrame)\r\n      fra...";
      }
    });
  }

  static public JInternalFrame addInternalFrame(JDesktopPane desktop, String title) {
    return addInternalFrame(desktop, title, jpanel());
  }

  static public JInternalFrame minInternalFrameWidth(final JInternalFrame frame, final int w) {
    {
      swing(() -> {
        if (frame != null && frame.getWidth() < w)
          frame.setSize(w, frame.getHeight());
      });
    }
    return frame;
  }

  static public JInternalFrame minInternalFrameWidth(int w, JInternalFrame frame) {
    return minInternalFrameWidth(frame, w);
  }

  static public <A extends Component> A packInternalFrameVertically(A c) {
    return packInternalFrameVertically(-1, c);
  }

  static public <A extends Component> A packInternalFrameVertically(int width, A c) {
    final JInternalFrame win = getInternalFrame(c);
    if (win == null)
      return c;
    final int w = width < 0 ? win.getWidth() : width;
    {
      swing(() -> {
        win.pack();
        win.setSize(w, win.getHeight());
        fixInternalFrame(win);
      });
    }
    return c;
  }

  static public JInternalFrame centerInternalFrame(final JInternalFrame f) {
    {
      swing(() -> {
        Container c = f.getParent();
        if (c != null) {
          f.setLocation((c.getWidth() - f.getWidth()) / 2, (c.getHeight() - f.getHeight()) / 2);
        }
      });
    }
    return f;
  }

  static public JInternalFrame centerInternalFrame(final int w, final int h, final JInternalFrame f) {
    {
      swing(() -> {
        f.setSize(w, h);
      });
    }
    return centerInternalFrame(f);
  }

  static public void consoleSetInput(final String text) {
    if (headless())
      return;
    setTextAndSelectAll(consoleInputField(), text);
    focusConsole();
  }

  static public List<String> dropPunctuation_keep = ll("*", "<", ">");

  static public List<String> dropPunctuation(List<String> tok) {
    tok = new ArrayList<String>(tok);
    for (int i = 1; i < tok.size(); i += 2) {
      String t = tok.get(i);
      if (t.length() == 1 && !Character.isLetter(t.charAt(0)) && !Character.isDigit(t.charAt(0)) && !dropPunctuation_keep.contains(t)) {
        tok.set(i - 1, tok.get(i - 1) + tok.get(i + 1));
        tok.remove(i);
        tok.remove(i);
        i -= 2;
      }
    }
    return tok;
  }

  static public String dropPunctuation(String s) {
    return join(dropPunctuation(nlTok(s)));
  }

  static public List<String> javaTokPlusPeriod(String s) {
    List<String> tok = new ArrayList<String>();
    if (s == null)
      return tok;
    int l = s.length();
    int i = 0;
    while (i < l) {
      int j = i;
      char c;
      String cc;
      while (j < l) {
        c = s.charAt(j);
        cc = s.substring(j, Math.min(j + 2, l));
        if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
          ++j;
        else if (cc.equals("/*")) {
          do ++j; while (j < l && !s.substring(j, Math.min(j + 2, l)).equals("*/"));
          j = Math.min(j + 2, l);
        } else if (cc.equals("//")) {
          do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0);
        } else
          break;
      }
      tok.add(s.substring(i, j));
      i = j;
      if (i >= l)
        break;
      c = s.charAt(i);
      cc = s.substring(i, Math.min(i + 2, l));
      if (c == (char) 0x201C || c == (char) 0x201D)
        c = '"';
      if (c == '\'' || c == '"') {
        char opener = c;
        ++j;
        while (j < l) {
          char _c = s.charAt(j);
          if (_c == (char) 0x201C || _c == (char) 0x201D)
            _c = '"';
          if (_c == opener) {
            ++j;
            break;
          } else if (s.charAt(j) == '\\' && j + 1 < l)
            j += 2;
          else
            ++j;
        }
        if (j - 1 >= i + 1) {
          tok.add(opener + s.substring(i + 1, j - 1) + opener);
          i = j;
          continue;
        }
      } else if (Character.isJavaIdentifierStart(c))
        do ++j; while (j < l && (Character.isJavaIdentifierPart(s.charAt(j)) || s.charAt(j) == '\''));
      else if (Character.isDigit(c))
        do ++j; while (j < l && Character.isDigit(s.charAt(j)));
      else if (cc.equals("[[")) {
        do ++j; while (j + 1 < l && !s.substring(j, j + 2).equals("]]"));
        j = Math.min(j + 2, l);
      } else if (cc.equals("[=") && i + 2 < l && s.charAt(i + 2) == '[') {
        do ++j; while (j + 2 < l && !s.substring(j, j + 3).equals("]=]"));
        j = Math.min(j + 3, l);
      } else if (s.substring(j, Math.min(j + 3, l)).equals("..."))
        j += 3;
      else if (c == '$' || c == '#')
        do ++j; while (j < l && Character.isDigit(s.charAt(j)));
      else
        ++j;
      tok.add(s.substring(i, j));
      i = j;
    }
    if ((tok.size() % 2) == 0)
      tok.add("");
    return tok;
  }

  static public <A> A liftLast(List<A> l) {
    if (empty(l))
      return null;
    int i = l(l) - 1;
    A a = l.get(i);
    l.remove(i);
    return a;
  }

  static public <A> List<A> liftLast(int n, List<A> l) {
    int i = l(l) - n;
    List<A> part = cloneSubList(l, i);
    removeSubList(l, i);
    return part;
  }

  static public boolean charactersEqualIC(char c1, char c2) {
    if (c1 == c2)
      return true;
    char u1 = Character.toUpperCase(c1);
    char u2 = Character.toUpperCase(c2);
    if (u1 == u2)
      return true;
    return Character.toLowerCase(u1) == Character.toLowerCase(u2);
  }

  static public String xltrim(String s) {
    int i = 0, n = l(s);
    while (i < n && contains(" \t\r\n", s.charAt(i))) ++i;
    return substr(s, i);
  }

  static public String takeCharsWhile(String s, Object pred) {
    int i = 0;
    while (i < l(s) && isTrue(callF(pred, s.charAt(i)))) ++i;
    return substring(s, 0, i);
  }

  static public String takeCharsWhile(IF1<Character, Boolean> f, String s) {
    return takeCharsWhile(s, f);
  }

  static public boolean jInternalFrame_iconifiable = true;

  static public JInternalFrame jInternalFrame() {
    return jInternalFrame("");
  }

  static public JInternalFrame jInternalFrame(final String title) {
    return swing(new F0<JInternalFrame>() {

      public JInternalFrame get() {
        try {
          JInternalFrame f = new JInternalFrame(title, true, true, true, jInternalFrame_iconifiable);
          f.setVisible(true);
          return f;
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "JInternalFrame f = new JInternalFrame(title, true, true, true, jInternalFrame...";
      }
    });
  }

  static public void setInternalFrameContents(final Component c, final Object contents) {
    {
      swing(() -> {
        JInternalFrame frame = getInternalFrame(c);
        if (frame == null)
          return;
        frame.getContentPane().removeAll();
        frame.getContentPane().setLayout(new BorderLayout());
        if (contents != null)
          frame.getContentPane().add(wrap(contents));
        revalidate(frame);
      });
    }
  }

  static public void internalFrameDefaultPosition(JInternalFrame f) {
    f.setSize(500, 300);
    centerInternalFrame(f);
  }

  static public int fixInternalFrame_borderTopLeft = 0;

  static public int fixInternalFrame_borderBottomRight = 40;

  static public JInternalFrame fixInternalFrame(final JInternalFrame f) {
    return swing(new F0<JInternalFrame>() {

      public JInternalFrame get() {
        try {
          Container c = f.getParent();
          if (c == null)
            return f;
          Rect r = toRect(f.getBounds());
          int a = fixInternalFrame_borderTopLeft, b = fixInternalFrame_borderBottomRight;
          Rect outer = new Rect(a, a, c.getWidth() - b, c.getHeight() - b);
          if (!rectContains(outer, r))
            f.setLocation(max(a, min(r.x, outer.x2())), max(a, min(r.y, outer.y2())));
          if (r.w > c.getWidth() || r.h > c.getHeight())
            f.setSize(c.getWidth() - a, c.getHeight() - a);
          return f;
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "Container c = f.getParent();\r\n    if (c == null) ret f;\r\n    Rect r = toRect(...";
      }
    });
  }

  static public JTextField setTextAndSelectAll(final JTextField tf, final String text) {
    if (tf != null) {
      swing(() -> {
        tf.setText(text);
        tf.selectAll();
      });
    }
    return tf;
  }

  static public JTextField consoleInputField() {
    Object console = get(getJavaX(), "console");
    return (JTextField) getOpt(console, "tfInput");
  }

  static public void focusConsole(String s) {
    setConsoleInput(s);
    focusConsole();
  }

  static public void focusConsole() {
    JComponent tf = consoleInputFieldOrComboBox();
    if (tf != null) {
      tf.requestFocus();
    }
  }

  static public List<String> nlTok(String s) {
    return javaTokPlusPeriod(s);
  }

  static public <A> List<A> cloneSubList(List<A> l, int startIndex, int endIndex) {
    return newSubList(l, startIndex, endIndex);
  }

  static public <A> List<A> cloneSubList(List<A> l, int startIndex) {
    return newSubList(l, startIndex);
  }

  static public void removeSubList(List l, int from, int to) {
    if (l != null)
      subList(l, from, to).clear();
  }

  static public void removeSubList(List l, int from) {
    if (l != null)
      subList(l, from).clear();
  }

  static public String substr(String s, int x) {
    return substring(s, x);
  }

  static public String substr(String s, int x, int y) {
    return substring(s, x, y);
  }

  static public boolean rectContains(int x1, int y1, int w, int h, Pt p) {
    return p.x >= x1 && p.y >= y1 && p.x < x1 + w && p.y < y1 + h;
  }

  static public boolean rectContains(Rect a, Rect b) {
    return b.x >= a.x && b.y >= a.y && b.x2() <= a.x2() && b.y2() <= a.y2();
  }

  static public boolean rectContains(Rect a, int x, int y) {
    return a != null && a.contains(x, y);
  }

  static public void setConsoleInput(String text) {
    consoleSetInput(text);
  }

  static public JComponent consoleInputFieldOrComboBox() {
    Object console = get(getJavaX(), "console");
    JComboBox cb = (JComboBox) (getOpt(console, "cbInput"));
    if (cb != null)
      return cb;
    return (JTextField) getOpt(console, "tfInput");
  }

  static public <A> List<A> newSubList(List<A> l, int startIndex, int endIndex) {
    return cloneList(subList(l, startIndex, endIndex));
  }

  static public <A> List<A> newSubList(List<A> l, int startIndex) {
    return cloneList(subList(l, startIndex));
  }

  static public class RasterBars extends Animation {

    public List<Pair<IntRange, Integer>> streaks;

    public RasterBars() {
    }

    public RasterBars(int w, int h, List<Pair<IntRange, Integer>> streaks) {
      this.streaks = streaks;
      this.h = h;
      this.w = w;
    }

    public void paint() {
      for (var streak : streaks) fillRect(g, 0, streak.a.start, w, l(streak.a), grayToColor(streak.b));
    }
  }

  static public class AutoComboBox extends JComboBox<Object> {

    public String[] keyWord = { "item1", "item2", "item3" };

    public Vector myVector = new Vector();

    public boolean acceptOnTab = false;

    public AutoComboBox() {
      setModel(new DefaultComboBoxModel(myVector));
      setSelectedIndex(-1);
      setEditable(true);
      JTextField text = (JTextField) this.getEditor().getEditorComponent();
      text.setFocusable(true);
      text.setText("");
      text.addKeyListener(new ComboListener(this, myVector));
      if (acceptOnTab)
        text.setFocusTraversalKeysEnabled(false);
      setMyVector();
    }

    public void setKeyWord(String[] keyWord) {
      this.keyWord = keyWord;
      setMyVector();
    }

    public void setKeyWord(Collection<String> keyWord) {
      setKeyWord(toStringArray(keyWord));
    }

    final public void setMyVector() {
      copyArrayToVector(keyWord, myVector);
    }

    public class ComboListener extends KeyAdapter {

      public JComboBox cb;

      public Vector vector;

      public ComboListener(JComboBox cb, Vector vector) {
        this.vector = vector;
        this.cb = cb;
      }

      public void keyPressed(KeyEvent key) {
        if (key.getKeyCode() == KeyEvent.VK_ENTER)
          return;
        if (key.getKeyCode() == KeyEvent.VK_ESCAPE) {
          cb.hidePopup();
          return;
        }
        if (acceptOnTab && key.getKeyCode() == KeyEvent.VK_TAB) {
          _print("Have tab event (modifiers=" + key.getModifiers() + ")");
          if ((key.getModifiers() & ActionEvent.SHIFT_MASK) == 0 && cb.isPopupVisible()) {
            cb.setSelectedIndex(0);
            cb.hidePopup();
          } else
            swing_standardTabBehavior(key);
          return;
        }
        JTextField tf = (JTextField) (cb.getEditor().getEditorComponent());
        if (tf.getCaretPosition() != l(tf.getText()))
          return;
        String text = ((JTextField) key.getSource()).getText();
        Vector list = getFilteredList(text);
        if (nempty(list)) {
          cb.setModel(new DefaultComboBoxModel(list));
          cb.setSelectedIndex(-1);
          tf.setText(text);
          cb.showPopup();
        } else
          cb.hidePopup();
      }

      public Vector getFilteredList(String text) {
        return new Vector(scoredSearch(text, vector));
      }
    }
  }

  static public class PNGFile extends Concept {

    public String pngPath;

    public Rect r;

    public PNGFile() {
    }

    public PNGFile(String pngPath) {
      this.pngPath = pngPath;
    }

    public PNGFile(RGBImage img) {
      this(img.getBufferedImage());
    }

    public File pngFile() {
      if (pngPath == null) {
        pngPath = _programID() + "/" + id + ".png";
        change();
      }
      return prepareFile(new File(javaxDataDir(), pngPath));
    }

    public PNGFile(BufferedImage img) {
      savePNG(pngFile(), img);
    }

    public BufferedImage loadImage() {
      return loadImage2(pngFile());
    }

    public BufferedImage getImage() {
      return loadImage();
    }

    public BufferedImage getImageSafe() {
      try {
        return loadImage();
      } catch (Throwable __e) {
        printStackTrace(__e);
      }
      return null;
    }

    public String md5() {
      try {
        return md5OfBufferedImage(getImage());
      } catch (Throwable __e) {
        printStackTrace(__e);
      }
      return "-";
    }

    public boolean hasImage() {
      return pngFile().exists();
    }
  }

  static abstract public class DialogIO implements AutoCloseable {

    public String line;

    public boolean eos, loud, noClose;

    public Lock lock = lock();

    abstract public String readLineImpl();

    abstract public boolean isStillConnected();

    abstract public void sendLine(String line);

    abstract public boolean isLocalConnection();

    abstract public Socket getSocket();

    public int getPort() {
      Socket s = getSocket();
      return s == null ? 0 : s.getPort();
    }

    public boolean helloRead = false;

    public int shortenOutputTo = 500;

    public String readLineNoBlock() {
      String l = line;
      line = null;
      return l;
    }

    public boolean waitForLine() {
      try {
        ping();
        if (line != null)
          return true;
        line = readLineImpl();
        if (line == null)
          eos = true;
        return line != null;
      } catch (Exception __e) {
        throw rethrow(__e);
      }
    }

    public String readLine() {
      waitForLine();
      helloRead = true;
      return readLineNoBlock();
    }

    public String ask(String s, Object... args) {
      if (loud)
        return askLoudly(s, args);
      if (!helloRead)
        readLine();
      if (args.length != 0)
        s = format3(s, args);
      sendLine(s);
      return readLine();
    }

    public String askLoudly(String s, Object... args) {
      if (!helloRead)
        readLine();
      if (args.length != 0)
        s = format3(s, args);
      print("> " + shorten(s, shortenOutputTo));
      sendLine(s);
      String answer = readLine();
      print("< " + shorten(answer, shortenOutputTo));
      return answer;
    }

    public void pushback(String l) {
      if (line != null)
        throw fail();
      line = l;
      helloRead = false;
    }
  }

  static abstract public class DialogHandler {

    abstract public void run(DialogIO io);
  }

  static public class ImageChooser extends SingleComponentPanel {

    public ImageSurface is = new ImageSurface();

    public JTextField tfPath = new JTextField();

    public ImageChooser(BufferedImage img) {
      this();
      setImage(img);
    }

    public ImageChooser(RGBImage img) {
      this(img.getBufferedImage());
    }

    public ImageChooser(PNGFile png) {
      this(png == null ? null : png.getImage());
    }

    public ImageChooser() {
      bindToComponent(this, new Runnable() {

        public void run() {
          try {
            is.zoomToWindow();
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "is.zoomToWindow()";
        }
      });
      is.loadFromClipboard();
      setComponent(jMinSize(100, 100, jscroll(is)));
      componentPopupMenu(is, new VF1<JPopupMenu>() {

        public void get(JPopupMenu menu) {
          try {
            addMenuItem(menu, "Screenshot in 3", new Runnable() {

              public void run() {
                try {
                  startThread("Screenshot in 3", new Runnable() {

                    public void run() {
                      try {
                        sleep(3000);
                        final BufferedImage img = shootScreen2();
                        swingLater(new Runnable() {

                          public void run() {
                            try {
                              is.setImage(img);
                              infoMessage("Screenshot taken (" + img.getWidth() + "*" + img.getHeight() + " px)", 2);
                            } catch (Exception __e) {
                              throw rethrow(__e);
                            }
                          }

                          public String toString() {
                            return "is.setImage(img);\r\n            infoMessage(\"Screenshot taken (\" + img.getWidt...";
                          }
                        });
                      } catch (Exception __e) {
                        throw rethrow(__e);
                      }
                    }

                    public String toString() {
                      return "sleep(3000);\r\n          final BufferedImage img = shootScreen2();\r\n          ...";
                    }
                  });
                } catch (Exception __e) {
                  throw rethrow(__e);
                }
              }

              public String toString() {
                return "thread \"Screenshot in 3\" {\r\n          sleep(3000);\r\n          final BufferedI...";
              }
            });
            addMenuItem(menu, "Load snippet or file...", new Runnable() {

              public void run() {
                try {
                  final JTextField tf = new JTextField();
                  showFormTitled("Load image from snippet or file", "Path or snippet ID", tf, new Runnable() {

                    public void run() {
                      try {
                        is.setImage(loadImage2(tf.getText().trim()));
                        is.zoomToDisplaySize();
                      } catch (Exception __e) {
                        throw rethrow(__e);
                      }
                    }

                    public String toString() {
                      return "is.setImage(loadImage2(tf.getText().trim()));\r\n            is.zoomToDisplaySi...";
                    }
                  });
                } catch (Exception __e) {
                  throw rethrow(__e);
                }
              }

              public String toString() {
                return "final new JTextField tf;\r\n        showFormTitled(\"Load image from snippet or ...";
              }
            });
          } catch (Exception __e) {
            throw rethrow(__e);
          }
        }

        public String toString() {
          return "addMenuItem(menu, \"Screenshot in 3\", r {\r\n        thread \"Screenshot in 3\" {\r...";
        }
      });
    }

    public boolean hasImage() {
      return is.getImage() != null && is.getImage().getWidth() * is.getImage().getHeight() > 1;
    }

    public BWImage getBWImage() {
      return is.getImage() == null ? null : new BWImage(is.getImage());
    }

    public BufferedImage getImage() {
      return hasImage() ? is.getImage() : null;
    }

    public void setImage(BufferedImage img) {
      is.setImage(img);
      is.zoomToWindow();
    }

    public PNGFile createPNGFile() {
      return hasImage() ? new PNGFile(getImage()) : null;
    }

    public void setTitleForUpload(String title) {
      is.titleForUpload = title;
    }
  }

  static public class Value<A> implements IF0<A>, IFieldsToList {

    public A value;

    public Value() {
    }

    public Value(A value) {
      this.value = value;
    }

    public boolean equals(Object o) {
      if (!(o instanceof Value))
        return false;
      Value __1 = (Value) o;
      return eq(value, __1.value);
    }

    public int hashCode() {
      int h = 82420049;
      h = boostHashCombine(h, _hashCode(value));
      return h;
    }

    public Object[] _fieldsToList() {
      return new Object[] { value };
    }

    public A get() {
      return value;
    }

    public String toString() {
      return str(get());
    }
  }

  abstract static public class AbstractLayoutManager implements LayoutManager {

    public Dimension preferredSize = new Dimension(100, 100);

    public Dimension minimumSize = new Dimension(10, 10);

    public void addLayoutComponent(String name, Component comp) {
    }

    public void removeLayoutComponent(Component comp) {
    }

    public Dimension preferredLayoutSize(Container parent) {
      layoutContainer(parent);
      return preferredSize;
    }

    public Dimension minimumLayoutSize(Container parent) {
      return minimumSize;
    }
  }

  static public interface IF2_IntInt_Double {

    public double get(int a, int b);
  }

  static public class IntVar {

    public int a;

    public synchronized void set(int v) {
      if (v != a) {
        a = v;
        notifyAll();
      }
    }

    public synchronized int get() {
      return a;
    }

    synchronized public int waitForValue(int x) {
      try {
        while (a != x) wait();
        return a;
      } catch (Exception __e) {
        throw rethrow(__e);
      }
    }
  }

  static public class ScanlineBitMatrix extends AbstractMatrix<Boolean> implements Matrix<Boolean> {

    public ScanlineBitMatrix() {
    }

    public int bx1 = Integer.MAX_VALUE, by1, bx2, by2;

    public int[] scanlineData;

    public int[] scanlineStarts;

    public ScanlineBitMatrix(Matrix<Boolean> m) {
      super(m.getWidth(), m.getHeight());
      while (by1 < h && bitMatrixRowEmpty(m, by1)) by1++;
      by2 = h;
      while (by2 > by1 && bitMatrixRowEmpty(m, by2 - 1)) by2--;
      int ptr = 0;
      scanlineStarts = new int[by2 - by1];
      IntBuffer scanlineData = new IntBuffer();
      lineLoop: for (int y = by1; y < by2; y++) {
        scanlineStarts[y - by1] = l(scanlineData);
        for (int x = 0; x < w; ) {
          while (!m.get(x, y)) if (++x >= w)
            continue lineLoop;
          int x2 = x + 1;
          while (x2 < w && m.get(x2, y)) ++x2;
          scanlineData.add(x);
          scanlineData.add(x2);
          if (x < bx1)
            bx1 = x;
          if (x2 > bx2)
            bx2 = x2;
          x = x2;
        }
      }
      this.scanlineData = scanlineData.toArray();
    }

    public Boolean get(int x, int y) {
      if (x < bx1 || y < by1 || x >= bx2 || y >= by2)
        return false;
      int ptr = scanlineStarts[y - by1];
      int end = y == by2 - 1 ? scanlineData.length : scanlineStarts[y - by1 + 1];
      while (ptr < end) {
        int x1 = scanlineData[ptr++];
        if (x < x1)
          return false;
        int x2 = scanlineData[ptr++];
        if (x < x2)
          return true;
      }
      return false;
    }

    public void set(int x, int y, Boolean a) {
      unimplemented();
    }

    public Rect boundingBoxOfTrueBits() {
      return bx1 >= bx2 ? null : rect(bx1, by1, bx2, by2);
    }

    public int nRuns() {
      return scanlineData.length / 2;
    }

    public IterableIterator<Rect> runs() {
      return new IterableIterator<Rect>() {

        public int y = 0, ptr = 0;

        public boolean hasNext() {
          return ptr < l(scanlineData);
        }

        public Rect next() {
          while (y < scanlineStarts.length - 1 && ptr >= scanlineStarts[y + 1]) ++y;
          int x1 = scanlineData[ptr++];
          int x2 = scanlineData[ptr++];
          return rect(x1, by1 + y, x2 - x1, 1);
        }
      };
    }
  }

  static public GlobalID aGlobalIDObjUnlessLoading() {
    return dynamicObjectIsLoading() ? null : aGlobalIDObj();
  }

  static public Color grayToColor(double f) {
    return toColor(brightnessToRGBA(iceil(f * 256)));
  }

  static public void setSelectedIndex(final JList l, final int i) {
    if (l != null) {
      swing(() -> {
        l.setSelectedIndex(i);
      });
    }
  }

  static public void setSelectedIndex(final JComboBox cb, final int i) {
    if (cb != null) {
      swing(() -> {
        cb.setSelectedIndex(i);
      });
    }
  }

  static public void copyArrayToVector(Object[] array, Vector v) {
    v.clear();
    v.addAll(toList(array));
  }

  static public <A> A _print(String s, A a) {
    return print(s, a);
  }

  static public <A> A _print(A a) {
    return print(a);
  }

  static public void _print() {
    print();
  }

  static public void swing_standardTabBehavior(KeyEvent key) {
    if ((key.getModifiers() & ActionEvent.SHIFT_MASK) != 0)
      KeyboardFocusManager.getCurrentKeyboardFocusManager().focusPreviousComponent();
    else
      KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent();
  }

  static public List<String> scoredSearch(String query, Iterable<String> data) {
    Map<String, Integer> scores = new HashMap();
    List<String> searchTerms = scoredSearch_prepare(query);
    if (empty(searchTerms))
      return asList(data);
    for (String s : data) {
      int score = scoredSearch_score(s, searchTerms);
      if (score != 0)
        scores.put(s, score);
    }
    return keysSortedByValuesDesc(scores);
  }

  static public File prepareFile(File file) {
    return mkdirsForFile(file);
  }

  static public File prepareFile(File dir, String name) {
    return mkdirsForFile(newFile(dir, name));
  }

  static public RGBImage loadImage(String snippetIDOrURL) {
    return new RGBImage(loadBufferedImage(snippetIDOrURL));
  }

  static public RGBImage loadImage(File f) {
    return new RGBImage(loadBufferedImage(f));
  }

  static public String md5OfBufferedImage(BufferedImage img) {
    return img == null ? null : rgbMD5(new RGBImage(img));
  }

  static public <A extends Component> A jMinSize(int w, int h, A c) {
    return jMinWidth(w, jMinHeight(h, c));
  }

  static public <A extends Component> A jMinSize(A c, Dimension d) {
    return jMinSize(d.width, d.height, c);
  }

  static public boolean bitMatrixRowEmpty(Matrix<Boolean> m, int y) {
    int w = m.getWidth();
    for (int x = 0; x < w; x++) if (m.get(x, y))
      return false;
    return true;
  }

  static public RuntimeException unimplemented() {
    throw fail("TODO");
  }

  static public RuntimeException unimplemented(String msg) {
    throw fail("TODO: " + msg);
  }

  static public RuntimeException unimplemented(Object obj) {
    throw fail("TODO: implement method in " + className(obj));
  }

  static public GlobalID aGlobalIDObj() {
    return asGlobalID(randomID(16));
  }

  static public GlobalID aGlobalIDObj(Random random) {
    return asGlobalID(randomID(random, 16));
  }

  static public Color toColor(RGB rgb) {
    return rgb == null ? null : rgb.getColor();
  }

  static public Color toColor(int rgb) {
    return new Color(rgb);
  }

  static public Color toColor(String hex) {
    return awtColor(hex);
  }

  static public Color toColor(int[] rgb) {
    return new Color(rgb[0], rgb[1], rgb[2]);
  }

  static public int iceil(double d) {
    return (int) Math.ceil(d);
  }

  static public List<String> scoredSearch_prepare(String query) {
    return map(__64 -> replacePlusWithSpace(__64), splitAtSpace(query));
  }

  static public int scoredSearch_score(Iterable<String> l, List<String> words) {
    int score = 0;
    if (l != null)
      for (String s : l) score += scoredSearch_score(s, words);
    return score;
  }

  static public int scoredSearch_score(String s, List<String> words) {
    int score = 0;
    if (nempty(s))
      for (String word : unnullForIteration(words)) score += scoredSearch_score_single(s, word);
    return score;
  }

  static public int scoredSearch_score(String s, String query) {
    return scoredSearch_score(s, scoredSearch_prepare(query));
  }

  static public <A, B> List<A> keysSortedByValuesDesc(final Map<A, B> map) {
    List<A> l = new ArrayList(map.keySet());
    sort(l, mapComparatorDesc(map));
    return l;
  }

  static public String rgbMD5(RGBImage img) {
    return md5OfRGBImage(img);
  }

  static public <A extends Component> A jMinWidth(final int w, final A c) {
    if (c == null)
      return null;
    return swing(new F0<A>() {

      public A get() {
        try {
          Dimension size = c.getMinimumSize();
          c.setMinimumSize(new Dimension(w, size.height));
          return jPreferWidth(w, c);
        } catch (Exception __e) {
          throw rethrow(__e);
        }
      }

      public String toString() {
        return "Dimension size = c.getMinimumSize();\r\n    c.setMinimumSize(new Dimension(/*ma...";
      }
    });
  }

  static public <A extends Component> A jMinHeight(A c, int h) {
    return jMinHeight(h, c);
  }

  static public <A extends Component> A jMinHeight(int h, A c) {
    Dimension size = c.getMinimumSize();
    c.setMinimumSize(new Dimension(size.width, max(h, size.height)));
    return jPreferHeight(h, c);
  }

  static public GlobalID asGlobalID(String id) {
    return id == null ? null : new GlobalID(id);
  }

  static public String replacePlusWithSpace(String s) {
    return replace(s, '+', ' ');
  }

  static public int scoredSearch_score_single(String s, String query) {
    int i = indexOfIC_underscore(s, query);
    if (i < 0)
      return 0;
    if (i > 0)
      return 1;
    return l(s) == l(query) ? 3 : 2;
  }

  static public <A, B> Comparator<A> mapComparatorDesc(final Map<A, B> map) {
    return new Comparator<A>() {

      public int compare(A a, A b) {
        return cmp(map.get(b), map.get(a));
      }
    };
  }

  static public String md5OfRGBImage(RGBImage img) {
    try {
      MessageDigest m = MessageDigest.getInstance("MD5");
      m.update(intToBytes(img.getWidth()));
      int[] pixels = img.getPixels();
      for (int i = 0; i < l(pixels); i++) m.update(intToBytes(pixels[i]));
      return bytesToHex(m.digest());
    } catch (Exception __e) {
      throw rethrow(__e);
    }
  }

  static public <A extends Component> A jPreferHeight(int h, A c) {
    Dimension size = c.getPreferredSize();
    c.setPreferredSize(new Dimension(size.width, max(h, size.height)));
    return c;
  }

  static public int indexOfIC_underscore(String a, String b) {
    int la = l(a), lb = l(b);
    if (la < lb)
      return -1;
    int n = la - lb;
    elsewhere: for (int i = 0; i <= n; i++) {
      for (int j = 0; j < lb; j++) {
        char c2 = b.charAt(j);
        if (c2 == '_' || eqic(c2, a.charAt(i + j))) {
        } else
          continue elsewhere;
      }
      return i;
    }
    return -1;
  }

  static public byte[] intToBytes(int i) {
    return new byte[] { (byte) (i >>> 24), (byte) (i >>> 16), (byte) (i >>> 8), (byte) i };
  }
}


Author comment

Began life as a copy of #1033525

download  show line numbers  debug dex  old transpilations   

Travelled to 3 computer(s): bhatertpkbcr, mowyntqkapby, mqqgnosmbjvj

No comments. add comment

Snippet ID: #1033636
Snippet name: Gazelle 22 Standalone [stable version]
Eternal ID of this version: #1033636/25
Text MD5: 8cf2c941a2580188dd4fe0eed22ecefe
Transpilation MD5: 4c6fa38870f514b15736bd85f2cbcc56
Author: stefan
Category: javax / screen recognition
Type: JavaX source code (desktop)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-01-09 16:30:36
Source code size: 604779 bytes / 20985 lines
Pitched / IR pitched: No / No
Views / Downloads: 805 / 3370
Version history: 24 change(s)
Referenced in: [show references]