public static String decode(String in) {
		init();
		final String input = in;
		final int expOrgSize = (int)Math.floor(input.length() / 1.6);
		final int expPadSize = ((int)Math.ceil(expOrgSize / 5.0)) * 8;
		final StringBuilder s= new StringBuilder(input);
		for (int i = 0; i < expPadSize; i++) {
			s.append("=");
		}

		final char[] data    = s.toString().toLowerCase().toCharArray();
		int dataLen    = data.length;
		while (dataLen > 0) {
			if (!ignore(data[dataLen - 1]))
				break;

			dataLen--;
		}

		final java.util.List<Byte> output = new java.util.ArrayList<Byte>();
		int i = 0;
		final int e = dataLen - 8;
		for (i = next(data, i, e); i < e; i = next(data, i, e)) {
			final byte b1 = decoding[data[i++]];
			i = next(data, i, e);
			final byte b2 = decoding[data[i++]];
			i = next(data, i, e);
			final byte b3 = decoding[data[i++]];
			i = next(data, i, e);
			final byte b4 = decoding[data[i++]];
			i = next(data, i, e);
			final byte b5 = decoding[data[i++]];
			i = next(data, i, e);
			final byte b6 = decoding[data[i++]];
			i = next(data, i, e);
			final byte b7 = decoding[data[i++]];
			i = next(data, i, e);
			final byte b8 = decoding[data[i++]];

			output.add((byte) ((b1 << 3) | (b2 >> 2)));
			output.add((byte) ((b2 << 6) | (b3 << 1) | (b4 >> 4)));
			output.add((byte) ((b4 << 4) | (b5 >> 1)));
			output.add((byte) ((b5 << 7) | (b6 << 2) | (b7 >> 3)));
			output.add((byte) ((b7 << 5) | b8));
		}

		if (data[dataLen - 6] == '=') {
			output.add((byte) (((decoding[data[dataLen - 8]]) << 3) | (decoding[data[dataLen - 7]] >> 2)));
		} else if(data[dataLen - 4] == '=') {
			output.add((byte) (((decoding[data[dataLen - 8]]) << 3) | (decoding[data[dataLen - 7]] >> 2)));
			output.add((byte) (((decoding[data[dataLen - 7]]) << 6) | (decoding[data[dataLen - 6]] << 1) | (decoding[data[dataLen - 5]] >> 4)));
		} else if(data[dataLen - 3] == '=') {
			output.add((byte) (((decoding[data[dataLen - 8]]) << 3) | (decoding[data[dataLen - 7]] >> 2)));
			output.add((byte) (((decoding[data[dataLen - 7]]) << 6) | (decoding[data[dataLen - 6]] << 1) | (decoding[data[dataLen - 5]] >> 4)));
			output.add((byte) (((decoding[data[dataLen - 5]]) << 4) | (decoding[data[dataLen - 4]] >> 1)));
		} else if(data[dataLen - 1] == '=') {
			output.add((byte) (((decoding[data[dataLen - 8]]) << 3) | (decoding[data[dataLen - 7]] >> 2)));
			output.add((byte) (((decoding[data[dataLen - 7]]) << 6) | (decoding[data[dataLen - 6]] << 1) | (decoding[data[dataLen - 5]] >> 4)));
			output.add((byte) (((decoding[data[dataLen - 5]]) << 4) | (decoding[data[dataLen - 4]] >> 1)));
			output.add((byte) (((decoding[data[dataLen - 4]]) << 7) | (decoding[data[dataLen - 3]] << 2) | (decoding[data[dataLen - 2]] >> 3)));
		} else {
			output.add((byte) (((decoding[data[dataLen - 8]]) << 3) | (decoding[data[dataLen - 7]] >> 2)));
			output.add((byte) (((decoding[data[dataLen - 7]]) << 6) | (decoding[data[dataLen - 6]] << 1) | (decoding[data[dataLen - 5]] >> 4)));
			output.add((byte) (((decoding[data[dataLen - 5]]) << 4) | (decoding[data[dataLen - 4]] >> 1)));
			output.add((byte) (((decoding[data[dataLen - 4]]) << 7) | (decoding[data[dataLen - 3]] << 2) | (decoding[data[dataLen - 2]] >> 3)));
			output.add((byte) (((decoding[data[dataLen - 2]]) << 5) | (decoding[data[dataLen - 1]])));
		}

		final byte[] b = toPrimitive(output.toArray(new Byte[0]));
		return trim(new String(b));
	}