public interface AuthBehavior {

	/**
	 * @param engine Экземпляр класса {@link Engine}
	 * @param login Логин
	 * @param pass Пароль
	 * @return Возвращает результат авторизации с типом {@link AuthData} 
	 */
	public AuthData auth(Engine engine, String login, String pass);
	
} public abstract class Checker {
			
	public abstract ClientStatus checkClient( Engine engine, String clientName );
		
	public abstract LauncherData getLauncherData( Engine engine );
	
	public abstract DirectoryStatus checkMods( Engine engine, String clientName );
	
	public abstract DirectoryStatus checkDirectory( Engine engine, String clientName, String directoryName );
	
} public abstract class Config {
	
	public abstract void setPassword( String pass );
	
	public abstract String getPassword();
	
	public abstract void setLogin( String login );
	
	public abstract String getLogin();
	
	public abstract String getProperty( String name ) ;
	
	public abstract void setServer( String server );
	
	public abstract String getServer();
	
	public abstract void setMemory( int memory );
	
	public abstract int getMemory();
	
	public abstract void setProperty( String key, String value );
	
	public abstract void setSecureProperty( String key, String value );
	
} public class DefaultAuthBehavior implements AuthBehavior {

	public AuthData auth(Engine engine, String login, String pass) {
		AuthData ret = new AuthData(login, null, AuthResult.BAD_CONNECTION);
		try {
			String data = "action=auth";
			data += "&login=" + URLEncoder.encode( AES.encrypt( login ), "UTF-8");
			data += "&pass=" + URLEncoder.encode( AES.encrypt( pass ), "UTF-8");
			
			String answer = NetManager.sendPostRequest( NetManager.getEngineLink( engine ), data );

			if (engine.isDebug()) {
				System.out.println(answer);
			}
			
			String[] answerParts = answer.split("<:>");
			if(answerParts.length > 3)
				return ret;

			if ("OK".equals(answerParts[0])) {
				ret.setSession( AES.decrypt( answerParts[1] ) );
				ret.setToken( AES.decrypt( answerParts[2] ) );
				ret.setResult( AuthResult.OK );
			} else
				ret.setResult( AuthResult.valueOf( answer.trim() ) );
			
		} catch (Exception e) {
			e.printStackTrace();
		}

		return ret;
	}
} public class DefaultChecker extends Checker {

	// Проверяемые файлы. Так же проверяется наличие natives под систему клиента
	static String[] files = { "jinput.jar", "lwjgl.jar", "lwjgl_util.jar", "minecraft.jar" };

	private Engine engine;
	
	private String clientName, folder;

	public ClientStatus checkClient( Engine e, String clientName ) {
		try {
			clientName = clientName.toLowerCase();
			String applicationName = e.getSettings().getDirectory();
			
			this.engine = e;

			if (!NetManager.isOnline()) {
				return ClientStatus.BAD_CONNECTION;
			}

			if (!OSManager.getWorkingDirectory(applicationName).exists() | !OSManager.getClientFolder(applicationName , clientName).exists()) {
				return ClientStatus.CLIENT_NOT_EXIST;
			}

			StringBuffer hash = new StringBuffer();
			File f = null;
			
			for (String name : files) {
				f = new File( OSManager.getClientFolder(applicationName, clientName ), name);
				if (!f.exists()) {
					return ClientStatus.WRONG_CLIENT;
				}

				hash.append( MD5.getMD5(f) );
			}
			
			return send( clientName , hash.toString(), OSManager.getPlatform() );
			
		} catch ( IOException ex ) {
			ex.printStackTrace();
			return ClientStatus.CLIENT_DOES_NOT_MATCH;
		}
	}

	private ClientStatus send(String client, String hash, OS system) {
		try {
			String data = "action=" + URLEncoder.encode("check", "UTF-8");
			data += "&client=" + URLEncoder.encode(client, "UTF-8");
			data += "&hash=" + URLEncoder.encode(hash, "UTF-8");
			data += "&system=" + URLEncoder.encode(system.toString(), "UTF-8");

			String s = NetManager.sendPostRequest( NetManager.getEngineLink( engine ) , data);
			
			return ClientStatus.valueOf(s.trim());
		} catch (IOException e) {
			e.printStackTrace();
			return ClientStatus.BAD_CONNECTION;
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
			return ClientStatus.BAD_CONNECTION;
		}
	}
	
	public LauncherData getLauncherData( Engine engine ) {
		
		LauncherData laun = null;
		
		try{
			String answer = NetManager.sendPostRequest( NetManager.getEngineLink( engine ), "action=launcher");
			
			if( engine.isDebug() )
				System.out.println( answer );
			
			laun = new LauncherData( Integer.parseInt( answer.split("<:>")[0] ) , answer.split("<:>")[1] );
			
			return laun;
		}catch( MalformedURLException e ) {
			e.printStackTrace();
		}catch( IOException e ) {
			e.printStackTrace();
		}
		
		return laun;
	}
			
	public DirectoryStatus checkMods( Engine engine, String clientName ) {
		this.clientName = clientName;
		this.folder = "mods";
		
		try {
			File directory = new File( OSManager.getWorkingDirectory(engine) + File.separator + clientName, this.folder );
			String data;
						
			if( !directory.exists() ) {
				data = generateData( "not_exist" );	
				String answer = NetManager.sendPostRequest(  NetManager.getEngineLink( engine ) , data );
				
				if( engine.isDebug() )
					System.out.println( answer );	
				
				if ( answer.equals( "OK" ) ) 
					return DirectoryStatus.OK;
				else
					if( answer.equals( "DIRECTORY_DOES_NOT_MATCH" ) )
						return DirectoryStatus.DIRECTORY_DOES_NOT_MATCH;
			}else{
				ArrayList< File > files = new ArrayList< File >();
				
				for ( File f : directory.listFiles() ) {					
					if( f.isFile() ) {
						files.add( f );
					}
				}
				
				String answer = NetManager.sendPostRequest(  NetManager.getEngineLink( engine ) , generateData( "count", Integer.toString( files.size() ) ) );

				if( engine.isDebug() )
					System.out.println( answer );
				
				if( answer.contains( "DIRECTORY_DOES_NOT_MATCH" ) )
					return DirectoryStatus.DIRECTORY_DOES_NOT_MATCH;
				
				//TODO сделать сборку хеша и сверку с сгенерированным на сервере
				
				return DirectoryStatus.OK;
 			}	
		}catch( Exception e ) {
			e.printStackTrace();
			return DirectoryStatus.BAD_CONNECTION;
		}
		
		return DirectoryStatus.DIRECTORY_DOES_NOT_MATCH;
	}

	@Deprecated
	public DirectoryStatus checkDirectory( Engine engine, String clientName, String directoryName ) {
		//TODO Реализовать метод
		return null;
	}
	
	private String generateData( String data ) {
		return "action=directory&folder=" + this.folder + "&client=" + this.clientName + "&data=" + data;
	}
	
	private String generateData( String data, String option ) {
		return "action=directory&folder=" + this.folder + "&client=" + this.clientName + "&data=" + data + "&option=" + option;
	}
	
}
 public class DefaultConfig extends Config {
	
	private Properties prop = new Properties();
	private File config;

	public DefaultConfig( Engine engine ) {
		config = new File( OSManager.getWorkingDirectory( engine ).toString(), "launcher.config" );
		
		try {
			if( !config.exists() ) {
				config.getParentFile().mkdirs();
				new FileOutputStream(config).close();
			}
			
			prop.load( new FileInputStream( config ) );
			
			check("login");
			check("password");
			check("memory");
			check("server");
			
			save();
		}catch( IOException e ) {
			e.printStackTrace();
		}			
	}
	
	private void save() {
		try {
			prop.store( new FileOutputStream( config ) ,"");
		} catch ( IOException e ) {
			e.printStackTrace();
		}
	}
	
	private void check( String key ) {
		if( !prop.containsKey( key ) ) {
			prop.setProperty( key, "" );
		}
	}
	
	public void setPassword( String pass ) {
		if( pass == null ) return;
		pass = StringUtils.newStringUtf8( StringUtils.getBytesUtf8( pass ) );
		try {
			prop.setProperty("password", AES.encrypt( pass ) );
		} catch (GeneralSecurityException e) {
			e.printStackTrace();
			prop.setProperty("password", pass);
		}
		save();
	}

	public String getPassword() {
		try {
			return AES.decrypt( prop.getProperty("password") );
		} catch (GeneralSecurityException e) {
			e.printStackTrace();
			return prop.getProperty("password");
		}
	}

	public void setLogin( String login ) {
		if( login == null ) return;
		login = StringUtils.newStringUtf8( StringUtils.getBytesUtf8( login ) );
		prop.setProperty("login", login);
		save();
	}

	public String getLogin() {
		return prop.getProperty("login");
	}
	
	public String getProperty( String name ) {
		return prop.getProperty( name );
	}

	public void setProperty( String key, String value ) {
		if( key == null || value == null ) return;
		key = StringUtils.newStringUtf8( StringUtils.getBytesUtf8( key ) );
		value = StringUtils.newStringUtf8( StringUtils.getBytesUtf8( value ) );
		prop.setProperty( key , value );
		save();
	}

	public void setSecureProperty( String key, String value ) {
		if( key == null || value == null ) return;
		key = StringUtils.newStringUtf8( StringUtils.getBytesUtf8( key ) );
		value = StringUtils.newStringUtf8( StringUtils.getBytesUtf8( value ) );
		try {
			prop.setProperty( key, AES.encrypt( value ) );
		} catch (GeneralSecurityException e) {
			e.printStackTrace();
			prop.setProperty( key, value );
		}
		save();
	}

	public void setServer( String server ) {
		if( server == null ) return;
		server = StringUtils.newStringUtf8( StringUtils.getBytesUtf8( server ) );
		prop.setProperty( "server", server );
		save();
	}

	public String getServer() {
		return prop.getProperty( "server" ) ;
	}

	public void setMemory( int memory ) {
		if( memory < 0 ) memory = Math.abs( memory );
		prop.setProperty( "memory", Integer.toString( memory ) );
		save();
	}

	public int getMemory() {
		return Integer.parseInt( prop.getProperty("memory") );
	}
	
} public class DefaultDownloader extends Downloader{

	private ArrayList< String > basic = new ArrayList< String >(),
								archives = new ArrayList< String >();
		
	public DefaultDownloader() {
		basic.add( "jinput.jar" );
		basic.add( "lwjgl.jar" );
		basic.add( "lwjgl_util.jar" );
		basic.add( "minecraft.jar" );
		
		archives.add( "client.zip" );
		archives.add( "natives/"+OSManager.getPlatform().toString()+".zip" );
	}

	private DownloadEvent event = new DownloadEvent();
	
	private Engine engine = null;
	private String clientName = null;
	private ArrayList< String > temp = new ArrayList< String >();
		
	public DownloadResult downloadClient( Engine e , String clientName ) {
		this.engine = e;
		this.clientName = clientName;
		
		basic.addAll( additionalFiles );
		archives.addAll( additionalArchives );
		
		temp.addAll( basic );
		temp.addAll( archives );
		
		event = new DownloadEvent();
		event.setCurrentFileAddress( getFileAddress( basic.get( 0 ) ) );
		event.setCurrentFileName( basic.get( 0 ) );
		event.setCurrentFileNumber( 0 );
		event.setCurrentFilePercents( 0 );
		event.setCurrentFileSize( getFileSizeKB( basic.get( 0 ) ) );
		
		event.setFilesAmount( temp.size() - 1 );
		event.setTotalSize( getTotalSize() );
		
		event.setNextFileAddress(  getFileAddress( basic.get( 1 ) ) );
		event.setNextFileName( basic.get( 1 ) );

		for ( String s : temp ) {
			if( !fileExist( getFileAddress( s ) ) ) {
				System.err.println( "Файл не найден: " + getFileAddress( s ) );
				return DownloadResult.FILE_NOT_EXIST;
			}
		}
		
		onStartDownload( event );
		
		delete( new File ( OSManager.getWorkingDirectory( engine ), clientName ) );
		
		for ( int num = 0; num < temp.size(); num++ ) {
			String filename = temp.get( num );
			
			event.setCurrentFileAddress( getFileAddress( filename ) );
			event.setCurrentFileName( filename );
			event.setCurrentFileNumber( num );
			event.setCurrentFileSize( getFileSizeKB( filename ) );
			
			if( num != temp.size() - 1 ) {
				event.setNextFileAddress( getFileAddress( temp.get( num + 1 )  ) );
				event.setNextFileName( temp.get( num + 1 ) );
				event.setNextFileSize( getFileSizeKB( temp.get( num + 1 ) ) );
			}else{
				event.setNextFileAddress( null );
				event.setNextFileName( null );
				event.setNextFileSize( -1 );
			}
			
			try {
				download( event.getCurrentFileAddress(), new File( OSManager.getClientFolder( engine, clientName ), event.getCurrentFileName() ) );
			} catch ( IOException ex ) {
				return DownloadResult.FILE_NOT_EXIST;
			}
			
			onFileChange( event );
		}
		
		File to = OSManager.getClientWorkingDirectory( engine, clientName ),
			 from = OSManager.getClientFolder( engine, clientName );
		
		for ( String s : archives ) {
			if( s.equalsIgnoreCase( "natives/"+OSManager.getPlatform().toString()+".zip" ) ) {
				ZipManager.unzip( new File( from, s ), new File( OSManager.getClientFolder( engine, clientName ), "natives") );
			}else
				ZipManager.unzip( new File( from, s ), to );
		}
		
		ZipManager.removeAllZipFiles( from );
		ZipManager.removeAllZipFiles( new File( OSManager.getClientFolder( engine, clientName ), "natives") );
			
		return DownloadResult.OK;
	}

	private boolean fileExist( URL address ) {
		try {
			HttpURLConnection con = (HttpURLConnection) address.openConnection();
			if( con.getResponseCode() != 200 ) {
				return false;
			}
			return true;
		} catch ( IOException e ) {
			return false;
		}
	}
	
	private int getTotalSize() {
		int sum = 0;

		for ( String s : basic ) {
			sum += getFileSizeKB( s );
		}
		
		for ( String s : archives ) {
			sum += getFileSizeKB( s );
		}
	
		return sum;
	}
	
	private int getFileSizeKB( String filename ) {
		try {
			URLConnection connection = getFileAddress( filename ).openConnection();
			connection.setDefaultUseCaches(false);
			
			return connection.getContentLength() / 1024;
		}catch( IOException e ) {
			return 0;
		}
	}
	
	private URL getFileAddress( String filename ) {
		try {
			return new URL( NetManager.getServerLink( this.engine ).concat( "clients/".concat( this.clientName.concat( "/bin/".concat( filename ) ) ) ) );
		} catch ( MalformedURLException e ) {
			return null;
		}
	}
	
	private void download( URL url, File f ) throws IOException {
		int size = getFileSizeKB( event.getCurrentFileName() );
		
		f.mkdirs();

		f.delete();
		f.createNewFile();
		
		URLConnection connection = url.openConnection();

		long down = connection.getContentLength();

		long downm = f.length();

		if (downm != down) {

			HttpURLConnection conn = (HttpURLConnection) url.openConnection();

			BufferedInputStream bis = new BufferedInputStream(
					conn.getInputStream());

			FileOutputStream fw = new FileOutputStream(f);

			byte[] b = new byte[1024];
			int count = 0;
			long total = 0;

			while ((count = bis.read(b)) != -1) {
				total += count;
				fw.write(b, 0, count);
				event.setCurrentFilePercents( (int) ( total * 100 ) / ( size * 1024 ) );
				this.onPercentChange( event );
			}
			fw.close();
		}else{
			return;
		}
	}
		
	private static void delete( File file ) {
	    if( !file.exists() ) return;
	    
	    if( file.isDirectory() ) {
	    	for(File f : file.listFiles())
	    		delete(f);
	    		file.delete();
	    	}else{
	    		file.delete();
	    	}
	}
	
} public abstract class Downloader {
		
 	private ArrayList<DownloadListener> listeners = new ArrayList<DownloadListener>();
	
	protected ArrayList< String > additionalFiles = new ArrayList< String >(),
								  additionalArchives = new ArrayList< String >();
	
	public void addDownloadListener( DownloadListener listener ){
		listeners.add( listener );
	}
	
	public void removeDownloadListener( DownloadListener listener ){
		listeners.remove( listener );
	}
	
	public void addAdditionalFile( String filename ) {
		additionalFiles.add( filename );
	}
	
	public void removeAdditionalFile( String filename ) {
		additionalFiles.remove( filename );
	}
	
	public void addAdditionalArchive( String filename ) {
		additionalArchives.add( filename );
	}
	
	public void removeAdditionalArchive( String filename ) {
		additionalArchives.remove( filename );
	}
	
	protected void onStartDownload( DownloadEvent e ){
		for( DownloadListener dl : listeners )
			dl.onStartDownload(e);
	}
	
	protected void onFileChange( DownloadEvent e ){
		for( DownloadListener dl : listeners )
			dl.onFileChange(e);
	}
	
	protected void onPercentChange( DownloadEvent e ){
		for( DownloadListener dl : listeners )
			dl.onPercentChange(e);
	}
	
	public abstract DownloadResult downloadClient( Engine e , String clientName );
	
} public class Intent {

	private Engine engine;

	public Intent(Engine engine) {
		this.engine = engine;
	}

	/**
	 * Загрузка клиента с сервера
	 * 
	 * @param clientName Имя клиента
	 * @return Возвращает результат загрузки типа {@link DownloadResult}
	 */
	public DownloadResult downloadClient( String clientName ) {
		return engine.getDownloader().downloadClient( engine, clientName );
	}
	
	/**
	 * Авторизация пользователя
	 * 
	 * @param login Логин
	 * @param pass Пароль
	 * @return обьект {@link AuthData } с содержимым сессии, логина и результате авторизации
	 */
	public AuthData auth( String login, String pass ) {
		return engine.getAuth().auth( engine, login, pass );
	}
	
	/**
	 * Проверка клиента
	 * 
	 * @param clientName Имя клиента
	 * @return Статус клиента типа {@link ClientStatus}
	 */
	public ClientStatus checkClient( String clientName ) {
		return engine.getChecker().checkClient( engine, clientName );
	}
	
	/** Запуск клиента Minecraft
	 * @param clientName Имя клиента
	 * @param authData Идентификационные данные
	 * @param frame Окно в котором запускать
	 */
	public void startMinecraft( String clientName, AuthData authData, JFrame frame) {
		engine.getStarter().startMinecraft( engine.getSettings().getDirectory(), clientName, authData, null, null, frame );
	}
	
	/**
	 * Запуск клиента Minecraft
	 * @param clientName Имя клиента
	 * @param authData Идентификационные данные
	 * @param server Адрес сервера
	 * @param port Порт сервера
	 * @param frame Окно в котором запускать
	 */
	public void startMinecraft( String clientName, AuthData authData, String server, String port, JFrame frame ) {
		engine.getStarter().startMinecraft( engine.getSettings().getDirectory() , clientName, authData, server, port, frame );
	}
	
} public class MinecraftAppletStarter implements MinecraftStarter {
	
	private JFrame temp = new JFrame();
	
	private boolean fullscreen = false, output = true;
	private int width = 800, height = 600;

	public void startMinecraft( String dir, String clientName, AuthData authData, String server, String port, Frame frame ) {
		if ( dir == null || clientName == null || authData == null || frame == null ) throw new NullPointerException();
		if( port == null ) port = "25565";
			else if ( port.equals( "" ) ) port = "25565";

		String bin = OSManager.getClientFolder(dir, clientName).getAbsolutePath() + File.separator;
		
		URL[] urls = new URL[4];
		try {
			urls[0] = new File(bin, "minecraft.jar").toURI().toURL();
			urls[1] = new File(bin, "lwjgl.jar").toURI().toURL();
			urls[2] = new File(bin, "jinput.jar").toURI().toURL();
			urls[3] = new File(bin, "lwjgl_util.jar").toURI().toURL();
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}

		final Launcher mcapplet = new Launcher(bin, urls, authData);
		mcapplet.customParameters.put("username", authData.getLogin());
		mcapplet.customParameters.put("sessionid", authData.getSession());
		mcapplet.customParameters.put("stand-alone", "true");
		if (server != null) {
			mcapplet.customParameters.put("server", server);
			mcapplet.customParameters.put("port", port);
		}

		frame.setVisible( false );
		frame.dispose();
		
		if( fullscreen ) {
			temp.setExtendedState( JFrame.MAXIMIZED_BOTH );
			temp.setMinimumSize( new Dimension( 800, 600 ) );
		}else
			temp.setSize( new Dimension( width, height ) );
		
		temp.setLayout( new BorderLayout() );
		temp.setLocationRelativeTo( null );
		temp.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
	
		mcapplet.setForeground(Color.BLACK);
		mcapplet.setBackground(Color.BLACK);

		temp.add( mcapplet, BorderLayout.CENTER );
		temp.validate();
		temp.setVisible( true );

		System.setProperty("minecraft.applet.WrapperClass", "net.minecraft.Launcher");
		
		if( output ) {
			System.setErr(new PrintStream( new NulledStream()) );
			System.setOut(new PrintStream( new NulledStream()) );
		}

		mcapplet.init();
		mcapplet.start();
	}

	private class NulledStream extends OutputStream {
		public void write(int b) throws IOException {}
	}

	public void useFullScreen( boolean bool ) {
		this.fullscreen = bool;
	}
	
	public void useOutput( boolean output ) {
		this.output = output;
	}

	public boolean isFullScreen() {
		return fullscreen;
	}

	public boolean isOutput() {
		return output;
	}

	public void setSize( int width, int height ) {
		this.width = width;
		this.height = height;
	}
	
} public interface MinecraftStarter {

	/**
	 * @param dir
	 * @param clientName Имя клиента
	 * @param authData
	 * @param server Адрес сервера для автоподключения, если server != null
	 * @param port Порт сервера для автоподключения
	 * @param frame Окно в котором запускать клиент
	 */
	public void startMinecraft( String dir, String clientName, AuthData authData, String server, String port, Frame frame );
	
	/**
	 * Принимает boolean-значение и устанавливает его.<br>
	 * Если true, то будет использоваться переход в полно-экранный режим
 	 * @param bool - boolean значение
	 */
	public void useFullScreen( boolean bool );

	/**
	 * Включает или выключает консольный вывод запускаемого клиента
	 * 
	 * @param bool
	 */
	public void useOutput( boolean output );
	
 	public boolean isFullScreen();
 
 	public boolean isOutput();

 	/**
 	 * Устанавливает размер окна в котором запускается клиент.
 	 * <br>
 	 * Размер окна не изменяется, если fullscreen - true
 	 * 
 	 * @param width - ширина окна
 	 * @param height - высота окна
 	 */
 	public void setSize( int width, int height );
 	
}
 public class FatalError {
	
	/**
	 * @param e - Исключение
	 */
	public static void showErrorWindow( Exception e ) {
		if( e != null )
			showErrorWindow( e.getClass(), e.getStackTrace(), e.getMessage() );
	}

	/**
	 * @param cl
	 *            класс исключения
	 * @param trace
	 *            трассировка стека
	 * @param message
	 *            сообщение исключения
	 */
 	private static void showErrorWindow( Class<?> cl, StackTraceElement[] trace, String message ) {
 		try {
			UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
		} catch ( ClassNotFoundException | InstantiationException
				| IllegalAccessException | UnsupportedLookAndFeelException e ) {}
 		
		JPanel panel = new JPanel();
		panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

		BufferedImage img;
		try {
			img = ImageIO.read(FatalError.class.getResource("sinrel.png"));
		} catch (IOException e1) {
			img = null;
		}
		ImageIcon logo = new ImageIcon(img);

		JLabel l = new JLabel();
		l.setIcon(logo);

		panel.add(l);

		JLabel info = new JLabel("Критическая ошибка привела к завершению работы.");
		info.setFont(info.getFont().deriveFont(12F));

		panel.add(info);

		JLabel info2 = new JLabel("Обратитесь к разработчику, прилагая текст ниже:");
		info2.setFont(info.getFont());

		panel.add(info2);

		JTextArea tp = new JTextArea();
		tp.setEnabled(true);
		tp.setEditable(false);
		tp.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 12));
		tp.setText(cl.getName() + ": " + message + "\n");
		tp.setBounds(10, 45 + info.getHeight() + img.getHeight(), 370, 160);

		for (StackTraceElement st : trace) {
			tp.setText(tp.getText() + "   " + "at " + st.toString() + "\n");
		}
		
		tp.setText( tp.getText().trim() );

		JScrollPane sp = new JScrollPane(tp);

		panel.add(sp);

		JLabel aboutLabel = new JLabel("Информация о компьютере:");
		aboutLabel.setFont(aboutLabel.getFont().deriveFont(12F));

		panel.add(aboutLabel);
		
		JTextArea about = new JTextArea();
		about.setEnabled(true);
		about.setEditable(false);
		about.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 12));
		about.setText("");

		String[] keys = { "java.version", "java.vm.version", "java.io.tmpdir", "os.name", "os.arch", "os.version", "user.name", "user.home" };

		for (String s : keys) {
			about.setText(about.getText() + "   " + s + ": " + System.getProperty(s) + "\n");
		}
		
		String s = about.getText();
		s = s.substring( 0, s.length()-1 );
		about.setText( s );

		JScrollPane scroll = new JScrollPane(about);

		panel.add(scroll);

		// Make JOptionPane

		JOptionPane opane = new JOptionPane(panel);
		opane.setPreferredSize(new Dimension(500, 400));

		opane.setComponentOrientation( JOptionPane.getRootFrame().getComponentOrientation() );

		JDialog dialog = opane.createDialog("SLE Fatal Error");
				
		dialog.setIconImage( img.getSubimage( 1, 4, 52, 52) );
		dialog.setVisible(true);
		dialog.dispose();
	}
	
}
import org.sinrel.engine.actions.AuthBehavior;
import org.sinrel.engine.actions.Checker;
import org.sinrel.engine.actions.Config;
import org.sinrel.engine.actions.DefaultAuthBehavior;
import org.sinrel.engine.actions.DefaultChecker;
import org.sinrel.engine.actions.DefaultConfig;
import org.sinrel.engine.actions.DefaultDownloader;
import org.sinrel.engine.actions.Downloader;
import org.sinrel.engine.actions.Intent;
import org.sinrel.engine.actions.MinecraftAppletStarter;
import org.sinrel.engine.actions.MinecraftStarter;
import org.sinrel.engine.exception.FatalError;
package org.sinrel.engine;


public class Engine {
	
	private EngineSettings settings;
	
	private Intent intent;
	private Config config;
	
	private Downloader downloader;