protected void encodePacket(OutputStream out, String sharedSecret, RadiusPacket request) throws IOException {
		// check shared secret
		if (sharedSecret == null || sharedSecret.length() == 0)
			throw new RuntimeException("no shared secret has been set");

		// check request authenticator
		if (request != null && request.getAuthenticator() == null)
			throw new RuntimeException("request authenticator not set");

		// request packet authenticator
		if (request == null) {
			// first create authenticator, then encode attributes
			// (User-Password attribute needs the authenticator)
			authenticator = createRequestAuthenticator(sharedSecret);
			encodeRequestAttributes(sharedSecret);
		}

		byte[] attributes = getAttributeBytes();
		int packetLength = RADIUS_HEADER_LENGTH + attributes.length;
		if (packetLength > MAX_PACKET_LENGTH)
			throw new RuntimeException("packet too long");

		// response packet authenticator
		if (request != null) {
			// after encoding attributes, create authenticator
			authenticator = createResponseAuthenticator(sharedSecret, packetLength, attributes, request.getAuthenticator());
		}
		else {
			// update authenticator after encoding attributes
			authenticator = updateRequestAuthenticator(sharedSecret, packetLength, attributes);
		}

		DataOutputStream dos = new DataOutputStream(out);
		dos.writeByte(getPacketType());
		dos.writeByte(getPacketIdentifier());
		dos.writeShort(packetLength);
		dos.write(getAuthenticator());
		dos.write(attributes);
		dos.flush();
	}