@SuppressWarnings("UseOfSystemOutOrSystemErr")
  protected static void start(Remote remote, boolean localHostOnly, boolean spinForever) throws Exception {
    IdeaWatchdog watchdog = new IdeaWatchdogImpl();
    if (remote instanceof IdeaWatchdogAware) {
      ((IdeaWatchdogAware)remote).setWatchdog(watchdog);
    }

    setupRMI(localHostOnly);
    banJNDI();
    setupSSL();

    if (ourRemote != null) throw new AssertionError("Already started");
    ourRemote = remote;

    Registry registry;
    int port;
    for (Random random = new Random(); ; ) {
      port = random.nextInt(0xffff);
      if (port < 4000) continue;
      try {
        if (localHostOnly) {
          registry = LocateRegistry.createRegistry(port);
        }
        else {
          registry = LocateRegistry.createRegistry(port, null, RMISocketFactory.getSocketFactory());
        }


        break;
      }
      catch (ExportException ignored) {
      }
    }

    try {
      Remote stub = UnicastRemoteObject.exportObject(ourRemote, 0);
      String name = remote.getClass().getSimpleName() + Integer.toHexString(stub.hashCode());
      registry.bind(name, stub);

      // the first used port will be reused for all further exported objects,
      // unless they're exported with explicit port other than 0, or with custom socket factories
      Matcher matcher = REF_ENDPOINT_PATTERN.matcher(stub.toString());
      String servicesPort = matcher.find() ? matcher.group(1) : "0";

      Remote watchdogStub = UnicastRemoteObject.exportObject(watchdog, 0);
      registry.bind(IdeaWatchdog.BINDING_NAME, watchdogStub);

      System.out.println("Port/ServicesPort/ID: " + (port + "/" + servicesPort + "/" + name));
      System.out.println();

      if (!spinForever) {
        spinWhileWatchdogAlive(watchdog);
      }
    }
    catch (Throwable e) {
      e.printStackTrace(System.err);
      System.exit(1);
    }
  }
@SuppressWarnings("UseOfSystemOutOrSystemErr")
  protected static void start(Remote remote, boolean localHostOnly, boolean spinForever)