I have used dropbox-api-content-hasher (gitrepo here) within a node.js environment for an Electron project with great success, but now I need to use it in a Phonegap/cordova project and I've no idea how to replace the following:
const fs = require('fs');
const dch = require('dropbox-content-hasher');
... with vanilla javascript so I can use it!
I have included the <script type="text/javascript" src="js/dropbox-content-hasher.js"></script> but I need to access the dch variable to do the following:
const hasher = dch.create();
and then access hasher the rest of what I need to do. I don't have the experience on how to convert it across, any ideas?
I am building in phonegap rather than cordova cli as I'm more experienced in this approach.
EDIT:
This is a fiddle of my attempt based on Alex's answer but I'm getting 'CryptoJS is not a constructor' in the web console. I don't know how to bring in the cryptojs library!
Fiddle here
I just needed the same and adapted the example from the dropbox repo.
I use the crypto-js library. The code is in ES6 and is used in a quasar-framework app (which btw. might be interesting for you, due to phonegap/cordova):
/**
* Computes a hash using the same algorithm that the Dropbox API uses for the
* the "content_hash" metadata field.
*
* The `digest()` method returns a hexadecimal-encoded version
* of the digest of the hash.
* The "content_hash" field in the Dropbox API is a hexadecimal-encoded version
* of the digest.
*
* Example:
*
* import DropboxContentHasher from 'dropboxContentHasher'
*
* let hasher = new DropboxContentHasher()
* hasher.update(content) // content is some string or CryptoJS.lib.WordArray
* return hasher.digest()
*/
import cryptoJS from 'crypto-js'
const BLOCK_SIZE = 4 * 1024 * 1024
class DropboxContentHasher {
constructor () {
this._overallHasher = cryptoJS.algo.SHA256.create()
this._blockHasher = cryptoJS.algo.SHA256.create()
this._blockPos = 0
}
update (data) {
let offset = 0
while (offset < data.length) {
if (this._blockPos === BLOCK_SIZE) {
this._overallHasher.update(this._blockHasher.finalize())
this._blockHasher = cryptoJS.algo.SHA256.create()
this._blockPos = 0
}
let spaceInBlock = BLOCK_SIZE - this._blockPos
let inputPartEnd = Math.min(data.length, offset + spaceInBlock)
let inputPartLength = inputPartEnd - offset
this._blockHasher.update(data.slice(offset, inputPartEnd))
this._blockPos += inputPartLength
offset = inputPartEnd
}
}
digest () {
if (this._blockPos > 0) {
this._overallHasher.update(this._blockHasher.finalize())
this._blockHasher = null
}
let r = this._overallHasher.finalize().toString()
this._overallHasher = null // Make sure we can't use this object anymore.
return r
}
}
export default DropboxContentHasher
Simple JavaScript implementation using crypto-js:
function computeContentHash(content) {
const BLOCK_SIZE = 4 * 1024 * 1024;
let hash = CryptoJS.algo.SHA256.create();
for (let p = 0; p < content.length; p += BLOCK_SIZE) {
let chunk = content.substr(p, BLOCK_SIZE);
hash.update(CryptoJS.SHA256(chunk));
}
return hash.finalize().toString();
}
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I wrote the bubble sort algorithm in JavaScript and Wasm using Rust and the JS code is faster than Rust code. How is this possible?
JavaScript code
import * as wasm from "wasm-comparision-sort-algorithms";
function main() {
const arr = generateRandomArray({size: 50000, min: 1, max: 1000})
const arr2 = [...arr]
console.time("Bubble Sort JS")
bubbleSort(arr)
console.timeEnd("Bubble Sort JS")
wasm.handle_bubble_sort(arr2)
}
/**
* Algorithm to sort an array of numbers using the bubble sort algorithm.
* #param {Number[]} arr - The array of numbers to sort.
*/
function bubbleSort(arr) {
const len = arr.length
for (let i = 0; i < len; i++) {
for (let j = 0; j < len - i - 1; j++) {
// Sort numbers
if (arr[j] > arr[j + 1]) {
const temp = arr[j]
arr[j] = arr[j + 1]
arr[j + 1] = temp
}
}
}
}
/**
* Generate a random array of numbers between a range of numbers.
* #param {Number} size - The size of the array to generate.
* #param {Number} min - The minimum number in the range.
* #param {Number} max - The maximum number in the range.
* #returns {Number[]} - The generated array of numbers.
*/
function generateRandomArray({
size, min, max}) {
const arr = []
for (let i = 0; i < size; i++) {
arr.push(Math.floor(Math.random() * (max - min + 1) + min))
}
return arr
}
document.addEventListener("click", main)
Rust code
mod utils;
use wasm_bindgen::prelude::*;
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
#[wasm_bindgen]
extern {
fn alert(s: &str);
}
#[wasm_bindgen]
pub fn handle_bubble_sort(array: JsValue) {
let mut elements: Vec<u32> = array.into_serde().unwrap();
web_sys::console::time_with_label("Bubble Sort WASM");
bubble_sort(&mut elements);
web_sys::console::time_end_with_label("Bubble Sort WASM");
alert(&format!("The sum of all elements is {}", sum));
}
/*
* Create a bubble sort algorithm
*/
pub fn bubble_sort(array: &mut [u32]) {
let _i = 0;
let _j = 1;
let _size_array = array.len();
for _i in 0.._size_array {
for _j in 0.._size_array - _i - 1 {
unsafe {
let t1 = *array.get_unchecked(_j);
let t2 = *array.get_unchecked(_j + 1);
if t1 > t2 {
array.swap_unchecked(_j, _j+1);
}
}
}
}
}
Cargo.toml
[package]
name = "wasm-comparision-sort-algorithms"
version = "0.1.0"
authors = ["a simple mortal"]
edition = "2018"
[lib]
crate-type = ["cdylib", "rlib"]
[features]
default = ["console_error_panic_hook"]
[dependencies]
wasm-bindgen = { version = "0.2.63", features = ["serde-serialize"] }
serde = { version = "1.0", features = ["derive"] }
web-sys = { version = "0.3.55", features = ["console"] }
# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
# code size when deploying.
console_error_panic_hook = { version = "0.1.6", optional = true }
# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
# compared to the default allocator's ~10K. It is slower than the default
# allocator, however.
#
# Unfortunately, `wee_alloc` requires nightly Rust when targeting wasm for now.
wee_alloc = { version = "0.4.5", optional = true }
[dev-dependencies]
wasm-bindgen-test = "0.3.13"
[profile.release]
# Tell `rustc` to optimize for small code size.
opt-level=3 # Optimal for time execution
The average times:
JavaScript: 5115 ms
Rust: 9499 ms
Version of environment:
I'm using wasm-pack version 0.10.1
Node version used from localhost server is: 16.13.0
Cargo and Rustc version: 1.57.0
I'm testing on Brave browser version: 1.31.88
I use wasm-pack build --release to build the project.
I'm attempting to create a revisable document, with the edits stored as fast-json-patched objects.
The rough outline is :
const jsonpatch = require('fast-json-patch');
/**
* Generate a doc, with all the state changes recorded as
* diffed objects.
* #param {object} docParams The parameters to generate the doc from
* #returns {object} the doc
*/
function generateDoc(docParams) {
const defaults = {
docnumber: 'TS99999',
edits: 1,
};
// create a complete set of properties to work from
const { docnumber, edits } = {
...defaults,
...docParams,
};
// basic docs setup
const doc = {
parameters: { docnumber, edits },
history: [],
state: { docnumber, notes: [] },
};
// update the doc 'edits' times
for (let edit = 0; edit < edits; edit++) {
// clone to preserve the current state
const currentState = JSON.parse(JSON.stringify(doc.state));
// add at least one note, up to every edit
const notesToAdd = Math.ceil(Math.random() * 5);
for (let i = 0; i < notesToAdd; i++) {
doc.state.notes.push('Note: ' + Math.ceil(Math.random() * 500));
}
doc.history.push(jsonpatch.compare(currentState, doc.state));
}
return doc;
}
/**
* Set the current doc state to the state at the spercifier point in time
* #param {object} doc The doc to update
* #param {integer} edit The point in time to use
* #returns {boolean} Was the doc set updated?
*/
function timetravel(doc, editPoint) {
if (
doc.parameters.currentedit === editPoint ||
editPoint > doc.parameters.edits ||
editPoint < 1
) {
return false; // don't travel too far into the future or past!
}
const patchesToApply = doc.history.slice(0, editPoint);
const patches = [].concat.apply([], patchesToApply);
let newDoc = {};
newDoc = jsonpatch.applyPatch(newDoc, patches).newDocument;
doc.state = newDoc;
doc.parameters.currentedit = editPoint;
return true;
}
// Testing....
const doc = generateDoc({
docnumber: 'TS99999',
edits: 5,
});
console.log(doc);
timetravel(doc, 2);
console.log(doc);
Clearly my understanding of what should be happening is wrong, as I get the following error...
/Users/dd/Code/patchtesting/node_modules/fast-json-patch/commonjs/core.js:14
obj[key] = this.value;
just at the jsonpatch.applyPatch line.
I've tried alternative approaches:
// seems to be one popular suggestion...
const patchesToApply = doc.history.slice(0, editPoint);
const patches = [].concat.apply([], patchesToApply);
doc.state = patches.reduce(jsonpatch.applyReducer, {});
doc.parameters.currentedit = editPoint;
or...
// Trying to see the effect of applying a single patch at a time...
patches.forEach(patch => {
console.log(patch);
newDoc = jsonpatch.applyPatch(newDoc, [patch]).newDocument;
console.log(newDoc);
});
The patches that are generated make sense, I just can't seem to apply them :-(
Sorry, it was a basic coding / fencepost-ish error:
...
// basic docs setup
const doc = {
parameters: { docnumber, edits },
history: [],
state: { docnumber, notes: [] },
};
// ADDED: need to record the initial state
doc.history.push(jsonpatch.compare({}, doc.state))
// update the doc 'edits' times
...
;
Is there a way to ignore some documented symbols conditionally?
I'd like to do something like this (pseudo-code):
/**
* #ignore if dev
*/
var a = 42;
/**
* #ignore if prod
*/
var b = 24;
In this example I would like to have my JSDoc generator to only document var a if I configured my generator to dev and vice versa for var b.
Is this possible?
You can implement your own jsdoc plugin to test an ignore condition and set its value in doclet.ignore property. Setting it to true will prevent the doclet being processed - not adding it to the final documentation.
exports.defineTags = function(dictionary) {
var env = require('jsdoc/env');
/*
* Usage: #customIgnore prod, test
*/
dictionary.defineTag('customIgnore', {
mustHaveValue: true,
onTagged: function(doclet, tag) {
var i;
// "envParams" is a property of your jsdoc.json
var environments = env.conf.envParams;
// Will hold "prod, test"
var tagValue = tag.value;
var conditionValues = tag.value.split(",");
for (i = 0; i < conditionValues.length && !doclet.ignore; i++) {
if (environments.indexOf(conditionValues[i].trim()) !== -1) {
doclet.ignore = true;
}
}
}
});
};
I hope I'm asking the question correctly, but essentially, is there a way in NodeJS to have a CommonJS module return a stream of data instead of a finalized chunk of data after a (long) computation? Assuming there is more than one way, what are those techniques?
For example, say I have a findPrimes function, written as a CommonJS module:
find-primes.js
/**
* #module findPrimes
* #param {int} n - Find all primes less than this number
* #return {array}
*/
module.exports = function(n) {
if (n < 2) {
return [];
} else if (n === 2) {
return [2];
}
var primes = [2];
for (let i = 3; i < n; i += 2) {
let is_prime = true;
let sq = Math.ceil(Math.sqrt(i));
for (let t = 2; t <= sq; t++) {
if (i % t === 0) {
is_prime = false;
break;
}
}
if (is_prime) {
primes.push(i);
}
}
return primes;
};
As you can see, this function returns an array of all the prime numbers less than its input. It returns the array after it has computed all those numbers.
So, say I go to use this module in a node script
index.js
const primes = require('./find-primes.js');
// Usage: `node index.js <num>`
let primes_less_than = process.argv[2];
console.log(primes(primes_less_than));
When I run the above script with an arg of 25, I get the following (expected) output:
$ node index.js 25
[ 2, 3, 5, 7, 11, 13, 17, 19, 23 ]
However, say I passed in a much larger number, like 10,000,000
$ node index.js 10000000
# Takes a while to run before outputting the numbers...
While this works, ideally I'd like the program to start writing out the numbers it has computed before it finishes.
So my program would still take a while to run, but it would start outputting information to the screen much faster than "compute EVERYTHING first, then output ALL results".
What is the best way to achieve this effect? Streams? Promises?
I'm open to any and all techniques for this, thanks.
You'll have to use the Stream class from nodejs, and the method should export a callback with a stream as the commentaries said:
const stream = require('stream');
function getPrimesStream(n, cb) {
const primesStream = new stream.Stream();
cb(null, primesStream);
if (n >= 2) {
primesStream.emit('data', 2);
}
const primes = [2];
for (let i = 3; i < n; i += 2) {
let isPrime = true;
const sq = Math.ceil(Math.sqrt(i));
for (let t = 2; t <= sq; t += 1) {
if (i % t === 0) {
isPrime = false;
break;
}
}
if (isPrime) {
primesStream.emit('data', i);
primes.push(i);
}
}
return primes;
}
getPrimesStream(1000, function (err, stream) {
stream.on('data', function (data) {
console.log(data);
});
stream.on('end', function() {
console.log('finished');
});
});
You may use Node.js's stream module for this. It's hard to answer your question within a few lines of code, but if you are really interested in how streams work, have a look at this video (this is me giving a talk about Node.js streams at the Node.js meetup in Munich, Germany).
Alternatively, you may use a generator function with yield, but this as well is hard to explain from scratch in a few lines.
Anyway, streams and generator functions are the terms you should look for.
I have not seen anything that specifically answers this question.
I intend to develop a text-based game that involves an action occurring every time an idle bar fills up(every x seconds passes)
I'm just trying to figure out the very basic layout of my javascript that will make the battling system in this game.
I'm trying to make the computer re-calculate pDamThisRound if pDamThisRound is not > baseD which is this case is 10.
If it is greater than baseD my code works and prints pDamThisRound. But if it isn't the code just prints nothing.
var baseD = 10;
var pStr = 25;
var pDam = Math.floor((baseD + pStr) / 2);
var pDamThisRound;
var pDamTR = function() {
pDamThisRound = (Math.floor(Math.random() * 2 * pDam));
};
pDamTR();
if(pDamThisRound > baseD) {
document.getElementById("h").innerHTML = pDamThisRound;
}
else {
pDamTR();
}
https://jsfiddle.net/qfnvf1y8/4/
the code just prints nothing
That's because there isn't any code which prints anything. Look at your else block:
else {
pDamTR();
}
What does that function do?:
var pDamTR = function() {
pDamThisRound = (Math.floor(Math.random() * 2 * pDam));
};
Nowhere do you produce any output.
Basically, if you want to print something then, well, print something. Just like you already do in your if block. For example:
document.getElementById("h").innerHTML = "something";
The function pDamTR is probably executing, the problem is that its assigning something to a variable, but doing nothing with it.
Here you go, a corrected version with a while operator:
https://jsfiddle.net/qfnvf1y8/6/
var baseD = 10;
var pStr = 25;
var pDam = Math.floor((baseD + pStr) / 2);
var pDamThisRound;
var pDamTR = function() {
pDamThisRound = (Math.floor(Math.random() * 2 * pDam));
};
pDamTR();
while(pDamThisRound <= baseD) {
pDamTR();
}
if(pDamThisRound > baseD) {
document.getElementById("h").innerHTML = pDamThisRound;
}
else {
pDamTR();
}
Regards,
Eugene
Several mistakes:
1) your else branch does not print anything
2) if you want pDamThisRound > baseD you need a while loop
while(pDamThisRound <= baseD) {
pDamTR();
}
printpDamTR();
function printpDamTR(){
document.getElementById("h").innerHTML = pDamThisRound;
}
The function printpDamTR would not be necessary, but it generally is a good idea to encapsulate such things, as you are probably going to use it more often. Also it increases the maintainability of your code since you loosen the dependencies between your JS and your HTML.
You can use setTimeout to help you, with something like this:
var baseD = 10;
var pStr = 25;
var pDam = Math.floor((baseD + pStr) / 2);
var timeoutDuration = 3000; // 3 seconds
window.setTimeout(function () {
// execute the check and the update logic here
var pDamThisRound = (Math.floor(Math.random() * 2 * pDam));
if(pDamThisRound > baseD) {
document.getElementById("h").innerHTML = pDamThisRound;
}
}, timeoutDuration);
This will execute the check every 3 seconds