Saturday, October 31, 2009

Membangkitkan Bilangan Acak

Terdapat dua fungsi yang dibutuhkan untuk membangkitkan bilangan acak srand() dan rand(). Fungsi srand() dibutuhkan untuk menentukan "bibit" dari bilangan acak yang akan dibangkitkan. Sama seperti kalau kita menanam tumbuhan, bibit yang berbeda tentu akan menghasilkan tambuhan dewasa yang berbeda pula. Sedangkan fungsi rand() digunakan untuk menampilkan bilangan acak yang dihasilkan dari "bibit" yang diberikan ke fungsi srand().

Bentuk umum dari fungsi srand() adalah:

srand(bibit);


Sebagai Contoh:

srand(4);


Bentuk umum dari fungsi rand() adalah:

rand() % n;


Bilangan acak yang dihasilkan oleh fungsi rand() adalah dari 0 s/d (n-1).


Sebagai contoh:
rand() % 10;


Perintah di atas akan menghasilkan bilangan antara 0 s/d 9.

Seperti yang sudah dijelaskan sebelumnya, jika kita menggunakan "bibit" yang sama maka hasil yang diperoleh dari bibit ini pastilah sama. Untuk membuktikan, cobalah menjalankan program berikut berkali-kali dan perhatikan tampilan dilayar:

#include<iostream>
using namespace std;

int main()
{
srand(5);
int data = rand() % 10;
cout << data << endl; cin.get(); }


Agar bisa membangkitkan bilangan yang benar-benar acak, kita harus memberikan "bibit" yang berbeda-beda pula kepada fungsi srand(). Salah satu cara yang bisa dilakukan adalah memberikan "bibit" menggunakan fungsi time(), seperti berikut:


srand(time(NULL));


Sekarang, cobalah jalankan program berikut beberapa kali, dan perhatikan keluaran yang ditampilkan ke layar.


#include<iostream>
using namespace std;

int main()
{
srand(time(NULL));
int data = rand() % 10;
cout << data << endl; cin.get(); }


Fungsi rand() umumnya digunakan untuk membangkitkan bilangan acak yang bertipe bilangan bulat. Cobalah mencari solusi bagaimana membuat bilangan acak "pecahan" antara 0 dan 1 ?

Friday, October 30, 2009

Menampilkan Tabel ASCII

Perhatikan program berikut:



#include <iostream>
using namespace std;

int main()
{
int data = 48;
for(int i=0;i<=9;i++) {
cout << char(data+i) << " ";
}
cout << endl;
}


Program diatas akan menampilkan angka dari 0 s/d 9. Ide dibalik program sederhana di atas adalah menampilkan informasi yang bernilai desimal (48 s/d 57) dalam bentuk karakter ke layar.


Representasi desimal dalam bentuk karakter bisa dilihat pada tabel ASCII.

Program berikut akan menampilkan semua isi tabel ASCII.



#include <iostream>
using namespace std;

int main()
{
for(int i=0;i<=255;i++) {
cout << char(i) << " ";
if(i%15==0) {
cout << endl;
}
}
cout << endl;
}

Thursday, October 29, 2009

Pengenalan Bahasa C++ (Bagian 11)

Di dalam pemrograman berorientasi objek (PBO) umumnya semua variabel/atribut diletakan pada bagian private.

class A
{
private:
int x;
};



Hal ini berarti variabel-variabel ini hanya bisa diakses dari dalam kelas itu sendiri. Misalnya dari dalam salah satu method/fungsi yang berada di dalam kelas.

class A
{
private:
int x;

public:
void fungsi()
{
// variabel x, bersifat private
// jadi hanya bisa dipanggil dari dalam
// kelas A
x = 5;
}

};


penggunaan variabel ini dari luar kelas, misal memanggil dari fungsi main, tidak bisa dilakukan.

int main()
{
A myObjek;
// Error. x bersifat private utk kelas A
myObjek.x = 6;
}



Untuk bisa menggunakan (mengubah atau melihat) sebuah variabel yang bersifat private di dalam sebuah kelas, biasanya dilakukan menggunakan fungsi setter dan getter.

Friday, October 16, 2009

Pengenalan Bahasa C++ (Bagian 9)


Pengantar

Salah satu keunggulan C++ dibandingkan C adalah dukungan yang baik akan Object Oriented Programming (OOP). Saat bekerja dengan OOP, kita pasti akan berhadapan dengan yang dinamakan class karena merupakan template / cetakan dari sebuah objek. Di Ambon, makanan khas kami adalah Sagu. Untuk membuat sagu kami biasanya menggunakan porna. Sagu yang masih mentah, disebut Sagu manta, akan dimasukkan ke dalam porna ini untuk kemudian dibakar. Dari sebuah porna kita bisa memperoleh beberapa buah sagu. Setelah sagu menjadi masak dan disiap dimakan, porna yang sudah dipakai bisa dipakai lagi untuk membuat sagu yang lain. Untuk itu porna bisa juga kita pahami sebagai template / cetakan untuk membuat objek yang disebut Sagu bakar.

Bentuk Umum Sebuah Class

class nama_kelas
{

};

Berikut ini adalah beberapa catatan penting yang perlu diperhatikan dari bentuk umum ini:
  • kata kunci class, menunjukkan bahwa kita hendak membuat sebuah kelas dan harus ditulis menggunakan huruf kecil.
  • nama_kelas adalah nama dari kelas yang hendak kita buat. Sebaiknya nama ini bisa melukiskan fungsi dari kelas tersebut. Sebagai contoh, kita hendak membuat kelas untuk menyimpan data diri dari seorang mahasiswa, maka sebaiknya nama kelas yang digunakan adalah Mahasiswa atau DataMahasiswa. Perlu juga untuk diperhatikan aturan pemberian nama kelas: (1) Selalu dimulai dengan huruf Besar, misal Mahasiswa (2) Jika terdapat lebih dari satu suku kata maka setiap suku kata selalu dimulai dengan huruf besar, misal DataMahasiswa.
  • Jangan melupakan tanda titik koma ';' untuk mengakhiri deklarasi dari sebuah kelas.

Posisi Penulisan Class dan Fungsi Utama

Andaikan kita akan mendeklarasikan kelas di dalam sebuah file yang terdapat fungsi utama, maka struktur program kita adalah sebagai berikut:

#include< …>
#include
using namespace std;

class Mahasiswa
{

};

class Dosen
{

};


int main()
{
//body fungsi utama

return 0;
}

Class Sebagai Tipe Data

Selama ini kita sudah mengenal beberapa macam tipe data seperti int, float, double dll. Kelas juga bisa digunakan sebagai tipe data dari sebuah variable. Sebagai contoh, andaikan kita mempunyai kelas dengan nama Mahasiswa dan kita hendak mendeklarasikan sebuah variabel bertipe Mahasiswa maka penulisannya adalah sebagai berikut:

Mahasiswa mhs;

Pendeklarasian sebuah variabel yang memiliki tipe kelas tertentu bisa juga dipahami sebagai proses pembuatan objek. Pada contoh di atas kita memiliki sebuah objek dengan nama mhs.

Membuat Objek

Pembuatan objek bisa dilakukan dengan mendeklarasikan sebuah varibel bertipe kelas tertentu seperti yang sudah dijelaskan di atas. Bisa juga dilakukan dengan menggunakan pointer, seperti berikut:

Mahasiswa *mhs1 = new Mahasiswa();

Keunggulan menggunakan pointer adalah kita bisa membuat objek pada saat program dijalankan – runtime. Penting untuk diingat setiap objek yang sudah diciptakan (menggunakan pointer) harus dihapus jika sudah tidak dibutuhkan lagi menggunakan perintah delete.

delete (mhs);

Membuat Sebuah Class

Sebuah kelas bisa memiliki variabel/attribute dan fungsi/method. Setiap variabel dan fungsi ini memiliki beberapa sifat seperti private, protected dan public. Ketiga sifat ini disebuh access specifiers dan digunakan untuk menentukan siapa yang berhak mengakses variabel dan fungsi.

Berikut ini adalah bentuk umum sebuah kelas yang berisi variabel, fungsi dan access specifiers:

class Mahasiswa
{
private:
// deklarasi variabel dan fungsi yang bersifat private

protected:
//deklarasi variabel dan fungsi yang bersifat protected

public:
//deklarasi variabel dan fungsi yang bersifat public

};

Mengenal Konstruktor dan Destruktor

Di dalam sebuah kelas terdapat dua buah fungsi/method spesial. Disebut spesial karena kita tidak akan pernah memanggil fungsi tersebut secara langsung namun fungsi ini akan dijalankan secara otomatis. Fungsi Konstruktor (constructor) adalah fungsi yang dipanggil pada saat pembuatan sebuah objek. Sedangkan fungsi Destruktor (destructor) adalah fungsi yang dipanggil pada saat penghancuran sebuah objek.

Pertanyaan yang menarik bagi kita adalah “kapan sih sebuah objek dihancurkan” ? Jawabannya adalah saat objek itu sudah tidak lagi digunakan. Untuk objek yang dibuat menggunakan pointer, objek ini akan dihancurkan hanya pada saat kita memanggil perintah delete. Sedangkan untuk objek yang dibuat tanpa menggunakan pointer, objek tersebut akan dihancurkan jika keluar dari scope objek / variabel tersebut. Pembahasan tentang scope sudah pernah dibahas sebelumnya. Agar lebih memahami cobalah memahami source code yang disertakan pada tulisan ini.

Sifat spesial yang lain dari kedua fungsi ini adalah nama. Kedua fungsi memiliki nama yang sama dengan nama kelas. Namun yang membedakan, untuk fungsi Destruktor ditambahkan tanda 'cacing' didepan nama fungsi. Sebagai contoh, jika kita mempunyai kelas dengan nama Mahasiswa maka nama fungsi konstruktor dari kelas ini adalah Mahasiswa() sedangkan nama fungsi destruktor dari kelas ini adalah ~Mahasiswa(). Kedua fungsi ini biasanya bersifat public.

Dengan demikian bentuk umum dari sebuah kelas adalah sebagai berikut:

class Mahasiswa
{
private:
// deklarasi variabel dan fungsi yang bersifat private

protected:
//deklarasi variabel dan fungsi yang bersifat protected

public:
//deklarasi variabel dan fungsi yang bersifat public

Mahasiswa()
{
//body dari konstruktor

}

~Mahasiswa()
{
//body dari destruktor

}

};



Wednesday, October 14, 2009

Implementasi Array dengan Vector



Pengantar

Array adalah variabel dengan sifat khusus yaitu mampu menyimpan nilai lebih dari satu dalam waktu yang bersamaan. Setiap nilai ini disimpan pada alamat tertentu yang biasa disebut indeks. Ingat indeks selalu dimulai dari 0 (nol). Membuat program menggunakan array sudah pernah dijelaskan sebelumnya, namun kelamahan dari pendekatan ini adalah kita harus sangat memperhatikan berapa jumlah data yang disimpan ke dalam array. Jika data yang dimasukkan ke dalam array melebihi kemampuan yang disediakan maka akan menimbulkan masalah buffer overflow.

Pada tulisan ini diperkenalkan bagaimana membuat array menggunakan salah satu tipe data yang disebut vector. Dengan menggunakan tipe data ini, jumlah data yang dimasukkan sangat fleksibel, tergantung dari keinginan kita. Kita tidak perlu mendeklarasikan secara eksplisit berapa jumlah data yang bisa disimpan ke dalam array. Tipe data ini menyediakan sebuah fungsi yang bisa dipakai untuk mengetahui sebarapa banyak jumlah data yang telah tersimpan, disebut size(). Terdapat juga fungsi yang digunakan untuk menambahkan data ke dalam array, disebut push_back().

Lebih Jauh Tentang Vector

Secara formal, Vector dikenal sebagai container / wadah dan diperkenalkan dalam C++. Kita tidak akan menemukan Vector di dalam bahasa C. Vector adalah wadah yang bisa menampung semua jenis tipe data, sehingga yang perlu kita lakukan hanyalah menentukan tipe data apa yang hendak disimpan sedangkan cara untuk bekerja dengan data tersebut adalah sama untuk semua tipe data.

Untuk bisa menggunakan vector, kita perlu memberitahukan compiler bahwa kita menggunakan pustaka vector

#include<vector>

Contoh kita ingin bekerja dengan tipe data int, maka yang perlu kita lakukan adalah mendefinisikan variabel yang bertipe vector of int, seperti berikut:

vector<int> myVariable;

Jika ingin bekerja dengan tipe data float maka definisinya seperti berikut:

vector<float> myVariable;

Kita juga bisa bekerja dengan class (ingat class juga bisa digunakan sebagai tipe data) maka definisinya seperti berikut:

vector<nama_class> myVariable;

Untuk mengetahui jumlah data yang disimpan, kita bisa menggunakan fungsi size() seperti berikut:

myVariable.size();

Andaikan kita bekerja dengan tipe data int, maka cara menambahkan data ke dalam vector adalah seperti berikut:

myVariable.push_back(5);

atau bisa juga seperti berikut:

int data = 10;
myVariable.push_back(data);

atau bisa juga seperti berikut:

int data_baru = 0;
cout << “Input data baru : “;
cin >> data_baru;
myVariable.push_back(data_baru);

Untuk mengakses data tertentu yang tersimpan, cara yang digunakan sama persis dengan penggunaan array. Misal untuk menampilkan data pada indeks ke-5 (ingat indeks selalu dimulai dari 0);

cout << myVariable[5];

Pada source code yang diberikan, terdapat contoh sederhana bagaimana menyimpan data ke dalam array menggunakan cara yang sudah kita kenal dan bagaimana caranya jika hal tersebut kita buat menggunakan vector.




Sunday, October 11, 2009

Mengenal Fungsi Swap

Pengantar

Fungsi swap adalah fungsi yang digunakan untuk menukarkan dua buah nilai. Fungsi ini sangat dibutuhkan ketika kita hendak membuat aplikasi pengurutan data (sorting). Pada pemrograman C++, fungsi ini sudah tersedia dengan fleksibilitas yang tinggi. Artinya bisa digunakan untuk menukar dua buah nilai dengan tipe data yang bermacam-macam. Walaupun sudah tersedia dan tinggal pakai, tidak ada salahnya kita belajar bersama-sama bagaimana membuat fungsi ini. Contoh penggunaan fungsi swap yang sudah tersedia juga akan tersedia pada source code yang diberikan.

Sekilas Tentang Pointer

Pointer sudah pernah dibahas pada tulisan, pengenalan bahasa C++ (bagian 3). Pada bagian ini akan dijelaskan secara singkat penggunaan sederhana dari pointer.

Konsep penting yang perlu diingat adalah, pointer biasanya digunakan untuk menunjuk ke variabel yang lain. Untuk itu pointer membutuhkan alamat dari variabel yang ditunjuk. Setelah mengetahui alamat, dengan menggunakan pointer kita bisa mengubah nilai dari variabel yang ditunjuk.

Kita sudah tahu bahwa untuk membuat sebuah variabel, kita perlu menentukan tipe dari variabel dan kita juga perlu memperhatikan aturan pemberian nama dari variabel tersebut. Misal kita akan membuat variabel dengan nama data dan bertipe int, maka kita dapat menulisnya sebagai berikut:

int data;

Jika kita hendak membuat pointer. Kita cukup mendambahkan tanda bintang setelah tipe data.

int* myPointer;

pada deklarasi ini, kita membuat sebuah pointer dengan nama myPointer. Pointer ini hanya bisa menunjuk ke variabel yang bertipe int.

Seperti yang sudah dijelaskan sebelumnya, untuk menunjuk sebuah variabel, pointer membutuhkan alamat dari variabel yang hendak ditunjuk. Dengan menggunakan tanda '&' kita bisa mendapatkan alamat dari sebuah variabel. Berikut ini ditunjukkan bagaimana caranya myPointer bisa menunjuk ke alamat dari data.

myPointer = &data;

Variabel sebenarnya hanya merupakan nama lain dari alamat dimemori. Kita tentu akan lebih mudah mengingat nama seperti data dari pada sebuah alamat dimemori, 0x22ff5c.

Sekarang diandaikan kita memberikan nilai 10 (sepuluh) pada variabel data

data = 10;

pernyataan tersebut sebenarnya, kita menyimpan nilai 10 ke alamat tertentu dimemori yang diwakili dengan nama data. Karena myPointer telah menunjuk ke alamat dari data, ini berarti myPointer juga menunjuk ke nilai 10.

Untuk mengakses (misal membaca) nilai yang ditunjuk oleh pointer, kita bisa menggunakan tanda '*' didepan nama dari pointer.

cout<< *myPointer ;

Keluaran dari pernyataan ini adalah angka 10 akan tercetak ke layar. Keluaran ini akan sama jika kita menampilkan nilai dari variabel data.

cout<< data;

Kita juga bisa mengubah nilai yang ditunjuk oleh pointer, seperti berikut:

*myPointer = 15;

Setelah pernyataan diatas maka keluaran dari kedua pernyataan berikut akan sama persis yaitu menampilkan angka 15.

cout << data;
cout << *myPointer;

Membuat Fungsi Swap

Untuk membuat sebuah fungsi, kita bisa memulai dengan membayangkan bagaimana caranya kita memanggil fungsi yang akan kita pakai. Sebagai contoh fungsi swap yang akan kita buat dipanggil dengan cara sebagai berikut:

int a = 5;
int b= 7;
mySwap(&a,&b);
cout << a; // harapannya tertampil 7
cout << b; // harapannya tertampil 5

berangkat dari skenario di atas, tampak bahwa fungsi swap memiliki dua buah parameter pointer dengan tipe int. Untuk itu bentuk fungsi kita kira-kira seperti berikut:

void mySwap (int* x, int* y)
{
//body dari swap
...
}

pada kasus ini kita tidak membutuhkan nilai kembalian sehingga tipe data dari return value dibuat void. Kenapa tidak butuh ? Silahkan melihat lagi skenario yang kita buat di atas.

Karena fungsi kita hendak menukarkan nilai x dan nilai y (ingat x dan y adalah pointer, sehingga kita butuh tanda * untuk mengubah nilai), maka kita membutuhkan sebuah penampung (variabel tambahan) untuk melakukan proses penukaran ini.

Buf = *x;// buf bernilai x
*x = *y; // x bernilai y
*y = buf;// y bernilai x

pada contoh diatas, penampung yang kita pakai adalah Buf. Karena Buf dipakai untuk menampung nilai bertipe int, maka Buf juga harus dideklarasikan bertipe int.

int Buf;

Dengan demikian bentuk fungsi kita selengkapnya, kira-kira seperti berikut:

void swap (int* x, int* y)
{
//body dari swap
int Buf;
Buf = *x;
*x = *y;
*y = Buf;
}

Pemanggilan fungsi dengan cara mengirimkan alamat dari variabel, dikenal dengan istilah passing parameter by reference.

Di dalam bahasa C++, diperkenalkan teknik baru untuk pengiriman parameter berupa reference dengan menggunakan tanda '&'. Dengan menggunakan teknik ini, cara pemanggilan fungsi swap bisa diskenariokan sebagai berikut:

int a = 5;
int b= 7;
swap(a,b); // perhatikan tanda & dihilangkan
cout << a;
cout << b;

Perubahan juga perlu dilakukan pada fungsi kita sebagai berikut:

void swap (int& x, int& y) //perhatikan tanda &
{
//body dari swap
int Buf;
Buf = x;// tanda * juga dihilangkan
x = y;
y = Buf;
}


Thursday, October 8, 2009

Pengenalan Bahasa C++ (Bagian 8)

Operasi file adalah operasi yang berhubungan dengan file. Pada tulisan ini akan diberikan penjelasan tentang bagaimana membaca file (per baris dan per kata), membuat file baru, dan membuat duplikasi dari sebuah file.

Tuesday, October 6, 2009

Mari Berlatih Bahasa C++ (Bagian 3)

Tugas kali ini merupakan pengembangan dari tugas sebelumnya, Input Kalimat, dengan penekanan pada pembuatan fungsi. Disarankan teman-teman untuk membaca artikel tentang fungsi, pengenalan bahasa C++ (bagian 7).


Saran:
Jangan melihat dulu source code. Cobalah membaca lagi petunjuk tugas dan menjalankan contoh program yang disediakan. Jika sudah selesai atau mengalami masalah dalam menyelesaikan tugas ini, silahkan membuka source code.



Monday, October 5, 2009

Pengenalan Bahasa C++ (Bagian 7)

Pada tulisan ini akan dibahas khusus tentang fungsi dan merupakan pelengkap penjelasan dari tulisan Pengenalan Bahasa C++ (bagian 2). Penjelasan disertai dengan ilustrasi berupa gambar dengan penekanan pada bagian-bagian penting yang perlu diperhatikan saat mengimplementasikan prototipe sebuah fungsi.

Sunday, October 4, 2009

Mari Berlatih Bahasa C++ (Bagian 2)

Saat bekerja dengan ARRAY, hal yang perlu diperhatikan adalah jangan sampai memberikan data ke dalam ARRAY melebihi kapasitas yang disediakan. Jika hal ini dilanggar maka masalah yang dihadapi adalah buffer overflow. Tujuan dari tugas kali ini adalah membuat suatu sistem “Input Kalimat” di mana user hanya bisa menyimpan data ke dalam ARRAY sebanyak tempat yang sudah ditentukan sebelumnya.

Saran:
Jangan melihat dulu source code. Cobalah membaca lagi petunjuk tugas dan menjalankan contoh program yang disediakan. Jika sudah selesai atau mengalami masalah dalam menyelesaikan tugas ini, silahkan membuka source code.



Mari Berlatih Bahasa C++ (Bagian 1)

Program membalikan kata adalah salah satu tugas yang saya dapatkan di lab, ketika mulai belajar C/C++. Tugas ini sangat bagus untuk mengetahui sebaik mana pengetahuan kita tentang ARRAY, dalam hal ini STRING. Untuk bisa menyelesaikan tugas ini, pemahaman tentang VARIABEL, PERULANGAN dan INPUT-OUPUT dengan C++ sangat dibutuhkan.

Saran:
Jangan melihat dulu source code. Cobalah membaca lagi petunjuk tugas dan menjalankan contoh program yang disediakan. Jika sudah selesai atau mengalami masalah dalam menyelesaikan tugas ini, silahkan membuka source code.

Saturday, October 3, 2009

Pengenalan Bahasa C++ (Bagian 6)

Di dalam kehidupan ini seringkali kita diperhadapkan dengan pengambilan keputusan. Dan setiap keputusan selalu dihadapkan dengan konsekuensi. Jika saya memutuskan untuk melakukan 'A' maka konsekuensinya adalah nasib saya akan menjadi 'B' namun jika saya melakukan C maka nasib saya akan menjadi 'B+' .

Di dalam struktur pemrograman bahasa C/C++, ilustrasi di atas dapat dituliskan sebagai berikut:

jika (saya melakukan A) maka
{
.....nasib_saya = B
} namun
jika (saya melakukan C) maka
{
.....nasib_saya = B+
}

Konsep inilah yang dikenal dengan istilah percabangan.

Pembahasan di dalam tulisan ini meliputi:
  1. Percangan dengan if tanpa else
  2. Percabangan dengan if dengan else
  3. Percabangan dengan switch
  4. Konsep Scope. Konsep ini sangat penting untuk memahami konsep lokalitas dari sebuah variabel.
  5. Contoh Program, dimana penjelasan diawali dengan menjelaskan permasalahan yang hendak dipecahkan, algoritma yang digunakan dan diakhiri dengan penyelesaian.

Download Artikel
Baca Online


Friday, October 2, 2009

Mari Berlatih Bahasa C++

Tulisan tentang “Mari Belatih Bahasa C++” adalah seri belajar bahasa pemrograman C++ dari awal yang ditujukkan untuk teman-teman yang baru belajar pemrograman. Harapannya adalah dengan mengikuti seri ini, teman-teman akan belajar menggunakan pengetahuan yang sudah dipelajari di bangku kuliah atau pelajari lewat materi yang disediakan di website ini, untuk menyelesaikan persoalan mulai dari yang tingkat dasar sampai dengan tingkat lanjut. Dengan berlatih, mudah-mudahan kemampuan pemrograman teman-teman akan bisa semakin baik.

Thursday, October 1, 2009

Pengenalan Bahasa C++ (Bagian 5)

Di dalam bahasa C++ terdapat 3 (tiga) metode yang bisa digunakan untuk membuat perulangan yaitu, for, while atau dengan do ... while. Ketiga perulangan ini membutuhkan pengontrol jalannya perulangan yang disebut kondisi. Selama kondisi benar, perulangan akan terus dikerjakan.

Tulisan ini membahas dengan detail aspek penting yang perlu diperhatikan dalam membuat perulangan. Berikut ini adalah garis besar topik yang dibahas:
  • Konsep kondisi
  • Mengenal operator logika
  • perulangan dengan for
  • perulangan dengan while
  • perulangan dengan do ... while
  • perbedaan antara perulangan dengan while dan do ... while

Download Artikel
Baca Online