    /**
	 * @return one random character out of 62 ('A'..'Z','a'..'z','0'..'9')
	 */
	function getRandomChar() {
		var x = Math.floor(Math.random()*62);
		if (x<10) return (48+x); // ASCII code for '0'..'9'
		x-=10;
		if (x<26) return (65+x); // ASCII code for 'A'..'Z'
		x-=26;
		return (97+x); // ASCII code for 'a'..'z'
	}

	/**
	 * @param c
	 * @return c+1 (within '0'..'9','A'..'Z','a'..'z')
	 */
	function incChar(c) {
		if (c==57) return 65; // 58=48+10-1
		if (c==90) return 97; // 91=65+26-1
		if (c==122) return 48; // 123=97+26-1
		c++;
		return c;
	}

	/**
	 * "increments" a base-62 number whose digits are '0'..'9', 'A'..'Z', 'a'..'z'. <br>
	 * the number is stored as sequence of bytes (ASCII codes) in MSDF (most significant
	 * digit first).
	 * @param array - byte array
	 * @param offset - offset
	 */
	function incCharArray(array, offset) {
		var i = array.length - 1;
		for (;i>=offset;i--) {
			if ((array[i] = incChar(array[i])) != 48) break;
		}
	}

	/**
	 * @param stamp
	 * @param min
	 * @return checks whether a bitstring (MSB first) starts at least with [minimum] zeros
	 */
	function hasPostage(hash, min) {
		var i=0;
		while (min>=4) {
			if (hash.charAt(i++)!='0') return false;
			min-=4;
		}
		if (min>0) { // hex char -> bit conversion
		    var msb = hash.charAt(i);
			if (msb > '7') return false; // 8 and higher start with bits '1xxx'
		    if (((msb.charCodeAt(0)-48) >> (4-min)) != 0) return false; //conversion for 0-7
		}
		return true;
	}

	/**
	 * @param prefix
	 * @param postage
	 * @return a string s with s=prefix|suffix where hex_md5(s) starts with [postage] zeros
	 */
	function findStamp(prefix, postage) {
		try {
		    if (postage<0 || postage>160) throw "'postage' parameter out of range";
			var suflen = Math.ceil(6+postage/6); // compute the length of the suffix
			var asBytes = new Array(suflen);
			var i;
			//load the suffix with random characters
			for (i=0; i<suflen; i++) { asBytes[i] = getRandomChar(); }
			var j;
			var stamp;
			var hash;
			for (i=0;;) {
    			stamp = prefix;
    			for (j=0; j<suflen; j++) { stamp+=String.fromCharCode(asBytes[j]) } //add the suffix
        	    hash = hex_sha1(stamp); //using sha1 hash since performance impact seems negligible
				if (hasPostage(hash,postage)) return stamp; //we found a good stamp
				//otherwise, we're still here
				incCharArray(asBytes,0); //increment the suffix
			}
		} catch (err) {
			return null;
		}
	}
	
	/**
	 * @param postage
	 * @param ID - a unique identifier for the desired recipient of the message
	 * @param servertime
	 * @return a stamp prefix with 'version:[postage]:date:time:[ID]:'
	 */
	function derivePrefix(postage,ID,servertime) {
	    return 'H:'+postage+':'+formatDate(servertime,'yyMMdd:HHmm:')+ID+':';
	}

