Shiki

I'm so bad with words that I can't even make a cool tagline

PicLyf Snap for iPhone and Android

We made these a few months ago: iPhone and Android apps for PicLyf. The iPhone version was made using Titanium Mobile while the Android version was made using good ol’ Java.

This was actually the first time I worked with Java. I learned the language as I went along with the project. I would say it wasn’t that hard to start working with it. That’s probably because it’s quite similar to ActionScript and C#, which I did a lot of before. I think I spent more time figuring out the Android platform than learning Java. The Android app was a quick (less than 2 weeks) project hence it’s still very bare. But it’s good enough to post pics to PicLyf.

We’re now working on improving these apps. We’re gonna do small quick updates for the Android app every now and then. The Android Market allows this so we’re abusing it :D For the iPhone app, we’re porting it to Objective-C for various technical reasons.

PicLyf Snap is available on the App Store and on the Android Market (market link).

Playing with Ruby: Silly backup tool for Amazon S3

To celebrate the New Year, I played a little with Ruby. I made this small Ruby script to download all original image files of PicLyf stored in Amazon S3:

#!/usr/bin/env ruby

require 'rubygems'
require 'aws/s3'

bucket = 'bucket_name'

AWS::S3::Base.establish_connection!(
  :access_key_id     => 'our_access_key',
  :secret_access_key => 'our_secret_key'
)

last_key = nil
while true do
  puts "Getting objects " + (last_key == nil ? "" : "after #{last_key}")
  objects = AWS::S3::Bucket.objects bucket, :max_keys => 10, :marker => last_key

  objects.each do |object|
    # download file if it is the original and if it doesn't exist locally yet
    if !File.exist?(object.key) && object.key.match(/^\w+_o.\w+$/)
      puts "Downloading #{object.key} "
      open(object.key, 'w') do |file|
        AWS::S3::S3Object.stream(object.key, bucket) do |chunk|
          file.write chunk
        end
      end
    end
  end

  last_key = objects.last.key if !objects.empty?
end

The scripts loops through all objects from S3 and downloads only the original image files (ours have the “*_o.jpg” pattern). If it reaches the end of the loop, it will wait for new objects.

This is really just a simple silly script but it’s a good Ruby exercise :)

Quick editing of hosts file on Windows 7

This is just a quick tip on editing the hosts file on Windows 7. Normally, administrator privileges is required to edit the hosts file. I found that the quickest way to do this is:

  1. Open up your Start Menu
  2. Type this in the quick search/launcher (see image for reference):

    notepad c:\windows\system32\drivers\etc\hosts
    
  3. Hit Ctrl+Shift+Enter to launch Notepad with admin privileges. Click Yes on the dialog that will pop up.

  4. Modify hosts file and save :)

Done! You can also use the Ctrl+Shift+Enter trick for other apps that need to be launched as admin.

Custom Properties in Titanium Windows and Controls

Instantiated windows and controls in Titanium Appcelerator act like JavaScript objects. JavaScript allows you to create custom properties in objects even when that property is not defined. You can take advantage of this in Titanium to pass some information to a window that you are about to open.

For example, on a clean project, you can have this on your app.js:

/**
 * app.js
 */
var mywindow = Titanium.UI.createWindow({ 
  url: 'mywindow.js', // load a different window file (mywindow.js)
  backgroundColor:'#fff'
});
mywindow.username = 'John Doe'; // this will be passed to mywindow.js

mywindow.open();

Above, we are setting a custom property named username to the mywindow variable which is an instance of Titanium.UI.Window. We can now access the value of username in mywindow.js:

/**     
 * mywindow.js
 */
var textfield = Ti.UI.createTextField({
  value: Ti.UI.currentWindow.username, // getting the value from app.js ("John Doe")

  borderStyle:Titanium.UI.INPUT_BORDERSTYLE_ROUNDED,
  height:35
});
Ti.UI.currentWindow.add(textfield);

The output would be a window with a textbox whose default value is “John Doe”. That was the value we set in app.js.

Not Just Scalar Values

You’re not limited to scalar values like what I just showed. You can also set full JavaScript objects:

// app.js
mywindow.userInfo = {      
  id:  1,
  name: 'John Doe',
  location: 'Neverland'
};

And access them similarly:

// mywindow.js
alert(Ti.UI.currentWindow.userInfo.location); // "Neverland"

There is one caveat when setting objects. When setting a property to an object, you won’t be able to modify that object’s properties directly:

// app.js
mywindow.userInfo = {      
  id:  1,
  name: 'John Doe',
  location: 'Neverland'
};
mywindow.userInfo.location = "Wonderland";

alert(mywindow.userInfo.location); // still "Neverland"

You’ll have to set the property again to your modified object. You can do it like this:

var userInfo = mywindow.userInfo;
userInfo.location = "Wonderland";
mywindow.userInfo = userInfo; // set the whole modified again

alert(mywindow.userInfo.location); // now "Wonderland" 
alert(mywindow.userInfo.name); // other properties still work

Also applicable to controls

Remember that you can also set custom properties on controls:

var textfield = Ti.UI.createTextField({
  value: "Jane"
});

textfield.surname = "Doe";
alert(textfield.surname); // "Doe"

It comes in handy sometimes.

Final words

Watch out when setting custom properties. Make sure that the property name doesn’t exist. For this reason I prefer to set objects to a single custom property (e.g. mywindow.params).

The Titanium Experience

I’m currently working on our first mobile app for PicLyf called PicLyf Snap. I’m also working on our API (OAuth) at the same time.

I’m using Appcelerator Titanium Mobile for both the iPhone and Android version. Titanium allows you to build native applications for these platforms using only JavaScript. It is a good tool for those who want to build native apps but don’t want to use Obj-C or Java. And I thought that it would allow us to quickly build our application for both platforms. It wasn’t as quick as I thought. Like every tool, there are some parts of it that will slap you in the face.

It is not a “write once, deploy all” solution.

This should have been obvious but I previously believed that it was. So I tried coding the app in a way that it will work on both iPhone and Android. The result was messy code with lots of compromises. I wasted a lot of time trying to write UI code that will work on both platforms. I ended up with lots of if(iPhone) and if(Android) conditions that it was no longer funny. This problem was only on the GUI though, other non-GUI APIs like the Titanium.Network worked nicely on both platforms.

I gave up in the end and split the project into two. It made the code much cleaner and focused for the target platform. And I could take advantage of those controls that are unique to a platform.

No GUI designer.

Titanium currently doesn’t have a GUI designer like the Interface Builder. You’ll have to write code to add controls to the window. For example, here’s some code to add a textfield to the current window:

var textField = Ti.UI.createTextField({
  hintText: 'e-mail address',
  top: 10,
  left: 20,
  height: 40,
  width: 190,
  backgroundColor: '#ddd',
  keyboardType: Titanium.UI.KEYBOARD_EMAIL,
  paddingLeft: 5, 
  paddingRight: 5
});
Ti.UI.currentWindow.add(textField);

Now imagine that you need lots of textfields. That’s going to be a lot of javascript code. I spend a huge amount of time in writing code for the UI: building, and trial and errors because the controls just won’t show up where I want them to be. Perhaps when I get more experience doing this, the time spent will be lessened. One could also write helpers and templates to make the task easier.

Note: someone made a xib file to javascript converter. I haven’t tested it though.

No debugger.

There’s currently no debugger like the one in XCode. You only have access to a logging API. Logs will show up in Titanium’s project window.

It’s not really that much of a problem for me though. I’m used to debugging with other languages using only logs. I think a GUI designer is a much needed feature compared to a debugger.

Why it’s still cool.

Titanium has the advantage of using a popular language that will work on all supported mobile platforms, JavaScript. For developers who know JavaScript and want to get into mobile app development, I can see this as a major selling point. They can immediately focus on just learning the platform instead of learning another language at the same time.

Using a single language also means that you can write reusable libraries that can be shared with your projects in different platforms. For example, I have a JavaScript library built for accessing our own API. This library is shared and works on both iPhone and Android projects. You can also write helpers that will be cross-platform. I made a small (and undocumented) helper library here. It is also possible to use other existing JavaScript libraries like jQuery. For our project, I’m using underscore.js, it’s a very useful utility library.

Verdict

I’d still use and recommend Titanium for mobile app development. In an adept Titanium developer’s hands, it can seriously kick ass. But if a project has the requirement to use a platform’s bleeding edge features, I think it’s best to use the platform’s primary tools (e.g. XCode) to do the job.

Adding a MovieClip/Sprite from an external SWF to a skin

I’m trying to learn a little bit of Flex 4 development. I’ve done a lot of Flash/AS3 since more than a year now but I haven’t really gotten into Flex yet. From what I learned in a day, they did a lot of improvements in separating the logic from the presentation (design). Most of this is done through skins (i.e. separate mxml files defining how a control will look). Skins act just like a container; it can contain shapes and additional controls. If applied to a control, that control will inherit all the shapes and controls from that skin.

My first annoying stumbling block was trying to add an exported symbol (e.g. MovieClip, Sprite) from an external swf to a skin. The skin will be applied to a button and should apply a background using the exported symbol. There are two ways that I’ve come up with: using BitmapImage or SpriteVisualElement.

For BitmapImage, just add this to the skin (<s:SparkSkin> tag):

<s:BitmapImage source="@Embed('assets/assets.swf#CaptureButton')" />

The above will add a bitmap version of the exported symbol named “CaptureButton” from the SWF file named “assets/assets.swf” located in the project directory. The problem with bitmaps is they look horrible when scaled up so I wanted to add the CaptureButton as a Sprite or MovieClip (vector) instead. I did it using SpriteVisualElement which takes a few more lines to set up. You’ll have to add the SpriteVisualElement tag and add the external symbol to it through code (on the addedToStage event). Here’s the full code of the skin file using SpriteVisualElement:

<?xml version="1.0" encoding="utf-8"?>
<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" 
             xmlns:fb="http://ns.adobe.com/flashbuilder/2009" 
             xmlns:mx="library://ns.adobe.com/flex/mx"
             minWidth="21" minHeight="21" alpha.disabled="0.5">

  <fx:Metadata><![CDATA[ [HostComponent("spark.components.Button")] ]]></fx:Metadata>
  <fx:Script>
    <![CDATA[

      // embed our symbol (Sprite)
      [Embed('assets/assets.swf#CaptureButton')]
      private var CaptureButton:Class;

      /**
       * As defined in the SpriteVisualElement tag at the bottom of the page, this 
       * event handler will be called when it gets added to the stage.
       */
      protected function mySprite_addedToStageHandler(event:Event):void
      {
        // create an instance of our embedded symbol
        var sprite:Sprite = new CaptureButton() as Sprite; // or use MovieClip if you're adding a symbol with more than 1 frame
        sprite.x = 10;
        sprite.scaleX *= 2;
        sprite.scaleY *= 2;
        mySprite.addChild(sprite); // add it to the SpriteVisualElement
      }
    ]]>
  </fx:Script>

  <s:states>
    <s:State name="over" />
    <s:State name="down" />
    <s:State name="disabled" />
    <s:State name="up"/>
  </s:states>  

  <!-- call mySprite_addedToStageHandler() when this element gets added to the stage -->
  <s:SpriteVisualElement id="mySprite" addedToStage="mySprite_addedToStageHandler(event)" />

</s:SparkSkin>

The SpriteVisualElement takes more lines to setup than BitmapImage. I hope that this is just a lack of knowledge on my part. There might be a way to add a Sprite/MovieClip with just 1 tag. For now, this works great and I’m fine with that.

Assigning the skin to a button should look like this:

<!-- assuming we named our skin "CaptureButtonSkin" -->
<s:Button id="captureButton" skinClass="CaptureButtonSkin" height="197" width="442" x="365"/>

Update 2010-08-26

After a night’s sleep I found it. Crap. It was this easy:

<mx:Image source="@Embed('assets/assets.swf#CaptureButton')" />

Face palm. Excuse me while I bang my head against the wall.

Creating a custom image service for Twitter for iPhone Tweetbot

Update Jan 13, 2012: It looks like setting a custom image service is no longer available on Twitter for iPhone. Tweetbot allows it though. This article still works for Tweetbot. For the rest of this article, please treat the text “Twitter for iPhone” as any app that supports custom image services (e.g. Tweetbot).

We’ve just recently deployed a custom endpoint to allow Twitter for iPhone users to post their pics through PicLyf.

When you attach an image to a tweet, Twitter for iPhone will upload that image to the image service of your choice. It allows you to choose from various image services (e.g. yFrog, Twitpic, TweetPhoto) or a custom image service. In our (PicLyf) case, it was custom. We made a custom endpoint: http://api.piclyf.com/twitter. Using this url as the custom image service, attached images will be uploaded to the user’s PicLyf account.

Implementation

This functionality works through the use of OAuth Echo. From Twitter:

OAuth Echo is a means to securely delegate OAuth authorization with a third party while interacting with an API. Within the Twitter ecosystem, we use OAuth Echo as a means to allow your application to use services such as Twitpic and yfrog.

You may want to read about OAuth Echo first. Basically, Twitter for iPhone sends you the image along with the OAuth credentials of the user who wants to upload the image. Note that the OAuth credentials also includes the app’s consumer key. What you’ll have to do is use these credentials and verify them with the Twitter API. If the verification succeeds, you will receive the user’s Twitter information. You may then save the image in your server and link it with the user’s Twitter account. Lastly, you will have to return the correct response to Twitter for iPhone specifying the url where the image can be viewed:

<mediaurl>http://foo.com/bar/pic-url.html</mediaurl>

Sample code in PHP

Here is a sample class which encapsulates the OAuth Echo process:

class TwitterOAuthEcho
{
  public $verificationUrl = 'https://api.twitter.com/1/account/verify_credentials.json';
  public $userAgent = __CLASS__;

  public $verificationCredentials;

  /**
   *
   * @var int
   */
  public $resultHttpCode;
  /**
   *
   * @var array
   */
  public $resultHttpInfo;
  public $responseText;

  /**
   * Save the OAuth credentials sent by the Consumer (e.g. Twitter for iPhone, Twitterrific)
   */
  public function setCredentialsFromRequestHeaders()
  {    
    $this->verificationCredentials = isset($_SERVER['HTTP_X_VERIFY_CREDENTIALS_AUTHORIZATION']) 
      ? $_SERVER['HTTP_X_VERIFY_CREDENTIALS_AUTHORIZATION'] : '';
  }

  /**
   * Verify the given OAuth credentials with Twitter
   * @return boolean
   */
  public function verify()
  {
    $curl = curl_init($this->verificationUrl);
    curl_setopt($curl, CURLOPT_USERAGENT, $this->userAgent);
    curl_setopt($curl, CURLOPT_HEADER, false);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_HTTPHEADER, array(
        'Authorization: ' . $this->verificationCredentials,
      ));

    $this->responseText = curl_exec($curl);
    $this->resultHttpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    $this->resultHttpInfo = curl_getinfo($curl);
    curl_close($curl);

    return $this->resultHttpCode == 200;
  }
}

The setCredentialsFromRequestHeaders method saves the OAuth credentials sent by the consumer (e.g. Twitter for iPhone, Twitterrific). These credentials will be used in the verify method which sends the verification request to Twitter.

Using the class above, your custom image service page (e.g. http://api.piclyf.com/twitter) should handle the request like this:

$oauthecho = new TwitterOAuthEcho();
$oauthecho->userAgent = 'My Custom Image Service App 1.0';
$oauthecho->setCredentialsFromRequestHeaders();
if ($oauthecho->verify()) {      
  // Verification was a success, we should be able to access the user's Twitter info from the responseText.
  $userInfo = json_decode($oauthecho->responseText, true);
  $twitterId = isset($userInfo['id']) ? $userInfo['id'] : null;      
  // You can use $userInfo or $twitterId above to maybe check if you have a record of this user
  // in your db.

  // You can access the uploaded image using $_FILES. Save it and create a url where it can be accessed.

  // Return the image url back to the consumer
  $imagePageUrl = 'http://somwhere.com/image1';
  echo '<mediaurl>' . $imagePageUrl . '</mediaurl>';

} else {
  // verification failed, we should return the error back to the consumer
  $response = json_decode($oauthecho->responseText, true);      
  $message = isset($response['error']) ? $response['error'] : null;      
  if (!headers_sent())
    header('HTTP/1.0 ' . $oauthecho->resultHttpCode);
  echo $message;
}

The code above is just a sample and your final code will look very different especially if you’re using a framework. I’ve also left out the part where you’ll get the image from $_FILES and save/process it. That is beyond the scope of this article.

Notes

The note in Twitter for iPhone’s custom image service screen says you can get more (developer) info in this url: http://developer.atebits.com. As of this writing, the information on that page is no longer accurate. Twitter for iPhone no longer sends you the user’s username and password. The info at Twitterrific is more accurate. And yes, if your service works for Twitter for iPhone, it should work on Twitterrific too.

Further reading:

Why I don’t code in Ruby

Well, not yet anyway. Perhaps when those hosting prices go down I’d go and take a shot at building something useful. I did start reading a few books on Ruby and Rails. It’s an incredibly awesome and fun language. I’ve never been very excited when learning a new language. I drool when I see Ruby code. It’s easy to learn but I’ve already forgotten most about it since I don’t use it fulltime.

If it were just me, I’d have built PicLyf using Ruby to make it more exciting. But there’s the city talent pool we had to think of. Currently, it’s hard to find good PHP developers. I reckon it’ll be more hard to find those who know Ruby.

Creating PID files for beanstalkd on CentOS

Yep, managing servers is hard >.< I’ve been trying to set beanstalkd to be managed by monit on CentOS. Unfortunately beanstalkd doesn’t seem to create pid files on CentOS (it creates one in Ubuntu though). Pid files are needed by monit so it can check if the process is still running or not. Many grueling hours later, I settled with modifying /etc/init.d/beanstalkd and adding this to the start() function (after daemon $exec…):

echo `ps auxf | grep -v grep | grep "$exec -d $options" | awk '{print $2}'` > /var/run/beanstalkd.pid

I have no idea what all those grep and awk exactly mean. ^_^x But the effect is it creates the pid file in /var/run/beanstalkd.pid containing the correct process id of beanstalkd. You could then have monit watch that pid file.

Here’s the whole modified script. And this is my main reference: http://gist.github.com/508889. A huge thanks to him (Sam X).

The undefined curl function in console (WampServer)

Stupid stupid me. On Windows/WampServer, I’ve always had this problem when working with PHP code that can run in the console and using cURL methods..

PHP Fatal error:  Call to undefined function curl_init() in D:\Shiki\github\yii-clockwerk\test-app\CurlHelper.php on line 90
Fatal error: Call to undefined function curl_init() in D:\Shiki\github\yii-clockwerk\test-app\CurlHelper.php on line 90

It (cURL) works in the browser but not when in console. I didn’t think that it was this simple to fix. The PHP CLI uses a different config file (php.ini) compared to the one used by WampServer/Apache. You can see the location of the config file being used by typing:

php --ini

Result:

Configuration File (php.ini) Path: C:\Windows
Loaded Configuration File:         C:\wamp\bin\php\php5.3.0\php.ini
Scan for additional .ini files in: (none)
Additional .ini files parsed:      (none)

You can then fix the curl problem by enabling it in the php.ini file being used. Make sure this is not commented out:

extension=php_curl.dll