<commit_before>package ui.issuepanel.expanded;

import java.awt.Rectangle;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Optional;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import javafx.concurrent.Task;

import org.apache.commons.io.IOUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.Point;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

import service.ServiceManager;
import ui.UI;
import util.GitHubURL;
import util.IOUtilities;
import util.events.IssueSelectedEvent;
import util.events.IssueSelectedEventHandler;
import util.events.LoginEvent;
import util.events.LoginEventHandler;

/**
 * An abstraction for the functions of the Selenium web driver.
 */
public class BrowserComponent {
	
	private static final boolean USE_MOBILE_USER_AGENT = true;

	private static String HIDE_ELEMENTS_SCRIPT_PATH = USE_MOBILE_USER_AGENT
			? "ui/issuepanel/expanded/mobileHideUI.js"
			: "ui/issuepanel/expanded/hideUI.js";

	// Chrome, Android 4.2.2, Samsung Galaxy S4
	private static final String MOBILE_USER_AGENT = "Mozilla/5.0 (Linux; Android 4.2.2; GT-I9505 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Mobile Safari/537.36";
	
	static {
		
		setupChromeDriverExecutable();
		
	}
	
	private final UI ui;
	private ChromeDriver driver = null;
	
	// We want browser commands to be run on a separate thread, but not to
	// interfere with each other. This executor is limited to a single instance,
	// so it ensures that browser commands are queued and executed in sequence.

	// The alternatives would be to:
	// - allow race conditions
	// - interrupt the blocking WebDriver::get method
	
	// The first is not desirable and the second does not seem to be possible
	// at the moment.
	private Executor executor;
	
	public BrowserComponent(UI ui) {
		this.ui = ui;
		this.executor = Executors.newSingleThreadExecutor();
	}
	
	private static void setupChromeDriverExecutable() {
		
		String osName = System.getProperty("os.name");
		String binaryPath =
				osName.startsWith("Mac OS") ? "chromedriver"
				: osName.startsWith("Windows") ? "chromedriver.exe"
				: "chromedriver_linux";
		
		File f = new File(binaryPath);
		if(!f.exists()) {
			InputStream in = BrowserComponent.class.getClassLoader().getResourceAsStream("ui/issuepanel/expanded/chromedriver");
			OutputStream out;
			try {
				out = new FileOutputStream(binaryPath);
				IOUtils.copy(in, out);
				out.close();
				f.setExecutable(true);
			} catch (IOException e) {
				System.out.println("Could not load Chrome driver binary!");
				e.printStackTrace();
			}
			System.out.println("Could not find " + binaryPath + "; extracted it from jar");
		} else {
			System.out.println("Located " + binaryPath);
		}
		
		System.setProperty("webdriver.chrome.driver", binaryPath);
	}

	/**
	 * Called on application startup. Blocks until the driver is created.
	 * Guaranteed to only happen once.
	 */
	public void initialise() {
		assert driver == null;
		driver = setupChromeDriver();
		ui.registerEvent(new LoginEventHandler() {
			@Override public void handle(LoginEvent e) {
				login();
			}
		});
		ui.registerEvent(new IssueSelectedEventHandler() {
			@Override public void handle(IssueSelectedEvent e) {
				if (!ui.isExpanded()) {
					ui.getBrowserComponent().showIssue(e.id);
				}<commit_msg>Fixed bug where Mac executable was being used on Windows<commit_after>package ui.issuepanel.expanded;

import java.awt.Rectangle;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Optional;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import javafx.concurrent.Task;

import org.apache.commons.io.IOUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.Point;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

import service.ServiceManager;
import ui.UI;
import util.GitHubURL;
import util.IOUtilities;
import util.events.IssueSelectedEvent;
import util.events.IssueSelectedEventHandler;
import util.events.LoginEvent;
import util.events.LoginEventHandler;

/**
 * An abstraction for the functions of the Selenium web driver.
 */
public class BrowserComponent {
	
	private static final boolean USE_MOBILE_USER_AGENT = true;

	private static String HIDE_ELEMENTS_SCRIPT_PATH = USE_MOBILE_USER_AGENT
			? "ui/issuepanel/expanded/mobileHideUI.js"
			: "ui/issuepanel/expanded/hideUI.js";

	// Chrome, Android 4.2.2, Samsung Galaxy S4
	private static final String MOBILE_USER_AGENT = "Mozilla/5.0 (Linux; Android 4.2.2; GT-I9505 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Mobile Safari/537.36";
	
	static {
		
		setupChromeDriverExecutable();
		
	}
	
	private final UI ui;
	private ChromeDriver driver = null;
	
	// We want browser commands to be run on a separate thread, but not to
	// interfere with each other. This executor is limited to a single instance,
	// so it ensures that browser commands are queued and executed in sequence.

	// The alternatives would be to:
	// - allow race conditions
	// - interrupt the blocking WebDriver::get method
	
	// The first is not desirable and the second does not seem to be possible
	// at the moment.
	private Executor executor;
	
	public BrowserComponent(UI ui) {
		this.ui = ui;
		this.executor = Executors.newSingleThreadExecutor();
	}
	
	private static void setupChromeDriverExecutable() {
		
		String osName = System.getProperty("os.name");
		String binaryFileName =
				osName.startsWith("Mac OS") ? "chromedriver"
				: osName.startsWith("Windows") ? "chromedriver.exe"
				: "chromedriver_linux";
		
		File f = new File(binaryFileName);
		if(!f.exists()) {
			InputStream in = BrowserComponent.class.getClassLoader().getResourceAsStream("ui/issuepanel/expanded/" + binaryFileName);
			OutputStream out;
			try {
				out = new FileOutputStream(binaryFileName);
				IOUtils.copy(in, out);
				out.close();
				f.setExecutable(true);
			} catch (IOException e) {
				System.out.println("Could not load Chrome driver binary!");
				e.printStackTrace();
			}
			System.out.println("Could not find " + binaryFileName + "; extracted it from jar");
		} else {
			System.out.println("Located " + binaryFileName);
		}
		
		System.setProperty("webdriver.chrome.driver", binaryFileName);
	}

	/**
	 * Called on application startup. Blocks until the driver is created.
	 * Guaranteed to only happen once.
	 */
	public void initialise() {
		assert driver == null;
		driver = setupChromeDriver();
		ui.registerEvent(new LoginEventHandler() {
			@Override public void handle(LoginEvent e) {
				login();
			}
		});
		ui.registerEvent(new IssueSelectedEventHandler() {
			@Override public void handle(IssueSelectedEvent e) {
				if (!ui.isExpanded()) {
					ui.getBrowserComponent().showIssue(e.id);
				}
{'fraction_non_alphanumeric': 0.10541044776119403, 'fraction_numerical': 0.00906183368869936, 'mean_word_length': 4.277777777777778, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '6533803', 'n_tokens_mistral': 2560, 'n_tokens_neox': 2256, 'n_words': 596}