src/main/java/io/uploader/drive/util/Callback.java
public interface Callback <T> {
	public void onSuccess (T result) ;
	public void onFailure (Throwable cause) ;
}
src/main/java/io/uploader/drive/gui/dlg/MessageDialogs.java
public enum Response {
	NO, YES, CANCEL
};
src/main/java/io/uploader/drive/config/Configuration.java
public enum Configuration implements HasConfiguration {
	INSTANCE ;
	
	final private Logger logger = LoggerFactory.getLogger(Configuration.class);
	
	private final String defaultXmlPath ; 
	
	private final String appName = "Drive Uploader" ;
	private final String appVersion = "1.1-SNAPSHOT" ;
	
	@Override
	public String getAppName ()
	{
		return appName ;
	}
	
	@Override
	public String getAppVersion ()
	{
		return appVersion ;
	}
	
	@Override
	public String getDataStoreDirectory() {
		String app = appName.toLowerCase().replaceAll(" ", "") ; 
		StringBuilder sb = new StringBuilder ();
		sb.append(System.getProperty("user.home")) ;
		sb.append(File.separator) ;
		sb.append(".") ;
		sb.append(app) ;
		sb.append(File.separator) ;
		sb.append(appVersion) ;
		sb.append(File.separator) ;
		sb.append("store") ;
		sb.append(File.separator) ;
		return sb.toString() ;
	}
	
	
	@Override
	public String getTmpDirectory() {
		String app = appName.toLowerCase().replaceAll(" ", "") ; 
		StringBuilder sb = new StringBuilder ();
		sb.append(System.getProperty("user.home")) ;
		sb.append(File.separator) ;
		sb.append(".") ;
		sb.append(app) ;
		sb.append(File.separator) ;
		sb.append(appVersion) ;
		sb.append(File.separator) ;
		sb.append("tmp") ;
		sb.append(File.separator) ;
		File dir = new File (sb.toString()) ;
		if (!dir.exists()) {
			dir.mkdirs() ;
		}
		return sb.toString() ;
	}
	
	
	private Configuration ()
	{
		String app = appName.toLowerCase().replaceAll(" ", "") ; 
		StringBuilder sb = new StringBuilder ();
		sb.append(System.getProperty("user.home")) ;
		sb.append(File.separator) ;
		sb.append(".") ;
		sb.append(app) ;
		sb.append(File.separator) ;
		sb.append(appVersion) ;
		sb.append(File.separator) ;
		sb.append(app) ;
		sb.append("-settings.xml") ;
		defaultXmlPath = sb.toString() ;
	}
	
	private volatile XMLConfiguration config = null ;
	
	private final ProxySettingsImpl httpProxySettings = new ProxySettingsImpl ("proxy.http", 80, "http") ;
	private final ProxySettingsImpl httpsProxySettings = new ProxySettingsImpl ("proxy.https", 443, "https") ;
	
	private Credential credential = null ;
	private AuthenticationSettingsImpl authenticationSettingsImpl = null ;

	public void load (String xmlPath) throws ConfigurationException
	{
		String settingFilePath = (xmlPath == null || xmlPath.isEmpty()) ? (defaultXmlPath) : (xmlPath) ;
		
		logger.debug("Load setting file {}.", settingFilePath);
		
		checkConfigFile (settingFilePath) ;
		try{
			config = new XMLConfiguration(settingFilePath);
		}
		catch (ConfigurationException e) {
			logger.error("Error occurred while opening the settings file", e);
		}
		if (config == null)
			return ;
		// TODO: when the commom-configuration 2.0 will be released
		// set the synchronizer
		//config.setSynchronizer(new ReadWriteSynchronizer());
		config.setThrowExceptionOnMissing(false);
		httpProxySettings.setConfig(config);
		httpsProxySettings.setConfig(config);
		
		setProxy () ;
	}
	
	
	private void checkConfigFile (String path)
	{
		try 
		{			
			File file = new File (path) ;
			if (!file.exists())
			{
				File parent = file.getParentFile() ;
				if (parent != null)
					parent.mkdirs() ;
				file.createNewFile() ;
				PrintWriter writer = new PrintWriter(file.getPath(), "UTF-8");
				writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?><settings></settings>" );
				writer.close();	
			}
		} 
		catch (IOException | SecurityException | NullPointerException e) 
		{
			logger.error("Error occurred while creating the settings file", e);
		}	
	}
	
	
	public void setAuthenticationSettingsImpl (AuthenticationSettingsImpl authenticationSettingsImpl) {
		this.authenticationSettingsImpl = authenticationSettingsImpl ;
	}
	
	
	@Override
	public HasAuthenticationSettings getAuthenticationSettings() {
		return authenticationSettingsImpl;
	}
	
	
	public void setCredential (Credential credential) {
		this.credential = credential ;
	}
	
	
	@Override
	public Credential getCredential() {
		return credential;
	}
	
	
	@Override
	public HasProxySettings getHttpProxySettings ()
	{
		return httpProxySettings ;
	}
	
	
	@Override
	public HasProxySettings getHttpsProxySettings ()
	{
		return httpsProxySettings ;
	}
	
		
	@Override
	public void updateProxy(Proxy newProxy) {
		
		try 
		{
			if ("http".equalsIgnoreCase(newProxy.getProtocol()))
			{
				httpProxySettings.update(newProxy);
				setProxySystemProperty (httpProxySettings, "http") ;
			}
			else if ("https".equalsIgnoreCase(newProxy.getProtocol()))
			{
				httpsProxySettings.update(newProxy);
				setProxySystemProperty (httpsProxySettings, "https") ;
			}
			else
			{
				logger.info("Unsupported proxy protocol: {}.", newProxy.getProtocol());
			}
		} 
		catch (ConfigurationException e) 
		{
			logger.error("Error occurred while updating the proxy settings", e);
		}
	}

	
	private static void setProxySystemProperty (HasProxySettings proxySettings, String prot)
	{
		if (proxySettings == null)
			return ;
		if (prot == null || prot.isEmpty())
			return ;
		
		prot = prot.toLowerCase() ;
		
    	if (proxySettings.isActive())
    	{
    		String host = proxySettings.getHost() ;
    		String user = proxySettings.getUsername() ;
    		String pwd = proxySettings.getPassword() ;
    		int port = proxySettings.getPort() ;
    		
    		if (host != null)
    			System.setProperty(prot + ".proxyHost", host);
	    	System.setProperty(prot + ".proxyPort", String.valueOf(port));
	    	if (user != null)
	    		System.setProperty(prot + ".proxyUser", user);
	    	if (pwd != null)
	    		System.setProperty(prot + ".proxyPassword", pwd);
    	}
	}

	
	
    private void setProxy ()
    {    	
    	setProxySystemProperty (httpProxySettings, "http") ;
    	setProxySystemProperty (httpsProxySettings, "https") ;
    	    	
		Authenticator.setDefault(new Authenticator() {
		    @Override
		    protected PasswordAuthentication getPasswordAuthentication() 
		    {
		        if (getRequestorType() == RequestorType.PROXY) 
		        {
		            String prot = getRequestingProtocol().toLowerCase();
		            
		            String host = System.getProperty(prot + ".proxyHost", "");
		            String port = System.getProperty(prot + ".proxyPort", "80");
		            String user = System.getProperty(prot + ".proxyUser", "");
		            String password = System.getProperty(prot + ".proxyPassword", "");

		            if (getRequestingHost().equalsIgnoreCase(host)) 
		            {
		                if (Integer.parseInt(port) == getRequestingPort()) 
		                    return new PasswordAuthentication(user, password.toCharArray());  
		            }
		        }
		        return null;
		    }  
		});
    }
}
src/main/java/io/uploader/drive/util/ObserverService.java
public abstract class ObserverService <T> extends Service <T> implements Observer {

	private static final Logger logger = LoggerFactory.getLogger(ObserverService.class);
	
	public ObserverService () {
		this (5) ;
	}
	
	public ObserverService (int threadPoolSize) {
		super () ;
		if (threadPoolSize <= 0) {
			throw new IllegalArgumentException () ;
		}
		setExecutor(Executors.newFixedThreadPool(threadPoolSize)) ;
	}
	
	@Override
	public void update(Observable o, Object arg) {

		if (arg != null) {
			if (arg instanceof AppEvent.Event) {
				if (((AppEvent.Event)arg) == AppEvent.Event.EXIT)
				{
					logger.info("Exit Event") ;
					cancel() ;
					Executor exe = getExecutor() ;
					if (exe != null && exe instanceof ExecutorService) {
						ThreadUtils.shutdownExecutor((ExecutorService) exe) ;
					}
				}
			}
		}
	}
}
src/main/java/io/uploader/drive/auth/DriveUploaderAuthorizationCodeInstalledApp.java
public class DriveUploaderAuthorizationCodeInstalledApp extends
		AuthorizationCodeInstalledApp {
	
	@SuppressWarnings("unused")
	final private static Logger logger = LoggerFactory.getLogger(SimpleBrowserImpl.class);
	
	private final Browser browser ;

	public DriveUploaderAuthorizationCodeInstalledApp(
			AuthorizationCodeFlow flow, VerificationCodeReceiver receiver, Browser browser) {
		super(flow, receiver);
		Preconditions.checkNotNull(browser) ;
		this.browser = browser ;
	}


	@Override
	protected void onAuthorization(AuthorizationCodeRequestUrl authorizationUrl)
			throws IOException {

		final String url = authorizationUrl.build() ;
		
		Platform.runLater(new Runnable() {
			@Override
			public void run() {
				logger.info("Authorization url: " + url);
				browser.show();
				browser.goTo(url) ;
			}
		});
	}
}
src/main/java/io/uploader/drive/auth/webbrowser/Browser.java
public interface Browser {
	public void goTo (String url) ;
	public void show () ;
	public void close () ;
}
src/main/java/io/uploader/drive/auth/webbrowser/SimpleBrowserImpl.java
public class SimpleBrowserImpl implements Browser {
 
	final private static Logger logger = LoggerFactory.getLogger(SimpleBrowserImpl.class);
	
	private final Stage stage ;
	private final WebEngine webEngine ;
	
    public SimpleBrowserImpl(Stage stage, String url) throws IOException {

    	super () ;
    	
    	Preconditions.checkNotNull(stage) ;
    	
    	this.stage = stage ;
    	stage.setTitle("Drive Uploader - Authentication");
    	UiUtils.setStageAppSize(stage) ;
        Scene scene = new Scene(new Group());

        AnchorPane root = new AnchorPane () ;  

        final WebView browser = new WebView();
        webEngine = browser.getEngine();
        
        /*
        Menu settingsMenu = new Menu ("Settings") ;
        MenuItem proxy = new MenuItem ("Proxy") ;
        settingsMenu.getItems().add(proxy) ;
        MenuBar menuBar = new MenuBar () ;
        menuBar.getMenus().add(settingsMenu) ;
        proxy.setOnAction(new EventHandler<ActionEvent> () {

			@Override
			public void handle(ActionEvent event) {
				try {
					ProxySettingDialog dlg = new ProxySettingDialog (stage, Configuration.INSTANCE) ;
					dlg.showDialog();
				} catch (IOException e) {
					logger.error("Error occurred while opening the proxy setting dialog", e);
				}
			}});*/
        
		FXMLLoader mainMenuLoader = new FXMLLoader(getClass().getResource("/fxml/MainMenu.fxml")); 
		VBox mainMenuBar = (VBox)mainMenuLoader.load() ;
		AnchorPane.setTopAnchor(mainMenuBar, 0.0);
		AnchorPane.setLeftAnchor(mainMenuBar, 0.0);
		AnchorPane.setRightAnchor(mainMenuBar, 0.0);
		MainMenuController mainMenuController = mainMenuLoader.<MainMenuController>getController();
		mainMenuController.setOwner(stage) ;
		mainMenuController.setConfiguration(Configuration.INSTANCE) ;
		mainMenuController.hideAccountMenu(true);
             
        ScrollPane scrollPane = new ScrollPane();
        scrollPane.setContent(browser);
        scrollPane.setFitToWidth(true);
        scrollPane.setFitToHeight(true);
        
        if (StringUtils.isNotEmpty(url)) {
        	goTo (url) ;
        }
                
        if (DriveUploader.isMacOsX()) {
        	AnchorPane.setTopAnchor(scrollPane, 5.0) ;
        } else {
        	AnchorPane.setTopAnchor(scrollPane, 35.0) ;
        }
        AnchorPane.setLeftAnchor(scrollPane, 5.0) ;
        AnchorPane.setRightAnchor(scrollPane, 5.0) ;
        AnchorPane.setBottomAnchor(scrollPane, 5.0) ;
        
        root.getChildren().add(mainMenuBar) ;
        root.getChildren().addAll(scrollPane);
        scene.setRoot(root);
        
        stage.setScene(scene);
    }
    
    
    @Override
    public void goTo (String url) {
    	
    	logger.info ("url: " + url) ;
    	
        String tmp = toURL(url);
        if (tmp == null) {
            tmp = toURL("http://" + url);
        }
        webEngine.load(tmp);
    }
    
    
    @Override
    public void show () {
    	stage.show() ;
    }
    
    
	@Override
	public void close() {
		stage.close() ;
	}
    
    
    public void stage () {
    	stage.showAndWait() ;
    }
    
    
    private static String toURL(String str) {
        try {
            return new URL(str).toExternalForm();
        } catch (MalformedURLException e) {
        	logger.error("Error occurred while loading the specified url.", e);
        	return null ;
        }
    }
}
src/main/java/io/uploader/drive/gui/MainWindow.java
public class MainWindow {

	@SuppressWarnings("unused")
	private static final Logger logger = LoggerFactory.getLogger(MainWindow.class);
	
	private final Stage stage ;
	
	public MainWindow(Drive client, Stage stage, AppEvent appEvent, HasConfiguration config) throws IOException {
		super();
		if (client == null) {
			throw new IllegalArgumentException () ;
		}
		this.stage = stage;
		
		stage.setTitle("Drive Uploader");
		
		AnchorPane mainFrame = (AnchorPane)FXMLLoader.load(getClass().getResource("/fxml/MainFrame.fxml"));
		Scene scene = new Scene(mainFrame);
		
		FXMLLoader mainMenuLoader = new FXMLLoader(getClass().getResource("/fxml/MainMenu.fxml")); 
		VBox mainMenuBar = (VBox)mainMenuLoader.load() ;
		AnchorPane.setTopAnchor(mainMenuBar, 0.0);
		AnchorPane.setLeftAnchor(mainMenuBar, 0.0);
		AnchorPane.setRightAnchor(mainMenuBar, 0.0);

		FXMLLoader driveTaskPanelViewLoader = new FXMLLoader(getClass().getResource("/fxml/DriveTaskPanelView.fxml")); 
		Pane mainPanel = (Pane)driveTaskPanelViewLoader.load();
		AnchorPane.setTopAnchor(mainPanel, (DriveUploader.isMacOsX()) ? (10.0) : (30.0));
		AnchorPane.setLeftAnchor(mainPanel, 10.0);
		AnchorPane.setRightAnchor(mainPanel, 10.0);
		AnchorPane.setBottomAnchor(mainPanel, 10.0);
		
		((AnchorPane) scene.getRoot()).getChildren().addAll(mainMenuBar, mainPanel);
		
		UiUtils.setStageAppSize(stage) ;
		
		final DriveTaskFactoryImpl taskFactory = new DriveTaskFactoryImpl (client) ;
		appEvent.addObserver(taskFactory) ;
		
		DriveTaskPanelViewController driveTaskPanelViewController = driveTaskPanelViewLoader.<DriveTaskPanelViewController>getController();
		driveTaskPanelViewController.setTaskFactory(taskFactory);
		driveTaskPanelViewController.setDriveUiFactory(new DriveUiFactoryImpl (client)) ;
		
		MainMenuController mainMenuController = mainMenuLoader.<MainMenuController>getController();
		mainMenuController.setOwner(stage) ;
		mainMenuController.setConfiguration(config) ;
		
		stage.setScene(scene);
	}

	public void show () {
		stage.show() ;
	}
}
src/main/java/io/uploader/drive/gui/dlg/MessageDialogs.java
public class MessageDialogs {
	
	private MessageDialogs () { super () ; throw new IllegalStateException () ; } ;
	
	public enum Response {
		NO, YES, CANCEL
	};
	
	public enum MessageType {
		NONE, INFO, WARNING, CONFIRM, ERROR
	};

	private static Response buttonSelected = Response.CANCEL;

	private static ImageView icon = new ImageView();

	private final static String logo = "/images/DriveUploader32.png";

	
	static class Dialog extends Stage {
			
		public Dialog(String title, Stage owner, Scene scene, String iconFileName) {
			super () ;
			setTitle(title);
			initStyle(StageStyle.UTILITY);
			initModality(Modality.WINDOW_MODAL);
			initOwner(owner);
			setResizable(false);
			setScene(scene);
			if (StringUtils.isEmpty(iconFileName)) {
				icon.setImage(new Image(getClass().getResourceAsStream(logo)));
			} else {
				icon.setImage(new Image(getClass().getResourceAsStream(iconFileName)));
			}
		}

		public void showDialog() {
			sizeToScene();
			showAndWait();
		}
	}

	
	static class Message extends Text {
		public Message(String msg) {
			super(msg);
			setWrappingWidth(250);
		}
	}

	
	public static Response showConfirmDialog(Stage owner, String message,
			String title) {
		return showConfirmDialog (owner, message, title, MessageType.CONFIRM) ;
	}
	
	
	private static String getIconName (MessageType type) {
		String iconName = null ;
		switch (type) {
		case ERROR:
			iconName = "/icons/Error32.png" ;
			break;
		case INFO:
			iconName = "/icons/Info32.png" ;
			break;
		case WARNING:
			iconName = "/icons/Warning32.png" ;
			break;
		case CONFIRM:
			iconName = "/icons/Confirm32.png" ;
			break;
		default:
			break;
		}
		return iconName ;
	}
	
	
	public static Response showConfirmDialog(Stage owner, String message,
			String title, MessageType type) {
		VBox vb = new VBox();
		Scene scene = new Scene(vb);
		final Dialog dial = new Dialog(title, owner, scene, getIconName (type));
		vb.setPadding(new Insets(10, 10, 10, 10));
		vb.setSpacing(10);
		Button yesButton = new Button("Yes");
		yesButton.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent e) {
				dial.close();
				buttonSelected = Response.YES;
			}
		});
		Button noButton = new Button("No");
		noButton.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent e) {
				dial.close();
				buttonSelected = Response.NO;
			}
		});
		BorderPane bp = new BorderPane();
		HBox buttons = new HBox();
		buttons.setAlignment(Pos.CENTER);
		buttons.setSpacing(10);
		buttons.getChildren().addAll(yesButton, noButton);
		bp.setCenter(buttons);
		HBox msg = new HBox();
		msg.setSpacing(15);
		msg.getChildren().addAll(icon, new Message(message));
		vb.getChildren().addAll(msg, bp);
		dial.showDialog();
		return buttonSelected;
	}

	
	public static void showMessageDialog(Stage owner, String message,
			String title) {
		showMessageDialog(owner, new Message(message), title, MessageType.NONE);
	}
	
	
	public static void showMessageDialog(Stage owner, String message,
			String title, MessageType type) {
		showMessageDialog(owner, new Message(message), title, type);
	}
	
	
	public static void showMessageDialog(Stage owner, Node message, String title, MessageType type) {
		VBox vb = new VBox();
		Scene scene = new Scene(vb);
		final Dialog dial = new Dialog(title, owner, scene, getIconName (type));
		vb.setPadding(new Insets(10, 10, 10, 10));
		vb.setSpacing(10);
		Button okButton = new Button("OK");
		okButton.setAlignment(Pos.CENTER);
		okButton.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent e) {
				dial.close();
			}
		});
		BorderPane bp = new BorderPane();
		bp.setCenter(okButton);
		HBox msg = new HBox();
		msg.setSpacing(5);
		msg.getChildren().addAll(icon, message);
		vb.getChildren().addAll(msg, bp);
		dial.showDialog();
	}
}
src/main/java/io/uploader/drive/config/auth/AuthenticationSettingsImpl.java
public class AuthenticationSettingsImpl implements HasAuthenticationSettings {

	private final GoogleClientSecrets clientSecrets ;
	
	public AuthenticationSettingsImpl(GoogleClientSecrets clientSecrets) {
		super();
		this.clientSecrets = clientSecrets;		
	}


	public static InputStream getClientSecretJson() throws IOException {
		InputStream in = AuthenticationSettingsImpl.class.getResourceAsStream("/client_secrets.json") ;
		if (in == null) {
			in = AuthenticationSettingsImpl.class.getResourceAsStream("/client_secrets_ori.json") ;
		}
		return in ;
	}
	
	
	@Override
	public synchronized String getClientId() {
		return clientSecrets.getDetails().getClientId() ;
	}

	
	@Override
	public synchronized String getClientSecret() {
		return clientSecrets.getDetails().getClientSecret() ;
	}
	

	@Override
	public String getCallBackUrl() {
		return clientSecrets.getDetails().getRedirectUris().get(0) ;
	}
}


Question: import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import io.uploader.drive.auth.DriveUploaderAuthorizationCodeInstalledApp;
import io.uploader.drive.auth.webbrowser.Browser;
import io.uploader.drive.auth.webbrowser.SimpleBrowserImpl;
import io.uploader.drive.config.Configuration;
import io.uploader.drive.config.auth.AuthenticationSettingsImpl;
import io.uploader.drive.gui.MainWindow;
import io.uploader.drive.gui.dlg.MessageDialogs;
import io.uploader.drive.gui.dlg.MessageDialogs.Response;
import io.uploader.drive.util.Callback;
import io.uploader.drive.util.ObserverService;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import org.apache.commons.configuration.ConfigurationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.VerificationCodeReceiver;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.store.DataStoreFactory;
import com.google.api.client.util.store.FileDataStoreFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.DriveScopes;
import com.google.common.base.Preconditions;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.EventHandler;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
/*
 * Copyright 2014 Loic Merckel
 * Copyright (c) 2013 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

/*
* 
* The original version of this file (i.e., the one that is copyrighted 2013 Google Inc.) 
* can  be found here:
*
*  https://code.google.com/p/google-api-java-client/source/browse/drive-cmdline-sample/src/main/java/com/google/api/services/samples/drive/cmdline/DriveSample.java?repo=samples
*  
*/

package io.uploader.drive;







public class DriveUploader extends Application {

	private static final Logger logger = LoggerFactory.getLogger(DriveUploader.class);
	
	private static final boolean activateNativeLookAndFeelForMacOs = true ;
	
	public static boolean isMacOsX ()
	{
		if (!activateNativeLookAndFeelForMacOs) {
			return false ;
		}
		String os = System.getProperty("os.name") ;
		return (os != null && os.toLowerCase().contains("mac")) ;
	}
	
	/**
	 * Be sure to specify the name of your application. If the application name
	 * is {@code null} or blank, the application will log a warning. Suggested
	 * format is "MyCompany-ProductName/1.0".
	 */
	private static final String APPLICATION_NAME = Configuration.INSTANCE.getAppName() ;

	/** Directory to store user credentials. */
	private static final java.io.File DATA_STORE_DIR = new java.io.File(Configuration.INSTANCE.getDataStoreDirectory());

	/**
	 * Global instance of the {@link DataStoreFactory}. The best practice is to
	 * make it a single globally shared instance across your application.
	 */
	private static FileDataStoreFactory dataStoreFactory;

	/** Global instance of the JSON factory. */
	private static final JsonFactory JSON_FACTORY = JacksonFactory
			.getDefaultInstance();

	/** Global instance of the HTTP transport. */
	private static HttpTransport httpTransport;

	private static Drive client;
		
	private static final AppEvent appEvent = new AppEvent () ;

	
	public static void main(String[] args) {
		
    	if (isMacOsX ())
    	{
    		System.setProperty("apple.laf.useScreenMenuBar", "true");
    		System.setProperty("com.apple.mrj.application.apple.menu.about.name", Configuration.INSTANCE.getAppName());
    		try {
				UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
			} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
				logger.error("Error occurred while initializing the UI", e);
			}
    	}
    	
    	Platform.setImplicitExit(false);	
		
		// load the settings
    	String settingsFile = "driveuploader-settings.xml" ;
    	if (!new java.io.File (settingsFile).exists())
    		settingsFile = null ;
		try {
			Configuration.INSTANCE.load(settingsFile);
		} catch (ConfigurationException e) {
			logger.error("Error occurred while initializing the configuration", e);
		}
		
		try {
			// initialize the transport
			httpTransport = GoogleNetHttpTransport.newTrustedTransport();

			// initialize the data store factory
			dataStoreFactory = new FileDataStoreFactory(DATA_STORE_DIR);

		} catch (IOException e) {
			logger.error("Error occurred while initializing the drive", e);
			Platform.exit() ;
		} catch (Throwable t) {
			logger.error("Error occurred while initializing the drive", t);
			Platform.exit() ;
		}
    	
		launch(args);
	}

	private static void authorize(final Browser browser, final Callback<Credential> callback)  {
		try {
			// load client secrets
			GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(
					JSON_FACTORY,
					new InputStreamReader(AuthenticationSettingsImpl.getClientSecretJson()));
			if (clientSecrets.getDetails().getClientId().startsWith("Enter")
					|| clientSecrets.getDetails().getClientSecret().startsWith("Enter ")) {
				System.out
						.println("Overwrite the src/main/resources/client_secrets.json file with the client secrets file "
								+ "you downloaded from the Quickstart tool or manually enter your Client ID and Secret "
								+ "from https://code.google.com/apis/console/?api=drive#project:94720202188 "
								+ "into src/main/resources/client_secrets.json");
				System.exit(1);
			}
			
			Configuration.INSTANCE.setAuthenticationSettingsImpl(new AuthenticationSettingsImpl (clientSecrets));
	
			// Set up authorization code flow.
			Set<String> scopes = new HashSet<String>();
			scopes.add(DriveScopes.DRIVE);
			// old api for large file support (where upload takes more than one hour)
			scopes.add("https://docs.google.com/feeds") ;
	
			final GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
					httpTransport, JSON_FACTORY, clientSecrets, scopes)
					.setDataStoreFactory(dataStoreFactory)
					.setAccessType("offline").setApprovalPrompt("force").build();
			
			// authorize
			final VerificationCodeReceiver receiver = new LocalServerReceiver() ;

			ObserverService<Credential> service = new ObserverService<Credential>() {

				private volatile DriveUploaderAuthorizationCodeInstalledApp driveUploaderAuthorizationCodeInstalledApp = null ;
			
				@Override
				protected Task<Credential> createTask() {
					Task<Credential> task = new Task<Credential>() {

						@Override
						protected Credential call() throws Exception {

							driveUploaderAuthorizationCodeInstalledApp = new DriveUploaderAuthorizationCodeInstalledApp(
									flow, receiver, browser) ;
							Credential credential = driveUploaderAuthorizationCodeInstalledApp.authorize("user");
							return credential;
						}
					};
					return task ;
				}
			};

			service.setOnSucceeded(new EventHandler<WorkerStateEvent>() {

				@Override
				public void handle(WorkerStateEvent t) {
					logger.info("Login success") ;
					Credential ret = (Credential) t.getSource().getValue();
					callback.onSuccess(ret);
				}
			});
			
			appEvent.addObserver(service) ;
			service.start();

		} catch (Exception e) {
			callback.onFailure(e) ;
		}
	}
	
	
	@Override
	public void stop() throws Exception {
		logger.info("Stop!") ;
		super.stop();
	}


	@Override
	public void start(final Stage stage) throws Exception {
		
		Preconditions.checkNotNull(stage) ;
		
		try {
			stage.onCloseRequestProperty().set(new EventHandler<WindowEvent>() {
				public void handle(WindowEvent e) {
					logger.info("Close request") ;
		
Answer: 					if (Response.NO == MessageDialogs.showConfirmDialog(stage, "Are you sure you want to close the application?", "Confirmation")) {