public void login() throws IOException
	{
		if (useGarena)
			getGarenaToken();
		
		getIPAddress();
		getAuthToken();

		TypedObject result, body;

		// Login 1
		body = new TypedObject("com.riotgames.platform.login.AuthenticationCredentials");
		if (useGarena)
			body.put("username", userID);
		else
			body.put("username", user);
		body.put("password", pass); // Garena doesn't actually care about password here
		body.put("authToken", authToken);
		body.put("clientVersion", clientVersion);
		body.put("ipAddress", ipAddress);
		body.put("locale", locale);
		body.put("domain", "lolclient.lol.riotgames.com");
		body.put("operatingSystem", "LoLRTMPSClient");
		body.put("securityAnswer", null);
		body.put("oldPassword", null);
		if (useGarena)
			body.put("partnerCredentials", "8393 " + garenaToken);
		else
			body.put("partnerCredentials", null);
		int id = invoke("loginService", "login", new Object[] { body });

		// Read relevant data
		result = getResult(id);
		if (result.get("result").equals("_error"))
			throw new IOException(getErrorMessage(result));
		
		body = result.getTO("data").getTO("body");
		sessionToken = body.getString("token");
		accountID = body.getTO("accountSummary").getInt("accountId");
		
		// Login 2
		byte[] encbuff = null;
		if (useGarena)
			encbuff = (userID + ":" + sessionToken).getBytes("UTF-8");
		else
			encbuff = (user.toLowerCase() + ":" + sessionToken).getBytes("UTF-8");

		body = wrapBody(Base64.encodeBytes(encbuff), "auth", 8);
		body.type = "flex.messaging.messages.CommandMessage";

		id = invoke(body);
		result = getResult(id); // Read result (and discard)
		
		// Subscribe to the necessary items
		body = wrapBody(new Object[] { new TypedObject() }, "messagingDestination", 0);
		body.type = "flex.messaging.messages.CommandMessage";
		TypedObject headers = body.getTO("headers");
		//headers.put("DSRemoteCredentialsCharset", null); // unneeded
		//headers.put("DSRemoteCredentials", "");
		
		// bc
		headers.put("DSSubtopic", "bc");
		body.put("clientId", "bc-" + accountID);
		id = invoke(body);
		result = getResult(id); // Read result and discard
		
		// cn
		headers.put("DSSubtopic", "cn-" + accountID);
		body.put("clientId", "cn-" + accountID);
		id = invoke(body);
		result = getResult(id); // Read result and discard

		// gn
		headers.put("DSSubtopic", "gn-" + accountID);
		body.put("clientId", "gn-" + accountID);
		id = invoke(body);
		result = getResult(id); // Read result and discard

		// Start the heartbeat
		new HeartbeatThread();
		
		loggedIn = true;

		System.out.println("Connected to " + region);
	}