docs: private static int decode4to3(byte[] source, int srcOffset, byte[] destination, int destOffset, int options)
  	{
  		byte[] DECODABET = getDecodabet(options);
  
  		// Example: Dk==
  		if (source[srcOffset + 2] == EQUALS_SIGN)
  		{
  			// Two ways to do the same thing. Don't know which way I like best.
  			// int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
  			// | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 );
  			int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12);
  
  			destination[destOffset] = (byte) (outBuff >>> 16);
  			return 1;
  		}
  
  		// Example: DkL=
  		else if (source[srcOffset + 3] == EQUALS_SIGN)
  		{
  			// Two ways to do the same thing. Don't know which way I like best.
  			// int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
  			// | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
  			// | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 );
  			int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12)
  					| ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6);
  
  			destination[destOffset] = (byte) (outBuff >>> 16);
  			destination[destOffset + 1] = (byte) (outBuff >>> 8);
  			return 2;
  		}
  
  		// Example: DkLE
  		else
  		{
  			try
  			{
  				// Two ways to do the same thing. Don't know which way I like best.
  				// int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
  				// | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
  				// | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 )
  				// | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 );
  				int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12)
  						| ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6) | ((DECODABET[source[srcOffset + 3]] & 0xFF));
  
  				destination[destOffset] = (byte) (outBuff >> 16);
  				destination[destOffset + 1] = (byte) (outBuff >> 8);
  				destination[destOffset + 2] = (byte) (outBuff);
  
  				return 3;
  			}
  			catch (Exception e)
  			{
  
  				// Remove these after checking -- for context only.
  				// logger.error( Logger.SECURITY_FAILURE, "Problem writing object", e );
  				// logger.error( Logger.SECURITY_FAILURE, ""+source[srcOffset]+ ": " + ( DECODABET[ source[ srcOffset ] ] ) );
  				// logger.error( Logger.SECURITY_FAILURE, ""+source[srcOffset+1]+ ": " + ( DECODABET[ source[ srcOffset + 1 ] ] ) );
  				// logger.error( Logger.SECURITY_FAILURE, ""+source[srcOffset+2]+ ": " + ( DECODABET[ source[ srcOffset + 2 ] ] ) );
  				// logger.error( Logger.SECURITY_FAILURE, ""+source[srcOffset+3]+ ": " + ( DECODABET[ source[ srcOffset + 3 ] ] ) );
  
  				// CHECKME: I replaced the 5 separate logger.error() calls above with a single logger.error() call so they can't
  				// become interleaved with other log entries from other threads. Normally this would have placed log entries
  				// on separate lines, so I also added line terminators here as well. (Probably don't want it all on one single
  				// really long log entry, do we?) Anyhow, somebody should check the formatting to ensure that it's
  				// esthetically pleasing, etc. But this works for me. I'm also OK if you want to remove all the line terminators
  				// in which case the declaration for EOL should be removed as well. - Kevin Wall
  
  				StringBuilder sb = new StringBuilder("Problem writing object:");
  				sb.append(EOL);
  				sb.append(source[srcOffset]).append(": ").append((DECODABET[source[srcOffset]])).append(EOL);
  				sb.append(source[srcOffset + 1]).append(": ").append((DECODABET[source[srcOffset + 1]])).append(EOL);
  				sb.append(source[srcOffset + 2]).append(": ").append((DECODABET[source[srcOffset + 2]])).append(EOL);
  				sb.append(source[srcOffset + 3]).append(": ").append((DECODABET[source[srcOffset + 3]])).append(EOL);
  
  				return -1;
  			} // end catch
  		}
  	}