Google Apps Script for Fun and Profit

Saya suka membaca, buku, artikel, blog, notes dll, untuk blog saya biasa menggunakan google reader dan setelah di shutdown, saya berpindah menggunakan feedly, ada lebih dari seratus sumber berita saya subscribe (meskipun tidak selalu saya baca semua artikelnya). Saya juga senang sekali kalau ada yang mengirimkan artikel-artikel menarik melalui email karena tentu saja pengirim info tersebut telah memilihkan berita atau informasi yang menarik bagi saya. Hal tersebut yang dilakukan oleh salah seorang manager senior di kantor.

Karena beliau relatif sering mengirimkan artikel tersebut, saya berfikir untuk menyimpan artikel-artikel tersebut di google site saya, sehingga saya bisa mengaksesnya sewaktu-waktu dengan mudah. Oleh karena itu saya membuat script sederhana untuk mengambil artikel tersebut dan menyimpannya di google site dengan menggunakan google apps script. Menggunakan google apps script ternyata sangat mudah, berikut script yang saya buat:

/**
 * Retrieves all inbox and post body email from pak Soegi with subject: "fyi" to google sites
 * https://sites.google.com/a/kaskusnetworks.com/hakim/home/articles
 * For more information on using the GMail API, see
 * https://developers.google.com/apps-script/class_gmailapp
 */
function processInbox() {
  Logger.log("start reading inbox");
  // get top 50 inbox (assuming no more than 50 threads within a day)
  // sort it based on first message date, since sometimes old thread goes up because of new message/reply
  // it make sure that only latest message read and posted to google site
  var threads = GmailApp.getInboxThreads(0, 50).sort(function(thread1, thread2){
    return thread2.getMessages()[0].getDate().getTime() - thread1.getMessages()[0].getDate().getTime();
  });
  
  var day_in_miliseconds = 86400000; // 24*60*60*1000
  if (threads.length > 0){
    for (var i = 0; ; i++) {
      // get all messages in a given thread
      var thread = threads[i];
      var firstmessage = thread.getMessages()[0];
      var firstmessagedate = firstmessage.getDate()
      var now = new Date();
      // only check for past 24 hour email
      if ((now.getTime() - firstmessagedate.getTime()) <= day_in_miliseconds){
        var messages = thread.getMessages();
        // log message subject
        var message = messages[0]; // we only care for the first message
        Logger.log(message.getFrom() + " subject: "+ message.getSubject())
        if (message.getSubject().trim() == "fyi" && message.getFrom().indexOf("soegi") > 0){
          var date = message.getDate()
          // post to google sites
          var fyi = "<strong>" + date.toLocaleDateString() + "</strong><br/>"+message.getBody();
          addArticlesToPage(fyi);
        }
      }else{ // outdated message
        break;
      }
    }  
  }
  
};

function addArticlesToPage(fyi){
  var domain = 'kaskusnetworks.com';
  var sitenya = 'hakim';
  var site = SitesApp.getSite(domain, sitenya);
  var page = SitesApp.getPageByUrl("https://sites.google.com/a/kaskusnetworks.com/hakim/home/articles");
  var content = page.getHtmlContent();
  // append content
  content = content.replace("</div></td>","<br/>"+fyi+"</div></td>");
  page.setHtmlContent(content);
}

selanjutnya saya tinggal menentukan trigger yang akan mengeksekusi fungsi tersebut (semcam membuat cron jobs). akhirnya halaman google sites saya akan selalu terupdate dengan link-link informasi menarik yang dikirimkan kepada saya. Dan di akhir pekan, saya bisa membaca semua link-link tersebut dengan santai.

happy scripting :)

Your time is your Life

Your time is your life, and your life is your capital: by it you make your tread, and by it you will reach the eternal bounties in the proximity of Allah.
Every single breath of yours is a priceless jewel, because it is irreplaceable; once it is gone, there is no return for it. So do not be like the fools who rejoice each day as their wealth increases while their live decrease.
What good is there in wealth that increases while one’s lifespan decreases? Do not rejoice except in an increase of knowledge or an increase of good works. Truly they are your two friends who will accompany you in your grave, when your spouse, your wealth, your children, and your friends will remain behind. ~ Imam Ghazali

Mengenal Observer Pattern

Ayah hampir setiap hari kerja pergi ke kantor di pagi hari sampai sore/maghrib, ketika sampai rumah Bunda dan Ahmad menyambut ayah dengan menjemput di pintu masuk rumah dan bersalaman. Di sore hari, Bunda dan Ahmad selalu memperhatikan kalau ada suara salam di depan pintu, kalau ayah yang salam, berarti bunda dan Ahmad akan segera bersalaman dengan ayah.

Disini status ayah observable, yang di observe oleh Bunda dan Ahmad yang menjadi Observer.


import java.util.*;

public class Ayah extends Observable implements Runnable{
	private boolean pulang = false;

	public Result kerja(){}

	public void run(){
		while (!pulang){
			kerja();
		}
		setChanged();
		notifyObservers(OlehOleh);
	}
}


public class Bunda implements Observer{
	@Override
	public void update(Observable Observable, Object data){
		if (Observable instanceof Ayah){
			jemputAyahDiPintu();
			salimDenganAyah();
			pelukAyah();
			if (data != null && data instanceof OlehOleh){
				terima(data);
			}
		}
	}
}

public class Anak implements Observer{
	@Override
	public void update(Observable Observable, Object data){
		if (Observable instanceof Ayah){
			jemputAyahDiPintu();
			salimDenganAyah();
			mintaDipangkuAyah();
			if (data != null && data instanceof OlehOleh){
				terima(data);
			}
		}
	}
}

public class Kelurga{
	public static void main(String[] args) {
		Ayah ayah = new Ayah();
		Bunda bunda = new Bunda();
		Anak ahmad = new Anak();
		ayah.addObserver(bunda);
		ayah.addObserver(ahmad);

		ayah.start();
	}
}

baca juga ini: http://en.wikipedia.org/wiki/Observer_pattern

happy coding :)

Cara Mem-follow github organization

Meskipun secara default di web github saya ga bisa follow sebuah organisasi, tapi ternyata saya bisa follow dengan cara yang mudah. Karena pada dasarnya sebuah akun organization mirip dengan user biasa. caranya begini:

saya pakai google chrome,

  1. buka halaman yang hendak di follow misalnya Kaskus di https://github.com/kaskus/ , pastikan kamu sudah login di github.
  2. habis itu bukan Inspect element/developer tools (Cmd + option + i)
  3. di console ketik perintah berikut
    $.post("https://github.com/users/follow?target=kaskus");

    enter

nah, sekarang setiap kali kaskus membuat project baru, di dashboard githubmu bakal ada infonya. Kalau kamu ingin memfollow organisasi lain, cara yang sama bisa dilakukan.

Aplikasi Rumah Fiqih (2) : Overview Aplikasi

Aplikasi Rumah Fiqih versi terbaru saya kembangkan dengan menggunakan IDE Android Studio (beta version). Meski memiliki kekurangan utama waktu build yang masih relatif lambat (mungkin karena masih versi beta), Saya menyukai Android studio karena kita bisa membuat Flavor untuk aplikasi yang kita buat. Dengan menentukan flavor ini saya bisa membuat beberapa versi aplikasi dengan package yang berbeda dalam satu basecode/project yang sama.

    productFlavors{
        admin{
            applicationId "com.hakimlabs.rumahfiqih.admin"
        }
        publik{
            applicationId "com.hakimlabs.rumahfiqih"
        }
    }

Aplikasi Rumah Fiqih ini saya buat dengan dua flavor, yaitu versi publik dan versi admin. Versi publik adalah versi yang tersedia di Google Play Store sedangkan versi admin masih saya sendiri yang menggunakannya. Versi admin pada dasarnya sama dengan versi publik, hanya saja saya menambahkan menu yang memungkinan saya untuk meng-instantiate push notification dari aplikasi. Disamping itu, di versi admin ini saya juga melakukan experimen fitur-fitur yang nantinya bakal saya masukkan ke dalam versi publik.

project structure

Pengembangan aplikasi ini sangat terbantu dengan beberapa project open source, yaitu:
1. Picasso
Picasso adalah library untuk menampilkan image yang dibuat oleh Square Inc. Picasso ini saya pergunakan untuk menampilkan foto ustadz, dan juga snapshot video dari youtube.

	String snapshotUrl = fikrah.getYoutube().substring(fikrah.getYoutube().lastIndexOf("/")+1);
    snapshotUrl = "http://img.youtube.com/vi/"+snapshotUrl+"/0.jpg";
	Picasso.with(mContext).load(snapshotUrl).into(viewHolder);

2. Retrofit
Sebagaimana Picasso, Retrofit juga dibuat oleh developer-developer cerdas yang ada di perusahaan yang didirikan oleh salah satu founder twitter tersebut. Retrofit ini membuat implementasi API client jauh lebih mudah.
contohnya untuk endpoint:
url: API_URL/konsultasi/:kategori/:paging/:page
http method: GET
kita tinggal mendeklarasikan sebuah interface

    @GET("/konsultasi/{kategori}/{paging}/{page}")
    public List<KonsultasiSyariah> getKonsultasiKategori(@Path("kategori") int kategori, @Path("paging") int paging,
            @Path("page") int page);

den mengexecute-nya:

	restAdapter = new RestAdapter.Builder().setEndpoint(API_URL).setErrorHandler(errorHandler)
				.build();

	rumahfiqih = restAdapter.create(IRumahFiqih.class);

	.....
	public List<KonsultasiSyariah> getKonsultasiKategori(int kategori, int paging, int page) {
        return rumahfiqih.getKonsultasiKategori(kategori, paging, page);
    }

3. ListViewAnimations
Ini untuk memberikan animasi saat listview di scroll ke bawah.

4. Crouton
Saya tidak lagi menggunakan Toast untuk menampilkan error message karena berbagai isue. Penggantinya adalah crouton yang akan menampilak error message dengan lebih baik. Penggunaan crouton ini mulai banyak dipakai ketika Cyril Mottier membuat blog tentang ini di sini.

Dengan berbagai library di atas, pengembangan aplikasi Rumah Fiqih jadi jauh lebih cepat dan mudah.

Face detection dengan OpenCV

Saya suka sekali belajar sesuatu yang baru. Beberapa waktu yang lalu saya mulai belajar bahasa pemrograman Python. Python sangat menarik bagi saya karena dia scripting languange yang secara default sudah keinstall di OS X, jadi sewaktu waktu saya butuh simple programming, selain dengan shell script saya bisa langsung menggunakan Python. Ketertarikan saya ini berlanjut dengan mencoba menggunakan Pandas, python library/modules yang bisa kita gunakan untuk data (big atau small) analysis. Dan akhirnya, saya mencoba python untuk face detection dengan python opencv module. dengan menggunakan tutorial di sini, saya membuat simple script seperti ini:

import numpy as np
import cv2

face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier('haarcascade_eye.xml')
nose_cascade = cv2.CascadeClassifier('haarcascade_mcs_nose.xml')
img = cv2.imread('ayahahmad.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

faces = face_cascade.detectMultiScale(gray, 1.3, 5)

for (x, y, w, h) in faces:
	cv2.rectangle(img, (x,y), (x+w, y+h), (255, 0, 0), 2)
	roi_gray = gray[y:y+h, x:x+w]
	roi_color = img[y:y+h, x:x+w]
	eyes = eye_cascade.detectMultiScale(roi_gray)
	for (ex, ey, ew, eh) in eyes:
		cv2.rectangle(roi_color, (ex, ey), (ex+ew, ey+eh), (0, 255, 0), 2)

	nose = nose_cascade.detectMultiScale(roi_gray)
	for (nx, ny, nw, nh) in nose:
		cv2.rectangle(roi_color, (nx, ny), (nx+nw, ny+nh), (0, 0, 255), 2)

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

disini saya mencoba medeteksi wajah, sepasang mata dan juga hidung dengan metode Haar Cascades Classifier. OpenCV sudah menyediakan training classifier dalam format xml, jadi saya tinggal menggunakannya saja sebagaimana terlihat di source code di atas. Berikut hasil eksekusi dari script tersebut: Ayah dan Ahmad wah, ternyata mata Ahmad yang lagi menyipit tidak terdeteksi :)
kotak biru adalah bagian yang dideteksi sebagai wilayah wajah, kotak hijau adalah mata dan kotak merah adalah hidung.

Ahmad sedang sakit 3 hari ini, semoga lekas sembuh ya nak. Aamiin :'(

Pengembangan Aplikasi Rumah Fiqih (1): Server Side

Saya memanfaatkan sebagian waktu di bulan Ramadhan ini untuk memperbarui aplikasi Rumah Fiqih. Pembaruan ini meliputi perubahan disain yang semula menggunakan navigation drawer dirubah menjadi tab, penambahan fitur push notification serta penambahan tampilan banner iklan.

Perubahan dari navigation drawer ke model tab sejatinya di pengaruhi oleh disain facebook yang terbaru yang membuang sidemenu dan juga Google+ Apps yang tidak lagi menggunakan navigation drawer. Pertimbangan perubahan navigasi dari navigation drawer ke tabs ini juga karena saya melihat aplikasi Rumah Fiqih ini hanya memiliki sedikit menu (tiga buah yaitu: Fikrah, Konsultasi Fiqih dan Video), sehingga akan lebih cocok ditempatkan di tempat yang jelas (obvious) yang memudahkan bagi user untuk melakukan navigasi dari satu menu ke menu yang lain. Pertimbangan yang sama juga saya gunakan untuk menggunakan ViewPager untuk navigate antar menu dengan metode swipe.

Push notification saya tambahkan juga karena memang artikel rumah fiqih pada dasarnya tidak selalu muncul tiap hari, jadi saya berharap jika di hari tertentu artikel muncul pengguna aplikasi ini dapat langsung membacanya. Untuk server side saya menggunakan PHP yang sekaligus sebagai server API untuk aplikasi ini.

Arsitektur Server Side Rumah Fiqih App

Arsitektur Server Side Rumah Fiqih App

Saya menggunakan webserver apache karena kebanyakan hosting di Indonesia (yang murah meriha) menggunakan server ini. dan MySQL saya pilih sebagai database-nya karena saya sudah cukup terbiasa dengan MySQL. Untuk server side programming language, saya menggunakan PHP. Meskipun bukan bahasa pemrograman sehari-hari yang saya gunakan, PHP ini relatif mudah, Disamping memang hosting yang saya gunakan hanya support PHP :).
Dengan PHP ini saya membuat RestFull API dengan menggunakan Slimframework dan custom crawler.

Penambahan terakhir adalah banner dengan menggunakan AdMob terbaru yang menggunakan Google Play Service.

Aplikasi ini memang sederhana, tapi semoga bermanfaat bagi kita semuanya. aamiin :)
Yuk, download aplikasinya langsung melalui link berikut:

Get it on Google Play