I am working with an application called TEC-IT Wedge to interface with a grocery scale (for those not in the know a grocery scale is a glorified scale with a scanner.
The scale is connected to a serial port on the PC and thw wedge app monitors that port, the code below handles the scan of the barcode then requests the weight, all of this is working.
Where I am running into the issue is formating the returning weight from the scale.
the data returned from the scale is in the format of ASCII "S11####" so S110004 would be for an item weighing 0.04 pounds and this is how I need to send that wait to the application that we are using the scale to enter data with. For the code below a return of S110004 it returns 00.4
I think I am loosing 0's in the grab of the digits for some reason to place the decimal poit in the correct position.
var cartonverify = Left(DATARAW, 5);
var weightverify = Left(DATARAW, 3);
if (cartonverify == "S08B3")
{
ActivateWindow("Untitled - Notepad");
SendKeyStrokes(DATARAW.replace(/^S08B3+/i, '') );
DATA = "";
WriteToDevice("S11\x0d", 1000);
}
if (weightverify == "S11")
{
ActivateWindow("Untitled - Notepad");
var cartwieght = Right(DATA, 4);
if (cartwieght.length == 4)
{
var cartounces = Right(cartwieght, 2);
var cartpounds = Left(cartwieght, 2);
var WMWeight = cartpounds + "." + cartounces;
SendKeyStrokes(WMWeight);
DATA = "";
}
}
Re-form your string to something that can be parsed as a number as desired.
var str = 'S110004';
str = str.replace(/S11(\d\d)(\d\d)/, '$1.$2'); // "00.04"
var num = parseFloat(str); // 0.04
Putting the decimal place in at the RegExp step also saves you from having to use division.
Related
I am using angular2-signaturepad to collect digital signatures in an angular 6 application. Some users are just drawing a simple dot or straight line. Is it possible to require users to enter more than a few dots or a line? I'm not trying to verify a name or full signature, just that they drew more than a tiny signature. Thank you in advance.
You can also validate for a minimum number of xy points in signaturePad.toData(). Here's an example validation method that looks for a minimum number of points.
hasComplexity(pad: SignaturePad, complexity?: number) {
if (!complexity) {
complexity = 10;
}
const points = pad.toData();
const pointCount = [].concat.apply([], points).length;
return points && pointCount >= complexity;
}
Usage example:
const isValid = this.hasComplexity(this.pad, 10);
My suggestion would be take canvas and check pixels
var p = c.getImageData(x, y, 1, 1).data;
var hex = "#" + ("000000" + rgbToHex(p[0], p[1], p[2])).slice(-6);
So you should check how many are not empty.
Source
So I am trying to solve project euler #25 via the big integer brute force method with this module. Everything seems to go properly until the 36'th term, which actually decreases. Then the terms increase as they should, and then decrease again; they never go over 10 million. I have also noticed the 36'th term has all digits correct except one as it is supposed to be 14930352 but I get 4930352 Could this be a problem with my code or a bug in the module?
var bigInt = require('big-integer');
var number = bigInt(1);
var last = bigInt(1);
for(i=0;i<50;i++){
number = number.add(last);
last = number.minus(last);
console.log(number.toString());
}
Looks like a bug in the library. If you use a tmp variable it works fine.
var bigInt = require('big-integer');
var number = bigInt(1);
var last = bigInt(1);
for(i=0;i<50;i++){
//number = number.add(last);
//last = number.minus(last);
var tmp = number.add(last);
last = number;
number = tmp;
console.log((i + 3) + ":" + number.toString());
}
How do I add the following text boxes together with the logic below?
oneTextBox = $120.00,
twoTextBox = .03*oneTextBox,
threeTextBox = oneTextBox + twoTextBox
I would also like the units of each text box to be in dollars ($).
function doGet(e) {
var app = UiApp.createApplication();
var VertPanel = app.createVerticalPanel().setId('VertPanel');
var oneTextBox = app.createTextBox().setText("$120.00").setId("oneTextBox").setName("oneTextBox");
var twoTextBox = app.createTextBox().setId("twoTextBox").setName("twoTextBox");
var threeTextBox = app.createTextBox().setId("threeTextBox").setName("threeTextBox");
app.add(VertPanel);
VertPanel.add(oneTextBox).add(twoTextBox).add(threeTextBox);
return app;
}
The value returned by e.parameter.oneTextBox in the handler function is a string, in your example it should be "$120.00," and what you want is a numeric value... what I'd suggest is to use a replace() to remove all non numeric characters and convert that to a number like this :
var oneTextBoxNumValue = Number(e.parameter.oneTextBox.replace(/[^0-9]/g,''));// the regex ^0-9 takes everything not between 0 and 9 (and replace by '')
Using the same process on other textBoxes you can do everything you want with math operations after this conversion.
To get the results in $, simply add a '$' to your result
getElementById('oneTextBox').setText(resultNumeric+"$")
the only tricky thing is the decimal point, you'll need to take this into account in your conversion : $120.00, will become 12000 in numeric value so don't forget to divide the result somewhere or your stuff will become very expensive ! ;-)
Also I've had some rounding errors sometimes but it's always possible to handle quite easily, for example in a similar case I had to use something like this to get the correct result : (2.00 instead of 1.99 if quant = 2 in the example below, note that I divide the integer by 100 to get value with 2 decimals)
var total = parseInt(Number(quant)*valtotal*100+0.01)/100;
Hoping it will give some ideas to start with.
EDIT : here is a small code to illustrate :
function calcTest() {
var app = UiApp.createApplication().setTitle('TextField Calculator');
var button = app.createButton('Calculate');
var handler = app.createServerHandler('calc');
button.addClickHandler(handler);
var grid = app.createGrid(5, 2);
grid.setText(0, 0, 'value1 ');
grid.setWidget(0, 1, app.createTextBox().setName('value1').setText('$ 45.00/unit'));
grid.setText(1, 0, 'value2');
grid.setWidget(1, 1, app.createTextBox().setName('value2').setText('3 units'));
grid.setText(2, 0, 'press button to calculate');
grid.setWidget(2, 1, button);
grid.setText(3, 0, 'value3 = value1*1.35');
grid.setWidget(3, 1, app.createTextBox().setId('value3').setEnabled(false));
grid.setText(4, 0,'sum value1 + value2 + value3');
grid.setWidget(4, 1, app.createTextBox().setId('sum').setEnabled(false));
handler.addCallbackElement(grid);
app.add(grid);
var ss = SpreadsheetApp.getActive();
ss.show(app);
}
function calc(e){
var app = UiApp.getActiveApplication();
var value1 = Number(e.parameter.value1.replace(/[^0-9]/g,''))/100;
var value2 = Number(e.parameter.value2.replace(/[^0-9]/g,''));
var calcvalue = parseInt(value1*1.35*100)/100
var sumcalc = calcvalue+value1+value2
app.getElementById('value3').setText('$ '+calcvalue)
app.getElementById('sum').setText(sumcalc+' without unit;)')
return app
}
EDIT 2 : here is another code, a function that I use in an application to convert string values to Euros, it is slightly different in its approach but works pretty well.
function toEuro(val){
if(val==''){temp='';return temp}
var temp = val.toString().replace(/[^\d\.-]/g,'').split('.');
if(temp[0]==''){temp[0]='0'}
if(temp.length==1){var result = temp[0]+',00 €'}
else{
var int = temp[0]
var dec = temp[1]
if(dec.length==1){var result=int+','+dec+'0 €'}else{var result=int+','+dec+' €'}
}
return result
}
Context: multi-user app (node.js) - 1 painter, n clients
Canvas size: 650x400 px (= 260,000 px)
For the canvas to be updated frequently (I'm thinking about 10 times a second), I need to keep the data size as small as possible, especially when thinking about upload rates.
The toDataURL() method returning a base64 string is fine but it contains masses of data I don't even need (23 bit per pixel). Its length is 8,088 (without the preceding MIME information), and assuming the JavaScript strings have 8-bit encoding that would be 8.1 kilobytes of data, 10 times per second.
My next try was using JS objects for the different context actions like moveTo(x, y) or lineTo(x, y), sending them to the server and have the clients receive the data in delta updates (via timestamps). However, this turned out to be even less efficient than the base64 string.
{
"timestamp": 0,
"what": {
"name": LINE_TO,
"args": {"x": x, "y": y}
}
}
It doesn't work fluently nor precisely because there are nearly 300 lineTo commands already when you swipe your brush shortly. Sometimes there's a part of the movement missing (making a line straight instead of rounded), sometimes the events aren't even recognized by the script client-side because it seems to be "overwhelmed" by the mass of events triggered already.
So I have to end up using the base64 string with its 8.1 KB. I don't want to worry about this much - but even if done asynchronously with delta updates, there will be major lags on a real server, let alone the occasional bandwidth overrun.
The only colors I am using are #000 and #FFF, so I was thinking about a 1-bit data structure with delta updates only. This would basically suffice and I wouldn't mind any "color" precision losses (it is black after all).
With most of the canvas being white, you could think of additional Huffman run-length encoding to reduce size even further, too. Like a canvas with a size of 50x2 px and a single black pixel at (26, 2) would return the following string: 75W1B74W (50 + 25 white pixels, then 1 black pixel, then 24 more white pixels)
It would even help if the canvas consisted of a 1-bit string like this:
00000000000000000000000000000000000000000000000000
00000000000000000000000001000000000000000000000000
That would help a lot already.
My first question is: How to write an algorithm to get this data efficiently?
The second is: How could I pass the pure binary canvas data to the clients (via node server)? How do I even send a 1-bit data structure to the server? Would I have to convert my bits to a hexadecimal (or more) number and re-parse?
Would it be possible to use this as a data structure?
Thanks in advance,
Harti
I need to keep the data size as small as possible
Then don't send the entire data. Send only the changes, close to what you propose yourself.
Make the framework such that every user can only do "actions" such as "draw black strokeWidth 2 from X1,Y1 to X2,Y2".
I wouldn't bother with some pure binary thing. If there's only two colors then that's easy to send as the string "1,2,x,y,x2,y2", which the other people will parse precisely the same way the local client will, and it will get drawn the same way.
I wouldn't overthink this. Get it working with simple strings before you worry about any clever encoding. It's worth trying the simple thing first. Maybe the performance will be quite good without going through a lot of trouble!
I sorted it out, finally. I used an algorithm to get the image data within a specified area (i.e. the area currently drawn on), and then paste the image data to the same coordinates.
While drawing, I keep my application informed about how big the modified area is and where it starts (stored in currentDrawingCoords).
pixels is an ImageData Array obtained by calling context.getImageData(left, top, width, height) with the stored drawing coordinates.
getDeltaUpdate is called upon onmouseup (yeah, that's the drawback of the area idea):
getDeltaUpdate = function(pixels, currentDrawingCoords) {
var image = "" +
currentDrawingCoords.left + "," + // x
currentDrawingCoords.top + "," + // y
(currentDrawingCoords.right - currentDrawingCoords.left) + "," + // width
(currentDrawingCoords.bottom - currentDrawingCoords.top) + ""; // height
var blk = 0, wht = 0, d = "|";
// http://stackoverflow.com/questions/667045/getpixel-from-html-canvas
for (var i=0, n=pixels.length; i < n; i += 4) {
if(
pixels[i] > 0 ||
pixels[i+1] > 0 ||
pixels[i+2] > 0 ||
pixels[i+3] > 0
) {
// pixel is black
if(wht > 0 || (i == 0 && wht == 0)) {
image = image + d + wht;
wht = 0;
d = ",";
}
blk++;
//console.log("Pixel " + i + " is BLACK (" + blk + "-th in a row)");
} else {
// pixel is white
if(blk > 0) {
image = image + d + blk;
blk = 0;
d = ",";
}
wht++;
//console.log("Pixel " + i + " is WHITE (" + blk + "-th in a row)");
}
}
return image;
}
image is a string with a header part (x,y,width,height|...) and a data body part (...|w,b,w,b,w,[...])
The result is a string with less characters than the base64 string has (as opposed to the 8k characters string, the delta updates have 1k-6k characters, depending on how many things have been drawn into the modification area)
That string is sent to the server, pushed to all the other clients and reverted to ImageData by using getImageData:
getImageData = function(imagestring) {
var data = imagestring.split("|");
var header = data[0].split(",");
var body = data[1].split(",");
var where = {"x": header[0], "y": header[1]};
var image = context.createImageData(header[2], header[3]); // create ImageData object (width, height)
var currentpixel = 0,
pos = 0,
until = 0,
alpha = 0,
white = true;
for(var i=0, n=body.length; i < n; i++) {
var pixelamount = parseInt(body[i]); // amount of pixels with the same color in a row
if(pixelamount > 0) {
pos = (currentpixel * 4);
until = pos + (pixelamount * 4); // exclude
if(white) alpha = 0;
else alpha = 255;
while(pos < until) {
image.data[pos] = 0;
image.data[pos+1] = 0;
image.data[pos+2] = 0;
image.data[pos+3] = alpha;
pos += 4;
}
currentpixel += pixelamount;
white = (white ? false : true);
} else {
white = false;
}
}
return {"image": image, "where": where};
}
Call context.putImageData(data.image, data.where.x, data.where.y); to put the area on top of everything there is!
As previously mentioned, this may not be the perfect suit for every kind of monochrome canvas drawing application since the modification area is only submit onmouseup. However, I can live with this trade-off because it's far less stressful for the server than all the other methods presented in the question.
I hope I was able to help the people to follow this question.
So I have ~12600 subnets:
eg. 123.123.208.0/20
and an IP.
I can use a SQLite Database or an array or whatever
There was a similar question asked about a month ago, however I am not looking for checking one IP against one subnet but a bunch of subnets (obviously the most efficient way, hopefully not O(total subnets)) :)
How can I check that the IP is one of in one of these subnets, I need true or false not the subnet if that helps optimisation.
There are similar subnets in the current list eg.:
(actual extract)
123.123.48.0/22 <-- not a typo
123.123.48.0/24 <-- not a typo
123.123.90.0/24
123.123.91.0/24
123.123.217.0/24
In total they range from 4.x.y.z to 222.x.y.z
The best approach is IMO making use of bitwise operators. For example, 123.123.48.0/22 represents (123<<24)+(123<<16)+(48<<8)+0 (=2071670784; this might be a negative number) as a 32 bit numeric IP address, and -1<<(32-22) = -1024 as a mask. With this, and likewise, your test IP address converted to a number, you can do:
(inputIP & testMask) == testIP
For example, 123.123.49.123 is in that range, as 2071671163 & -1024 is 2071670784
So, here are some tool functions:
function IPnumber(IPaddress) {
var ip = IPaddress.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/);
if(ip) {
return (+ip[1]<<24) + (+ip[2]<<16) + (+ip[3]<<8) + (+ip[4]);
}
// else ... ?
return null;
}
function IPmask(maskSize) {
return -1<<(32-maskSize)
}
test:
(IPnumber('123.123.49.123') & IPmask('22')) == IPnumber('123.123.48.0')
yields true.
In case your mask is in the format '255.255.252.0', then you can use the IPnumber function for the mask, too.
Try this:
var ip2long = function(ip){
var components;
if(components = ip.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/))
{
var iplong = 0;
var power = 1;
for(var i=4; i>=1; i-=1)
{
iplong += power * parseInt(components[i]);
power *= 256;
}
return iplong;
}
else return -1;
};
var inSubNet = function(ip, subnet)
{
var mask, base_ip, long_ip = ip2long(ip);
if( (mask = subnet.match(/^(.*?)\/(\d{1,2})$/)) && ((base_ip=ip2long(mask[1])) >= 0) )
{
var freedom = Math.pow(2, 32 - parseInt(mask[2]));
return (long_ip > base_ip) && (long_ip < base_ip + freedom - 1);
}
else return false;
};
Usage:
inSubNet('192.30.252.63', '192.30.252.0/22') => true
inSubNet('192.31.252.63', '192.30.252.0/22') => false
I managed to solve this by using the node netmask module.
You can check if an IP belongs to a subnet by making something like this:
import { Netmask } from 'netmask'
const block = new Netmask('123.123.208.0/20')
const ip = '123.123.208.0'
console.log(block.contains(ip))
Will here print true.
You can install it by using:
npm i --save netmask
Convert the lower ip and the upper ip in the range to integers and store the range in the db then make sure both columns are indexed.
Off the top of my head (pseudo code):
function ipmap(w,x,y,z) {
return 16777216*w + 65536*x + 256*y + z;
}
var masks = array[ipmap(128,0,0,0), ipmap(196,0,0,0), ..., ipmap(255,255,255,255)]
function lowrange(w, x, y, z, rangelength) {
return ipmap(w, x, y, z) & masks[rangelength]
}
function hirange(w, x, y, z, rangelength) {
return lowrange(w, x, y, z, ,rangelength) + ipmap(255,255,255,255) - masks[rangelength];
}
That ought to do it.
To find whether a particular ip falls in any of the ranges, convert it to an integer and do:
SELECT COUNT(*) FROM ipranges WHERE lowrange <= 1234567 AND 1234567 <= highrange
The query optimizer should be able to speed this up greatly.
Functions IPnumber and IPmask are nice, however I would rather test like:
(IPnumber('123.123.49.123') & IPmask('22')) == (IPnumber('123.123.48.0') & IPmask('22'))
Because for each address, you only need to take into account the network part of the address. Hence doing IPmask('22') will zero-out the computer part of the address and you should do the same with the network address.
Keywords: Binary searching, preprocessing, sorting
I had a similar problem and binary search appears to be very efficient if you can pre-process your subnet list and sort it. Then you can achieve an asymptotic time complexity of O(log n).
Here's my code (MIT License, original location: https://github.com/iBug/pac/blob/854289a674578d096f60241804f5893a3fa17523/code.js):
function belongsToSubnet(host, list) {
var ip = host.split(".").map(Number);
ip = 0x1000000 * ip[0] + 0x10000 * ip[1] + 0x100 * ip[2] + ip[3];
if (ip < list[0][0])
return false;
// Binary search
var x = 0, y = list.length, middle;
while (y - x > 1) {
middle = Math.floor((x + y) / 2);
if (list[middle][0] < ip)
x = middle;
else
y = middle;
}
// Match
var masked = ip & list[x][1];
return (masked ^ list[x][0]) == 0;
}
And an example usage:
function isLan(host) {
return belongsToSubnet(host, LAN);
}
var LAN = [
[0x0A000000, 0xFF000000], // 10.0.0.0/8
[0x64400000, 0xFFC00000], // 100.64.0.0/10
[0x7F000000, 0xFF000000], // 127.0.0.0/8
[0xA9FE0000, 0xFFFF0000], // 169.254.0.0/16
[0xAC100000, 0xFFF00000], // 172.16.0.0/12
[0xC0A80000, 0xFFFF0000] // 192.168.0.0/16
];
isLan("127.12.34.56"); // => true
isLan("8.8.8.8"); // => false (Google's Public DNS)
You can get a PAC script* and see how it performs (it loads a China IP list from somewhere else, sorts them and formats them appropriately) against 5000s of subnets. In practice its speed is surprisingly satisfactory.
The preprocessing code can be inspected using F12 Dev Tools on the above page. In short, you need to convert 1.2.3.4/16 to [0x01020304, 0xFFFF0000], i.e. 32-bit unsigned integer for the IP address and network mask.
* Link goes to my personal website.