Starbeamrainbowlabs

Stardust
Blog


Archive


Mailing List Articles Atom Feed Comments Atom Feed Twitter Reddit Facebook

Tag Cloud

3d 3d printing account algorithms android announcement architecture archives arduino artificial intelligence artix assembly async audio automation backups bash batch blender blog bookmarklet booting bug hunting c sharp c++ challenge chrome os cluster code codepen coding conundrums coding conundrums evolved command line compilers compiling compression conference conferences containerisation css dailyprogrammer data analysis debugging defining ai demystification distributed computing dns docker documentation downtime electronics email embedded systems encryption es6 features ethics event experiment external first impressions freeside future game github github gist gitlab graphics guide hardware hardware meetup holiday holidays html html5 html5 canvas infrastructure interfaces internet interoperability io.js jabber jam javascript js bin labs latex learning library linux lora low level lua maintenance manjaro minetest network networking nibriboard node.js open source operating systems optimisation outreach own your code pepperminty wiki performance phd photos php pixelbot portable privacy problem solving programming problems project projects prolog protocol protocols pseudo 3d python reddit redis reference release releases rendering research resource review rust searching secrets security series list server software sorting source code control statistics storage svg systemquery talks technical terminal textures thoughts three thing game three.js tool tutorial twitter ubuntu university update updates upgrade version control virtual reality virtualisation visual web website windows windows 10 worldeditadditions xmpp xslt

Dailyprogammer Challenge #199 - Bank Numbers Pt 1

I have attempted another dailyprogammer challenge on reddit.

This time, the challenge is to take a number in and print a 'banner' representing that number, like this:

Input: 47262

Output:
    _  _  _  _
|_|  | _||_  _|
  |  ||_ |_||_

Here is my solution:

using System;

public class BigDigits
{
    static string[,] bannerTemplates = new string[,]{
        { " _ ", "| |", "|_|" },
        { "   ", "  |", "  |" },
        { " _ ", " _|", "|_ " },
        { " _ ", " _|", " _|" },
        { "   ", "|_|", "  |" },
        { " _ ", "|_ ", " _|" },
        { " _ ", "|_ ", "|_|" },
        { " _ ", "  |", "  |" },
        { " _ ", "|_|", "|_|" },
        { " _ ", "|_|", " _|" }
    };

    static void Main(string[] args)
    {
        if (args.Length == 0)
        {
            Console.WriteLine("This program converts a number to a banner.");
            Console.WriteLine("\nUse it like this: ");
            Console.WriteLine("    bigintbanners.exe <number>");
            Console.WriteLine("\n<number>: The number you want to convert.");
            return;
        }

        char[] intChars = args[0].ToCharArray();
        string[] resultLines = new string[3];
        int currentDigit = 0;

        int i = 0;

        for(i = 0; i < intChars.Length; i++)
        {
            currentDigit = int.Parse(intChars[i].ToString());
            for (int j = 0; j < 3; j++)
            {
                resultLines[j] += bannerTemplates[currentDigit,j];
            }
        }

        for(i = 0; i < resultLines.Length; i++)
        {
            Console.WriteLine(resultLines[i]);
        }
    }
}

I find the dailyprogrammer challenges to be a great way to practice a language that you are learning.

32 bit binary, SHA1: 0fc2483dacf151b162e22b3f9b4c5c64e6fe5bdf

Reddit post link

Ask below if you need a different binary (e.g. 64 bit, ARM, etc)

Finding Favicons with PHP

There hasn't been a post here for a little while because I have been ill. I am back now though :)

While writing more Bloworm, I needed a function that would automatically detect the url of the favicon that is associated with a given url. I wrote a quick function to do this a while ago - and have been improving it little by little.

I now have it at a point where it finds the correct url 99% of the time, so I thought that I would share it with you.

/*
 * @summary Given a url, this function will attempt to find it's correspending favicon.
 *
 * @returns The url of the corresponding favicon.
 */
function auto_find_favicon_url($url)
{
    if(!validate_url($url))
        senderror(new api_error(400, 520, "The url you specified for the favicon was invalid."));

    // todo protect against downloading large files
    // todo send HEAD request instead of GET request
    try {
        $headers = get_headers($url, true);
    } catch (Exception $e) {
        senderror(new api_error(502, 710, "Failed to fetch the headers from url: $url"));
    }
    $headers = array_change_key_case($headers);

    $urlparts = [];
    preg_match("/^([a-z]+)\:(?:\/\/)?([^\/?#]+)(.*)/i", $url, $urlparts);

    $content_type = $headers["content-type"];
    if(!is_string($content_type)) // account for arrays of content types
        $content_type = $content_type[0];

    $faviconurl = "images/favicon-default.png";
    if(strpos($content_type, "text/html") !== false)
    {
        try {
            $html = file_get_contents($url);
        } catch (Exception $e) {
            senderror(new api_error(502, 711, "Failed to fetch url: $url"));
        }
        $matches = [];
        if(preg_match("/rel=\"shortcut(?: icon)?\" (?:href=[\'\"]([^\'\"]+)[\'\"])/i", $html, $matches) === 1)
        {
            $faviconurl = $matches[1];
            // make sure that the favicon url is absolute
            if(preg_match("/^[a-z]+\:(?:\/\/)?/i", $faviconurl) === 0)
            {
                // the url is not absolute, make it absolute
                $basepath = dirname($urlparts[3]);

                // the path should not include the basepath if the favicon url begins with a slash
                if(substr($faviconurl, 0, 1) === "/")
                {
                    $faviconurl = "$urlparts[1]://$urlparts[2]$faviconurl";
                }
                else
                {
                    $faviconurl = "$urlparts[1]://$urlparts[2]$basepath/$faviconurl";
                }
            }
        }
    }

    if($faviconurl == "images/favicon-default.png")
    {
        // we have not found the url of the favicon yet, parse the url
        // todo guard against invalid urls

        $faviconurl = "$urlparts[1]://$urlparts[2]/favicon.ico";
        $faviconurl = follow_redirects($faviconurl);
        $favheaders = get_headers($faviconurl, true);
        $favheaders = array_change_key_case($favheaders);

        if(preg_match("/2\d{3}/i", $favheaders[0]) === 0)
            return $faviconurl;
    }

    return $faviconurl;
}

This code is pulled directly from the Bloworm source code - so you will need to edit it slightly to suit your needs. It is not perfect, and will probably will be updated from time to time.

Following Redirects in PHP

Recently I have found that PHP sometimes doesn't follow redirects (e.g. the get_headers() function). So I wrote this quick function to follow a url's redirects to a certain depth:

/*
 * @summary Follows a chain of redirects and returns that last url in the sequence.
 * 
 * @param $url - The url to start at.
 * @param $maxdepth - The maximum depth to which to travel following redirects.
 * 
 * @returns The url at the end of the redirect chain.
 */
function follow_redirects($url, $maxdepth = 10, $depth = 0)
{
    //return the current url if we have hit the maximum depth
    if($depth >= $maxdepth)
        return $url;

    //download the headers from the url and make all the keys lowercase
    $headers = get_headers($url, true);
    $headers = array_change_key_case($headers);
    //we have a redirect if the `location` header is set
    if(isset($headers["location"]))
    {
        return follow_redirects($headers["location"], $maxdepth, $depth + 1);
    }
    else
    {
        return $url;
    }
}

For example, you could do this:

follow_redirects("https://example.com/some/path", 5);

That would follow the redirects, starting at https://example.com/some/path, to a maximum depth of 5 urls.

When I learn networking in C♯ (and if it doesn't follow redirects), I will rewrite this function in C♯ for you.

Generating Session Tokens with PHP

Recently I needed to generate random strings to hex to act as a session token for Blow Worm. Using session tokens mean that you send the login credentials once, and then the server hands out a session token for use instead of the password for the rest of that session. In theory this is more secure than sending the password to the server every time.

The problem with generating random session tokens is that you need a secure random number generator, so that hackers can't attempt to guess the random numbers and hence guess the session tokens (that would be bad).

The way I did it (please leave a comment below if this is insecure!) is as follows:

  1. Generate ~128 bits of randomness using the OpenSSL function openssl_random_pseudo_bytes(). This randomness generator is apparently better than rand() and mt_rand().
  2. Hash that resulting randomness with SHA256 to ensure a constant session key length.

The PHP code I am currently using is as follows:

$sessionkey = hash("sha256", openssl_random_pseudo_bytes($session_key_length));

I thought that I would share this here since it took me a little while to look up how to do this. If anyone has a better way of doing this, I will gladly take suggestions and give full credit.

Easy C♯ Menus

I have written some easy to use C♯ menus, and I thought that I would post about them here.

There are currently 2 different methods (and 2 extra helper methods). Both methods also centre the dialog box in the middle of the console, and also don't produce much mess that needs cleaning up afterwards.

Firstly, here are the two helper methods:

//from https://stackoverflow.com/questions/17590528/pad-left-pad-right-pad-center-string
///<summary>
///Cool function from stackoverflow that pads a string on both sides to make it a given legnth.
///</summary>
///<param name="source">The source string to pad.</param>
///<param name="length">The desired length.</param>
///<returns>The padded string.</returns>
static string PadBoth(string source, int length)
{
    int spaces = length - source.Length;
    int padLeft = spaces/2 + source.Length;
    return source.PadLeft(padLeft).PadRight(length);
}

//utility function that uses the above to pad a string to the current width of the console.
static string PadToWindowWidth(string str)
{
    return PadBoth(str, Console.WindowWidth - 1);
}

These need to be included in addition to either (or both!) of the methods described below.

A screenshot of the first menu type. The first one is a flexible multiple choice selection window. You can pass in an array of string sthat you want the user to choose from, and the method will deal with the rest, returning the index in the array of the item that the user chose.

This method comes with support for an optional prompt to display at the top of the dialog box. If you omit it, the prompt will not be displayed.

Source code:

///<summary>
///Displays a nice multiple choice menu that the user can intract with using the arrow keys.
///</summary>
///<param name="options">An array of strings that should be used as the possible options in the menu.</param>
///<returns>The index of the option the user chose.</returns>
static int DisplayMenu(string[] options, string prompt = "")
{
    int cursorstartx = Console.CursorLeft,
        cursorstarty = Console.CursorTop,

        menuWidth = (int)(Console.WindowWidth * 0.8),
        menuHeight = 2 + (options.Length * 2) + 1;

    if(prompt.Length > 0)
        menuHeight += 2;

    int currentIndex = 0;

    string menu = "";

    while(true)
    {
        Console.SetCursorPosition(cursorstartx, cursorstarty);

        menu = "";
        menu += new String('\n', ((Console.WindowHeight - 1) - menuHeight) / 2);
        menu += PadToWindowWidth("".PadLeft(menuWidth, '-')) + "\n";

        if(prompt.Length > 0)
        {
            menu += PadToWindowWidth("| " + PadBoth(prompt, menuWidth - 4) + " |") + "\n";
            menu += PadToWindowWidth("".PadLeft(menuWidth, '-')) + "\n";
        }

        menu += PadToWindowWidth("|" + "".PadLeft(menuWidth - 2) + "|") + "\n";

        for(int i = 0; i < options.Length; i++)
        {
            if(currentIndex == i)
            {
                menu += PadToWindowWidth("|" + PadBoth("> " + options[i] + " <", menuWidth - 2) + "|") + "\n";
            }
            else
            {
                menu += PadToWindowWidth("|" + PadBoth(options[i], menuWidth - 2) + "|") + "\n";
            }
            menu += PadToWindowWidth("|" + "".PadLeft(menuWidth - 2) + "|") + "\n";
        }
        menu += PadToWindowWidth("".PadLeft(menuWidth, '-'));
        menu += new String('\n', ((Console.WindowHeight - 1) - menuHeight) / 2);

        Console.WriteLine(menu);

        ConsoleKeyInfo nextkey = Console.ReadKey(true);

        switch(nextkey.Key.ToString())
        {
            case "UpArrow":
                currentIndex--;
                break;

            case "DownArrow":
                currentIndex++;
                break;

            case "Enter":
                return currentIndex;
        }

        if(currentIndex < 0)
            currentIndex = options.Length - 1;
        if(currentIndex > options.Length - 1)
            currentIndex = 0;
    }
}

Confirm Dialog

A screenshot of the second menu type.

In case you want to obtain an answer to a simple yes/no question, this second method allows you to ask the user to choose between 2 choices. Simply specify a prompt, and optionally the text to display in the place of the "Yes" / "No", and the method will return true or false, depending on which one the user selected.

Source code:

///<summary>
///Asks the user a simple yes/no question in the form of a console based dialog box.
///</summary>
///<param name="prompt">The question to ask the user.</param>
///<param name="trueText">The text to display in the place of "Yes"</param>
///<param name="falseText">The text to display in the place of "No"</param>
///<returns>True if the user selected "Yes", or false if the user selected "No".</returns>
static bool DisplayConfirm(string prompt, string trueText = "Yes", string falseText = "No")
{
    int cursorstartx = Console.CursorLeft,
        cursorstarty = Console.CursorTop,

        menuWidth = (int)(Console.WindowWidth * 0.8),
        menuHeight = 7,

        currentIndex = 1;

    string menu = "";

    while(true)
    {
        Console.SetCursorPosition(cursorstartx, cursorstarty);

        menu = "";
        menu += new String('\n', ((Console.WindowHeight - 1) - menuHeight) / 2); //vertical centring

        menu += PadToWindowWidth("".PadLeft(menuWidth, '-')) + "\n"; //dashes
        menu += PadToWindowWidth("|" + "".PadLeft(menuWidth - 2) + "|") + "\n"; //space

        menu += PadToWindowWidth("|" + PadBoth(prompt, menuWidth - 2) + "|") + "\n"; //prompt
        menu += PadToWindowWidth("|" + "".PadLeft(menuWidth - 2) + "|") + "\n"; //space
        menu += PadToWindowWidth("".PadLeft(menuWidth, '-')) + "\n"; //dashes

        if(currentIndex == 0)
            menu += PadToWindowWidth("|" + PadBoth(trueText, (menuWidth - 3) / 2) + "|" + PadBoth("> " + falseText + " <", (menuWidth - 3) / 2) + "|") + "\n";
        else
            menu += PadToWindowWidth("|" + PadBoth("> " + trueText + " <", (menuWidth - 3) / 2) + "|" + PadBoth(falseText, (menuWidth - 3) / 2) + "|") + "\n";

        menu += PadToWindowWidth("".PadLeft(menuWidth, '-')) + "\n"; //dashes

        menu += new String('\n', ((Console.WindowHeight - 1) - menuHeight) / 2); //vertical centring

        Console.WriteLine(menu);

        ConsoleKeyInfo nextkey = Console.ReadKey(true);

        switch(nextkey.Key.ToString())
        {
            case "LeftArrow":
            case "UpArrow":
                currentIndex--;
                break;

            case "RightArrow":
            case "DownArrow":
                currentIndex++;
                break;

            case "Enter":
                if(currentIndex == 0)
                    return true;
                else
                    return false;
        }

        if(currentIndex < 0)
            currentIndex = 1;
        if(currentIndex > 1)
            currentIndex = 0;
    }
}

I will probably write a few more of these in the future, and make these current ones better.

Demonstration binaries are available upon request, simply leave a comment below.

Sorting: Selection Sort

Since I seem to be doing quite a few sorting algorithsms in my lectures at the moment, it would appear that I will be doing a series of sorting algorithm posts.

Today I did not have all that much time, so I wrote this one in javascript. I present to you: The selection sort.

The selection sort is a sorting algorithm where the smallest number is found and swapped with the number at the beginning, then the next smallest is swaped with the one next to the smallest number, and so on until the whoel sequence has been sorted.

Wikipedia has a rather nice animated GIF that explains the selection sort well here.

My implementation could be made faster be doing it in reverse, but I didn't have time to reverse it at the time of writing this post (check the comments to see if I did it later).

function selectionsort(arr)
{
    var maxid = 0, temp;
    for(var nextid = 0; nextid < arr.length - 1; nextid++)
    {
        //find the next smallest number remaining
        maxid = nextid;
        for(var j = nextid; j < arr.length; j++)
        {
            /*
            Invert to |
            sort desc.V */
            if(arr[j] < arr[maxid])
                maxid = j;
        }
        //swap the next number into place
        arr[nextid] = arr.splice(maxid, 1, arr[nextid])[0];

        console.log("nextid:", nextid, "state:", arr);
    }

    return arr; //for chaining
}

Here is a minified version (146 chars including newlines):

function selectionsort(e){for(var t=0,n=0;n<e.length-1;n++){t=n
for(var l=n;l<e.length;l++)e[l]<e[t]&&(t=l)
e[n]=e.splice(t,1,e[n])[0]}return e}

This was minified with UglifyJS.

Sample Output:

original [ 75, 4, 32, 87, 69, 73, 10, 18, 48, 2, 48, 96, 75, 36, 26 ]
nextid: 0 state: [ 2, 4, 32, 87, 69, 73, 10, 18, 48, 75, 48, 96, 75, 36, 26 ]
nextid: 1 state: [ 2, 4, 32, 87, 69, 73, 10, 18, 48, 75, 48, 96, 75, 36, 26 ]
nextid: 2 state: [ 2, 4, 10, 87, 69, 73, 32, 18, 48, 75, 48, 96, 75, 36, 26 ]
nextid: 3 state: [ 2, 4, 10, 18, 69, 73, 32, 87, 48, 75, 48, 96, 75, 36, 26 ]
nextid: 4 state: [ 2, 4, 10, 18, 26, 73, 32, 87, 48, 75, 48, 96, 75, 36, 69 ]
nextid: 5 state: [ 2, 4, 10, 18, 26, 32, 73, 87, 48, 75, 48, 96, 75, 36, 69 ]
nextid: 6 state: [ 2, 4, 10, 18, 26, 32, 36, 87, 48, 75, 48, 96, 75, 73, 69 ]
nextid: 7 state: [ 2, 4, 10, 18, 26, 32, 36, 48, 87, 75, 48, 96, 75, 73, 69 ]
nextid: 8 state: [ 2, 4, 10, 18, 26, 32, 36, 48, 48, 75, 87, 96, 75, 73, 69 ]
nextid: 9 state: [ 2, 4, 10, 18, 26, 32, 36, 48, 48, 69, 87, 96, 75, 73, 75 ]
nextid: 10 state: [ 2, 4, 10, 18, 26, 32, 36, 48, 48, 69, 73, 96, 75, 87, 75 ]
nextid: 11 state: [ 2, 4, 10, 18, 26, 32, 36, 48, 48, 69, 73, 75, 96, 87, 75 ]
nextid: 12 state: [ 2, 4, 10, 18, 26, 32, 36, 48, 48, 69, 73, 75, 75, 87, 96 ]
nextid: 13 state: [ 2, 4, 10, 18, 26, 32, 36, 48, 48, 69, 73, 75, 75, 87, 96 ]
result [ 2, 4, 10, 18, 26, 32, 36, 48, 48, 69, 73, 75, 75, 87, 96 ]

At some point I may port this to C♯.

(Probably) Coming Soon: (Binary) Insertion sort, Merge Sort, Quick Sort.

Security update to atom.gen.php

Since this website gets a lot of spam (ongoing investigations are currently in force in order to analyse the spambots' patterns, a post will be made here when they have been stopped) and this website also has a comments feed powered by atom.gen.php, I have had a chance to test atom.gen.php out in the wild with real data.

I discovered, unfortunately, that the script didn't handle invalid utf-8 and non printable characters very well, and this lead to the feed getting broken because XML doesn't like certain specific characters. This has now been fixed.

If you handle user input and use atom.gen.php to turn it into a feed, you will want to grab an updated copy of the script (quick link here) and overwrite your previous copy in order to fix this.

As well as fixing that, I also added a new option, $usecdata. This controls whether the <content> tag's contents should be wrapped in <![CDATA[...]]>. This should add extra protection again html / javascript injection attacks breaking your feeds. It defaults to false, though, so you need to manually enable it by setting it to true.

The reference has been updated accordingly.

If you find another bug, please comment below. You will recieve full credit at the top of the file (especially if you provide a fix!).

Three Thing Game!

This is just a quick post to announce that I will be taking part in Hull University's Three Thing Game!

Three Thing Game is a game jam where you get virtual cash to buy 3 'things' at the auction of things, and then you make a game in 24 hours that includes those three things. It is organised by Rob Miles.

In other news I have been rather busy over the last few weeks, so there wasn't a post last Wednesday. It should be up sometime soon.

A Simpler Way to Generate XML in PHP

In an effort to make XML generation simpler in PHP, I have written another PHP class, called simpexmlwriter.

Much like atom.gen.php, everything you need is all packaged up into one file - simply download and require simplexmlwriter.php and you are ready to start. Links can be found near the bottom of this post.

The same system is in place for contributions and feature requests: post a comment below to either request a feature or link to a modified version of the code and I will consider either merging your changes or adding the feature that you request.

It also has a 'reference' - just like atom.gen.php. A link can be found near the bottom of this post.

If you are still reading this and you are not interested in code, there will be a few things that you may be interesting in appearing on this website soon.

simplexmlwriter.php

simplexmlwriter.php reference

Generating Atom Feeds

Edit 11th May 2020: Since I made this post, I've discovered about a much better and safer way to generate XML. I suggest reading this newer post instead: Generating Atom Feeds. I'm leaving this post otherwise intact for historical interest.


This week I am releasing atom.gen.php, the PHP script that powers this blog's Atom feed (which you can find here!).

This PHP class has been designed to be simple and easy to use (apart from the addentry() function which needs tidying up :D), and quick to get started with. I have also created a basic example showing you how to use it and a 'reference' that covers all of the functions and properties that are available for use. Links to both the script and the 'reference' can be found at the bottom of this post.

Although I have tested it, it is entirely possible that you will come across a bug. If you do, please post about in the comments below.

You may also find that atom.gen.php does not do everything that you want it to. In this case, you have two options: either post a comment down below and I will consider adding the feature you request, or adding the feature yourself. If you add the feature or fix a bug yourself, please post a comment down below along with a link to the modified code and I will merge your changes and give you full credit for all the work you have done.

atom.gen.php

atom.gen.php reference

Art by Mythdael