How Big is the Market?

Posted on Friday, February 7, 2014

Mari kita lihat data dari Google trends Indonesia 

Yang mengagetkan saya, hal-hal berbau CPNS, Pegawai negeri, Badan Kepegawaian, muncul sebagai trend. 

Market ada di: CPNS, Bola (Sport), Games, News, Gossip & Entertainment.

Ide: membuat sesuatu yg berhubungan dengan cpns atau bola.

 ardikartax:

TEAMO
We are not in a hurry to build this company.But our brain is always hungry. And our heart is forever passionate.

BOOM!

ardikartax:

TEAMO

We are not in a hurry to build this company.
But our brain is always hungry. And our heart is forever passionate.

BOOM!

 (via purityofislam) :

Ar-Rahman

(via purityofislam) :

Ar-Rahman

Java New Generation Concurency API

Posted on Monday, May 14, 2012

Pasti sering menggunakan Download Accelerator kan? Dibalik layar aplikasi jenis ini melakukan proses download dengan cara memecah tugas download 1file menjadi beberapa bagian (task). Kemudian disiapkan beberapa pekerja (thread) yg menampung tugas-tugas tadi tanpa menunggu satu selesai baru yg lainnya jalan (non blocking) tapi langsung dijalankan secara bersama-sama. Hasil dari masing-masing thread akan digabungkan lagi menjadi 1 file utuh.

Java telah lama memiliki implementasi solusi seperti kasus tadi dengan Java Thread API. Java old Thread API, bukannya ga bagus, tapi “Is There a Reason to Use the Old Threading API?” ketika sejak Java 5 telah diciptakan Pustaka sakti yg dilupakan banyak org: Java New Generation Concurency API.

Lupakan jelimetnya berurusan dengan keyword ini di Thread: wait, notify, synchronize, join. Mari berkenalan dengan Pustaka Sakti generasi terbaru!

Contoh kasus aplikasi Currency Converter, aplikasi ini akan menghitung kurs beberapa mata uang terhadap USD.

Berikut ini fungsi yg digunakan untuk mendapatkan nilai kurs terharap USD melalui Yahoo Finance, sesuai dengan mata uang yg ingin dicari :

private HashMap getRates(String ccy) throws Exception {

	URL url = new URL("http://finance.yahoo.com/d/quotes.csv?e=.csv&f=sl1d1t1&s=USD"
					+ ccy + "=X");
	BufferedReader reader = new BufferedReader(new InputStreamReader(
			url.openStream()));

	String data = reader.readLine();
	String[] dataItems = data.split(",");
	Double rate = Double.valueOf(dataItems[1]);
	HashMap ccyRate = new HashMap();
	ccyRate.put("CCY", ccy);
	ccyRate.put("RATE", rate);

	return ccyRate;
}

Saya akan mulai dengan Strategi yg pertama, dengan Metode Sekuensial (berurutan)

final String[] CURRENCY = new String[] { "IDR", "MYR", "AUD", "SGD", "THB" };

void checkRateSequential() throws Exception {

	System.out.println("checkRateSequential :");
	long start = System.nanoTime();
	for (String ccy : CURRENCY) {
		HashMap ccyRate = getRates(ccy);
		System.out.println("Value of $1 in " + ccy + " is " + ccyRate.get("RATE"));
	}

	long end = System.nanoTime();
	System.out.println("Time (seconds) taken " + (end - start) / 1.0e9);
}
checkRateSequential :
Value of $1 in IDR is 9218.0
Value of $1 in MYR is 3.0717
Value of $1 in AUD is 0.9976
Value of $1 in SGD is 1.2526
Value of $1 in THB is 31.193
Time (seconds) taken 14.404746959

Metode ini paling umum digunakan, aplikasi akan melakukan request berulang-ulang berurutan untuk mendapatkan nilai kurs, satu request selesai baru request yg lain dijalankan (blocking IO), sampai selesai.
Dengan metode ini hanya ada satu proses IO yg berjalan. Sayang banget, CPU udah multicore, internet udah ngebut kok disia-siakan resource yg ada ?
Ok, Strategi berikutnya, Menjalankan beberapa request sekaligus secara bersamaan. Saya akan gunakan pustaka sakti Java Concurent API

void checkRateAllAtEnd() throws Exception {
	System.out.println("checkRateAllAtEnd :");
	long start = System.nanoTime();
	
	ExecutorService executorPool = Executors.newCachedThreadPool();

	List<Callable> tasks = new ArrayList<Callable>();
	for (final String ccy : CURRENCY) {
		tasks.add(new Callable() {
			public HashMap call() throws Exception {
				return getRates(ccy);
			}
		});
	}
	final List<Future> listRates = executorPool.invokeAll(tasks, 3600, TimeUnit.SECONDS);
	
	for (Future rate : listRates) {
		HashMap ccyRate = rate.get();
		System.out.println("Value of $1 in " + ccyRate.get("CCY") + " is " + ccyRate.get("RATE"));
	}
	
	executorPool.shutdown();
	
	long end = System.nanoTime();
	System.out.println("Time (seconds) taken " + (end - start) / 1.0e9);
}
checkRateAllAtEnd :
Value of $1 in IDR is 9218.0
Value of $1 in MYR is 3.0717
Value of $1 in AUD is 0.9976
Value of $1 in SGD is 1.2526
Value of $1 in THB is 31.193
Time (seconds) taken 3.782909569

Wow, ada penambahan kecepatan hingga lebih dari 3 kali lipat! Dengan memanfaatkan Pustaka Concurency, aplikasi dapat melakukan beberapa request sekaligus secara bersama-sama. Tidak perlu harus nganggur menunggu task yg satu selesai.
Penjelasan singkat mengenai penggunaan Java Concurency diatas:

ExecutorService executorPool = Executors.newCachedThreadPool(); 

Membuat Object Executor yg akan menjalankan task request. Executor ini sebagai tempat penampung beberapa thread (pekerja keras nan gigih yg siaga), diatas saya memakai “newCachedThreadPool” dengan ini Java akan secara otomatis membuat beberapa thread sesuai kebutuhan dan kemampuan sistem, jika sudah tidak aktif akan kembali ke pool.
Namun apabila ingin menentukan secara manual berapa jumlah thread yg diinginkan, bisa menggunakan ini “Executors.newFixedThreadPool(10)” tapi pastikan jangan sampai jumlah thread lebih kecil dari jumlah core CPU (ya iya lah!)

List<Callable> tasks = new ArrayList<Callable>();
for (final String ccy : CURRENCY) {
	tasks.add(new Callable() {
		public HashMap call() throws Exception {
			return getRates(ccy);
		}
	});
}

Pada baris ke-1 difungsikan untuk menampung task yg akan dikerjakan oleh executor. Untuk itu perlu di isi, task apa aja yg ingin dijalankan. List ini harus berisi daftar object Callable, yaitu object yg mengimplement interface Callable. Object dengan interface Callable memiliki method call() yg nantinya akan dijalankan oleh pekerja-pekerja keras yg ngantor di Executor!

List<Future> listRates = executorPool.invokeAll(tasks, 3600, TimeUnit.SECONDS);

Eksekusi seluruh task yg ada tidak boleh lebih dari 3600 detik, jika lebih maka pekerjaan dihentikan (timeout)

for (Future rate : listRates) {
	HashMap ccyRate = rate.get();
	System.out.println("Value of $1 in " + ccyRate.get("CCY") + " is " + ccyRate.get("RATE"));
}	

Objek Future disini merupakan representasi hasil dari object yg akan di hasilkan oleh thread yg mengeksekusi task. Java bisa memprediksi masa depan, hoho :)
Jadi for looping disini bertugas untuk mengumpulkan hasil dari masing-masing thread yg telah susah payah bekerja tidak boleh lebih dari 3600 detik tadi! Mudah bukan? gampang digunakan dan enak dibaca.

Nah ada lagi satu strategi yg akan saya perkenalkan. Metode diatas mengumpulkan hasil dari masing-masing thread secara berurutan dari thread yg pertama ke yg terakhir, Apa yg terjadi jika thread terakhir ternyata lebih berotot sehingga dia lebih dulu selesai ? Harusnya dia yg dapat medali penghargaan kan ?
Dengan Strategi ini, siapa thread yg duluan selesai dia yg akan diambil langsung hasilnya, jadi ga bisa diprediksi dengan pasti urutannya, tergantung kekuatan otot masing-masing pekerja!! haha.

void checkRateAsItComplete() throws Exception {
	System.out.println("checkRateAsItComplete :");
	long start = System.nanoTime();
	
	ExecutorService executorPool = Executors.newCachedThreadPool();
	CompletionService compService = new ExecutorCompletionService(executorPool);
	
	for (final String ccy : CURRENCY) {
		compService.submit(new Callable() {
			public HashMap call() throws Exception {
				return getRates(ccy);
			}
		});
	}
	
	
	for (int i=0; i<CURRENCY.length; i++)
		future = compService.take();
		HashMap ccyRate = future.get();
		System.out.println("Value of $1 in " + ccyRate.get("CCY") + " is " + ccyRate.get("RATE"));
	}
	
	executorPool.shutdown();

	long end = System.nanoTime();
	System.out.println("Time (seconds) taken " + (end - start) / 1.0e9);

checkRateAsItComplete :
Value of $1 in MYR is 3.0717
Value of $1 in SGD is 1.2526
Value of $1 in AUD is 0.9976
Value of $1 in THB is 31.193
Value of $1 in IDR is 9218.0
Time (seconds) taken 3.933620191

Waktu yg dicapai ga jauh beda dengan strategi sebelumnya, agak lebih lama dikit, lihat juga urutan selesai disini gak beraturan MYR diurutan pertama sedangkan IDR posisi buncit :( Tapi ini karena contoh kasus dengan data yg simple, bukan data ribuan, puluhan ratusan ribu, strategi ini tentu lebih cepat. Dimana thread yg telah selesai bekerja harus langsung balik ke pool (Executor) untuk menjalankan task berikutnya yg udah ngantri di pool.

CompletionService compService = new ExecutorCompletionService(executorPool);

for (int i=0; i<CURRENCY.length; i++) {
	Future future = compService.take();
	HashMap ccyRate = future.get();

Perbedaannya ada disini, gunakan jurus ajaib CompletionService. Lalu perhatikan for looping nya tidak menggunakan ordered list tapi menyerahkan kepada aplikasi, thread mana yg lebih dulu selesai, dialah yg akan diambil. Ini baru Fair!

Baris kode lengkap yg telah digabungkan menjadi satu class dapat di lihat disini   https://gist.github.com/2689054

Scrapy + Selenium + Headless Firefox

Posted on Friday, June 24, 2011

Scrapy is a fast high-level screen scraping and web crawling framework, used to crawl websites and extract structured data from their pages. It can be used for a wide range of purposes, from data mining to monitoring and automated testing

Selenium Remote Control is a client/server system that allows you to control web browsers locally or on other computers, using almost any programming language and testing framework

Scrapy memiliki kekurangan, yaitu ketidakmampuannya untuk scraping web yang mengharuskan adanya pemanggilan fungsi javascript, satu-satunya cara adalah dengan menggunakan Selenium

Jalankan Selenium-rc :

$ java -jar selenium-server-standalone-2.0rc2.jar

Buat file: test_selenium.py

from selenium import selenium
from scrapy.spider import BaseSpider
from scrapy.http import Request
import time
import lxml.html

class SeleniumSprider(BaseSpider):
    name = "selenium"
    allowed_domains = ['selenium.com']
    start_urls = ["http://localhost"]
    
    def __init__(self,  **kwargs):
        print kwargs
        self.sel = selenium("localhost", 4444, "*firefox","http://selenium.com/")
        self.sel.start()
    
    def parse(self, response):
        sel = self.sel
        sel.open("/index.aspx")
        sel.click("id=radioButton1")
        sel.select("genderOpt", "value=male")
        sel.type("nameTxt", "irfani")
        sel.click("link=Submit")
        time.sleep(1) #wait a second for page to load
        root = lxml.html.fromstring(sel.get_html_source())

Lalu eskekusi

$ ./python test_selenium.py

Namun menjadi menjengkelkan jika setiap kali menjalankan script selenium akan membuka browser firefox untuk mensimulasikan perintah yg ada di script tsb.
Maka gunakan virtual framebuffer untuk mematikan window firefox. Jalankan perintah ini :

$ sudo aptitude install xvfb
$ sudo aptitude install xfonts-100dpi xfonts-75dpi xfonts-scalable xfonts-cyrillic
$ sudo mod u+s `which Xvfb`
$ Xvfb :99 -ac &
$ xclock -display :99 &
$ xwd -out xfvbtest.xwd -root -display :99
$ xwud -in xfvbtest.xwd

Jalankan Selenium-rc :

$ DISPLAY=:99 java -jar selenium-server-standalone-2.0rc2.jar

Maka setiap kali script dijalankan selenium tidak akan membuka window firefox tapi sebenarnya menjalankannya dibelakang layar (virtual)

40 Lines URL Shortener App

Posted on Wednesday, May 4, 2011

Here is my another 40 lines simple ruby app, URL Shortener App.
I use a Base 62(0-9, A-Z, a-z) numbering system to represent the row id. And Fortunately, Ruby already has a library for it, The alphadecimal gem :)

%w(sinatra dm-core dm-migrations haml alphadecimal uri).each { |lib| require lib}

get '/' do haml :index end	

get '/:url' do redirect Url.first(:id => params['url'].alphadecimal).origin end

post '/' do
  uri = URI::parse(params['origin'])	
  raise "Invalid URL" unless uri.kind_of? URI::HTTP or uri.kind_of? URI::HTTPS
  @url = Url.first_or_create(:origin => uri.to_s)
  haml :index
end

class Url
  include DataMapper::Resource
  property :id, Serial
  property :origin, String
  
  def alias() self.id.alphadecimal end
end

configure do
  DataMapper.setup(:default, "sqlite:///development.sqlite3")
  DataMapper.auto_migrate!
end

__END__

@@ index
%html
	%head
		%title Klik - Url Shortener App
	%body
		%h1 Klik - Url Shortener App
		- unless @url.nil? 
			%code= @url.origin
			%a{:href => env['HTTP_REFERER'] + @url.alias}= env['HTTP_REFERER'] + @url.alias
		%form{:action => '/', :method => 'POST'}
			%input{:type => 'text', :name => 'origin'}
			%input{:type => 'submit', :value => 'Pendekin!'}
 Hello guys, its been a while since i last blogged about coding related stuff.Now, I&#8217;d like to show you How simple and fun The Ruby Programming Language is.
I wrote Todolist with Sinatra (web framework) + DataMapper (db persistent) + Haml (view template) The total number of lines is just only 41, in a single file including the view  template :)
require 'sinatra'
require 'dm-core'
require 'dm-migrations'
require 'haml'

class Todo
  include DataMapper::Resource
  property :id, Serial
  property :text, String
end

configure do
  DataMapper.setup(:default, "sqlite:///development.sqlite3")
  DataMapper.auto_migrate!
end

get '/' do
  @todos = Todo.all
  haml :index
end

post '/' do
  Todo.create(:text =&gt; params['todo'])
  redirect '/'
end

__END__

@@ index
!!!
%html
	%head
		%title Todo
	%body
		%h1 Todo
		%ul
		-	@todos.each do |todo|
			%li= todo.text
		%form{:action =&gt; '/', :method =&gt; 'POST'}
			%input{:type =&gt; 'text', :name =&gt; 'todo'}
			%input{:type =&gt; 'submit', :value=&gt; 'Todo!'}

Hello guys, its been a while since i last blogged about coding related stuff.
Now, I’d like to show you How simple and fun The Ruby Programming Language is.

I wrote Todolist with Sinatra (web framework) + DataMapper (db persistent) + Haml (view template) The total number of lines is just only 41, in a single file including the view template :)

require 'sinatra'
require 'dm-core'
require 'dm-migrations'
require 'haml'

class Todo
  include DataMapper::Resource
  property :id, Serial
  property :text, String
end

configure do
  DataMapper.setup(:default, "sqlite:///development.sqlite3")
  DataMapper.auto_migrate!
end

get '/' do
  @todos = Todo.all
  haml :index
end

post '/' do
  Todo.create(:text => params['todo'])
  redirect '/'
end

__END__

@@ index
!!!
%html
	%head
		%title Todo
	%body
		%h1 Todo
		%ul
		-	@todos.each do |todo|
			%li= todo.text
		%form{:action => '/', :method => 'POST'}
			%input{:type => 'text', :name => 'todo'}
			%input{:type => 'submit', :value=> 'Todo!'}

The World’s First Batik Train

Posted on Sunday, May 1, 2011

This train is the first batik train in the world!! cool

Bandung - West Java - Indonesia

(Source: hasnatsaniya.blogspot.com)

Risih dengan penulisan nilai mata uang dollar di Media

Posted on Monday, April 18, 2011

http://investasi.kontan.co.id/v2/read/1302851098/64979/Kuartal-I-2011-penjualan-alat-berat-INTA-lampaui-total-penjualan-tahun-lalu

"Perkiraan nilai total penjualan US$ 167 juta,” kata Fred, Jumat (15/4).
INTA tahun lalu mencatat lonjakan pendapatan sebesar 55% menjadi Rp 1,8 triliun dan laba bersih melesat 121% menjadi Rp 83 miliar dibandingkan 2009.
Tahun ini perseroan menargetkan pendapatan naik 63% menjadi US$ 2,9 triliun dibandingkan 2010. Sementara itu, laba bersih 2011 ditargetkan naik 88% menjadi US$ 155,8 miliar dibandingkan tahun lalu.

Sudah terlalu lama unek-unek ini ingin diungkapkan, sejak bertahun-tahun yg lalu (sejak saya mulai *serius* membaca berita anggap saja 10 thn yg lalu).

Read More
 

(Source: her-shade)