Choropleth Pretty Breaks - javascript

I'm trying to develop pretty breaks function in javascript, but I only find examples in r.
Do you know where to find the information for javascript ?
My issue is that I dont understand how to generate the breaks. I understand how to make a round breaks, but how do we calculate the ranges of breaks when selecting 4 breaks ?
I use geojson file working with density.
Thank you for the help
PS : I apologize for my english, I am not a native speaker.

I've solved using this steps.
I hope it serves someone else.
Thanks a lot :D
function prettyBreaks(minimum, maximum, classes) {
let breaks = [];
if ( classes < 1 ) {
breaks.push( maximum );
return breaks;
}
let minimumCount = parseInt(classes / 3 );
let shrink = 0.75;
let highBias = 1.5;
let adjustBias = 0.5 + 1.5 * highBias;
let divisions = parseInt( classes );
let h = highBias;
let cell;
let small = false;
let dx = maximum - minimum;
if (NearTo( dx, 0.0 ) && NearTo( maximum, 0.0 )) {
cell = 1.0;
small = true;
} else {
let U = 1;
cell = (Math.abs(maximum) >= Math.abs(minimum)) ? Math.abs(maximum) : Math.abs(minimum);
if ( adjustBias >= 1.5 * h + 0.5) {
U = parseInt( 1 + (1.0 / (1 + h)) );
} else {
U = parseInt( 1 + ( 1.5 / ( 1 + adjustBias ) ) );
}
let maxBetweenDivisions = (1 >= divisions) ? 1 : divisions;
small = dx < ( cell * U * maxBetweenDivisions * 1e-07 * 3.0 );
}
if (small) {
if (cell > 10) {
cell = 9 + cell / 10;
cell = cell * shrink;
}
if (minimumCount > 1) {
cell = cell / minimumCount;
}
} else {
cell = dx;
if (divisions > 1) {
cell = cell / divisions;
}
}
if (cell < 20 * 1e-07) {
cell = 20 * 1e-07;
}
let base = Math.pow(10.0, Math.floor( Math.log10( cell )));
let unit = base;
if ( ( 2 * base ) - cell < h * ( cell - unit ) ) {
unit = 2.0 * base;
if ( ( 5 * base ) - cell < adjustBias * ( cell - unit ) )
{
unit = 5.0 * base;
if ( ( 10.0 * base ) - cell < h * ( cell - unit ) )
{
unit = 10.0 * base;
}
}
}
let start = parseInt( Math.floor( minimum / unit + 1e-07 ) );
let end = parseInt( Math.ceil( maximum / unit - 1e-07 ) );
// Extend the range out beyond the data. Does this ever happen??
while ( start * unit > minimum + ( 1e-07 * unit ) ) {
start = start - 1;
}
while ( end * unit < maximum - ( 1e-07 * unit ) ) {
end = end + 1;
}
let k = parseInt( Math.floor( 0.5 + end - start ) );
if ( k < minimumCount ) {
k = minimumCount - k;
if ( start >= 0 ) {
end = end + k / 2;
start = start - k / 2 + k % 2;
}
else {
start = start - k / 2;
end = end + k / 2 + k % 2;
}
}
let minimumBreak = start * unit;
let count = parseInt( end - start );
breaks = [];
for ( let i = 1; i < count + 1; i++ ) {
breaks.push( minimumBreak + i * unit );
}
if ( breaks.length === 0 ) return breaks;
if ( breaks[0] < minimum ) {
breaks.splice(0, 1, minimum);
}
if ( breaks[breaks.length-1] > maximum ) {
breaks.splice(breaks.length-1, 1, maximum);
}
if ( minimum < 0.0 && maximum > 0.0 ) { //then there should be a zero somewhere
let breaksMinusZero = []; // compute difference "each break - 0"
for ( let i = 0; i <= breaks.length; i++ ) {
breaksMinusZero.push( breaks[i] - 0.0 );
}
let posOfMin = 0;
for ( let i = 1; i <= breaks.length; i++ ) { // find position of minimal difference
if ( Math.abs( breaksMinusZero[i] ) < Math.abs( breaksMinusZero[i - 1] ) )
posOfMin = i;
}
breaks[posOfMin] = 0.0;
}
return breaks;
};
/** Check if value1 is nearest to value2 */
function NearTo(value1, value2) {
if (value1 > 1 || value2 > 1) return false;
else if ((value1 >= 0 && value1 < 1 ) && (value2 >= 0 && value2 < 1 )) return true;
else return false;
};

Related

Move the knight from position 1 to position 2 with less than 10 moves

I have a question.
here is my chess board , ok?
enter image description here
I wanna move knight from postion 1 to postion 2 with all possible ways.
but with less than 10 moves.
can any one help me have to do this?
function isSafe(x,y,board){
if(x >= 0 && y >= 0 && x < 8 && y < 8 && board[y][x] == 0){return true}
else{return false}
}
function printBoard(board){
for(let i = 0; i < 8; i++){
for(let x = 0; x < 8; x++){
console.log(board[i][x] + " ");
}
}
}
function solve(){
let board = [];
for(let i = 0; i < 8; i++){
board[i] = [];
for(let x = 0; x < 8; x++){
board[i][x] = 0;
}
}
var move_x = [2, 1, -1, -2, -2, -1, 1, 2];
var move_y = [1, 2, 2, 1, -1, -2, -2, -1];
board[0][0] = 1;
var pos = 1;
if(solveKTUtil(board,0,0,move_x,move_y,pos)){
printBoard(board);
}
else{console.log('no answer')}
console.log(board)
}
function solveKTUtil(board,curr_x,curr_y,move_x,move_y,pos){
if(curr_x == 7 && curr_y == 7){return true}
for(let i = 0; i < 8; i++){
var new_y = curr_y + move_y[i] ;
var new_x = curr_x + move_x[i] ;
if(isSafe(new_x,new_y,board)){
console.log(new_x,new_y)
board[new_y][new_x] = pos;
if(board[7][7] === 1){return true}
else{
solveKTUtil(board,curr_x,curr_y,move_x,move_y,pos);
}
}
}
return false
}
solve();
now it's nowt working fine . please help me
Refactored your code, and shaped the solution into a depth first search (DFS) with a taxicab distance heuristic to favor the moves of the knight that are closer to the goal square. Additionally, introduced a recursive generator function in the event that one wants to control how often and how long the solutions are sought.
The solution count ramps up quickly, of course, when seeking more moves. Some quick testing reveals that there are...
108 solutions of 6 moves or less
1896 solutions of 8 moves or less
40432 solutions of 10 moves or less
736396 solutions of 12 moves or less
Inline comments assist in understanding the recursive generator function...
Running the code snippet will display all 108 solutions of 6 moves or less.
function printBoard( board ){
let bm = '';
for (let rank = 7; 0 <= rank; rank-- ) {
for ( let file = 0; file < 8; file++ ) {
if ( board[ rank ][ file ] === -1 ) {
bm += " X ";
} else if ( board[ rank ][ file ] === 0 ) {
bm += " - ";
} else {
bm += ( " " + board[ rank ][ file ] ).slice( -2 ) + " ";
}
}
bm += '\n'
}
return bm + '\n';
}
function genAndSortKnightMoves( knightRank, knightFile, goalRank, goalFile ) {
const knightMoves = [ [-2,-1], [-2,1], [-1,-2], [-1,2], [1,-2], [1,2], [2,-1], [2,1] ];
function isKnightOnTheBoard( r, f ){
return ( 0 <= r && 0 <= f && r < 8 && f < 8 );
}
// Generate list of possible moves where the Knight is on the board and the
// square has not already been visited.
let moves = [];
knightMoves.forEach( rf => {
let rank = knightRank + rf[ 0 ];
let file = knightFile + rf[ 1 ];
if ( isKnightOnTheBoard( rank, file ) ) {
moves.push( [ rank, file ] );
}
} );
// Now, sort the moves based on which is closer to the goal using the
// taxicab distance.
moves.sort( ( a, b ) =>
( Math.abs( a[ 0 ] - goalRank ) + Math.abs( a[ 1 ] - goalFile ) )
- ( Math.abs( b[ 0 ] - goalRank ) + Math.abs( b[ 1 ] - goalFile ) )
);
return moves;
}
// Set up zero filled 8 x 8 array.
let workingBoard = new Array( 8 ).fill( 0 ).map( () => new Array( 8 ).fill( 0 ) );
function* solve( startRank, startFile, goalRank, goalFile, maxDepth = 12, depth = 0 ) {
// Set the square that the knight landed on.
workingBoard[ startRank ][ startFile ] = ( depth === 0 ? -1 : depth );
// If we reached the goal square, let's yield the result.
if ( startRank === goalRank && startFile === goalFile ) {
yield workingBoard;
} else if ( depth < maxDepth ) {
// Otherwise, if we haven't reached maxDepth, let's go deeper. First, get
// the list of candidate knight moves, sorted by the squares closest to the
// goal using the simple taxicab distance.
let candidateMoves = genAndSortKnightMoves( startRank, startFile, goalRank, goalFile );
// Now, loop through the options, and if the square is empty, let's jump
// to that square.
for ( let move of candidateMoves ) {
let rank = move[ 0 ];
let file = move[ 1 ];
if ( workingBoard[ rank ][ file ] === 0 ) {
yield* solve( rank, file, goalRank, goalFile, maxDepth, depth + 1 );
}
}
}
// At this point, the recursion has unwound, so lets clear the knight off
// the square by resetting it to zero.
workingBoard[ startRank ][ startFile ] = 0;
}
// Set up the solution, by creating the iterator with the beginning square and
// goal square, and setting the max depth to the number of max moves sought.
let solutionsCount = 0;
let moveCountSought = 6;
const findSolution = solve( 0, 0, 7, 7, moveCountSought );
// Now, simply iterate over the yielded solutions.
do {
let soln = findSolution.next();
if ( soln.done ) {
break;
}
if ( workingBoard[ 7 ][ 7 ] <= moveCountSought ) {
solutionsCount++;
console.log( printBoard( workingBoard ) );
}
} while ( true );
console.log( `Number of solutions less than or equal to ${moveCountSought} moves is ${solutionsCount}.` );

Bringing in a Function from Javascript to Big Query StandardSQL

I have a javascript that assigns a certain bucket to a customer according to the algorithm number and test number (function getBuckets). However I am having trouble bringing this function over from the javascript and defining it into standard sql. So I can use it on specific databases.
Here is the Input Schema from Big Query that I am trying to get a bucket number for:
7354430 AS customerId,
4 AS algorithmIndex,
5947 AS testId
Here is what the output should be after running my sql:
customerId,
bucketNumber
Does anyone know how to bring in the getBuckets function from the javascript into big query standard sql in order to get the bucketNumber?
Javascript is below:
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* SHA-1 implementation in JavaScript (c) Chris Veness 2002-2014 / MIT Licence */
/* */
/* - see http://csrc.nist.gov/groups/ST/toolkit/secure_hashing.html */
/* http://csrc.nist.gov/groups/ST/toolkit/examples.html */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* jshint node:true *//* global define, escape, unescape */
'use strict';
/**
* SHA-1 hash function reference implementation.
*
* #namespace
*/
var Sha1 = {};
/**
* Generates SHA-1 hash of string.
*
* #param {string} msg - (Unicode) string to be hashed.
* #returns {string} Hash of msg as hex character string.
*/
Sha1.hash = function(msg) {
// convert string to UTF-8, as SHA only deals with byte-streams
msg = msg.utf8Encode();
// constants [§4.2.1]
var K = [ 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 ];
// PREPROCESSING
msg += String.fromCharCode(0x80); // add trailing '1' bit (+ 0's padding) to string [§5.1.1]
// convert string msg into 512-bit/16-integer blocks arrays of ints [§5.2.1]
var l = msg.length/4 + 2; // length (in 32-bit integers) of msg + ‘1’ + appended length
var N = Math.ceil(l/16); // number of 16-integer-blocks required to hold 'l' ints
var M = new Array(N);
for (var i=0; i<N; i++) {
M[i] = new Array(16);
for (var j=0; j<16; j++) { // encode 4 chars per integer, big-endian encoding
M[i][j] = (msg.charCodeAt(i*64+j*4)<<24) | (msg.charCodeAt(i*64+j*4+1)<<16) |
(msg.charCodeAt(i*64+j*4+2)<<8) | (msg.charCodeAt(i*64+j*4+3));
} // note running off the end of msg is ok 'cos bitwise ops on NaN return 0
}
// add length (in bits) into final pair of 32-bit integers (big-endian) [§5.1.1]
// note: most significant word would be (len-1)*8 >>> 32, but since JS converts
// bitwise-op args to 32 bits, we need to simulate this by arithmetic operators
M[N-1][14] = ((msg.length-1)*8) / Math.pow(2, 32); M[N-1][14] = Math.floor(M[N-1][14]);
M[N-1][15] = ((msg.length-1)*8) & 0xffffffff;
// set initial hash value [§5.3.1]
var H0 = 0x67452301;
var H1 = 0xefcdab89;
var H2 = 0x98badcfe;
var H3 = 0x10325476;
var H4 = 0xc3d2e1f0;
// HASH COMPUTATION [§6.1.2]
var W = new Array(80); var a, b, c, d, e;
for (var i=0; i<N; i++) {
// 1 - prepare message schedule 'W'
for (var t=0; t<16; t++) W[t] = M[i][t];
for (var t=16; t<80; t++) W[t] = Sha1.ROTL(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1);
// 2 - initialise five working variables a, b, c, d, e with previous hash value
a = H0; b = H1; c = H2; d = H3; e = H4;
// 3 - main loop
for (var t=0; t<80; t++) {
var s = Math.floor(t/20); // seq for blocks of 'f' functions and 'K' constants
var T = (Sha1.ROTL(a,5) + Sha1.f(s,b,c,d) + e + K[s] + W[t]) & 0xffffffff;
e = d;
d = c;
c = Sha1.ROTL(b, 30);
b = a;
a = T;
}
// 4 - compute the new intermediate hash value (note 'addition modulo 2^32')
H0 = (H0+a) & 0xffffffff;
H1 = (H1+b) & 0xffffffff;
H2 = (H2+c) & 0xffffffff;
H3 = (H3+d) & 0xffffffff;
H4 = (H4+e) & 0xffffffff;
}
return Sha1.toHexStr(H0) + Sha1.toHexStr(H1) + Sha1.toHexStr(H2) +
Sha1.toHexStr(H3) + Sha1.toHexStr(H4);
};
/**
* Function 'f' [§4.1.1].
* #private
*/
Sha1.f = function(s, x, y, z) {
switch (s) {
case 0: return (x & y) ^ (~x & z); // Ch()
case 1: return x ^ y ^ z; // Parity()
case 2: return (x & y) ^ (x & z) ^ (y & z); // Maj()
case 3: return x ^ y ^ z; // Parity()
}
};
/**
* Rotates left (circular left shift) value x by n positions [§3.2.5].
* #private
*/
Sha1.ROTL = function(x, n) {
return (x<<n) | (x>>>(32-n));
};
/**
* Hexadecimal representation of a number.
* #private
*/
Sha1.toHexStr = function(n) {
// note can't use toString(16) as it is implementation-dependant,
// and in IE returns signed numbers when used on full words
var s="", v;
for (var i=7; i>=0; i--) { v = (n>>>(i*4)) & 0xf; s += v.toString(16); }
return s;
};
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/** Extend String object with method to encode multi-byte string to utf8
* - monsur.hossa.in/2012/07/20/utf-8-in-javascript.html */
if (typeof String.prototype.utf8Encode == 'undefined') {
String.prototype.utf8Encode = function() {
return unescape( encodeURIComponent( this ) );
};
}
/** Extend String object with method to decode utf8 string to multi-byte */
if (typeof String.prototype.utf8Decode == 'undefined') {
String.prototype.utf8Decode = function() {
try {
return decodeURIComponent( escape( this ) );
} catch (e) {
return this; // invalid UTF-8? return as-is
}
};
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
if (typeof module != 'undefined' && module.exports) module.exports = Sha1; // CommonJs export
if (typeof define == 'function' && define.amd) define([], function() { return Sha1; }); // AMD
Sha1.getDeterministicBuckets = function(customerId,algorithmIndex,testNumber) {
var testDescriptors = {
28:{s:100, d:'1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1'},
29:{s:21, d:'40/3/3/3/3/3/3/3/3/3/3/3/3/3/3/3/3/3/3/3/3'}
};
var seed = (customerId+testNumber).toString();
var sha1 = Sha1.hash(seed);
var end = sha1.substr(36)
var c = parseInt(end, 16)/65535.0;
var result = '';
/*
if ( algorithmIndex == 3 )
if ( c < 0.10 ) result = 9;
else if ( c < 0.20 ) result = 8;
else if ( c < 0.30 ) result = 7;
else if ( c < 0.40 ) result = 6;
else if ( c < 0.50 ) result = 5;
else if ( c < 0.60 ) result = 4;
else if ( c < 0.70 ) result = 3;
else if ( c < 0.80 ) result = 2;
else if ( c < 0.90 ) result = 1;
else result = 0;
*/
/* (on 6/3/13) Bad inputs (and/or logged out users) yield a -1. */
if ( customerId == null || algorithmIndex == null || testNumber == null ) {
result = -1;
if( algorithmIndex < 1 || algorithmIndex > 27)
result = 0;
/* 25/25/50 */
}else if ( algorithmIndex == 1 ) {
if ( c < 0.25 ) result = 2;
else if ( c < 0.50 ) result = 1;
else result = 0;
/* 1/99 */
}else if ( algorithmIndex == 2 ) {
if ( c < 0.01 ) result = 1
else result = 0;
/* 10/10/10/... */
}else if ( algorithmIndex == 3 ){
if ( c < 0.10 ) result = 9;
else if ( c < 0.20 ) result = 8;
else if ( c < 0.30 ) result = 7;
else if ( c < 0.40 ) result = 6;
else if ( c < 0.50 ) result = 5;
else if ( c < 0.60 ) result = 4;
else if ( c < 0.70 ) result = 3;
else if ( c < 0.80 ) result = 2;
else if ( c < 0.90 ) result = 1;
else result = 0;
/* 25/25/25/25 */
}else if ( algorithmIndex == 4 ) {
if ( c < 0.25 ) result = 3;
else if ( c < 0.50 ) result = 2;
else if ( c < 0.75 ) result = 1;
else result = 0;
/* 50/50 */
}else if ( algorithmIndex == 5 ) {
if ( c < 0.50 ) result = 1;
else result = 0;
/* 10/90 */
}else if ( algorithmIndex == 6 ) {
if ( c < 0.10 ) result = 1;
else result = 0;
/* 10/10/10/10/10/50 */
}else if ( algorithmIndex == 7 ) {
if ( c < 0.10 ) result = 5;
else if ( c < 0.20 ) result = 4;
else if ( c < 0.30 ) result = 3;
else if ( c < 0.40 ) result = 2;
else if ( c < 0.50 ) result = 1;
else result = 0;
/* 20/20/20/20/20 */
}else if ( algorithmIndex == 8 ){
if ( c < 0.20 ) result = 4;
else if ( c < 0.40 ) result = 3;
else if ( c < 0.60 ) result = 2;
else if ( c < 0.80 ) result = 1;
else result = 0;
/* 96/2/2 */
}else if ( algorithmIndex == 9 ) {
if ( c < 0.02 ) result = 2;
else if ( c < 0.04 ) result = 1;
else result = 0;
/* 80/20 */
}else if ( algorithmIndex == 10 ) {
if ( c < 0.20 ) result = 1;
else result = 0;
/* 12.5/12.5/12.5/etc */
}else if ( algorithmIndex == 11 ) {
if ( c < 0.125 ) result = 7;
else if ( c < 0.250 ) result = 6;
else if ( c < 0.375 ) result = 5;
else if ( c < 0.500 ) result = 4;
else if ( c < 0.625 ) result = 3;
else if ( c < 0.750 ) result = 2;
else if ( c < 0.875 ) result = 1;
else result = 0;
/* 50/10/20/20 */
}else if ( algorithmIndex == 12 ) {
if ( c < 0.20 ) result = 3;
else if ( c < 0.40 ) result = 2;
else if ( c < 0.50 ) result = 1;
else result = 0;
/* 100 */
}else if ( algorithmIndex == 13 ) {
result = 0;
/* 80/2/2/2/2/2/2/2/2/2/2 */
}else if ( algorithmIndex == 14 ) {
if ( c < 0.02 ) result = 10;
else if ( c < 0.04 ) result = 9;
else if ( c < 0.06 ) result = 8;
else if ( c < 0.08 ) result = 7;
else if ( c < 0.10 ) result = 6;
else if ( c < 0.12 ) result = 5;
else if ( c < 0.14 ) result = 4;
else if ( c < 0.16 ) result = 3;
else if ( c < 0.18 ) result = 2;
else if ( c < 0.20 ) result = 1;
else result = 0;
/* 11/11/3/3/3/3/.... */
}else if ( algorithmIndex == 15 ) {
if ( c < 0.03 ) result = 27;
else if ( c < 0.06 ) result = 26;
else if ( c < 0.09 ) result = 25;
else if ( c < 0.12 ) result = 24;
else if ( c < 0.15 ) result = 23;
else if ( c < 0.18 ) result = 22;
else if ( c < 0.21 ) result = 21;
else if ( c < 0.24 ) result = 20;
else if ( c < 0.27 ) result = 19;
else if ( c < 0.30 ) result = 18;
else if ( c < 0.33 ) result = 17;
else if ( c < 0.36 ) result = 16;
else if ( c < 0.39 ) result = 15;
else if ( c < 0.42 ) result = 14;
else if ( c < 0.45 ) result = 13;
else if ( c < 0.48 ) result = 12;
else if ( c < 0.51 ) result = 11;
else if ( c < 0.54 ) result = 10;
else if ( c < 0.57 ) result = 9;
else if ( c < 0.60 ) result = 8;
else if ( c < 0.63 ) result = 7;
else if ( c < 0.66 ) result = 6;
else if ( c < 0.69 ) result = 5;
else if ( c < 0.72 ) result = 4;
else if ( c < 0.75 ) result = 3;
else if ( c < 0.78 ) result = 2;
else if ( c < 0.89 ) result = 1;
else result = 0;
/* 23/23/23/23/8 */
} else if ( algorithmIndex == 16 ) {
if ( c < 0.08 ) result = 4;
else if ( c < 0.31 ) result = 3;
else if ( c < 0.54 ) result = 2;
else if ( c < 0.77 ) result = 1;
else result = 0;
/* 97/0.5/0.5/0.5/0.5/0.5?0.5 */
}else if ( algorithmIndex == 17 ) {
if ( c < 0.005 ) result = 6;
else if ( c < 0.010 ) result = 5;
else if ( c < 0.015 ) result = 4;
else if ( c < 0.020 ) result = 3;
else if ( c < 0.025 ) result = 2;
else if ( c < 0.030 ) result = 1;
else result = 0;
/* 80/10/10 */
} else if ( algorithmIndex == 18 ){
if ( c < 0.10 ) result = 2;
else if ( c < 0.20 ) result = 1;
else result = 0;
/* 70/10/10/10 */
} else if ( algorithmIndex == 19 ){
if ( c < 0.10 ) result = 3;
else if ( c < 0.20 ) result = 2;
else if ( c < 0.30 ) result = 1;
else result = 0;
/* 90/5/5 */
}else if ( algorithmIndex == 20 ){
if ( c < 0.05 ) result = 2;
else if ( c < 0.10 ) result = 1;
else result = 0;
/* 80/5/5/5/5 */
}else if ( algorithmIndex == 21 ){
if ( c < 0.05 ) result = 4;
else if ( c < 0.10 ) result = 3;
else if ( c < 0.15 ) result = 2;
else if ( c < 0.20 ) result = 1;
else result = 0;
/* 45/45/10 */
}else if ( algorithmIndex == 22 ) {
if ( c < 0.10 ) result = 2;
else if ( c < 0.55 ) result = 1;
else result = 0;
/* 5.88 x 17 ... seriously? */
} else if ( algorithmIndex == 23 ){
if ( c < 0.0588 ) result = 16;
else if ( c < 0.1176 ) result = 15
else if ( c < 0.1764 ) result = 14;
else if ( c < 0.2352 ) result = 13;
else if ( c < 0.2940 ) result = 12;
else if ( c < 0.3528 ) result = 11;
else if ( c < 0.4116 ) result = 10;
else if ( c < 0.4704 ) result = 9;
else if ( c < 0.5292 ) result = 8;
else if ( c < 0.5880 ) result = 7;
else if ( c < 0.6468 ) result = 6;
else if ( c < 0.7056 ) result = 5;
else if ( c < 0.7644 ) result = 4;
else if ( c < 0.8232 ) result = 3;
else if ( c < 0.8820 ) result = 2;
else if ( c < 0.9401 ) result = 1;
else result = 0;
/* 97.5/2.5 */
}else if ( algorithmIndex == 24 ) {
if ( c < 0.025 ) result = 1;
else result = 0;
/* 92.5/7.5 */
}else if ( algorithmIndex == 25 ) {
if ( c < 0.075 ) result = 1;
else result = 0;
/* 50/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5 */
/* not sure why this one was setup with results asc vs desc; results were validated and match webstore */
}else if ( algorithmIndex == 26 ) {
if ( c < 0.025 ) result = 1;
else if ( c < 0.050 ) result = 2;
else if ( c < 0.075 ) result = 3;
else if ( c < 0.100 ) result = 4;
else if ( c < 0.125 ) result = 5;
else if ( c < 0.150 ) result = 6;
else if ( c < 0.175 ) result = 7;
else if ( c < 0.200 ) result = 8;
else if ( c < 0.225 ) result = 9;
else if ( c < 0.250 ) result = 10;
else if ( c < 0.275 ) result = 11;
else if ( c < 0.300 ) result = 12;
else if ( c < 0.325 ) result = 13;
else if ( c < 0.350 ) result = 14;
else if ( c < 0.375 ) result = 15;
else if ( c < 0.400 ) result = 16;
else if ( c < 0.425 ) result = 17;
else if ( c < 0.450 ) result = 18;
else if ( c < 0.475 ) result = 19;
else if ( c < 0.500 ) result = 20;
else result = 0;
/* 33.3/33.3/33.3 */
} else if ( algorithmIndex == 27 ) {
if ( c < 0.333 ) result = 2;
else if ( c < 0.666 ) result = 1;
else result = 0;
} else {
if (algorithmIndex in testDescriptors) {
var distributions = testDescriptors[algorithmIndex].d.split('/');
var threshold = 0.0;
result = 0;
for (var i = 1; i < distributions.length; i++) {
threshold += parseFloat(distributions[i])/100.0;
if (c < threshold) {
result = i;
break;
}
}
}
}
return result;
};
function getBuckets(row, emit) {
var result = Sha1.getDeterministicBuckets(row.inCustomerId,row.inAlgorithmIndex,row.inTestNumber);
emit({bucketNumber: result , CustomerId: row.inCustomerId});
};
bigquery.defineFunction(
'getBuckets', // Name of the function exported to SQL
['inCustomerId','inAlgorithmIndex','inTestNumber'], // Names of input columns
[{'name': 'bucketNumber', 'type': 'integer'}, // Output schema
{'name': 'CustomerId', 'type': 'integer'}],
getBuckets // Reference to JavaScript UDF
);
I fixed it for #standardSQL.
First, add these 3 lines at the beginning, to define a JS UDF:
CREATE TEMP FUNCTION getDeterministicBuckets(customerId INT64, algorithmIndex INT64, testId INT64)
RETURNS STRUCT<bucketNumber INT64, CustomerId INT64>
LANGUAGE js AS """
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* SHA-1 implementation in JavaScript (c) Chris Veness 2002-2014 / MIT Licence */
/* */
/* - see http://csrc.nist.gov/groups/ST/toolkit/secure_hashing.html */
/* http://csrc.nist.gov/groups/ST/toolkit/examples.html */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
At the end, instead of a signature for a function:
Don't use emit()
return instead
Like in:
return {bucketNumber: Sha1.getDeterministicBuckets(customerId, algorithmIndex, testId) , CustomerId: customerId};
""";
That will allow you to call the function like this:
SELECT getDeterministicBuckets(7354430,4,5947) x
Complete working code:
CREATE TEMP FUNCTION getDeterministicBuckets(customerId INT64, algorithmIndex INT64, testId INT64)
RETURNS STRUCT<bucketNumber INT64, CustomerId INT64>
LANGUAGE js AS """
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* SHA-1 implementation in JavaScript (c) Chris Veness 2002-2014 / MIT Licence */
/* */
/* - see http://csrc.nist.gov/groups/ST/toolkit/secure_hashing.html */
/* http://csrc.nist.gov/groups/ST/toolkit/examples.html */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* jshint node:true *//* global define, escape, unescape */
'use strict';
/**
* SHA-1 hash function reference implementation.
*
* #namespace
*/
var Sha1 = {};
/**
* Generates SHA-1 hash of string.
*
* #param {string} msg - (Unicode) string to be hashed.
* #returns {string} Hash of msg as hex character string.
*/
Sha1.hash = function(msg) {
// convert string to UTF-8, as SHA only deals with byte-streams
msg = msg.utf8Encode();
// constants [§4.2.1]
var K = [ 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 ];
// PREPROCESSING
msg += String.fromCharCode(0x80); // add trailing '1' bit (+ 0's padding) to string [§5.1.1]
// convert string msg into 512-bit/16-integer blocks arrays of ints [§5.2.1]
var l = msg.length/4 + 2; // length (in 32-bit integers) of msg + ‘1’ + appended length
var N = Math.ceil(l/16); // number of 16-integer-blocks required to hold 'l' ints
var M = new Array(N);
for (var i=0; i<N; i++) {
M[i] = new Array(16);
for (var j=0; j<16; j++) { // encode 4 chars per integer, big-endian encoding
M[i][j] = (msg.charCodeAt(i*64+j*4)<<24) | (msg.charCodeAt(i*64+j*4+1)<<16) |
(msg.charCodeAt(i*64+j*4+2)<<8) | (msg.charCodeAt(i*64+j*4+3));
} // note running off the end of msg is ok 'cos bitwise ops on NaN return 0
}
// add length (in bits) into final pair of 32-bit integers (big-endian) [§5.1.1]
// note: most significant word would be (len-1)*8 >>> 32, but since JS converts
// bitwise-op args to 32 bits, we need to simulate this by arithmetic operators
M[N-1][14] = ((msg.length-1)*8) / Math.pow(2, 32); M[N-1][14] = Math.floor(M[N-1][14]);
M[N-1][15] = ((msg.length-1)*8) & 0xffffffff;
// set initial hash value [§5.3.1]
var H0 = 0x67452301;
var H1 = 0xefcdab89;
var H2 = 0x98badcfe;
var H3 = 0x10325476;
var H4 = 0xc3d2e1f0;
// HASH COMPUTATION [§6.1.2]
var W = new Array(80); var a, b, c, d, e;
for (var i=0; i<N; i++) {
// 1 - prepare message schedule 'W'
for (var t=0; t<16; t++) W[t] = M[i][t];
for (var t=16; t<80; t++) W[t] = Sha1.ROTL(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1);
// 2 - initialise five working variables a, b, c, d, e with previous hash value
a = H0; b = H1; c = H2; d = H3; e = H4;
// 3 - main loop
for (var t=0; t<80; t++) {
var s = Math.floor(t/20); // seq for blocks of 'f' functions and 'K' constants
var T = (Sha1.ROTL(a,5) + Sha1.f(s,b,c,d) + e + K[s] + W[t]) & 0xffffffff;
e = d;
d = c;
c = Sha1.ROTL(b, 30);
b = a;
a = T;
}
// 4 - compute the new intermediate hash value (note 'addition modulo 2^32')
H0 = (H0+a) & 0xffffffff;
H1 = (H1+b) & 0xffffffff;
H2 = (H2+c) & 0xffffffff;
H3 = (H3+d) & 0xffffffff;
H4 = (H4+e) & 0xffffffff;
}
return Sha1.toHexStr(H0) + Sha1.toHexStr(H1) + Sha1.toHexStr(H2) +
Sha1.toHexStr(H3) + Sha1.toHexStr(H4);
};
/**
* Function 'f' [§4.1.1].
* #private
*/
Sha1.f = function(s, x, y, z) {
switch (s) {
case 0: return (x & y) ^ (~x & z); // Ch()
case 1: return x ^ y ^ z; // Parity()
case 2: return (x & y) ^ (x & z) ^ (y & z); // Maj()
case 3: return x ^ y ^ z; // Parity()
}
};
/**
* Rotates left (circular left shift) value x by n positions [§3.2.5].
* #private
*/
Sha1.ROTL = function(x, n) {
return (x<<n) | (x>>>(32-n));
};
/**
* Hexadecimal representation of a number.
* #private
*/
Sha1.toHexStr = function(n) {
// note can't use toString(16) as it is implementation-dependant,
// and in IE returns signed numbers when used on full words
var s="", v;
for (var i=7; i>=0; i--) { v = (n>>>(i*4)) & 0xf; s += v.toString(16); }
return s;
};
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/** Extend String object with method to encode multi-byte string to utf8
* - monsur.hossa.in/2012/07/20/utf-8-in-javascript.html */
if (typeof String.prototype.utf8Encode == 'undefined') {
String.prototype.utf8Encode = function() {
return unescape( encodeURIComponent( this ) );
};
}
/** Extend String object with method to decode utf8 string to multi-byte */
if (typeof String.prototype.utf8Decode == 'undefined') {
String.prototype.utf8Decode = function() {
try {
return decodeURIComponent( escape( this ) );
} catch (e) {
return this; // invalid UTF-8? return as-is
}
};
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
if (typeof module != 'undefined' && module.exports) module.exports = Sha1; // CommonJs export
if (typeof define == 'function' && define.amd) define([], function() { return Sha1; }); // AMD
Sha1.getDeterministicBuckets = function(customerId,algorithmIndex,testNumber) {
var testDescriptors = {
28:{s:100, d:'1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1'},
29:{s:21, d:'40/3/3/3/3/3/3/3/3/3/3/3/3/3/3/3/3/3/3/3/3'}
};
var seed = (customerId+testNumber).toString();
var sha1 = Sha1.hash(seed);
var end = sha1.substr(36)
var c = parseInt(end, 16)/65535.0;
var result = '';
/*
if ( algorithmIndex == 3 )
if ( c < 0.10 ) result = 9;
else if ( c < 0.20 ) result = 8;
else if ( c < 0.30 ) result = 7;
else if ( c < 0.40 ) result = 6;
else if ( c < 0.50 ) result = 5;
else if ( c < 0.60 ) result = 4;
else if ( c < 0.70 ) result = 3;
else if ( c < 0.80 ) result = 2;
else if ( c < 0.90 ) result = 1;
else result = 0;
*/
/* (on 6/3/13) Bad inputs (and/or logged out users) yield a -1. */
if ( customerId == null || algorithmIndex == null || testNumber == null ) {
result = -1;
if( algorithmIndex < 1 || algorithmIndex > 27)
result = 0;
/* 25/25/50 */
}else if ( algorithmIndex == 1 ) {
if ( c < 0.25 ) result = 2;
else if ( c < 0.50 ) result = 1;
else result = 0;
/* 1/99 */
}else if ( algorithmIndex == 2 ) {
if ( c < 0.01 ) result = 1
else result = 0;
/* 10/10/10/... */
}else if ( algorithmIndex == 3 ){
if ( c < 0.10 ) result = 9;
else if ( c < 0.20 ) result = 8;
else if ( c < 0.30 ) result = 7;
else if ( c < 0.40 ) result = 6;
else if ( c < 0.50 ) result = 5;
else if ( c < 0.60 ) result = 4;
else if ( c < 0.70 ) result = 3;
else if ( c < 0.80 ) result = 2;
else if ( c < 0.90 ) result = 1;
else result = 0;
/* 25/25/25/25 */
}else if ( algorithmIndex == 4 ) {
if ( c < 0.25 ) result = 3;
else if ( c < 0.50 ) result = 2;
else if ( c < 0.75 ) result = 1;
else result = 0;
/* 50/50 */
}else if ( algorithmIndex == 5 ) {
if ( c < 0.50 ) result = 1;
else result = 0;
/* 10/90 */
}else if ( algorithmIndex == 6 ) {
if ( c < 0.10 ) result = 1;
else result = 0;
/* 10/10/10/10/10/50 */
}else if ( algorithmIndex == 7 ) {
if ( c < 0.10 ) result = 5;
else if ( c < 0.20 ) result = 4;
else if ( c < 0.30 ) result = 3;
else if ( c < 0.40 ) result = 2;
else if ( c < 0.50 ) result = 1;
else result = 0;
/* 20/20/20/20/20 */
}else if ( algorithmIndex == 8 ){
if ( c < 0.20 ) result = 4;
else if ( c < 0.40 ) result = 3;
else if ( c < 0.60 ) result = 2;
else if ( c < 0.80 ) result = 1;
else result = 0;
/* 96/2/2 */
}else if ( algorithmIndex == 9 ) {
if ( c < 0.02 ) result = 2;
else if ( c < 0.04 ) result = 1;
else result = 0;
/* 80/20 */
}else if ( algorithmIndex == 10 ) {
if ( c < 0.20 ) result = 1;
else result = 0;
/* 12.5/12.5/12.5/etc */
}else if ( algorithmIndex == 11 ) {
if ( c < 0.125 ) result = 7;
else if ( c < 0.250 ) result = 6;
else if ( c < 0.375 ) result = 5;
else if ( c < 0.500 ) result = 4;
else if ( c < 0.625 ) result = 3;
else if ( c < 0.750 ) result = 2;
else if ( c < 0.875 ) result = 1;
else result = 0;
/* 50/10/20/20 */
}else if ( algorithmIndex == 12 ) {
if ( c < 0.20 ) result = 3;
else if ( c < 0.40 ) result = 2;
else if ( c < 0.50 ) result = 1;
else result = 0;
/* 100 */
}else if ( algorithmIndex == 13 ) {
result = 0;
/* 80/2/2/2/2/2/2/2/2/2/2 */
}else if ( algorithmIndex == 14 ) {
if ( c < 0.02 ) result = 10;
else if ( c < 0.04 ) result = 9;
else if ( c < 0.06 ) result = 8;
else if ( c < 0.08 ) result = 7;
else if ( c < 0.10 ) result = 6;
else if ( c < 0.12 ) result = 5;
else if ( c < 0.14 ) result = 4;
else if ( c < 0.16 ) result = 3;
else if ( c < 0.18 ) result = 2;
else if ( c < 0.20 ) result = 1;
else result = 0;
/* 11/11/3/3/3/3/.... */
}else if ( algorithmIndex == 15 ) {
if ( c < 0.03 ) result = 27;
else if ( c < 0.06 ) result = 26;
else if ( c < 0.09 ) result = 25;
else if ( c < 0.12 ) result = 24;
else if ( c < 0.15 ) result = 23;
else if ( c < 0.18 ) result = 22;
else if ( c < 0.21 ) result = 21;
else if ( c < 0.24 ) result = 20;
else if ( c < 0.27 ) result = 19;
else if ( c < 0.30 ) result = 18;
else if ( c < 0.33 ) result = 17;
else if ( c < 0.36 ) result = 16;
else if ( c < 0.39 ) result = 15;
else if ( c < 0.42 ) result = 14;
else if ( c < 0.45 ) result = 13;
else if ( c < 0.48 ) result = 12;
else if ( c < 0.51 ) result = 11;
else if ( c < 0.54 ) result = 10;
else if ( c < 0.57 ) result = 9;
else if ( c < 0.60 ) result = 8;
else if ( c < 0.63 ) result = 7;
else if ( c < 0.66 ) result = 6;
else if ( c < 0.69 ) result = 5;
else if ( c < 0.72 ) result = 4;
else if ( c < 0.75 ) result = 3;
else if ( c < 0.78 ) result = 2;
else if ( c < 0.89 ) result = 1;
else result = 0;
/* 23/23/23/23/8 */
} else if ( algorithmIndex == 16 ) {
if ( c < 0.08 ) result = 4;
else if ( c < 0.31 ) result = 3;
else if ( c < 0.54 ) result = 2;
else if ( c < 0.77 ) result = 1;
else result = 0;
/* 97/0.5/0.5/0.5/0.5/0.5?0.5 */
}else if ( algorithmIndex == 17 ) {
if ( c < 0.005 ) result = 6;
else if ( c < 0.010 ) result = 5;
else if ( c < 0.015 ) result = 4;
else if ( c < 0.020 ) result = 3;
else if ( c < 0.025 ) result = 2;
else if ( c < 0.030 ) result = 1;
else result = 0;
/* 80/10/10 */
} else if ( algorithmIndex == 18 ){
if ( c < 0.10 ) result = 2;
else if ( c < 0.20 ) result = 1;
else result = 0;
/* 70/10/10/10 */
} else if ( algorithmIndex == 19 ){
if ( c < 0.10 ) result = 3;
else if ( c < 0.20 ) result = 2;
else if ( c < 0.30 ) result = 1;
else result = 0;
/* 90/5/5 */
}else if ( algorithmIndex == 20 ){
if ( c < 0.05 ) result = 2;
else if ( c < 0.10 ) result = 1;
else result = 0;
/* 80/5/5/5/5 */
}else if ( algorithmIndex == 21 ){
if ( c < 0.05 ) result = 4;
else if ( c < 0.10 ) result = 3;
else if ( c < 0.15 ) result = 2;
else if ( c < 0.20 ) result = 1;
else result = 0;
/* 45/45/10 */
}else if ( algorithmIndex == 22 ) {
if ( c < 0.10 ) result = 2;
else if ( c < 0.55 ) result = 1;
else result = 0;
/* 5.88 x 17 ... seriously? */
} else if ( algorithmIndex == 23 ){
if ( c < 0.0588 ) result = 16;
else if ( c < 0.1176 ) result = 15
else if ( c < 0.1764 ) result = 14;
else if ( c < 0.2352 ) result = 13;
else if ( c < 0.2940 ) result = 12;
else if ( c < 0.3528 ) result = 11;
else if ( c < 0.4116 ) result = 10;
else if ( c < 0.4704 ) result = 9;
else if ( c < 0.5292 ) result = 8;
else if ( c < 0.5880 ) result = 7;
else if ( c < 0.6468 ) result = 6;
else if ( c < 0.7056 ) result = 5;
else if ( c < 0.7644 ) result = 4;
else if ( c < 0.8232 ) result = 3;
else if ( c < 0.8820 ) result = 2;
else if ( c < 0.9401 ) result = 1;
else result = 0;
/* 97.5/2.5 */
}else if ( algorithmIndex == 24 ) {
if ( c < 0.025 ) result = 1;
else result = 0;
/* 92.5/7.5 */
}else if ( algorithmIndex == 25 ) {
if ( c < 0.075 ) result = 1;
else result = 0;
/* 50/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5/2.5 */
/* not sure why this one was setup with results asc vs desc; results were validated and match webstore */
}else if ( algorithmIndex == 26 ) {
if ( c < 0.025 ) result = 1;
else if ( c < 0.050 ) result = 2;
else if ( c < 0.075 ) result = 3;
else if ( c < 0.100 ) result = 4;
else if ( c < 0.125 ) result = 5;
else if ( c < 0.150 ) result = 6;
else if ( c < 0.175 ) result = 7;
else if ( c < 0.200 ) result = 8;
else if ( c < 0.225 ) result = 9;
else if ( c < 0.250 ) result = 10;
else if ( c < 0.275 ) result = 11;
else if ( c < 0.300 ) result = 12;
else if ( c < 0.325 ) result = 13;
else if ( c < 0.350 ) result = 14;
else if ( c < 0.375 ) result = 15;
else if ( c < 0.400 ) result = 16;
else if ( c < 0.425 ) result = 17;
else if ( c < 0.450 ) result = 18;
else if ( c < 0.475 ) result = 19;
else if ( c < 0.500 ) result = 20;
else result = 0;
/* 33.3/33.3/33.3 */
} else if ( algorithmIndex == 27 ) {
if ( c < 0.333 ) result = 2;
else if ( c < 0.666 ) result = 1;
else result = 0;
} else {
if (algorithmIndex in testDescriptors) {
var distributions = testDescriptors[algorithmIndex].d.split('/');
var threshold = 0.0;
result = 0;
for (var i = 1; i < distributions.length; i++) {
threshold += parseFloat(distributions[i])/100.0;
if (c < threshold) {
result = i;
break;
}
}
}
}
return result;
};
return {bucketNumber: Sha1.getDeterministicBuckets(customerId, algorithmIndex, testId) , CustomerId: customerId};
""";
SELECT getDeterministicBuckets(7354430,4,5947) x
If your question is how to call your JS function in the example, you can follow https://cloud.google.com/bigquery/docs/reference/standard-sql/user-defined-functions#including-javascript-libraries to:
Upload the JS file to GCS bucket
Create a function to call the JS function, which will be something like
CREATE OR REPLACE FUNCTION yourDataset.getBuckets(customerId STRING, algorithmIndex FLOAT64, testId STRING)
RETURNS STRING
LANGUAGE js
OPTIONS (
library=["gs://my-bucket/path/to/lib1.js", "gs://my-bucket/path/to/lib2.js"]
)
AS """
return yourJS.getBuckets(...);
"""
Looks like your JavaScript is SHA-1 implementation in JavaScript
So, how about simply using built-in SHA1 function

Creating svg paths with javascript(shape morphing)

So I have this class which is used for shape morphing:
class ShapeOverlays {
constructor(elm) {
this.elm = elm;
this.path = elm.querySelectorAll('path');
this.numPoints = 18;
this.duration = 600;
this.delayPointsArray = [];
this.delayPointsMax = 300;
this.delayPerPath = 100;
this.timeStart = Date.now();
this.isOpened = false;
this.isAnimating = false;
}
toggle() {
this.isAnimating = true;
const range = 4 * Math.random() + 6;
for (var i = 0; i < this.numPoints; i++) {
const radian = i / (this.numPoints - 1) * Math.PI;
this.delayPointsArray[i] = (Math.sin(-radian) + Math.sin(-radian * range) + 2) / 4 * this.delayPointsMax;
}
if (this.isOpened === false) {
this.open();
} else {
this.close();
}
}
open() {
this.isOpened = true;
this.elm.classList.add('is-opened');
this.timeStart = Date.now();
this.renderLoop();
}
close() {
this.isOpened = false;
this.elm.classList.remove('is-opened');
this.timeStart = Date.now();
this.renderLoop();
}
updatePath(time) {
const points = [];
for (var i = 0; i < this.numPoints + 1; i++) {
points[i] = ease.cubicInOut(Math.min(Math.max(time - this.delayPointsArray[i], 0) / this.duration, 1)) * 100
}
let str = '';
str += (this.isOpened) ? `M 0 0 V ${points[0]} ` : `M 0 ${points[0]} `;
for (var i = 0; i < this.numPoints - 1; i++) {
const p = (i + 1) / (this.numPoints - 1) * 100;
const cp = p - (1 / (this.numPoints - 1) * 100) / 2;
str += `C ${cp} ${points[i]} ${cp} ${points[i + 1]} ${p} ${points[i + 1]} `;
}
str += (this.isOpened) ? `V 0 H 0` : `V 100 H 0`;
return str;
}
render() {
if (this.isOpened) {
for (var i = 0; i < this.path.length; i++) {
this.path[i].setAttribute('d', this.updatePath(Date.now() - (this.timeStart + this.delayPerPath * i)));
}
} else {
for (var i = 0; i < this.path.length; i++) {
this.path[i].setAttribute('d', this.updatePath(Date.now() - (this.timeStart + this.delayPerPath * (this.path.length - i - 1))));
}
}
}
renderLoop() {
this.render();
if (Date.now() - this.timeStart < this.duration + this.delayPerPath * (this.path.length - 1) + this.delayPointsMax) {
requestAnimationFrame(() => {
this.renderLoop();
});
}
else {
this.isAnimating = false;
}
}
}
(function() {
const elmHamburger = document.querySelector('.hamburger');
const gNavItems = document.querySelectorAll('.global-menu__item');
const elmOverlay = document.querySelector('.shape-overlays');
const overlay = new ShapeOverlays(elmOverlay);
elmHamburger.addEventListener('click', () => {
if (overlay.isAnimating) {
return false;
}
overlay.toggle();
if (overlay.isOpened === true) {
elmHamburger.classList.add('is-opened-navi');
for (var i = 0; i < gNavItems.length; i++) {
gNavItems[i].classList.add('is-opened');
}
} else {
elmHamburger.classList.remove('is-opened-navi');
for (var i = 0; i < gNavItems.length; i++) {
gNavItems[i].classList.remove('is-opened');
}
}
});
}());
Can some one please explain this code? I don't really get how the paths are created using time,how the points are placed and how could I modify it.What is range used for? Why are trigonometral functions used for the delayPointsArray?
Basically it's this part that I don't get:
updatePath(time) {
const points = [];
for (var i = 0; i < this.numPoints + 1; i++) {
points[i] = ease.cubicInOut(Math.min(Math.max(time - this.delayPointsArray[i], 0) / this.duration, 1)) * 100
}
let str = '';
str += (this.isOpened) ? `M 0 0 V ${points[0]} ` : `M 0 ${points[0]} `;
for (var i = 0; i < this.numPoints - 1; i++) {
const p = (i + 1) / (this.numPoints - 1) * 100;
const cp = p - (1 / (this.numPoints - 1) * 100) / 2;
str += `C ${cp} ${points[i]} ${cp} ${points[i + 1]} ${p} ${points[i + 1]} `;
}
str += (this.isOpened) ? `V 0 H 0` : `V 100 H 0`;
return str;
}
render() {
if (this.isOpened) {
for (var i = 0; i < this.path.length; i++) {
this.path[i].setAttribute('d', this.updatePath(Date.now() - (this.timeStart + this.delayPerPath * i)));
}
} else {
for (var i = 0; i < this.path.length; i++) {
this.path[i].setAttribute('d', this.updatePath(Date.now() - (this.timeStart + this.delayPerPath * (this.path.length - i - 1))));
}
}
}
Why is time being used? What is the purpose of this:
points[i] = ease.cubicInOut(Math.min(Math.max(time - this.delayPointsArray[i], 0) / this.duration, 1)) * 100
If you look at how updatePath() is being called, it's like this:
this.updatePath(Date.now() - (this.timeStart + this.delayPerPath * i))
So the time value passed in is the difference between the current time, and the start time of the path we are working with.
So what then is the line of code you are interested in, doing?
points[i] = ease.cubicInOut(Math.min(Math.max(time - this.delayPointsArray[i], 0) / this.duration, 1)) * 100
I'm going to ignore delayPointsArray. It is modifying the start time slightly based on angle. Without seeing the full demo, I'm not sure of the reason for that.
The purpose of this line of code is to calculate how far through the current path's animation we are. The result is in the form of a coordinate value from 0 to 100.
It's doing a lot in that one line of code. So let's break down the individual steps.
Firstly, we are clamping the elapsed time to minimum of 0.
Math.max(time, 0)
In other words, anything before the animation start time becomes zero.
Then we divide by the animation's duration.
Math.max(time, 0) / duration
This will result in a value from 0, representing the start of the animation, to 1, representing the end of the animation. However, the value might also be greater than 1 if the elapsed time is after the end of the animation. Hence the next step.
Now clamp this value to a maximum of 1.
Math.min( Math.max(time, 0) / duration, 1)
We now have a value >= 0 and <= 1 whichdescribes where in the course of the animation, the path is supposed to be. 0 if we should be at the animations start position. 1 if we should be at the animations end position. And somewhere in between if the animation is in progress.
However this value is strictly linear, corresponding with the progression of time. And usually linear movement is not what you want. It is unnatural. Objects accelarate when the start moving and decelerate when the come to a stop. That will be what the easeInOut() function will be doing. If you are not familiar with easing curves, take a look at the diagram below.
Source: Google: The Basics of Easing
So we pass in a linear time value from 0..1 (horizontal axis). It will return a modified value that takes into account acceleration and deceleration.
The final step is to multiply by 100, to convert to a final coordinate value (0..100).
Hope this helps.

javascript minesweeper placed unnecessary "1"

i wrote a minesweeper in JavaScript which was working fine for a while, and then randomly on 1 run (i was trying to improve the styling) it gave me this:
note the "1" in the upper-right corner as well as 2 missing 1's two and three spaces below it
here is my function for adding numbers to squares:
function nextToBombCheck(event) {
//reset bomb count
bombCount = 0 ;
//initialize variable for checking nerby boxes
var nextToBox = 0;
//asign the box's id as a number
var boxNum = parseInt(event.id);
var checkSide = 0;
for ( var i = 9 ; i <= 11 ; i++ ) {
nextToBox = boxNum + i;
//check if its a wrap
if ( ( nextToBox%10 === 0 && boxNum%10 === 9 ) || ( nextToBox%10 === 9 && boxNum%10 === 0 ) ) {
continue;
//check boxes below
} else if ( bomb.indexOf( nextToBox ) >= 0 ) {
bombCount++;
}
}
for ( i = -1 ; i <= 1 ; i++ ) {
nextToBox = boxNum + i;
//check if its a wrap (above and below wont work anyway)
if ( ( nextToBox%10 === 0 && boxNum%10 === 9 ) || ( nextToBox%10 === 9 && boxNum%10 === 0 ) ) {
continue;
//check boxes alongside
} else if ( bomb.indexOf( nextToBox ) >= 0 ) {
bombCount++;
}
}
for ( i = -11 ; i <= -9 ; i++ ) {
nextToBox = boxNum + i;
if ( ( nextToBox%10 === 0 && boxNum%10 === 9 ) || ( nextToBox%10 === 9 && boxNum%10 === 0 ) ) {
continue;
//check boxes above
} else if ( bomb.indexOf( nextToBox ) >= 0 ) {
bombCount++;
}
}
//set class(colors) based on bombCount
event.className = classList[ bombCount ];
if ( bombCount !== 0 ) {
//write number of neighboring bombs
event.innerHTML = bombCount;
}
}
my program works on using a table and each td has an id 0-99
heres a link if that helps
Nice game. But you commit the common error of counting the last index. Do you see that your table have size of 11x11 = 121? But in your program you use
var rowAmount = 10;
var columnAmount = 10;
cellAmount = columnAmount * rowAmount;
which is wrong. The for loop also explicitly assume there are 11 column:
for ( i = 0 ; i <= rowAmount ; i++ ) {
gameBox += "<tr>";
for ( var j = 0 ; j <= columnAmount ; j++ ) {
var idValue = i * 10 + j;
gameBox += "<td class = 'box' id = '" + idValue + "' onclick = 'process(this);' ></td>"; }
gameBox += "</tr>";
}
but idValue is using 10 column. It means that your program will ignore the last column. Change that in all your codes and you will be fine.
I believe that the problem is related to the multiple elements with the same id as you can see in the screen shot from Chrome inspector. As you can notice the last cell of the row and the first cell of the next row have the same id. And this is true for all rows.
Instead of using modulo trickery etc, use X and Y coordinates and have a function to get a cell id from given X and Y, that is
function getCellId(x, y) {
return 'cell-' + x + '-' + y);
}
And name your cell id's cell-0-0 -> cell-9-9
Then the neighboring cells are
(x - 1, y - 1)
(x, y - 1)
(x + 1, y - 1)
(x - 1, y )
(x + 1, y )
(x - 1, y + 1)
(x, y + 1)
(x + 1, y + 1)
This problem could have also be avoided, provided that this approach was used.

How to validate a EAN / GTIN barcode in JavaScript

How can I check if a string is a valid EAN / GTIN barcode in JavaScript?
I need checks for EAN8, EAN12, EAN13, EAN14, EAN18 and also GTIN12, GTIN13, GTIN14.
EDIT I also created a npm module, which can be found on github.
I created a small library, which supports EAN8, EAN12, EAN13, EAN14, EAN18, GTIN12, GTIN13 and GTIN14.
It works inside node.js and all modern browsers.
barcoder.js:
/*!
* Barcoder
* Copyright (c) 2013 mifitto GmbH <dominik#mifitto.com>
* MIT Licensed
*/
(function() {
'use strict';
/**
* Library version.
*/
var version = '1.1.0';
/**
* Supported formats
*/
var minValidLength = 6;
var maxValidLength = 18;
var usualValidChars = /^\d+$/;
var formats = {
'ean8' : { validChars : /^\d+$/, validLength : 8 },
'ean12' : { validChars : /^\d+$/, validLength : 12 },
'ean13' : { validChars : /^\d+$/, validLength : 13 },
'ean14' : { validChars : /^\d+$/, validLength : 14 },
'ean18' : { validChars : /^\d+$/, validLength : 18 },
'gtin12' : { validChars : /^\d+$/, validLength : 12 },
'gtin13' : { validChars : /^\d+$/, validLength : 13 },
'gtin14' : { validChars : /^\d+$/, validLength : 14 }
};
/**
* Validates the checksum (Modulo 10)
* GTIN implementation factor 3
*
* #param {String} value The barcode to validate
* #return {Boolean}
* #api private
*/
var validateGtin = function( value ) {
var barcode = value.substring( 0, value.length - 1 );
var checksum = parseInt( value.substring( value.length - 1 ), 10 );
var calcSum = 0;
var calcChecksum = 0;
barcode.split('').map(function( number, index ) {
number = parseInt( number, 10 );
if ( value.length % 2 === 0 ) {
index += 1;
}
if ( index % 2 === 0 ) {
calcSum += number;
}
else {
calcSum += number * 3;
}
});
calcSum %= 10;
calcChecksum = (calcSum === 0) ? 0 : (10 - calcSum);
if ( calcChecksum !== checksum ) {
return false;
}
return true;
};
/**
* Barcoder class
*
* #param {string} format See formats
* #param {Object} options Valid option `enableZeroPadding`, defaults to `true`
* #api public
*/
var Barcoder = function ( format, options ) {
if ( format && !formats[format] ) throw new Error( '"format" invalid' );
this.format = (format) ? formats[format] : 'autoSelect';
this.options = (options) ? options : { enableZeroPadding : true };
if ( !this.options.enableZeroPadding ) {
this.options.enableZeroPadding = true;
}
};
/**
* Validates a barcode
*
* #param {string} barcode EAN/GTIN barcode
* #return {Boolean}
* #api public
*/
Barcoder.prototype.validate = function( barcode ) {
var self = this;
if ( self.format === 'autoSelect' ) {
if ( barcode.length < minValidLength || barcode.length > maxValidLength ) {
return false;
}
var isValidGtin = validateGtin( barcode );
var paddedBarcode = barcode;
var successfullyPadded = false;
if ( !isValidGtin ) {
var possiblyMissingZeros = maxValidLength - barcode.length;
while( possiblyMissingZeros-- ) {
paddedBarcode = '0' + paddedBarcode;
if ( validateGtin( paddedBarcode ) ) {
isValidGtin = true;
successfullyPadded = true;
break;
}
}
}
return {
possibleType: (barcode.length > 8) ? 'GTIN' + barcode.length : 'EAN8 / padded GTIN',
isValid: isValidGtin
};
}
var validChars = self.format.validChars;
var validLength = self.format.validLength;
var enableZeroPadding = self.options.enableZeroPadding;
if ( validChars.exec( barcode ) === null ) {
return false;
}
if ( enableZeroPadding && barcode.length < validLength ) {
var missingZeros = validLength - barcode.length;
while( missingZeros-- ) {
barcode = '0' + barcode;
}
}
else if ( !enableZeroPadding && barcode.length != validLength ) {
return false;
}
else if ( barcode.length > validLength ) {
return false;
}
return validateGtin( barcode );
};
/**
* Export
*/
if ( 'undefined' !== typeof module && module.exports ) {
module.exports = Barcoder;
exports.version = version;
}
if ( 'undefined' === typeof ender ) {
this['Barcoder'] = Barcoder;
}
if ( 'function' === typeof define && define.amd ) {
define('Barcoder', [], function () {
return Barcoder;
});
}
}).call( this );
Installation:
$ npm install barcoder
Usage:
var Barcoder = require('barcoder');
var ean1 = '0016T20054453';
var ean2 = '9330071314999';
var validator = new Barcoder('ean13');
console.log( '%s ean1 is valid: %s', ean1, validator.validate( ean1 ) );
console.log( '%s ean2 is valid: %s', ean1, validator.validate( ean2 ) );
// or /w automatic type selection
validator = new Barcoder();
var validation1 = validator.validate( ean1 );
var validation2 = validator.validate( ean2 );
console.log( '%s is valid: %s and has guessed type: %s', ean1, validation1.isValid, validation1.possibleType );
console.log( '%s is valid: %s and has guessed type: %s', ean2, validation2.isValid, validation2.possibleType );
I am not sure why, but #doms solution did not work correctly for me. Also I would like to both calculate new codes as well as verify old ones. I ended up with this, that I have verified to be working in my browsers atleast:
function eanCheckDigit(s){
var result = 0;
for (let counter = s.length-1; counter >=0; counter--){
result = result + parseInt(s.charAt(counter)) * (1+(2*(counter % 2)));
}
return (10 - (result % 10)) % 10;
}
2020 Update - Had to add let in front of counter otherwise it was saying counter was not defined.
2020 2nd Update - After lots of fighting with this, I realized this formula only works for UPC's passed in that are 10(or even digits in length). If you pass one in that is 11 digits, this doesn't work. So I've modified it to work with any length UPC. Let me know if this can be written cleaner.
function eanCheckDigit(s){
let result = 0;
let i = 1;
for (let counter = s.length-1; counter >=0; counter--){
result = result + parseInt(s.charAt(counter)) * (1+(2*(i % 2)));
i++;
}
return (10 - (result % 10)) % 10;
}
Here is a short version that can check if the EAN13 check digit is valid:
var checkSum = ean.split('').reduce(function(p,v,i) {
return i % 2 == 0 ? p + 1 * v : p + 3 * v;
}, 0);
if (checkSum % 10 != 0) {
alert('error');
}
GS1 US published the check digit calculation algorithm for GTIN. It uses padding to calculate various barcodes and is actually a lot simpler than other methods I found above here.
It works with GTIN barcodes: GTIN-8, GTIN-12 (UPC), GTIN-13 (EAN) and GTIN-14 (ITF-14).
function isValidBarcode(value) {
// We only allow correct length barcodes
if (!value.match(/^(\d{8}|\d{12,14})$/)) {
return false;
}
const paddedValue = value.padStart(14, '0');
let result = 0;
for (let i = 0; i < paddedValue.length - 1; i += 1) {
result += parseInt(paddedValue.charAt(i), 10) * ((i % 2 === 0) ? 3 : 1);
}
return ((10 - (result % 10)) % 10) === parseInt(paddedValue.charAt(13), 10);
}
Here is my solution, checking for different length barcodes using the specification to calculate the check digit at the end (see note):
// ean/gtin validation for 8, 12, 13 & 14 digit barcodes
function codeOnBlur(barcode) {
var barcodeLengthArr = [8, 12, 13, 14];
var allowedChars = new RegExp(/\d{8,14}/); // >7 & <15
// put numbers in array and convert to type Int.
var barcodeArray = barcode.split('');
for( var i = 0; i < barcodeArray.length; i++) {
barcodeArray[i] = parseInt(barcodeArray[i], 10);
}
// get the last digit for checking later
var checkDigit = barcodeArray.slice(-1)[0];
// we'll need a to compare it to this:
var remainder = 0;
// check if input (barcode) is in the array and check against the regex.
if (($.inArray(barcode.length, barcodeLengthArr) > -1) && (allowedChars.test(barcode))) {
console.log("barcodeArray ", barcodeArray, " :: checkDigit ", checkDigit);
// Pop the last item from the barcode array, test if the length is
// odd or even (see note on calculating the check digit) and
// multiply each item in array based in position:
var total = 0;
barcodeArray.pop();
// odd length after pop
if (barcodeArray.length % 2 === 1) {
for (var i = barcodeArray.length - 1; i >= 0; i--) {
barcodeArray[i] = i % 2 === 0 ? barcodeArray[i] * 3 : barcodeArray[i] * 1;
total += barcodeArray[i];
}
// even length after pop
} else if (barcodeArray.length % 2 === 0) {
for (var i = barcodeArray.length - 1; i >= 0; i--) {
barcodeArray[i] = i % 2 === 0 ? barcodeArray[i] * 1 : barcodeArray[i] * 3;
total += barcodeArray[i];
}
} else {
// validation passed = false
}
// calculate the remainder of totalrounded up to nearest multiple of 10:
remainder = (Math.ceil((total + 1) / 10) * 10) - total;
console.log("loop total = ", total, ", remainder: ", remainder);
if ( remainder === checkDigit ) {
//validation passed = true;
return;
} else {
//validation passed = false;
}
} else {
//validation Passed = false;
}
}
I'm certain this code can be tidied up some :)
Manually checking the "integrity bit" or check digit:
barcode: 13: 4 0 1 1 2 0 0 2 9 6 9 0 8
8: 5 0 8 1 8 9 0 7
multiplier: 3 1 3 1 3 1 3 1 3 1 3 1 check digit
To take the 8 digit code working backwards:
0*1 + 9*3 + 8*1 + 1*3 + 8*1 + 0*3 + 5*1 = 73
Difference from 73 to 80 is 7 (the specification will have you round up to
the nearest power of 10).
7 is both the check digit and the remainder of 80-73.
This is what I came up with:
/**
* Test a string for valid EAN5 EAN8 EAN13 EAN14 EAN18
* #see: https://www.activebarcode.com/codes/ean13.html
* #param {string} ean A string to be tested
* #return {boolean} true for a valid EAN
* #author Vitim.us <https://stackoverflow.com/a/65928239/938822>
*/
function isValidEAN(ean) {
function testChecksum(ean) {
const digits = ean.slice(0, -1);
const checkDigit = ean.slice(-1) | 0;
let sum = 0;
for (let i = digits.length - 1; i >= 0; i--) {
sum += (digits.charAt(i) * (1 + (2 * (i % 2)))) | 0;
}
sum = (10 - (sum % 10)) % 10;
return sum === checkDigit;
}
ean = String(ean);
const isValidLength = ean.length === 18 || ean.length === 14 || ean.length === 13 || ean.length === 8 || ean.length === 5;
return isValidLength && /^\d+$/.test(ean) && testChecksum(ean);
}
I'm sorry if this code is a little too long, but this is what I have for verifying an EAN13 barcode:
function isBarcode(barcode) {
if (typeof barcode === 'number') {
throw 'RuntimeError: Barcode MUST NOT be in number format'
} else if (barcode.length!==12) {
throw 'RuntimeError: String length is not 12'
};
var _= barcode.toString().split("")
var _1 = 0
var _2 = 0
var __
for ($=0;$<=10;++$) {
_1+=+_[$]
};for ($=10;$>=0;$-=2) {
_2+=+_[$]
};_2*=2
var _3 = _1+_2
__=+_3.toString().substring(1,2)
if (__>9) {
__=+_3.toString().substring(1,2)
} else if (__===0) {
__=10
};
__=10-__
if (__===+_[11]) {
return true
}
return false
};

Categories

Resources