Chrome Extension: Findmjob

06 January 2014

I just got my first Chrome Extension published: Findmjob: Push Jobs to You

the basic was created with Extensionizr. it’s a very useful tool.

the source is at

it’s pure javascript. use localStorage to store the options data and transfer data from background.js to browser_action.js (need JSON parse and stringify since it only accept strings.)

Notification is quite simple as below:

var notification = window.webkitNotifications.createNotification(
    '../../icons/icon48.png',            // The image.
    v.title,                       // The title.
    v.title      // The body.
notification.onclick = function() { // Open on click + v.url + '?' + REF_STRING);
// Close after 20 secs
setTimeout(function() {
}, 20 * 1000);

and Badge Text in browserAction:

    text: data.updates.length.toString()

super simple. and works great.


Play with Go Lang

28 December 2013

Well, few days ago I was a bit free and boring, I started to read a Go book online.

you know you’ll get nothing until you start coding, so I started my hack on simplest stuff. always get stroke count of a Chinese character. at last, all the code is at

The whole progress is done by keeping Googling with how to read file with Go, how to replace string, upper case etc. but I’m quite glad that the code is working finally.

the learning is interesting and there are some good points in Go that I like.

  • you can’t import a module but do not use it (well, it’s quite troublesome that I need keep enable fmt for debugging then disable it on publish anyway)
  • import functions are started with upper case. there are traditions/rules everywhere that makes Go faster.

and something I do not like at all.

  • the type system is pretty killing since I am from a Perl background. I’m good with a type system like Python but Go is really quite trouble when there are string, bytes and rune in strconv.
  • the func return is not that … you have to use , _ (to discard the extra values) even we just need one value returned.

Well, it’s from a newbie really. I just read Go for just 3 or 4 hours. so bear with it.


Mojolicious basic_auth and DBIx::Class JSON InflateColumn::Serializer

15 December 2013

Well, it’s very good that you have something to work or hack. yesterday I was working to add some new features to my toy website

I decided to add an admin interface which will use basic_auth to protect.

Mojolicious::Plugin::BasicAuth fits the need well but it does not have a good example really. I do want to put it under a whole site or certain path instead of write it everywhere. so here is the sample code

    $r = $r->under(sub {
        my $self = shift;
        unless ( $self->basic_auth( realm => sub { return 1 if "@_" eq $config->{admin}->{auth} } ) ) {
            $self->render(text => 'Permission Denied.');
            return 0;
        return 1;

another story is for DBIx:Class InflateColumn::Serializer. well, I use DBIx::Class::Schema::Loader to create the Result which means that I can’t hack the add_columns as suggested in the POD. by checking the source, I know I can do it somehow like

use DBIx::Class::InflateColumn::Serializer::JSON;
    data => {
        inflate => DBIx::Class::InflateColumn::Serializer::JSON->get_unfreezer('data'),
        deflate => DBIx::Class::InflateColumn::Serializer::JSON->get_freezer('data'),

but that’s too damn weird and not looks good. so instead, I start writing a patch for that module so that it can be also written as:

__PACKAGE__->set_serialize_column('data', 'JSON');

the patch is here. hope that it can be merged soon.

Happy Hacking.

Updated on Dec 28th

the patch is really not useful. the Author pointed out that we can do it like below:

__PACKAGE__->add_columns('+data', { serializer_class => 'JSON' });

which is much more cleaner. Thanks

evil fake voting: shuapiao

09 December 2013

Some days ago, one of my relatives asks me if I know how to do fake votings. she has a niece who wants to be a cover girl of the calendar.

Yes. I know it’s evil. but as I know, some people are also doing that. so we have no choice somehow.

for fake voting, there are two requirements. one is you need lots of IPs (Tor is not changing IP fastly and not reliable on such task). the other is you need do some decaptcha to prove you’re not a robot (actually that’s a robot).

I won’t tell you how to rent lots of IPs. but the decaptcha service, I recommend the DeathByCaptcha, it’s quite cheap and reliable on most of the time.

I published the code at github, that you can take a look

that’s a simple Perl script, nothing magic. here are few tips:

  • use WWW::UserAgent::Random to change user agent so that it looks like not from one user.
  • use Parallel::ForkManager to do the forks. +1 every minute is not fast, you can’t beat others.

otherwise, all are simple and you’re welcome to use that as a start for a new fake voting script.

have fun.

PHP Composer, Slim Middleware RequireHTTPS

05 December 2013

Well, I’m not a fan or expert of PHP. I do not use PHP a lot and I do not know PHP well.

but when I come to write a PHP website, my first pick is always Slim. it’s very lightweight and fits my needs well.

Today I got a needs to redirect all http to https for a website written by Slim, and come out as a new VERY SIMPLE middleware Slim-Middleware-RequireHTTPS.

the usage is quite simple:

$app = new \Slim\Slim();
$app->add(new \Slim\Middleware\RequireHTTPS());

and that’s all. now all http:// will be redirected to https://

Slim uses composer inside, so I think it’s better put my package as a part of composer too. I spent few minutes to check how to write composer.json (copied from slim one) and get it into the Packagist in next few minutes.

I was amazed by the progress at some points. damn, CPAN is really very old fashion (BUT it works GOOD.).

first, submit a new package is simply type a URL. and it will read all the info from remote composer.json. dead simple.

since that’s git (or other VCS), version is simply supported with –tags. you do git tag -a X.Y and with hook in github repos settings, the version will be shown up in the website immediately. and there is always dev-master which maps to the master source code.

Packagist does not need host any files. when you go composer install/update, it fetches from the remote VCS. really smart idea.

Have fun.


30 November 2013

I just got a new CPAN module released: Email::Sender::Transport::SMTPS

it’s a replacement for Email::Sender::Transport::SMTP::TLS.

the new module uses great Net::SMTPS instead of a little messy Net::SMTP::TLS::ButMaintained

here is few examples from the POD:

my $transport = Email::Sender::Transport::SMTPS->new({
  host => '',
  ssl  => 'starttls',
  sasl_username => '',
  sasl_password => 'mypassword',
my $transport = Email::Sender::Transport::SMTPS->new(
  host => '',
  ssl  => 'starttls',
  sasl_username => '',
  sasl_password => 'api_key',
  helo => '',
my $transport = Email::Sender::Transport::SMTPS->new(
  host => '',
  ssl  => 'starttls',
  sasl_username => 'xx',
  sasl_password => 'zzz',

and you’re welcome to give it a try and provide feedback!


cpan-count nodejs module

17 November 2013

It is my first npm module. it is a nodejs module to get the modules count of one CPAN author thourgh MetaCPAN API. it is quite simple because it’s almost a copy-paste from the gem-count. but at last, it’s still very interesting and fun to learn some nodejs and try npm publish

few points:

  • it takes a while for me to find out the cpan-count api call as
  • I have also contributed a pull request to the author of
  • npm register and publish is so damn simple that I haven’t imagined. sign up on the web costs less than 1 minute. npm adduser costs less than 1 minute. npm publish . costs less than 1 minute. and MY MODULE SHOWS UP AT THE WEBSITE costs less than 1 minute.
  • I like the package.json, I know Perl has META.yml or META.json but package.json has two points I like, one is you do not define version in somewhere else (Perl need write it in the main module also. that’s why dzil is so popular because it saves time.) and it contains keywords. keywords is good for search.

Have fun.

phantomjs/casperjs and qiandao

14 November 2013

Well, qiandao here means Chinese 签到。

that action is boring that you need open browser, login, then click buttons. afterwards, you get some points that you can use it somehow as a little money.

Programming is born for saving you from daily repeating/boring works. and that’s why programming is fun.

I spent few hours to write a casperjs coffeescript today to do the action for the code is quite simple and the result is very interesting. phantomjs or casperjs is born for suck work.

you can take a look of the code at, it’s quite self-explaining. open page, click button, wait until frame shows, type user/pass, then submit. afterwards, just wait until the result shows up. and print it. meanwhile, after collect few 淘金币, it also collects one 集分宝.

crontab it as casperjs /path/to/casperjs-qiandao/ –username=fayland_lam –password=secret

and that’s it. programming does the job for you and it’s reliable.

have fun.

phantomjs/casperjs and google plus new share

10 November 2013

phantomjs is great. the wrapper casperjs is even better.

when surfing around for a Google+ poster as what I did for Twitter/Facebook/Linkedin etc., I find amazing altryne/google-plus-api

it use casperjs and it’s very simple to use.

just one tiny issue, it does not use cookie and logins every time. so I made a small patch for that, and send the pull request to the author.

I’ll merge it into soon. you’ll find fresh job posting on Findmjob Google+.

Have fun.

Perl for JS toString parseInt with radix

07 November 2013

it’s almost a copy-paste from module JE. it’s used in one of my code to parse JS code value with Perl.

sub js_toString {
    my ($num, $radix) = @_;

    return $num unless $radix;
    return $num if ($radix == 10 || $radix < 2 || $radix > 36 || $radix =~ /\./);

    if ($radix == 2) {
        return sprintf('%b', $num);
    } elsif($radix == 8) {
        return sprintf('%o', $num);
    } elsif($radix == 16) {
        return sprintf('%x', $num);

    my $result = '';
    my @_digits = (0..9, 'a' .. 'z');
    while ($num >= 1) {
        substr($result,0,0) =
            $_digits[$num % $radix];
        $num /= $radix;

    return $result;

sub js_parseInt {
    my ($str, $radix) = @_;

    return unless defined $str;
    $radix ||= 0;

    my $s = qr.[\p{Zs}\s\ck]*.;
    $str =~ s/^$s//;

    my $sign = $str =~ s/^([+-])//
        ? (-1,1)[$1 eq '+']
        :  1;
    $radix = (int $radix) % 2 ** 32;
    $radix -= 2**32 if $radix >= 2**31;
    $radix ||= $str =~ /^0x/i
    ?   16
    :   10
    $radix == 16 and
        $str =~ s/^0x//i;

    $radix < 2 || $radix > 36 and return;

    my @digits = (0..9, 'a'..'z')[0..$radix-1];
    my $digits = join '', @digits;
    $str =~ /^([$digits]*)/i;
    $str = $1;

    my $ret;
    if(! length $str){
        $ret = '';
    } elsif($radix == 10) {
        $ret = $sign * $str;
    } elsif($radix == 16) {
        $ret = $sign * hex $str;
    } elsif($radix == 8) {
        $ret = $sign * oct $str;
    } elsif($radix == 2) {
        $ret = $sign * eval "0b$str";
    } else {
        my ($num, $place);
        for (reverse split //, $str){
            $num += ($_ =~ /[0-9]/ ? $_
                : ord(uc) - 55)
                * $radix**$place++
        $ret = $num*$sign;

    return $ret;

say js_parseInt('z', 36); # 35
say js_toString(35, 36);  # 'z'

sub js_fromCharCode {
    my $str = '';
    my $num;
    for (@_) {
        # % 2**16 is buggy in perl
        $num = $_;
        $num = ($num < 0 ? ceil($num) : floor($num))
            % 2**16 ;
        $str .= chr($num == $num && $num);
            # change nan to 0
    return $str;

sub js_charCodeAt {
    my ($str, $pos) = @_;

    if (defined $pos) {
        $pos = int($pos);
        $pos = 0 unless $pos == $pos;

    return ($pos < 0 || $pos >= length $str)
            ? 0
            : ord substr $str, $pos, 1;