Andrey Butov

Ethan Tyler Butov

May 6th, 2012

Just a few hours old.

Hello World …

May 5th, 2012

Ethan Tyler Butov came into this world on Friday, May 4th at 5:17 PM. Mom and baby are doing great and resting. I haven’t slept in about 50 hours.

Antair Nightstand for Android and the Kindle Fire

February 19th, 2012

Antair Nightstand is now available for Android tablets, and for the Amazon Kindle Fire.

  

Antair Nightstand for your iPad

February 11th, 2012

Antair Nightstand, our popular alarm clock app for the BlackBerry PlayBook, is now available for the iPad.

Pregnancy Food Guide on Android

December 17th, 2011

Pregnancy Food Guide has been available for the iPhone for a short while now, and as of today, it’s also available for your Android phone.

The What Now? Podcast

December 16th, 2011

A long time ago, Gavin Bowman and I worked together at Antair.

Gavin is now the co-founder of Retro Dreamer, where he makes awesome mobile games … and I’m still stuck here. :)

Anyway, check out our new podcast, What Now?, where we talk about making a living by peddling mobile apps and games.

 

Our latest app for the iPhone

November 16th, 2011

I’d like to introduce the Pregnancy Food Guide, Antair’s latest app for the iPhone.

 

Know what you can eat and what you can’t when you’re expecting.

When shopping for food or eating at a restaurant, this handy and informative guide will help you make safe decisions for you and your baby.

The application features hundreds of common foods, drinks, and ingredients, along with information on whether the food is safe to consume during pregnancy, and any related benefits or dangers.

 

How to set up a faster Android emulator

October 14th, 2011

For certain projects, you may find that the default Android emulator is far too slow for accurate testing.

In this guide, I will show you how to set up a faster alternative. I will be using Windows, but the tools are platform-agnostic, so you shouldn’t have trouble setting up a faster Android emulator on a Mac or a Linux box. I will also show you how to configure the resolution of the new Android emulator so you can emulate specific Android devices, such as the Amazon Kindle Fire.

 

First, download and install VirtualBox. We’ll be running our faster Android emulator as a virtual machine. You can probably use VMWare, or Parallels, but VirtualBox is available free of charge, and works perfectly well for our purposes.

 

Now, download the Android image. For this guide, I will be using Android 2.3 (Gingerbread). For that release, the matching download is android-x86.2.3-4th-test-110620.iso.

 

Start VirtualBox and create a new virtual machine.

 

Enter a name for your new virtual machine. Select Linux for the operating system, and Other Linux for the version.

 

I want my Android emulator to run with 1 GB of RAM. You can choose whatever amount of memory is best for your needs.

 

For Virtual Hard Disk, check Start-up Disk, and choose to Create a new hard disk.

 

Select VDI (VirtualBox Disk Image) for the type of virtual disk.

 

Choose Dynamically Allocated storage.

 

For disk size, I tend to allocate 512 MB. Feel free to allocate more or less disk space for your new emulator.

 

Once this is done, continue with the last few dialog boxes to create the new Android virtual machine.

 

Click on Audio, and change the Audio Controller from ICH AC97, which doesn’t work very well with this setup, to SoundBlaster 16.

 

Click on Network, and change the setting to Host-only Adapter. Now, this bit is specific to your particular network configuration. Some folks claim that setting this to NAT or Bridged Adapter gives best results. Use whichever works best for your rig. I will proceed with Host-only Adapter.

 

Click on Storage. Under Storage Tree, click on the icon to add a new CD/DVD device. When prompted, click on Choose Disk, and select the Android .iso image you downloaded earlier.

 

Start the new virtual machine. When prompted, choose Install Android-X86 to harddisk.

 

When prompted to choose a partition, select Create/Modify partitions. In the cfdisk partition manager screen that follows, choose New, then Primary, and keep the default partition size. Toggle Bootable, and then proceed to Write. After the partition is created, choose Quit to exit cfdisk. Select the newly created partition, and choose ext3 for the filesystem format. Select Yes when prompted to install the boot loader GRUB, and Yes to make the /system directory read-write. Installation should take just a few seconds.

After installation, close the virtual machine and remove the Android .iso CD/DVD in the Storage Settings before starting the virtual machine again.

 

When you start the new Android virtual machine, you’ll notice that you cannot use your mouse inside the Android OS. To fix this, choose Machine from the VirtualBox menu, and then choose to Disable Mouse Integration. You will now be able to use the mouse inside the Android OS. Take note of the host key used by your installation of VirtualBox. Without this host key, you won’t be able to get your mouse back out of the Android OS. I believe that the default host key used by VirtualBox on Windows is the right Control key, but this may be different in your installation. Click inside the Android virtual machine to bring your mouse into that environment. Click on the host key to get the mouse back out.

 

To test your application in the new Android emulator from Eclipse, you’ll need to know the IP address of the virtual machine. Click ALT-F1 to bring up the VirtualBox console, and type netcfg to display the IP address assigned to it. Take note of the IP address and click ALT-F7 to get rid of the console.

You can now connect the Android Debug Bridge (adb) to the new virtual machine Android emulator. Bring up a command prompt window, and type adb connect 192.168.56.102. Of course, you’ll use the IP address of your virtual machine, which may be different. If your system can’t find adb.exe, add it to your environment PATH. You’ll find adb.exe in your Android SDK installation directory.

Now you can set up a new Run Configuration in Eclipse to test your application in the new Android emulator. When setting up a new Run Configuration in Eclipse, click on the Target tab, and select a Manual deployment target.

 

Once this is done, when you choose to Run your application from Eclipse, you’ll be presented with a dialog from which you can select the Android device on which to run your application. Since you connected adb to your new Android virtual machine, you should see the IP address of the virtual machine as one of the available devices on which to test.

 

Custom Resolutions

What if you need to run the Android virtual machine with a custom resolution?

I’m going to configure my new emulator to look like the Amazon Kindle Fire, which has a DPI of 169 with a resolution of 1024 x 600.

First, in your VirtualBox, right click on your new virtual machine, and choose Show in Explorer. This will show you the location of the .vbox configuration file for the new VM. We’re going to edit this file, but first, we’ll need to close VirtualBox, and close our virtual machine, if it’s running.

Edit the .vbox file; it’s just an XML configuration file.

Find the ExtraData section, and add a line to it declaring your custom resolution:

<ExtraData>
      <ExtraDataItem name="GUI/LastCloseAction" value="powerOff"/>
      <ExtraDataItem name="GUI/LastGuestSizeHint" value="800,600"/>
      <ExtraDataItem name="GUI/LastNormalWindowPosition" value="998,300,800,639"/>
      <ExtraDataItem name="CustomVideoMode1" value="1024x600x16"/>
</ExtraData>

 

I added the CustomVideoMode1 line above.

Save and close the configuration file.

 

Now, start your virtual machine, and when you see the GRUB boot loader screen, choose Debug Mode.

 

At the command prompt that follows, type the command vi /mnt/grub/menu.lst to edit the GRUB boot menu file.

You should probably be familiar with the vi editor for this part. If you aren’t, find a quick tutorial to familiarize yourself with the basics.

Duplicate one of the existing entries in the file to create a new one, then change its title to something more meaningful, change its DPI parameter to 169 (that’s what we want from our Amazon Kindle Fire emulator), and add the parameter vga=ask to the end of the line.

Save, close the file, and restart the virtual machine.

 

You will see the new boot entry as one of the menu items on the GRUB loading screen.

 

When you select the new boot entry, you’ll be given the option to hit ENTER to see the available resolutions (you entered vga=ask in the GRUB configuration file, remember?). Your new entry, 1024x600x16, will be one of the items.

 

And here’s our new Android emulator running at a resolution of 1024×600 and a DPI of 169 — all ready for you to test your Amazon Kindle Fire applications.

 

That’s all!

That should be all. I’m sure you’ll find that the Android emulator running as a virtual machine is far more responsive that the standard emulator. Happy testing!

Help! My BlackBerry JDE won’t start anymore.

August 26th, 2011

You’ve been writing BlackBerry applications and building your code with the BlackBerry JDE for some time now. Then, one day, you launch the JDE and it fails to open!

What gives?

I assume you’ve covered the basics – your system has the Java runtime environment set up, with all the Java-related environment variables set up properly and pointing to the right places.

Are you running on a 64-bit system?

BlackBerry tools don’t play nice with 64-bit systems. Tools don’t run properly, simulators don’t simulate accurately (sometimes not at all). If you are running the BlackBerry dev tools on a 64-bit version of Windows, and start seeing weird behavior, all other things aside, this could be the cause.

At Antair, we run all of our BlackBerry tools on 32-bit Windows XP (virtual) machines. Until RIM updates their tools to support 64-bit systems (ha!), I suggest you set up a 32-bit rig for your BlackBerry dev work.

I’m already running on a 32-bit system. The JDE just fails to open!

OK. Maybe it’s a memory or configuration issue.

Let’s take a look at the batch file that launches the IDE. If you’re working with JDE 4.5, you’ll find the launcher batch file in

“C:\Program Files\Research In Motion\BlackBerry JDE 4.5.0\bin”

Take a look at the ide.bat file. The batch file launches the JDE with something like:

start javaw -Xmx256M -DRIM_RUNTIME=..\lib -DRIM_BIN=..\bin -jar IDE.jar

Open up the command prompt, go to the directory containing the ide.bat file, and run the launch command manually to see if any errors are thrown out to the console:

javaw -Xmx256M -DRIM_RUNTIME=..\lib -DRIM_BIN=..\bin -jar IDE.jar

If you get a clear error message,  you can take steps to address whatever the process was complaining about. In certain instances, you may get an error indicating that there isn’t enough memory provided to the process to launch the IDE. It can happen. But hey, memory is cheap, so let’s give it some more:

javaw -Xmx1024M -DRIM_RUNTIME=..\lib -DRIM_BIN=..\bin -jar IDE.jar

See if that fixes things. We’ve had instances where allowing the process to grab more memory fixes the entire “JDE not starting” issue.

OK. 256, 1024, 2048, it doesn’t matter. I don’t see any error messages on the console, and the JDE still won’t start.

You installed a simulator recently didn’t you? Admit it. You’re testing an existing application to see if it will run on a new BlackBerry device, and you just downloaded and installed one of those brand new simulators that RIM provides. Right?

This breaks JDEs. I don’t know why, but installing standalone simulators with existing JDEs on the system, sometimes breaks some of those JDEs.

To fix it, go into the same bin directory that contained the ide.bat file we’ve been messing with. In there, you’ll find a “Settings.rc” file.

Delete it. Or move it, to be safe. Then start the JDE.

It’ll start as a “newly installed” JDE, with the samples project open, and no customizations that you spent all that time setting up … but it will start.

 

How do I find unused functions in my PHP project?

August 20th, 2011

Find unused functions and methods in a set of PHP files.

USAGE: find_unused_functions.php <root_directory>

NOTE: This is a ‘quick-n-dirty’ approach to the problem. This script only performs a lexical pass over the files, and does not respect situations where different modules define identically named functions or methods. If you use an IDE for your PHP development, it may offer a more comprehensive solution.

Requires PHP 5

Direct download: find_unused_functions.zip

Code:

#!/usr/bin/php -f
 
<?php
 
// ============================================================================
//
// find_unused_functions.php
//
// Find unused functions in a set of PHP files.
// version 1.3 - 08/20/2011
//
// ============================================================================
//
// Copyright (c) 2011, Andrey Butov. All Rights Reserved.
// This script is provided as is, without warranty of any kind.
//
// http://www.andreybutov.com
//
// ============================================================================
 
// This may take a bit of memory...
ini_set('memory_limit', '2048M');
 
if ( !isset($argv[1]) ) 
{
	usage();
}
 
$root_dir = $argv[1];
 
if ( !is_dir($root_dir) || !is_readable($root_dir) )
{
	echo "ERROR: '$root_dir' is not a readable directory.\n";
	usage();
}
 
$files = php_files($root_dir);
$tokenized = array();
 
if ( count($files) == 0 )
{
	echo "No PHP files found.\n";
	exit;
}
 
$defined_functions = array();
 
foreach ( $files as $file )
{
	$tokens = tokenize($file);
 
	if ( $tokens )
	{
		// We retain the tokenized versions of each file,
		// because we'll be using the tokens later to search
		// for function 'uses', and we don't want to 
		// re-tokenize the same files again.
 
		$tokenized[$file] = $tokens;
 
		for ( $i = 0 ; $i < count($tokens) ; ++$i )
		{
			$current_token = $tokens[$i];
			$next_token = safe_arr($tokens, $i + 2, false);
 
			if ( is_array($current_token) && $next_token && is_array($next_token) )
			{
				if ( safe_arr($current_token, 0) == T_FUNCTION )
				{
					// Find the 'function' token, then try to grab the 
					// token that is the name of the function being defined.
					// 
					// For every defined function, retain the file and line
					// location where that function is defined. Since different
					// modules can define a functions with the same name,
					// we retain multiple definition locations for each function name.
 
					$function_name = safe_arr($next_token, 1, false);
					$line = safe_arr($next_token, 2, false);
 
					if ( $function_name && $line )
					{
						$function_name = trim($function_name);
						if ( $function_name != "" )
						{
							$defined_functions[$function_name][] = array('file' => $file, 'line' => $line);
						}
					}
				}
			}
		}
	}
}
 
// We now have a collection of defined functions and
// their definition locations. Go through the tokens again, 
// and find 'uses' of the function names. 
 
foreach ( $tokenized as $file => $tokens )
{
	foreach ( $tokens as $token )
	{
		if ( is_array($token) && safe_arr($token, 0) == T_STRING )
		{
			$function_name = safe_arr($token, 1, false);
			$function_line = safe_arr($token, 2, false);;
 
			if ( $function_name && $function_line )
			{
				$locations_of_defined_function = safe_arr($defined_functions, $function_name, false);
 
				if ( $locations_of_defined_function )
				{
					$found_function_definition = false;
 
					foreach ( $locations_of_defined_function as $location_of_defined_function )
					{
						$function_defined_in_file = $location_of_defined_function['file'];
						$function_defined_on_line = $location_of_defined_function['line'];
 
						if ( $function_defined_in_file == $file && 
							 $function_defined_on_line == $function_line )
						{
							$found_function_definition = true;
							break;
						}
					}
 
					if ( !$found_function_definition )
					{
						// We found usage of the function name in a context
						// that is not the definition of that function. 
						// Consider the function as 'used'.
 
						unset($defined_functions[$function_name]);
					}
				}
			}
		}
	}
}
 
 
print_report($defined_functions);	
exit;
 
 
// ============================================================================
 
function php_files($path) 
{
	// Get a listing of all the .php files contained within the $path
	// directory and its subdirectories.
 
	$matches = array();
	$folders = array(rtrim($path, DIRECTORY_SEPARATOR));
 
	while( $folder = array_shift($folders) ) 
	{
		$matches = array_merge($matches, glob($folder.DIRECTORY_SEPARATOR."*.php", 0));
		$moreFolders = glob($folder.DIRECTORY_SEPARATOR.'*', GLOB_ONLYDIR);
		$folders = array_merge($folders, $moreFolders);
	}
 
	return $matches;
}
 
// ============================================================================
 
function safe_arr($arr, $i, $default = "")
{
	return isset($arr[$i]) ? $arr[$i] : $default;
}
 
// ============================================================================
 
function tokenize($file)
{
	$file_contents = file_get_contents($file);
 
	if ( !$file_contents )
	{
		return false;
	}
 
	$tokens = token_get_all($file_contents);
	return ($tokens && count($tokens) > 0) ? $tokens : false;
}
 
// ============================================================================
 
function usage()
{
	global $argv;
	$file = (isset($argv[0])) ? basename($argv[0]) : "find_unused_functions.php";
	die("USAGE: $file <root_directory>\n\n");
}
 
// ============================================================================
 
function print_report($unused_functions)
{
	if ( count($unused_functions) == 0 )
	{
		echo "No unused functions found.\n";
	}
 
	$count = 0;
	foreach ( $unused_functions as $function => $locations )
	{
		foreach ( $locations as $location )
		{
			echo "'$function' in {$location['file']} on line {$location['line']}\n";
			$count++;
		}
	}
 
	echo "=======================================\n";
	echo "Found $count unused function" . (($count == 1) ? '' : 's') . ".\n\n";
}
 
// ============================================================================
 
/* EOF */