Node.js crash - async issue or something else? - arrays

I've got a crash happening on my node server and I can't figure out how it could logically happen. I haven't personally repro'd but its happened a few times in the last week according to bugsnag. Any thoughts on why it might be happening or suggestions for additional logging to help debug would be greatly appreciated.
I've got a 2-player game, where each person is dealt a hand, and then needs to select two cards from their hand to discard. Discarding is done simultaneously, so players may discard at different moments or the same moment. Here's my discard function:
Game.prototype.discard = function(socket, msg) {
var self = this;
socket.get('playerNum', function (err, playerNum) {
self.crib.push(self.cards[playerNum].splice(msg.cards[0],1)[0]);
self.crib.push(self.cards[playerNum].splice(msg.cards[1]-1,1)[0]);
for (var i = 0; i < self.cards[playerNum].length; i++) //add cards kept as unpegged
self.currentUnPeggedCards.push(self.cards[playerNum][i]);
socket.broadcast.in('gamea' + self.tableNumber).emit('other player discarded');
if (self.crib.length == CARDS_PER_CRIB) { //both players discarded
var jsonGame = self.buildJSON('starter');
self.dbConnection.query("UPDATE savedgames SET game = '"+jsonGame+"' WHERE room = 'a' and player1_id = "+self.seatedPlayers[0][2]+" and player2_id = "+self.seatedPlayers[1][2]+";");
if (playerNum == self.dealer)
socket.broadcast.in('gamea' + self.tableNumber).emit('cut starter card');
else
socket.emit('cut starter card');
}
else {
var jsonGame = self.buildJSON('discard');
self.dbConnection.query("UPDATE savedgames SET game = '"+jsonGame+"' WHERE room = 'a' and player1_id = "+self.seatedPlayers[0][2]+" and player2_id = "+self.seatedPlayers[1][2]+";");
}
});
}
The msg param is passed in from the client side, and is built as the result of the user toggling two cards and then selecting to discard. Here's what the client-side code generating the msg looks like:
function clickedDiscard() {
if (myTurnButton) {
var discards = [];
var keepCards = [];
for (var i=0; i<6; i++) {
if (cardsClicked[i])
discards.push(i);
cardsClicked[i] = false;
}
numCardsClicked = 0;
socket.emit('discard',{cards:discards});
}
}
So it pushes two cards to self.crib (which contains both player's discards), then it checks to see if both players have discarded (by looking at the length of self.crib, and then I'm building a storing a json object which represents the current state of the game, so if people get disconnected they can resume, etc.
The crash is happening in my buildJSON function. Here's the entire code for that function (as requested):
Game.prototype.buildJSON = function(state) {
console.log('starting build json');
var self = this;
var stateStr = '"state":"'+state+'",';
var scoreStr = '"score":['+self.score+'],';
var winsStr = '"wins":['+self.wins+'],';
var mostRecentPtsStr = '"mostRecentPts":['+self.mostRecentPts+'],';
var mostRecentCardPtsStr = '"mostRecentCardPts":['+self.mostRecentCardPts+'],';
var mostRecentCountStr = '"mostRecentCount":['+self.mostRecentCount+'],';
var dealerStr = '"dealer":'+self.dealer+',';
var dealsFirstStr = '"dealsFirst":'+self.dealsFirst+',';
var peggerStr = '"pegger":'+self.currentPegger+',';
var cardNamesStr = '"hands":[';
for (var i=0; i<self.cards.length;i++) {
cardNamesStr += '[';
for (var j=0; j<self.cards[i].length;j++) {
cardNamesStr += '"'+self.cards[i][j].getName()+'"';
if (j==self.cards[i].length-1)
cardNamesStr += ']';
else
cardNamesStr += ',';
}
if (i!=self.cards.length-1)
cardNamesStr += ',';
}
cardNamesStr += '],';
var cribStr = '"crib":[';
for (var i=0;i<self.crib.length;i++) {
cribStr += '"'+self.crib[i].getName()+'"';
if (i!=self.crib.length-1)
cribStr += ',';
}
cribStr += '],';
var starterStr = '';
if (self.starterCard != null)
starterStr = '"starter":"'+self.starterCard.getName()+'",';
var deckStr = '"deck":[';
var deckCards = self.deck.getCards();
for (var i=0;i< deckCards.length;i++) {
deckStr += '"'+deckCards[i].getName()+'"';
if (i!= deckCards.length-1)
deckStr += ',';
}
deckStr += '],';
var pegCountStr = '"count":'+self.currentPeggingCount+',';
var peggedStr = '"pegged":[';
for (var i=0; i<self.peggedCards.length;i++) {
peggedStr += '[';
for (var j=0; j<self.peggedCards[i].length;j++) {
peggedStr += '"'+self.peggedCards[i][j].getName()+'"';
if (j!=self.peggedCards[i].length-1)
peggedStr += ',';
}
peggedStr += ']';
if (i!=self.peggedCards.length-1)
peggedStr += ',';
}
peggedStr += '],';
var currentPeggedStr = '"currentPegged":[';
for (var i=0;i<self.currentPeggedCards.length;i++) {
currentPeggedStr += '"'+self.currentPeggedCards[i].getName()+'"';
if (i!=self.currentPeggedCards.length-1)
currentPeggedStr += ',';
}
currentPeggedStr += '],';
var currentUnPeggedStr = '"currentUnPegged":[';
for (var i=0;i<self.currentUnPeggedCards.length;i++) {
currentUnPeggedStr += '"'+self.currentUnPeggedCards[i].getName()+'"';
if (i!=self.currentUnPeggedCards.length-1)
currentUnPeggedStr += ',';
}
currentUnPeggedStr += ']';
var gameJSON = '{' + stateStr + scoreStr + winsStr + mostRecentPtsStr + mostRecentCardPtsStr + mostRecentCountStr + dealerStr + dealsFirstStr + peggerStr + cardNamesStr + cribStr + starterStr + deckStr + pegCountStr + peggedStr + currentPeggedStr + currentUnPeggedStr + '}';
console.log('json built');
return gameJSON;
}
The crash happens on the call to getName(), with the error being: Cannot call method 'getName' of undefined
At this point, I'm not sure how this can happen. The for loop, is, by definition over the length of the object, so there has to be an element at each index in the loop. And yet, clearly there isn't, because the object is undefined. Is this somehow happening because of an async problem? When pushing to an array, does it somehow increase the length of the array before actually adding the object to the array itself? I suppose it's possible that what I'm splicing out of the original array is undefined? Pretty stumped.

Related

Why array comparison isn't working? (GAS)

The code below used to work. Now, when comparing two arrays, even though there is a difference, as highlighted below, the code says that there is a duplicate.
I've tried it using .join() as well, but I keep getting the same result.
Script:
function SaveEditedEntry() {
const lock = LockService.getScriptLock();
lock.tryLock(3000);
if (lock.hasLock()) {
var sourceSheet = 'Entries';
var destinationSheet = 'Database';
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(sourceSheet);
var LastRowSource = sheet.getLastRow();
//var LastColumnSource = sheet.getLastColumn();
var entryValues = sheet.getRange(7, 1, LastRowSource, 16).getValues();
var dbSheet = ss.getSheetByName(destinationSheet);
var entryDataPushed = [];
var dbData = dbSheet.getRange(2, 1, dbSheet.getLastRow(), 16).getValues();
var dbDataPushed = [];
//var dbDataPushed = new Array();
var company = sheet.getRange("B3").getValue();
var period = sheet.getRange("B4").getValue();
var entryID = sheet.getRange("J5").getValue();
var timeStamp = new Date();
var user = Session.getActiveUser().getEmail();
if (company == '') {
Browser.msgBox('Make sure that you have chosen a valid company.');
return;
}
if (period == '') {
Browser.msgBox('Please, make sure that you have chosen a valid period.');
return;
}
var emptyRow = 0;
for (var i = 0; i < entryValues.length; i++) {
if (entryValues[i][0] != '') {
emptyRow = i + 1;
}
if (emptyRow < 1) {
Browser.msgBox('Please, make sure that you have entered a transaction.');
return;
}
if (entryValues[i][0] != '') {
entryDataPushed.push(entryValues[i]);
}
}
for (var n = 0; n < dbData.length; n++) {
if (dbData[n][1] != '' && dbData[n][0] == company && dbData[n][14] == period) {
dbDataPushed.push(dbData[n]);
}
}
var duplicate = false;
loop1:
for (var x = 0; x < entryValues.length; x++) {
loop2:
for (var j = 0; j < dbDataPushed.length; j++) {
if (JSON.stringify(entryValues[x]) == JSON.stringify(dbDataPushed[j])) {
duplicate = true;
break loop1;
}
}
}
Logger.log("EntryDataPushed: " + entryDataPushed);
Logger.log("dbDataPushed: " + dbDataPushed);
if (duplicate == true) {
Browser.msgBox('No change has been made.');
return;
This is the logs print:
Could anyone point me to the right direction on getting this solved?
Thank you!
Antonio
You were comparing entryValues vs dbDataPushed but is logging entryDataPushed and dbDataPushed. Is this expected?
Anyways, since you are logging the variables, I assume the variables logged are the ones you need to compare.
Convert them into JSON string by wrapping the variables with JSON.stringify(). I use this all the time when I encounter an issue similar to yours right now.
var duplicate = false;
if (JSON.stringify(entryDataPushed) == JSON.stringify(dbDataPushed)) {
duplicate = true;
}
Output:
See resource below for other ways to properly compare arrays if the above code doesn't work.
Resources:
JSON.stringify()
StackOverflow Reference

How do i declare an array as public in typescript?

I have a function that involves declaring and populating an array called ArrayRoute. I need to reference this array later in a for loop. How do I set this array as global so I can access it outside of the function?
Thanks
function route(permutation, origins) {
var myroute = origins[0];
var ArrayRoute = [];
ArrayRoute.push(origins[0]);
console.log('ArrayRoute= ' + ArrayRoute);
for (var i = 0; i < permutation.length; i++){
myr += '\n' + myd[permutation[i] - 1];
ArrayRoute.push(myd[permutation[i] - 1]);
}
return myroute;
}
for (i = 0; i < ArrayRoute.length - 1; i++) {
console.log(ArrayRoute[i] + '->' + ArrayRoute[i + 1]);
}
console.log('ArrayRouteeee= ' + ArrayRoute);
You can't.
If you create the array inside the function then it is only accessible from within the function body.
You can declare it outside of the function:
let ArrayRoute = [];
function route(permutation, origins) {
var myroute = origins[0];
ArrayRoute.push(origins[0]);
console.log('ArrayRoute= ' + ArrayRoute);
for (var i = 0; i < permutation.length; i++){
myr += '\n' + myd[permutation[i] - 1];
ArrayRoute.push(myd[permutation[i] - 1]);
}
return myroute;
}
for (i = 0; i < ArrayRoute.length - 1; i++) {
console.log(ArrayRoute[i] + '->' + ArrayRoute[i + 1]);
}
console.log('ArrayRouteeee= ' + ArrayRoute);
You can pass it as a parameter to the function:
function route(permutation, origins, ArrayRoute) {
...
}
Or you can return the array as a result from the function:
function route(permutation, origins) {
var myroute = origins[0];
var ArrayRoute = [];
ArrayRoute.push(origins[0]);
console.log('ArrayRoute= ' + ArrayRoute);
for (var i = 0; i < permutation.length; i++){
myr += '\n' + myd[permutation[i] - 1];
ArrayRoute.push(myd[permutation[i] - 1]);
}
return { myroute, ArrayRoute };
}
let { myroute, ArrayRoute } = route(...);

JSON: How to access deep level array

Everything pre-loop is fine. I need help finding the way to access deeper level json. I'm stuck in the "for" loop. The product_name comes out okay in the first loop but nothing deeper than that. I've added some output for each deeper level loop but I don't seem to pass the second one.
Follow URL to view JSON array.
<script>
var xmlhttp = new XMLHttpRequest();
var url = 'http://www.weber.se/?type=88&pageAlias=lecareglttklinker26&json=1';
xmlhttp.onreadystatechange=function() {
if (this.readyState == 4 && this.status == 200) {
readJson(this.responseText);
}
}
xmlhttp.open("GET", url, true);
xmlhttp.send();
function readJson(response) {
var object = JSON.parse(response);
var output = '<div class="container-fluid">';
output += '<div class="row">';
output += '<div class="col-xs-6 text-left"><img src="' + object.product[0].packaging_picture + '" height="230"></div>';
output += '<div class="col-xs-6 text-right"><img src="' + object.product[0].main_picture + '" height="230"></div>';
output += '</div>';
output += '<div class="row">';
output += '<div>' + object.product[0].standfirst + '</div>';
output += '</div>';
output += '<div class="row">';
output += '<div class="well"><h2>Egenskaper</h2>' + object.product[0].benefits_description + '</div>';
output += '</div>';
for (var a = 0; a < object.product.length; a++) {
var product = object.product[a];
var name = product.product_name;
output += '<h2>' + name + '</h2>';
for (var b = 0; b < product.tabs.length; b++) {
var tabs = product.tabs[b];
output += 'tabs<br>';
for (var c = 0; c < product.tabs.tab.length; c++) {
var tab = tabs.tab[c];
output += 'tab<br>';
for (var d = 0; d < product.tabs.tab.contents.length; d++) {
var contents = tab.contents[d];
output += 'contents<br>';
for (var e = 0; e < product.tabs.tab.contents.content.length; e++) {
var content = contents.content[e];
output += 'content<br>';
for (var f = 0; f < product.tabs.tab.contents.content.title.length; f++) {
var title = content.title[f];
var bodytext = content.bodytext[f];
output += '<h3>' + title + '</h3>';
output += bodytext;
}
}
}
}
}
}
output += '</div>';
document.getElementById("output").innerHTML = output;
}
</script>
Your second loop is not valid. as per the data in the link, product.tabs is not an array. its an object. so you can't really loop and object you need to have a different way to process that object.
for (var a = 0; a < object.product.length; a++) {
var product = object.product[a];
var name = product.product_name;
output += '<h2>' + name + '</h2>';
output += 'tabs<br>';
var tabs = product['tabs']['tab'];
for (var c = 0; c < tabs.length; c++) {
var tab = tabs[c];
output += 'tab<br>';
var contents = tab['contents'] != undefined ? tab['contents']['content'] : [];
output += 'contents<br>';
for (var e = 0; e < contents.length; e++) {
var content = contents[e];
output += 'content<br>';
var title = content.title;
var bodytext = content.bodytext;
output += '<h3>' + title + '</h3>';
output += bodytext;
}
}
}

Text one, two three etc in Angular automatically

I have the following snippet of code that creates 1, 2, 3 etc based on the number in parent repeat (All good).
{{$index+1}}
But I am looking for Text such as One, Two Three etc
Is there a way to achieve this in Angular? (Text instead of numerics)
One solution is to create a filter, for example:
// Script.js
angular.module('app')
.filter('numberToWord', function() {
return function( s ) {
var th = ['','thousand','million', 'billion','trillion'];
var dg = ['zero','one','two','three','four', 'five','six','seven','eight','nine'];
var tn = ['ten','eleven','twelve','thirteen', 'fourteen','fifteen','sixteen', 'seventeen','eighteen','nineteen'];
var tw = ['twenty','thirty','forty','fifty', 'sixty','seventy','eighty','ninety'];
s = s.toString();
s = s.replace(/[\, ]/g,'');
if (s != parseFloat(s)) return 'not a number';
var x = s.indexOf('.');
if (x == -1) x = s.length;
if (x > 15) return 'too big';
var n = s.split('');
var str = '';
var sk = 0;
for (var i=0; i < x; i++)
{
if ((x-i)%3==2)
{
if (n[i] == '1')
{
str += tn[Number(n[i+1])] + ' ';
i++;
sk=1;
}
else if (n[i]!=0)
{
str += tw[n[i]-2] + ' ';
sk=1;
}
}
else if (n[i]!=0)
{
str += dg[n[i]] +' ';
if ((x-i)%3==0) str += 'hundred ';
sk=1;
}
if ((x-i)%3==1)
{
if (sk) str += th[(x-i-1)/3] + ' ';
sk=0;
}
}
if (x != s.length)
{
var y = s.length;
str += 'point ';
for (var i=x+1; i<y; i++) str += dg[n[i]] +' ';
}
return str.replace(/\s+/g,' ');
};
})
And then you can use it like this:
{{$index | numberToWord }}
Edit: An example Plunker http://plnkr.co/edit/DIQ3YVkH7N6PUaqju82X?p=preview
There is no standard feature in Angular for that. Here is a link to a great algorithm to convert number to word Developers blog - Convert Numbers into Words Using JavaScript
Put the algorithm in a function and use it like this :
{{convertNumberToWord($index+1)}}
Here is a working example in Plunker for your situation

accessing array elements in another frame as3

I have created an Array in frame 1 and dynamically create a list of movieclips with it , and I want to create the same Array in frame 3 and those movieclips again if something is true or false.is it possible ? because when I'm trying to do this , I will get this error :
1151: A conflict exists with definition i in namespace internal.
here is my code at frame 1 :
stop();
import flash.display.MovieClip;
var p_x:uint = 90;
var p_y:uint = 108;
var my_list:String = "Games,Videos, Medias,Images,Photos,Personal Photos,Social Media,Private,Social,None,Names,Families";
var myListString:Array = my_list.split(",");
var myArray:Array=new Array ();
var listObject = 1;
for (var i:uint=0; i<12; i++)
{
var myItemList:mrb=new mrb();
myItemList.x = p_x;
myItemList.y = p_y + 80;
myItemList.y = (p_y + (listObject * 65));
myArray.push(myItemList);
myItemList.txt.text = i.toString();
myItemList.txt.text = myListString[i].toString();
myItemList.name = "item"+i;
addChild(myItemList) as MovieClip ;
listObject++;
}
and here is code at frame 3 :
var tmpCurFrame:int = currentFrame;
this.addEventListener(Event.ENTER_FRAME, handleUpdate)
function handleUpdate(e:Event):void {
if (tmpCurFrame != currentFrame) {
this.removeEventListener(Event.ENTER_FRAME, handleUpdate);
return;
}
if (so.data.fav1 != undefined)
{
if ( so.data.fav1 == "on")
{
for (var i:int = 0; i < myListString.length;)
{ if (myListString[i].indexOf() > -1)
{
var myRectangle:mrb=new mrb();
trace("found it at index: " + i);
myRectangle.x = p_x;
myRectangle.y = (p_y + (findobject * 50));
trace('p_y+80 =' + (p_y+(findobject*80)) + 'p_x = ' + p_x );
myArray.push(myRectangle);
myRectangle.txt.text = myListString[i].toString();
trace(my_array2[i].toString() );
addChild(myRectangle);
}
}
}
}
else
{
fav_1.fav_on.visible=true;
}
}
This error message simply means that you use twice the same variable i. You just have to give them differents names.

Resources