node.js websocket chat to handle parallel colors - arrays

I'm working on some project where I need some chat application. I decided to test some node.js/websocket version here: http://martinsikora.com/nodejs-and-websocket-simple-chat-tutorial
everything works perfect, but as he mentions in the end of the tutorial:
Node.js unlike Apache doesn't use processes for each connection.
It means that after 7 users logged in, every hard coded color will be used and then it uses white color for username style.
// Array with some colors
var colors = [ 'red', 'green', 'blue', 'magenta', 'purple', 'plum', 'orange' ];
// ... in random order
colors.sort(function(a,b) { return Math.random() > 0.5; } );
userName = htmlEntities(message.utf8Data);
// get random color and send it back to the user
userColor = colors.shift();
connection.sendUTF(JSON.stringify({ type:'color', data: userColor }));
console.log((new Date()) + ' User is known as: ' + userName
+ ' with ' + userColor + ' color.');
Is it somehow possible to allow two users to use the same color?
Thanks

You're better off just randomly picking a color on each request (which means you don't have to pre-shuffle the colors array). Yes, that means that sometimes two consecutive users will get the same color; that's an inherent property of real randomness, rather than what people mistakenly imagine randomness to be.

you shouldn't use Array.shift(), since it removes an element from your colors array, so basicaly after 7 users your array is empty.
just generate a random id
var idx = Math.floor(Math.random()*colors.length)
.....
({ type:'color', data: colors[idx] })

After doing:
usercolor = colors.shift();
Add this line:
colors.push(usercolor);
This puts the returned color back into the array at the other end. The net result is it'll cycle through your seven colors over and over.

Related

Unable to display text output with Alexa Show via flask-ask

So I have built a custom pool control system in Python. I then used Flask-ask to integrate this with my Echo Dots and Show. With the Echo Show, I was using a simple_card format which reads back all my information while showing it on the screen:
#ask.intent("GetAllStats")
def get_pool_stats():
pool_current_ph = read_database("pool_chemicals", "pool_current_ph")
pool_current_orp = read_database("pool_chemicals", "pool_current_orp")
pool_current_temp = int(float(read_database("system_status", "pool_current_temp")))
pool_level_percentage = read_database("pool_level", "pool_level_percentage")
pic = 'https://richard.mydomian.net/pool_control.jpg'
msg = render_template('our_stats', temperature=pool_current_temp,
ph=pool_current_ph,
orp=pool_current_orp,
level=pool_level_percentage)
return statement(msg).simple_card(title='Pool Control', content='Pool Temperature: {0}\n Pool PH: {1}\n Pool ORP: {2}\n Water Level: {3}% .format(pool_current_temp,pool_current_ph,pool_current_orp,pool_level_percentage))
Here is my our_stats from my templates.yaml:
our_stats: |
<speak>
The pool temperature is currently {{temperature}} degrees. The P H of our pool water is currently {{ph}}, while our oxygen reduction potential
is right at {{orp}}. The level of our water is at {{level}} percent.
</speak>
This works great, but I do not have any font control (that I can find) and the background is always grey.
So I started to research using the display_render method and I was able to get it to put up a really nice background picture of my pool and still read back my stats, but now I cannot get it to display the information in printed form.
I changed my return statement above to:
return statement(msg).display_render(template='BodyTemplate3', title='Pool Control', background_image_url=pic)
Again, this works great and reads back my information, but it I try to pass any content to it via textContent, primaryText, content, or text it always fails. I have also tried various templates including BodyTemplate's and listTemplate's. All to no avail. Anytime I try to add content to the screen the skill fails. I remove the content and I get a fantastic picture and it will speak to me all of the information, but that is as far as I can get.
One of the main problems is that I just have not been able to find any pertinent kind of examples using Flask-Ask and the Echo Show with anything but the simple_card.
I am hoping someone has figured this out and can point me in the right direction.
You have to edit your flask-ask models.py.
In the method display_render delete:
,
'textContent': text
change:
def display_render(self, template=None, title=None, backButton='HIDDEN', token=None, background_image_url=None, image=None, text=None, hintText=None):
to:
def display_render(self, template=None, title=None, backButton='HIDDEN', token=None, background_image_url=None, image=None, text=None, format=None, hintText=None):
and add after:
if background_image_url is not None:
directive[0]['template']['backgroundImage'] = {
'sources': [
{'url': background_image_url}
]
}
this:
if format == None:
format = 'PlainText'
if text is not None:
directive[0]['template']['textContent'] = {
'primaryText': {
'type': format,
'text': text
},
'secondaryText': {
'type': format,
'text': None
},
'tertiaryText': {
'type': format,
'text': None
}
}
Now you should be able to use:
display_render(template='BodyTemplate6', title='Pool Control', background_image_url=pic, text='Text', format='Format')
I'm using BodyTemplate6 here because some Templates don't support text, format can be 'PlainText' or 'SSML'

Best practices to execute faster a CasperJS script that scrapes thousands of pages

I've written a CasperJS script that works very well except that it takes a (very very) long time to scrape pages.
In a nutshell, here's the pseudo code:
my functions to scrape the elements
my casper.start() to start the navigation and log in
casper.then() where I loop through an array and store my links
casper.thenOpen() to open each link and call my functions to scrap.
It works perfectly (and fast enough) for scraping a bunch of links. But when it comes to thousands (right now I'm running the script with an array of 100K links), the execution time is endless: the first 10K links have been scrapped in 3h54m10s and the following 10K in 2h18m27s.
I can explain a little bit the difference between the two 10K batches : the first includes the looping & storage of the array with the 100K links. From this point, the scripts only open pages to scrap them. However, I noticed the array was ready to go after roughly 30 minutes so it doesn't explain exactly the time gap.
I've placed my casper.thenOpen() in the for loop hoping that after each new link built and stored in the array, the scrapping will happen. Now, I'm sure I've failed this but will it change anything in terms of performance ?
That's the only lead I have in mind right now and I'd be very thankful if anyone is willing to share his/her best practices to reduce significantly the running time of the script's execution (shouldn't be hard!).
EDIT #1
Here's my code below:
var casper = require('casper').create();
var fs = require('fs');
// This array maintains a list of links to each HOL profile
// Example of a valid URL: https://myurl.com/list/74832
var root = 'https://myurl.com/list/';
var end = 0;
var limit = 100000;
var scrapedRows = [];
// Returns the selector element property if the selector exists but otherwise returns defaultValue
function querySelectorGet(selector, property, defaultValue) {
var item = document.querySelector(selector);
item = item ? item[property] : defaultValue;
return item;
}
// Scraping function
function scrapDetails(querySelectorGet) {
var info1 = querySelectorGet("div.classA h1", 'innerHTML', 'N/A').trim()
var info2 = querySelectorGet("a.classB span", 'innerHTML', 'N/A').trim()
var info3 = querySelectorGet("a.classC span", 'innerHTML', 'N/A').trim()
//For scraping different texts of the same kind (i.e: comments from users)
var commentsTags = document.querySelectorAll('div.classComments');
var comments = Array.prototype.map.call(commentsTags, function(e) {
return e.innerText;
})
// Return all the rest of the information as a JSON string
return {
info1: info1,
info2: info2,
info3: info3,
// There is no fixed number of comments & answers so we join them with a semicolon
comments : comments.join(' ; ')
};
}
casper.start('http://myurl.com/login', function() {
this.sendKeys('#username', 'username', {keepFocus: true});
this.sendKeys('#password', 'password', {keepFocus: true});
this.sendKeys('#password', casper.page.event.key.Enter, {keepFocus: true});
// Logged In
this.wait(3000,function(){
//Verify connection by printing welcome page's title
this.echo( 'Opened main site titled: ' + this.getTitle());
});
});
casper.then( function() {
//Quick summary
this.echo('# of links : ' + limit);
this.echo('scraping links ...')
for (var i = 0; i < limit; i++) {
// Building the urls to visit
var link = root + end;
// Visiting pages...
casper.thenOpen(link).then(function() {
// We pass the querySelectorGet method to use it within the webpage context
var row = this.evaluate(scrapDetails, querySelectorGet);
scrapedRows.push(row);
// Stats display
this.echo('Scraped row ' + scrapedRows.length + ' of ' + limit);
});
end++;
}
});
casper.then(function() {
fs.write('infos.json', JSON.stringify(scrapedRows), 'w')
});
casper.run( function() {
casper.exit();
});
At this point I probably have more questions than answers but let's try.
Is there a particular reason why you're using CasperJS and not Curl for example ? I can understand the need for CasperJS if you are going to scrape a site that uses Javascript for example. Or you want to take screenshots. Otherwise I would probably use Curl along with a scripting language like PHP or Python and take advantage of the built-in DOM parsing functions.
And you can of course use dedicated scraping tools like Scrapy. There are quite a few tools available.
Then the 'obvious' question: do you really need to have arrays that large ? What you are trying to achieve is not clear, I am assuming you will want to store the extracted links to a database or something. Isn't it possible to split the process in small batches ?
One thing that should help is to allocate sufficient memory by declaring a fixed-size array ie:
var theArray = new Array(1000);
Resizing the array constantly is bound to cause performance issues. Every time new items are added to the array, expensive memory allocation operations must take place in the background, and are repeated as the loop is being run.
Since you are not showing any code, so we cannot suggest meaningful improvements, just generalities.

react display property with number

In reactjs I want to display a property.
Normally this isn't really hard to do it, but this time there is a number in the property. And that number depends on how many links the user has added.
This is an example of what my api returns to my react app:
embed_links: ["2"]
embed_links_0_embed_link: ["https://www.url.com"]
embed_links_1_embed_link: ["https://www.url.com"]
The embed_links is an array which says how many urls the user has filled in.
Then you get the urls the user has filled in, and each one has a number in it.
This is where I got stuck. I have tried to display the links with a for loop like this:
let embed_links = this.props.embed_links[0]
for (let i = 0; i < embed_links; i++) {
console.log(this.props.embed_links_[i]_embed_link[0]);
}
But this does not work..
So my question is basically, is there a possibility that you can display properties witch custom variables/numbers in it?
If you are asking access to a dynamical property within your object:
console.log(this.props["embed_links_" + i + "_embed_link"][0]);
Your syntax is wrong, the correct way to write this is as follows:
let embed_links = this.props.embed_links[0]
for (let i = 0; i < embed_links; i++) {
console.log(this.props['embed_links_' + i + '_embed_link][0]);
}
In the example, 'embed_links_' + i + '_embed_link' is the key that you use to select the correct property of object props.
Yes you can use this.props['embed_links_' + i + '_embed_link'][0]
However i would suggest storing your embed links in an array as objects
embed_links_collection: [
{
url:'https://www.url.com',
id: '1'
}
]
This is a cleaner, managable solution - you could also generate your embed_links property as this.props.embed_links_collection.length
You can use for .. in for enumerating this.props properties

AngularJS Microsoft Edge Screen doesn't reflect the DOM

I'm using AngularJS 1.5.0 and Microsoft Edge browser screen doesn't reflect the DOM.
I would like some suggestion how this can be fixed.
I can't really apply a fix for each element as the application is somewhat big with dynamic user content including Angular equations.
Also the app include a lot of dynamic bindings linked to input boxes.
Selecting the text with the mouse turn the 0 into a 2 which is the right value in the example below.
Also changing the position style back and forth seem to force Edge to redraw the element but it's somewhat an ugly fix that I don't like very much and it need to be trigger at so many places (Ajax request, input changes and so on...)
The page start with a value of 0. Then an Ajax call is made and it go fetch the real data. After some experimentation the bug only appears if the new data is 1 character (ex: 2 or 9). And it happens every time. If it's a 2 digit number (ex: 26) then the good number appears.
Any help on this matter would be gladly appreciated.
We were facing the same problem and it stopped occurring after removing the text-transform: uppercase style from the elements that are not updating.
#Sampson, it looks like this is a bug in Edge.
I was able to make a temporary fix with the use of Mutation Observer.
Little script that I made that works for AngularJS elements created server side.
Currently those are the only one causing trouble in my app.
<script>
$(document).ready(function(){
var ua = navigator.userAgent;
var re = new RegExp("Edge/");
if (re.exec(ua) != null){
console.log('edgeMutationObserver ON!!')
var edgeMutationConfig = { characterData: true, subtree: true };
var edgeMutationObserver = new MutationObserver(function(mutations) {
var rgb_p = /rgb\((\d+), (\d+), (\d+)\)/g;
var rgba_p = /rgba\((\d+), (\d+), (\d+), (\d.?\d*)\)/g;
mutations.forEach(function(mutation){
if(mutation.target.nodeType == 3){
var that = mutation.target.parentNode;
// Save the background color
var bgc = that.style.backgroundColor;
// Get applied style from style or css
var bgc_css = bgc || $(that).css('backgroundColor');
var bgc_temp,match;
if(match = rgb_p.exec(bgc_css)){
// rgb transformed in rgba triggers update
bgc_temp = 'rgba('+match[1]+','+match[2]+','+match[3]+',1)';
}else if(match = rgba_p.exec(bgc_css)){
// Slightly modify transparency
var alpha = match[4] == 0 ? 0.01 : match[4] - 0.01 ;
bgc_temp = 'rgba('+match[1]+','+match[2]+','+match[3]+','+alpha+')';
}else{
// If either inline style or css is already equal to transparent the redraw is not made so i choose an alternate color with 0 opacity
bgc_temp = bgc_css != 'transparent' ? 'transparent' : 'rgba(0,0,0,0)';
}
// Change background color to force redraw
that.style.backgroundColor = bgc_temp;
setTimeout(function(){
// Apply back previous style
// Doesn't redraw without a timeout in Edge
that.style.backgroundColor = bgc;
},0);
}
});
});
$('.ng-binding').each(function(){
edgeMutationObserver.observe(this, edgeMutationConfig);
});
}
});
</script>

Updating array values (Appcelerator Titanium Mobile)

I'm using both the 1.5.1 and 1.6.0 to test my apps on my OS X.
I'm trying to update some values in this array:
var myTab = [
{title:'foo1',value:'bar1'},
{title:'foo2',value:'bar2'}
];
If I update a value field in this array, it doesn't do it (which isn't normal):
Titanium.API.info('Before :' + myTab[0].value);
myTab[0].value = 'updated!';
Titanium.API.info('After :' + myTab[0].value);
It displays 'bar1' instead of 'updated!'.
What I tried next is to put the tab as a property list:
Titanium.App.Properties.setList('propTab',myTab);
And then, I tried to do the same thing:
Titanium.API.info('Before :' + Titanium.App.Properties.getList('propTab')[0].value);
Titanium.App.Properties.getList('propTab')[0].value = 'updated!';
Titanium.API.info('After :' + Titanium.App.Properties.getList('propTab')[0].value[0].value);
Same result: It displays 'bar1' instead of 'updated!'.
Is there another solution?
Thank you,
Regards
I've run into this sort of behavior before. While I never ascertained the cause, I found a workaround: you need to set myTab[0] to a value, and not myTab[0].value to a value. So, thus:
myTab[0] = {title: myTab[0].title, value: "updated!"};
Why, I do not know... I should probably figure it out.
You need to mention it as an array element then it should work. For e.g., in your case you may modify as foolows
myTab[0]['value'] = 'updated!';

Resources