Sunday 17 June 2012

Flash Crash Problems with Firefox 13.0.1 and Adobe Flash 11.3.300.257

Flash Crashing constantly in Firefox 13.0.1

All day I have been experiencing problems with Firefox and Flash.

Flash is notoriously buggy and crashes a lot which is why HTML5 offers so much hope for those of us wanting to watch movies online, on our phones or devices and Youtube style with the VIDEO tag and a wrapper iFrame.

I don't have a fix but I just wanted to put it out there that Flash version 11.3.300.257 is causing constant problems when used with Firefox 13.0.1.

A movie will start playing and then hang or the screen will go black before the "flash crash" message appears.

I am trying to watch some comedy central with another header plugin and up until today I have had no problems at all.

I don't know if this a problem with Flash or Firefox or a combination of both but it is really starting to piss me off. I have re-installed both Firefox and Flash multiple times.

I don't know why Adobe cannot get their act together with Flash as people are working their ass off to accommodate them and their notorious bugs, high CPU and memory leaks on devices whereas before they were just going to ditch Flash altogether and wait for HTML5 to spread.

If anyone else is having the same problem with Flash crashing let me know.

Saturday 16 June 2012

Forgotten your SSH Password?

How to quickly recover your SSH password

If you are like me your memory sometimes fails you and like today I tried to login with SSH into my server with Putty and couldn't remember my password. After about five attempts of all the ones I could remember I decided to give up incase I blocked myself.

Luckily I had added my IP into AllowHosts so I wouldn't be blocked by the DenyHosts settings which contain a long long list of IP addresses who have tried hacking my server but it was obviously doing my head in.

I then thought of a quick way of recovering it.

I could access WebMin in Chrome easily as my password was auto-filled stored but in Firefox it wasn't which had the web developer toolbar. Therefore as copying passwords doesn't work I couldn't use the web developer toolbar to show the password with a single button click.

Therefore in Chrome with the auto-filled password for my https://domain.com:10000 login page I did the following.


  • Hit F12 - this opens the developers console
  • Choose the Console tab
  • In the console write the necessary code to change the type of the input from "password" to "text"
  • If the password doesn't have an ID like VirtualMin then you can just access the first password in the form e.g:

document.forms[0].pass.type = 'text';


And if my magic your password field will change into a text input and you can retrieve your password.

And if your in any doubt about why you should leave your computers locked when you are away from your desk then this should be a reminder to you!

Tuesday 12 June 2012

New unobtrusive EU Cookie Compliance Code

Some people have said that my JavaScript lightbox method for EU Cookie compliance is a bit off putting for users as it takes them away from the site if they disagree.


Also at the last minute the EU has allowed compliance with their new cookie privacy rules through a much easier method.

This allows sites to show the users that cookies are being used with a link to the sites cookie policy and a button to hide the message in future. If they continue to use the site they have basically agreed to the use of cookies.

You may have noticed on sites like the BBC or Channel 4 etc they will show a little piece of text at the top of the page that slides out and tells the user that cookies are being used with a link to their cookie policy. They also have a button to set a cookie so the message isn't shown again.

This method is a lot less intrusive and doesn't take the user away from the site as there is no "agree" or "disagree" button.

Therefore for those of you not wanting to make use of my EU Cookie compliance code I have created a newer version that follows this new format which can be seen here.

It is up to you to create a cookie policy document that details how cookies can be viewed and disabled through various browsers and toolbars etc. Plus the text and styling is up to you but the example html page shows this new unobtrusive method in action.

The code makes use of jQuery to handle the animations so load in the source code from your usual repository e.g Google or jQuery e.g: http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
  
The actual JavaScript for the html test page is below.


// run immediatley - place in footer
(function(){

 EUCookie = {
  
  confirmed : false,

  Confirm : function(e){   
   var self = this;
   
   // create cookie   
   self.CreateCookie("EUCookie",1,365);  
   
   // slide back in the cookie bar
   $("#cookieWarning").animate({
     height: 0
   }, 300, function(){
    $("#cookieWarning").css("display", "none");
   });
   
   return false;
  },

  CheckEUCookie : function(){

   var self = this,
    val = self.ReadCookie("EUCookie");
   
   // if our cookie has been set
   if(typeof(val)!=undefined && val==1){   
    self.confirmed = true;
   }
 
   return self.confirmed;
  },

  CreateCookie : function(name,value,days) {
 
   if (days){
    var date = new Date();
    date.setTime(date.getTime()+(days*24*60*60*1000));
    var expires = "; expires="+date.toGMTString();
   }else{
    var expires = "";
   }
   
   document.cookie = name+"="+escape(value)+expires+"; path=/";
  },

  ReadCookie : function(name){
   
   var nameEQ = name + "=";
   var ca = document.cookie.split(';');
   for(var i=0;i < ca.length;i++) {
    var c = ca[i];
    while (c.charAt(0)==' ') c = c.substring(1,c.length);
    if (c.indexOf(nameEQ) == 0){
     var r = unescape(c.substring(nameEQ.length,c.length));    
     return r;
    }
   }
   return null;
  }
 };

 // add click event;
 $("#cookie-close-button").click(function(){EUCookie.Confirm()});
 
 // if no cookie set show form
 if(EUCookie.CheckEUCookie()){
  
  // cookie already set so hide box
  $("#cookieWarning").css("display", "none");
 }else{
  
  // Show the form - set to zilch then slide out to the appropriate height
  document.getElementById("cookieWarning").style.display = "none";
  document.getElementById("cookieWarning").style.height = 0;
  
  $("#cookieWarning").animate({
     height: 28
   }, 500, function(){
  }).css("display", "block");    
 }
})();

To view the code in action you can visit the demo page and download the html page and tweak it to your hearts desire.

Let me know what you think.

Saturday 2 June 2012

The Strictly iPhone Console - Debugging on iPhones

The Strictly iPhone Console - Increasing real debugging without simulators



Yesterday I blogged about debugging on iPhones and how useful the Debugger console was which showed up JavaScript errors and console messages without the need for an agent switcher. However I complained about the lack of ability to view the generated source code on the page when viewing on an iPhone.

However I remembered sometime back I blogged about some bookmarklets I was using that enabled me to view the generated source on older browsers like IE 6 and tonight I knocked together a little script that enables you to have basic "onscreen" debugging functionality when using an iPhone.

The code is some basic JavaScript that adds a DIV area to the bottom of the current page with two links at the top that allow you to view the generated and raw source code for the page. These open up in new windows and  if you have problems with them opening you might need to enable the popup window functionality in your iPhone Safari settings first.

Underneath is a basic console which due to the lack of scrollbar functionality on DIVs with overflow:auto or overflow:scroll I have created with a readonly textarea. If you need to scroll down the console you should use the two finger drag option to move the content within the textarea up or down.

I have also overwritten the window.console object so that the console.log function pipes out messages to this console if it's being used.

To Install the Strictly iPhone Console

1. On your iPhone visit this page and copy the JavaScript code from the area below into your clipboard. or vis

2 .Bookmark any page on your phone and then go into your bookmarks and edit it. Change the name to "Strictly Console" before pasting in the copied source code as the URL location for the bookmark.

3. Test that the code is working by going to a webpage on your iPhone and once the page has loaded open your bookmarks and select the "Strictly Console" bookmark. The console should appear at the bottom of the page. At the top of the console will be two links in a grey background "View Source" and "View Generated Source". Underneath will be the console area.

Clicking on either of those links will open up a new page with either the original source code or the generated source code from the current page. If nothing happens when you click the link check your Safari settings so that you allow Pop Ups. When you click the link it will ask you whether you want to open the pop up or not. Choosing Yes will show you the source in a new window.

4. To pipe debug out to the Strictly iPhone console window just use the standard console.log('hello'); function to do so.

As with all code that relies on DOM element make sure you check for the the existence of the console before trying to access it e.g a simple debug function could look like this:


function ShowDebug(m){
 if(typeof(window.console)!="undefined")){
  console.log(m);
 }
}


If you have problems copying and pasting from here (due to the crumy formatting of HTML in blogger) then you can download the compressed script from this location: iphoneconsolebookmark.js

javascript:(function()%7B
function%20htmlEscape(s)%7Bs=s.replace(/&/g,'&amp;');s=s.replace(/%3E/g,'&gt;');s=s.replace(/%3C/g,'&lt;');return%20s%7D
var%20_d=document,jq=_d.createElement('script');jq.type='text/javascript';jq.async=true;jq.src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js';var%20s=_d.getElementsByTagName('script')[0];s.parentNode.insertBefore(jq,s);
console=%7B
log:function(m)%7var%20l=_d.getElementById("logwindow"),txt=l.value,nt=((txt==""||/^\s+$/.test(txt))?m:txt+m)+"\n";l.value=nt;%7D,
GenSource:function()%7Bconsole.ViewSource(htmlEscape('%3Chtml%3E\n'+_d.documentElement.innerHTML+'\n%3C/html%3E'))%7D,
RawSource:function()%7B$.get(location.href,function(data)%7Bconsole.ViewSource(htmlEscape(data))%7D)%7D,
ViewSource:function(s)%7Bx=window.open();x.document.write('%3Cpre%3E'+s+'\n%3C/pre%3E');x.document.close()%7D%7D;
var%20log=_d.createElement("div");log.setAttribute("id","logger");log.style.visibility="visible";log.style.display="block";log.style.zIndex="2147483647";log.style.position="relative";log.style.backgroundColor="#fff";log.style.border="1px%20solid";log.style.width="98%";log.style.left="0";log.style.bottom="0";log.style.height="3300px";log.style.padding="5px";log.style.textAlign="left";_d.getElementsByTagName("body")[0].appendChild(log);var%20link=_d.createElement("div");link.style.width="100%";link.style.background="lightgray";link.style.color="navy";link.style.fontWeight="bold";link.innerHTML="%3Ca%20onmouseout='this.style.color=\"navy\";'%20onmouseover='this.style.color=\"blue\";'%20style='text-decoration:none;'%20href='#'%20onclick='console.RawSource();return%20false;'%3EView%20Source%3C/a%3E%20|%20%3Ca%20onmouseout='this.style.color=\"navy\";'%20onmouseover='this.style.color=\"blue\";'%20style='text-decoration:none;'%20href='#'%20onclick='console.GenSource();return%20false;'%3EView%20Generated%20Source%3C/a%3E";log.appendChild(link);var txt=_d.createElement("textarea");txt.setAttribute("id","logwindow");txt.setAttribute("readonly","readonly");txt.style.width="100%";txt.style.height="300px";log.appendChild(txt);
%7D)();


Test the Strictly Debug Console now

You can try the Strictly iPhone debug console out on this page by clicking the following button which will add a new debug message to the console on each click. The console should already have 15 messages inside it which were added when the page loaded. Remember the console will be at the very bottom of the screen so scroll right down to see it.



Obviously this is a very basic iPhone Console and nothing like Firebug or Chromes inbuilt console but it could be easily expanded with a little work and by loading in the jQuery iphone library you could easily create a popup DOM inspector that was initialised by a long tap down event to show the current elements styling and positioning. Let me know what you think and if you amend it to add more features let me know so I can update the code here.

To read why a proper debugging console ON the device is required rather than a user-agent switcher then read this article I wrote about debugging on iPhones.

C# Betfair API Code for identifying WIN only markets

Identifying WIN only markets on the BETFAIR API

Updated 02-JUN-2012 

As it's Derby day again I ran into the same problem as last year with this article except that the wrong market identified as WIN ONLY was the FAV SP market. One in which you bet on the favourites starting price. Therefore I have updated the BOT code for identifying a market from the Betfair API from HorseName, Racedatetime and Course alone.


If you don't know I developed the www.fromthestables.com website which allows members to access UK horse trainer information everyday about their runners.

As a side line I have also developed my own AutoBOT which uses the BETFAIR Free API to place bets automatically using my own ranking system which I have developed. You can follow my tips on Twitter at @HorseRaceInfo.

One of the problems I have come across during the development of my AutoBOT is that if you have the name of the Horse, Course and time of the race and want to find the Market ID that Betfair uses to identify each race there is a costly mistake that can occur due to all the various markets that are available.

I really got hooked on racing (not betting but actually watching horse racing) when I had a bet on Workforce in the 2010 Derby.

It came from the back of the field to storm past everyone else and won the Derby in record course time and in astonishing style.

Watching him apply the same tactics in the Prix de l'Arc de Triomphe to become the champion of Europe that same year installed the racing bug and then watching Frankel win the 2000 guineas this year in such amazing style has ensured that something I used to have no interest in watching whatsoever has become a TV channel turner.

Therefore when Frankel won the St Jame's Palace Stakes this year at Royal Ascot I was happy knowing that the AutoBOT I had written had placed a WIN bet on this horse early enough to get a decent price (for what was on offer for an almost 100% guaranteed win).

However when I found out that I had actually lost this bet that my BOT had placed I spent more than a few minutes scratching my head and cursing the PC I was sat in front of. However I found out that the actual market my application had put the bet on was a special WIN market in which the winner had to win by at least 4 clear lengths. Because Frankel had won by less than a length I had lost the bet. I wanted to know why.

I was annoyed.

I was quite pissed off actually and when I looked into it I found that to place a WIN only bet on the main WIN market in Betfair is quite a pain in the arse to achieve if you don't know the Market ID upfront as there is nothing in the compressed data that is given to you to identify that the market is the main WIN market and not some special market such as the one in which I lost that bet in.

Instead all you can do is run through a series of negative tests to ensure that the market is not a PLACE market, a Reverse Forecast or a Horse A versus Horse B market.

In fact since then I have found that there are so many possible markets it can be quite a nightmare to get the right one if you don't already have the Market ID.

For example today at 15:50 there was a race at Ascot, the Betfair Summer Double First Leg International Stakes that actually had alongside the usual markets a FIVE TO BE PLACED and TEN TO BE PLACED market. This was in a race with 23 runners!

The prices were obviously minimal and you would have had to of put down a tenner to win 70p on the favourite Hawkeythenoo but it meant that my original code to identify the main WIN market required updating as it was returning these new market ID's instead of the one that I wanted.

I have outputted the code for my Betfair API Unpack class below and this is just the part of my AutoBOT that returns a Market ID when provided with the compressed string of data that Betfair provides along with the Course name, the market type (WIN or PLACE) and the Race Date and Time.

You will see that I am using LINQ to filter out my data and I am using a custom function in my WHERE clause to return a match. It is this function that is the key as it has to check all the possible Betfair Market types to rule them out when looking for the main WIN market.

If you don't use C# then LINQ is one of the cool tools that makes it such a great language as it enables you to apply SQL like queries to any type of object that extends IEnumerable.

Obviously if you don't bet or don't use Betfair you might be wondering what the heck this has to interest you and you would be right apart from this bit of code being a nice example of how to use LINQ to return a custom list that can be iterated through like any array or list of objects.

Remember: Betfair may introduce even more markets in the future and if anyone knows of any markets I have missed then please let me know as I don't want to lose any more money by accident because of some weird market Betfair decides to trade on.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BetfairUnpack
{
 // This is my object that holds data about the Betfair market
 public class MarketDataType
 {
     public int marketId;
     public string marketName;
     public string marketType;
     public string marketStatus;
     public DateTime eventDate;
     public string menuPath;
     public string eventHeirachy;
     public int betDelay;
     public int exchangeId;
     public string countryCode;
     public DateTime lastRefresh;
     public int noOfRunners;
     public int noOfWinners;
     public double totalAmountMatched;
     public bool bspMarket;
     public bool turningInPlay;
 }

 public class UnpackMarket
 {

     // Use my own class amd make a list object we can loop through like an array
     public List<MarketDataType> marketData;

     private string BaseDateVal = "1/1/1970";
     private string ColonCode = "&%^@"; // The substitute code for "\:"
     private int DaylightSavings = 3600000;

// This method unpacks a compressed string and returns the correct MarketID filtering by the Course, Date and Market type
     public UnpackMarket(string MarketString, string racecourse, DateTime racedatetime, string marketType)
     {

         string[] Mdata;

    // Betfair uses it's own format and we need to split on a colon
         Mdata = MarketString.Replace(@"\:", ColonCode).Split(':');

    // get our date and time
         DateTime BaseDate = Convert.ToDateTime(BaseDateVal);

         // if we are not currently in daylight savings then set that property to 0 so we get the correct time
    // I have had instances where the correct market is not returned due to Daylight savings time
         if (!DateTime.Now.IsDaylightSavingTime())
         {
             DaylightSavings = 0;
         }

    // Use LINQ on our IEnumerable object to query our list of markets filtering by our custom function MatchMarket
         IEnumerable<MarketDataType> queryMarkets =
             from m in Mdata
             where !String.IsNullOrEmpty(m)
             let field = m.Split('~')
             where (MatchMarket(field[5], BaseDate.AddMilliseconds(DaylightSavings + Convert.ToDouble(field[4])), field[1], racecourse, racedatetime, marketType))
             select new MarketDataType()
             {
                 marketId = Convert.ToInt32(field[0]),
                 marketName = field[1].Replace(ColonCode, ":"),
                 marketType = field[2],
                 marketStatus = field[3],
                 eventDate = BaseDate.AddMilliseconds(DaylightSavings + Convert.ToDouble(field[4])),
                 menuPath = field[5].Replace(ColonCode, ":"),
                 eventHeirachy = field[6],
                 betDelay = Convert.ToInt32(field[7]),
                 exchangeId = Convert.ToInt32(field[8]),
                 countryCode = field[9],
                 lastRefresh = BaseDate.AddMilliseconds(DaylightSavings + Convert.ToDouble(field[10])),
                 noOfRunners = Convert.ToInt32(field[11]),
                 noOfWinners = Convert.ToInt32(field[12]),
                 totalAmountMatched = Convert.ToDouble(field[13]),
                 bspMarket = (field[14] == "Y"),
                 turningInPlay = (field[15] == "Y")
             };

    // convert into a nice easy to iterate list
         marketData = queryMarkets.ToList();

     }

// return a Market if the values provided match
     private bool MatchMarket(string menuPath, DateTime eventDate, string marketName, string racecourse, DateTime racedatetime, string marketType)
     {
         bool success = false;

    // do some cleaning as Betfair's format isn't the prettiest!
         menuPath = menuPath.Replace(ColonCode, ":");
         marketName = marketName.Trim();

         // does the path contain the market abreviation - we keep a list of Courses and their Betfair abreviation code
         if (menuPath.Contains(racecourse))
         {
             // check the date is also in the string
             string day = racedatetime.Day.ToString();
             string month = racedatetime.ToString("MMM");

             // we don't want 15:00 matching 17:15:00 so add :00 to the end of our time
             string time = racedatetime.ToString("HH:mm:ss");

             if (menuPath.Contains(day) && menuPath.Contains(month) && eventDate.ToString().Contains(time))
             {
                 // if no bet type supplied returned all types
                 if (String.IsNullOrEmpty(marketType))
                 {
                     success = true;
                 }
                 else
                 {
                     if (marketType == "PLACE")
                     {
                         // place bet so look for the standard To Be Placed market (change if you want specific markets e.g the 10 Place market = 10 TBP
                         if (marketName.Contains("To Be Placed"))
                         {
                             return true;
                         }
                         else
                         {
                             return false;
                         }
                     }
                     // we can only identify the main WIN market by ruling out all other possibilities if Betfair adds new markets then this
  // can cost us some severe money!
                     else if (marketType == "WIN")                                                                                                                                                                                                                                                  
                     {
      // rule out all the various PLACE markets which seem to go up to ten horses! Just look for TBP e.g 10 TBP or 5 TBP
                         if (marketName.Contains("To Be Placed") || marketName.Contains("Place Market") || marketName.Contains(" TBP"))
                         {
                             return false;
                         }
                         // ignore forecast & reverse forecast and horseA v horseB markets                            
                         else if (marketName.Contains("forecast") || marketName.Contains("reverse") || marketName.Contains(" v ") || marketName.Contains("without ") || marketName.Contains("winning stall") || marketName.Contains(" vs ") || marketName.Contains(" rfc ") || marketName.Contains(" fc ") || marketName.Contains("less than") || marketName.Contains("more than") || marketName.Contains("lengths") || marketName.Contains("winning dist") || marketName.Contains("top jockey") || marketName.Contains("dist") || marketName.Contains("finish") || marketName.Contains("isp %") || marketName.Contains("irish") || marketName.Contains("french") || marketName.Contains("welsh") || marketName.Contains("australian") || marketName.Contains("italian") || marketName.Contains("winbsp") || marketName.Contains("fav sp") || marketName.Contains("the field"))
                         {
                             return false;
                         }
                         else
                         {
                             return true;
                         }
                     }
                     else
                     {
                         // I cannot match anything!
                         return false;
                     }

                 }
             }
         }

         return success;
     }
 }
}