I am trying to do a simple If function in zapier that returns a number between 1-10 based on another number input. for example if the number input is equal to 7200000 it should output 2. so far i have this:
if (inputData.num === '7200000') {
output = '2';
} else {
output = inputData.num;
}
This is giving me the error "You must return a single object or array of objects."
Can anyone help with this?
Thanks in advance :)
I found the solution,
Input Data: ms = TimeEstimate
var d = new Date(1000*Math.round(inputData.ms/1000));
function pad(i) { return ('0'+i).slice(-2); }
var str = d.getUTCHours() + ',' + pad(d.getUTCMinutes());
console.log(str);
output = [{str}];
I am following the solutions from here:
How can I return a JavaScript string from a WebAssembly function
and here:
How to return a string (or similar) from Rust in WebAssembly?
However, when reading from memory I am not getting the desired results.
AssemblyScript file, helloWorldModule.ts:
export function getMessageLocation(): string {
return "Hello World";
}
index.html:
<script>
fetch("helloWorldModule.wasm").then(response =>
response.arrayBuffer()
).then(bytes =>
WebAssembly.instantiate(bytes, {imports: {}})
).then(results => {
var linearMemory = results.instance.exports.memory;
var offset = results.instance.exports.getMessageLocation();
var stringBuffer = new Uint8Array(linearMemory.buffer, offset, 11);
let str = '';
for (let i=0; i<stringBuffer.length; i++) {
str += String.fromCharCode(stringBuffer[i]);
}
debugger;
});
</script>
This returns an offset of 32. And finally yields a string that starts too early and has spaces between each letter of "Hello World":
However, if I change the array to an Int16Array, and add 8 to the offset (which was 32), to make an offset of 40. Like so:
<script>
fetch("helloWorldModule.wasm").then(response =>
response.arrayBuffer()
).then(bytes =>
WebAssembly.instantiate(bytes, {imports: {}})
).then(results => {
var linearMemory = results.instance.exports.memory;
var offset = results.instance.exports.getMessageLocation();
var stringBuffer = new Int16Array(linearMemory.buffer, offset+8, 11);
let str = '';
for (let i=0; i<stringBuffer.length; i++) {
str += String.fromCharCode(stringBuffer[i]);
}
debugger;
});
</script>
Then we get the correct result:
Why does the first set of code not work like its supposed to in the links I provided? Why do I need to change it to work with Int16Array to get rid of the space between "H" and "e" for example? Why do I need to add 8 bytes to the offset?
In summary, what on earth is going on here?
Edit: Another clue, is if I use a TextDecoder on the UInt8 array, decoding as UTF-16 looks more correct than decoding as UTF-8:
AssemblyScript uses utf-16: https://github.com/AssemblyScript/assemblyscript/issues/43
Additionally AssemblyScript stores the length of the string in the first 32 or 64 bits.
That's why my code behaves differently. The examples in the links at the top of this post were for C++ and Rust, which do string encoding differently
I have the following string:
SigV1i8njyrAGrbAfHRNdM3fmEu3kd7keGsqTTDG3Wt3tXqT153eFya2JsEigrK7Pjmh6HhEQLp5bmNXyeHsKNELW7cD3
Is there a javascript string compression function that can shorten this somehow?
I also need a way to extract it back to its original string state.
The idea is to convert the available base62 string into a higher base string. This way you save space. But doing this in vanilla JS (or using Jquery) is difficult because JS doesn't handle big numbers very well. With the help of an external library bigint.js, it is possible. You can test it here. This code was not written by me, but its quite useful:
var base_symbols = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~`!##$%^&*()-_=+[{]}\\|;:'\",<.>/?¿¡";
function baseConvert(src, from_base, to_base, src_symbol_table, dest_symbol_table) {
// From: convert.js: http://rot47.net/_js/convert.js
// Modified by MLM to work with BigInteger: https://github.com/peterolson/BigInteger.js
src_symbol_table = src_symbol_table ? src_symbol_table : base_symbols;
dest_symbol_table = dest_symbol_table ? dest_symbol_table : src_symbol_table;
if(from_base > src_symbol_table.length || to_base > dest_symbol_table.length) {
console.warn("Can't convert", src, "to base", to_base, "greater than symbol table length. src-table:", src_symbol_table.length, "dest-table:", dest_symbol_table.length);
return false;
}
var val = bigInt(0);
for(var i = 0; i < src.length; i ++) {
val = val.multiply(from_base).add(src_symbol_table.indexOf(src.charAt(i)));
}
if(val.lesser(0)) {
return 0;
}
var r = val.mod(to_base);
var res = dest_symbol_table.charAt(r);
var q = val.divide(to_base);
while(!q.equals(0)) {
r = q.mod(to_base);
q = q.divide(to_base);
res = dest_symbol_table.charAt(r) + res;
}
return res;
}
var input = 'SigV1i8njyrAGrbAfHRNdM3fmEu3kd7keGsqTTDG3Wt3tXqT153eFya2JsEigrK7Pjmh6HhEQLp5bmNXyeHsKNELW7cD3';
var a = baseConvert(input, 62, 80);
baseConvert(a, 80, 62);
The resultant output converts 94 characters into 82 characters:
SigV1i8njyrAGrbAfHRNdM3fmEu3kd7keGsqTTDG3Wt3tXqT153eFya2JsEigrK7Pjmh6HhEQLp5bmNXyeHsKNELW7cD3
$sIn3#WAto¿rf<zVn"+:Pkgq;&x.fciVZC7O)`0ii+sf/\X¿CM9Ad!0Z^q?t6uK=w}S8=JZhboIHd'fY\]Qf
SigV1i8njyrAGrbAfHRNdM3fmEu3kd7keGsqTTDG3Wt3tXqT153eFya2JsEigrK7Pjmh6HhEQLp5bmNXyeHsKNELW7cD3
To get better compression, just chanage the base_symbols to include a lot more characters and then convert the input into an even higher base.
I was wondering if it is possible to format numbers in Javascript template strings, for example something like:
var n = 5.1234;
console.log(`This is a number: $.2d{n}`);
// -> 5.12
Or possibly
var n = 5.1234;
console.log(`This is a number: ${n.toString('.2d')}`);
// -> 5.12
That syntax obviously doesn't work, it is just an illustration of the type of thing I'm looking for.
I am aware of tools like sprintf from underscore.string, but this seems like something that JS should be able to do out the box, especially given the power of template strings.
EDIT
As stated above, I am already aware of 3rd party tools (e.g. sprintf) and customised functions to do this. Similar questions (e.g. JavaScript equivalent to printf/String.Format) don't mention template strings at all, probably because they were asked before the ES6 template strings were around. My question is specific to ES6, and is independent of implementation. I am quite happy to accept an answer of "No, this is not possible" if that is case, but what would be great is either info about a new ES6 feature that provides this, or some insight into whether such a feature is on its way.
No, ES6 does not introduce any new number formatting functions, you will have to live with the existing .toExponential(fractionDigits), .toFixed(fractionDigits), .toPrecision(precision), .toString([radix]) and toLocaleString(…) (which has been updated to optionally support the ECMA-402 Standard, though).
Template strings have nothing to do with number formatting, they just desugar to a function call (if tagged) or string concatenation (default).
If those Number methods are not sufficient for you, you will have to roll your own. You can of course write your formatting function as a template string tag if you wish to do so.
You should be able to use the toFixed() method of a number:
var num = 5.1234;
var n = num.toFixed(2);
If you want to use ES6 tag functions here's how such a tag function would look,
function d2(pieces) {
var result = pieces[0];
var substitutions = [].slice.call(arguments, 1);
for (var i = 0; i < substitutions.length; ++i) {
var n = substitutions[i];
if (Number(n) == n) {
result += Number(substitutions[i]).toFixed(2);
} else {
result += substitutions[i];
}
result += pieces[i + 1];
}
return result;
}
which can then be applied to a template string thusly,
d2`${some_float} (you can interpolate as many floats as you want) of ${some_string}`;
that will format the float and leave the string alone.
Here's a fully ES6 version of Filip Allberg's solution above, using ES6 "rest" params. The only thing missing is being able to vary the precision; that could be done by making a factory function. Left as an exercise for the reader.
function d2(strs, ...args) {
var result = strs[0];
for (var i = 0; i < args.length; ++i) {
var n = args[i];
if (Number(n) == n) {
result += Number(args[i]).toFixed(2);
} else {
result += args[i];
}
result += strs[i+1];
}
return result;
}
f=1.2345678;
s="a string";
console.log(d2`template: ${f} ${f*100} and ${s} (literal:${9.0001})`);
While template-string interpolation formatting is not available as a built-in, you can get equivalent behavior with Intl.NumberFormat:
const format = (num, fraction = 2) => new Intl.NumberFormat([], {
minimumFractionDigits: fraction,
maximumFractionDigits: fraction,
}).format(num);
format(5.1234); // -> '5.12'
Note that regardless of your implementation of choice, you might get bitten by rounding errors:
(9.999).toFixed(2) // -> '10.00'
new Intl.NumberFormat([], {
minimumFractionDigits: 2,
maximumFractionDigits: 2, // <- implicit rounding!
}).format(9.999) // -> '10.00'
based on ES6 Tagged Templates (credit to https://stackoverflow.com/a/51680250/711085), this will emulate typical template string syntax in other languages (this is loosely based on python f-strings; I avoid calling it f in case of name overlaps):
Demo:
> F`${(Math.sqrt(2))**2}{.0f}` // normally 2.0000000000000004
"2"
> F`${1/3}{%} ~ ${1/3}{.2%} ~ ${1/3}{d} ~ ${1/3}{.2f} ~ ${1/3}"
"33% ~ 33.33% ~ 0 ~ 0.33 ~ 0.3333333333333333"
> F`${[1/3,1/3]}{.2f} ~ ${{a:1/3, b:1/3}}{.2f} ~ ${"someStr"}`
"[0.33,0.33] ~ {\"a\":\"0.33\",\"b\":\"0.33\"} ~ someStr
Fairly simple code using :
var FORMATTER = function(obj,fmt) {
/* implements things using (Number).toFixed:
${1/3}{.2f} -> 0.33
${1/3}{.0f} -> 1
${1/3}{%} -> 33%
${1/3}{.3%} -> 33.333%
${1/3}{d} -> 0
${{a:1/3,b:1/3}}{.2f} -> {"a":0.33, "b":0.33}
${{a:1/3,b:1/3}}{*:'.2f',b:'%'} -> {"a":0.33, "b":'33%'} //TODO not implemented
${[1/3,1/3]}{.2f} -> [0.33, 0.33]
${someObj} -> if the object/class defines a method [Symbol.FTemplate](){...},
it will be evaluated; alternatively if a method [Symbol.FTemplateKey](key){...}
that can be evaluated to a fmt string; alternatively in the future
once decorators exist, metadata may be appended to object properties to derive
formats //TODO not implemented
*/
try {
let fracDigits=0,percent;
if (fmt===undefined) {
if (typeof obj === 'string')
return obj;
else
return JSON.stringify(obj);
} else if (obj instanceof Array)
return '['+obj.map(x=> FORMATTER(x,fmt))+']'
else if (typeof obj==='object' && obj!==null /*&&!Array.isArray(obj)*/)
return JSON.stringify(Object.fromEntries(Object.entries(obj).map(([k,v])=> [k,FORMATTER(v,fmt)])));
else if (matches = fmt.match(/^\.(\d+)f$/))
[_,fracDigits] = matches;
else if (matches = fmt.match(/^(?:\.(\d+))?(%)$/))
[_,fracDigits,percent] = matches;
else if (matches = fmt.match(/^d$/))
fracDigits = 0;
else
throw 'format not recognized';
if (obj===null)
return 'null';
if (obj===undefined) {
// one might extend the above syntax to
// allow for example for .3f? -> "undefined"|"0.123"
return 'undefined';
}
if (percent)
obj *= 100;
fracDigits = parseFloat(fracDigits);
return obj.toFixed(fracDigits) + (percent? '%':'');
} catch(err) {
throw `error executing F\`$\{${someObj}\}{${fmt}}\` specification: ${err}`
}
}
function F(strs, ...args) {
/* usage: F`Demo: 1+1.5 = ${1+1.5}{.2f}`
--> "Demo: 1+1.5 = 2.50"
*/
let R = strs[0];
args.forEach((arg,i)=> {
let [_,fmt,str] = strs[i+1].match(/(?:\{(.*)(?<!\\)\})?(.*)/);
R += FORMATTER(arg,fmt) + str;
});
return R;
}
sidenote: The core of the code is as follows. The heavy lifting is done by the formatter. The negative lookbehind is somewhat optional, and to let one escape actual curly braces.
let R = strs[0];
args.forEach((arg,i)=> {
let [_,fmt,str] = strs[i+1].match(/(?:\{(.*)(?<!\\)\})?(.*)/);
R += FORMATTER(arg,fmt) + str;
});
You can use es6 tag functions. I don't know ready for use of that.
It might look like this:
num`This is a number: $.2d{n}`
Learn more:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
https://developers.google.com/web/updates/2015/01/ES6-Template-Strings
I don't get it.
I can't increment the Tweet-ID ...
Here is a demo: http://jsbin.com/idupoq/1/edit
glb = {};
glb.lastTweetId = 0;
getTweets();
function getTweets()
{
console.info('# LAST ID');
console.log(glb.lastTweetId);
console.info('# TEST 1');
glb.lastTweetId++;
console.log(glb.lastTweetId);
console.info('# TEST 2');
glb.lastTweetId = glb.lastTweetId+1;
console.log(glb.lastTweetId);
console.info('# TEST 3, OK IS INT BUT PARSE AGAIN ');
glb.lastTweetId = parseInt(glb.lastTweetId);
glb.lastTweetId++;
console.log(glb.lastTweetId);
$.getJSON('http://search.twitter.com/search.json?q=%23wwm&since_id='+glb.lastTweetId+'&include_entities=true&result_type=mixed&lang=de&callback=?', function(data, textStatus)
{
if(data.results.length > 0)
{
glb.lastTweetId = data.results[0]['id'];
}
glb.tm= setTimeout('getTweets();',5000);
});
}
Thanks in advance!
This happens because the received ID is out of range of Number format, e.g.
271567725082578940 + 1 = 271567725082578940
You should use special libraries to work with large numbers. Some examples:
https://github.com/jtobey/javascript-bignum
http://jsfromhell.com/classes/bignumber
As others have said already, it is because of Number cannot express 271567725082578941. If all you ever want to do to this number is to increase it by one, then the following function should be all you need:
function stringInc(v){
var digits = v.toString().split('');
var i = digits.length-1;
while (digits[i]==9 && i>0){
digits[i] = 0;
i--;
}
digits[i] = 1+parseInt(digits[i]);
return digits.join('');
}
If you expect to want to do something more with the number, then you might be better off using a BigNumber library as suggested by VisioN.
Either way, you should note that you cannot read the tweet id from data.results[0]['id'], because that is interpreted as a Number and rounded to 271567725082578940. You need to use data.results[0]['id_str'].
See updated jsbin here: http://jsbin.com/idupoq/19/. Notice the console is logging the result from the server:
...
"geo":null,
"id": 271580395022217200,
"id_str":"271580395022217216",
"iso_language_code":"de"
...
So the value 271567725082578940 that you have been observing is incorrect as well.
Dirty but short
http://jsbin.com/idupoq/18/edit
glb.lastTweetId = ''+data.results[0]['id']+'';
var lastTwoDig = parseInt(glb.lastTweetId.substr(glb.lastTweetId.length-2));
var startDigit = glb.lastTweetId.substring(0, glb.lastTweetId.length-2);
lastTwoDig++;
if(lastTwoDig==01){ lastTwoDig = '01'; }
console.log(glb.lastTweetId);
console.log(' '+startDigit+''+lastTwoDig+' ');