Mojolicious I18N and po file

22 August 2014

The example in Mojolicious::Plugin::I18N is that you put all your translations into our %Lexicon.

but sometimes you got .po files from standard I18N tools like gettext. in that case you can do something like below to do the trick.

just create MyApp::I18N

package MyApp::I18N;

use base 'Locale::Maketext';
use File::Basename qw/dirname/;
use Locale::Maketext::Lexicon {
    _auto => 1,
    _decode => 1,
    '*' => [Gettext => dirname(__FILE__) . '/I18N/*.po']


that’s all you need do. the path above is using lib/MyApp/I18N/*.po, you can change it to somewhere that you put the .po files.

another point is that if you want just do [% l(‘Hello’) %] instead of [% c.l(‘Hello’) %] in TT2, you just put

$c->render(template => 'template_name', handler => 'tt', l => sub {

That’s it. Enjoy!

Chrome Extension: qiandao

12 May 2014

It’s just another chrome extension I developed in last few days. it uses content_scripts of Chrome. add hooks after visiting the related pages. and get the cookie/token to post Ajax request for signup/qiandao.

the code is available at


have fun.

RSA Encrypt in Java Decrypt in Perl: keyczar rocks

23 April 2014

I have been struggling with Java RSA decrypt for a long time last night until I meet keyczar

the case is that we developed an API login which is used in a mobile App. but it’s quite insecure to pass the plain password directly to server. so it must be encrpyted in Java (Android App) then post to the Perl API.

the Java is using something like below to encrypt the pass Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, key); return cipher.doFinal(data);

then decrypt with Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.DECRYPT_MODE, key); return cipher.doFinal(cipherData);

it was a nightware to find equivalent code in Perl. RSA+EBC+PKCS1Padding, no luck with a lots of RSA modules tried.

until I found the Crypt::Keyczar. it saves a lot. the author wrote a very good file to do the Java magic. with the make running, you got a crypt-rsa and crypt-rsa-pub created. actually it’s done by KeyczarTool

create --location=crypt-rsa --purpose=crypt --asymmetric=rsa addkey --location=crypt-rsa --status=primary pubkey --location=crypt-rsa --destination=crypt-rsa-pub

after that, we encrypt the string in Java with code like: ``` import org.keyczar.*;

public class demo { public static void main(String[] args) throws Exception { KeyczarFileReader reader = new KeyczarFileReader(“./crypt-rsa-pub”); try { Encrypter crypter = new Encrypter(reader); System.out.print(crypter.encrypt(“hello”) + “\n”);

    } catch (org.keyczar.exceptions.KeyczarException e) {
} } ```

sample output: $ export CLASSPATH="log4j.jar:gson.jar:keyczar.jar:." $ javac $ java demo AG1jZrM2CFMhPpNegCx5jletymyJ_9-DlkIgigYo83WCiF6tkTRpotg754LRIjy8ILMSA6Q4AMTg0YD7EgiI6S2rLE1r9lwOYIc0E84tKSWJ3tw0QEBeCLPwuotZbHB92K2Dkuylp3dsP3ESG7rD_RLQylITssyUgNmzdDOGNfmLRJE9XSvJMw3jov3unvLp0iBsK5E71ntsU56kRRXGAI37-tRxo3mmcQZkkozdrS_2p0QZ4zQ08rjCYbCMlrl_xdMlOB3fd1y-HujLHzYID0lb83gW_o5pX2gurldU0-nB2bitgH21pQuPRQz1qEy5zW1TLkOkDX66uqIowHA08R-ueWKSwkm72MbdWvdUmuA-NtkY7IJ-1wRW6HWRaSqbIo3Hz3uPp3j2FfXlNsxtnfdFgV5Hhh348oIjzTE7AGhXSfBE9KB8S0lHGFIxXEc3I43ZIt4gNBbn_nNwhLjzn5hmE_OrlGPKNsoALwLMDGzFQfh7IXfGQmKISfobr5YVv-3ZDes3et8zIEQX9X4iEKLPtX4Jw1qNxFRi715kpXjim1fkya9SjNOYAvwul_Ql16Uvzr2xM0ohip4RuEXNkuqqyLxoF8pS0ISexHiBKLbD23rJy-ZjUPxJa6zXHUW4Fx8r2VPW-03xW5QCxekG1-1zqdUVL9jHti19ObZOzsSjSZ4X9w

with Perl code like: ``` use Crypt::Keyczar::Crypter; use FindBin qw/$Bin/;

my $msg = “AG1jZrM2CFMhPpNegCx5jletymyJ_9-DlkIgigYo83WCiF6tkTRpotg754LRIjy8ILMSA6Q4AMTg0YD7EgiI6S2rLE1r9lwOYIc0E84tKSWJ3tw0QEBeCLPwuotZbHB92K2Dkuylp3dsP3ESG7rD_RLQylITssyUgNmzdDOGNfmLRJE9XSvJMw3jov3unvLp0iBsK5E71ntsU56kRRXGAI37-tRxo3mmcQZkkozdrS_2p0QZ4zQ08rjCYbCMlrl_xdMlOB3fd1y-HujLHzYID0lb83gW_o5pX2gurldU0-nB2bitgH21pQuPRQz1qEy5zW1TLkOkDX66uqIowHA08R-ueWKSwkm72MbdWvdUmuA-NtkY7IJ-1wRW6HWRaSqbIo3Hz3uPp3j2FfXlNsxtnfdFgV5Hhh348oIjzTE7AGhXSfBE9KB8S0lHGFIxXEc3I43ZIt4gNBbn_nNwhLjzn5hmE_OrlGPKNsoALwLMDGzFQfh7IXfGQmKISfobr5YVv-3ZDes3et8zIEQX9X4iEKLPtX4Jw1qNxFRi715kpXjim1fkya9SjNOYAvwul_Ql16Uvzr2xM0ohip4RuEXNkuqqyLxoF8pS0ISexHiBKLbD23rJy-ZjUPxJa6zXHUW4Fx8r2VPW-03xW5QCxekG1-1zqdUVL9jHti19ObZOzsSjSZ4X9w”;

my $c = Crypt::Keyczar::Crypter->new(“$Bin/crypt-rsa”); print $c->decrypt(Crypt::Keyczar::Util::decode($msg)) . “\n”; ## print hello ```

pretty neat. many thanks to the author. have fun.

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 => '[email protected]',
  sasl_password => 'mypassword',
my $transport = Email::Sender::Transport::SMTPS->new(
  host => '',
  ssl  => 'starttls',
  sasl_username => '[email protected]',
  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.