Showing posts with label Web. Show all posts
Showing posts with label Web. Show all posts

Tuesday, 25 February 2025

Outlook Continues to be Dreadful

Today Microsoft Outlook is back at it's old habits of being utterly dreadful.


So I need to put "29th" with the the in superset, it used to do this itself, but not any more.... now you get "2  h" in normal and "9t" in superset... Dreadful!

 

 

Saturday, 21 July 2018

C++ : Coding Standards by Example #1 (with Boost Beast)

Today I've spent sometime doing a little different video, rather than just play about in code, whilst I played about I made a video of the time I had... Here is it...


We cover:


  • C++
  • Coding Standards
  • Structured Programming
  • Functional Programming
  • Encapsulation
  • Object Orientated Programming
  • Building the Boost Libraries (1.67.0)
  • Visual Studio 2017
  • Static Linking

And generally spend time seeing how I turn gobble-de-gook code into something usable and maintainable against my own Coding Standards.

Get the code yourself here: https://github.com/Xelous/boostBeast

Tuesday, 17 January 2017

Development : Microsoft Tools Troll the Office

Today, I've been working on a brand new project, which literally I thought was parked just yesterday... My mistake it seems this project was expected to be being worked on.. A coworker is currently slogging through the same API but for a different (embedded platform) and it's taken him quite a while.

So the product owner for this new piece of software from me (which is to call XML Web Services through SOAP up stream and a hardware device over USB or serial down stream) was quite upset when they arrived at my desk and asked how their product was coming, and my reply was "Doesn't exists, waiting for the hardware".

After a short, and shirty, moment with them I assured them I would do all I could with the interface, implement ALL the XML Web Service calls through the published ASMX tomorrow... Which is today... They looked sceptical, gave me that long stare saying "no, no you won't"....

And of course I have!... Microsoft Visual Studio Troll tool award of the day, it is so simple to work with a published ASMX, just add a service reference to the URL and it generated everything for you, then tell C# you're using that name space and voila there it all is laid out for you on a platter.

I just finished this project, less than 5 hours after starting it, so have dished it back to the product owner to find the hardware, I know they're not going to believe how quickly I've completed this cycle on the development, not least because the other chap has been on it weeks and has only done about 60% of the calls so far... Yeah, I say... But he's not using troll Tools.

Sometimes, times like this in fact, I quite like C#... Don't let on, it's my dirty secret.

Friday, 13 January 2017

People : Who is Robert Yates?

I'd love to know who Robert Yates is... I noticed a small bump in my viewing figures, someone had been viewing my site over and over with a source redirection of "protopage.com".

I've never heard of protopage, so took a look and found my humble blog here being a feed on the page of a one "Robert Yates".

Robert, thank you for adding me as a feed on your page, to reside alongside such illuminating voices as Dilbert is great to see, my only question is why?  What brought you to my humble abode?

Friday, 29 July 2016

Gaming : SuperSnake.io - New Personal Best


Just shy of 20 minutes growth... Not bad... Died to a super snake, he clipped the last of his fifth gold tokens as my venom spit struck, and... boom I popped, but I was quite happy with this performance.


Tuesday, 26 July 2016

WebSense Low-jinx

I've discovered today that WebSense is automatically killing off many links to many articles in my blog...

I covered this happening as a joke back in 2010... Six years ago!...

But today it seems the moronic thing has listed a whole plethora of my pages as "Sex"!


This blog is anything but!

And they're owned by Raytheon now, you know the US defence contractor, the ones who make missiles!... How can you trust any of their code when it does this amount of false positives, and is doing six whole years after I first pointed this out?!?!?!

Thursday, 30 June 2016

Blog Update : New Look

Some of you, the eagle eyed, may have spotted a new look & feel for the blog just went live... If you did spot it, congratulations, have a cookie on me!


I hope you like the new look, and I'll be talking to you soon about my adventures trying to secure new branding & hiring artists/designers to help!

Monday, 20 April 2015

Blog Views

We're in a unique position of two first, today is the first day my Blog has Russia as the top source of viewers (hello Russia - you strange lot you)... And also the first time the United Arab Emirates has featured on my top view count list... 


Wednesday, 4 February 2015

I broke Amazon

I broke Amazon... I've had an item on order since Monday, and at the time of ordering it was listed as in stock and I even paid for expedited delivery...

When on Tuesday it'd not been dispatched I really wondered why, so asked, but had no immediate reply, four hours later I started to chat with them and not only did I get my expedited payment refunded, but they insisted the item would be sent for delivery 1st class.

Unfortunately, since then I've seen the item appear as "Out of Stock", as "12 items in stock", as "Back in stock Friday", and as "In Stock"... So I've not been confident it'll be delivered.

Today, it's still not listed as dispatched, but it is still listed as "In Stock", however the price has risen £20... From Monday to Wednesday, £20...?

This is sold and dispatched by Amazon... I dunno, maybe my query cost them to answer, so they upped the price.

Either way now, if I get it before the weekend I'll be ecstatic, but just to get it for the original price I'll be happy...

Monday, 27 October 2014

British Gas - Poor Systems

I have to just release this, because if I don't vent, I'm going to blow... The payment and billing systems at British Gas must be so archaic it's untrue, they seem to have different systems doing separate different parts of the same job, and these separate different systems don't share information, so they're out of sync or slow or just so fucking annoying.

I've commented to them directly about this several times and they've simply ignored me, but now I figure its beyond a joke.

Last night, I had a reminder to submit my meter readings, so I popped onto their website to put them in, as I logged in I noted last months bill was still not paid, so I checked and made payment in full.  Submitted the new readings and had an instant bill...

Here's my first beef, if my bill was a reading last time and a reading this time then the values are consecutive and they calculate a bill instantly, and I paid it instantly....

However, the previous bill went unpaid for a month because the bill prior to that was estimated, and they waaaaaaay over estimated, so the readings went in and they were lower than even the estimates that had been put in.

The system immediately has a brain fart and doesn't give a bill, so after waiting all weekend for it I clearly gave up and didn't pay all month, because their system is just so shit, I figure a human had to intervene somewhere and reconcile their stupid estimate bullshit and issue the bill, and I can say this happens because more than once I've had to call them and correct a bill, to have to manually intervene and call an Indian call centre just to get a bill is wholly unacceptable in my book, it's the online equivalent of standing up and waving for the waiter in a restaurant and him giving you the finger.

So what did the website do last night?... Well, luckily this time it generated a new bill, and so I paid the first, submitted and paid the second... right done?... All cool...

NO!!!!!!

Because fucking hours later another system at British Gas decides to e-mail me and tell me I need to submit my readings....

Time runs upwards here, earlier messages are lower...

I'm tempted to go give them a reading which is like 1kw/h different and watch their system's brain drop out... Or even, I might start submitting individual readings each time the gas and electricity meter changes value... You know proper spam that sucker, I've read their billing small print there's nothing which says how few readings one has to make, just that one has to submit a reading or allow access to the meters by reading taking staff at intervals...

So, I use say 301Kw/h of electricity per month, lets submit 301 readings, their system asked me to submit a reading 5 hours after I'd done just that for the month!

Tuesday, 19 August 2014

Google Gaffs with Greggs

I just love this joke....


But I love it even more, now I've had a look and the news article is actually about the logo I went to see.

I suddenly fancy a hot sausage roll... DAMN IT!

PMSL... Whilst drafting my post, the logo has gone... Search now and it's blank.



And the story hit the Telegraph... 

Tuesday, 12 August 2014

Supermarket Search - Website Failz

So, I have some computer restoration and cleaning to do, this is of a set of four Atari ST's and an older Commodore 16... So I want to get some isopropyl alcohol really, but I'm skint the budget for this project is spent on the carcass Atari STe to re-case one I have which was painted green...

Anyway, a cheap alternative is to therefore look for cheap alcohol based skincare products in the beauty isle... Now I'm at work, and its lunch time, so I hit the internets and I wondered if Asda had anything suitable.... Here's the search


WHAT AN EPIC FAIL!

Yes, the search ability of this website is appalling, its not the only super market chain with this kind of problem, Sainsbury's is an online supermarket site I've used a lot and it's search is terrible...

Supermarkets, make this better, or hire me... I'll make it better.

Monday, 4 August 2014

Gaming Update - Heroes & Generals

War Games, Games of War, Call of War... We could list any number of iterations of warlike words and find a hint of a game in there, so we each need to pick our genre and wade through the mess of bad games to find good ones, this weekend however I've found one which I find strangely compelling, but which I don't think is the perfect game.


What do I mean by perfect game?  Well, I think for everyone their perfect game is different, I once thought World of Warcrack was my perfect game.  But fifteen minutes of thinking about how much time I'd wasted collecting tokens to then see an expansion appear with yet more quests to collect yet more tokens (BUT THEY WERE BLUE THIS TIME!) had me quit, from sheer frustration... Many other games have come and gone since...

World of Tanks for example, this has been a staple over the last few years, but it ebbs and flows to and from in my playing landscape, mainly because of the huge step up in skill and memory needed to just play tanks... As a kid I could play tanks, I poured them out of my plastic tub and drove back and forth across the iron curtain with them in the soil and sand of the back yard... Now-a-days the entry level is so much higher, especially when you add competitive people into the mix, and you suddenly find yourself meeting people who don't just want to wallow in the mud like the little white bull, but instead they want to ammo rack you and hide behind your burning hulk.

This isn't a jab at competitive play, I was very competitive in other games, notably Day of Defeat, my first major and perhaps the only multiplayer third person shooter I mastered, and the one of the few games I've chosen to actively play competitively.

So finding Heroes and Generals, and being a little tired of being shot out the skies in War Thunder, or having my Tank blown from under me in World of Tanks, and so very annoyed with other titles in my Steam library, I downloaded and set to figuring out this game.

Figuring out is the main challenge, you see the game comes in multiple parts, there is a browser like part, which acts as a window onto the solider's, weapons, vehicles, training and skills you have - as well as the credits or game gold you've earned or purchased to unlock more of the game.


Then once you enter battle a 3D client launches connecting you to the battlefield.



Once into the 3D world, you choose your spawn location, and set about working out how this game works...



Its a massively multiplayer World War Two landscape, this is Day of Defeat of old for me... Except, one can end up training to drive tanks, jeeps, trucks, planes... Or just fight on foot.

And as a beginner, fighting on foot was my only option.  So creating a German soldier, I was handed my G43 and a few potato masher grenades and thrown into the mix.


Almost the first thing I found was the ability to use nearly anything you find on the battlefield, enemy guns, ammo, vehicles and even a villagers trusty bicycle.

At the low levels you need to get used to the bikes, because they're the ubiquitous and only transport in the game, at least transport faster then your own feet.


The mechanics of the soldier are good, raising his weapon, aiming and reloading all come naturally to anyone with even a modicum of first person shooter experience.  Moving has its down sides.

The initial problem I had with movement was using sprint (shift) and then sending my man prone (z), between the two is the "\" key or "|" bar key on a UK layout keyboard... pressing this rogue key brought up the 3D engines message queue, a little like the old style console in the Quake engine... And hitting it was very very annoying, locking out your controls and initially I was not aware I'd miss keyed and hence had no idea how I'd opened this console view... once I got it closed a controls remapping was in order... Except, I could not change this damn key - least not in the base view.


The game is very atmospheric however, providing early morning fog, dust, smoke, impressive explosions and good terrain.


If you can find a position to shoot from, you can pretty much shoot from it... However, there are some annoying problems, and problems with benefit the annoyance causing, teeth gnashingly smug, camping... Yes, this game encourages more camping than...


Initially without resorting to camping I found myself dead time and time again, but at least I was leading assaults, one tactic I noted benefited the early games (which are played on a simple set map with three capture flags) is that if one flanked around and went to capture the enemies first flag, they would all rush back to save the flag.  This allowed your own team to then capture the contested middle flag more easily... I'd be there time and again, capping the rear enemy flag as about 8 enemy would hove into view and nail me with a nail of gunfire and grenade... But all was good, because we took the middle, kept the middle and I kept going back to the enemies flank and rear to stir up trouble, thinning the struggle for the middle.

I just did this, it was obviously a winning tactic, and game after game we won...

You know what reward I got for this active effort... NOTHING.

Not a dime, not a sausage, not a scrat... I had a horrendously negative Kill to Death ratio, and received no capture points - because I never completed a full cap - and though I might spot and nail the odd enemy coming in, I was basically hiding in their base, with a limited field of fire, so unable to really get meat a head of my shots and so I didn't score much.

The agony of this state of affairs was only added to by the crappy G43 weapon I had, and the very high prices of alternative weapons... For instance, in the whole weekend I earned around 40,000 credits.... I had to spend 5,300 on grenades and was forced to spend my initial credits on a MP36 (which I never use) by the tutorial...

So, what could I get for my 40,000 credits... NOTHING... The K98, a more powerful rifle is 71,000 credits... So for playing maybe 12 hours over a busy weekend, and winning games, I didn't earn nearly anything.

Luckily I levelled up quickly and around level 4 I was earning "Soldiers Pay", this is an amount of credits automatically awarded on a Win, if you're active for 50% or more of the battle... And Winning I was in the early games, so with credits coming in, I decided to upgrade my pitiful G43 rifle, rather than save up for the K98.


New sights, different ammo and a new barrel and I had added to the punch of the weapon significantly, though it was still perhaps 100,000 credits away from being a one shot killer.

The upgrade statistics are also a bit of a black box here, you can select items to see how they affect range, or damage done, but there are no real obvious benefits to some of the options available... Huge damage, but massive accuracy penalty... Right, I smell the game balance here, but this is a war game, in war designers don't generally strike the nerf bat so hard on an option.


However, from level 4 and above I had a very quick rise in Ranks, mainly because once you get over level 4 you're out of the boring 3 flag set map and into the open world of any battle on any map... You can select which mission to enter, or even join a battle on a specific location, for example I took part in the defence of Nottingham several times - loosing each time - DOH.

But, I did find a general rule of thumb, missions either consisted of winning quickly with friendly armour and combined arms... Or my team literally under performing all around me.

Add to this the already mentioned - no reward for tactical actions - and I was getting a little bit frustrated.

So much so between Saturday and Sunday, I took a break and thought about how should I play, should I come to this game and try to play it like others - like Day of Defeat, where I would never have had a G43 as my main weapon? - or should I try to learn more about this game, about how the game designers want you to work it.

I chose the latter option, and things started to take form...  The first thing I noted was that one could select a badge on ones character, the badge is like a special skill, and it defaulted to a badge given to me by the training mission, however, changing it to a different skill I found I was much less noticeable by the enemy, great for my flanking actions.

Then I changed how I moved, instead of running from A to B, I found myself going from tree to tree, from tree to rock, reading the terrain and trying to learn how to stay in cover.  To my delight the game picked this up and awarded me skill points for scouting, for combat movement, for all manner of things... And these added into the very complex layers of the browser section of the game, upgrading my soldier.


One can pay to win here, just throw gold at your skills (or ribbons as they're called in game) and you can max them out, buy any weapon and take people out, but I'm in this for the long haul, I want to unlock the game as I go.

I think, when I'm bored of WarThunder or everything else, Heroes and Generals might be a place for me to while away an hour in first person combat.  I just hope that the unlock curve is not as exponential as I fear it maybe - as I'm now 20 hours into playing and after upgrades and ammo refills, still only have around 40,000 credits, where I want to really start to buy more powerful weapons, such as those I pick up off of corpses.

Rethinking the game play style I found most successful, it consisted of hiding in the flanks, taking out enemy as they were in obvious locations and then picking up a sniper rifle, or other such powerful rifle as soon as possible.  Sticking with the issued G43 is a real struggle, especially as you pick up the US counterpart Garand and its far superior...

Monday, 13 January 2014

LXF - Flushed with Challenges

I was just browsing to the LXF site and I notice I've been flushed....


"You can't request more than 20 challenges..."  What the heck is that all about?

Saturday, 30 November 2013

YouTube Censorship?

I've just been the victim of censorship, on the internet, I'm sat here on the internet and I can pretty much get to see anything I want from this seat... I can see frogs put in blenders, I can see car crash victims, I can see men in Bikini's impersonating women... Yet I can't watch a video by a YouTube comic?


I find this fascinating... I'm now furiously going to find an internet gateway obfuscator just to see what is so fancy I can't watch it...

Friday, 22 November 2013

Sketches of Unidentified Bodies

Reading the news there is a call for a European wide website, or database for all unidentified bodies to be searched for, a great idea and one I can't believe has not been implemented before in our information age.


However, as part of this reading I ended up looking on the UK Missing Persons Bureau website, and looking at their case search pages... 

There was no-one there I knew, but I did see lots of the sketches made of some of these poor people, their last images on Earth in many cases... Some where photo's of reconstructions as clearly nature had taken its tole and they were only skeletal remains.  But some here quite life like sketches doing honour and making the person look real.

However, some of the sketches on there... looked like they were done by blind brick layers, some sketch artist who was only telling people they could draw, the pictures were terrible, childlike, lacking any skill, or depth or flair for art at all.  And worst of all, apart from looking awful these terrible sketches, if anything, detract from the chance of anyone recognising the body.

Terrible, there should be some level of competance in such situations, surely, even just getting a budding amateur whom has the nack with a pencil, rather then whomever was got in on some of those pictures.

Tuesday, 12 November 2013

Google Goofs with Plus

I'm an avid YouTube watcher, I enjoy many topics, but the number of the subscriptions I have whom are mentioning the Google+ comments bullshit on YouTube... We have...

Jingles... "It sucks doesn't it"

Boogie (aka Francis)... "I tried to put up with this new Google+ bullshit"

Dave (aka EEVBlog)... "Hello McFly... Hello... I'm approving... It's retarded... It just doesn't work"


This debacle is just on going... I personally hate the system, they've removed functionality I enjoy, such as the addition of a time into the comment so you can link what you're saying to a specific moment, then it used to allow me to reply to a comment, right now I don't know how to address a comment to a specific recipient.

And then the "Real name" thing.. I've seen Hitler posting... And the big JC... Santa and fucking Gandalf... Like he's not busy enough... it's like What the fuck!?!!?

This is Google's biggest visible change ever, and its abigger flop than anything that they've had flop before.  I hate google+, I only use my google account for gmail and this blog, it happens they own YouTube so that's linked in there too, but I don't specifically use Google+... I like blogspot, and I like YouTube, and I used those services on their own merit.  The fact they're piggy backing Google+ on those more used, more popular interfaces says a lot, if Google+ was as all invasive and defined the social space then fine, but it doesn't, so to make it impact on YouTube is a pain in the back side, stupid.

And as that mad Aussie bloke says better... "this is just Evil".


Addendum, after writing this yesterday, Boogie has been back on camera, lets see him in action:



Another Addendum, I've made one reply to one message in the new system... Look what appears in my inbox linked to my YouTube account... This is new, it never did this shit before...


That's just an hour in my small inbox, on a small comment on one video, I usually post all over... And I went into my Video Manager area to look for my YouTube inbox... No, my YouTube inbox is gone, its sending messages out to my own personal e-mail... just swamping me in mails, I can't imagine how terrible this would be for a content maker.

And then I've spotted more issues with the new system itself... Like if someone has relied to a comment, you used to be able to click "Show Comment", so the new message could be linked back in a tree to the comment it was about, this is called a discussion, and its how we as humans converse...  Now however, you only get the name of the person you're replying to, and you click it and the site takes you to their profile page... Not to the comment... So the context which 90% of comments sit in has been lost, totally lost.

I'm beginning to really hate the new system, and I'm happy to see big contributors, like boogie standing up to this shit.

Wednesday, 12 June 2013

Outlook Web Mail

Here's my review of outlook web mail - which I've oft moaned I've been forced into using - from a working e-mail system to this piece of shit.... And that's my review...

ITS A PIECE OF SHIT

And just so you can see just a few of my problems with it, a picture speaks a 1000 words.


And yes, I've tried it on all the major browsers, I try to use it from different locations (i.e. different internet connections) and from different Operating Systems.  It just does not function sufficiently, and I'm fast becoming forced to have to resign myself from using it - after over 15 years using that e-mail address - which is a major MAJOR ball ache.

Tuesday, 2 April 2013

E-mail Hacked, WarThunder Ruins Economy & Minecraft restart


What a bit of a roller coaster time I've been having, lots of personal stuff, but then technology has slowly crept back into me.

I'm still enjoying WarThunder - though less so with the currently fucked economic model (I have Spitfire Vb and Vc, as well as two differnet model 109's to buy - all for 100,000 credits, whilst only able to earn about 10,000 per game, this means I'm going to take about 50 games to earn the cash -  and I only get to play 2-3 games an evening, so this is over a months grind to just play the next level of aircraft) and to be honest I can do without a grind of a game.

They did a good job with the April Fools joke in game however - I did enjoy flying in the My Little Pony Airforce, and the artwork was top notch, however I'd have been happier to see an economy fix.

Also, there was an event on Sunday where for winning your first and fifth fight you'd get gold eagles, I never saw this advertised, I never understood the text in game, and I never won in the one game I played that evening, so I never got any gold eagles and this makes me sad, from such PR highs to lows all in the space of a weekend.

The other technology news was that one of my e-mail addresses was hacked, by a chap in India, whom I thoroughly intend to visit and castrate.  Seems he trawled and then trolled my Yahoo e-mail password and started to spam people in my address list at 3am.  The next morning my wife asked "Why were you up at 3am sending me this"... and of course she'd clicked the fucking link, so I had to wipe the laptop, and change my yahoo account and all manner of things.  But being in possession of an ounce of technical nouse I fired  up a virtual machine and tracked this link mailed around down, I also tracked the links in the dozens of failed mail daemon delivery messages spammed from my account.  And they all went back to an educational establishment in the Punjab.

I sent a mail to the administrator of said Educational Establishment, but I don't hold much hope of them cracking down on this shit, not least because this place in the Punjab appears to be a rocky stoney mountain when you look on Google earth, but the image of the site as shown on their web page looks like a none-descript office building from Droitwich - no offence to Droitwich.

The other thing that's been going on is Minecraft - I've had minecraft since it first came out - I've even studied the java code under the hood - yes I'm that much of a geek.  But I've only really played it once.

I started to play it again - mostly as I'm so agreeved at WarThunder - but also because I'm still without power on my main gaming PC so wanted something I can run on the laptop whilst on battery power.

Anyway, I've started to enjoy Minecraft some, I have a little railway, I've got a cow farm, and I'm starting to automate somethings with the seemingly magic redstone.  I've been to the nether and I plan to open a big mining facility to discover more diamonds.  But I'm also tempted to start to record my exploits, and make a series of progress videos.  IJevin on YouTube does a good job of this, but he does seem to appear with lots of gear start off the bat, I'd rather show everything in real-time - or at least sped up in places - to show every rock, every seed, every stick gathered and how it came along.  But this is a pipe dream, I don't have a voice for YouTube video commentary, and I don't have the time, though I've love to have more YouTube content.

Thursday, 3 January 2013

HTML5 SSE Chat Server Example (Full Code & Video)


My first post of the year, and I should say Happy New Year I suppose.  The year is already starting out better for you poor folks reading my non-sense blog, because I have an item I'm going to explain in detail for you, including videos and pictures, and this is how to set up a very simple anonymous chat system through a server to multiple browsers using HTML5's Server Side Eventing mechanisms to remove the need to write polling javascript code in your browser.

The reason I'm going to cover this in details is that though there are lots of examples and descriptions out there as to how to set about doing just this the example code given is sketchy in most cases, missing in many and does not actually accomplish much with the technology to plant the seed of actually putting it to use.  So, in the hope of setting a trend for the year I'm going to put this post together, take video and explain it all and hopefully you'll all be able to get to the same stage I'm at and have a working chat exchange program.

Prerequisites
Lets cover the prerequisites, you need a web server set up on a machine, in my example here I'm going to use apache2 on Ubuntu 12.04 LTS, with PHP5 as my server side scripting language.  The browser I'm going to use is Google's Chromium, because I like its debugging in the form of the javascript console.

The server I have has been set up as a blank server image on a VMWare virtual machine instance, and I've run the following commands to get it set up:

sudo apt-get install apache2 php5 libapache2-mod-php5
sudo /etc/init.d/apache2 restart
sudo apt-get install apache2 php5-mysql mysql-server
sudo /etc/init.d/apache2 restart
sudo apt-get install phpmyadmin

I allowed phpmyadmin to install and selected to install it into "apache2" at the prompt and I'm done, my passwords are all known to me and so whenever I've been asked for one I've typed it in, you will need do the same, and no, I don't want to know your passwords :)

I've gotten the server's IP (ifconfig) and from my desktop machine I've browses to its IP "http://192.168.2.101/phpmyadmin" and checked I can get onto the database.

Database
I'm using a database and a single table as an imtermediary, each browser connected to the chat page will insert lines of text "chat strings" and they will be inserted in time order into the table and then delivered to all the listening clients as they cycle around.

This processing of the chat potentially allows us to process and filter it for profanity, or prevent inappropriate discussions of any type we choose, before we insert it into the database.

We need to add a database with a table to the server, and so we're going to use this code:


(Don't worry this is an image, we're going to break down the SQL line by line).

CREATE DATBASE ChatSystem CHARACTER SET latin1 COLLATE latin1_general_ci;

This line actually creates the database for us, its called "ChatSystem" and uses the latin character set and sorts (collates) its columns in tables by index against the latin character set.  If you're intenting to use a different character set you'll have to hit your chose SQL server's documentation for their available character sets.  But latin1 is going to cover most of Western Europe, North and South America's and the Antipodes for this example.

USE ChatSystem;

This just selects the database we just created.

CREATE TABLE IF NOT EXISTS GeneralChat
(
    Id   BIGINT NOT NULL AUTO_INCREMENT,
    PRIMARY KEY (Id),

    Tme     BIGINT NOT NULL,

    Text     VARCHAR(128)
)
Engine = InnoDb;

This instruction does pretty much as you would guess reading it, it creates the table with the three fields "Id", "Tme" and "Text".  Text is just the chat string we're exchanging, the field design allows for upto 128 characters so in our HTML presented to take chat strings in we must remember to limit the input box's length to allow only 128 or less characters.

Tme is actually time, I'm omitting the 'i' to avoid using a reserved word in anyones SQL implementation, the time we're going to take as the time the server receives the chat string.  The client browser is not going to have to send it, and its just going to be a number becuase our server side scripting language (PHP) gives us the command "time()" which returns the time as a single integer.

Finally Id is the order the chat strings are inserted, we're going to leave this as an auto incremented integer because then we need not worry about it in our SQL insert statement later, again like Tme the Id need not be worried about nor generated by the client browser.

I take all this SQL and run it through phpmyadmin's SQL intepreter and I get my new database and table ready for use.

Client Side - Chat.html
On the client I'm going to have a very simple page, which is an outer page with an input box and a "send" button, and then an inner frame (iframe) which is showing the messages as they come back from the server... I could make this all one page, but I'm splitting things up to keep the demonstration as simple as possible.

The outer page first, we need to have a table (yes I like tables you can use divs and spans all you like) which has two rows, the top row is going to show us chat arriving and contain our iframe and below we're going to have our input text box:

<table>
<tr>
<td>
<iframe src="chatstream.html"></iframe>
</td>
</tr>

<tr>
<td>
<table width="100%" border=0 cellspacing=0 cellpadding=0>
<col width="85%">
<col width="15%">

<tr>
<td colspan=1>
<input id="ChatString"
type="text"
value=""
maxlength="48"
onkeypress="HandleKeyPress(event)">
</td>
<td colspan=1
onclick="UserSubmitChat()">
Send
</td>
</table>
</td>
</tr>
</table>

So we have several things we need now define, first the inner frame HTML "chatstream.html", which we'll cover in detail below.  And then two javascript functions:

"HandleKeypress(event)" and "UserSubmitChat()", the first function just checks whether we're handling the enter key and calls the second function, it looks like this:

function HandleKeyPress (event)
{
var l_chCode = ('charCode' in event) ? event.charCode : event.keyCode;
if ( l_chCode == 13 )
{
UserSubmitChat();
}
}

So the mor importand function is "UserSubmitChat()" which looks like this:

function UserSubmitChat ()
{
var l_textBox = document.getElementById ("ChatString");
if ( l_textBox )
{
InsertChatString(l_textBox.value);
l_textBox.value = "";
}
}

Very simply the function looks up the element called "ChatString" which is our input box (see above in the HTML) and if found it inserts the chat string, blanking the input box.

Note: One could optimise the page to take the "document.getElementById" call once and store the "l_textBox" throughout!

So, I'm simply taking the string content of the input box and calling yet another function, what is this "InsertChatString(value)" function doing?  Well, lets take a look:

function InsertChatString (p_ChatString)
{
m_ChatQueue.push(p_ChatString);
}

Well, it takes the string and pushes it onto the queue of strings going somewhere, this is important we want to order the chat we're posting and a queue is an easy way to achieve this, we push onto the back of the queue and pop off the front when we want to dispatch the string somewhere.

Few developers realise the queue functionality is built directly into the javascript array, so to allow the member "m_ChatQueue" to be a queue for us we simply have to create it as an empty array:

var m_ChatQueue = [];

So, all in all our javascript block now looks like this, with neat and tidy functions to handle key pressing, string extraction and pushing the string onto the queue.

<script language="javascript">
var m_ChatQueue = [];

function InsertChatString (p_ChatString)
{
m_ChatQueue.push(p_ChatString);
}

function UserSubmitChat ()
{
var l_textBox = document.getElementById ("ChatString");
if ( l_textBox )
{
InsertChatString(l_textBox.value);
l_textBox.value = "";
}
}

function HandleKeyPress (event)
{
var l_chCode = ('charCode' in event) ? event.charCode : event.keyCode;
if ( l_chCode == 13 )
{
UserSubmitChat();
}
}
</script>

But still the strings go no-where, what I have done is therefore rather than have an iframe or hidden on screen element posting (with an HTML form) the data I've decided to have a server side script page (php) which will take the chat string as a HTTP GET parameter.

This page is to be called "chatsubmission.php" and take the paramter "ChatString", so the URL for posting the chat string "HelloWorld" will be "chatsubmission.php?ChatString=HelloWorld".

When I open the chat posting page then I want to smooth out the posting of these strings to the server, as the user enters chat strings I don't want them to be paused out as it posts to the server I want things to flow.  So the user seamlessly queues the chat strings they enter, and they may have posted many before the page submits them all, but the submission goes on as a background task very fast without seeming to interrupt the user or their browser.

To achieve this I'm going to use a timer, and when the HTML loads I'll start it:

<script language="javascript">
var m_ChatTimer = null;

function StartChatTimer ()
{
StopChatTimer ();
m_ChatTimer = setInterval(ChatTimerMatured, 500);
}

function StopChatTimer()
{
if ( m_ChatTimer != null )
{
clearInterval(m_ChatTimer);
m_ChatTimer = null;
}
}
</script>

Note: All the functions shown all go in the same single "<script>" block on the same page, I'm splitting them up for this post only, and will post the whole page code at the bottom.

The HTML to start the timer is then:

<body onload="StartChatTimer()">

Now we have a timer maturing every 0.5 seconds, and its going to submit to some URL we we've defined all the strings of text in the m_ChatQueue.  What does this code look like?

function ChatTimerMatured ()
{
StopChatTimer ();

if ( m_ChatQueue.length > 0 )
{
while (m_ChatQueue.length > 0)
{
var l_value = m_ChatQueue.pop();

var l_URL = "chatsubmission.php?ChatString=" + l_value;
var l_HTTP = new XMLHttpRequest();
l_HTTP.open ("GET", l_URL, false);
l_HTTP.send (null);
}
}

StartChatTimer();
}

Let us just analyse this code, so we stop the chat timer, to prevent another timer mature happening whilst we're processing a potentially long list of strings of chat.  And then check the queue, if there are queued items we take one item off (pop) at a time and build the submission URL.

Armed with the URL, we then cheat, we use the javascript XMLHttpRequest object to get that URL, effectively then our server side page gets the request and parameters.  Much as if we had an HTML form and submitted it causing an HTTP Post.

Take a moment to look this code over, both above and in the full listing for "chat.html" at the bottom of the post.

Once all the strings are posted, or we're determined there's nothing to do, we start the chat timer again.  During this interlude the user may have posted more chat strings, but we smooth out the operation.  We could also temper the duration of the timer to better suit slow internet connections, or increase the responsiveness if necessary.

Server Side - ChatSubmission.php
So far we've taken the user input and cleverly posted it into the server, now we must see what the server side does with the chat string:

<?php

if ( !empty($_GET) )
{
require_once('dbFunctions.inc');

$l_ChatString = $_GET["ChatString"];
if ( InsertChat($l_ChatString) )
{
echo "Y";
}
else
{
echo "N";
}
}

?>

This is the complete "ChatSubmission.php" page called by the javascript XMLHttpRequest object we previously explored, the PHP page includes some functions (written by us) and then from the URL gets the "ChatString" parameter, if there is such a parameter it then calls the function "InsertChat".

The PHP function I have written for this looks like this:

function InsertChat ($p_ChatString)
{
$l_result = false;
$l_Connection = ConnectDatabase();
if ( $l_Connection != null )
{
$l_ServerTime = time();

$l_SQL = "INSERT INTO GeneralChat VALUES (null, $l_ServerTime, '" . $p_ChatString . "')";

mysql_query($l_SQL, $l_Connection);

CloseDatabase($l_Connection);

$l_result = true;
}

return $l_result;
}

It opens the database connection, builds the insert SQL and performs the insert, returning true upon success or otherwise false.  Very simple, and you may pick over the bones in the full listing.

Before we move on, we need to just see the "$l_ServerTime" and use of "null" in the SQL we insert with, the null is for the Id, which as you should recall we set as AUTO INCREMENT, and the time is the server time at which we receive the message.  This time will be of interest later.

So, there we have the first leg of our chat string's journey, from the text input box into a javascript queue and then on a timer maturation out to the server as a seamless posting and into the mysql database.

Note: You can use any database or server side language you want at this point!  Change the script around however you want and experiment!

Server Side Event - Second Leg
The second leg of our chat strings journey is to be from the database out to the screen, this is performed with the "chatstream.html" page, which is going to set up the client browser to listen for the server side events being pushed back.  This is the page which you'll see most demonstrated out there on the internet, most demo's cover this setting yp of the message reception, and many do it better than I.

There are basically three events you can handle with Server Side Events in HTML5, "open" which is the event of the connection to the server being established, "error" which is the event when something has gone wrong server side, and finally "message" which is a text based string of characters from the server.

What you choose to put into the event is up to you, there are examples of doing json, xml or just plain text.  For our chat system the message sent is going to be the actual raw chat string.  We're going to make sure the server sends one chat string per message.

So, lets take a look at our HTML, its very simple:

<html>

<head>

<script language="javascript">
...
</script>

</head>

<body onload="LoadPage()">

<table id="chatTable" border=1 width="100%">
<tr>
<td>Chat</td>
</tr>
</table>

</body>

</html>

So we have a table called "chatTable" and we call a function called "LoadPage" when we open the page in the browser, we can now define the javascript:

function LoadPage ()
{
m_ChatTable = document.getElementById("chatTable");

source = new EventSource('chatlist.php');
source.addEventListener ("message", ChatArrived, false);
}

Breaking this down, we grap the chatTable from the HTML and then set up the key SSE receiving object.  This "EventSource" points to a new server side php page (chatlist.php).

And then registers for the "message" arriving to point to javascript function called "ChatArrived":

function ChatArrived (event)
{
console.log(event.data);
}

For debugging, this function will suffice, but my full function takes the data string and appends it to the chatTable:

<script language="javascript">
var source = null;
var m_LastTime = 0;
var m_ChatTable = null;

function LoadPage ()
{
m_ChatTable = document.getElementById("chatTable");

source = new EventSource('chatlist.php');
source.addEventListener ("message", ChatArrived, false);
}

function InsertChat (p_ChatString)
{
if ( m_ChatTable != null )
{
var l_newRow = m_ChatTable.insertRow(m_ChatTable.rows.length);
var l_newCell = l_newRow.insertCell(0);
l_newCell.innerHTML = p_ChatString;
}
}

function ChatArrived (event)
{
InsertChat (event.data);
}
</script>

This therefore completes the HTML5 SSE loop back, so long as the "chatlist.php" serves up SSE events each time it sends a message it'll arrive on the page and append to our chat table.

Note: Some readers have forgotten this "chatstream.html" page we've just defined is inside the iframe from the first page, so we can see on the table the chat listing in the iframe and then the input box below.

Server Side - chatlist.php 
Our final page is the PHP page which lists the chat back to the clients, the design I've gone with is a loop which takes the time and then returns each line of chat between the time taken and "now" each loop.  Then it sleeps and repeats, it looks like this:

<?php

header("Content-Type: text/event-stream\n\n");
header("Cache-Control: no-cache");

require_once('dbFunctions.inc');

$l_LastTime = 0;
while ( true )
{
$l_LastTime = ListChat($l_LastTime);
sleep(1);
}
?>

The important parts for the HTML5 SSE mechanism are the two header lines, we define the header type to be "text/event-stream" and that the page is to use no cache on the client side.

Note: The two new lines "\n\n" on the Content-Type string are very important and should not be ommitted.

Again the PHP page uses the include file we've defined, which has its complete listing below, but we'll just cover the "ListChat" function now:

function ListChat ($p_LastTime)
{
$l_LastTime = $p_LastTime;

$l_Connection = ConnectDatabase();

if ( $l_Connection != null )
{
if ( $l_LastTime == 0 )
{
$l_LastTime = time();
}
$l_Time = time();

$l_sql = "SELECT * FROM GeneralChat WHERE Tme > " . $l_LastTime . " AND Tme <= " . $l_Time;

$l_result = mysql_query($l_sql, $l_Connection);
if ( $l_result )
{
$l_numRows = mysql_numrows($l_result);
if ( $l_numRows > 0 )
{
for ($l_i = 0; $l_i < $l_numRows; ++$l_i)
{
$l_LastTime = mysql_result($l_result, $l_i, "Tme");
$l_Message = mysql_result($l_result, $l_i, "Text");

sendMsg ($l_LastTIme, $l_Message);
}
}
}
CloseDatabase($l_Connection);
}

return $l_LastTime;
}

Important to the operation of this function, it takes the last time we checked for chat and returns the "now" time for the last message dispatched.  This lets us then query in the center for only those lines of chat we need to send.

The flow of the function simply opens the database, builds the SQL, performs the query and if there are results dispatches each row of results (each chat string) as an individual event to the client side.  Our client handles this in its "ChatArrived" function and posts each row onto the onscreen table.

We also specially make sure if the time of the last query was zero (i.e. the script just started running) we correct to "now" to prevent the whole history of the text being stremed back to the client.

The key piece of code however is this snippet:

for ($l_i = 0; $l_i < $l_numRows; ++$l_i)
{
$l_LastTime = mysql_result($l_result, $l_i, "Tme");
$l_Message = mysql_result($l_result, $l_i, "Text");

sendMsg ($l_LastTIme, $l_Message);
}

Each result takes its time, which we use as a value to send the string against, and the string, the sendMsg function then looks like this:

function sendMsg($id, $msg) 
{
echo "id: $id" . PHP_EOL;
echo "data: $msg" . PHP_EOL;
echo PHP_EOL;
ob_flush();
flush();
}

Again, many of the online examples of SSE give this style of function as their example, we add the Id to the PHP echo (which is going back down the text/event-stream to the client) and the "data: " line is the line which is passed to the "ChatArrived" function as the "event" parameter.

So if we put the code:

echo "id: 1" . PHP_EOL;
echo "data: HelloWorld" . PHP_EOL;
echo PHP_EOL;
ob_flush();
flush();

Then the "ChatArrived" function would receive a parameter of "HelloWorld", not "data: " leading it!

And this folks is the whole example.... You can follow the flow now:


  • chat.html : Takes the input string, queues and then dispatches the strings
  • chatsubmission.php : Accepts the dispatched strings into the database
  • chatstream.html : Sets up the SSE event source and registers to handle messages from chatlist.php
  • chatlist.php : Sends the messages as they arrive into the database

What follows is a live stream of my performing all these steps with a Ubuntu laptop and a Ubuntu server (Recorded 1st Jan 2013):



/// chat.sql full listing ----------------------------------

  CREATE DATABASE ChatSystem
  CHARACTER SET latin1
COLLATE latin1_general_ci;

  USE ChatSystem;

  CREATE TABLE IF NOT EXISTS GeneralChat
  (
Id BIGINT NOT NULL AUTO_INCREMENT,
PRIMARY KEY (Id),

Tme BIGINT NOT NULL,
Text VARCHAR(128)
  ) Engine = InnoDb;


/// chat.html full listing --------------------------------

<html>

<head>
<title>Chat</title>
<script language="javascript">
var m_ChatQueue = [];
var m_ChatTimer = null;

function InsertChatString (p_ChatString)
{
m_ChatQueue.push(p_ChatString);
}

function UserSubmitChat ()
{
var l_textBox = document.getElementById ("ChatString");
if ( l_textBox )
{
InsertChatString(l_textBox.value);
l_textBox.value = "";
}
}

function HandleKeyPress (event)
{
var l_chCode = ('charCode' in event) ? event.charCode : event.keyCode;
if ( l_chCode == 13 )
{
UserSubmitChat();
}
}

function StartChatTimer ()
{
StopChatTimer ();
m_ChatTimer = setInterval(ChatTimerMatured, 500);
}

function StopChatTimer()
{
if ( m_ChatTimer != null )
{
clearInterval(m_ChatTimer);
m_ChatTimer = null;
}
}

function ChatTimerMatured ()
{
StopChatTimer ();

if ( m_ChatQueue.length > 0 )
{
while (m_ChatQueue.length > 0)
{
var l_value = m_ChatQueue.pop();

var l_URL = "chatsubmission.php?ChatString=" + l_value;
var l_HTTP = new XMLHttpRequest();
l_HTTP.open ("GET", l_URL, false);
l_HTTP.send (null);
}
}

StartChatTimer();
}

</script>

<body onload="StartChatTimer()">

<table>
<tr>
<td>
<iframe src="chatstream.html"></iframe>
</td>
</tr>

<tr>
<td>
<table width="100%" border=0 cellspacing=0 cellpadding=0>
<col width="85%">
<col width="15%">

<tr>
<td colspan=1>
<input id="ChatString"
type="text"
value=""
maxlength="48"
onkeypress="HandleKeyPress(event)">
</td>
<td colspan=1
onclick="UserSubmitChat()">
Send
</td>
</table>
</td>
</tr>
</table>

</body>

</html>

/// dbcredentials.inc -- Full Listing ----------------------

<?

$g_User = "root";
$g_Password = "********";   // Place your password here
$g_Database = "ChatSystem";

?>

/// dbfunctions.inc -- Full Listing -------------------------

<?

function ConnectDatabase ()
{
$l_Connection = null;
include ('dbCredentials.inc');

$l_Connection = mysql_connect ('localhost', $g_User, $g_Password);
if ( $l_Connection )
{
if ( !mysql_select_db($g_Database) )
{
mysql_close($l_Connection);
$l_Connection = null;
}
}

return $l_Connection;
}

function CloseDatabase ($p_Connection)
{
if ( $p_Connection != null )
{
mysql_close($p_Connection);
$p_Connection = null;
}
}

function InsertChat ($p_ChatString)
{
$l_result = false;
$l_Connection = ConnectDatabase();
if ( $l_Connection != null )
{
$l_ServerTime = time();

$l_SQL = "INSERT INTO GeneralChat VALUES (null, $l_ServerTime, '" . $p_ChatString . "')";

mysql_query($l_SQL, $l_Connection);

CloseDatabase($l_Connection);

$l_result = true;
}

return $l_result;
}

function sendMsg($id, $msg) 
{
echo "id: $id" . PHP_EOL;
echo "data: $msg" . PHP_EOL;
echo PHP_EOL;
ob_flush();
flush();
}

function ListChat ($p_LastTime)
{
$l_LastTime = $p_LastTime;

$l_Connection = ConnectDatabase();

if ( $l_Connection != null )
{
if ( $l_LastTime == 0 )
{
$l_LastTime = time();
}
$l_Time = time();

$l_sql = "SELECT * FROM GeneralChat WHERE Tme > " . $l_LastTime . " AND Tme <= " . $l_Time;

$l_result = mysql_query($l_sql, $l_Connection);
if ( $l_result )
{
$l_numRows = mysql_numrows($l_result);
if ( $l_numRows > 0 )
{
for ($l_i = 0; $l_i < $l_numRows; ++$l_i)
{
$l_LastTime = mysql_result($l_result, $l_i, "Tme");
$l_Message = mysql_result($l_result, $l_i, "Text");

sendMsg ($l_LastTIme, $l_Message);
}
}
}
CloseDatabase($l_Connection);
}

return $l_LastTime;
}

?>

/// ChatStream.html --- Full Listing ------------------------

<html>

<head>

<script language="javascript">
var source = null;
var m_LastTime = 0;
var m_ChatTable = null;

function LoadPage ()
{
m_ChatTable = document.getElementById("chatTable");

source = new EventSource('chatlist.php');
source.addEventListener ("message", ChatArrived, false);
}

function InsertChat (p_ChatString)
{
if ( m_ChatTable != null )
{
var l_newRow = m_ChatTable.insertRow(m_ChatTable.rows.length);
var l_newCell = l_newRow.insertCell(0);
l_newCell.innerHTML = p_ChatString;
}
}

function ProcessChat (p_ChatString)
{
InsertChat (p_ChatString);
}

function ChatArrived (event)
{
ProcessChat (event.data);
}
</script>

</head>

<body onload="LoadPage()">

<table id="chatTable" border=1 width="100%">
<tr>
<td>Chat</td>
</tr>
</table>

</body>

</html>