@Override
		public void run() {
			try {
				socket = new Socket(GTALK_SERVER, GTALK_PORT);
				OutputStream out = socket.getOutputStream();
				InputStream in = socket.getInputStream();

				String line;

				// a
				out.write((STREAM_START).getBytes());
				// b
				line = nextResponse(in, STREAM_START_RESULT);
				// c
				out.write((STANZA_C).getBytes());
				// d
				line = nextResponse(in, STANZA_C_RESULT);
				// TLS Negotiation
				SSLSocket sslSocket = startTLSHandshake(socket);
				InputStream inSsl = sslSocket.getInputStream();
				OutputStream outSsl = sslSocket.getOutputStream();
				// e
				outSsl.write((STREAM_START).getBytes());
				// f
				line = nextResponse(inSsl, STREAM_START_RESULT);
				// Build credential
				String credential = Base64.encodeBase64String(("\0" + username
						+ "\0" + authToken).getBytes());
				// h
				String authStanza = STANZA_H.replace("[credential]", "\n"
						+ credential);
				outSsl.write((authStanza).getBytes());
				// i
				line = nextResponse(inSsl, STANZA_H_RESULT);
				// SASL Authentication Handshake End
				// j
				outSsl.write((STREAM_START).getBytes());
				// k
				line = nextResponse(inSsl, STREAM_START_RESULT);
				// l
				String stanza_l = STANZA_L.replace("[resource name]",
						resourceName);
				outSsl.write((stanza_l).getBytes());
				// m
				line = nextResponse(inSsl, STANZA_L_RESULT);
				// Get bare JID
				String bareJid = line.replaceAll(".*<jid>(.*?)/.*", "$1");
				// n
				outSsl.write((STANZA_N).getBytes());
				// o
				line = nextResponse(inSsl, STANZA_N_RESULT);
				// p
				String stanza_p = STANZA_P.replace("[bare jid]", bareJid);
				outSsl.write((stanza_p).getBytes());
				// q
				line = nextResponse(inSsl, STANZA_P_RESULT);

				running = true;
				latch.countDown();
				
				// Notify listeners
				for (PushListener listener : listeners) {
					listener.onConnect();
				}
				
				// Waiting for Push Notifications
				while (true) {
					line = nextResponse(inSsl, PUSH_MESSAGE_RESULT);
					String printerId = new String(Base64.decodeBase64(line
							.replaceAll(".*<push:data>(.*?)</push:data>.*",
									"$1")));
					
					// Notify listeners
					for (PushListener listener : listeners) {
						listener.onReceive(printerId);
					}
				}
			} catch (Exception e) {
				if(running == true) {
					// Notify listeners
					for (PushListener listener : listeners) {
						listener.onDisconnect();
					}
				}
				
				running = false;

				if (!(e instanceof java.net.SocketException)) {
					e.printStackTrace();
				}
				latch.countDown();

			}

		}