[wip] add untested base58 encode in ts
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* Base58 encoding/decoding
|
||||
*/
|
||||
|
||||
export {
|
||||
encode
|
||||
// decode
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// ENCODING
|
||||
//=============================================================================
|
||||
|
||||
/**
|
||||
* Encode a Uint8Array into base58
|
||||
*/
|
||||
function
|
||||
encode(binary : Uint8Array): string {
|
||||
let num_leading_zeros : number = nlz(binary);
|
||||
let rest : Uint8Array = binary.slice(num_leading_zeros);
|
||||
let ones : string = encode_zeros(num_leading_zeros);
|
||||
let rest_b58 : string = encode_rest(rest);
|
||||
let result : string = ones + rest_b58;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* count the number of leading zeros in a uint8array
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
function
|
||||
nlz(bytes: Uint8Array): number {
|
||||
let n = 0;
|
||||
for (let this_byte of bytes) {
|
||||
if (0 === this_byte)
|
||||
n++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate a bunch of '1's for however many leading zeros there are
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
function
|
||||
encode_zeros(how_many : number): string {
|
||||
let ones : string = '';
|
||||
for (let i = 1;
|
||||
i <= how_many;
|
||||
i++)
|
||||
{
|
||||
ones += '1';
|
||||
}
|
||||
|
||||
return ones;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Encode a Uint8Array that has no leading zeros
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
function
|
||||
encode_rest(bytes : Uint8Array): string {
|
||||
let bytes_bignum : bigint = bytes_to_bigint(bytes);
|
||||
let result : string = bignum_to_base58(bytes_bignum);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Convert a bytestring to a bignum
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
function
|
||||
bytes_to_bigint(bytes: Uint8Array): bigint {
|
||||
let acc_bigint : bigint = 0n;
|
||||
for(let this_byte of bytes) {
|
||||
acc_bigint <<= 8n;
|
||||
acc_bigint += BigInt(this_byte);
|
||||
}
|
||||
return acc_bigint;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Convert a BigInt to Base58
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
function
|
||||
bignum_to_base58(q: bigint) {
|
||||
let s = '';
|
||||
while (q !== 0n) {
|
||||
let this_n : bigint = q % 58n;
|
||||
q /= 58n;
|
||||
|
||||
let this_b58_char : string = bigint_to_char(this_n);
|
||||
s = this_b58_char + s;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// TRANSLATION TABLES
|
||||
//=============================================================================
|
||||
|
||||
function
|
||||
bigint_to_char(n: bigint) {
|
||||
switch(n) {
|
||||
case 0n: return '1';
|
||||
case 1n: return '2';
|
||||
case 2n: return '3';
|
||||
case 3n: return '4';
|
||||
case 4n: return '5';
|
||||
case 5n: return '6';
|
||||
case 6n: return '7';
|
||||
case 7n: return '8';
|
||||
case 8n: return '9';
|
||||
case 9n: return 'A';
|
||||
case 10n: return 'B';
|
||||
case 11n: return 'C';
|
||||
case 12n: return 'D';
|
||||
case 13n: return 'E';
|
||||
case 14n: return 'F';
|
||||
case 15n: return 'G';
|
||||
case 16n: return 'H';
|
||||
case 17n: return 'J';
|
||||
case 18n: return 'K';
|
||||
case 19n: return 'L';
|
||||
case 20n: return 'M';
|
||||
case 21n: return 'N';
|
||||
case 22n: return 'P';
|
||||
case 23n: return 'Q';
|
||||
case 24n: return 'R';
|
||||
case 25n: return 'S';
|
||||
case 26n: return 'T';
|
||||
case 27n: return 'U';
|
||||
case 28n: return 'V';
|
||||
case 29n: return 'W';
|
||||
case 30n: return 'X';
|
||||
case 31n: return 'Y';
|
||||
case 32n: return 'Z';
|
||||
case 33n: return 'a';
|
||||
case 34n: return 'b';
|
||||
case 35n: return 'c';
|
||||
case 36n: return 'd';
|
||||
case 37n: return 'e';
|
||||
case 38n: return 'f';
|
||||
case 39n: return 'g';
|
||||
case 40n: return 'h';
|
||||
case 41n: return 'i';
|
||||
case 42n: return 'j';
|
||||
case 43n: return 'k';
|
||||
case 44n: return 'm';
|
||||
case 45n: return 'n';
|
||||
case 46n: return 'o';
|
||||
case 47n: return 'p';
|
||||
case 48n: return 'q';
|
||||
case 49n: return 'r';
|
||||
case 50n: return 's';
|
||||
case 51n: return 't';
|
||||
case 52n: return 'u';
|
||||
case 53n: return 'v';
|
||||
case 54n: return 'w';
|
||||
case 55n: return 'x';
|
||||
case 56n: return 'y';
|
||||
case 57n: return 'z';
|
||||
default:
|
||||
throw new Error('invalid base58 bigint: ' + n)
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
%% https://digitalbazaar.github.io/base58-spec/#encode
|
||||
|
||||
main([]) ->
|
||||
{ok, Cases} = file:consult("b58_cases.eterms"),
|
||||
{ok, Cases} = file:consult("b58_cases_3.eterms"),
|
||||
test_cases(Cases).
|
||||
|
||||
test_cases([{{encoded, E}, {decoded, D}} | Rest]) ->
|
||||
@@ -19,8 +19,8 @@ test_cases([{{encoded, E}, {decoded, D}} | Rest]) ->
|
||||
"YOU ARE A FAILURE TO ENCODE~n"
|
||||
"===============================~n"
|
||||
"decoded : ~tw~n"
|
||||
"expected : ~tw~n"
|
||||
"actual : ~tw~n~n",
|
||||
"expected : ~ts~n"
|
||||
"actual : ~ts~n~n",
|
||||
[D, E, enc(D)])
|
||||
end,
|
||||
ok =
|
||||
@@ -29,7 +29,7 @@ test_cases([{{encoded, E}, {decoded, D}} | Rest]) ->
|
||||
false -> io:format("===============================~n"
|
||||
"YOU ARE A FAILURE TO DECODE~n"
|
||||
"===============================~n"
|
||||
"encoded : ~tw~n"
|
||||
"encoded : ~ts~n"
|
||||
"expected : ~tw~n"
|
||||
"actual : ~tw~n~n",
|
||||
[E, D, dec(E)])
|
||||
@@ -40,10 +40,39 @@ test_cases([]) ->
|
||||
|
||||
% this was much clearer: https://www.youtube.com/watch?v=GedV3S9X89c
|
||||
|
||||
enc(Bits) ->
|
||||
NBits = bit_size(Bits),
|
||||
<<BitNum:NBits>> = Bits,
|
||||
enc(BitNum, []).
|
||||
-spec enc(Bytes) -> Base58
|
||||
when Bytes :: binary(),
|
||||
Base58 :: string().
|
||||
|
||||
enc(Bytes) ->
|
||||
% grab leading 0s
|
||||
{NumLeadingZeros, Rest} = split_zeros(Bytes, 0),
|
||||
NBitsInRest = bit_size(Rest),
|
||||
<<RestBigNum:NBitsInRest>> = Rest,
|
||||
ZerosBase58 = [$1 || _ <- lists:seq(1, NumLeadingZeros)],
|
||||
RestBase58 = enc(RestBigNum, []),
|
||||
ZerosBase58 ++ RestBase58.
|
||||
|
||||
|
||||
|
||||
-spec split_zeros(Bytes, InitZeros) -> {NumLeadingZeros, Rest}
|
||||
when Bytes :: binary(),
|
||||
InitZeros :: integer(),
|
||||
NumLeadingZeros :: binary(),
|
||||
Rest :: binary().
|
||||
|
||||
split_zeros(<<0:8, Rest/binary>>, NumZerosAcc) ->
|
||||
NewNumZerosAcc = NumZerosAcc + 1,
|
||||
split_zeros(Rest, NewNumZerosAcc);
|
||||
split_zeros(Rest, NumZerosAcc) ->
|
||||
{NumZerosAcc, Rest}.
|
||||
|
||||
|
||||
|
||||
-spec enc(BytesBigNum, Base58Acc) -> Base58
|
||||
when BytesBigNum :: integer(),
|
||||
Base58Acc :: [0..57],
|
||||
Base58 :: string().
|
||||
|
||||
enc(0, Acc) ->
|
||||
lists:map(fun int2char/1, Acc);
|
||||
@@ -53,9 +82,24 @@ enc(BitNum, Acc) ->
|
||||
enc(Q, [R | Acc]).
|
||||
|
||||
|
||||
|
||||
-spec dec(Base58) -> DecodedBytes
|
||||
when Base58 :: string(),
|
||||
DecodedBytes :: binary().
|
||||
|
||||
dec(Str) ->
|
||||
Ns = lists:map(fun char2int/1, Str),
|
||||
dec(Ns, 0).
|
||||
% the number of leading 1s tells us the number of leading zeros
|
||||
{NumLeadingZeros, RestStr} = split_ones(Str, 0),
|
||||
LeadingZeros = << <<0>> || _ <- lists:seq(1, NumLeadingZeros) >>,
|
||||
RestNs = lists:map(fun char2int/1, RestStr),
|
||||
RestBytes = dec(RestNs, 0),
|
||||
<<LeadingZeros/binary, RestBytes/binary>>.
|
||||
|
||||
split_ones([$1 | Rest], NOnes) ->
|
||||
split_ones(Rest, NOnes + 1);
|
||||
split_ones(B58Str, NOnes) ->
|
||||
{NOnes, B58Str}.
|
||||
|
||||
|
||||
dec([N | Ns], Acc) ->
|
||||
NewAcc = (Acc*58) + N,
|
||||
|
||||
@@ -9,27 +9,123 @@ really checking to see if my code matches the base58 package
|
||||
import base58 as b
|
||||
import random as r
|
||||
|
||||
###########################
|
||||
### simple cases (single bytes, two bytes, 10 bytes of same byte)
|
||||
###########################
|
||||
|
||||
## 1 byte cases
|
||||
|
||||
def single_byte_case(byte):
|
||||
'''
|
||||
return the encode/decode pair corresponding to a single byte
|
||||
'''
|
||||
decoded_bytes = bytes([byte])
|
||||
encoded_bytes = b.b58encode(decoded_bytes)
|
||||
return {'db': decoded_bytes, 'eb': encoded_bytes}
|
||||
|
||||
|
||||
def single_byte_cases():
|
||||
'''
|
||||
return the encode/decode pairs corresponding to every single byte case for
|
||||
byte between 0 and 255
|
||||
'''
|
||||
# range(0, 256) = [0, 256) intersect Z
|
||||
return [single_byte_case(n) for n in range(0, 256)]
|
||||
|
||||
## too many of these
|
||||
|
||||
### 2 byte cases
|
||||
#
|
||||
#def two_bytes(n):
|
||||
# '''
|
||||
# return the two bytes corresponding to <<n // 256, n % 256>>
|
||||
# '''
|
||||
# return bytes([n // 256, n % 256])
|
||||
#
|
||||
#
|
||||
#def two_byte_case(n):
|
||||
# '''
|
||||
# return the encode/decode pair corresponding to <<n // 256, n % 256>>
|
||||
# '''
|
||||
# decoded_bytes = two_bytes(n)
|
||||
# encoded_bytes = b.b58encode(decoded_bytes)
|
||||
# return {'db': decoded_bytes, 'eb': encoded_bytes}
|
||||
#
|
||||
#
|
||||
#def two_byte_cases():
|
||||
# '''
|
||||
# return the encode/decode pairs for each two bytes <<n:8, m:8>>
|
||||
# '''
|
||||
# return [two_byte_case(n) for n in range(0, 256*256)]
|
||||
|
||||
|
||||
## 10 byte cases
|
||||
|
||||
def ten_bytes(byte):
|
||||
'''
|
||||
return the ten byte string which is byte repeated 10 times
|
||||
'''
|
||||
return bytes([byte for _ in range(10)])
|
||||
|
||||
|
||||
def ten_byte_case(n):
|
||||
'''
|
||||
return the encode/decode pair corresponding to <<n>> * 10
|
||||
'''
|
||||
decoded_bytes = ten_bytes(n)
|
||||
encoded_bytes = b.b58encode(decoded_bytes)
|
||||
return {'db': decoded_bytes, 'eb': encoded_bytes}
|
||||
|
||||
|
||||
def ten_byte_cases():
|
||||
'''
|
||||
return the encode/decode pairs for each string <<n:8>> * 10
|
||||
'''
|
||||
return [ten_byte_case(n) for n in range(0, 256)]
|
||||
|
||||
|
||||
|
||||
## all simple cases in one function
|
||||
|
||||
def simple_cases():
|
||||
return single_byte_cases() + ten_byte_cases()
|
||||
|
||||
|
||||
###########################
|
||||
### case generation
|
||||
###########################
|
||||
|
||||
def random_bytes():
|
||||
'''
|
||||
return between 0 and 999 random bytes
|
||||
'''
|
||||
# randint is between [left, right]
|
||||
len = r.randint(0, 999)
|
||||
#len = 10
|
||||
acc = []
|
||||
for _ in range(len):
|
||||
# randint is between [left, right]
|
||||
randbyte = r.randint(0, 255)
|
||||
acc.append(randbyte)
|
||||
return bytes(acc)
|
||||
|
||||
|
||||
def case():
|
||||
'''
|
||||
return a random encode/decode pair
|
||||
'''
|
||||
decoded_bytes = random_bytes()
|
||||
encoded_bytes = b.b58encode(decoded_bytes)
|
||||
return {'db': decoded_bytes, 'eb': encoded_bytes}
|
||||
|
||||
|
||||
def cases(n):
|
||||
'''
|
||||
return n randomly generated encode/decode pairs
|
||||
'''
|
||||
return [case() for _ in range(n)]
|
||||
|
||||
|
||||
###########################
|
||||
### js formatting
|
||||
###########################
|
||||
@@ -99,7 +195,7 @@ def format_cases_erl(cases):
|
||||
###########################
|
||||
|
||||
def main():
|
||||
c = cases(100)
|
||||
c = simple_cases() + cases(100_000)
|
||||
#print(format_cases_js(c))
|
||||
print(format_cases_erl(c))
|
||||
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
%-module(b58).
|
||||
%-export([enc/1, dec/1]).
|
||||
|
||||
-mode(compile).
|
||||
%-spec enc(binary()) -> string().
|
||||
%% https://digitalbazaar.github.io/base58-spec/#encode
|
||||
|
||||
main([]) ->
|
||||
{ok, Cases} = file:consult("b58_cases_3.eterms"),
|
||||
DoCase =
|
||||
fun(Case) ->
|
||||
spawn(fun() -> test_case(Case) end)
|
||||
end,
|
||||
lists:foreach(DoCase, Cases).
|
||||
|
||||
test_case({{encoded, E}, {decoded, D}}) ->
|
||||
EncodeOk = E =:= enc(D),
|
||||
DecodeOk = D =:= dec(E),
|
||||
ok =
|
||||
case EncodeOk of
|
||||
true -> ok;
|
||||
false -> io:format("===============================~n"
|
||||
"YOU ARE A FAILURE TO ENCODE~n"
|
||||
"===============================~n"
|
||||
"decoded : ~tw~n"
|
||||
"expected : ~ts~n"
|
||||
"actual : ~ts~n~n",
|
||||
[D, E, enc(D)])
|
||||
end,
|
||||
ok =
|
||||
case DecodeOk of
|
||||
true -> ok;
|
||||
false -> io:format("===============================~n"
|
||||
"YOU ARE A FAILURE TO DECODE~n"
|
||||
"===============================~n"
|
||||
"encoded : ~ts~n"
|
||||
"expected : ~tw~n"
|
||||
"actual : ~tw~n~n",
|
||||
[E, D, dec(E)])
|
||||
end,
|
||||
ok.
|
||||
|
||||
% this was much clearer: https://www.youtube.com/watch?v=GedV3S9X89c
|
||||
|
||||
-spec enc(Bytes) -> Base58
|
||||
when Bytes :: binary(),
|
||||
Base58 :: string().
|
||||
|
||||
enc(Bytes) ->
|
||||
% grab leading 0s
|
||||
{NumLeadingZeros, Rest} = split_zeros(Bytes, 0),
|
||||
NBitsInRest = bit_size(Rest),
|
||||
<<RestBigNum:NBitsInRest>> = Rest,
|
||||
ZerosBase58 = [$1 || _ <- lists:seq(1, NumLeadingZeros)],
|
||||
RestBase58 = enc(RestBigNum, []),
|
||||
ZerosBase58 ++ RestBase58.
|
||||
|
||||
|
||||
|
||||
-spec split_zeros(Bytes, InitZeros) -> {NumLeadingZeros, Rest}
|
||||
when Bytes :: binary(),
|
||||
InitZeros :: integer(),
|
||||
NumLeadingZeros :: binary(),
|
||||
Rest :: binary().
|
||||
|
||||
split_zeros(<<0:8, Rest/binary>>, NumZerosAcc) ->
|
||||
NewNumZerosAcc = NumZerosAcc + 1,
|
||||
split_zeros(Rest, NewNumZerosAcc);
|
||||
split_zeros(Rest, NumZerosAcc) ->
|
||||
{NumZerosAcc, Rest}.
|
||||
|
||||
|
||||
|
||||
-spec enc(BytesBigNum, Base58Acc) -> Base58
|
||||
when BytesBigNum :: integer(),
|
||||
Base58Acc :: [0..57],
|
||||
Base58 :: string().
|
||||
|
||||
enc(0, Acc) ->
|
||||
lists:map(fun int2char/1, Acc);
|
||||
enc(BitNum, Acc) ->
|
||||
Q = BitNum div 58,
|
||||
R = BitNum rem 58,
|
||||
enc(Q, [R | Acc]).
|
||||
|
||||
|
||||
|
||||
-spec dec(Base58) -> DecodedBytes
|
||||
when Base58 :: string(),
|
||||
DecodedBytes :: binary().
|
||||
|
||||
dec(Str) ->
|
||||
% the number of leading 1s tells us the number of leading zeros
|
||||
{NumLeadingZeros, RestStr} = split_ones(Str, 0),
|
||||
LeadingZeros = << <<0>> || _ <- lists:seq(1, NumLeadingZeros) >>,
|
||||
RestNs = lists:map(fun char2int/1, RestStr),
|
||||
RestBytes = dec(RestNs, 0),
|
||||
<<LeadingZeros/binary, RestBytes/binary>>.
|
||||
|
||||
split_ones([$1 | Rest], NOnes) ->
|
||||
split_ones(Rest, NOnes + 1);
|
||||
split_ones(B58Str, NOnes) ->
|
||||
{NOnes, B58Str}.
|
||||
|
||||
|
||||
dec([N | Ns], Acc) ->
|
||||
NewAcc = (Acc*58) + N,
|
||||
dec(Ns, NewAcc);
|
||||
dec([], FinalAccN) ->
|
||||
bignum_to_binary_bige(FinalAccN, <<>>).
|
||||
|
||||
bignum_to_binary_bige(0, Acc) ->
|
||||
Acc;
|
||||
bignum_to_binary_bige(N, Acc) ->
|
||||
Q = N div 256,
|
||||
R = N rem 256,
|
||||
NewAcc = <<R, Acc/binary>>,
|
||||
bignum_to_binary_bige(Q, NewAcc).
|
||||
|
||||
int2char( 0) -> $1;
|
||||
int2char( 1) -> $2;
|
||||
int2char( 2) -> $3;
|
||||
int2char( 3) -> $4;
|
||||
int2char( 4) -> $5;
|
||||
int2char( 5) -> $6;
|
||||
int2char( 6) -> $7;
|
||||
int2char( 7) -> $8;
|
||||
int2char( 8) -> $9;
|
||||
int2char( 9) -> $A;
|
||||
int2char(10) -> $B;
|
||||
int2char(11) -> $C;
|
||||
int2char(12) -> $D;
|
||||
int2char(13) -> $E;
|
||||
int2char(14) -> $F;
|
||||
int2char(15) -> $G;
|
||||
int2char(16) -> $H;
|
||||
int2char(17) -> $J;
|
||||
int2char(18) -> $K;
|
||||
int2char(19) -> $L;
|
||||
int2char(20) -> $M;
|
||||
int2char(21) -> $N;
|
||||
int2char(22) -> $P;
|
||||
int2char(23) -> $Q;
|
||||
int2char(24) -> $R;
|
||||
int2char(25) -> $S;
|
||||
int2char(26) -> $T;
|
||||
int2char(27) -> $U;
|
||||
int2char(28) -> $V;
|
||||
int2char(29) -> $W;
|
||||
int2char(30) -> $X;
|
||||
int2char(31) -> $Y;
|
||||
int2char(32) -> $Z;
|
||||
int2char(33) -> $a;
|
||||
int2char(34) -> $b;
|
||||
int2char(35) -> $c;
|
||||
int2char(36) -> $d;
|
||||
int2char(37) -> $e;
|
||||
int2char(38) -> $f;
|
||||
int2char(39) -> $g;
|
||||
int2char(40) -> $h;
|
||||
int2char(41) -> $i;
|
||||
int2char(42) -> $j;
|
||||
int2char(43) -> $k;
|
||||
int2char(44) -> $m;
|
||||
int2char(45) -> $n;
|
||||
int2char(46) -> $o;
|
||||
int2char(47) -> $p;
|
||||
int2char(48) -> $q;
|
||||
int2char(49) -> $r;
|
||||
int2char(50) -> $s;
|
||||
int2char(51) -> $t;
|
||||
int2char(52) -> $u;
|
||||
int2char(53) -> $v;
|
||||
int2char(54) -> $w;
|
||||
int2char(55) -> $x;
|
||||
int2char(56) -> $y;
|
||||
int2char(57) -> $z.
|
||||
|
||||
char2int($1) -> 0;
|
||||
char2int($2) -> 1;
|
||||
char2int($3) -> 2;
|
||||
char2int($4) -> 3;
|
||||
char2int($5) -> 4;
|
||||
char2int($6) -> 5;
|
||||
char2int($7) -> 6;
|
||||
char2int($8) -> 7;
|
||||
char2int($9) -> 8;
|
||||
char2int($A) -> 9;
|
||||
char2int($B) -> 10;
|
||||
char2int($C) -> 11;
|
||||
char2int($D) -> 12;
|
||||
char2int($E) -> 13;
|
||||
char2int($F) -> 14;
|
||||
char2int($G) -> 15;
|
||||
char2int($H) -> 16;
|
||||
char2int($J) -> 17;
|
||||
char2int($K) -> 18;
|
||||
char2int($L) -> 19;
|
||||
char2int($M) -> 20;
|
||||
char2int($N) -> 21;
|
||||
char2int($P) -> 22;
|
||||
char2int($Q) -> 23;
|
||||
char2int($R) -> 24;
|
||||
char2int($S) -> 25;
|
||||
char2int($T) -> 26;
|
||||
char2int($U) -> 27;
|
||||
char2int($V) -> 28;
|
||||
char2int($W) -> 29;
|
||||
char2int($X) -> 30;
|
||||
char2int($Y) -> 31;
|
||||
char2int($Z) -> 32;
|
||||
char2int($a) -> 33;
|
||||
char2int($b) -> 34;
|
||||
char2int($c) -> 35;
|
||||
char2int($d) -> 36;
|
||||
char2int($e) -> 37;
|
||||
char2int($f) -> 38;
|
||||
char2int($g) -> 39;
|
||||
char2int($h) -> 40;
|
||||
char2int($i) -> 41;
|
||||
char2int($j) -> 42;
|
||||
char2int($k) -> 43;
|
||||
char2int($m) -> 44;
|
||||
char2int($n) -> 45;
|
||||
char2int($o) -> 46;
|
||||
char2int($p) -> 47;
|
||||
char2int($q) -> 48;
|
||||
char2int($r) -> 49;
|
||||
char2int($s) -> 50;
|
||||
char2int($t) -> 51;
|
||||
char2int($u) -> 52;
|
||||
char2int($v) -> 53;
|
||||
char2int($w) -> 54;
|
||||
char2int($x) -> 55;
|
||||
char2int($y) -> 56;
|
||||
char2int($z) -> 57.
|
||||
Reference in New Issue
Block a user