Hackviking He killed Chuck Norris, he ruled dancing so he took up a new hobby…

9Aug/162

Front-end Demos on Github

I really like both JSFiddle and Plunker but they come with limitations. To counteract cross site scripting issues and other security concerns they sandbox the code with iFrames and similar methods. That is just fine when you do simple examples of front-end implementations. I actually managed to implement a connection to Google oAuth ina JSFiddle but it was hard and requires several re-loads of the page before the user actually get anywhere. Plunker suffer from similar limitations but is much better for larger demos since you can split the code into several files. I also like their editor better.

For more complex demos that implement oAuth, requiring post-backs or other more advanced features I'm now using the Github.io pages. Simply put the service allows static pages, which is great for JavaScript demos, to be served straight from a Github repository!

First you setup a repository named {githubusername}.github.io and check in whatever HTML, CSS and JavaScript content you'd like to run. This will be accessible via the {githubusername}.github.io web address. It has support for SSL (HTTPS) as well as custom domain names. If you use a custom domain name you will not be able to use SSL at this time. I have seen workarounds with CDN solutions like CloudFlare but I haven't tested it my self yet.

For any other repository you create you can commit files to a branch named "gh-pages" and they will be served at {githubusername}.github.io/{repositoryname}. In my case I put a "front page" in my {githubusername}.github.io repository linking other demos but you could actually build a complete blog in that space if you like. So far I have only scratched the surface of what can be done with this but there are a lot of information out there. At the bottom of this post there is a link to some more information to get you started.

The reason I ended up with this solution was due to JSFiddle/Plunker implementation complexity for my latest demo. When I moved to the US from Sweden my phone took care of my phone numbers missing country code and allowed me to dial them as +46. When I used Skype to dial them it just got the original number entered in the phone without country code. One big difference between the dial screen in Skype and the phone is that you can't edit the phone number in Skype. You have to delete the whole thing and type it in with country code and then the number. Since I sync my phone with Google Contacts I figured I'll use their API and a E164 (country code + phone number) javascript library to update all contacts in my address book.

Since the code use for my self was a bit of a one of, I now type in new numbers with country code, I thought I'll make a functioning demo out of the code. If people want to use it to correct their own address book they can. At the same time it's a complete Google oAuth, API implementation demo written in AngularJS.

E164 formatter demo: https://kallsbo.github.io/gcontactse164/
G
ithub demos: https://kallsbo.github.io

More info on Github pages: https://pages.github.com/

In the menu above you will find links to my demos on JSFiddle, Plunker and Github.

19Oct/150

Implementing Google OAuth in JSFiddle

The implementation of Google OAuth for use with there API's are simple with there API Client Library for JavaScript, if you are developing a normal webpage. If you want the functionality in a JSFiddle it's a little more complex for several reasons. I have put together a demo on JSFiddle that shows how it can be accomplished!

Background

I wanted to be able to include Google Oauth for API access in demos I create on JSFiddle. I did a few tests with the API Client Library for JavaScript provided by Google. Ran into several issues with cross-site limitations and sandboxing. Since JSFiddle runs in i sandboxed iframes it limits access to navigation, URL reading and other stuff that the client.js relies on to authenticate the user and get the token back. I found that if the user is already authenticated with Google and you set the immediate parameter to true it will work. That's probably good enough for several demos but it's not a clean solution so I spent a few hours and came up with a solution. If the user isn't already authenticated two new tabs will open up and nothing more will happen.

Pre-requirements

You need to setup a project in the Google Cloud Platform Console and get the clientID. You also need to setup Authorized redirect URIs that matches your JSFiddle. Due to the iframe nature of JSFiddle you cant use the jsfiddle.net address, since the result frame being served from the fiddle.jshell.net domain. For this demo I setup these two redirect URIs:

One address for the case of direct access to the fiddle (someone fining it via Google for example) and one if they navigate to it from my dashboard.

To get this to work I implemented the OAuth flow from the ground up. The demo uses jquery, because it's easier, but it can be done in pure JavaScript if you want to. I'm using the standard Oauth 2 flow were you send the user to Google for login with your client_id, redirect_uri and scope as query string parameters. The user authenticates with Google and get's redirected back to the provided redirect_uri with access_token, token_type and expires_in parameters as query string parameters. Google OAuth supports redirecting the user back to a http address but that's no good from a security standpoint! JSFiddle does support https on all it's fiddles so let's make use of it!

Different then a standard JSFiddle

There are a few things that are different from a regular JSFiddle implementation, to create a safe demo that handles the iframe limitations.

  • Check for HTTPS
    This is just for making the demo safe. When Google returns the user to the site with the token as query string parameter it is possible to intercept if you don't use HTTPS. A simple implementation of location.protocol == 'https:' checks if we are secure or not. This isn't needed since you can send the user from a HTTP site to Google and get the user back on a HTTPS redirect. This is just put there to make a point of the HTTPS implementation.
  • The use of fiddle.jshell.net instead of jsfiddle.net
    Since the iframe with the result, where all the javascript is executed, is served from fiddle.jshell.net all the content needs to be served from there. If not the script cant access the parent frame URL containing the access token returned from Google.

Points of interest in the code

  • Check for HTTPS
    As above this isn't really needed since I can set the redirect_uri to whatever address I want as long as it's specified in the cloud console.
  • Create the authentication link
    For this to work properly it needs to be a target="_blank" link. Navigation inside the iframe is blocked outside the jsfiddle domains. This is the reason why the demo needs to open a new tab to be able to return with the access token. The parameters at the top will set the basic information for building the link:

    var oAuthEndPoint = "https://accounts.google.com/o/oauth2/auth";
    var oAuthClientID = "702841265150-iaravt3jmu0c67k892pivj9kgkb8dbco.apps.googleusercontent.com";
    var oAuthScope = "https://www.googleapis.com/auth/userinfo.profile";
    

    Then we build the redirect uri from the current JSFiddle address. I implemented it this way to make it easy to fork it to create other demos based on this implementation. I use the a element for easy manipulation of the domain and path. Replacing the protocol and domain with https://fiddle.jshell.net:

    var a = document.createElement('a');
    a.href = document.referrer;
    var redirect_uri = ['https://fiddle.jshell.net', a.pathname].join('');
    a = '';
    

    document.referrer is used to get the actual address of the fiddle from the parent frame, even if the domains doesn't match at this point. An easy way to get around the same origin limitations of the iframe.

  • User clicks the authentication link/button
    The user is sent to Google to authenticate and allow the app access to the user information. The only scope requested in this demo is basic profile information.
  • User is returned to JSFiddle
    When the user is returned the fiddle will load all over again. So each time it loads it will check if HTTPS is used, if so check for the URL parameter access_token. This is why we need to use the fiddle.jshell.net domain, it will make all the iframes of the fiddle to load from the same domain giving our script access to it's parent. We need that access to grab the URL and extract the parameters. This function grabs different parameters from the URL of the parent frame:

    function GetURLParameter(sParam) {
        var sPageURL = window.parent.location.hash.substring(1);
        var sURLVariables = sPageURL.split('&');
        
        for (var i = 0; i < sURLVariables.length; i++) {
            var sParameterName = sURLVariables[i].split('=');
            if (sParameterName[0] == sParam) {
                return sParameterName[1];
            }
        }
    }
    
  • Use the token for API access
    As soon as we have the token we can use that for accessing the API with a simple ajax request via this simple function:

    function LoadUserInfo(access_token, expires_in) {
        $.ajax({
            url: 'https://www.googleapis.com/userinfo/v2/me',
            type: 'GET',
            dataType: 'json',
            headers: {
                'Authorization': 'Bearer ' + access_token
            },
            success: function (data) {
                // Hide login
                $("#login").hide();
    
                // Populate demo, img and name
                $("#user_pic").attr("src", data.picture);
                $("#user_name").attr("href", data.link);
                $("#user_name").text(data.name);
    
                // Show raw data
                for (var property in data) {
                    if (data.hasOwnProperty(property)) {
                        $("#raw_data").append("<b>" + property + "</b>" + data[property] + "<br/>");
                    }
                }
    
                // Display demo
                $("#demo").show();
            },
            error: function () {
                $('#demo').html('<p>An error has occurred</p>');
            }
        });
    }
    

Limitations

So there are a few limitations with this approach. You get the token that is valid for 3600 seconds (one hour) and implementing code for renewing that with out losing state is not possible. So if the user have started creating something and the token expires renewing it will end up in a reload of the fiddle. The other, smaller limitation, is that there always will be a second tab opened to authenticate the user.

You also need to set the code as base in the fiddle at all times, redirects to a version number like /3 will make the redirect back from Google to fail!

Any thoughts, questions or suggestions? Please share in the comments below!

Complete JSFiddle demo

12Oct/150

Embed image in HTML code

You can embed images straight into HTML code without loading a separate image file. This is called data URL and is a base 64 encoded representation of the actual image file. You can more or less embed what ever data you like this way but the only implementations I have seen so far is with images. So why do this? There are probably hundreds of examples where this can be useful, I have used it for:

  • For taglines on services like JSFiddle, where external hosting of files can be a mess. If I delete the file or my server is down my JSFiddle demos will be broken.
  • E-mail signatures, same thing here no dependence on external servers for serving images in my mail signature. Some e-mail clients out there doesn't display data URL's so be careful with this one.
  • Screenshots in documentation distributed with software. Since the file is loaded from the users local hard drive the bigger size (see below) isn't an issue for any image and I only have to distribute on HTML file with the complete documentation.

So why isn't every image put into HTML this way? The answer is simple, the size increases! For small images, usually part of the layout, can be loaded faster even though the size is increased. This is due to the lack of overhead from an additional http request to get the image file. Every time someone opens an HTML page over the internet the browser then open new http connections for each resource referenced in the HTML like images, css and javascript files. So by cutting down on the number of request the page can load faster.

Dataurl.net by Sveinbjorn Thordarson is a really good resource to check what files on your site that would be suitable for data url embeds.

Simple example of a base 64 encoded data url image, my tagline image:

<img class="brand-img" alt="Kristofer Källsbo aka Hackviking"    src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QCORXhpZgAATU0AKgAAAAgABgMBAAUAAAABAAAAVgMCAAIAAAAMAAAAXlEQAAEAAAABAQAAAFERAAQAAAABAAAOxFESAAQAAAABAAAOxIdpAAQAAAABAAAAagAAAAAAAYagAACxEElDQyBQcm9maWxlAAABkoYABwAAAAoAAAB8AAAAAFVOSUNPREUAACr/4gIcSUNDX1BST0ZJTEUAAQEAAAIMbGNtcwIQAABtbnRyUkdCIFhZWiAH3AABABkAAwApADlhY3NwQVBQTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLWxjbXMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApkZXNjAAAA/AAAAF5jcHJ0AAABXAAAAAt3dHB0AAABaAAAABRia3B0AAABfAAAABRyWFlaAAABkAAAABRnWFlaAAABpAAAABRiWFlaAAABuAAAABRyVFJDAAABzAAAAEBnVFJDAAABzAAAAEBiVFJDAAABzAAAAEBkZXNjAAAAAAAAAANjMgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0ZXh0AAAAAEZCAABYWVogAAAAAAAA9tYAAQAAAADTLVhZWiAAAAAAAAADFgAAAzMAAAKkWFlaIAAAAAAAAG+iAAA49QAAA5BYWVogAAAAAAAAYpkAALeFAAAY2lhZWiAAAAAAAAAkoAAAD4QAALbPY3VydgAAAAAAAAAaAAAAywHJA2MFkghrC/YQPxVRGzQh8SmQMhg7kkYFUXdd7WtwegWJsZp8rGm/fdPD6TD////bAEMAAgEBAgEBAgICAgICAgIDBQMDAwMDBgQEAwUHBgcHBwYHBwgJCwkICAoIBwcKDQoKCwwMDAwHCQ4PDQwOCwwMDP/bAEMBAgICAwMDBgMDBgwIBwgMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDP/AABEIAJYAlgMBIgACEQEDEQH/xAAfAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgv/xAC1EAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYTUWEHInEUMoGRoQgjQrHBFVLR8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4eLj5OXm5+jp6vHy8/T19vf4+fr/xAAfAQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgv/xAC1EQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/AP0zBwAOOBjrVO4VjI5G3luhqxLIFjPyj04qjdwyX6tErFC4IZh1UetftVSSgrs/n2lFzlyop20H9qoZCANxPznggZIAX29a0rTSoEQYiRgOQwHf/Gn2pjghEZgeMKvAGMAAfWprOVJEYoqFQTyD1968evUcpanuUcPyR0IX01Ym81QVboPceh9jUsdyphDEgZ4x6VleK/F9p4bsri4up4YYLWNpXeSVUVABkkknAA9TxXxB+0F/wV50vSrzUNK+H8NrrUmnSSQ3Or3BdrOGUA8xonzSpnPz7lU4+UMOa5KtaNNXkelQw0pu0EfeT6rFBwzYH86jHiG33YEg56V+HvxD/wCCn/xj8a6pcxz+M9UsfsyhojodvBawSKTz5oKO+Og+SXn14rzy6/a3+I17rT3Vz4y8YzreTbrlJ9budjoVwSiZAjkUncNmAeAQcKRwTzOmnax6sMmqNXckf0GJrME2MOhyOu4VX+2p9vdRlmAHAr8Pvgv/AMFIvit8E9Wm0+08U6nq+nXTs1tDr0j3yF+eBJKfMU5GNoYA5zX1N+zz/wAFubrWnitfGXheMNvCy3OnTNEwY5C/uJMjcSCCDKMHoOlVDH0Z6Xsc9bLK0Fdan6QrcOZRiI47k8YpxuGhzmOQAjqBuFcj8FvjdoPxx8F2mt+H76O8sLo7Q4BV42GdyOp5VgQQQeRiu4tk/d9B6jiuyx5zTWjK8UwIODz6dD+XWrNrfvbE7SR7E8UTWyzHoQcHvVeZXsTg7nTsQeR+HpRe2gGmdajusRzoOfWq994ZjvWE1vIF24YqTkHHSqZO47h0I45oe5kt4mMed2Rikp62E4xabZ43+2P8LLr4g/BbWNJXSDrU5C3FrbLeNZu08cgkjaOYcxyBlBVuzAV8a+L/ANjz4n/FP4dt5dtImpR6zLYQpq01rDfXmhXHkPMLlrfETzLPHuVsbnAJPzMTX2rpfxG8X6n478X6TrulzaZp0ixJ4fuoUEqhSsqs7FQcNuQSYkwBuC15npb/ABO0XQPDyw6cNTv7zTle4MzO6idw+9J2Z0EYTcpOUYPu2jbtDV9Zl+Ir4em6cHHe+rPtckqYnAUnRoThfmUldvt5eR5lpv7L/jb4X/F/xtqGk+HLDW9N13VHvbKWbxfd6eiRypEzqbVIpIg3mhzvwGwcd6K7CwX476Sdw0MahbM8xRp0gWclpWfLqbobFClVQB2GEbPQAFbTrVZu85xv6/n59ztq4nMpSvOpTbsle71skrvXd21PrxlCJjO4sOmaXR4g0TSHO5z19uRj9Kr3sq+SeDj6CtDSlX7PHgfXivJx8nypI/IctguZyYk9gpXIAcsNoz2rnZLn7As7JIqiPgjjKnHII/lXWToQh449q8g/a21KXwT+z/441W0adrmz0G8lhAb7jJA5UjjIII6/4V5E58sXI96Ku0j8x/8AgpB/wUcf4z/EW+8H6JsvPCemTGKQzllttQkjkKvJKiHMsSuMLHwrlNzHbgV8pzazrXi0ZtdVa/jgJH2dLYwxRrydqBflXnOAO3es/wCAvwsv/HXiK2F2HdY9uU3E7iB/Ew6qvYV9/wDwO/Z30WLSh/aVt9om2YQsmPx6fjXzi9pXk5Nn1kpU8PBQitUfB2kpf3Pn7rB7WVlEJdXIZhnJGcZ7GtnSvBR1iyNrNI8NxHlVIyEnQ9QT2P41+j3hr9kTwrqk2+bSLeUyMd6kZB5/Ou5sP2N/CNmgCadDGchtoQDp3z1Fbxy+W7OeWZK1rH5gn4CaxLHA8EV0/lARSDySfOXgqCAM8AYzjpg1e/4U1qdnf3F4lnIk0cZS9heM4nxwrjOOmPxHNfqRb/AvRPD2nG1t7KMw7i+1xuAPtkcVznib4f2+mRv/AKNDsk6yIgGeP4sf5NH1O2rM1j7uyPkz9gn9p26+AnxstFlnMWma20dnqdvKdiycgJOM4AZec/3lOO1fsH4c1ePU7CN43Dq65Vwchh6ivyt/aE/Z1sPHVrIUVLS5Y7UuFXBXBBG4fxLxX15/wTk/aJu/iR8NIvDniJmj8WeEo0sr/OMXUa/JFcL67goyfXnuK68JUavCb0OTH04uPtIb9T6pTv8ASmyRgDp+dJDKJYwQT70Bt3QGu57HklK6H2SYk7vLc8DHQ0N+8XHGepzU14gkjdX5U9M8mqVs5IIxggkE/T/9dQPluiG/t1HTqCcfj1r5j+JfxQ8ceAP2kNB02x8TaRrMGtaghk8NQ6RtnsNJ2sst89yHLIUkXq4EbtmMLvyw9+8afEfT/COuaVp940/2rXJmgtVSIupKjcSxHCgDnNfO3xM+Hug3X7U15PZeM/HGh+Jtft7Ke+07SvsQiuLe2WRI5JHlt3kWFdrhgHA3zAYDOapUa07ciPSwlCpLpo9jJ+GH/BSzTrHV/Eus/EBNY8JeEZ9WuNL8O399p6pY3K2sjQsRMheQyzSJM4WRFHlxjaW2uSVz3ib9nf4GfE9ZoNdvdT1jRL2/uNSh8NHUJrjT7K7JDTXMUEJJjJM5P3tn79ioG8klT9Vxf8rOmeXOTv7Nn2L42vtS0/w9cSaVb215qAQeRDcTmGORtwBywRyOM/wnOAOM5Gn4C1K8u9KCag9gb6FykyWjs6RnAYKd2DuwQeR/EPWsvx/DqKaJK2li2bUREwtPtG7yRLtO0vjnbnGcVmfA6bWok1aHXZdON8k6yiOAx+eiNGoUzhAF3Eq+0jOUVQTxXr4+bc1Hoj43LKfuOfU9Hdv3fJ4Iryf9r26+yfs/eMmUxhv7EvQu77ufIcjPtXq7jaqjseteQftmeHrrxH+z34wsrIO1zcaZMiBD8zfLkgY9QDXnTdoNHrwbUo27n5sfsxfDvTPDHgG1njWOW9lGZpG+Y55HXk8/hX0d8OLVWGI2A5DHuDXzl+z5rrR6fLEzNJHaKHJwSWUdcZ56Z4Fe3J8UdE+Hmk293fahbwCaLzQrZ3uDg8DjH414dLRnuVOabbPonwhp8awsyhPMwAfb/PFbaqYEyegPrXkHwe/ae8LeNGjis9UsJJJQAvzhS/HGM8mvXoruOeAMj5IwSc8Zr0aclLY4JRcXZkbIJlLkYH0xXPa/ZpJEx5bPXIziukluEgJaR1UDklq81+MH7RHhL4ZWUg1LVrOOfYXEXmBnIHfaOf0pSlFblRi5aI4vx7oORMYUyDj5SP5e/wBa8m0X4vXXwC+OPh3xDY8R3Ey6dqKHI8yB5ADkDuuQwz3Wl8Q/t0aDqOqEQ2c50uQgG5YEDk9emB34zXPfFT7H4zh0e6sZUuILm+t0jOMj5pFXacema4as02nE7YJpWaP1a0HUDPaRscZIA45q+JAP7w/Cuf8ACcuzTohlSegx7VtC4UjO3ivTjK6ueHLdhO+5WGT3603R3gluZoZvlJwVPr2P9Kill3KwxgjmqcYW4vmXglUHUe55rSEOZ2OTE13SjzIy/jH8Brf4o6fZQ3M9xBFYXUd0phWPzCyHIAZ1YpyByhVscAjJNed/Er4X+ELLxLpt54gvo7bXZ40s7C4uLxLa6nKM8u2LG0s21pNyoMMuQV2ivaY72WwOI24P8Lcj9DXy7/wUs+Dd9+0F4U8E22mw3sGpaf4pt2ivrSNpn0lpbe4hS7+XkLFNJA7Z7K3IrqqVa9KN4PY7sszaUpxpRm420Rv/AA2+Hvw8n06313w1e2+rWtzE1vb6hbam15EYlKqYopPMx5atHgKOAVPGc0V822Pw5+Iv7Jv7OVz4M8EeGtX1q40PxW0VmLa1kKT2M1oLiSdMA/J9pkkTvgqQTniiuX+0sT1lL7/+Ae39ZxD2qy+9/wCR+h2t2wuNPkxsDkEKXGVzjv3IzjpzXMfC3TtdtI5jrl1pE87hBtsLR4URgDuUs8jl+Tx0wCa6nUpQylEAZ3HA9PeuW+H2heKNK1y/fV9TtLqwkz9mgjh3Sx8nBMoKBhtAG3YMd3Neli6kb2PjcFBttrRHaM5EYOeo/WsbxXYJdabMrqG3oQy9QQetbMJIQCRg8g+YnFYfjmSSLQrowg+csbGIjrvxx+tcDasz0oNto/MC38IN8J/jF46tLqJ47TTbmQqVj+9EHYqB0IyCoH/66y/BHwK0n4kNeeOvihK8NhcyIbKwmnxDDEM7PlBAJOegHNdP4Oubnxl4g8QXGpxXYvNSiH2gXGWIcMUb5s8g4JGOOaT9qXwTrOq+GNDg0yACx0qRCyI20yDAUgf3flJGe2TivDjr71rn0CqNWizN8Y/D34WWYhu7LR7rQ1lf5LyBJrcMT0bqR24yvavWv2dfHMPgq8j05tfuNYs9QTNo1zL5ki44wp5yDmvK/hX+zXpOmeOr7xWNK1ORbi3eNNJvLo3FvCXUgjdvbKruJX5Vb3qY/Cc+DLGyuWnu31K3uzcw7YhFFbLkZQAFi3bGfSrXNF86M21Ncp9TfEPWpLjwzcgTfZw8ZO/+4Mda+RPGy+EvDl+b2PSJ/GGsvEZZJ7yVmgiQE7nbaDgcHgA8D0r3jxhcz6/8Glnd3eOeLYWJ554PpXnvgD4YW8F9Bd2CXFrfRWps3HnbraeI5zmIggkknOfzrSrq7RJpJLRnB6D+1poWoaOw/sXRdc8ORutteNZ2MsMVqxJCj94pVsFSBnZnHWtb4pfD6DwxG+q+GAh0zUMamLbaVijkjZZFKgdAdpyB68Gut8T/ALMYvvDl1pNsHtrG/nW4njhjVFnZRhd2WLHaM4HTnpWzF8Lv7D8Ji2bzEjgQEQsxcL6ge3tWfLK1pL5mraTuj6U/ZH+PbfF3wxcx3ctu2o6YyLM0a7BIGTIYL2BKv+Ve2xuXjUA9+30FfHH/AAT+sbOw8Varb25RLixtFtLpFwAyrJuif/vhz+tfY1ohKJ1967MPK8EeNiY8lRpCTIcHdwcdaraWUmklkBxuYAE88D/J/Sk169CDykJ8yXgew9ahgRrZAAxCjkc4NephKDcrnzWaY5KSpFjX5pYdNmeBRNIEJVCeZDg4XPPX/PNeKfDL4m+L/HHwKkv73S9Vs/F+nPFLcR/Zyi3vltDLOkW+NFCsGkiC7QcxkBnxvPttuz380cPLs7BTkn1rT8T26abpLJGqqQmwEdQO/wCv+Ndk60acXGUbs9TIMVCMHKUE3dWb6Hydq/jDx9qXjG/v7e01aHwxc3U4tkn0lp7xSIrXZhGkUxxFvtWAVBJUEcUVlWHx3+IHhb43P4T1MeHfGt62lzane2fh+xltZNAPnRLAkssszKwlR5CoYRu3kMwUqDgrOOaxt/CX3I+6p5pKMUo0qaXnG7+8+vLCDK735c1OxEIDDOTycUtsuE/GmOjMo2Ae/wCRrglNyd2fERp8kUhILl5pnTOQozjHIqj4jjM1gylc4XuPz/TNa0VqPOLEc4xkVBqVkFiJw2D+dSdMXqmfmbp+o3XhX4ueKNMvLeRJba6byllBEhhEhAK5+8uefWvb/C32bxZpo81EKDAww5HTg+lef/8ABRrw5f8Aws+PHh7xaIt+kaqv2GaQEgQyYztP+8Mke6N1rqvh5qkGraTAQXikIBQhtrH6MOo/zivNhG0pRPXlLmipRO+0rw7DptoEiVGXGDgYry/9o+2Xw/4fa7CFnkYJEqjlnOcDH4V65oXnSx7JEM6q3JU4cfgODXn37U3iDSdJ8L2l5qEjiy0q5WaXYpLDIYDhec9u/WtKqXIzOnK00J4a8LPr3wTWzk3IRECCnOGIzmsX4IWc013c6TeQmG/sAAS3/LZDkbwe+DjP1FZP7On7T+m/Ebwzq0Fk6K2nMwMbk4jjHAcMyrkfh2rA+A/7U2k+MPiHBamwubbVI3mjubgkeRIFPy7CSS2Rg54xj6VipRtFo2cKiTi0fQkeiNCDuVixFc94uFu9jKM/MV+XjOf8K6v+24dciTyiGDdOQT+hrlPFlssMUxwMKCCB/nGa6ZpcpzwbMD9hW6Gk/HbxgHVV862gZACMnaTnnOcY/nX2fb65blVC+Zyc5PI6Cvhz9j7xDp//AAvbxczzxLOYIIoV8xQ0gy5fA6nBC/THvX1/p2tRS23ykM2OgOMU8Mv3a9TDGW57s1dWu4G1CFo5FDsGQqeMgVZUgnsc81yMmqpqVy77CFG4LuJycEgn25FaOl6sYgqNkKTj1KfSvfoJxpnwmPlzVm4HaeFrHzp2uMZEQwPTPrXOfEH4oaNa+NrXw1PfImqXkTNDblWJkwrMSpxt+6pJGexrtdMt/wCzNDXdw2NzEfnXnPjb4fz+IvGVlrQu/KlsLS5igiMe9RLKY8SkZGdqIVA9JG9TXC3TlJ8+x9dlGHpQhyVnbT8T5UtPhhqPhHxh40GkfFW60+C/8Q3WoXKnwhBcPHcTsZGiaeVWE3lrsQEcqqKvQUV6d8Vf2b/D/iPxtc6vr2sR21veKq/ZcR20UkqgAO7EgSOoyFJ5UOw5BGCtVg8JJJ87XzPqvYZfVSnKs07K61PpNOI1PrzXBfFn4rah8OJtPFh4b1bxAb2fymNopZYFCO3z7QzKW2qqkgIWcbnUZI75f3kQAUDsa8W/aX0xb/VNLhGma9e3V7bXdrHLY3BghstwjLs8m1hGWRWVWZSpyy9WBHFLY+Yp2nJJnt2nzi4iXkEbc5H+cU6Z8oc4woNYXhLVQvhyyLR3ERMKZS4x5sXyj5W9x0PuDWP8SfjNo3w30Ka91a+itIEbYp5Z5WPRERQWdz2VQSaG0ldjs27JHl//AAUD+Ftr8V/2dPE9owjFzaWr6hZyHgxzW4MinODgHaQfYmvir9kL4/2mr6TBomqBlkijQb5MspUnCkt69P513Hxg/ac+IH7anjPVPBfhCxm8K+GLQiHUru9H+kyRnljMBxDHt6RDMkhOGKjIr5KHhW9+CfxgvNB+2BLvTbpPLnQFY7xAd0bryeWA4GevFebiK3v80UerhKL9m4y3P0ustdTQ9IkuobiKSJI+MsGUADpnr/Ovm/4n6pr/AMeI5be00yW3tbtyiSvlVROctngNiuv+F/jK18dfD8Brl4JPL3SGThzg/dYd+g5qn4l+HcXxD06GS71/VtP0Voh/o+iXj2scoxz5rRkOR04zjFKdS68ioRin5nlR/ZEm8KRzxaH4ujtLy5Biu94JUocb1IBz0HB/DFT+H/gx4R8Maq0+jeLrGXVWIA33EaZGBkKCQeaseJfA/wAHPhzZLbalpGn3onkDeQ1rG7SSMTg7yNxJP94963PB0fw48V6Vbtpvh/T4Igg227W8ZjXgHbtC4yOP5VnGKv7p0ud1c734Z61q/hq9tkllivLO4BjlkjkDhOeGB59s4q98bfiBBoNjLHuBmkTcFHU84yPpxmrGg6Tp/hbQmFvBFaKiB/JjACKO20DgCvCP2gfiRaarqSrGzyCGUFnQn91Gwz+hroc3DRnIrLU8m8Q3Ex8TDVBZ6zPFBMZXudNWUS2TYJ3GSMbkGD1PBxivffgD+1b49tYENhrdp4s06EEtb6sohmjQY6XSDGR6PGfQmvMPg18QP7M1bULuH7WqtclUjThZsYUA4/hAJJ9a9Ti+Afhjx1qZ1Sxe/wBD1PVjvmW1lAt5XGQSYj0ywJOCAfStYKy0MZtyV2tD3HwP+2/4buvE8GkeIVvfCWoX2GszqIRLS9c8EQ3IJic5ydpIbttFfQvhK7j1d4F4YLlmJ4yOOuevb86/KbXPj3aeBPiPrHgTx/BbzGOdra5a6jLQ3sBCmOQZ7FCpGehJ9K+pP2Qvi/c/Ba4sbM3c2s/D3VXWPTruUl59IZvuxO5+/ESflJJI9a64Zg0uSR5FXKYyr+0pbbu/6H3smpiTT/ILZKEZI/u9qpXJGSSRjpzWHo+vLfX/AJ2QYpvlB/vD1rJ+O/xBm+Fvwz1fX4LdLttNh83y2LBWG4A52gscA5woySMDkipinUmordnfSoudRQhu3Y+f/wDgot40+HPwrt9B1/xt4Nt/Gl9cSvp9jbPbW9w8MeDJI6rcOqAAiMEj5v3ijpmirHxw160+O/wI8O61d+CfDHie4kvP3una/YJexWEgEqSEJIuUcMmOQGAJB5FFdn9l1W3fS2n3H1GDyxxp8lZ2km07vsz6vsrn7TbRscblGGBPINeQftVaHNrFhoiW+l6hq0320qi2/wBmaG3Bic+bOJ0dPLBAG4KWXdlQx+U+vNZfZZDKJEKMMsAM15x+034X03xZ8L71r/Ur6zsbDF2ZbGcwyPtV127gDwdxGPUgjkCs8VQdPXofD4GupyXc8Q+M37Z0X7PHwt0HQdF0K81rxzd6cf7N0Ge6+aGKCPD3N3PjMcK7RlyAzkhVXdkD4V+Jv7V3jC68S6bLr2sy6z4116/WwtDBA0VnaCVwnlwQjIjjUHByS7EEs7cAbvx70ZP2YvClx4pk12e68S6zt89S6tPlpC0VtGAAAkavhUQBRzwM1Z/ZT/4J2eLb3xnZfFT4qavPorW9wL3TNACBWPO5Rck58vnH7sDd3JGa8KtUqVHaPRn09GlRp03Ob/4J778XL2D4B/BV9F0ueS3mMQ+0aj5W97iZhgyygHOCQfun5RgAYBz8F+Jn1XWfFlys0ry6zZyB4mEnzTL1GCOD1GDxX3F+0uk76YWSeGUSIxRZEyHyCT82BxjNfE2pafcQfEm3jtlhhhffEGkn4Uj5gM9x1/Cs611oGEk+VtdTe8I/FDUdPsNQs5pZFjW3O1ZFO+2kOA2SPXHqe/Fe5fs8/Fm60fw3b2t4RJZsrJEFYtIwGQTg9ec9hgV5trXwitfGugRMZGS8UANNbvgyHtuX+Lj0561ykt1rHwm1OOLUhZJazKWguoySs/IHA4wQB901kmXKMZu56h46+G1l8R/F0lzFcSSWtuyqkY+QqzFsufTGcV0fhL4Z6Z4V0tY7Rr2Mxg7FLkmRCMgZPvk5rzjwT8ZBapb2qJDJeK7PJL5oAK8deP8A9VdjoXxON3pbIxina6G+CXeMjk+3XGRVLcmppGx6b4i+JMUvhSazeVhPFGCpAwVwB9Mfjwa+ejaTeKJJPLZkT5kkl3Y75Cj1NdBqHgzxF4t1tRbxyW1vdoC8k+5EK5XI6fMe/vW5Z+CW8Oi206PymghOUctyx68n1JzVPXc53TbXunknhK9jsvEuuQia8DWt5GfkUgrvClRkHjvx6Zr6G+FHi1dVEEO25aZZA6sp2ggNg5z7Z4rxjxdoC+FPildXDSxhNRijWcGTASSM/IT/AMBOM+1eg/B2SbwwSZVHm3jSG3CyAhYmySfqSPyAqlNju3oew6/4N8PeJvFY1++8NWF9qktqLCWeWGN3MG7cAQwIxhjjjODjOBis7wB4StPg98R7vwlbQyXHhXxZbtPpUQxs0+Uf66Fc9F4Dr/dyRnitfwbqU95bMzRQbYgqt/eAGBngGriaTJrGq2Rt2RLnTbtbu3xJtZtpwy846oWH41tKrzLUmjSabZ9H/A3V7mTwqltOweeyIhLZyW29DmvUtZ0e08U6NLb3sEF3aXke2WGaMSRyqR8ylTwQehry34Z6bJZ6nLlVC3aCQfMCM9D3/rXrGkQt/Z0YIUFflyGBHGff3rqpN2TRwzm4z0OU0z4b6D4K0tLDT9JsLG2UALDb24RAFLEcYx1dvzPrRXQ6vaPcSADGOvDf/WNFXKc27u/3scq1S95PU2rgLHGNx+8vy49K87+NNmbv4c3ihGkEzqHVeu3dya9EKgxqMZIBB+tcB8Y2ks/BGpodpWSNimT0b+eOB+te5jKfNTb7Hy+XVFCurnxTYfs+aL8Tv239V8X6zrEl2PCTxjRdM+xAQ2c4QD7Q+RtZwwOODyAc8V7b8Z/Eo0zwTcGS5hUGPaZA4XCjoAOvPtXBfEzxfqXj74YJ4h0C610a34Xdre903SbqGF523DLnzEcMQvzAEAnJFeKah+254fudNGjeONL8d6bO4BS5uoLW7WFS2MlY9hHTJOOBn0r5a6iml1PtlTlUkp/gdj8QPDFr8Q/BRNpcSIwXerR5C8ex7ZwK+HfjTpV74Y+JGlJKNtzZzyXcqBm+dRgHvnndX2F8OfivoXiO+vLTStSi1K1aM/NGys0ZBwAVDdzk57Yr5m/a8tyP2g9PtZY5ALnTriSByCVkUsg4PfBFclWTSO3DLlm0z0D4ZamrojFVnEq4Ak4JB9/Q8da9j8L/AA/sfEsIHkRMqY/dGMHawH8Sn8ga+W/g14hltNPjtrhRtVgoBGOOnrX1V8JdfjVIMykSLkoytllA9PUVUbXMJxaehq+D/wBlvwhY3TGTw5pi3jjLNJbK+8+qk5H4V09l8KNG8LA28Gk2FsoOEaC1jTr9FyD7A4rvvBmu2erLGlxGnmuMhyAQx/of/wBVbmvLbRRbX8qRWHDHkewx0H411xijBybZ4x4r0EQwgTKhhKKFwoyT25xkV5zr2mrYwOhUlCRkk5Jx6969c8f6p9pEUSlDGFMeOqr0IGO/1rynx3L/AGVZ4Yt8xITjpnqD6/Wuab1djeirnhXxwjWS7ll3YEkYhyDyM4H5jrWz8CfF1v41YRNKRPpqLAyMRktt4ORwQa434x6s9zqEWneW86xv5lwOTtJHA9eBkke4pv7OkUfh74r2xkt7pLfUYzC6tkDfkFc++M4rLn6BKl7t30PqvRLdPDXhVov3nmSZZxg8kfjVLw/rtzc+I4bKCNllnmCIz5ABPtyCMZ/OjxT4ge2sFR2X51JQqdvGMYJ9j1Pf2rG0rxbB4G0W58R3NrcNY6JA11Iox5koOASpbjADDknvwKbk9EXG7Wm59dfDnxAtl4rs9PD48m2V8AYwCfp7V7poEjSWjpubnDD5q/P/APZH+NEvxN+I9zq8zMn20kJHjiJAVCqMdcDvnnNffPgmb7UmFYkiNSM59frXdh5qT06HmYmHLoeeWmieNtF/aG1O5W7nvfDN3p7SLFKpaK2lLQLHGoY+WCAlw2UUEiX5jwtFe8/YEtrGPEcLP/00Hy/56UV7sMxcYqPIj0qWcuEVH2UXbyRmzExTuN235j9etch8U7X7Z4VvFHJ8s/niuvnmWSUvnO4bie3PNYXjGDzNHnHZlwfp/k16dk4fI/NbuNbToz8nPiZ+03dfsl/tVwajc+fN4c1mQW+qwx/NsjJ4lC8/MnX3GR6V9EeJvhX4O+OnhYXenvDPa3kXmw3FtcbmQdmjPOEYHBPbOK+Tf+Cl/gSWw+JFxdtaNJbiRX3oI9wXPIyV3ZxnoR19q3/+CY/j65034ewXO/T9RFnGdMuY4ZC2o6XDGSseYjgeWy/NkevTIzXxM/cqukz9JpqM8PGrDexc8Y/s/an8O/FMmu6Ss9ykTFpDbxPIWGD8skSclueHUZ55HWrvxj8F6Z8XvhrY39tbS/23pzF7RfKbzuARJE2PujgdeAVr6I8RfC+y+KWm3epaNNHo+qzOPLuoQxFwRjmVBgfiOT3riB8E9ZvtTtYNXCR3UAbFxHaIUlb3QkoRyOcbuTz2qZUnYdOpprufIvhjSp0u5CEkTzn+YkHIbH5fh1r1L4U+MH0K4NneOzKOdpGOemc159+1XpXiz9nD4wWuoQ2v9peGteJmWJj/AMedyuPNRHAztIxIobgeYRjipx8TbbxxBHfppl5YXsfLEoDG6465AH58Vi3qbKNlzdD6i0n4qx6NHHFcMAkpzuPTA9ew+tdN/wALZWWyGZnkhk+TIXe0Q96+e/DPirTdb0y3kedtrK26NoGJx2GcfrTdI8T/ANia/c3VnYX9zgCM70cb1A4VeQOvetVNoyXK9Ue4ajqrO0iDgyuCrMeFx/jXmHxq+JC+F/D8ZEyG6WMtawgqwbB6sOo69e9Pu/F+s+INNb+zdKaxeVcFpFDtH/u54rjbn4Dajr2oNc3cVzcTtw8pJLsOxJJx+nesamrFHR36HnS31vPdxP58ZjvRNPKznbsaTHU5zwVwPY1mappv9pSW1vZC3kvpb2F7XaxKxODyQTg8AZ717Tafsx3ETBvskoJ+XdtAxkdcgZrq/g/+yzJe/Eayke0As7V2ediMGVdpG33BJ7nFJU9dAmk1c2fDGnL8T5oYbi8kewtATMqKHlkywwNoORk/pXlf7TiTeOvEtp4Y02/az0eyvEF+8ShfMjRQQVG7lIWcKQcZY5PQV9O+OPhdcfDzw3NbaHZxPJOdkXmRLIkbHH7xgRjC/wAPB5ryWD9mrxRNdx3EzTfKsiEhclFk5cYG0ckZ6cU5xdrNDpKN00zO/ZO0BfAnjmG1gaZirsHMksch4OM/IcDJHTrxX6d/CK3N7ZRyZGNq9Pr/APqr46+Bn7PuqaVfwTzr57KchdpXHuMde/WvuP4V6SdL8NQ7xk4znqR7evrXTgk1e5xYtK6s7mj4ku0geOIbm/iIXjFFVry7ZrhnmlSGFjhGHLHH14or0zl5JdjI+HWpDxT8NfDOpOG3ajo1jdHd1/eW0bc475ParWuaWJLGdSe3HtRRXtUZP2S9D5bGxSru3d/mfGH7X/7N9n44ubh52gHm85KZIr5L0D9j9/h/4qXU9A1g6ZqSPzcRF1MiAklWAxuHHQ8Giivn8fTi6jdj6bK6s1SSTPpv4UQG/u9Mg1TYuqbiPtVqPkn2MeXQkYJ2/wAJ719NR/D+11CDE0cLEYLKV3Ke5xnpRRWVFKxriJtPc8++Pf7NOi/E3TbXSrqGEG3nM4kZdxXAI446nmvOfDH7Cmh2dzJa7oXtgc8rln46HjgfSiiuvD0oOpqjhxVepGkkmdjoH7GWiaaWMAgEfXa6Z746V0Fn+y9pFjwLa0ZWGRnPHb0oor154Oi9XE8J46uoNKTNHSf2cdK02SRpkgliBI2BMbPoa6fTf2dtHSAGBQqsMhWXt9aKK4cVh6cZJJHdlmKqzheUi4nwI06GNozFAwzjkZ/pV/Rfg/ZWBBihgUMMDk5/lRRXE6cVsj14VZtpNll/hlb3EgV1h9Omeg6Uy3+GVnuER2lM7SNuBxRRVckXfQvnd7XOj0Twxa6aFSGGONV44HNdTdwm1094YwqkrtXsPxooojFJaGcG+doxV09bdA/mP8/aiiiqPRhsf//Z">

This code will result in this:
Kristofer Källsbo aka Hackviking

I put together a JSFiddle with some example code for converting images to base 64 encoded data url's using HTML5 components and plain javascript: