Thursday 24 October 2013

BlueStacks Android Emulator

Android Emulation

My new TV has an android and iOS App as an alternative to the old fashioned remote control. I sometimes use this on my iphone or ipad, but because the App can also be used to stream what's on the TV, I want to run it on my Laptop too.

When I started looking into this I discovered you could run an Android disk image in a VM such as VirtualBox. But I carried on looking for a hassle free way and eventually found an emulator called BlueStacks App Player. The best thing is that it's available for both Windows (XP, Vista, Win7/8) and Mac OSX (which is still in Beta right now) and it's FREE.

Installing BlueStacks

After downloading the install went easily, but it took some time to start up. So go and make yourself a cup of tea or something, you've got something like a 5 minute wait.
BlueStacks Loading Screen - Takes A While

Once initialised you come to a My App screen where you'll see there's a few popular apps preloaded. But click on the Top Charts icon to start adding new ones.

If you're running a laptop with a standard trackpad then you can scroll up and down through the lists quite easily, but you might have problems if you use a mouse. I struggled a bit with my aging Mighty Mouse because the little scroll ball doesn't work very well anymore.

(I couldn't find any other way of page scrolling)


The Charts Screen - Lets Add Some Apps

Click on the search icon (the blue magnifying glass) you'll find all of the apps that you could ever want (and loads more besides). Sadly my TV app refused to install but I did find that most of the popular games I tried worked fine.

As soon as you make a selection BlueStacks will take you through the login or registration process. I then turned off the automatic account syncing because I don't have any other Android devices (although it listed my old phone in the Google account details as a registered device).


Angry Birds - The Defacto Test

Generally it works great (even if my TV app was a no-go) so I went on to install it on the kid's Mac Mini. I left them playing "Cut The Rope" as most things run ok with a mouse, and then half an hour later I noticed they'd installed and were playing other games.

It's that easy to use, it's kid's play!

I hope this has been some use to those who want to run a android apps on their laptop or desktop computer. It's easy to do and completely free, so don't waste any more time, lets get those green piggies.

Monday 14 October 2013

Minecraft Server Log Web Interface

Introduction

If you run a Minecraft server in Linux then you'll probably like to keep track of what's going on in the server log. I found that it was a real pain having to remote shell into the server all the time and if it was available via a web browser I could keep track of it more conveniently, or by using my phone or tablet.

I decided that I would use PHP (even though PERL is generally my scripting weapon of choice) and once I'd found the correct commands and syntax it came together quite quickly. If you fancy giving it a try you just need a web server (such as Apache) and of course PHP running on your server.

How it works

It started out being a simple process of opening the server.log file and outputting each line as pre-formatted html.

Something like this..

<html>
<head><title>Minecraft Log</title></head>
<body><pre>
<?php
$filepath = "/opt/minecraft/server.log";
$file = file($filepath);
foreach($file as $line) {
    echo $line."<br/>\n";
}
?>
</pre></body>
</html>

This was great at first, but after we'd been running for a few weeks the server.log file gets too big and the web page gets slower and slower to load. What we needed was a way of only showing the current days log entries, and maybe a date selector so you can reference older stuff.

So I created version two with the following enhancements:-
  • Default to showing today's log entries.
  • A date selector is added to the top of the web page which sends the new value if altered.
  • If page requested with a date parameter then use this instead of today's date.
  • If no date has been passed then run a javascript function to scroll the log section to the bottom.
There's a nice feature in the log where text is coloured. This would typically be for chat or system warnings, but as it stood they left messy control codes littered about the log. Rather than remove these I decided to replace them and style the text to match these colours.

This enhancement required the following:-
  • Create a series of regular expression replaces to match the control codes.
  • Each colour code instance is replaced by a span tag which corresponds to a set of pre-defined styles (the css for these is defined in the head section).
  • Put log into a scrollable div.
Here's the completed code..

<!DOCTYPE html>
<html>
<head>
<title>Minecraft Log</title>
<style>
    #log{
        height:400px;
        overflow-y: scroll;
        margin: 5px 0 0 1px;
        border: 1px solid;
    }
    .green{color: green;}
    .red{color: red;}
    .purple{color: purple;}
    .black{color: black;}
    .blue{color: darkblue;}
    .gold{color: gold;}
    .cyan{color: darkcyan;}
    .aqua{color: cadetblue;}
    .gray{color: #888;}
    .bold{ font-weight:bold;}
</style>
<script>
    function scroll(){
    //scroll div to bottom
    var objDiv = document.getElementById("log");
    objDiv.scrollTop = objDiv.scrollHeight;
    }
</script>
</head>
<?php
$pass = htmlspecialchars($_POST["date"]);
if (!$pass){
    echo "<body onLoad='scroll()'>";
}
else {
    echo "<body>";
}

$filepath = "/opt/minecraft/server.log";
$file = file($filepath);
$dates = array();
$last = "";


/* Get List Of Dates */
foreach($file as $line) {
    $date = substr($line, 0, 10);
    if ($date != $last){
        if(preg_match('/\d{4}\-\d{2}\-\d{2}/',$date)) {
            array_push($dates, substr($line, 0, 10));
            $last = $date;
        }
    }
}

/* If Date Provided Use This */
if(preg_match('/\d{4}\-\d{2}\-\d{2}/',$pass)) {
    $last = $pass;
}

/* Add Form Element and Date Selector */
echo "<form method='post'>Select date: <select name='date' onchange='this.form.submit()'>\n";
foreach($dates as $value){
    $select = "";
    if ($value == $last){ $select = " selected='selected'"; }
    echo "<option value='".$value."'".$select.">".$value."</option>\n";
}
echo "</select></form>\n";

/* Output Log For Required Date */
echo "<div id='log'>";
foreach($file as $line) {
    /* Remap Problem Characters */
    $line = preg_replace("/</","&lt;",$line);
    $line = preg_replace("/>/","</span>&gt;",$line);
    $date = substr($line, 0, 10);
    if ($date == $last) {
        /* Remove Unrequired Formatting Codes */
        $line = str_replace("[m","",$line);
        $line = str_replace("[21m","",$line);
        $line = str_replace("[3m","",$line);
        /* Split Log Line Into Sections to Using First Formatting Code Style */
        $segarray = preg_split( '/(\[0|\[m)/', $line );
        for ($i = 1; $i < count($segarray); ++$i){
            /* Do Replace to Add Styled Spans */
            if (preg_match('/;\d{2};\d+m/', $segarray[$i])) {
                $segarray[$i] = preg_replace("/;30/","<span class='black",$segarray[$i]);
                $segarray[$i] = preg_replace("/;31/","<span class='red",$segarray[$i]);
                $segarray[$i] = preg_replace("/;32/","<span class='green",$segarray[$i]);
                $segarray[$i] = preg_replace("/;33/","<span class='gold",$segarray[$i]);
                $segarray[$i] = preg_replace("/;34/","<span class='blue",$segarray[$i]);
            $segarray[$i] = preg_replace("/;35/","<span class='purple",$segarray[$i]);
                $segarray[$i] = preg_replace("/;36/","<span class='aqua",$segarray[$i]);
                $segarray[$i] = preg_replace("/;37/","<span class='gray",$segarray[$i]);
                $segarray[$i] = preg_replace("/;22m/","'>",$segarray[$i]);
                $segarray[$i] = preg_replace("/;1m/"," bold'>",$segarray[$i]);
                $segarray[$i] = $segarray[$i]."</span>";
            }
        }
        /* Rejoin Then Split Log Line Using Second Formatting Code Style */
        $line = join("",$segarray);
        $segarray = preg_split( '/§/', $line );
        for ($i = 1; $i < count($segarray); ++$i){
            /* Do Replace to Add Styled Spans */
            $segarray[$i] = preg_replace("/^0/","<span class='black'>",$segarray[$i]);
            $segarray[$i] = preg_replace("/^1/","<span class='blue'>",$segarray[$i]);
            $segarray[$i] = preg_replace("/^2/","<span class='green'>",$segarray[$i]);
            $segarray[$i] = preg_replace("/^3/","<span class='aqua'>",$segarray[$i]);
            $segarray[$i] = preg_replace("/^4/","<span class='red'>",$segarray[$i]);
            $segarray[$i] = preg_replace("/^5/","<span class='purple'>",$segarray[$i]);
            $segarray[$i] = preg_replace("/^6/","<span class='gold'>",$segarray[$i]);
            $segarray[$i] = preg_replace("/^7/","<span class='gray'>",$segarray[$i]);
            $segarray[$i] = preg_replace("/^8/","<span class='gray'>",$segarray[$i]);
            $segarray[$i] = preg_replace("/^9/","<span class='blue'>",$segarray[$i]);
            $segarray[$i] = preg_replace("/^a/","<span class='green'>",$segarray[$i]);
            $segarray[$i] = preg_replace("/^b/","<span class='aqua'>",$segarray[$i]);
            $segarray[$i] = preg_replace("/^c/","<span class='red'>",$segarray[$i]);
            $segarray[$i] = preg_replace("/^d/","<span class='purple'>",$segarray[$i]);
            $segarray[$i] = preg_replace("/^e/","<span class='gold'>",$segarray[$i]);
            $segarray[$i] = preg_replace("/^f/","<span class='black'>",$segarray[$i]);
            $segarray[$i] = preg_replace("/^r/","<span class='black'>",$segarray[$i]);
            $segarray[$i] = $segarray[$i]."</span>";
        }
        /* Rejoin and Output to Webpage */
        $line = join("",$segarray);
        echo $line."<br/>\n";
    }
}

echo "</div>";
?>
</body>
</html>

nb. Notice the log must now be read twice!

Installation Instructions

Copy the code into a file called index.php and drop it into a directory accessible to your web server and ensure you grant the file execution rights.

Alter the $filepath = "/opt/minecraft/server.log"; line so that it points to your server log and ensure the web server has read rights to this file.

How to Use

Just open the PHP code in your browser and the a page should open showing today's log entries, scrolled to the bottom of the log.

If you then select an earlier date the page will refresh and show this dates entries without the auto-scrolling.

Friday 4 October 2013

OSX Time Machine kills old disks

Round 1

Earlier this year I decided to replace the disk in my Macbook Pro with an SSD. The HDD was only a year old but I was already having problems that required frequent fixing in DiskUtility. Also those odd clicking noises it was making were making me feel nervous.

I decided to backup asap (once I'd fixed the disk again) and set about manually copying my data to an external disk in the finder window. After is kept failing on a bad block I decided to try and update my Time Machine backup instead. It ran for a while and then the machine froze, forcing me to reboot the machine. I then found that the disk was corrupted and Diskutility could see it but refused to touch it.

I bought a copy of Stellar Phoenix Mac Recovery because the demo version showed all my files listed, but after recovering about 200Gb they all proved unusable. Other attempts have proved equally unsuccessful with days of processing not finding any files what-so-ever. My experience of buying recovery software has proven to be a huge waste of money! (I found similar trying to recover ReiserFS partitions)

So I ran fsck (details here) to see if it would fix it..

admin$ fsck /dev/disk1s2 -f

BAD SUPER BLOCK: MAGIC NUMBER WRONG

LOOK FOR ALTERNATIVE SUPERBLOCKS? [yn] y


CANNOT READ: BLK 16585216

CONTINUE? [yn] y

THE FOLLOWING DISK SECTORS COULD NOT BE READ: 16585216, 16585217, 16585218, 16585219, 16585220, 16585221, 16585222, 16585223,

CANNOT READ: BLK 567944160

CONTINUE? [yn] y

THE FOLLOWING DISK SECTORS COULD NOT BE READ: 567944168, 567944169, 567944170, 567944171, 567944172, 567944173, 567944174, 567944175,

SEARCH FOR ALTERNATE SUPER-BLOCK FAILED. YOU MUST USE THE
-b OPTION TO FSCK TO SPECIFY THE LOCATION OF AN ALTERNATE
SUPER-BLOCK TO SUPPLY NEEDED INFORMATION; SEE fsck(8).

So that didn't work then! (I haven't got a clue where I'd find an alternative super-block.)

Round 2

This last weekend I bought a new USB portable disk unit to use as a new Time Machine volume. My wife's Macbook hadn't been backed up since earlier this year so I decided that was the first machine to try it out on.

I hooked up the drive, kicked off Time Machine and left it running. I noticed after about an hour that it was stuck at 48% so I attempted to kill it and start again, but the Macbook refused to respond. In the end I rebooted the machine but wasn't able to get past a blank grey startup screen. I booted from a startup CD can ran DiskUtility but it refused to see the internal disk.

In the end I replaced the HDD (which was 4½ years old) and recovered from her old Time Machine backup. So that's another internal disk that Time Machine pushed over the edge, and this time it refused to show as a drive.

I'm definitely reaching the conclusion that you shouldn't use Time Machine if you have any doubts over the integrity of your hard disk. Make sure you backup regularly and you'll not lose much.

You do backup don't you?

Update (10th Oct)

I've found that Disk Warrior 4.4 can cope with a faulty disk and will mount this disk in read-only mode so that you can copy off your files. It wasn't without it's problems though, the failing disk causing disk copies to occasionally hang on certain files.