Javascript Put 4 integers in the RGBA range - javascript

I have a function that puts 4 integers in the RGBA range. In other words, it takes 4 integers, puts the first 3 in the 8-bit range (0-255) (decimal don't matter) and puts the 4th number in the range of 0-1.
And then it makes the fillStyle to that color. (It's important that this all happens in the function because I want to use random Math operations on the numbers)
Here's the code:
function FillColor(r,g,b,a){
if (r > 255){r = 255;}
if (g > 255){g = 255;}
if (b > 255){b = 255;}
if (a > 1){a = 1;}
if (r < 0){r = 0;}
if (g < 0){g = 0;}
if (b < 0){b = 0;}
if (a < 0){a = 0;}
ctx.fillStyle = "rgba(" + r + "," + g + "," + b + "," + a + ")";
}
My problem is that it looks unnecessarily long and it mainly just repeats itself. Is there a better way to do this?

Try this:
function FillColor(r, g, b, a) {
for (let i = 0; i < arguments.length; i++) {
if (i === 3) arguments[i] = Math.min(Math.max(parseInt(arguments[i]), 0), 1);
else arguments[i] = Math.min(Math.max(parseInt(arguments[i]), 0), 255);
}
ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${a})`;
}

You can use ternary operator:
r = (r > 255) ? 255 :(r < 0 ) ? 0 : r
example:
<html>
<script type="application/javascript">
function FillCOllor(r) {
r = (r > 255) ? 255 : (r < 0) ? 0 : r
console.log(r)
}
</script>
<body>
<button onclick="FillCOllor(-12)">click</button>
</body>
</html>

// Your code:
/*function FillColor(r,g,b,a){
if (r > 255){r = 255;}
if (g > 255){g = 255;}
if (b > 255){b = 255;}
if (a > 1){a = 1;}
if (r < 0){r = 0;}
if (g < 0){g = 0;}
if (b < 0){b = 0;}
if (a < 0){a = 0;}
ctx.fillStyle = "rgba(" + r + "," + g + "," + b + "," + a + ")";
}*/
// Updated function (assuming you can use ES6/ES2015):
function FillColor(r, g, b, a) {
const rgb = (v) => v < 0 ? 0 : v > 255 ? 255 : v;
const alpha = a < 0 ? 0 : a > 1 ? 1 : a;
// You can replace this "return" with your "ctx.fillStyle", but it doesn't work for this example to log the values out.
return `rgba(${rgb(r)}, ${rgb(g)}, ${rgb(b)}, ${a})`;
}
// Updated function (assuming you are bound to ES5):
function FillColorEs5(r, g, b, a) {
var rgb = function(v) {
return v < 0 ? 0 : v > 255 ? 255 : v;
}
var alpha = a < 0 ? 0 : a > 1 ? 1 : a;
// Same thing here...you can replace the "return" with your "ctx.fillStyle" instead.
return "rgba(" + rgb(r) + ", " + rgb(g) + ", " + rgb(b) + ", " + alpha + ")";
}
// Sample running function:
console.log(FillColor(1, 2, 354, 0.1));
console.log(FillColorEs5(1, 2, 354, 0.1));

function FillColor(red,green,blue,alpha){
let [r,g,b] = [red,green,blue].map(c => Math.max(0, Math.min(255, c)));
let a = Math.max(0, Math.min(1, alpha));
ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${a})`;
}

Related

Efficient way to get longest palindrome subsequence in a string

I'm trying to implement a function that takes a string as input and returns the longest palindrome subsequence in the string.
I've tried using dynamic programming and have come up with the following code:
function longestPalindromicSubsequence(str) {
let n = str.length;
let dp = Array(n);
for (let i = 0; i < n; i++) {
dp[i] = Array(n);
dp[i][i] = 1;
}
for (let cl = 2; cl <= n; cl++) {
for (let i = 0; i < n - cl + 1; i++) {
let j = i + cl - 1;
if (str[i] === str[j] && cl === 2)
dp[i][j] = 2;
else if (str[i] === str[j])
dp[i][j] = dp[i + 1][j - 1] + 2;
else
dp[i][j] = Math.max(dp[i][j - 1], dp[i + 1][j]);
}
}
return dp[0][n - 1];
}
However, this code doesn't seem to be giving me efficient and better results for all test cases. The Time and Space Complexity is also be reduced. I've been struggling with this for days and can't seem to find the issue. Can someone help me figure out what's going wrong and how to fix it?
Oh, I think Dynamic Programming does not work with this sort of problem, because it does not break down recursively, i.e. to find the longest palindrome in a string, you don't need all second-largest palindromes. You can just check at each position and see if it is the center of a palindrome longer than any before. This can be solved with a greedy algorithm:
const pals = "asd1234321fghjkl1234567887654321qwertzu1234321"
function palindromeAtPos(str, pos, checkEven = false){
let ix = 0
const off = checkEven ? 2 : 1
while(pos-ix-1 >= 0 && pos+ix+1+off < str.length && str[pos-ix-1] === str[pos+ix+off]){
ix++
}
return ix === 0 ? str[pos] : str.substring(pos-ix, pos+ix+off)
}
function longestPalindrome(str){
let longest = ''
for(let i = 1; i < str.length; i++){
const odd = palindromeAtPos(str, i)
longest = odd.length > longest.length ? odd : longest
const even = palindromeAtPos(str, i, true)
longest = even.length > longest.length ? even : longest
}
return longest
}
console.log(longestPalindrome(pals))
On paper (and for a string like aaaaaaaaaa), this has quadratic complexity, but for most strings, it will be almost linear.
/*
* s => string
* return [] of strings witch have the max lenth
*/
function maxLenPalindromes(s) {
const l = s.length
let c, z, zz, a, b, a1, b1, maxl = 0, result = []
if (l < 2) return result
for (c = 0; c < l - 1; c++) {
a = -1
if (maxl>(l-c)*2+1) return result
if (c > 0 && s[c - 1] == s[c + 1]) {
zz = Math.min(c, l - c - 1)
for (z = 1; z <= zz; z++) {
if (s[c - z] != s[c + z]) {
a = c - z + 1; b = c + z
break
}
else if (z == zz) {
a = c - z; b = c + z + 1
break
}
}
if (a >= 0) {
if (b-a > maxl) {
result = [s.slice(a, b)]
maxl = b-a
}
else if (b-a == maxl) {
result.push(s.slice(a, b))
}
}
}
a=-1
if (s[c] == s[c + 1]) {
if (c == 0 || c == l - 2) {
a = c; b = c + 2
}
else {
zz = Math.min(c, l - c - 2)
for (z = 1; z <= zz; z++) {
if (s[c - z] != s[c + z + 1]) {
a = c - z + 1; b = c + z + 1
break
}
else if (z == zz) {
a = c - z; b = c + z + 2
break
}
}
}
if (a >= 0) {
if (b-a > maxl) {
result = [s.slice(a, b)]
maxl = b-a
}
else if (b-a == maxl) {
result.push(s.slice(a, b))
}
}
}
}
return result
}
const s1="112233111222333"
const s2="11_22_33_111_222_333"
const s3="12345_54321xqazws_swzaq_qwertytrewq"
const s4="sdfgsdfg1qqqqqAAAAA_123456789o o987654321_AAAAAqqqqq;lakdjvbafgfhfhfghfh"
console.log(maxLenPalindromes(s1))
console.log(maxLenPalindromes(s2))
console.log(maxLenPalindromes(s3))
console.log(maxLenPalindromes(s4))

Submitting an OTP to Microsoft API with RSA encryption

I'm gonna keep this short and clean.
I need to submit an OTP to Microsoft's API. This OTP however, is encrypted on the client side with some JavaScript function and then submitted to the API. That's the Microsoft's script for encryption (the original script has over 2000 lines, I only left functions used by Encrypt() function. I believe it is just plain RSA encryption in JavaScript but I could be wrong):
function Encrypt(e, t, i, r) {
var n = [];
switch (i.toLowerCase()) {
case "saproof":
if (null == t) {
return null
}
n = PackageSADataForProof(t);
break;
case "newpwd":
if (null == r) {
return null
}
}
if (null == n || "undefined" == typeof n) {
return n
}
if ("undefined" != typeof Key && void 0 !== parseRSAKeyFromString) {
var o = parseRSAKeyFromString(Key)
}
var s = RSAEncrypt(n, o, randomNum);
return s
}
function PackageSADataForProof(e) {
var t, i = [], r = 0;
for (t = 0; t < e.length; t++) {
i[r++] = 127 & e.charCodeAt(t),
i[r++] = (65280 & e.charCodeAt(t)) >> 8
}
return i
}
function parseRSAKeyFromString(e) {
var t = e.indexOf(";");
if (0 > t) {
return null
}
var i = e.substr(0, t)
, r = e.substr(t + 1)
, n = i.indexOf("=");
if (0 > n) {
return null
}
var o = i.substr(n + 1);
if (n = r.indexOf("="),
0 > n) {
return null
}
var s = r.substr(n + 1)
, a = new Object;
return a.n = hexStringToMP(s),
a.e = parseInt(o, 16),
a
}
function hexStringToMP(e) {
var t, i, r = Math.ceil(e.length / 4), n = new JSMPnumber;
for (n.size = r,
t = 0; r > t; t++) {
i = e.substr(4 * t, 4),
n.data[r - 1 - t] = parseInt(i, 16)
}
return n
}
function RSAEncrypt(e, t) {
for (var i = [], r = 42, n = 2 * t.n.size - r, o = 0; o < e.length; o += n) {
if (o + n >= e.length) {
var s = RSAEncryptBlock(e.slice(o), t, randomNum);
s && (i = s.concat(i))
} else {
var s = RSAEncryptBlock(e.slice(o, o + n), t, randomNum);
s && (i = s.concat(i))
}
}
var a = byteArrayToBase64(i);
return a
}
function RSAEncryptBlock(e, t, i) {
var r = t.n
, n = t.e
, o = e.length
, s = 2 * r.size
, a = 42;
if (o + a > s) {
return null
}
applyPKCSv2Padding(e, s, i),
e = e.reverse();
var l = byteArrayToMP(e)
, d = modularExp(l, n, r);
d.size = r.size;
var h = mpToByteArray(d);
return h = h.reverse()
}
function JSMPnumber() {
this.size = 1,
this.data = [],
this.data[0] = 0
}
function byteArrayToMP(e) {
var t = new JSMPnumber
, i = 0
, r = e.length
, n = r >> 1;
for (i = 0; n > i; i++) {
t.data[i] = e[2 * i] + (e[1 + 2 * i] << 8)
}
return r % 2 && (t.data[i++] = e[r - 1]),
t.size = i,
t
}
function modularExp(e, t, i) {
for (var r = [], n = 0; t > 0; ) {
r[n] = 1 & t,
t >>>= 1,
n++
}
for (var o = duplicateMP(e), s = n - 2; s >= 0; s--) {
o = modularMultiply(o, o, i),
1 == r[s] && (o = modularMultiply(o, e, i))
}
return o
}
function modularMultiply(e, t, i) {
var r = multiplyMP(e, t)
, n = divideMP(r, i);
return n.r
}
function multiplyMP(e, t) {
var i = new JSMPnumber;
i.size = e.size + t.size;
var r, n;
for (r = 0; r < i.size; r++) {
i.data[r] = 0
}
var o = e.data
, s = t.data
, a = i.data;
if (e == t) {
for (r = 0; r < e.size; r++) {
a[2 * r] += o[r] * o[r]
}
for (r = 1; r < e.size; r++) {
for (n = 0; r > n; n++) {
a[r + n] += 2 * o[r] * o[n]
}
}
} else {
for (r = 0; r < e.size; r++) {
for (n = 0; n < t.size; n++) {
a[r + n] += o[r] * s[n]
}
}
}
return normalizeJSMP(i),
i
}
function normalizeJSMP(e) {
var t, i, r, n, o;
for (r = e.size,
i = 0,
t = 0; r > t; t++) {
n = e.data[t],
n += i,
o = n,
i = Math.floor(n / 65536),
n -= 65536 * i,
e.data[t] = n
}
}
function removeLeadingZeroes(e) {
for (var t = e.size - 1; t > 0 && 0 == e.data[t--]; ) {
e.size--
}
}
function divideMP(e, t) {
var i = e.size
, r = t.size
, n = t.data[r - 1]
, o = t.data[r - 1] + t.data[r - 2] / 65536
, s = new JSMPnumber;
s.size = i - r + 1,
e.data[i] = 0;
for (var a = i - 1; a >= r - 1; a--) {
var l = a - r + 1
, d = Math.floor((65536 * e.data[a + 1] + e.data[a]) / o);
if (d > 0) {
var h = multiplyAndSubtract(e, d, t, l);
for (0 > h && (d--,
multiplyAndSubtract(e, d, t, l)); h > 0 && e.data[a] >= n; ) {
h = multiplyAndSubtract(e, 1, t, l),
h > 0 && d++
}
}
s.data[l] = d
}
removeLeadingZeroes(e);
var u = {
"q": s,
"r": e
};
return u
}
function multiplyAndSubtract(e, t, i, r) {
var n, o = e.data.slice(0), s = 0, a = e.data;
for (n = 0; n < i.size; n++) {
var l = s + i.data[n] * t;
s = l >>> 16,
l -= 65536 * s,
l > a[n + r] ? (a[n + r] += 65536 - l,
s++) : a[n + r] -= l
}
return s > 0 && (a[n + r] -= s),
a[n + r] < 0 ? (e.data = o.slice(0),
-1) : 1
}
function applyPKCSv2Padding(e, t, i) {
var r, n = e.length, o = [218, 57, 163, 238, 94, 107, 75, 13, 50, 85, 191, 239, 149, 96, 24, 144, 175, 216, 7, 9], s = t - n - 40 - 2, a = [];
for (r = 0; s > r; r++) {
a[r] = 0
}
a[s] = 1;
var l = o.concat(a, e)
, d = [];
for (r = 0; 20 > r; r++) {
d[r] = Math.floor(256 * Math.random())
}
d = SHA1(d.concat(i));
var h = MGF(d, t - 21)
, u = XORarrays(l, h)
, c = MGF(u, 20)
, p = XORarrays(d, c)
, f = [];
for (f[0] = 0,
f = f.concat(p, u),
r = 0; r < f.length; r++) {
e[r] = f[r]
}
}
function MGF(e, t) {
if (t > 4096) {
return null
}
var i = e.slice(0)
, r = i.length;
i[r++] = 0,
i[r++] = 0,
i[r++] = 0,
i[r] = 0;
for (var n = 0, o = []; o.length < t; ) {
i[r] = n++,
o = o.concat(SHA1(i))
}
return o.slice(0, t)
}
function XORarrays(e, t) {
if (e.length != t.length) {
return null
}
for (var i = [], r = e.length, n = 0; r > n; n++) {
i[n] = e[n] ^ t[n]
}
return i
}
function SHA1(e) {
var t, i = e.slice(0);
PadSHA1Input(i);
var r = {
"A": 1732584193,
"B": 4023233417,
"C": 2562383102,
"D": 271733878,
"E": 3285377520
};
for (t = 0; t < i.length; t += 64) {
SHA1RoundFunction(r, i, t)
}
var n = [];
return wordToBytes(r.A, n, 0),
wordToBytes(r.B, n, 4),
wordToBytes(r.C, n, 8),
wordToBytes(r.D, n, 12),
wordToBytes(r.E, n, 16),
n
}
function wordToBytes(e, t, i) {
var r;
for (r = 3; r >= 0; r--) {
t[i + r] = 255 & e,
e >>>= 8
}
}
function PadSHA1Input(e) {
var t, i = e.length, r = i, n = i % 64, o = 55 > n ? 56 : 120;
for (e[r++] = 128,
t = n + 1; o > t; t++) {
e[r++] = 0
}
var s = 8 * i;
for (t = 1; 8 > t; t++) {
e[r + 8 - t] = 255 & s,
s >>>= 8
}
}
function SHA1RoundFunction(e, t, i) {
var r, n, o, s = 1518500249, a = 1859775393, l = 2400959708, d = 3395469782, h = [], u = e.A, c = e.B, p = e.C, f = e.D, m = e.E;
for (n = 0,
o = i; 16 > n; n++,
o += 4) {
h[n] = t[o] << 24 | t[o + 1] << 16 | t[o + 2] << 8 | t[o + 3] << 0
}
for (n = 16; 80 > n; n++) {
h[n] = rotateLeft(h[n - 3] ^ h[n - 8] ^ h[n - 14] ^ h[n - 16], 1)
}
var g;
for (r = 0; 20 > r; r++) {
g = rotateLeft(u, 5) + (c & p | ~c & f) + m + h[r] + s & 4294967295,
m = f,
f = p,
p = rotateLeft(c, 30),
c = u,
u = g
}
for (r = 20; 40 > r; r++) {
g = rotateLeft(u, 5) + (c ^ p ^ f) + m + h[r] + a & 4294967295,
m = f,
f = p,
p = rotateLeft(c, 30),
c = u,
u = g
}
for (r = 40; 60 > r; r++) {
g = rotateLeft(u, 5) + (c & p | c & f | p & f) + m + h[r] + l & 4294967295,
m = f,
f = p,
p = rotateLeft(c, 30),
c = u,
u = g
}
for (r = 60; 80 > r; r++) {
g = rotateLeft(u, 5) + (c ^ p ^ f) + m + h[r] + d & 4294967295,
m = f,
f = p,
p = rotateLeft(c, 30),
c = u,
u = g
}
e.A = e.A + u & 4294967295,
e.B = e.B + c & 4294967295,
e.C = e.C + p & 4294967295,
e.D = e.D + f & 4294967295,
e.E = e.E + m & 4294967295
}
function rotateLeft(e, t) {
var i = e >>> 32 - t
, r = (1 << 32 - t) - 1
, n = e & r;
return n << t | i
}
function hexStringToMP(e) {
var t, i, r = Math.ceil(e.length / 4), n = new JSMPnumber;
for (n.size = r,
t = 0; r > t; t++) {
i = e.substr(4 * t, 4),
n.data[r - 1 - t] = parseInt(i, 16)
}
return n
}
function duplicateMP(e) {
var t = new JSMPnumber;
return t.size = e.size,
t.data = e.data.slice(0),
t
}
function mpToByteArray(e) {
var t = []
, i = 0
, r = e.size;
for (i = 0; r > i; i++) {
t[2 * i] = 255 & e.data[i];
var n = e.data[i] >>> 8;
t[2 * i + 1] = n
}
return t
}
function byteArrayToBase64(e) {
var t, i, r = e.length, n = "";
for (t = r - 3; t >= 0; t -= 3) {
i = e[t] | e[t + 1] << 8 | e[t + 2] << 16,
n += base64Encode(i, 4)
}
var o = r % 3;
for (i = 0,
t += 2; t >= 0; t--) {
i = i << 8 | e[t]
}
return 1 == o ? n = n + base64Encode(i << 16, 2) + "==" : 2 == o && (n = n + base64Encode(i << 8, 3) + "="),
n
}
function base64Encode(e, t) {
var i, r = "";
for (i = t; 4 > i; i++) {
e >>= 6
}
for (i = 0; t > i; i++) {
r = mapByteToBase64(63 & e) + r,
e >>= 6
}
return r
}
function mapByteToBase64(e) {
return e >= 0 && 26 > e ? String.fromCharCode(65 + e) : e >= 26 && 52 > e ? String.fromCharCode(97 + e - 26) : e >= 52 && 62 > e ? String.fromCharCode(48 + e - 52) : 62 == e ? "+" : "/"
}
var Key = "e=10001;m=d0fa1d37fa0bb621a8cbb6669249ba1d14bbd5058592f050240d8c3b68674f0e28283018a7753f4377aaa3b3645e5f119a0032129a0a64322f74888aed3519de49e98c5b3c221460218140616f01ac5e9f2f8042e2749b8a89112f15310690dad7531f6758c0c65e525dff7859283b566a5b154352c57161cd24e59133a61432f461583e40cac749d722909dfcf0edd6af3cbc9a25e639b0caaf55e8c7b08b53c7d52038b48e1b26ad40f8bb84b3bb9c92bc9b947d2ab5ae4664a5093a4895af09659a78c9393797ea76b5b9416a45025e2ab3ea1627f08d85abd22e156d3e842efbaa1d0e1e4885028b2bc0aa7be8e444799e96fce0444f2b56bd14c0244b4d"
var randomNum = "AA278C7C00D44877AA95055BB0497A6169195B7B79C664E0AC9DFDCE1112CE28282BAA83D5CD95041CB512CD35624CCD6FD873C98579E4D3C4D25E5E6134F65628BDA9DE9C00A6E53A0194EA7483BCB1AABD8AA983282259E2953CC8705D36BB9936E57E"
console.log(Encrypt(null, "1234", "saproof"))
Example output from above code
V2loAc3ik+qXTJMVF/V/0yKdbQeKGqO7UIA82cqafWUPJ6ALYd/6Bwb9QFsJOEC+yKfwqu5YE36+J3Dpsuk14EQG4YktFVao5D2i5C/2Akm5i1WhPDMbHUFfUJtxbQ3Ldc0jgpMpOrhuEkQ/u9MUgL3l1tL08GTvl4KdnvW2delt1HpuyGFI11WNb5/xXbzmZvRsF2fc3tNpZCvHSTCEQuMOzsQSTeghttXEBFFvmqC9fwH+KjiBGwl11zyH+shv8kYi+LRaqN2LoVz4eFMmWDJ0PNNeA7Aq+mQ/9BIY+tz7Tzz51OSlCgajsPnJbxyHiURdUrc103oKdja8Vd9dnw==
The main function here is Encrypt(). My program is written in Python. I tried encrypting my OTP using Python's rsa module but to no avail. The API rejected the request and marked the encrypted OTP as invalid.
import rsa
import base64
Key = "d0fa1d37fa0bb621a8cbb6669249ba1d14bbd5058592f050240d8c3b68674f0e28283018a7753f4377aaa3b3645e5f119a0032129a0a64322f74888aed3519de49e98c5b3c221460218140616f01ac5e9f2f8042e2749b8a89112f15310690dad7531f6758c0c65e525dff7859283b566a5b154352c57161cd24e59133a61432f461583e40cac749d722909dfcf0edd6af3cbc9a25e639b0caaf55e8c7b08b53c7d52038b48e1b26ad40f8bb84b3bb9c92bc9b947d2ab5ae4664a5093a4895af09659a78c9393797ea76b5b9416a45025e2ab3ea1627f08d85abd22e156d3e842efbaa1d0e1e4885028b2bc0aa7be8e444799e96fce0444f2b56bd14c0244b4d"
encrypted = rsa.encrypt(b'1234', rsa.PublicKey(int(Key, 16), 65537))
b64encrypted = base64.b64encode(encrypted)
print(b64encrypted.decode('utf-8'))
So my question is, how can I use Microsoft's encryption function in Python? Do I need to manually translate the code myself, or maybe I am doing something wrong with rsa module?
Thanks for help.
The JavaScript code uses RSA with OAEP as padding and SHA-1 for both digests (see applyPKCSv2Padding()). In addition, the plaintext is encoded with UTF-16LE (see PackageSADataForProof()) and the ciphertext is encoded in little endian order (see byteArrayToBase64()).
The RSA library used does not support OAEP, see issue #68. A possible library that supports OAEP is PyCryptodome and a possible implementation that is functionally identical to the JavaScript code is (strictly speaking, this applies only to plaintexts up to 214 bytes, for longer ones see the next section):
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
import base64
modulusHex = 'd0fa1d37fa0bb621a8cbb6669249ba1d14bbd5058592f050240d8c3b68674f0e28283018a7753f4377aaa3b3645e5f119a0032129a0a64322f74888aed3519de49e98c5b3c221460218140616f01ac5e9f2f8042e2749b8a89112f15310690dad7531f6758c0c65e525dff7859283b566a5b154352c57161cd24e59133a61432f461583e40cac749d722909dfcf0edd6af3cbc9a25e639b0caaf55e8c7b08b53c7d52038b48e1b26ad40f8bb84b3bb9c92bc9b947d2ab5ae4664a5093a4895af09659a78c9393797ea76b5b9416a45025e2ab3ea1627f08d85abd22e156d3e842efbaa1d0e1e4885028b2bc0aa7be8e444799e96fce0444f2b56bd14c0244b4d';
pubExpHex = '010001'
plaintextStr = '1234'
modulus = int(modulusHex, 16)
pubExp = int(pubExpHex, 16)
plaintext = plaintextStr.encode('utf-16le') # encode plaintext with UTF-16LE
publicKey = RSA.construct((modulus, pubExp))
cipher = PKCS1_OAEP.new(publicKey) # apply OAEP as padding
ciphertext = cipher.encrypt(plaintext)
ciphertextReversed = ciphertext[::-1] # encode ciphertext in little endian order
ciphertextReversedB64 = base64.b64encode(ciphertextReversed)
print(ciphertextReversedB64)
Note that OAEP is not deterministic, i.e. repeated encryption with the same key and plaintext gives different ciphertexts. Therefore, the implementation cannot be verified by comparing the ciphertexts, but only by a successful decryption (see the last section).
Plaintexts, larger than 214 bytes: The posted JavaScript code implements a rather unusual feature: RSA can only encrypt plaintexts whose maximum length is equal to the key length (here 2048 bits = 256 bytes) minus the space required by the padding (here for OAEP with SHA-1: 42 bytes), i.e. the maximum length here is 256 - 42 = 214 bytes, see here.
But the Java Script code posted here splits the plaintext into blocks of 214 bytes (or less in the case of the last block), encrypts each block separately and concatenates the ciphertexts. This allows encryption of arbitrarily long plaintexts.
The Python code snippet above does not take this into account, since it is not needed for the short plaintext 1234 used in the example. But for plaintexts larger than 214 bytes this has to be added.
Note that usually long plaintexts are not encrypted this way, but with hybrid encryption, in which e.g. RSA is combined with AES: The plaintext is encrypted with AES, the AES key with RSA.
Test: The JavaScript code below decrypts a ciphertext generated with the JavaScript code posted in the question and a ciphertext generated with the Python code posted in this answer.
Result: Both ciphertexts can be decrypted with the same logic, which shows that the JavaScript and Python encryption code are functionally identical.
Note that a new key pair was used for this test, since only the public key was posted in the question, and that the public key of this new key pair must be applied when generating the ciphertexts (see JavaScript code for encryption) so that the private key used in decryption matches.
(async () => {
function Encrypt(e, t, i, r) {
var n = [];
switch (i.toLowerCase()) {
case "saproof":
if (null == t) {
return null
}
n = PackageSADataForProof(t);
break;
case "newpwd":
if (null == r) {
return null
}
}
if (null == n || "undefined" == typeof n) {
return n
}
if ("undefined" != typeof Key && void 0 !== parseRSAKeyFromString) {
var o = parseRSAKeyFromString(Key)
}
var s = RSAEncrypt(n, o, randomNum);
return s
}
function PackageSADataForProof(e) {
var t, i = [], r = 0;
for (t = 0; t < e.length; t++) {
i[r++] = 127 & e.charCodeAt(t),
i[r++] = (65280 & e.charCodeAt(t)) >> 8
}
return i
}
function parseRSAKeyFromString(e) {
var t = e.indexOf(";");
if (0 > t) {
return null
}
var i = e.substr(0, t)
, r = e.substr(t + 1)
, n = i.indexOf("=");
if (0 > n) {
return null
}
var o = i.substr(n + 1);
if (n = r.indexOf("="),
0 > n) {
return null
}
var s = r.substr(n + 1)
, a = new Object;
return a.n = hexStringToMP(s),
a.e = parseInt(o, 16),
a
}
function hexStringToMP(e) {
var t, i, r = Math.ceil(e.length / 4), n = new JSMPnumber;
for (n.size = r,
t = 0; r > t; t++) {
i = e.substr(4 * t, 4),
n.data[r - 1 - t] = parseInt(i, 16)
}
return n
}
function RSAEncrypt(e, t) {
for (var i = [], r = 42, n = 2 * t.n.size - r, o = 0; o < e.length; o += n) {
if (o + n >= e.length) {
var s = RSAEncryptBlock(e.slice(o), t, randomNum);
s && (i = s.concat(i))
} else {
var s = RSAEncryptBlock(e.slice(o, o + n), t, randomNum);
s && (i = s.concat(i))
}
}
var a = byteArrayToBase64(i);
return a
}
function RSAEncryptBlock(e, t, i) {
var r = t.n
, n = t.e
, o = e.length
, s = 2 * r.size
, a = 42;
if (o + a > s) {
return null
}
applyPKCSv2Padding(e, s, i),
e = e.reverse();
var l = byteArrayToMP(e)
, d = modularExp(l, n, r);
d.size = r.size;
var h = mpToByteArray(d);
return h = h.reverse()
}
function JSMPnumber() {
this.size = 1,
this.data = [],
this.data[0] = 0
}
function byteArrayToMP(e) {
var t = new JSMPnumber
, i = 0
, r = e.length
, n = r >> 1;
for (i = 0; n > i; i++) {
t.data[i] = e[2 * i] + (e[1 + 2 * i] << 8)
}
return r % 2 && (t.data[i++] = e[r - 1]),
t.size = i,
t
}
function modularExp(e, t, i) {
for (var r = [], n = 0; t > 0; ) {
r[n] = 1 & t,
t >>>= 1,
n++
}
for (var o = duplicateMP(e), s = n - 2; s >= 0; s--) {
o = modularMultiply(o, o, i),
1 == r[s] && (o = modularMultiply(o, e, i))
}
return o
}
function modularMultiply(e, t, i) {
var r = multiplyMP(e, t)
, n = divideMP(r, i);
return n.r
}
function multiplyMP(e, t) {
var i = new JSMPnumber;
i.size = e.size + t.size;
var r, n;
for (r = 0; r < i.size; r++) {
i.data[r] = 0
}
var o = e.data
, s = t.data
, a = i.data;
if (e == t) {
for (r = 0; r < e.size; r++) {
a[2 * r] += o[r] * o[r]
}
for (r = 1; r < e.size; r++) {
for (n = 0; r > n; n++) {
a[r + n] += 2 * o[r] * o[n]
}
}
} else {
for (r = 0; r < e.size; r++) {
for (n = 0; n < t.size; n++) {
a[r + n] += o[r] * s[n]
}
}
}
return normalizeJSMP(i),
i
}
function normalizeJSMP(e) {
var t, i, r, n, o;
for (r = e.size,
i = 0,
t = 0; r > t; t++) {
n = e.data[t],
n += i,
o = n,
i = Math.floor(n / 65536),
n -= 65536 * i,
e.data[t] = n
}
}
function removeLeadingZeroes(e) {
for (var t = e.size - 1; t > 0 && 0 == e.data[t--]; ) {
e.size--
}
}
function divideMP(e, t) {
var i = e.size
, r = t.size
, n = t.data[r - 1]
, o = t.data[r - 1] + t.data[r - 2] / 65536
, s = new JSMPnumber;
s.size = i - r + 1,
e.data[i] = 0;
for (var a = i - 1; a >= r - 1; a--) {
var l = a - r + 1
, d = Math.floor((65536 * e.data[a + 1] + e.data[a]) / o);
if (d > 0) {
var h = multiplyAndSubtract(e, d, t, l);
for (0 > h && (d--,
multiplyAndSubtract(e, d, t, l)); h > 0 && e.data[a] >= n; ) {
h = multiplyAndSubtract(e, 1, t, l),
h > 0 && d++
}
}
s.data[l] = d
}
removeLeadingZeroes(e);
var u = {
"q": s,
"r": e
};
return u
}
function multiplyAndSubtract(e, t, i, r) {
var n, o = e.data.slice(0), s = 0, a = e.data;
for (n = 0; n < i.size; n++) {
var l = s + i.data[n] * t;
s = l >>> 16,
l -= 65536 * s,
l > a[n + r] ? (a[n + r] += 65536 - l,
s++) : a[n + r] -= l
}
return s > 0 && (a[n + r] -= s),
a[n + r] < 0 ? (e.data = o.slice(0),
-1) : 1
}
function applyPKCSv2Padding(e, t, i) {
var r, n = e.length, o = [218, 57, 163, 238, 94, 107, 75, 13, 50, 85, 191, 239, 149, 96, 24, 144, 175, 216, 7, 9], s = t - n - 40 - 2, a = [];
for (r = 0; s > r; r++) {
a[r] = 0
}
a[s] = 1;
var l = o.concat(a, e)
, d = [];
for (r = 0; 20 > r; r++) {
d[r] = Math.floor(256 * Math.random())
}
d = SHA1(d.concat(i));
var h = MGF(d, t - 21)
, u = XORarrays(l, h)
, c = MGF(u, 20)
, p = XORarrays(d, c)
, f = [];
for (f[0] = 0,
f = f.concat(p, u),
r = 0; r < f.length; r++) {
e[r] = f[r]
}
}
function MGF(e, t) {
if (t > 4096) {
return null
}
var i = e.slice(0)
, r = i.length;
i[r++] = 0,
i[r++] = 0,
i[r++] = 0,
i[r] = 0;
for (var n = 0, o = []; o.length < t; ) {
i[r] = n++,
o = o.concat(SHA1(i))
}
return o.slice(0, t)
}
function XORarrays(e, t) {
if (e.length != t.length) {
return null
}
for (var i = [], r = e.length, n = 0; r > n; n++) {
i[n] = e[n] ^ t[n]
}
return i
}
function SHA1(e) {
var t, i = e.slice(0);
PadSHA1Input(i);
var r = {
"A": 1732584193,
"B": 4023233417,
"C": 2562383102,
"D": 271733878,
"E": 3285377520
};
for (t = 0; t < i.length; t += 64) {
SHA1RoundFunction(r, i, t)
}
var n = [];
return wordToBytes(r.A, n, 0),
wordToBytes(r.B, n, 4),
wordToBytes(r.C, n, 8),
wordToBytes(r.D, n, 12),
wordToBytes(r.E, n, 16),
n
}
function wordToBytes(e, t, i) {
var r;
for (r = 3; r >= 0; r--) {
t[i + r] = 255 & e,
e >>>= 8
}
}
function PadSHA1Input(e) {
var t, i = e.length, r = i, n = i % 64, o = 55 > n ? 56 : 120;
for (e[r++] = 128,
t = n + 1; o > t; t++) {
e[r++] = 0
}
var s = 8 * i;
for (t = 1; 8 > t; t++) {
e[r + 8 - t] = 255 & s,
s >>>= 8
}
}
function SHA1RoundFunction(e, t, i) {
var r, n, o, s = 1518500249, a = 1859775393, l = 2400959708, d = 3395469782, h = [], u = e.A, c = e.B, p = e.C, f = e.D, m = e.E;
for (n = 0,
o = i; 16 > n; n++,
o += 4) {
h[n] = t[o] << 24 | t[o + 1] << 16 | t[o + 2] << 8 | t[o + 3] << 0
}
for (n = 16; 80 > n; n++) {
h[n] = rotateLeft(h[n - 3] ^ h[n - 8] ^ h[n - 14] ^ h[n - 16], 1)
}
var g;
for (r = 0; 20 > r; r++) {
g = rotateLeft(u, 5) + (c & p | ~c & f) + m + h[r] + s & 4294967295,
m = f,
f = p,
p = rotateLeft(c, 30),
c = u,
u = g
}
for (r = 20; 40 > r; r++) {
g = rotateLeft(u, 5) + (c ^ p ^ f) + m + h[r] + a & 4294967295,
m = f,
f = p,
p = rotateLeft(c, 30),
c = u,
u = g
}
for (r = 40; 60 > r; r++) {
g = rotateLeft(u, 5) + (c & p | c & f | p & f) + m + h[r] + l & 4294967295,
m = f,
f = p,
p = rotateLeft(c, 30),
c = u,
u = g
}
for (r = 60; 80 > r; r++) {
g = rotateLeft(u, 5) + (c ^ p ^ f) + m + h[r] + d & 4294967295,
m = f,
f = p,
p = rotateLeft(c, 30),
c = u,
u = g
}
e.A = e.A + u & 4294967295,
e.B = e.B + c & 4294967295,
e.C = e.C + p & 4294967295,
e.D = e.D + f & 4294967295,
e.E = e.E + m & 4294967295
}
function rotateLeft(e, t) {
var i = e >>> 32 - t
, r = (1 << 32 - t) - 1
, n = e & r;
return n << t | i
}
function hexStringToMP(e) {
var t, i, r = Math.ceil(e.length / 4), n = new JSMPnumber;
for (n.size = r,
t = 0; r > t; t++) {
i = e.substr(4 * t, 4),
n.data[r - 1 - t] = parseInt(i, 16)
}
return n
}
function duplicateMP(e) {
var t = new JSMPnumber;
return t.size = e.size,
t.data = e.data.slice(0),
t
}
function mpToByteArray(e) {
var t = []
, i = 0
, r = e.size;
for (i = 0; r > i; i++) {
t[2 * i] = 255 & e.data[i];
var n = e.data[i] >>> 8;
t[2 * i + 1] = n
}
return t
}
function byteArrayToBase64(e) {
var t, i, r = e.length, n = "";
for (t = r - 3; t >= 0; t -= 3) {
i = e[t] | e[t + 1] << 8 | e[t + 2] << 16,
n += base64Encode(i, 4)
}
var o = r % 3;
for (i = 0,
t += 2; t >= 0; t--) {
i = i << 8 | e[t]
}
return 1 == o ? n = n + base64Encode(i << 16, 2) + "==" : 2 == o && (n = n + base64Encode(i << 8, 3) + "="),
n
}
function base64Encode(e, t) {
var i, r = "";
for (i = t; 4 > i; i++) {
e >>= 6
}
for (i = 0; t > i; i++) {
r = mapByteToBase64(63 & e) + r,
e >>= 6
}
return r
}
function mapByteToBase64(e) {
return e >= 0 && 26 > e ? String.fromCharCode(65 + e) : e >= 26 && 52 > e ? String.fromCharCode(97 + e - 26) : e >= 52 && 62 > e ? String.fromCharCode(48 + e - 52) : 62 == e ? "+" : "/"
}
var Key = "e=10001;m=ba71796836ba1c27cb30c23f3192d3e610e4df4e0253eca914c162063a3041d50c40a60767e7e4941ec6a4bc426adc5827f859eeb8df1c7dca96adb4fd8d446d80d1a29c9349f92b4f33f3c2c5f852bfe5db90ad75095d847093320c1ffc4bff6ee04da1b7f375913e0e176fe654302ad8c8e379432af022e6411eb764c5c1f25c26b06244978470b7d58164d7191427ee09e058aca452ee6b4bcdde014d711fd14ba2341fca26bcf7f13292238eeffdd45b077e3004d9f472e34b1dbf2dfde0da3afcd5e89f12660396b8bf399a783a166efb4068d4b5e5a024defaf9884366025fb11ab543aec9032dd95c31e2e57e77f0370cfe8fb4c1812a917c4ade221b"
var randomNum = "AA278C7C00D44877AA95055BB0497A6169195B7B79C664E0AC9DFDCE1112CE28282BAA83D5CD95041CB512CD35624CCD6FD873C98579E4D3C4D25E5E6134F65628BDA9DE9C00A6E53A0194EA7483BCB1AABD8AA983282259E2953CC8705D36BB9936E57E"
var ciphertextB64FromJS = Encrypt(null, "1234", "saproof");
document.getElementById("js_enc").innerHTML = "JavaScript code (encryption): " + ciphertextB64FromJS;
// Decryption ======================================================================================================================================================
// Decryption of a ciphertext from the JavaScript Code
var decryptedCiphertextFromJS = await decrypt(ciphertextB64FromJS);
document.getElementById("js_dec").innerHTML = "JavaScript code (decryption): " + decryptedCiphertextFromJS;
// Decryption of a ciphertext from the Python code for encryption
var ciphertextB64FromPy = 'iQefWJtEXRjMpJj59NmODmDVuJJkmsSV2pNvPrAX74lDWiXHjY4H34XAEGHY5bJ/3xJ3f7pM1R0Nb8cBJSgQMpCO/0PCdDSbalw7M/cbEEOzrIVMxg8NXOsUM6tqetaroSAutyesg8+EsP4liow3ssV6I7cX/QDpunFV0vRHxTM9Am35QNrNfpvZMu4kV642dq9ocSJLdbaBfaKXUyBA6nYzUIhq3nHx8XzPxo9DnAoE6qkGeRpQzV7Mo+jeY26YOP/DyVmb0JuOXPI8Uz/4yxhQp7ygAVOF5CNojZN0XtZVqORV4+2bFEMD+Fi9YIIFFMrym169ACoy2faTfLYjlw=='; // MAKE SURE TO USE THE CORRECT PUBLIC KEY DURING ENCRYPTION!!!: modulus = 0xba717968..., public exponent = 0x10001 (s. above)
var decryptedCiphertextFromPy = await decrypt(ciphertextB64FromPy);
document.getElementById("py_dec").innerHTML = "Python code (decryption): " + decryptedCiphertextFromPy;
async function decrypt(ciphertextBase64){
var pkcs8Der = b642ab('MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6cXloNrocJ8swwj8xktPmEOTfTgJT7KkUwWIGOjBB1QxApgdn5+SUHsakvEJq3Fgn+FnuuN8cfcqWrbT9jURtgNGinJNJ+StPM/PCxfhSv+XbkK11CV2EcJMyDB/8S/9u4E2ht/N1kT4OF2/mVDAq2MjjeUMq8CLmQR63ZMXB8lwmsGJEl4Rwt9WBZNcZFCfuCeBYrKRS7mtLzd4BTXEf0UuiNB/KJrz38TKSI47v/dRbB34wBNn0cuNLHb8t/eDaOvzV6J8SZgOWuL85mng6Fm77QGjUteWgJN76+YhDZgJfsRq1Q67JAy3ZXDHi5X538DcM/o+0wYEqkXxK3iIbAgMBAAECggEASlJj0ExIomKmmBhG8q8SM1s2sWG6gdQMjs6MEeluRT/1c2v79cq2Dum5y/+UBl8x8TUKPKSLpCLs+GXkiVKgHXrFlqoN+OYQArG2EUWzuODwczdYPhhupBXwR3oX4g41k/BsYfQfZBVzBFEJdWrIDLyAUFWNlfdGIj2BTiAoySfyqmamvmW8bsvc8coiGlZ28UC85/Xqx9wOzjeGoRkCH7PcTMlc9F7SxSthwX/k1VBXmNOHa+HzGOgO/W3k1LDqJbq2wKjZTW3iVEg2VodjxgBLMm0MueSGoI6IuaZSPMyFEM3gGvC2+cDBI2SL/amhiTUa/VDlTVw/IKbSuar9uQKBgQDd76M0Po5Lqh8ZhQ3obhFqkfO5EBXy7HUL15cw51kVtwF6Gf/J2HNHjwsg9Nb0eJETTS6bbuVd9bn884JoRS986nVTFNZ4dnjEgKjjQ8GjfzdkpbUxsRLWiIxuOQSpIUZGdMi2ctTTtspvMsDsjRRYdYIQCe/SDsdHGT3vcUCybwKBgQDXDz6iVnY84Fh5iDDVrQOR4lYoxCL/ikCDJjC6y1mjR0eVFdBPQ4j1dDSPU9lahBLby0VyagQCDp/kxQOl0z2zBLRI4I8jUtz9/9KW6ze7U7dQJ7OTfumd5I97OyQOG9XZwKUkRgfyb/PAMBSUSLgosi38f+OC3IN3qlvHFzvxFQKBgQCITpUDEmSczih5qQGIvolN1cRF5j5Ey7t7gXbnXz+Umah7kJpMIvdyfMVOAXJABgi8PQwiBLM0ySXo2LpARjXLV8ilNUggBktYDNktc8DrJMgltayaj3HNd2IglD5rjfc2cKWRgOd7/GlKcHaTEnbreYhfR2sWrWLxJOyoMfuVWwKBgFalCbMV6qU0LfEo8aPlBN8ttVDPVNpntP4h0NgxPXgPK8Pg+gA1UWSy4MouGg/hzkdHaj9ifyLlCX598a5JoT4S0x/ZeVHd/LNI8mtjcRzD6cMde7gdFbpLb5NSjIAyrsIAX4hxvpnqiOYRePkVIz0iLGziiaMbfMwlkrxvm/LRAoGBALPRbtSbE2pPgvOHKHTGPr7gKbmsWVbOcQA8rG801T38W/UPe1XtynMEjzzQ29OaVeQwvUN9+DxFXJ6Yvwj6ih4Wdq109i7Oo1fDnMczOQN9DKch2eNAHrNSOMyLDCBm++wbyHAsS2T0VO8+gzLABviZm5AFCQWfke4LZo5mOS10');
var privateKey = await window.crypto.subtle.importKey("pkcs8", pkcs8Der, {name: "RSA-OAEP", hash: "SHA-1"}, true, ["decrypt"]);
var ciphertext = b642ab(ciphertextBase64);
ciphertext = ciphertext.reverse(); // reverse little endian order
var decrypted = await window.crypto.subtle.decrypt({name: "RSA-OAEP"}, privateKey, ciphertext); // apply OAEP as padding
return decodeUTF16LE(decrypted); // decode with UTF-16LE
}
// Helper
function b642ab(base64_string){
return Uint8Array.from(window.atob(base64_string), c => c.charCodeAt(0));
}
// https://stackoverflow.com/a/14601808
function decodeUTF16LE(buf) {
var cp = [];
var binaryStr = String.fromCharCode.apply(null, new Uint8Array(buf));
for( var i = 0; i < binaryStr.length; i+=2) {
cp.push(
binaryStr.charCodeAt(i) |
( binaryStr.charCodeAt(i+1) << 8 )
);
}
return String.fromCharCode.apply( String, cp );
}
})();
<p style="font-family:'Courier New', monospace;" id="js_enc"></p>
<p style="font-family:'Courier New', monospace;" id="js_dec"></p>
<p style="font-family:'Courier New', monospace;" id="py_dec"></p>

Convert a number between 1 and 16777215 to a colour value

I'm trying to convert a number between 1 and 16,777,215 to any colour format (RGB/HSL/HEX) that increments through the colour spectrum using Javascript/jQuery.
The number 16,777,215 is the total possible combinations of RGB(255,255,255) which is 32 bit colour.
I initially thought converting the value to a hex value using toString(16) would increment through the spectrum, however as the number increases it seems to work through different lightness values instead and flashes. An example of this unwanted behaviour is here http://jsfiddle.net/2z82auka/
var colour = 16777215;
window.setInterval(function(){
colour -= 1000;
$('body').css({background:'#' + colour.toString(16)});
}, 50);
How can I convert a value between 1 and 16777215 to a colour on the colour spectrum shown below?
The code below will do exactly what you want - it'll give you vibrant colors of the color spectrum exactly as the image below, and to prove it, the demo will print out the integer values beside the color. The result will look like this. Please use the rainbow function in your setInterval code.
var colours = 16777215;
function rainbow(numOfSteps, step) {
var r, g, b;
var h = 1 - (step / numOfSteps);
var i = ~~(h * 6);
var f = h * 6 - i;
var q = 1 - f;
switch(i % 6){
case 0: r = 1, g = f, b = 0; break;
case 1: r = q, g = 1, b = 0; break;
case 2: r = 0, g = 1, b = f; break;
case 3: r = 0, g = q, b = 1; break;
case 4: r = f, g = 0, b = 1; break;
case 5: r = 1, g = 0, b = q; break;
}
var c = "#" + ("00" + (~ ~(r * 235)).toString(16)).slice(-2) + ("00" + (~ ~(g * 235)).toString(16)).slice(-2) + ("00" + (~ ~(b * 235)).toString(16)).slice(-2);
return (c);
}
function render(i) {
var item = "<li style='background-color:" + rainbow(colours, i) + "'>" + i + "</li>";
$("ul").append(item);
}
function repeat(fn, times) {
for (var i = 0; i < times; i+=10000) fn(i);
}
repeat(render, colours);
li {
font-size:8px;
height:10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<ul></ul>
(I can't take credit for this code, but I can take credit for not giving up and settling for jerky color changes. Ref: https://gist.github.com/ruiwen/6163115)
Convert to range the initial value from 1 > 16777216 from 0 > 360
Technique here: Convert a number range to another range, maintaining ratio
Then use the HSL colour model, and increment from H0 S100 L100 > H360 S100 L100
Sticking to RGB: Always incrementing by one will not result in a steady grade through the spectrum. For example, when you go from #0000ff (which is blue) to that +1, you end up at #000100, which is essentially black.
Instead, you will probably want to do something more like incrementing each of the three values (the R value, the G value, and the B value) by one. However, that will omit many, many colors. But if smoothness is what you value over comprehensiveness, that's a simple way to get there.
#nada points out that this will give you an awful lot of grey. If you want to avoid that, you can try variations like: increment R until it can't be incremented anymore. Leave it at max value while you increment G until it hits max, then increment B to max. Now reverse it: Decrement R to minimum, then G, then B. This will still miss a ton of colors (in fact, it will miss most colors), but it should be smooth and it should avoid being nothing but grey.
Although this will work (if you don't mind missing most colors), I'm sure there is a better solution. I hope someone weighs in with it. I'm very curious.
You have the hue value, so you need to turn that into the various color formats using fixed brightness and saturation.
To properly scale the hue from [1, 16777215] to a [0, 1] scale, you'll need to do (x - 1) / 16777215. Take this number and feed it into hsl2rgb (here's a JS implementation) with a high lum and relatively high sat.
Something like so:
// From this answer: https://stackoverflow.com/a/9493060/129032
function hslToRgb(h, s, l) {
var r, g, b;
if (s == 0) {
r = g = b = l; // achromatic
} else {
var hue2rgb = function hue2rgb(p, q, t) {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
}
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
function scaleHue(hue) {
return ((hue - 1) / 16777215);
}
var colour = 0;
window.setInterval(function() {
colour = (colour + 100000) % 16777215;
var hue = scaleHue(colour);
var current = hslToRgb(hue, 0.8, 0.8);
$('body').css({
background: '#' + current[0].toString(16) + current[1].toString(16) + current[2].toString(16)
});
}, 50);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I increased the step from 1000 to 100000 to make the demo more obvious.
This works for me...
export function intToHex(colorNumber)
{
function toHex(n) {
n = n.toString(16) + '';
return n.length >= 2 ? n : new Array(2 - n.length + 1).join('0') + n;
}
var r = toHex(Math.floor( Math.floor(colorNumber / 256) / 256 ) % 256),
g = toHex(Math.floor( colorNumber / 256 ) % 256),
b = toHex(colorNumber % 256);
return '#' + r + g + b;
}
Generally, this is the formula for converting an integer to rgba
r = (val)&0xFF;
g = (val>>8)&0xFF;
b = (val>>16)&0xFF;
a = (val>>24)&0xFF;
Expressed as javascript
function ToRGBA(val){
var r = (val)&0xFF;
var g = (val>>8)&0xFF;
var b = (val>>16)&0xFF;
var a = (val>>24)&0xFF;
return "rgb(" + r + "," + g + "," + b + ")";
}
Updated fiddle: http://jsfiddle.net/2z82auka/2/
Something like that ?
<script>
function intToHex(colorNumber) {
var R = (colorNumber - (colorNumber%65536)) / 65536;
var G = ((colorNumber - R*65536) - ((colorNumber - R*65536)%256)) / 256;
var B = colorNumber - R*65536 - G*256;
var RGB = R.toString(16) + G.toString(16) + B.toString(16);
return RGB;
}
</script>
Marrying this answer with Drake's:
function colorNumberToHex(colorNumber) {
function toHex(n) {
n = n.toString(16) + '';
return n.length >= 2 ? n : new Array(2 - n.length + 1).join('0') + n;
}
var r = toHex(colorNumber % 256),
g = toHex(Math.floor( colorNumber / 256 ) % 256),
b = toHex(Math.floor( Math.floor(colorNumber / 256) / 256 ) % 256);
return '#' + r + g + b;
}
The picture you've shown suggests you really just want to rotate through a set of continuous colors, not every possible rgb color (since many of them essentially look white or black). I would suggest using HSV as a base instead of RGB. Trying to increment a number that represents an RGB value will lead to the stuttering you see (like #Trott pointed out, going from 0000ff to 000100 jumps from a blue to a black).
Try something like this (Fiddle):
$(document).ready(function(){
var h = 0;
window.setInterval(function(){
h += .01;
if (h >= 1) h-=1;
var rgbColor = HSVtoRGB(h, 1, 1);
var colorString = '#' + convertComponentToHex(rgbColor.r)
+ convertComponentToHex(rgbColor.g)
+ convertComponentToHex(rgbColor.b);
$('body').css({background:colorString});
}, 50);
});
function convertComponentToHex(v) {
return ("00" + v.toString(16)).substr(-2);
}
function HSVtoRGB(h, s, v) {
var r, g, b, i, f, p, q, t;
if (h && s === undefined && v === undefined) {
s = h.s, v = h.v, h = h.h;
}
i = Math.floor(h * 6);
f = h * 6 - i;
p = v * (1 - s);
q = v * (1 - f * s);
t = v * (1 - (1 - f) * s);
switch (i % 6) {
case 0: r = v, g = t, b = p; break;
case 1: r = q, g = v, b = p; break;
case 2: r = p, g = v, b = t; break;
case 3: r = p, g = q, b = v; break;
case 4: r = t, g = p, b = v; break;
case 5: r = v, g = p, b = q; break;
}
return {
r: Math.floor(r * 255),
g: Math.floor(g * 255),
b: Math.floor(b * 255)
};
}
(Thanks to this SO answer for the conversion code. I was too lazy to go figure it out for myself.)
My implementation....
var r = 255;
var g = 0;
var b = 0;
var stage = 1;
var step = 5;
var int = setInterval(function () {
if (stage == 1) {
g += step;
if (g >= 255) {
g = 255;
stage = 2;
}
} else if (stage == 2) {
r -= step;
if (r <= 0) {
r = 0;
stage = 3;
}
} else if (stage == 3) {
b += step;
if (b >= 255) {
b = 255;
stage = 4;
}
} else if (stage == 4) {
g -= step;
if (g <= 0) {
g = 0
stage = 5;
}
} else if (stage == 5) {
r += step;
if (r >= 255) {
r = 255;
stage = 6;
}
} else if (stage == 6) {
b -= step;
if (b <= 0) {
b = 0;
clearInterval(int);
}
}
//console.log(r,g,b);
$('body').css('background-color', 'RGB('+r+','+g+','+b+')');
}, 10);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

How to (always) add commas to decimal separator in JavaScript

I'm using the following script to use dots as the thousands separator and commas as decimals separator that I got from this question.
var numero = 1000.00;
function formatThousands(n, dp) {
var s = ''+(Math.floor(n)),
d = n % 1,
i = s.length,
r = '';
while ((i -= 3) > 0) {
r = '.' + s.substr(i, 3) + r;
}
return s.substr(0, i + 3) + r + (d ? ',' + Math.round(d * Math.pow(10,dp||2)) : '');
}
alert(formatThousands(numero,2));
/// http://jsperf.com/compare-two-format-thousands
See also jsfiddle
This is working OK, except for integers.
For example, the number 1000 will return 1.000 and I want it to return 1.000,00 since the numbers refer to Euro currency.
How can I add the 2 decimals (cents) in every number?
Thanks for helping!
Does this work?
function formatThousands(n, dp) {
var s = ''+(Math.floor(n)), d = n % 1, i = s.length, r = '';
while ( (i -= 3) > 0 ) { r = '.' + s.substr(i, 3) + r; }
s = s.substr(0, i + 3) + r + (d ? ',' + Math.round(d * Math.pow(10,dp||2)) : '');
return s.charAt(-1) != ',' ? s+',00' : s;
}
EDIT:
How about this?
function formatThousands(n, dp) {
n = (''+n).split('.');
i = n[0];
d = !(n[1]) ? '00' : n[1];
n = i.match(/.{4}/g).join('.');
return n + ',' + d;
}
http://jsfiddle.net/XC3sS/12/

What was used to compress this code? [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I'm trying to understand what's going on in this code: http://js1k.com/2013-spring/demo/1396
This doesn't look like it's been minified or encoded in Base62 to me. When I paste it in Vim weird characters appear everywhere. Is there a way I can decode it?
This has been produced using the Data URI Scheme
https://en.wikipedia.org/wiki/Data_URI_scheme
The javascript file has been supplied as a URI which contains the file's contents. Lots of codes have been URL escaped, hence all the \s. And it may have been minified before that.
The data here is a whole HTML document. The first part is the start of the HTML file:
javascript:
'<!doctype html>\n<html>\n\t<head>\n\t\t<title>JS1k, 1k demo submission [1396]</title>\n\t\t<meta charset="utf-8" />\n\t</head>\n\t<body>\n\t\t<canvas id="c"></canvas>\n\t\t
After that an inline script:
var b = document.body;\n\t\t\tvar c = document.getElementsByTagName(\'canvas\')[0];\n\t\t\tvar a = c.getContext(\'2d\');\n\t\t\tdocument.body.clientWidth; // fix bug in webkit: http://qfox.nl/weblog/218\n\t\t
which you can easily decode as:
var b = document.body;
var c = document.getElementsByTagName('canvas')[0];
var a = c.getContext('2d');
document.body.clientWidth; // fix bug in webkit: http://qfox.nl/weblog/218
etc etc.
End of code there is script, which is used to decode code
for (Y = 0; $ = 'zxqj`_^ZWVUQONMKJIHGCA#8$ ' [Y++];)
with(_.split($)) _ = join(pop());
eval(_)
I put this firebug ... instead of eval(_) put console.log( _ )
code is
e = null;
T = function (b) {
c.width = c.height = 19 * s;
a.fillStyle = "#DB5";
a.fillRect(0, 0, c.width, c.width);
for (i = s / 2; i < c.width; i += s) a.moveTo(i, s / 2), a.lineTo(i, c.width - s / 2), a.moveTo(s / 2, i), a.lineTo(c.width - s / 2, i);
a.stroke();
b && (f = 19 * ~~(0.5 + (b.clientY - s / 2) / s) + ~~(0.5 + (b.clientX - s / 2) / s), t[f] == e && (t[f] = d, (L(f) | !(L(f + 1) & L(f - 1) & L(f + 19) & L(f - 19))) & (!m | f != n) ? "d" == b.type[5] ? (m = 0, u = f, d = !d, E(f + 1, d), E(f - 1, d), E(f + 19, d), E(f - 19, d), E(f)) : (t[f] = e, a.beginPath(), a.arc(~~(0.5 + (b.clientX - s / 2) / s) * s + s / 2, ~~ (0.5 + (b.clientY - s / 2) / s) * s + s / 2, s / 2 - 1, 0, 6.3, 1), a.strokeStyle = a.fillStyle = "rgba(0,0,0,0.3)", d && (a.fillStyle = "rgba(255,255,255,0.3)"), a.fill(), a.stroke()) : t[f] = e));
a.strokeStyle = "#000";
a.fillStyle = "#000";
for (i = s / 2 + 75; i < c.width; i += 6 * s) for (h = s / 2 + 75; h < c.width; h += 6 * s) a.beginPath(), a.arc(i, h, 2, 0, 6.3, 1), a.fill();
m && (t[n] = d, L(u) || (a.beginPath(), a.rect(n % 19 * s + s / 2 / 2, ~~ (n / 19) * s + s / 2 / 2, s / 2, s / 2), a.stroke()), t[n] = e);
for (i = t.length; i--;) t[i] != e && (a.beginPath(), a.arc(i % 19 * s + s / 2, ~~ (i / 19) * s + s / 2, s / 2 - 1, 0, 6.3, 1), a.fillStyle = "#000", t[i] && (a.fillStyle = "#FFF"), a.fill(), a.stroke())
};
E = function (b, g) {
if (!L(b, g)) {
1 == w.length && (m = 1, n = b);
for (i = w.length; i--;) t[w[i]] = e
}
};
L = function (b, g) {
w = [];
g == e && (g = t[b]);
l = function (b) {
for (i = w.length; i--;) if (w[i] == b) return;
w.push(b);
0 != (b + 1) % 19 && t[b + 1] == g && l(b + 1);
0 != b % 19 && t[b - 1] == g && l(b - 1);
t[b + 19] == g && l(b + 19);
t[b - 19] == g && l(b - 19)
};
if (g != e && g == t[b]) l(b);
else return 1;
for (i = w.length; i--;) if (0 != (w[i] + 1) % 19 && t[w[i] + 1] == e || 0 != w[i] % 19 && t[w[i] - 1] == e || 342 > w[i] && t[w[i] + 19] == e || 19 <= w[i] && t[w[i] - 19] == e) return 1;
return 0
};
s = 25;
d = m = n = 0;
c.addEventListener("mousemove", T);
c.addEventListener("mousedown", T);
t = [];
T();

Categories