Can anyone debug this for me? I've been staring at it and testing things for hours but can't seem to get it working. I'm starting to wonder whether the coding challenge web app is wrong and I'm right!
The task is this:
Find the number of generations it would take for a population p0 to surpass a max population p given that the population increases by percent% plus aug every generation
My one-liner is as follows:
nbYear = (p0, percent, aug, p) => {
return Array(999).fill().filter((_,i)=>Array(i+1).fill().map((_,j)=>j==0?p0:0).reduce((y,_)=>Math.round(y*percent/100+y+aug))<=p).length;
}
The code I've written passes on 100 tests but fails on one in particular (they don't disclose the input paramters on which it failed). All it says is that the function gave the output: 51 when it should have been 50
I've concluded that the one test for which it failed must have been for a value over 999.
Background
A Chinese company that provides PV systems uses highcharts to present data for users. They are moving us to a newer code base Highcharts JS v7.2.0 (2019-09-03).
In the old system, Highcharts JS v3.0.10 (2014-03-10), I could catch all data points in packets on my network with Wireshark while I stepped through displaying N days of data and then process the capture file to get all date, times and wattage values for my longer term analysis.
In the new system the daily data is passed in TLS as a zip file, I think this is part of the new code base feature set. It is more efficient but I can't get to see my data.
The Chinese do not provide any export to CSV, Excel options (just pdf, SVG pictures), and anyway I do not really want a file to process for each day if I am working through 60 to 300 days of data. (I have emailed them previously that they might like to add export the detailed data, and add drill down from month to day view etc both of which which I now see is supported in Highchart.)
I'm not holding my breath on that...
My Question
What is the easiest or best way, if any, to add some extra code in the page to append chart title, series data x&y values for each chart displayed to a file I can set at some initial point. Ideally only on first rendering to avoid getting multiple dumps of the data when the system auto-refreshes on a timer - in case I have left the recorder running!
To clarify I do not have any control of or access to the code at the server that embeds the protected TLS/zip data stream and highchair setup - it all happens in another country. To access the data values all I can think of is that I need to use some sort of console print / edit / function overload / event handler /greaseMonkey script etc I can inject/modify/add into the highchart code somehow in my browser (Safari, but I could use Firefox) after that code and data is received. I cannot see the data at all in the new system as it is behind TLS and in a zip file; all I get to see is a graph. I am not keen to add Export to CSV to the chart menu options as I do not want to have to save and work with N files...
You can see my processing and data from the old highchart based system here (where I could capture data off wifi) Best way to pull repeated table data from a pcap http file (could awk handle the disruptive breaks)?
Having dug about a little in last 14 days I am wondering if my browser can create a file stream object once and then append to that somehow when Highcharts has each data point:
var fs = require('fs');
var logStream = fs.createWriteStream('PVlog.txt', {flags: 'a'});
// use {flags: 'a'} to append and {flags: 'w'} to erase and write a new file
.... somewhere in Highcharts execution log my data (date, time, power) so something like:
logStream.write(it.heading, it.x, it.y);
I'm hoping I can record progress towards getting data out, the steps taken etc. I have some progress, but far from what I would want to use for capturing significant amounts of data.
For a sample of the working of the system I am referring to try clicking on any of the available sample systems currently producing power via the "Demo account" at
https://server.growatt.com/login/toViewExamlePlant
Opening js console I have found that the system creates new entries in the charts object array when a different day is displayed. Any older chart seems to get nulled to undefined (maybe this is an less than optimal use of Highcharts):
Array (3)
0 undefined
1 undefined
2 Chart {renderTo: <div class="chartDiv height1">, exporting: Object, navigation: Object, userOptions: Object, margin: [undefined, undefined, undefined, undefined], …}
So to access data in the latest current chart I have used [Highcharts.charts.length-1] to index into the charts array, which is 0 based.
For the date of data graphed my best solution so far is to examine the tooltip configuration:
console.log(Highcharts.charts[Highcharts.charts.length-1].tooltip.options.userOptions.headerFormat)
example output for 4 Jan 2020:
<span style="font-size:10px">2020-01-04 {point.key}</span><table>
For data point values:
console.log(Highcharts.charts[Highcharts.charts.length-1].series[0].yData)
Seeing the end of data is awkward as long data in console truncates end in ellipsis…
right-click > copy object SORT OF works with paste giving:
[Log] Array (16)
0 11.9
1 10.549999
2 18.8
3 18.05
4 21
5 29.7
6 38
7 37.6
8 66.4
9 83.1
10 75.46667
11 100
12 89.666664
13 96.833336
14 94.03333
15 92.26666
For the X axis categories, showing the times of day for each reading:
console.log(Highcharts.charts[Highcharts.charts.length-1].series[0].xAxis.categories)
As before right-click > copy object SORT OF works with paste giving:
[Log] Array (71)
0 "09:05"
1 "09:10"
2 "09:15"
3 "09:20"
4 "09:25"
5 "09:30"
6 "09:35"
7 "09:40"
8 "09:45"
9 "09:50"
10 "09:55"
11 "10:00"
12 "10:05"
13 "10:10"
14 "10:15"
15 "10:20"
So far this is really only first steps proof that I can get at the data. It is very clunky to use and would require considerable further work!
The first step would be to create a function to call that can obtain all the data in one go, ideally formatting the data ready for combining with other days of data, tab separated. Any standard date format would be fine too, e.g. 2018-11-30 as used in the tooltip:
06/11/18 11:20 799
06/11/18 11:25 744
06/11/18 11:30 720
06/11/18 11:35 681
06/11/18 11:40 543
06/11/18 11:45 350
06/11/18 11:50 274
06/11/18 11:55 230
06/11/18 12:00 286
06/11/18 12:05 435
06/11/18 12:10 544
06/11/18 12:15 899
06/11/18 12:20 1187
06/11/18 12:25 1575
06/11/18 12:30 1362
06/11/18 12:35 1423
My next aim would be to get that data appended to a single file, myPV_DataFile.txt by a single Console command, better would be automatically on "pageLoaded" or "chart_draw_completed" being signalled.
Next step forward for me:
for(q = 0; q < Highcharts.charts[Highcharts.charts.length-1].series[0].yData.length; q++) {console.log(Highcharts.charts[Highcharts.charts.length-1].series[0].xAxis.categories[q], Math.round(Highcharts.charts[Highcharts.charts.length-1].series[0].yData[q]))}
Which produces x_category,y_value pairs in the log, they do not seem to be easily copy/pasted though.
Thanks to https://github.com/edubey/browser-console-crawl/blob/master/single-story.js
... next step is to create console.save () function, and then a few lines to save the data as I want. TBH I was surprised the console would allow this much!
console.save = function (data, filename) {
if (!data) {
console.error('Console.save: No data')
return;
}
if (!filename) filename = 'story.json'
if (typeof data === "object") {
data = JSON.stringify(data, undefined, 4)
}
var blob = new Blob([data], {
type: 'text/json'
}),
e = document.createEvent('MouseEvents'),
a = document.createElement('a')
a.download = filename
a.href = window.URL.createObjectURL(blob)
a.dataset.downloadurl = ['text/json', a.download, a.href].join(':')
e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
a.dispatchEvent(e)
}
myPV = Highcharts.charts[Highcharts.charts.length-1].tooltip.options.userOptions.headerFormat+"\n";
for(q = 0; q < Highcharts.charts[Highcharts.charts.length-1].series[0].yData.length; q++) {myPV+=Highcharts.charts[Highcharts.charts.length-1].series[0].xAxis.categories[q] +", "+ Math.round(Highcharts.charts[Highcharts.charts.length-1].series[0].yData[q])+"\n"}
console.save(myPV, "QQsample3.txt")
Next step to strip out just the date from the headerFormat and use that as my filename, maybe. The the lot can be put in myGet function although it will still ask me to confirm each file name and save step in the UI. Sure that can be bypassed later!
Simple function can do the job for me, but is lost from console session if I refresh the page:
mySave = function () {
var myDate=Highcharts.charts[Highcharts.charts.length-1].tooltip.options.userOptions.headerFormat.substring(29,40);
myPV = myDate+"\n";
for(q = 0; q < Highcharts.charts[Highcharts.charts.length-1].series[0].yData.length; q++) {myPV+=Highcharts.charts[Highcharts.charts.length-1].series[0].xAxis.categories[q] +", "+ Math.round(Highcharts.charts[Highcharts.charts.length-1].series[0].yData[q])+"\n"}
console.save(myPV, myDate+".txt")
}
This produces a file like 2020-01-07.txt :
2020-01-07
08:20, 16
08:25, 25
08:30, 42
08:35, 66
08:40, 67
08:45, 65
08:50, 64
08:55, 72
09:00, 112
09:05, 147
09:10, 148
09:15, 165
09:20, 223
09:25, 209
09:30, 202
09:35, 188
09:40, 176
09:45, 225
09:50, 276
09:55, 325
10:00, 300
10:05, 281
10:10, 216
10:15, 203
10:20, 205
etc.
I've not really used js much before so pleased to get to this relatively easily. Ideally I'd want the functions to persist better, and secondly to trigger the saving via some update_completed event in the Highcharts (re-)drawing or other page event.
Knowing the best, or possible, ways to approach my final 2 goals probably requires more background knowledge than I will acquire in a few days!
I am trying to implement a protocol which use a certain checksum calculation I am unable to reproduce.
The specification says the checksum should be "7 bit, 2’s complement sum of command and message field
(m.s.b. = 0)".
Which according to me should be possible to calculate with:
const data = [0x04, 0x00, 0x10, 0x10, 0x18, 0x57, 0x05]
let sum = 0x00
for (let value of data) {
sum += value
}
const chk = 256 - sum // OR (~sum + 1) & 0xFF
console.log('0x' + chk.toString(16).padStart(2, '0'))
See, https://repl.it/repls/UntidySpotlessInternalcommand.
However, the result I get is 0x68, while the example I have says it should be 0x78.
Am I misunderstanding something in terms of calculating 2's complement sum?
The example is taken from a successfully executed command which is seen in a console window provided by the manufacturer.
Breaks down into:
SOM 10 02
CMD 04 (CONNECTED)
DATA 00 10 10 18 57
BTC 05
CHK 78
EOM 10 03
You should contact the manufacturer. Even using a programming calculator and making sure to use only 7 bits, the checksum comes out to 0x68. I'm not entirely sure your calculation is correct as per another comment it might not be 7 bit. But the sum of the numbers you provided is a 7 bit number anyway, so in the example you gave it shouldn't matter. It might matter for other data though. But definitely contact the company because the correct checksum does seem to be 0x68.
I'm reading an H.264 stream from a camera on a raspberry pi. I'm trying to pass this to Broadway via websockets to render in a web page.
The stream contains NAL units, and I'm chunking it on the [0,0,0,1] start prefix code, to send and then decode NAL units individually. I think that's working fine, but Broadway can't decode the result I end up with.
Digging into the parsing code I've based this on though, it seems to be expecting the 5th byte (straight after the start prefix code) to be either:
0x65 - an I frame
0x41 - a P frame
0x67 - an SPS frame
0x68 - a PPS frame
I've seen a lot of mention of these elsewhere too. All the units I have coming through though seem to start with (in order):
0x27 0x64 (1st unit)
0x28 0xEE (2nd unit)
0x25 0x88 (3rd unit, then intermittently later on)
0x21 0x9A (every single other unit in the stream)
What do these headers mean in an H.264 stream? Do they suggest something about what I need to do to match Broadway's expectations?
(If the full code would be useful to understand this better, see https://github.com/pimterry/pi-cam/tree/d801de9b)
This was a red herring: the actual issue for me here was that some existing frame dropping logic meant that I wasn't passing Broadway the first few frames in the stream, and it was failing to render. Replaying the SPS and PPS frames for all new connections and making sure they're never dropped has fixed the issue nicely.
I also did work out what these bytes are though, which helped, and may be useful for others for reference:
Hex Binary NAL type Meaning
0x65 = 11 00101 = type 5 Coded slice of an IDR picture (I-frame)
0x41 = 10 00001 = type 1 Coded slice of a non-IDR picture (P-frame)
0x27 = 01 00111 = type 7 Sequence parameter set (B-frame)
0x28 = 01 01000 = type 8 Picture parameter set (B-frame)
0x25 = 01 00101 = type 5 Coded slice of an IDR picture (B-frame)
0x21 = 01 00001 = type 1 Coded slice of a non-IDR picture (B-frame)
Special thanks to Jaromanda X though - the NAL units article [here] and the nal_ref_idc article made working this out much easier.
I'm facing a really strange problem comparing integer in Javascript. I have an array of numbers and I want to check if the current number in a loop is smaller than the previous one. To do so, I save the "current" number as "previous", so I can check them in the next loop. The function runs as expected, EXCEPT every time the current and the previous number have a different number of digits: in this case, the code doesn't see the actually smaller number as being smaller than the previous one.
For example:
111 < 120 ? ---> YES!
106 < 111 ? ---> YES!
98 < 106 ? ---> NO!
76 < 98 ? ---> YES!
5 < 76 ? ---> NO!
I'm unable to find anything strange in the code I'm using, as it is quite simple:
for(var j=0;j<arrScores.length;j++)
{
if(arrScores[j][0] < scoreAnt)
{
console.log("Smaller!");
}
scoreAnt = arrScores[j][0];
}
I've tried using parseInt() in both values, but nothing changes... Checking the length of both numbers using scoreAnt.toString().length returns a length of 1, no matter which number it is (100, 34 or 156798), and the same for arrScores[j][0]. I've also logged the whole thing to check that the numbers are the expected ones, and they are (the numbers used in the example are some of the ones I'm using)...
Any clue on what can be happening? I'm really lost with this, becuase it makes no sense for me...
Thanks in advance for your time and effort! :)
You always do scoreAnt = arrScores[j][0]; in the loop; but you should only do that if arrScores[j] is smaller; i.e. inside the inner curly braces.
for(var j=0;j<arrScores.length;j++)
{
if(arrScores[j][0] < scoreAnt)
{
console.log("Smaller!");
scoreAnt = arrScores[j][0];
}
}
Well, don't even know why, but after changing something relating the CORS of the server where these numbers came from (but not modifying the numbers at all), the comparison seems to work as expected... Have no clue about what might have changed! :S However, now it works correctly...