Sunday, August 25, 2013

Using Automator to get the absolute path of the selected file or folder in Finder in OS X 10.8.4

This guide shows how you can add a contextual menu (i.e. right click menu) which copies the full path of the selected file or folder to the clipboard.

I often need to report to clients the list of files changed in a project manually. Unlike Windows Explorer or Nautilus in Linux, OS X's Finder requires multiple steps in order to retrieve the absolute path of the currently visible directory. Fortunately, Automator comes to the rescue.

These instructions applies to OS X 10.8.4

1) Open Automator.
2) Click 'Service' then click 'Choose'
3) At the top right, change the drop down lists so they look like :
Service receives selected 'files or folders' in 'Finder'
4) Click 'Utilities'. Drag 'Run Shell Script' to the workflow.
5) For 'Pass input', select 'as arguments'
In the text area, use these :
for f in "$@"
do
 echo "$f"
 # echo "'$f'"
done
6) Click 'Utilities'. Drag 'Copy to Clipboard' to the workflow. Drop it at position 2.
7) Click 'File', 'Save'.
8) Give it a name like 'Copy path'.
9) You will now have an entry called 'Copy path' in your Finder contextual menu i.e. the right click menu.

Thursday, February 7, 2013

Taking screenshots of multiple sites using casperjs

Casperjs, together with Phantomjs, allows you to take screenshots of web pages without the need to launch a graphical browser like FF or Chrome.

The many examples on the net unfortunately skipped the issue of taking screenshots of multiple sites per execution. Also, the ones I've tried kept getting mobile versions of the sites I intended to capture.

So I decided to piece together the disparate info out there and do some tests to come up with a foolproof way to achieve what I wanted.

Before we go to the script, here's a visual guide of the variables used in it. The top, left corner is the (0,0) position. The image we want to take for each site is the clipped region at the center. The viewport width was set to a whooping 2000 to prevent sites like engadget.com from returning their mobile version.

Here is the Casperjs script. All images are dumped in the 'shots' directory relative to the script itself. The comments should hopefully guide you into understanding and subsequently modifying it for your testing needs.

// // Usage : casperjs casper_1.js

// // Size of the browser i.e. viewport
var view_width = 2000, view_height = 768;

// // Size of the clipped image
var clip_width = 1366, clip_height = 768;

var casper = require("casper").create({
 // // Set the viewport size
 viewportSize: {width: view_width, height: view_height},
 // // Set the position and the size of the clipped image
 clipRect: { 
  top: 0, 
  left: (view_width - clip_width)/2, 
  width: clip_width, 
  height: clip_height 
 }
});

// // Take screenshots of these sites
var links = [
    "http://engadget.com/",
    "http://shoryuken.com/2013/02/01/help-save-super-arcade/",
    "http://theverge.com/"
];

casper.start();
var i = 0;

casper.each(links, function(self, link) {
    this.thenOpen(link, function() {
        i++;

        // // Output to console on the current page's title
        this.echo(i + ' : ' + this.getTitle() + " @ " + link);

        // // Dump screenshots to directory 'shots'
        this.capture('shots/casper_1_' + i + '.png');
    });
});

casper.run();

Friday, January 13, 2012

Ensuring embedded Vimeo videos are clickable within an element controlled by Isotope in Firefox 9.0.1 on Mac



Recently I had to troubleshoot why embedded Vimeo videos appear but
can't be clicked on when loaded on an element handled via
Isotope.



It turns out that this issue is specific to Firefox 9.0.1 on Mac. Not
sure if it affects other browsers though.



Assuming that the Isotope controlled element loads the embedded Vimeo video
once it gets clicked, then the solution was to remove the '-moz-transform'
css from said element preferably at the end the function bound to its 'click' event.



An example is shown below. Here, the elements handled by Isotope are
those with class 'thumbnail'. The code utilizes the excellent
jQuery based plugin for detecting browsers and OS by Stoimen
.



jQuery('.thumbnail').click(function(){

// // Code to load content with embedded Vimeo video into this element.
// // This could be done via Ajax.

// // Workaround to make Vimeo working in FF (Mac)
if ((jQuery.client.os == 'Mac') && (jQuery.client.browser == 'Firefox')) {
jQuery(this).css('-moz-transform', '');
}

});



Hope this helps someone out there. Took me an obscene 2 days of work to troubleshoot this one :(

Sunday, July 10, 2011

Getting product list by category from magento web service


Never thought that in Magento Community Edition 1.5, retrieving product list by category via a web service function could be such a pain.

Let me explain ...

In Magento, you can assign a product to categories.

A product can also have what in Magento's lingo is called an 'attribute set'.



To get products by category, you use web service function catalog_category.assignedProducts. For example, to get products under category id 44 in store 1, use:


$responseInfo = $proxy->call($sessionId, 'catalog_category.assignedProducts', array(44, 1));

Notice that the category id and store id are passed in an array.

A major drawback with this function is that it has no filter options for pagination purposes. So one can't query for items 30 to 40 for a given category id. Strange omission indeed ...




Function catalog_product.list however allows some sort of workaround when it comes to pagination. However, it does not return products based on their category, it uses 'attribute set' instead. Bummer ...

Here is an example usage of this web service function. In the following, we are fetching records which have 'attribute set' 49 and id between 44 to 48.


$filters = array(
'type_id' => array( '=' => 'simple' ),
// // Fetch products which belong to a certain 'attribute set' NOT category.
'set' => array('=' => 49),
// // Fetch products from id 44 to 48, inclusive. Could be used for pagination I guess ...
'product_id' => array('in' => range(44,48)),
// // Fetch active products only
'status' => array('=' => 1)
);
$responseInfo = $proxy->call($sessionId, 'catalog_product.list', array($filters));


catalog_category.assignedProducts could be the prefect function to fetch products by category as this is how most stores display their wares, not using Magento's 'attribute set'. Unfortunately this function is rather spartan and has no filter options unlike catalog_product.list.

A somewhat inelegant workaround to achieve pagination using catalog_category.assignedProducts is by retrieving all products under a specified category and iterate manually to get the range of products which we want to display. IMHO, this may not work so well should the number of items under said category is huge.

Tuesday, September 21, 2010

Simple Git example for SVN users


In my case, using Git for the first time wasn't exactly a picnic, being so used to SVN. The learning curve was steep and requires a lot of thorough reading plus research (i.e Google). IMHO, it doesn't have the up-and-get-go ease of use as SVN, understandable as Git is far more advance.



So here's another Git guide for SVN users, albeit a simple one. Here, the central Git repository is hosted at GitHub and the OS used is Linux.



Say you have a GitHub a/c with u/p : myname/mypassword.



To access GitHub, create the SSL as described here.



Set global git parameters so you can execute commands without being asked for passwords and what not. For the user name and email, use the same one when you registered with GitHub.


git config --global user.name "myname"
git config --global user.email your_email@some_domain.com



Get a fresh copy of your repository from GitHub. In this case the GitHub url for the repository is git@github.com:some_user_name/RepositoryName.git. After this, a new directory called RepositoryName will be created. 'cd' into it so you may execute the rest of the git relevant commands.


git clone git@github.com:some_user_name/RepositoryName.git
cd RepositoryName



From here, begins your usual edit/compile/test cycle.



To see which files have been modified/added/deleted, you can use either of these:


git status
git diff --color



To commit a modified file, type the following. Note that unlike SVN, this does not go to the GitHub repository.


git commit app/views/projects/show.html.erb -m "fixed some bug"



To commit a new file, type the following. This also does not go to the GitHub repository immediately like in SVN.


git add app/views/projects/form.html.erb
git commit app/views/projects/form.html.erb -m "added new form"



To push what you've just committed to the GitHub repository:


git push



To get updates from the GitHub repository:


git pull



Hope that helps, especially when you're used to the SVN way of doing things.



Of course, do Google around for more info. There's tons out there.

Wednesday, May 5, 2010

The security header is not valid

Regarding Paypal API credentials, here's a summary to avoid confusion:

* If you're using SANDBOX mode, you need to use a SANDBOX account API credentials.
* If you're using LIVE mode, you need to use a LIVE account API credentials.

If you use a LIVE account to test in Paypal's SANDBOX environment, Paypal will respond with "The security header is not valid" and vice versa.

There must be a good reason why the returned message is so vague.

Sunday, October 11, 2009

Delete individual URL from Firefox's address text input

Shift + Delete

Simple right ?

You can also do this more than once. For example, while typing "www.c" on Firefox's address text input, it will display other URI starting with those characters. Here, you can use the arrow key to highlight the URL you want to remove and press "Shift + Delete". Repeat as necessary for other unwanted URI.

It was unusually difficult to locate this feature by navigating Firefox's menus, so I Googled. The result is posted here just to spread the word.

Monday, March 9, 2009

Linux fc tips

fc is a command in Linux which I can't seem to remember no matter how many distros I hopped onto.

So I post this as a reminder, as well as for the benefit of anyone who despise reading man pages :)

To list your executed command history:

fc -l


The above will lists the commands with line numbers on the left like so:

492 unrar x some.part1.rar
493 sync;exit
494 python editor_test.py
495 cd Documents/python_editor/
496 vi test.py
497 python test.py


To execute command history number 495 above:

fc -s 495


To edit it before executing however, use the one below.
After you exit the editor, the command will be executed:

fc 495


If you would like to execute the last command with the word 'mailer' in it:

!?mailer?

Sunday, December 21, 2008

Ensuring UTF-8 encoded files compile in Staticmatic

Pages with Russian characters are stored (AFAIK) encoded using UTF-8. Unfortunately, this encoding is not compilable by Staticmatic.

A simple workaround is to insert a blank line at the start of the page like so:



Problem solved :)

Tuesday, December 2, 2008

JBoss web service blocked

If you have a web service in JBoss of which you can access the WSDL but keep getting "connection refused" error when accessing the service, then the culprit is normally this:


C:\jboss-4.2.2.GA\bin\run.bat -b 0.0.0.0


or


C:\jboss-4.2.2.GA\bin\run.bat


A solution - at least what worked for me - was to use the actual IP of the machine like so:


C:\jboss-4.2.2.GA\bin\run.bat -b 192.168.1.11


Its funny how modifying JBoss startup scripts did not affect the "-b" option above. However specifying it on the command line works fine.

Monday, July 28, 2008

Using BETWEEN in an EJB3 query


Say if you have an EJB3 entity bean named Landmark which is mapped to a table called landmarks which has 2 columns longitude & latitude (amongst others). To query a given latitude & longitude, its a good idea to relax the query a bit by using BETWEEN.



An example is shown below where we allow a tolerance of 0.00003 for both latitude & longitude. The sample shown is an excerpt from an EJB3 entity bean, right before its class declaration.


@Entity
@Table(name = "landmarks")
@NamedQueries( {
@NamedQuery(
name = "Landmark.findByCoordinates",
query = "SELECT lgr FROM Landmark lgr " +
"WHERE lgr.latitude BETWEEN (?1 - 0.00003) AND (?1 + 0.00003) " +
"AND lgr.longitude BETWEEN (?2 - 0.00003) AND (?2 + 0.00003) ")
})
public class Landmark implements Serializable {

Convert NMEA latitude & longitude to decimal

Here's how you convert latitude & longitude obtained from NMEA's GPGGA to decimal:











 NMEADecimal
latitude0302.7846903 + (02.78469/60) = 3.046412
longitude10141.82531101 + 41.82531/60) = 101.6971


Notice that for latitude of 0302.78469,


03 ==> degress. counted as is


02.78469 ==> minutes. divide by 60 before adding to degrees above


Hence, the decimal equivalent is:


03 + (02.78469/60) = 3.046412

Friday, May 30, 2008

Comparing byte and int in Java

Yet another blog title of mine with "in Java" at the end :)

Anyway, one of the most confusing aspects of dealing with byte in Java was its actual value range. Based on some simple JUnit tests I made, I got the following output:

0 byte = 0 int
1 byte = 1 int
126 byte = 126 int
127 byte = 127 int
-128 byte = 128 int
-127 byte = 129 int
-2 byte = 254 int
-1 byte = 255 int

Interesting ....

From here we can deduce:
1) byte goes from 0 to 127 then -128 to -1
2) the range above actually corresponds to integer values of 0 to 127 then 128 to 255

Here is the JUnit test case which produced the above output. Note that Java does not allow byte values:
1) beyond or equal 128 and;
2) less or equal to -129
... which explains the remarked code portions below.


import static org.junit.Assert.*;
import org.junit.Test;

public class BaitTest {

@Test
public void printNegativeByte() {
byte baitValue;
int intValue;

baitValue = 0;
intValue = baitValue & 0xFF;
System.out.println(baitValue + " byte = " + intValue + " int");

baitValue = 1;
intValue = baitValue & 0xFF;
System.out.println(baitValue + " byte = " + intValue + " int");

baitValue = 126;
intValue = baitValue & 0xFF;
System.out.println(baitValue + " byte = " + intValue + " int");

baitValue = 127;
intValue = baitValue & 0xFF;
System.out.println(baitValue + " byte = " + intValue + " int");

// baitValue = 128;
// intValue = baitValue & 0xFF;
// System.out.println(baitValue + " byte = " + intValue + " int");

// baitValue = -129;
// intValue = baitValue & 0xFF;
// System.out.println(baitValue + " byte = " + intValue + " int");

baitValue = -128;
intValue = baitValue & 0xFF;
System.out.println(baitValue + " byte = " + intValue + " int");

baitValue = -127;
intValue = baitValue & 0xFF;
System.out.println(baitValue + " byte = " + intValue + " int");

baitValue = -2;
intValue = baitValue & 0xFF;
System.out.println(baitValue + " byte = " + intValue + " int");

baitValue = -1;
intValue = baitValue & 0xFF;
System.out.println(baitValue + " byte = " + intValue + " int");
}

}

How to properly print a hexadecimal byte array in Java

Here is a JUnit snippet of how to properly print a hexadecimal byte array in Java. The byte array may actually be an array of integers as well.


import static org.junit.Assert.*;
import org.junit.Test;

public class HeksTest {

@Test
public void printHex() {
byte[] bs = {
(byte)0xCA,
(byte)0x00,
(byte)0x00,
(byte)0x16,
(byte)0x04
};

int[] parameterArray = new int[5];
parameterArray[0] = bs[0];
parameterArray[1] = bs[1];
parameterArray[2] = bs[2];
parameterArray[3] = bs[3];
parameterArray[4] = bs[4];


StringBuffer sb = new StringBuffer();
String hexString = "";
for (int i = 0; i < 5; i++) {
hexString = Integer.toHexString(0xFF & parameterArray[i]).toUpperCase();
if (hexString.length() == 1) {
// i.e. if its "4" then print out as "04"
sb.append("0");
}
sb.append(hexString);
sb.append(" ");
}

int length = sb.length();
sb.setLength(length - 1);
hexString = sb.toString();

System.out.println("address (hex) = [" + hexString + "]");

assertTrue("CA 00 00 16 04".equals(hexString));

hexString = null;
}

}


Perhaps the most important line in the above code is the one shown below. Take note of the toHexString method used here. Also, the array element conversion uses 0xFF to ensure that negative values are converted properly.


hexString = Integer.toHexString(0xFF & parameterArray[i]).toUpperCase();

Convert byte array to integer in Java

The following JUnit test shows how to convert a byte array into a single integer in Java.


import static org.junit.Assert.*;
import org.junit.Test;

public class BaitTest {

@Test
public void printInt() {
byte[] bs = {
(byte)0x00,
(byte)0x00,
(byte)0x00,
(byte)0x16,
(byte)0x04
};

int address = (bs[0] << 32) | (bs[1] << 24) |
(bs[2] << 16) | (bs[3] << 8) | bs[4];

System.out.println("address (int) = [" + address + "]");
System.out.printf("address (hex) = [%X]\n", address);

assertTrue(5636 == address);
}
}


In the above, the line :

int address = (bs[0] << 32) | (bs[1] << 24) |
(bs[2] << 16) | (bs[3] << 8) | bs[4];

is where we convert the byte array to a single integer using the assumption that the most significant byte (i.e. MSB) is at index 0. Note that the bit shift values are incremented by multiples of 8 i.e. or 8*0, 8*1, 8*2, 8*3 and 8*4.

In Java 5 upwards, to print a decimal number as hexadecimal, use the "%X" modifier in "printf", as shown in this line from the above code :

System.out.printf("address (hex) = [%X]\n", address);


You'll see that the above will print out "1604" (i.e. 00 00 00 16 04) which is what the byte array looks like at the top of the code, i.e. :


byte[] bs = {
(byte)0x00,
(byte)0x00,
(byte)0x00,
(byte)0x16,
(byte)0x04
};

Thursday, January 31, 2008

How to eject CD drive in OS X

Press F12 for a few seconds.

Then (hopefully) your CD (or DVD) drive will eject.

Wait, why is this considered "not in the manual" ?

Well, today I had to insert a DVD into my optical drive but its physical eject button was not working anymore.

Since I was booted into OS X at the time, I decided to look around for any sign of said optical drive.

But no. Nada. Zip.



This simple & intuitive task in Windows & Linux proved to be surprisingly complicated in OS X. Funny (well ... not at the time though).

So, I went to the Terminal and typed :


eject /dev/cdrom


It replied saying "eject" wasn't found. True enough, the following returned zilch :


find / -name 'eject' -print


Finally succumbed and Googled instead. Then stumbled upon the F12 trick.

Of course once the optical drive isn't empty, then only Finder displays it as a mounted drive !



This, from a premium priced boutique OS :/

I have other gripes concerning OS X but I'll save it for later (... the fan boys are everywhere)

Solution to "Invalid thread access" in eRCP

In Embedded Rich Client Platform, i.e. eRCP, an "Invalid thread access" exception is produced when any class that extends ViewPart executes a new thread the conventional way in method
public void createPartControl(Composite parent)


What do I mean by "executes a new thread the conventional way" ? Well here's an example (let's say we have a class or subclass WeatherData which implements Runnable) :


// This will produce an "Invalid thread access" error
Thread thread = new Thread(new WeatherData());


To eliminate the "Invalid thread access" issue, use this instead :


parent.getDisplay().syncExec(new WeatherData());

Monday, January 28, 2008

Interesting PushRegistry behaviour in Nokia N95

Based on my observation, the PushRegistry feature in Nokia N95 acts unpredictably when the device misses one or more SMS meant for a listening port, i.e. most probably because the device was switched off.

Perhaps a little story would be in order :)

OK, say on your Nokia N95 device, there is a MIDlet which listens for incoming SMS at port 8044.

Now lets send a series of SMS targeted at port 8044 above.

SMS A was sent to the device when it was switched on. MIDlet wakes up ok.

Let's switched off the device.

Send SMS B to said device

Send another SMS, C.

And another one, D.

Now switch on the device.

Your MIDlet may or may not be awaken at this point (even if it does wake up, the content you get may come from either SMS B, C or D !).

A new SMS, E, is sent to the device.

Now you'll discover that the MIDlet will wake up but the contents you see may come from SMS B, C, or D.

Let's say when E was sent, your MIDlet displays content from B instead, not the one in E.

Now another new SMS, F, gets pushed to the device. You'll discover that the contents of SMS C will be displayed instead of the one in F ! (Interestingly if SMS E, resulted in D being displayed, then SMS F will display the contents in SMS E.)

As you can see, the order is intact i.e. SMS B followed by C etc. However, you're not getting the actual SMS which wakes up the MIDlet.

Weird. Very very weird.

Is it a firmware bug ? Could it be the carrier ? Honestly I can't be sure :/

Solution ? Uninstall & reinstall the MIDlet (and ... no, rebooting the device doesn't work either)

Of course once your MIDlet misses an SMS targeted for its PushRegistry port, then the issue pops up again. Hence, there is no solution really :(

"Must be Server" error from PushRegistry with sms

Whew ! Took 2 days to figure this out.

Recently attempted to create a MIDlet which wakes up on SMS using the PushRegistry feature in Java ME.

Kept getting "Must be Server" error at the
mc.receive()
line in following code snippet :


if (url.startsWith("sms://")) {
MessageConnection mc = (MessageConnection) Connector.open(url);
Message msg = mc.receive();
String data = "";

if (msg != null) {
if (msg instanceof TextMessage) {
form.append("TextMessage\n");
data = ((TextMessage)msg).getPayloadText();
}
}
}


Turns out the JAD file of said MIDlet has the following incorrectly typed PushRegistry entry :


MIDlet-Push-1: sms://8033, org.whatever.Poink, *


There should be a ":" after the 2 "slashes" like so :


MIDlet-Push-1: sms://:8033, org.whatever.Poink, *


After the above fix, the "Must be Server" disappeared :)

Friday, January 25, 2008

Probability notations made simple

OK, this ain't Java. Nonetheless this article by Eliezer Yudkowsky really helped in me understanding probability notations (those "|" and "&") as used in Bayesian theory by presenting actual problems instead of the usual Math gobbledygook. Here's a quote :


... p(Q|P) is the proportion of things that have property Q and property P
within all things that have P; i.e.,
the proportion of women with breast cancer and a positive mammography within
the group of all women with positive mammographies.

If there are

641 women with breast cancer and positive mammographies,
7915 women with positive mammographies, and
89,031 women,

then p(Q&P) is the probability of getting one of those 641 women
if you're picking at random from the entire group of 89,031,

while p(Q|P) is the probability of getting one of those 641 women
if you're picking at random from the smaller group of 7915.


Here's another quote :


In a sense, p(Q|P)really means p(Q&P|P), but specifying the extra P all the
time would be redundant. You already know it has property P, so the property
you're investigating is Q - even though you're looking at the size of group
Q&P within group P, not the size of group Q within group P (which would be
nonsense).

This is what it means to take the property on the right-hand side as given;
it means you know you're working only within the group of things that have
property P. When you constrict your focus of attention to see only this
smaller group, many other probabilities change. If you're taking P as given,
then p(Q&P) equals just p(Q) - at least, relative to the group P.
The old p(Q), the frequency of

"things that have property Q within the entire sample",

is revised to the new frequency of

"things that have property Q within the subsample of things that have property P".

If P is given, if P is our entire world, then looking for Q&P
is the same as looking for just Q.