<commit_before>package org.multibit.hd.ui;

import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.Uninterruptibles;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.multibit.commons.concurrent.SafeExecutors;
import org.multibit.hd.core.config.Configurations;
import org.multibit.hd.core.dto.WalletSummary;
import org.multibit.hd.core.events.CoreEvents;
import org.multibit.hd.core.events.ShutdownEvent;
import org.multibit.hd.core.logging.LoggingFactory;
import org.multibit.hd.core.managers.HttpsManager;
import org.multibit.hd.core.managers.InstallationManager;
import org.multibit.hd.core.managers.WalletManager;
import org.multibit.hd.core.services.CoreServices;
import org.multibit.hd.core.utils.OSUtils;
import org.multibit.hd.hardware.core.HardwareWalletService;
import org.multibit.hd.ui.audio.Sounds;
import org.multibit.hd.ui.controllers.HeaderController;
import org.multibit.hd.ui.controllers.MainController;
import org.multibit.hd.ui.events.controller.ControllerEvents;
import org.multibit.hd.ui.events.view.ViewEvents;
import org.multibit.hd.ui.platform.GenericApplicationFactory;
import org.multibit.hd.ui.platform.GenericApplicationSpecification;
import org.multibit.hd.ui.services.ExternalDataListeningService;
import org.multibit.hd.ui.views.MainView;
import org.multibit.hd.ui.views.SplashScreen;
import org.multibit.hd.ui.views.themes.ThemeKey;
import org.multibit.hd.ui.views.themes.Themes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import javax.swing.plaf.nimbus.NimbusLookAndFeel;
import javax.swing.text.DefaultEditorKit;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.io.File;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>Main entry point to the application</p>
 */
public class MultiBitHD {

  //////////////////////////// NO STATIC VARIABLES ALLOWED IN THIS CLASS! ////////////////////////

  // See initialiseSystemProperties for explanation

  // Special case logger that is not static
  private final Logger log = LoggerFactory.getLogger(MultiBitHD.class);
  private MainController mainController;
  private SplashScreen splashScreen;

  ////////////////////////////////////////////////////////////////////////////////////////////////

  /**
   * <p>Main entry point to the application</p>
   *
   * @param args None specified
   */
  public static void main(String[] args) throws Exception {

    // These are called at the first line to avoid any other class loading
    // interfering with them
    initialiseSystemProperties();

    // Hand over to an instance to simplify FEST tests
    final MultiBitHD multiBitHD = new MultiBitHD();
    if (!multiBitHD.start(args)) {
      // Failed to start so issue a hard shutdown
      CoreServices.shutdownNow(ShutdownEvent.ShutdownType.HARD);
    } else {
      // Initialise the UI views in the EDT, Nimbus etc
      SwingUtilities.invokeLater(
        new Runnable() {
          @Override
          public void run() {
            multiBitHD.initialiseUIViews();
          }
        });
    }
  }

  /**
   * Initialise any system properties that need to be in place before any other
   * classes are loaded
   */
  private static void initialiseSystemProperties() {

    // Fix for "TimSort" clipboard failure - https://github.com/bitcoin-solutions/multibit-hd/issues/645
    // Suggested by https://www.java.net/node/700601
    // See also http://stackoverflow.com/a/26829874/396747 for more details on ordering at startup
    // Verified that java.util.Arrays has not been loaded at this stage
    System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");

    // Fix for Windows / Java 7 / VPN bug
    System.setProperty("java.net.preferIPv4Stack", "true");

    // Fix for version.txt not visible for Java 7
    System.setProperty("jsse.enableSNIExtension", "false");

  }

  /**
   * <p>Start this instance of MultiBit HD</p>
   *
   * @param args The command line arguments
   *
   * @return True if the application started successfully, false if a shutdown is required
   *
   * @throws Exception If something goes wrong
   */
  public boolean start(String[] args) throws Exception {

    // Start the logging factory (see later for instance) to get console logging up fast
    LoggingFactory.bootstrap();

    // Get the configuration fast (Bitcoin URI processing relies on it)
    CoreServices.bootstrap();

    // Analyse the command line
    if (args != null && args.length > 0) {
      // Show the command line arguments
      for (int i = 0; i < args.length; i++) {
        log.info("MultiBit launched with args[{}]: '{}'", i, args[i]);
      }
    } else {
      // Provide empty arguments to avoid potential NPEs
      log.info("No command line arguments");
      args = new String[]{};
    }

    // Check for another instance as soon as possible
    Optional<ExternalDataListeningService> externalDataListeningService = initialiseListeningService(args);
    if (!externalDataListeningService.isPresent()) {
      return false;
    }

    log.info("This is the primary instance so showing splash screen.");
    // Provide an AWT splash screen to ensure faster initial rendering
    splashScreen = new SplashScreen();
    // Provide a short thread sleep to allow the AWT time to take over
    // and fill the Frame with the splash screen image
    try {
      Thread.sleep(100);
    } catch (InterruptedException e) {
      // Do nothing
    }

    // Prepare the CA certs (run on a separate thread)
    initialiseCaCerts();

    // Start core services (logging, environment alerts, configuration, Bitcoin URI handling etc)
    initialiseCore(args);

    // Create controllers so that the generic app can access listeners
    if (!initialiseUIControllers()) {

      // Required to shut down
      return false;

    }

    // Must be OK to be here
    return true;
  }

  public void stop() {
    log.debug("Stopping MultiBit HD");

    mainController = null;

    // final purge in case anything gets missed
    ViewEvents.unsubscribeAll();
    ControllerEvents.unsubscribeAll();
    CoreEvents.unsubscribeAll();
  }

  /**
   * @param args The command line arguments
   *
   * @return The external data listening service if it could be started successfully, absent implies another instance
   */
  private Optional<ExternalDataListeningService> initialiseListeningService(String[] args) {
    // Determine if another instance is running and shutdown if this is the case
    ExternalDataListeningService externalDataListeningService = new ExternalDataListeningService(args);

    if (externalDataListeningService.start()) {
      return Optional.of(externalDataListeningService);<commit_msg>#736 Include hardware wallet events during tear down<commit_after>package org.multibit.hd.ui;

import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.Uninterruptibles;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.multibit.commons.concurrent.SafeExecutors;
import org.multibit.hd.core.config.Configurations;
import org.multibit.hd.core.dto.WalletSummary;
import org.multibit.hd.core.events.CoreEvents;
import org.multibit.hd.core.events.ShutdownEvent;
import org.multibit.hd.core.logging.LoggingFactory;
import org.multibit.hd.core.managers.HttpsManager;
import org.multibit.hd.core.managers.InstallationManager;
import org.multibit.hd.core.managers.WalletManager;
import org.multibit.hd.core.services.CoreServices;
import org.multibit.hd.core.utils.OSUtils;
import org.multibit.hd.hardware.core.HardwareWalletService;
import org.multibit.hd.hardware.core.events.HardwareWalletEvents;
import org.multibit.hd.ui.audio.Sounds;
import org.multibit.hd.ui.controllers.HeaderController;
import org.multibit.hd.ui.controllers.MainController;
import org.multibit.hd.ui.events.controller.ControllerEvents;
import org.multibit.hd.ui.events.view.ViewEvents;
import org.multibit.hd.ui.platform.GenericApplicationFactory;
import org.multibit.hd.ui.platform.GenericApplicationSpecification;
import org.multibit.hd.ui.services.ExternalDataListeningService;
import org.multibit.hd.ui.views.MainView;
import org.multibit.hd.ui.views.SplashScreen;
import org.multibit.hd.ui.views.themes.ThemeKey;
import org.multibit.hd.ui.views.themes.Themes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import javax.swing.plaf.nimbus.NimbusLookAndFeel;
import javax.swing.text.DefaultEditorKit;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.io.File;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>Main entry point to the application</p>
 */
public class MultiBitHD {

  //////////////////////////// NO STATIC VARIABLES ALLOWED IN THIS CLASS! ////////////////////////

  // See initialiseSystemProperties for explanation

  // Special case logger that is not static
  private final Logger log = LoggerFactory.getLogger(MultiBitHD.class);
  private MainController mainController;
  private SplashScreen splashScreen;

  ////////////////////////////////////////////////////////////////////////////////////////////////

  /**
   * <p>Main entry point to the application</p>
   *
   * @param args None specified
   */
  public static void main(String[] args) throws Exception {

    // These are called at the first line to avoid any other class loading
    // interfering with them
    initialiseSystemProperties();

    // Hand over to an instance to simplify FEST tests
    final MultiBitHD multiBitHD = new MultiBitHD();
    if (!multiBitHD.start(args)) {
      // Failed to start so issue a hard shutdown
      CoreServices.shutdownNow(ShutdownEvent.ShutdownType.HARD);
    } else {
      // Initialise the UI views in the EDT, Nimbus etc
      SwingUtilities.invokeLater(
        new Runnable() {
          @Override
          public void run() {
            multiBitHD.initialiseUIViews();
          }
        });
    }
  }

  /**
   * Initialise any system properties that need to be in place before any other
   * classes are loaded
   */
  private static void initialiseSystemProperties() {

    // Fix for "TimSort" clipboard failure - https://github.com/bitcoin-solutions/multibit-hd/issues/645
    // Suggested by https://www.java.net/node/700601
    // See also http://stackoverflow.com/a/26829874/396747 for more details on ordering at startup
    // Verified that java.util.Arrays has not been loaded at this stage
    System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");

    // Fix for Windows / Java 7 / VPN bug
    System.setProperty("java.net.preferIPv4Stack", "true");

    // Fix for version.txt not visible for Java 7
    System.setProperty("jsse.enableSNIExtension", "false");

  }

  /**
   * <p>Start this instance of MultiBit HD</p>
   *
   * @param args The command line arguments
   *
   * @return True if the application started successfully, false if a shutdown is required
   *
   * @throws Exception If something goes wrong
   */
  public boolean start(String[] args) throws Exception {

    // Start the logging factory (see later for instance) to get console logging up fast
    LoggingFactory.bootstrap();

    // Get the configuration fast (Bitcoin URI processing relies on it)
    CoreServices.bootstrap();

    // Analyse the command line
    if (args != null && args.length > 0) {
      // Show the command line arguments
      for (int i = 0; i < args.length; i++) {
        log.info("MultiBit launched with args[{}]: '{}'", i, args[i]);
      }
    } else {
      // Provide empty arguments to avoid potential NPEs
      log.info("No command line arguments");
      args = new String[]{};
    }

    // Check for another instance as soon as possible
    Optional<ExternalDataListeningService> externalDataListeningService = initialiseListeningService(args);
    if (!externalDataListeningService.isPresent()) {
      return false;
    }

    log.info("This is the primary instance so showing splash screen.");
    // Provide an AWT splash screen to ensure faster initial rendering
    splashScreen = new SplashScreen();
    // Provide a short thread sleep to allow the AWT time to take over
    // and fill the Frame with the splash screen image
    try {
      Thread.sleep(100);
    } catch (InterruptedException e) {
      // Do nothing
    }

    // Prepare the CA certs (run on a separate thread)
    initialiseCaCerts();

    // Start core services (logging, environment alerts, configuration, Bitcoin URI handling etc)
    initialiseCore(args);

    // Create controllers so that the generic app can access listeners
    if (!initialiseUIControllers()) {

      // Required to shut down
      return false;

    }

    // Must be OK to be here
    return true;
  }

  public void stop() {
    log.debug("Stopping MultiBit HD");

    mainController = null;

    // Final purge in case anything gets missed
    ViewEvents.unsubscribeAll();
    ControllerEvents.unsubscribeAll();
    CoreEvents.unsubscribeAll();
    HardwareWalletEvents.unsubscribeAll();
  }

  /**
   * @param args The command line arguments
   *
   * @return The external data listening service if it could be started successfully, absent implies another instance
   */
  private Optional<ExternalDataListeningService> initialiseListeningService(String[] args) {
    // Determine if another instance is running and shutdown if this is the case
    ExternalDataListeningService externalDataListeningService = new ExternalDataListeningService(args);

    if (externalDataListeningService.start()) {
      return Optional.of(externalDataListeningService);
{'fraction_non_alphanumeric': 0.1157218001168907, 'fraction_numerical': 0.005040911747516073, 'mean_word_length': 3.204238329238329, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 21, 'https://': 4, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1691082', 'n_tokens_mistral': 3959, 'n_tokens_neox': 3824, 'n_words': 1103}