Our thoughts in real time
April 24, 2012
Jumping Back (Into) Flash
On my previous project, I was busy delving into the relatively new world of Unity game scripting as my go-to solution for dynamic content. Now I'm working on a game that has me going back into the world of Flash, so I thought I would write a brief commentary on the differences I perceive between the two frameworks as it pertains to 2D game-crafting.
This is significant, as Flash has been around so long it's become common for many rich internet applications. Most modern browsers include the latest flash player without any extra effort from the user, and it has extensive documentation and 3rd party resources. The fact that a prospective user will almost certainly have to download the beefy Unity plugin before using a Unity web-application is perhaps its most significant drawback when deciding what framework to use. If your goal is more eye-balls, Flash is simply more prevalent.
Publishing aside, Unity and Flash have some interesting differences when it comes to developing interactive content. The first difference that comes to mind is the hierarchy of classes and objects used to organize game elements. In Unity, everything starts with an abstract class called a GameObject. Lights are GameObjects, as are cubes used in level structure and localized audio sources. In the 3D editor, you can drag and drop various GameObjects into the world and arrange them as you like. Things start to get interesting when you attach one or more components to these GameObjects. Components can be anything, and are usually some customized script that dictates what behavior the GameObject will exhibit. For example, I would create a player GameObject based on certain geometric shapes. Then, I might attach to the player a 'PlayerControl' script component that dictates how it moves around the game world.
In what I'm sure is mostly a grammatical irony, my time developing Flash (using Flex) has me looking at this basic hierarchy backwards. The basic structure in Flex is actually the component, be it a Label or a TextArea or whatever. Once these components are identified and added to the stage, I can extend them in AS3 and give them behavioral functions that dictate how they interact with the user or other components. Flash in general does have the edge when dealing with pure 2D in a game setting. I was able to manipulate 2D objects in Unity just fine, but only after designing a number of custom classes and work-around techniques.

Aesthetically, the Unity editor is much more in tune with the demands of game developing. Changes are logged in real time, and you can start the simulation from any point. This is opposed to to having to start the game from scratch each time with Flash. The Flex design preview is a nice tool to set the initial conditions of the components, but does little in the way of representing interactivity in the editor, which is a shame given the long load times you have to sit through when tweaking a Flex component.
I enjoyed working with Unity, and I would recommend it to anyone who might appreciate an aesthetically different approach to developing interactive applications (games or otherwise), but its practical use might be dictated by the circumstances of your target audience.
Posted at 06:15 PM in AIR/FLex, Games, iPhone, Web/Tech | Permalink | Comments (0) | TrackBack (0)
April 18, 2012
How a LAMP developer learned to stop worrying and love Ruby on Rails
One of the most raging debates within the web developer community is LAMP vs. Ruby on Rails (RoR), with countless posts all over the Internet that debate the merits of one versus the other... but this blog entry isn't going to be one of them. You see, I'm new to RoR and hesitate to call myself an LAMP expert. So I'll just discuss my own experience going from working on PHP-based sites to working on RoR-based sites.
I realize that PHP is a language and RoR more of a framework. I'm sure there are a lot of good PHP frameworks that better stack up to RoR. However, I am comparing my experience working on a LAMP app "out of the box" versus a RoR app.
I'm primarily a front-end UI developer, but a few years ago I worked for a client with a site built on LAMP, and acquired extensive experience building PHP classes and writing MySQL database queries along with my usual HTML coding and CSS styling. I was planning to continue down this path, but sometimes you need to think outside your preconceived plans for your career path and prepare for the unexpected.
For the past few months, I've been doing extensive client-side jQuery programming and some light front-end Ruby coding on a Rails platform, and I've come to embrace my new role. One can argue forever over whether PHP or Ruby is better, but at the very least, Ruby offers a refreshing change of pace after working with PHP at my previous jobs.
For example, Rails has a templating system that is more organized than what PHP has to offer. With PHP, you can include one file within another. But with Rails, you can have designated partial files marked with an underscore at the beginning of the filename. Also, another favorite feature of mine is the use of js.erb files, which makes it easier to integrate back-end Ruby code with client-side jQuery. PHP, as far as I know, does not offer an equivalent to this.
Ruby on Rails used to have Prototype as its default Javascript library, but as of version 3.1 they have switched to jQuery. As the web continues to grow more dynamic and move beyond static HTML and CSS, it is becoming much more dependent on Javascript libraries, and of these, jQuery has become by far the most popular. So when I started being put on projects involving sites built on Rails, jQuery became a much bigger part of my job duties.
Are there things I miss about PHP/MySQL? Sure. I miss working with database queries. There's a certain amount of satisfaction in being able to take a more hands-on approach to linking back-end data with front-end content. But I'm getting equal satisfaction in being able to make the front-end user interface much more dynamic using jQuery and Rails.
Overall, I for one welcome my new Ruby on Rails overlords.
Posted at 02:43 PM in Web/Tech | Permalink | Comments (0) | TrackBack (0)
April 09, 2012
Grio Comic :)
Posted at 11:25 AM in Current Affairs, Weblogs | Permalink | Comments (0) | TrackBack (0)
March 28, 2012
Goodbye Flash world? Hello SVG world?
In the end, it's probably Steve Jobs' fault.
Back in April 2010, when Jobs explained why the iEmpire line wouldn't be supporting Flash, a subset of the developer community was anticipating HTML5 as giddily as a Twilight sequel, but the majority were only marginally aware of its existence. The first preview version of IE9 had just been released. Firefox had advanced support for many HTML5 elements, but only those early-adopting developers were really paying attention.
Once Jobs made his announcement, though, all that changed. Suddenly project managers and business developers were talking about HTML5, and some people had started to look at Flash as though it might make off with the good silver if nobody was paying attention.
A debate quickly sprung up over the merits and drawbacks of Flash and HTML5, and given the iProducts continued recalcitrance, it continues to this day. Most of this focused on the HTML5 <canvas> tag, and on video delivery, but ignored Flash's core functionality and its original reason for being: vector graphics and the animation of same.
However, <canvas>'s retiring sibling, <svg> does just that. It hasn't gotten quite the hype of <canvas>, but it's equally important. Here's a vector graphics standard with full penetration through the set of modern browsers (including iOS)
But why should we care about SVG (other than the iPhone issue, of course)? Why not keep using Flash? It's a proven technology and has deep market penetration. Why mess with success? Simple answer: because, in my humble opinion, it's a better approach, at least in theory.
SVG is just markup.
<svg> <path fill="orange" d="M 10,215 210,215 110, 42 z M 10,100 210,100 110,273 z" stroke="purple" stroke-width="3"/> </svg>
An SVG file (or html document fragment) is no more than a dialect of XML. This has all kinds of positive repercussions:
- It allows for all of the text indexing and manipulation methods of a simple xml document; it's searchable and internationalizable. It can be optimized for accessibility. (I know all of these are possible with Flash, but they tend to require workarounds and extra steps)
- It's part of the DOM. This means it can be styled with CSS. It can be accessed and manipulated with javascript. You can add events to individual SVG elements: shapes, groups, text. No more clunky ExternalInterface calls.
- It's open and visible. It's part of the document. Admittedly, this may introduce security problems which in the past would have been handled by Flash's internal security manager, but it's certainly beneficial for development. No need to go back and recompile or add extensive logging. Everything is right there in the browser and inspectable in Firebug or Chrome.
But what about the drawbacks? Isn't Flash's compiled file format faster? More compact? Better supported? Well... yes and no.
The most popular benchmark of Flash's performance vis-a-vis SVG's is a 2D particle simulator which counts the number of "frames" per second it's able to render. It isn't an accurate benchmark of anything in particular, since it doesn't distinguish between rendering times, calculation times and document modification times, and it's also dependent on the author's ActionScript vs. Javascript implementations, but it is a living demonstration of the current state of affairs, since you can see the tests play right in front of you on a variety of browsers. What I see when I look at them is that, with minor quirks, SVG is more or less in parity with Flash, except on Firefox (I'm looking at v11), where Flash is still the clear winner. Here's a summary of results from early 2012.
One problem that this comparison does turn up is that the performance of different implementations of SVG varies widely. Where you could at least expect that any browser with a Flash plugin would perform equally well on a given machine (IE and its ActiveX architecture excepted), now we're seeing differences across browsers on one machine. Until that gets normalized to some extent, widely-targeted sites using SVG may be slow to appear.
As for breadth of support, as of this writing inline SVG is supported by 62.48% of browsers in use, according to StatCounter GlobalStats (+/- your degree of skepticism over usage statistics). By all accounts Flash continues to hold steady with numbers in the upper nineties, at least in the non-mobile market.
So it looks like SVG is not quite ready for prime time. Perhaps with one more generation of browsers its use will be a no-brainer, but at the moment, most will prefer to stick with the tried-and-true.
My prediction: the .swf format will continue to be around for some time. Organizations have invested heavily in it, and it's mature and works well. But its slow eclipse has begun.
The Flash editor, on the other hand will probably get another life as an HTML5 editor, generating SVG/SMIL/javascript, and possibly canvas as well.
And it will be Steve Jobs' fault.
Postscript: What if I actually want to develop with SVG? You haven't said anything about that.
First you'll want to have an understanding of the basics of the document format, and how it fits into the DOM. The best, most complete and accessible resource I've found is http://www.w3.org/Graphics/SVG/IG/resources/svgprimer.html
Of course, most of the time, drawing images using markup is going to be tedious. To save time, people will use vector-graphics editors like Adobe Illustrator, the open-source Inkscape or, yes, Flash.
And javascript libraries like Raphael will be useful for higher-level manipulations of the SVG elements.
Posted at 11:10 PM in AIR/FLex, iOS, Web/Tech | Permalink | Comments (0) | TrackBack (0)
March 25, 2012
Picking an image from your Facebook photos in iOS
Apple provides a convinient class, UIImagePickerController, that easily allows your app to display a user interface to pick an image from the photo library. There are countless apps out there that utilize this class. Since this class manages all the user interactions, end-users of the apps that use it will find consistency when picking an image from photo library. Facebook iOS app, WhatsApp text messenger, Messages and Tweetbot are just a few popular apps that leverage this class. It'd be great had Apple provided a similar class for picking a photo from a Facebook account. This is particularly helpful for apps such as WhatsApp. I use WhatsApp more than I do Messages for texting. It's fun to be able to take a picture and send it to friends and family. But at times, I wanted to send a photo from my Facebook albums and I couldn't do that directly from WhatsApp. This is when the Facebook photo picker would come in handy. I googled around and couldn't find anything that was as simple to use as UIImagePickerController. There's PhotoPicker+ but it requires creating a developer account on their site and getting an app key (what's up with that?). Furthermore, its set of classes are far from being as simple as UIImagePickerController.
I decided to create a component that does exactly the same thing as UIImagePickerController but for picking a Facebook photo. I call it FacebookPhotoPickerController. If it takes the following 3 lines to pick an image from photo library:
UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.delegate = self;
[self presentModalViewController:imagePickerController animated:YES];
it also takes as many, if not less, number of lines to pick from Facebook albums:
FacebookPhotoPickerController *fbPicker = [[FacebookPhotoPickerController alloc] initWithDelegate:self];
[self presentModalViewController:fbPicker animated:YES];
The delegate object has to implement FacebookPhotoPickerControllerDelegate protocol. If you look closely, this protocol is very similar to UIImagePickerControllerDelegate.
FacebookPhotoPickerController encapsulates the Facebook authentication process. It uses Facebook Connect SDK to perform in-app authentication. Once authenticated, the class will display a selection of the available Facebook photo albums. Tapping on an album will bring user to a thumbnail grid view of the album's photos. This thumbnail view is a component from Three20 library. If the album contains a large number of photos, the view will not load all of them at once. Instead, it will only load a certain number at a time until user initiates to load for more. This article discusses how Three20 can handle this type of lazy loading.
To demonstrate how you can use this class, I've created a sample app called FacebookPhotoBrowser. When you run it, you'll see two buttons: Facebook Photo and a camera icon. The camera icon is to pick image from your photo library.
Tapping on Facebook Photo will bring up a UI to pick an image from your Facebook account:
Tapping on a thumbnail will initiate the download process of the fullsize image from Facebook and pass its UIImage object to the delegate object.
You can download the sample app and the source code of FacebookPhotoPickerController here. Enjoy.
Posted at 06:46 PM in Facebook, iOS, iPad, iPhone | Permalink | Comments (8) | TrackBack (0)
March 18, 2012
Google Android Translation Guide
If you are new to Android programming, you will find there are a few ‘new’ concepts and paradigms to learn. There are fancy new terms such as ‘Activity’ and ‘Intent’. Rest assured, most of these expressions are just Google trying to put their own stamp on some pretty tried and true programming paradigms.
I’ve prepared a ‘translation guide’ to help those coming to Android from web or iOS programming, where more standard terminology prevails. Here are some translations:
Activity == View Controller. An activity is essentially a view controller. It has a few extra bells and whistles, but at the end of the day it is used to control a view.
Intent == Message. An Intent is something that other objects listen for and respond to, such as Services, Activities and Broadcast Receivers. They are basically messages that support a custom payload.
One interesting thing about Intents is that they come in two flavors, explicit and implicit. Implicit Intents do not name a target and can be used to launch actions in other applications. The Android system find the best component to handle the message, er, Intent.
Gravity == Alignment. Gravity is a replacement for horizontal and vertical alignment in Android styling/layout. It combines the two into one entity, so you get ‘gravities’ like ‘center_vertical’ and ‘center_horizontal’. There is gravity, which controls the layout of a component’s children, and layout_gravity, which controls the layout of a component within it’s parent. Make sure you choose the right gravity for your planet; oops, I mean component.
Fragment == Component. A Fragment is essentially a component of an Activity. Fragments have essentially the same life cycle as an Activity, but they must reside within a parent Activity. Fragments were created to support reusable components with the release of Android tablet devices.
Inflate == Deserialize. AS you start writing Android view code, you’ll see ‘inflaters’ (LayoutInflater and MenuInflater, for example) that are used to create View objects. There is more going on under the hood, but basically inflating is turning for XML layout definitions into View objects.
I hope this helps demystify some of these terms. If you have more to add to the list, please let me know!
Posted at 03:31 PM in Android, Java | Permalink | Comments (0) | TrackBack (0)
March 14, 2012
Getting started with Amazon DynamoDB
What’s Amazon DynamoDB?
DynamoDB is one of the most recent services offered by Amazon.com. Announced on January 18, 2012, it is a fully managed NoSQL database service that provides fast and predictable performance along with excellent scalability. Let’s quickly analyze its positive and negative aspects in the lists below:
PROS:
- Scalable
- Simple
- Hosted by Amazon
- Good SDK
- Free account for small amount of reads/writes
- Pricing based on throughput
CONS:
- Poor documentation
- Limited data types
- Poor query comparison operators
- Unable to do complex queries
- 64KB limit on row size
- 1MB limit on querying
Setup and simple usage
Below I will provide a step-by-step guide to setup and start using DynamoDB
Requirements
This tutorial uses the following environment:
- Mac OS 10.7.3
- Aptana 3.0.8
- PHP 5.3.8
- AWS sdk 1.5.3
0) Sign up for an Amazon AWS account
Go to www.aws.amazon.com and signup for a free AWS account. With a free account you can obtain DynamoDB with up to 5 reads / sec and 5 writes / sec.
1) Install AWS sdk for php
Assuming you have pear already installed in your system enter the following commands (for more information on pear, see http://pear.php.net/):
pear channel-discover pear.amazonwebservices.com
pear install aws/sdk
Now some configuration files need to be modified in order to connect to your DynamoDB:
Go to your AWS management console (www.console.aws.amazon.com), click on your user name (top-right corner) and select “Security credentials”. Here you’ll find your Access Key Id and your Secret Access Key. Insert these credentials in the following file:
~/pear/share/pear/AWSSDKforPHP/sample-config.inc.php
and save the file with the name “config.inc.php”
sudo mv ~/pear/share/pear/AWSSDKforPHP/sample-config.inc.php ~/pear/share/pear/AWSSDKforPHP/config.inc.php
Once the sdk is installed and configured, you can use its APIs by including it with the following command:
require_once 'AWSSDKforPHP/sdk.class.php';
and establish a connection with your DynamoDB with:
$dynamodb = new AmazonDynamoDB();
2) Install AWS Toolkit for Eclipse/Aptana
With the AWS Toolkit for Eclipse/Aptana, it’s possible to manage your DynamoDB tables without having to login to the AWS management console.
To install it, follow the next steps:
- Start Eclipse/Aptana
- Open Help -> Install New Software….
- Enter http://aws.amazon.com/eclipse in the text box labeled “Work with” at the top of the dialog.
- Select “AWS Toolkit for Eclipse” from the list below.
- Click “Next”. Eclipse/Aptana guides you through the remaining installation steps.
- Restart Eclipse/Aptana;
- Go to preferences -> AWS Toolkit and insert your account’s credentials*.
3) Start using DynamoDB
Below I provide some instructions to start using DynamoDB through the AWS SDK. Starting from creating a new table, loading data into it and perform a simple query.
3.1) Create Table
To create a table, go to the AWS explorer in Eclipse/Aptana, right click on Amazon DynamoDB and click on “Create Table”. Define the Table name, the key attribute and value and define (if needed) the range key attribute and value. This last parameter represents a secondary key to filter data.
Let’s assume that you want to create a table called “Websites” that has two columns: id (key)(String) and URL (String)
3.2) Load data
To insert one row in your new table use the following function:
$dynamodb = new AmazonDynamoDB();
$generatedId = uniqid();
$websiteUrl = ‘http://www.grio.com’;
$put_response = $dynamodb->put_item(array(
'TableName' => “Websites”,
'Item' => array(
'id' => array( AmazonDynamoDB::TYPE_STRING => $generatedId ),
'URL' => array( AmazonDynamoDB::TYPE_STRING => $websiteUrl )
)
));
3.3) Query data
To query DynamoDB two methods can be used. The first one is called “query” and helps you to find the row identified by the provided key.
$dynamodb = new AmazonDynamoDB();
$grioId = “4f605c68e8c14”
$response = $dynamodb->query(array(
'TableName' => “Websites”,
'HashKeyValue' => array( AmazonDynamoDB::TYPE_STRING => $grioId ), ));
This will return the URL corresponding to the generated unique id (key) in the table “Webistes”.
The second method for querying DynamoDB is called “scan” and allows you to get the all table and filter it using more than one field.
$dynamodb = new AmazonDynamoDB();
$scan_response = $dynamodb->scan(array('TableName' => 'ProductCatalog',
'AttributesToGet' => array('Id'),
'ScanFilter' => array('Price' => array(
'ComparisonOperator' => AmazonDynamoDB::CONDITION_LESS_THAN,
'AttributeValueList' => array( array( AmazonDynamoDB::TYPE_NUMBER => '100' ))
))
));
Suppose you have a table called ProductCatalog that contains the ids and the prices of all the products.
The response of the above request will contain all the ids of Products with a Price lower than 100$.
“Scan” allows you to perform “more complex” queries but “query” guarantees better performances.
3.4) Parse response
The results of the above queries will be an Object of the type ECFResponse whose most important part is the body (that is a CFSimpleXML Object). To access the number of rows returned by the query it’s sufficient to look at the Count attribute:
$response->body->Count;
To get a specific field (e.g. URL) of the nth element of the response it’s necessary to access the Items attribute in the following way:
(string) $response->body->Items[n]->URL->S;
Where the cast ( “(string)” ) and the last letter “S”, depend on the type of the field ( in this case URL it’s an AmazonDynamoDB::TYPE_STRING as specified in 3.2).
Now you have all you need to start using DynamoDB for your application.
Summarizing, Amazon DynamoDB is a useful service if you need a simple, plug-and-play, scalable db. It becomes less handy if scalability is not your first concern or if your application needs to perform very complex queries. This said, we’re still talking of a very new product, which is going to improve over time.
To learn more about DynamoDB’s characteristics and APIs, go to its official website http://aws.amazon.com/dynamodb/ and reading its documentation at http://docs.amazonwebservices.com/amazondynamodb/
Alberto Montagnese
Posted at 06:36 PM in Amazon EC2, News, Web/Tech, Weblogs | Permalink | Comments (3) | TrackBack (0)
Technorati Tags: amazon, aws, database, db , dynamo, dynamodb, EC2, nosql, php, S3, sql
March 11, 2012
Thumbnail View of a Large Number of Photos with Three20
Three20 is an open-source library for iOS applications. It provides many handy features that make your iOS development life much easier. It's used in many popular iOS apps, including Facebook. One of the features that I'd like to discuss is the photo thumbnail view. Here's a screenshot of TTCatalog app, a sample app that comes with Three20 project.
There are many blogs that talk about how to use Three20 for displaying thumbnail view. I'm not going to repeat it here. Instead, I'll talk about how you can display a large number of thumbnails with "load more" at the bottom of the list. This kind of "paging" is commonly found in apps that have to deal with a large data set. For instance, the Mail app loads 50 messages at a time. A "Load More Messages..." will appear at the bottom of the list and if tapped, the app will load additional 50.
The main view controller of this component is called TTThumbsViewController. Typically you'd subclass this class to add more customizations. This controller depends on a model that is derived from TTModel class and a class that implements TTPhotoSource protocol. Each thumbnail is of class that implements TTPhoto.
I've created a simple app for this article. Its main purpose is to display photos of a Facebook album. Here are the three main classes:
@interface MyFacebookPhotosViewController : TTThumbsViewController <TTThumbsViewControllerDelegate>
@interface FacebookPhotoSource : TTModel <TTPhotoSource, FBRequestDelegate>
@interface FacebookPhoto : NSObject <TTPhoto>
TTThumbsViewController has all the logic to display "Load more" cell at the bottom of the list. It's up to the data source to "tell" the controller if there are more data to load. So, most of our works will be in FacebookPhotoSource class.
Two important methods in TTPhotoSource that tell TTThumbsViewController if "load more" needs to be present:
- (NSInteger)numberOfPhotos {
return 100;
}
- (NSInteger)maxPhotoIndex {
return _photos.count-1;
}
numberOfPhotos tells the controller the total number of thumbnails in the data set. maxPhotoIndex tells the number of thumbnails that are currently displayed. So, as long as numberOfPhotos > maxPhotoIndex, the "load more..." cell will appear.
In this example, I hardcoded numberOfPhotos to return 100. I could've called a Facebook Graph API to retrieve the number of photos in an album and used that count as the return value. But that would make the sample app more complex and harder to follow. It's definitely not the intention of this discussion.
Let's take a look at another important function:
- (void)load:(TTURLRequestCachePolicy)cachePolicy more:(BOOL)more {
_loadState = loading;
// increment page count if loading more...
if (more)
_page++;
NSString *request = [NSString stringWithFormat:@"10150146071791729/photos?limit=%d&offset=%d", NUM_PHOTOS_PER_PAGE, _page*NUM_PHOTOS_PER_PAGE];
[_facebook requestWithGraphPath:request
andDelegate:self];
}
"more" argument will be YES if the controller is trying to load data when user tapped on "load more..." cell. We keep a page counter (_page) and use it to construct a query to Facebook. Here, I hardcoded another constant: album id (10150146071791729). The Facebook Graph API to obtain list of photos in an album is https://graph.facebook.com/{album_id}/photos. It also accepts limit and offset as additional arguments.
NUM_PHOTOS_PER_PAGE is defined as 24. Obviously, it can be any arbitrary number. But I picked 24 because it's exactly divisible by 4 (number of thumbs in portrait mode) and 6 (in landscape). That way, you won't have blank columns at the last row.
Here's how the sample app looks like:
When "Load More Photos..." cell is tapped:
You can download this sample app here. Enjoy.
Posted at 07:57 PM in Facebook, iOS, iPad, iPhone | Permalink | Comments (0) | TrackBack (0)
March 09, 2012
Clustering your data on the Map. What should you use?
Web mapping services are become more popular as more applications are required to display a considerable amount of data on a map. Applications use a map view most of the time to show single points but clusters of data are becoming more popular.
Before moving forward with any of the web mapping services, it is better to understand what the application really needs from the map provider. In this case our system needs just two features:
· Clustering data
· Showing a single marker on the map
Based on the above criteria the evaluation has been focused on the following factors:
1. Ability to cluster a huge amount of data
2. Ease of implementation
3. Available API documentation and examples/tutorials
4. Number of features provided by the map services
5. Look and feel
Ability to cluster huge amount of data
Clustering services are provided by a subset of web mapping services: Google and Bing. Because only these two services are the only ones that provide clustering, we will not discuss the other web mapping services.
Google Cluster
Below is a sample of a Google cluster map. note the different colors for different cluster densities.
Bing Cluster
Here is an example of the Bing Cluster map. Note the differences in the UI from Google.
Google Cluster Implementation
Here is the code for the Google Map Clustering solution:
function initialize() {
var myOptions = {
center: new google.maps.LatLng(0, 0),
zoom: 2,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map"),myOptions);
var markers = [];
for (var i = 0; i < 30000; i++) {
var location = data.locations[i];
var latLng = new google.maps.LatLng(location.x, location.y);
var marker = new google.maps.Marker({position: latLng});
markers.push(marker);
}
var markerCluster = new MarkerClusterer(map, markers);
};
google.maps.event.addDomListener(window, 'load', initialize);
Bing Cluster implementation
The Bing implementation requires a lot of code. Because of the huge amount of lines required more bugs can occur and this will may require time for investigating, debugging and fixing bugs.
To have a better idea of what Bing javascript code looks like please refer to:
http://www.bing.com/community/site_blogs/b/maps/archive/2011/03/01/bing-maps-v7-modular-design-and-client-side-clustering.aspx
API documentation and examples/tutorials
Both Google and Bing map have well done API documentation. Google has more examples and tutorials and its community support is really active with a forum and discussion groups. Google Map API looks like the most used one as well.
Number of features provided by the map services
Either Google or Bing offers a variety of services such as different map views, zooming and the ability to save users’ locations.
To better understand the difference between those maps please refer to:
http://en.wikipedia.org/wiki/Comparison_of_web_map_services
Google is the most supported one across all browsers and offer most of the services to several countries more than what Bing does.
Conclusion
Based on my evaluation, Google wins because of its simplicity and time required for implementing the solution. Another consideration was the ability to implement the same tool on a mobile device. Both Google and Bing are very flexible and they can easily adapt their selves to mobile devices, but Google Map API is the prevalent solution for native applications on both Android and iOS.
I am not covering the pricing of these technologies. The free usage is limited in both cases.
- Google free usage corresponds to: 25,000 api calls / day 1
- Bing free usage corresponds to: 125,000 sessions (user’s sessions)/ year 2
I hope this article helps you in your selection of a map cluster solution!
Giuseppe Macrì
1. http://code.google.com/apis/maps/faq.html#usagelimits
2. http://www.microsoft.com/maps/product/licensing.aspx
Posted at 12:37 PM | Permalink | Comments (0) | TrackBack (0)
February 29, 2012
Custom log files in Rails 3
In addition to outputting lots of useful information, the Rails logger can be a useful debugging tool. But debugging with the log file can become frustrating as it will be cluttered with default content. The solution to this problem is to create a custom logger and log file for such output.
The easiest way to do this is to create a global log function, enable it in your development environment, and make sure that calls to it don't do anything in other environments.
To start, add a file to the initializers directory that will initialize the custom logger. (My dev environment is called "garret", not the traditional "development", so I'll be referring to the environment as such in subsequent code.)
My filename: <Rails.root>/config/initializers/garret_logging.rb
The logic in this file should check if the current environment is the "garret" environment, and if so, add our global logging function. If it's a different environment, we'll still add the global logging function, it just won't do anything.
Let's call the global function "glog", since that's what I call it.
As a quick aside, there's no such thing as a global function in Ruby. If you try to create a function at the highest scope Ruby will attach it as a method on the Object class. Since everything in Ruby is an object, and the Object class is the root class, adding a method to the Object class basically makes it behave exactly like a global function.
The code is pretty straight forward so I'll put in below without much more explanation. Here's what goes in garret_logging.rb.
if Rails.env == "garret"
class GarretLogger < Logger
def format_message(severity, timestamp, progname, msg)
"#{msg}\n"
end
end
logfile = File.open(Rails.root + 'log/gdev.log', File::WRONLY|File::APPEND|File::CREAT, 0666)
logfile.sync = true
Glog = GarretLogger.new(logfile)
class Object
def glog(mssg)
Glog.info(mssg)
end
end
else
class Object
def glog(mssg)
end
end
end
The Rails Logger class is extended but simplified so that there's no severity level. While in the "garret" development environment, "foobar" will get logged to the custom log file (<Rails.root>/log/gdev.log) simply by putting:
glog "foobar"
And in any other environment, the above will do nothing, so production won't crash if you leave in a few glog statements.
Posted at 07:46 PM | Permalink | Comments (0) | TrackBack (0)
February 26, 2012
In-App Facebook Authentication on iOS
The official Facebook iOS SDK provides an easy way for any iOS applications to authenticate against a Facebook account. If you follow this tutorial, you'll be able to add facebook authentication in your app in less than 15 minutes. It's that simple. Once your app has been authenticated, it will possess both access token and expiration date. These two pieces of data will be used in subsequent communication with Facebook.
From your app's user's perspective, this authentication process involves the following steps:
1. Put the app in the background
2a. If Facebook app is not installed on the iOS device, launch Safari and open Facebook login page.
2b. If Facebook app is installed, launch Facebook app.
3. Once user logged in, either Safari or Facebook app will launch your app.
These steps seem to be fairly straight-forward. It's all done by authorize method:
if (![facebook isSessionValid]) {
[facebook authorize:nil];
}
However, some may find it annoying to experience multiple app-switching. And worse, the only place that your code gets a chance to receive access token and expiration date information is at the app delegate:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [facebook handleOpenURL:url];
}
If you have a complex app and the part that needs Facebook authentication is buried deep inside several layers of features, it may be challenging to directly pass this authentication information. These are just a few reasons to consider Facebook authentication that doesn't involve switching of apps. Such in-app facebook authentication can be found in several popular apps, such as Flipboard and Photogene.
Fortunately, Facebook iOS SDK has already provided this type of in-app authentication. It's just not being defined publicly. If you look at the source code, in particular Facebook.h, you'll see the method signature for authorize:
- (void)authorize:(NSArray *)permissions;
authorize calls a private method, authorizeWithFBAppAuth:
- (void)authorize:(NSArray *)permissions {
self.permissions = permissions;
[self authorizeWithFBAppAuth:YES safariAuth:YES];
}
To make an in-app authentication, you can simply call authorizeWithFBAppAuth with both parameters set to NO:
[self authorizeWithFBAppAuth:NO safariAuth:NO];
One way to modify this behavior is to subclass Facebook and override the authorize method. Another way is to directly call authorizeWithFBAppAuth. Since this is not a public method, you'll get a compiler warning. To suppress the warning, you can call it thru performSelector:
if ([_facebook respondsToSelector:@selector(authorizeWithFBAppAuth:safariAuth:)])
[_facebook performSelector:@selector(authorizeWithFBAppAuth:safariAuth:) withObject:NO withObject:NO];
Here's the screenshot of Facebook authorization dialog within an app:
Posted at 09:48 PM in Facebook, iOS, iPad, iPhone | Permalink | Comments (2) | TrackBack (0)
February 22, 2012
Good Programmer == Pragmatic Programmer
I was working with a programmer with a deep knowledge of a particular technology. However, after working with him for a couple of hours, I realized that he was not especially pragmatic.
One criterion that makes a good programmer is pragmatism. There is a great book by Andrew Hunt and David Thomas called The Pragmatic Programmer. In their book, pragmatism is “a (person’s) attitude, a style, a philosophy of approaching problems and their solutions. They think beyond the immediate problem, always trying to place it in its larger context, always trying to be aware of the bigger picture.” The characteristics of a pragmatic programmer are:
- Early Adopter/Fast Adapter: When given something new, they can quickly grasp and integrate it with rest of their knowledge.
- Inquisitive: Always striving to understand a problem or technology. They tend to ask a lot of questions.
- Critical Thinker: They always think critically of any given situation.
- Realistic: They understand the underlying nature of each problem they face.
- Jack-of-all-trades: A generalist, they will always be learning.
A great programmer is a person who can take a problem and piece together the evidence that is presented to him or her in the larger scheme of things. He or she understands what questions need to be answered when presented with ambiguous or unclear evidence. And he or she actively searches for the concrete understanding of the issue and a concrete solution to that issue. Programming requires not only a deep knowledge of certain technology or memorizing all the shorthand techniques. It is also encompasses a person’s way of thinking.
Do you agree with Hunt and Thomas' definition and characteristics of a pragmatic programmer? Does a good programmer == pragmatic programmer? Let me hear your thoughts on this!
Posted at 03:22 PM | Permalink | Comments (1) | TrackBack (0)
February 09, 2012
A Quick Reference on Box-Shadows
Every few months I come across the need to add shadows to frontends, and it seems each time I have to go back and look up how these things work. I always take to the internet for a brush up on box shadows, but I seem to find more information than I'm looking for - I just want a quick cheat sheet, not the War and Peace of box-shadowing. So here's the cheat sheet I'll be using from now on to create the shadows I need.
The first thing to note is that for backwards and cross-browser support you'll need to write your box shadow css three times. Annoying! But its just a matter of writing the same css with different prefixes. Here's what it will look like:
-moz-box-shadow: 10px 5px 5px #888; -webkit-box-shadow: 10px 5px 5px #888; box-shadow: 10px 5px 5px #888;
Here's the CSS3 specification for box-shadow:
box-shadow: none |[, ] = inset? && [ (2,4)] && color
What? Lets break this down a bit.
First of all, the box-shadow specification tells us that we can have no shadow, one shadow, or a series of comma separated shadows.
Next we come to the shadow specification. First we have 'inset'. Inset is optional, so unless you specify inset, your shadows will always be offset from the element.
The next part (and this is where you'll do the bulk of your work) is the length. I always have trouble remembering this part of this definition - I know its a combination of 2-4 numbers, but what do the numbers refer to? Writing it out like this will help me remember it better:
length = horizontal offset, vertical offset, blur radius(optional), spread distance(optional)
or maybe:
length = HVBS
Someone more clever than me could come up with a little mnemonic device for this. Like, "Happy Valentine's, Big Sister" or "How Very Brilliant, Sartre"... I'll keep working on that bit.
The first two numbers are the required parameters, horizontal offset and vertical offset. Like it says in the names, these parameters define how far your shadow is offset from the original element. For horizontal offset, a positive number moves the shadow to the right, a negative number moves it to the left. For vertical offset, a positive number offsets the shadow below your element, and a positive number offsets it above.
Here's how you would create a shadow that is more horizontal than vertical:
#horizontal {
-moz-box-shadow: 10px 5px 5px 5px #888;
-webkit-box-shadow: 10px 5px 5px 5px #888;
box-shadow: 10px 5px 5px 5px #888;
}
And here's a shadow thats more vertical than horizontal:
#vertical {
-moz-box-shadow: 5px 10px 5px 5px #888;
-webkit-box-shadow: 5px 10px 5px 5px #888;
box-shadow: 5px 10px 5px 5px #888;
}
The blur radius is optional but to me this is the most important part of the shadow - its what makes your shadow look 'shadowy' and not just like an offset box. The higher the blur radius, the more blurred your shadow will be.
Here's an example of a shadow with and without a blur radius:
#blur {
-moz-box-shadow: 10px 5px 5px 0px #888;
-webkit-box-shadow: 10px 5px 0px 5px #888;
box-shadow: 10px 5px 5px 0px #888;
}
#no-blur {
-moz-box-shadow: 10px 5px 0px 0px #888;
-webkit-box-shadow: 10px 5px 0px 0px #888;
box-shadow: 10px 5px 0px 0px #888;
}
The spread distance is another optional parameter. Spread distance refers to the size of the shadow itself. A shadow with no spread distance will be the same size as the original element, a shadow with a positive spread distance will be larger, and a shadow with a negative spread will be smaller than the original element. To demonstrate this, here's a shadow without offset, but with spread distance:
#spread {
-moz-box-shadow: 0px 0px 5px 10px #888;
-webkit-box-shadow: 0px 0px 5px 10px #888;
box-shadow: 0px 0px 5px 10px #888;
}
#no-spread {
-moz-box-shadow: 0px 0px 5px 0px #888;
-webkit-box-shadow: 0px 0px 5px 0px #888;
box-shadow: 0px 0px 5px 0px #888;
}
The final part of the shadow specification is for the color. Since this is a cheat sheet about shadows, I'm going to presume you already know how to specify a color.
The specification allows you to combine shadows to create different effects. One of the things that it took me a while to figure out is how to add a shadow on only three sides of a element. Here's where adding multiple shadows to an element comes into play - in order to add shadow to three sides, we actually add three separate shadows, one for each side.
Below I've broken down exactly how each side is constructed, as well as the final product. Here you can also see I've added a negative spread distance to the shadow, so that its a little bit smaller than the element its shadowing.
#shadow-bottom {
-moz-box-shadow: 0px 7px 5px -5px blue;
-webkit-box-shadow: 0px 7px 5px -5px blue;
box-shadow: 0px 7px 5px -5px blue;
}
#shadow-right {
-moz-box-shadow: 7px 0px 5px -5px red;
-webkit-box-shadow: 7px 0px 5px -5px red;
box-shadow: 7px 0px 5px -5px red;
}
#shadow-left {
-moz-box-shadow: -7px 0px 5px -5px green;
-webkit-box-shadow: -7px 0px 5px -5px green;
box-shadow: -7px 0px 5px -5px green;
}
#shadow-three-sides {
-moz-box-shadow: 0px 7px 5px -2px blue, 7px 0px 5px -2px red, -7px 0px 5px -2px green;
-webkit-box-shadow: 0px 7px 5px -2px blue, 7px 0px 5px -2px red, -7px 0px 5px -2px green;
box-shadow: 0px 7px 5px -2px blue, 7px 0px 5px -2px red, -7px 0px 5px -2px green;
}
I hope other developers find this guide useful - give me a few months to forget and I'm sure I'll be referring back to it myself!
For more information about box-shadows I recommend:
Posted at 01:32 PM in Web/Tech | Permalink | Comments (1) | TrackBack (0)