summaryrefslogtreecommitdiffhomepage
path: root/ms-my
diff options
context:
space:
mode:
Diffstat (limited to 'ms-my')
-rw-r--r--ms-my/clojure-macros-my.html.markdown151
-rw-r--r--ms-my/clojure-my.html.markdown419
-rw-r--r--ms-my/common-lisp-my.html.markdown692
-rw-r--r--ms-my/elisp-my.html.markdown347
-rw-r--r--ms-my/javascript-my.html.markdown2
5 files changed, 1610 insertions, 1 deletions
diff --git a/ms-my/clojure-macros-my.html.markdown b/ms-my/clojure-macros-my.html.markdown
new file mode 100644
index 00000000..325f92e0
--- /dev/null
+++ b/ms-my/clojure-macros-my.html.markdown
@@ -0,0 +1,151 @@
+---
+language: "clojure macros"
+filename: learnclojuremacros-ms.clj
+contributors:
+ - ["Adam Bard", "http://adambard.com/"]
+translators:
+ - ["Burhanuddin Baharuddin", "https://github.com/burhanloey"]
+lang: ms-my
+---
+
+Sama seperti Lisp yang lain, sifat Clojure yang mempunyai [homoiconicity](https://en.wikipedia.org/wiki/Homoiconic)
+membolehkan anda untuk menggunakan sepenuhnya language ini untuk menulis code yang boleh generate code sendiri yang
+dipanggil "macro". Macro memberi cara yang sangat menarik untuk mengubahsuai language mengikut kehendak anda.
+
+Jaga-jaga. Penggunaan macro boleh dikatakan tidak elok jika digunakan secara berlebihan jika function sahaja sudah mencukupi.
+Gunakan macro hanya apabila anda mahu lebih kawalan terhadap sesuatu form.
+
+Biasakan diri dengan Clojure terlebih dahulu. Pastikan anda memahami semuanya di
+[Clojure in Y Minutes](/docs/ms-my/clojure-my/).
+
+```clojure
+;; Define macro menggunakan defmacro. Macro anda akan output list yang boleh
+;; dijalankan sebagai code clojure.
+;;
+;; Macro ini adalah sama seperti (reverse "Hello World")
+(defmacro my-first-macro []
+ (list reverse "Hello World"))
+
+;; Lihat hasil macro tersebut menggunakan macroexpand atau macroexpand-1.
+;;
+;; Pastikan panggilan kepada macro tersebut mempunyai tanda petikan
+(macroexpand '(my-first-macro))
+;; -> (#<core$reverse clojure.core$reverse@xxxxxxxx> "Hello World")
+
+;; Anda boleh menggunakan eval terus kepada macroexpand untuk mendapatkan hasil:
+(eval (macroexpand '(my-first-macro)))
+; -> (\d \l \o \r \W \space \o \l \l \e \H)
+
+;; Tetapi anda sepatutnya menggunakan cara yang lebih ringkas, sama seperti panggilan kepada function:
+(my-first-macro) ; -> (\d \l \o \r \W \space \o \l \l \e \H)
+
+;; Anda boleh memudahkan cara untuk membuat macro dengan mengguna tanda petikan
+;; untuk membuat list untuk macro:
+(defmacro my-first-quoted-macro []
+ '(reverse "Hello World"))
+
+(macroexpand '(my-first-quoted-macro))
+;; -> (reverse "Hello World")
+;; Perhatikan yang reverse bukan lagi function tetapi adalah simbol.
+
+;; Macro boleh mengambil argument.
+(defmacro inc2 [arg]
+ (list + 2 arg))
+
+(inc2 2) ; -> 4
+
+;; Tetapi jika anda membuat cara yang sama menggunakan tanda petikan, anda akan mendapat error sebab
+;; argument tersebut juga akan mempunyai tanda petikan. Untuk mengatasi masalah ini, Clojure memberi
+;; cara untuk meletak tanda petikan untuk macro: `. Di dalam `, anda boleh menggunakan ~ untuk mendapatkan scope luaran
+(defmacro inc2-quoted [arg]
+ `(+ 2 ~arg))
+
+(inc2-quoted 2)
+
+;; Anda boleh menggunakan destructuring untuk argument seperti biasa. Gunakan ~@ untuk mengembangkan variable
+(defmacro unless [arg & body]
+ `(if (not ~arg)
+ (do ~@body))) ; Jangan lupa do!
+
+(macroexpand '(unless true (reverse "Hello World")))
+;; ->
+;; (if (clojure.core/not true) (do (reverse "Hello World")))
+
+;; (unless) mengembalikan body jika argument yang pertama adalah false.
+;; Jika tidak, (unless) akan memulangkan nil
+
+(unless true "Hello") ; -> nil
+(unless false "Hello") ; -> "Hello"
+
+;; Jika tidak berhati-hati, macro boleh memeningkan anda dengan mencampuradukkan nama variable
+(defmacro define-x []
+ '(do
+ (def x 2)
+ (list x)))
+
+(def x 4)
+(define-x) ; -> (2)
+(list x) ; -> (2)
+
+;; Untuk mengelakkan masalah ini, gunakan gensym untuk mendapatkan identifier yang berbeza
+(gensym 'x) ; -> x1281 (atau yang sama waktu dengannya)
+
+(defmacro define-x-safely []
+ (let [sym (gensym 'x)]
+ `(do
+ (def ~sym 2)
+ (list ~sym))))
+
+(def x 4)
+(define-x-safely) ; -> (2)
+(list x) ; -> (4)
+
+;; Anda boleh menggunakan # di dalam ` untuk menghasilkan gensym untuk setiap simbol secara automatik
+(defmacro define-x-hygienically []
+ `(do
+ (def x# 2)
+ (list x#)))
+
+(def x 4)
+(define-x-hygienically) ; -> (2)
+(list x) ; -> (4)
+
+;; Kebiasaannya helper function digunakan untuk membuat macro. Jom buat beberapa function untuk
+;; membuatkan program boleh memahami inline arithmetic. Saja suka-suka.
+(declare inline-2-helper)
+(defn clean-arg [arg]
+ (if (seq? arg)
+ (inline-2-helper arg)
+ arg))
+
+(defn apply-arg
+ "Diberi argument [x (+ y)], pulangkan (+ x y)"
+ [val [op arg]]
+ (list op val (clean-arg arg)))
+
+(defn inline-2-helper
+ [[arg1 & ops-and-args]]
+ (let [ops (partition 2 ops-and-args)]
+ (reduce apply-arg (clean-arg arg1) ops)))
+
+;; Kita boleh test terlebih dahulu tanpa membuat macro
+(inline-2-helper '(a + (b - 2) - (c * 5))) ; -> (- (+ a (- b 2)) (* c 5))
+
+; Tetapi, kita perlu membuat macro jika kita mahu jalankan code tersebut
+(defmacro inline-2 [form]
+ (inline-2-helper form))
+
+(macroexpand '(inline-2 (1 + (3 / 2) - (1 / 2) + 1)))
+; -> (+ (- (+ 1 (/ 3 2)) (/ 1 2)) 1)
+
+(inline-2 (1 + (3 / 2) - (1 / 2) + 1))
+; -> 3 (sepatutnya, 3N, sebab nombor tersebut ditukarkan kepada pecahan rasional menggunakan /)
+```
+
+### Bacaaan Lanjut
+
+[Writing Macros daripada](http://www.braveclojure.com/writing-macros/)
+
+[Dokumen rasmi](http://clojure.org/macros)
+
+[Bila perlu guna macro?](https://lispcast.com/when-to-use-a-macro/)
diff --git a/ms-my/clojure-my.html.markdown b/ms-my/clojure-my.html.markdown
new file mode 100644
index 00000000..e199c8f4
--- /dev/null
+++ b/ms-my/clojure-my.html.markdown
@@ -0,0 +1,419 @@
+---
+language: clojure
+filename: learnclojure-ms.clj
+contributors:
+ - ["Adam Bard", "http://adambard.com/"]
+translators:
+ - ["Burhanuddin Baharuddin", "https://github.com/burhanloey"]
+lang: ms-my
+---
+
+Clojure ialah salah satu bahasa pengaturcaraan dalam keluarga Lisp yang dibangunkan untuk Java Virtual Machine. Ia lebih
+menekankan kepada konsep [functional programming](https://en.wikipedia.org/wiki/Functional_programming) jika dibandingkan
+dengan Common Lisp, tetapi juga menyediakan kemudahan [STM](https://en.wikipedia.org/wiki/Software_transactional_memory)
+untuk mengendalikan *state* apabila diperlukan.
+
+Gabungan tersebut membolehkan Clojure untuk mengendalikan beberapa proses serentak (*concurrency*) dengan mudah,
+dan kebiasaannya secara automatik.
+
+(Anda perlukan Clojure versi 1.2 ke atas)
+
+
+```clojure
+; Komen bermula dengan koma bertitik (semicolon).
+
+; Clojure ditulis dalam bentuk yang seragam, iaitu
+; senarai perkataan di dalam kurungan (parentheses), dipisahkan dengan ruang kosong (whitespace).
+;
+; Pembaca Clojure akan menganggap bahawa perkataan pertama dalam senarai tersebut
+; sebagai `function` atau `macro` untuk digunakan, dan yang selebihnya sebagai arguments.
+
+; Panggilan pertama di dalam fail Clojure mestilah bermula dengan ns, untuk menentukan `namespace`
+(ns learnclojure)
+
+; Contoh-contoh asas yang lain:
+
+; str akan mewujudkan sebuah string daripada beberapa `argument`
+(str "Hello" " " "World") ; => "Hello World"
+
+; Operasi matematik pun mudah
+(+ 1 1) ; => 2
+(- 2 1) ; => 1
+(* 1 2) ; => 2
+(/ 2 1) ; => 2
+
+; Tanda = boleh digunakan untuk membuat perbandingan yang sama
+(= 1 1) ; => true
+(= 2 1) ; => false
+
+; Gunakan not untuk mengubah lojik
+(not true) ; => false
+
+; Bentuk `nested` berfungsi seperti yang dijangkakan
+(+ 1 (- 3 2)) ; = 1 + (3 - 2) => 2
+
+; Type (Jenis Data)
+;;;;;;;;;;;;;
+
+; Clojure menggunakan jenis `object` dari Java untuk `boolean`, `string` dan nombor.
+; Gunakan `class` untuk memeriksa jenis sesebuah data.
+(class 1) ; Secara default jenis data untuk `Integer` ialah java.lang.Long
+(class 1.); Jenis data untuk Float pula ialah java.lang.Double
+(class ""); `String` sentiasa berada dalam tanda petikan (quotation mark), dan merupakan java.lang.String
+(class false) ; `Boolean` ialah java.lang.Boolean
+(class nil); Nilai "null" dipanggil nil
+
+; Jika mahu membuat senarai data secara harfiah, gunakan ' untuk elakkan senarai tersebut
+; daripada terus berfungsi
+'(+ 1 2) ; => (+ 1 2)
+; (singkatan untuk (quote (+ 1 2)))
+
+; Senarai data secara harfiah boleh berfungsi menggunakan eval
+(eval '(+ 1 2)) ; => 3
+
+; Collection & Sequence (Koleksi & Urutan)
+;;;;;;;;;;;;;;;;;;;
+
+; `List` ialah struktur data `linked-list`, manakala `Vector` pula berasaskan `array`.
+; `Vector` dan `List` juga merupakan class dari Java!
+(class [1 2 3]); => clojure.lang.PersistentVector
+(class '(1 2 3)); => clojure.lang.PersistentList
+
+; Sesebuah list boleh ditulis seperti (1 2 3), tetapi kita perlu meletakkan '
+; untuk mengelakkannya daripada berfungsi.
+; Juga, (list 1 2 3) adalah sama dengan '(1 2 3)
+
+; "Collections" hanyalah kumpulan data
+; Kedua-dua list dan vector ialah collection:
+(coll? '(1 2 3)) ; => true
+(coll? [1 2 3]) ; => true
+
+; "Sequences" (seq) ialah kriteria untuk sesebuah senarai data.
+; Hanya list yang dikira sebagai seq.
+(seq? '(1 2 3)) ; => true
+(seq? [1 2 3]) ; => false
+
+; Sesebuah seq hanya perlukan satu kemasukan data untuk diakses.
+; Jadi, seq yang boleh jadi `lazy` (malas) -- boleh menjadi tidak terkira (infinite):
+(range 4) ; => (0 1 2 3)
+(range) ; => (0 1 2 3 4 ...) (tiada penghujung)
+(take 4 (range)) ; (0 1 2 3)
+
+; Gunakan cons untuk menambah sesuatu di awal sesebuah list atau vector
+(cons 4 [1 2 3]) ; => (4 1 2 3)
+(cons 4 '(1 2 3)) ; => (4 1 2 3)
+
+; Conj akan menambah sesuatu ke dalam collection dengan paling berkesan.
+; Untuk list, data tersebut dimasukkan di permulaan. Untuk vector, dimasukkan di pengakhiran.
+(conj [1 2 3] 4) ; => [1 2 3 4]
+(conj '(1 2 3) 4) ; => (4 1 2 3)
+
+; Gunakan concat untuk menggabungkan list atau vector
+(concat [1 2] '(3 4)) ; => (1 2 3 4)
+
+; Gunakan filter dan map untuk berinteraksi dengan data di dalam collection
+(map inc [1 2 3]) ; => (2 3 4)
+(filter even? [1 2 3]) ; => (2)
+
+; Gunakan reduce untuk dikecilkan (kepada satu nilai)
+(reduce + [1 2 3 4])
+; = (+ (+ (+ 1 2) 3) 4)
+; => 10
+
+; Reduce boleh diberi nilai permulaan
+(reduce conj [] '(3 2 1))
+; = (conj (conj (conj [] 3) 2) 1)
+; => [3 2 1]
+
+; Function
+;;;;;;;;;;;;;;;;;;;;;
+
+; Gunakan fn untuk membuat `function`. Sesebuah function pasti memulangkan semula
+; hasil daripada barisan yang terakhir.
+(fn [] "Hello World") ; => fn
+
+; (Anda perlukan satu lagi kurungan supaya function tersebut dikira)
+((fn [] "Hello World")) ; => "Hello World"
+
+; Anda boleh membuat var menggunakan def
+(def x 1)
+x ; => 1
+
+; Tetapkan sebuah function ke dalam var
+(def hello-world (fn [] "Hello World"))
+(hello-world) ; => "Hello World"
+
+; Proses di atas boleh diringkaskan menggunakan defn
+(defn hello-world [] "Hello World")
+
+; Tanda [] merupakan senarai argument untuk function tersebut.
+(defn hello [name]
+ (str "Hello " name))
+(hello "Steve") ; => "Hello Steve"
+
+; Cara ini juga boleh digunakan untuk membuat function dengan lebih ringkas:
+(def hello2 #(str "Hello " %1))
+(hello2 "Fanny") ; => "Hello Fanny"
+
+; Anda juga boleh membuat satu function yang mempunyai beberapa bilangan argument
+(defn hello3
+ ([] "Hello World")
+ ([name] (str "Hello " name)))
+(hello3 "Jake") ; => "Hello Jake"
+(hello3) ; => "Hello World"
+
+; Function boleh diberi argument ekstra dalam bentuk seq
+(defn count-args [& args]
+ (str "You passed " (count args) " args: " args))
+(count-args 1 2 3) ; => "You passed 3 args: (1 2 3)"
+
+; Anda boleh letakkan sekali argument biasa dan argument ekstra
+(defn hello-count [name & args]
+ (str "Hello " name ", you passed " (count args) " extra args"))
+(hello-count "Finn" 1 2 3)
+; => "Hello Finn, you passed 3 extra args"
+
+
+; Map
+;;;;;;;;;;
+
+; Hash map dan array map menggunakan `interface` yang sama. Hash map lebih laju untuk diakses
+; tetapi tidak mengekalkan urutan.
+(class {:a 1 :b 2 :c 3}) ; => clojure.lang.PersistentArrayMap
+(class (hash-map :a 1 :b 2 :c 3)) ; => clojure.lang.PersistentHashMap
+
+; Arraymap akan bertukar menjadi hashmap secara automatik untuk kebanyakan operasi
+; apabila mereka menjadi semakin besar, jadi anda tidak perlu bimbang.
+
+; Map boleh menggunakan apa-apa sahaja jenis data sebagai key, tetapi kebiasaannya keyword adalah yang terbaik
+; Keyword adalah sama seperti string cuma lebih efisyen
+(class :a) ; => clojure.lang.Keyword
+
+(def stringmap {"a" 1, "b" 2, "c" 3})
+stringmap ; => {"a" 1, "b" 2, "c" 3}
+
+(def keymap {:a 1, :b 2, :c 3})
+keymap ; => {:a 1, :c 3, :b 2}
+
+; Oh, sebelum terlupa, tanda koma di atas hanya dianggap seperti whitespace, tak buat apa-apa.
+; Dapatkan nilai daripada map dengan menggunakannya seperti function
+(stringmap "a") ; => 1
+(keymap :a) ; => 1
+
+; Keyword juga boleh digunakan untuk mendapatkan nilai daripada map tersebut!
+(:b keymap) ; => 2
+
+; Jangan cuba teknik di atas menggunakan string, tak jadi.
+;("a" stringmap)
+; => Exception: java.lang.String cannot be cast to clojure.lang.IFn
+
+; Apabila key yang digunakan tidak wujud, map akan memberi nil
+(stringmap "d") ; => nil
+
+; Gunakan assoc untuk menambah key yang baru ke dalam hash-map
+(def newkeymap (assoc keymap :d 4))
+newkeymap ; => {:a 1, :b 2, :c 3, :d 4}
+
+; Tetapi ingat, data dalam clojure adalah `immutable` (tidak berubah)!
+keymap ; => {:a 1, :b 2, :c 3}
+
+; Gunakan dissoc untuk membuang key
+(dissoc keymap :a :b) ; => {:c 3}
+
+; Set
+;;;;;;
+
+(class #{1 2 3}) ; => clojure.lang.PersistentHashSet
+(set [1 2 3 1 2 3 3 2 1 3 2 1]) ; => #{1 2 3}
+
+; Tambah data menggunakan conj
+(conj #{1 2 3} 4) ; => #{1 2 3 4}
+
+; Buang data menggunakan disj
+(disj #{1 2 3} 1) ; => #{2 3}
+
+; Periksa kewujudan data dengan menggunakan set tersebut sebagai function:
+(#{1 2 3} 1) ; => 1
+(#{1 2 3} 4) ; => nil
+
+; Ada pelbagai lagi function untuk set di namespace clojure.sets.
+
+; Form yang berguna
+;;;;;;;;;;;;;;;;;
+
+; Lojik dalam clojure hanyalah sebuah macro, dan kelihatan seperti
+; yang lain
+(if false "a" "b") ; => "b"
+(if false "a") ; => nil
+
+; Gunakan let untuk membuat binding sementara
+(let [a 1 b 2]
+ (> a b)) ; => false
+
+; Kumpulkan beberapa statement sekali menggunakan do
+(do
+ (print "Hello")
+ "World") ; => "World" (prints "Hello")
+
+; Function sebenarnya ada do secara tersirat
+(defn print-and-say-hello [name]
+ (print "Saying hello to " name)
+ (str "Hello " name))
+(print-and-say-hello "Jeff") ;=> "Hello Jeff" (prints "Saying hello to Jeff")
+
+; Let pun sama
+(let [name "Urkel"]
+ (print "Saying hello to " name)
+ (str "Hello " name)) ; => "Hello Urkel" (prints "Saying hello to Urkel")
+
+
+; Gunakan `threading macro` (-> dan ->>) untuk menulis penggubahan data
+; dengan lebih jelas.
+
+; Macro "thread-first" (->) memasukkan hasil perkiraan ke setiap form
+; yang selepasnya, sebagai argument pertama (item yang kedua)
+(->
+ {:a 1 :b 2}
+ (assoc :c 3) ;=> (assoc {:a 1 :b 2} :c 3)
+ (dissoc :b)) ;=> (dissoc (assoc {:a 1 :b 2} :c 3) :b)
+
+; Code di atas boleh ditulis seperti ini:
+; (dissoc (assoc {:a 1 :b 2} :c 3) :b)
+; dan hasilnya ialah {:a 1 :c 3}
+
+; Yang dua anak panah pula membuat benda yang sama, tetapi memasukkan hasil perkiraan
+; setiap baris ke pengakhiran form selepasnya. Cara ini berguna untuk operasi
+; yang melibatkan collection:
+(->>
+ (range 10)
+ (map inc) ;=> (map inc (range 10)
+ (filter odd?) ;=> (filter odd? (map inc (range 10))
+ (into [])) ;=> (into [] (filter odd? (map inc (range 10)))
+ ; Result: [1 3 5 7 9]
+
+; Jika anda mahu lebih fleksibel untuk meletakkan hasil perkiraan,
+; anda boleh menggunakan macro `as->`. Dengan menggunakan macro tersebut,
+; anda boleh menentukan nama untuk output dan menggunakannya semula
+; ke dalam operasi berangkai:
+
+(as-> [1 2 3] input
+ (map inc input);=> You can use last transform's output at the last position
+ (nth input 2) ;=> and at the second position, in the same expression
+ (conj [4 5 6] input [8 9 10])) ;=> or in the middle !
+
+
+
+; Module
+;;;;;;;;;;;;;;;
+
+; Gunakan "use" untuk mendapatkan semua function daripada sesebuah module
+(use 'clojure.set)
+
+; Sekarang kita boleh menggunakan operasi untuk set
+(intersection #{1 2 3} #{2 3 4}) ; => #{2 3}
+(difference #{1 2 3} #{2 3 4}) ; => #{1}
+
+; Anda juga boleh memilih sebahagian daripada function untuk diimport
+(use '[clojure.set :only [intersection]])
+
+; Gunakan require untuk mengimport sesebuah module
+(require 'clojure.string)
+
+; Gunakan / untuk menggunakan function daripada module
+; Di sini, nama module tersebut ialah clojure.string dan function-nya ialah blank?
+(clojure.string/blank? "") ; => true
+
+; Anda juga boleh memberi nama yang lebih ringkas untuk module semasa import
+(require '[clojure.string :as str])
+(str/replace "This is a test." #"[a-o]" str/upper-case) ; => "THIs Is A tEst."
+; (#"" ialah ungkapan untuk regular expression, regex)
+
+; Anda boleh menggunakan require (dan use, tetapi elakkan) daripada namespace menggunakan :require.
+; Anda tidak perlu menulis semula nama module dengan cara ini.
+(ns test
+ (:require
+ [clojure.string :as str]
+ [clojure.set :as set]))
+
+; Java
+;;;;;;;;;;;;;;;;;
+
+; Java mengandungi banyak standard library yang kita boleh manfaatkan, jadi
+; anda patut tahu bagaimana untuk menggunakannya.
+
+; Gunakan import untuk load module java
+(import java.util.Date)
+
+; Anda juga boleh import menggunakan ns.
+(ns test
+ (:import java.util.Date
+ java.util.Calendar))
+
+; Gunakan nama class berserta "." di hujungnya untuk membuat object baru
+(Date.) ; <object date>
+
+; Gunakan . untuk menggunakan method. Atau gunakan shortcut seperti ".method"
+(. (Date.) getTime) ; <sebuah timestamp>
+(.getTime (Date.)) ; sama sahaja.
+
+; Gunakan / untuk menggunakan static method
+(System/currentTimeMillis) ; <sebuah timestamp> (System sentiasa wujud dalam Java)
+
+; Gunakan doto untuk menjadikan proses yang melibatkan class mutable (boleh berubah) lebih mudah
+(import java.util.Calendar)
+(doto (Calendar/getInstance)
+ (.set 2000 1 1 0 0 0)
+ .getTime) ; => Sebuah Date. yang ditetapkan kepada 2000-01-01 00:00:00
+
+; STM
+;;;;;;;;;;;;;;;;;
+
+; Software Transactional Memory ialah mekanisme dalam Clojure untuk mengendalikan
+; state yang kekal berterusan. Ada beberapa kaedah dalam Clojure yang menggunakan teknik tersebut.
+
+; Atom adalah yang paling mudah. Letakkannya sewaktu meletakkan nilai permulaan.
+(def my-atom (atom {}))
+
+; Kemas kini sebuah atom menggunakan swap!.
+; swap! mengambil satu function dan menggunakannya menggunakan nilai asal atom
+; sebagai argument pertama, dan argument selebihnya sebagai argument kedua
+(swap! my-atom assoc :a 1) ; Tetapkan my-atom kepada hasil perkiraan (assoc {} :a 1)
+(swap! my-atom assoc :b 2) ; Tetapkan my-atom kepada hasil perkiraan (assoc {:a 1} :b 2)
+
+; Gunakan '@' untuk mendapatkan nilai daripada atom
+my-atom ;=> Atom<#...> (memberi object atom itu sendiri)
+@my-atom ; => {:a 1 :b 2}
+
+; Ini adalah contoh untuk mengira menggunakan atom
+(def counter (atom 0))
+(defn inc-counter []
+ (swap! counter inc))
+
+(inc-counter)
+(inc-counter)
+(inc-counter)
+(inc-counter)
+(inc-counter)
+
+@counter ; => 5
+
+; Kaedah lain yang menggunakan STM ialah ref dan agent.
+; Ref: http://clojure.org/refs
+; Agent: http://clojure.org/agents
+```
+
+### Bacaan Lanjut
+
+Ini masih belum lengkap, tetapi harap-harap cukup untuk membuatkan anda lebih bersedia.
+
+Clojure.org mempunyai banyak artikel:
+[http://clojure.org/](http://clojure.org/)
+
+Clojuredocs.org mempunyai dokumentasi berserta contoh untuk menggunakan kebanyakan function teras:
+[http://clojuredocs.org/quickref/Clojure%20Core](http://clojuredocs.org/quickref/Clojure%20Core)
+
+4Clojure ialah cara yang baik untuk mengasah skill Clojure dan functional programming:
+[http://www.4clojure.com/](http://www.4clojure.com/)
+
+Clojure-doc.org (yup, serius) juga mengandungi beberapa artikel sebagai permulaan:
+[http://clojure-doc.org/](http://clojure-doc.org/)
diff --git a/ms-my/common-lisp-my.html.markdown b/ms-my/common-lisp-my.html.markdown
new file mode 100644
index 00000000..f5914aae
--- /dev/null
+++ b/ms-my/common-lisp-my.html.markdown
@@ -0,0 +1,692 @@
+---
+
+language: "Common Lisp"
+filename: commonlisp-ms.lisp
+contributors:
+ - ["Paul Nathan", "https://github.com/pnathan"]
+ - ["Rommel Martinez", "https://ebzzry.io"]
+translators:
+ - ["Burhanuddin Baharuddin", "https://github.com/burhanloey"]
+lang: ms-my
+---
+
+Common Lisp ialah programming language yang general-purpose (boleh digunakan untuk semua benda) dan multi-paradigm (konsep yang pelbagai) sesuai untuk pelbagai kegunaan di dalam
+industri aplikasi. Common Lisp biasa digelar sebagai programmable programming language (programming language yang boleh di-program-kan).
+
+Sumber bacaan yang klasik ialah [Practical Common Lisp](http://www.gigamonkeys.com/book/). Sumber bacaan yang lain dan
+yang terbaru ialah [Land of Lisp](http://landoflisp.com/). Buku baru mengenai best practices (amalan terbaik),
+[Common Lisp Recipes](http://weitz.de/cl-recipes/), baru sahaja diterbitkan.
+
+
+
+```common-lisp
+
+;;;-----------------------------------------------------------------------------
+;;; 0. Syntax
+;;;-----------------------------------------------------------------------------
+
+;;; General form (Bentuk umum)
+
+;;; Ada dua asas dalam syntax CL: ATOM dan S-EXPRESSION.
+;;; Kebiasaannya, gabungan S-expression dipanggil sebagai `forms`.
+
+10 ; atom; bermaksud seperti yang ditulis iaitu nombor 10
+:thing ; juga atom; bermaksud simbol :thing
+t ; juga atom, bermaksud true (ya/betul/benar)
+(+ 1 2 3 4) ; s-expression
+'(4 :foo t) ; juga s-expression
+
+
+;;; Comment (Komen)
+
+;;; Comment satu baris bermula dengan semicolon; gunakan empat untuk comment
+;;; mengenai file, tiga untuk seksyen penghuraian, dua untuk yang dalam definition,
+;;; dan satu untuk satu baris. Sebagai contoh,
+
+;;;; life.lisp
+
+;;; Foo bar baz, disebabkan quu quux. Sangat optimum untuk krakaboom dan umph.
+;;; Diperlukan oleh function LINULUKO. Ini merepek sahaja kebaboom.
+
+(defun meaning (life)
+ "Memulangkan hasil pengiraan makna KEHIDUPAN"
+ (let ((meh "abc"))
+ ;; Jalankan krakaboom
+ (loop :for x :across meh
+ :collect x))) ; Simpan hasil ke x, kemudian pulangkan
+
+;;; Komen berbentuk blok, sebaliknya, membenarkan komen untuk bentuk bebas. Komen
+;;; tersebut berada di antara #| dan |#
+
+#| Ini adalah komen berbentuk blok di mana
+ tulisan boleh ditulis dalam beberapa baris dan
+ #|
+ juga boleh dalam bentuk nested (berlapis-lapis)!
+ |#
+|#
+
+
+;;; Environment (benda-benda yang diperlukan untuk program menggunakan Common Lisp)
+
+;;; Common Lisp ada banyak jenis; kebanyakannya mengikut standard. SBCL
+;;; ialah titik permulaan yang baik. Quicklisp boleh digunakan untuk install
+;;; library third party.
+
+;;; CL kebiasaannya digunakan dengan text editor dan Real Eval Print
+;;; Loop (REPL) yang dilancarkan dengan serentak. REPL membolehkan kita menjelajah
+;;; program secara interaktif semasa program tersebut sedang berjalan secara "live".
+
+
+;;;-----------------------------------------------------------------------------
+;;; 1. Datatype primitif dan operator
+;;;-----------------------------------------------------------------------------
+
+;;; Simbol
+
+'foo ; => FOO Perhatikan simbol menjadi huruf besar secara automatik.
+
+;;; INTERN menjadikan string sebagai simbol secara manual.
+
+(intern "AAAA") ; => AAAA
+(intern "aaa") ; => |aaa|
+
+;;; Nombor
+
+9999999999999999999999 ; integer
+#b111 ; binary => 7
+#o111 ; octal => 73
+#x111 ; hexadecimal => 273
+3.14159s0 ; single
+3.14159d0 ; double
+1/2 ; ratio
+#C(1 2) ; complex number
+
+;;; Function ditulis sebagai (f x y z ...) di mana f ialah function dan
+;;; x, y, z, ... adalah argument.
+
+(+ 1 2) ; => 3
+
+;;; Jika anda ingin membuat data sebagai data bukannya function, gunakan QUOTE
+;;; untuk mengelakkan data tersebut daripada dikira oleh program
+
+(quote (+ 1 2)) ; => (+ 1 2)
+(quote a) ; => A
+
+;;; Singkatan untuk QUOTE ialah ' (tanda petikan)
+
+'(+ 1 2) ; => (+ 1 2)
+'a ; => A
+
+;;; Operasi arithmetic asas
+
+(+ 1 1) ; => 2
+(- 8 1) ; => 7
+(* 10 2) ; => 20
+(expt 2 3) ; => 8
+(mod 5 2) ; => 1
+(/ 35 5) ; => 7
+(/ 1 3) ; => 1/3
+(+ #C(1 2) #C(6 -4)) ; => #C(7 -2)
+
+;;; Boolean
+
+t ; true; semua nilai yang bukan NIL ialah true
+nil ; false; termasuklah list yang kosong: ()
+(not nil) ; => T
+(and 0 t) ; => T
+(or 0 nil) ; => 0
+
+;;; Character
+
+#\A ; => #\A
+#\λ ; => #\GREEK_SMALL_LETTER_LAMDA
+#\u03BB ; => #\GREEK_SMALL_LETTER_LAMDA
+
+;;; String ialah array character yang tidak berubah panjang
+
+"Hello, world!"
+"Benjamin \"Bugsy\" Siegel" ; backslash ialah escape character
+
+;;; String boleh digabungkan
+
+(concatenate 'string "Hello, " "world!") ; => "Hello, world!"
+
+;;; String boleh diperlakukan seperti urutan character
+
+(elt "Apple" 0) ; => #\A
+
+;;; FORMAT digunakan untuk output mengikut format, daripada penggubahan string
+;;; yang simple sehinggalah loop dan conditional. Argument pertama untuk FORMAT
+;;; menentukan ke mana string akan pergi. Jika NIL, FORMAT
+;;; akan pulangkan string sebagai data string; jika T, FORMAT akan output
+;;; ke standard output, biasanya di screen, kemudian pulangkan NIL.
+
+(format nil "~A, ~A!" "Hello" "world") ; => "Hello, world!"
+(format t "~A, ~A!" "Hello" "world") ; => NIL
+
+
+;;;-----------------------------------------------------------------------------
+;;; 2. Variable
+;;;-----------------------------------------------------------------------------
+
+;;; Anda boleh membuat variable global (dynamically scoped) menggunakan DEFVAR dan
+;;; DEFPARAMETER. Nama variable boleh guna mana-mana character kecuali: ()",'`;#|\
+
+;;; Beza antara DEFVAR dengan DEFPARAMETER ialah DEFVAR tidak akan ubah nilai
+;;; variable jika dijalankan semula. Manakala DEFPARAMETER, akan mengubah nilai
+;;; jika dijalankan semula.
+
+;;; Kebiasaannya, variable global diletakkan earmuff (asterisk) pada nama.
+
+(defparameter *some-var* 5)
+*some-var* ; => 5
+
+;;; Anda juga boleh menggunakan character unicode.
+(defparameter *AΛB* nil)
+
+;;; Variable yang tidak wujud boleh diakses tetapi akan menyebabkan undefined
+;;; behavior. Jangan buat.
+
+;;; Anda boleh membuat local binding menggunakan LET. Dalam snippet berikut, `me`
+;;; terikat dengan "dance with you" hanya dalam (let ...). LET mesti akan pulangkan
+;;; nilai `form` yang paling terakhir.
+
+(let ((me "dance with you")) me) ; => "dance with you"
+
+
+;;;-----------------------------------------------------------------------------;
+;;; 3. Struct dan collection
+;;;-----------------------------------------------------------------------------;
+
+
+;;; Struct
+
+(defstruct dog name breed age)
+(defparameter *rover*
+ (make-dog :name "rover"
+ :breed "collie"
+ :age 5))
+*rover* ; => #S(DOG :NAME "rover" :BREED "collie" :AGE 5)
+(dog-p *rover*) ; => T
+(dog-name *rover*) ; => "rover"
+
+;;; DOG-P, MAKE-DOG, dan DOG-NAME semuanya dibuat oleh DEFSTRUCT secara automatik
+
+
+;;; Pair
+
+;;; CONS membuat pair. CAR dan CDR pulangkan head (kepala) dan tail (ekor) CONS-pair.
+
+(cons 'SUBJECT 'VERB) ; => '(SUBJECT . VERB)
+(car (cons 'SUBJECT 'VERB)) ; => SUBJECT
+(cdr (cons 'SUBJECT 'VERB)) ; => VERB
+
+
+;;; List
+
+;;; List ialah data structure linked-list, dihasilkan daripada pair CONS dan
+;;; berakhir dengan NIL (atau '()) menandakan akhirnya list tersebut
+
+(cons 1 (cons 2 (cons 3 nil))) ; => '(1 2 3)
+
+;;; LIST ialah constructor untuk memudahkan penghasilan list
+
+(list 1 2 3) ; => '(1 2 3)
+
+;;; Apabila argument pertama untuk CONS ialah atom dan argument kedua ialah
+;;; list, CONS akan pulangkan CONS-pair baru dengan argument pertama sebagai
+;;; item pertama dan argument kedua sebagai CONS-pair yang lain
+
+(cons 4 '(1 2 3)) ; => '(4 1 2 3)
+
+;;; Gunakan APPEND untuk menggabungkan list
+
+(append '(1 2) '(3 4)) ; => '(1 2 3 4)
+
+;;; Atau CONCATENATE
+
+(concatenate 'list '(1 2) '(3 4)) ; => '(1 2 3 4)
+
+;;; List ialah type utama, jadi ada pelbagai function untuk mengendalikan
+;;; list, contohnya:
+
+(mapcar #'1+ '(1 2 3)) ; => '(2 3 4)
+(mapcar #'+ '(1 2 3) '(10 20 30)) ; => '(11 22 33)
+(remove-if-not #'evenp '(1 2 3 4)) ; => '(2 4)
+(every #'evenp '(1 2 3 4)) ; => NIL
+(some #'oddp '(1 2 3 4)) ; => T
+(butlast '(subject verb object)) ; => (SUBJECT VERB)
+
+
+;;; Vector
+
+;;; Vector ialah array yang tidak berubah panjang
+
+#(1 2 3) ; => #(1 2 3)
+
+;;; Gunakan CONCATENATE untuk menggabungkan vector
+
+(concatenate 'vector #(1 2 3) #(4 5 6)) ; => #(1 2 3 4 5 6)
+
+
+;;; Array
+
+;;; Vector dan string adalah sejenis array.
+
+;;; 2D array
+
+(make-array (list 2 2)) ; => #2A((0 0) (0 0))
+(make-array '(2 2)) ; => #2A((0 0) (0 0))
+(make-array (list 2 2 2)) ; => #3A(((0 0) (0 0)) ((0 0) (0 0)))
+
+;;; Perhatian: nilai awal MAKE-ARRAY adalah bergantung kepada jenis Common Lisp.
+;;; Untuk meletakkan nilai awal secara manual:
+
+(make-array '(2) :initial-element 'unset) ; => #(UNSET UNSET)
+
+;;; Untuk mengakses element di kedudukan 1, 1, 1:
+
+(aref (make-array (list 2 2 2)) 1 1 1) ; => 0
+
+
+;;; Adjustable vector (vector yang boleh berubah)
+
+;;; Adjustable vector mempunyai rupa yang sama dengan
+;;; vector yang tidak berubah panjang.
+
+(defparameter *adjvec* (make-array '(3) :initial-contents '(1 2 3)
+ :adjustable t :fill-pointer t))
+*adjvec* ; => #(1 2 3)
+
+;;; Tambah element baru
+
+(vector-push-extend 4 *adjvec*) ; => 3
+*adjvec* ; => #(1 2 3 4)
+
+
+;;; Set hanyalah list:
+
+(set-difference '(1 2 3 4) '(4 5 6 7)) ; => (3 2 1)
+(intersection '(1 2 3 4) '(4 5 6 7)) ; => 4
+(union '(1 2 3 4) '(4 5 6 7)) ; => (3 2 1 4 5 6 7)
+(adjoin 4 '(1 2 3 4)) ; => (1 2 3 4)
+
+;;; Tetapi, anda perlukan data structure yang lebih baik untuk digunakan dengan
+;;; data set yang sangat banyak
+
+;;; Kamus dibuat menggunakan hash table.
+
+;;; Bina hash table
+
+(defparameter *m* (make-hash-table))
+
+;;; Tetapkan nilai
+
+(setf (gethash 'a *m*) 1)
+
+;;; Baca nilai
+
+(gethash 'a *m*) ; => 1, T
+
+;;; CL boleh memulangkan beberapa nilai (multiple value).
+
+(values 1 2) ; => 1, 2
+
+;;; dan boleh digunakan dengan MULTIPLE-VALUE-BIND untuk bind setiap nilai
+
+(multiple-value-bind (x y)
+ (values 1 2)
+ (list y x))
+
+; => '(2 1)
+
+;;; GETHASH antara contoh function yang memulangkan multiple value. Value
+;;; pertama ialah nilai untuk key dalam hash table; jika key tidak
+;;; jumpa GETHASH akan pulangkan NIL.
+
+;;; Value kedua menentukan sama ada key tersebut betul-betul wujud dalam hash
+;;; table. Jika key tidak jumpa dalam table value tersebut ialah NIL. Cara ini
+;;; membolehkan kita untuk periksa sama ada value untuk key ialah NIL.
+
+;;; Dapatkan value yang tidak wujud akan pulangkan nil
+
+(gethash 'd *m*) ;=> NIL, NIL
+
+;;; Anda boleh menentukan value default untuk key yang tidak wujud
+
+(gethash 'd *m* :not-found) ; => :NOT-FOUND
+
+;;; Jom lihat penggunaan multiple return value di dalam code.
+
+(multiple-value-bind (a b)
+ (gethash 'd *m*)
+ (list a b))
+; => (NIL NIL)
+
+(multiple-value-bind (a b)
+ (gethash 'a *m*)
+ (list a b))
+; => (1 T)
+
+
+;;;-----------------------------------------------------------------------------
+;;; 3. Function
+;;;-----------------------------------------------------------------------------
+
+;;; Gunakan LAMBDA untuk membuat anonymous function. Function sentiasa memulangkan
+;;; value untuk expression terakhir.
+
+(lambda () "Hello World") ; => #<FUNCTION (LAMBDA ()) {1004E7818B}>
+
+;;; Gunakan FUNCALL untuk memanggil anonymous function
+
+(funcall (lambda () "Hello World")) ; => "Hello World"
+(funcall #'+ 1 2 3) ; => 6
+
+;;; Panggilan kepada FUNCALL juga boleh terjadi apabila lambda tersebut ialah CAR
+;;; (yang pertama) untuk list (yang tidak mempunyai tanda petikan)
+
+((lambda () "Hello World")) ; => "Hello World"
+((lambda (val) val) "Hello World") ; => "Hello World"
+
+;;; FUNCALL digunakan apabila argument sudah diketahui. Jika tidak, gunakan APPLY
+
+(apply #'+ '(1 2 3)) ; => 6
+(apply (lambda () "Hello World") nil) ; => "Hello World"
+
+;;; Untuk menamakan sebuah function, guna DEFUN
+
+(defun hello-world () "Hello World")
+(hello-world) ; => "Hello World"
+
+;;; Simbol () di atas bermaksud list kepada argument
+
+(defun hello (name) (format nil "Hello, ~A" name))
+(hello "Steve") ; => "Hello, Steve"
+
+;;; Function boleh ada argument optional (tidak wajib); argument tersebut bernilai
+;;; NIL secara default
+
+(defun hello (name &optional from)
+ (if from
+ (format t "Hello, ~A, from ~A" name from)
+ (format t "Hello, ~A" name)))
+
+(hello "Jim" "Alpacas") ; => Hello, Jim, from Alpacas
+
+;;; Nilai default boleh ditetapkan untuk argument tersebut
+
+(defun hello (name &optional (from "The world"))
+ (format nil "Hello, ~A, from ~A" name from))
+
+(hello "Steve") ; => Hello, Steve, from The world
+(hello "Steve" "the alpacas") ; => Hello, Steve, from the alpacas
+
+;;; Function juga mempunyai keyword argument untuk membolehkan argument diletakkan
+;;; tidak mengikut kedudukan
+
+(defun generalized-greeter (name &key (from "the world") (honorific "Mx"))
+ (format t "Hello, ~A ~A, from ~A" honorific name from))
+
+(generalized-greeter "Jim")
+; => Hello, Mx Jim, from the world
+
+(generalized-greeter "Jim" :from "the alpacas you met last summer" :honorific "Mr")
+; => Hello, Mr Jim, from the alpacas you met last summer
+
+
+;;;-----------------------------------------------------------------------------
+;;; 4. Kesamaan
+;;;-----------------------------------------------------------------------------
+
+;;; CL mempunyai sistem kesaksamaan yang canggih. Antaranya adalah seperti berikut.
+
+;;; Untuk nombor, guna `='
+(= 3 3.0) ; => T
+(= 2 1) ; => NIL
+
+;;; Untuk identiti object (lebih kurang) guna EQL
+(eql 3 3) ; => T
+(eql 3 3.0) ; => NIL
+(eql (list 3) (list 3)) ; => NIL
+
+;;; untuk list, string, dan bit-vector, guna EQUAL
+(equal (list 'a 'b) (list 'a 'b)) ; => T
+(equal (list 'a 'b) (list 'b 'a)) ; => NIL
+
+
+;;;-----------------------------------------------------------------------------
+;;; 5. Control Flow
+;;;-----------------------------------------------------------------------------
+
+;;; Conditional (syarat)
+
+(if t ; test expression
+ "this is true" ; then expression
+ "this is false") ; else expression
+; => "this is true"
+
+;;; Dalam conditional, semua value yang bukan NIL ialah true
+
+(member 'Groucho '(Harpo Groucho Zeppo)) ; => '(GROUCHO ZEPPO)
+(if (member 'Groucho '(Harpo Groucho Zeppo))
+ 'yep
+ 'nope)
+; => 'YEP
+
+;;; Guna COND untuk meletakkan beberapa test
+(cond ((> 2 2) (error "wrong!"))
+ ((< 2 2) (error "wrong again!"))
+ (t 'ok)) ; => 'OK
+
+;;; TYPECASE adalah seperti switch tetapi untuk data type value tersebut
+(typecase 1
+ (string :string)
+ (integer :int))
+; => :int
+
+
+;;; Loop
+
+;;; Recursion
+
+(defun fact (n)
+ (if (< n 2)
+ 1
+ (* n (fact(- n 1)))))
+
+(fact 5) ; => 120
+
+;;; Iteration
+
+(defun fact (n)
+ (loop :for result = 1 :then (* result i)
+ :for i :from 2 :to n
+ :finally (return result)))
+
+(fact 5) ; => 120
+
+(loop :for x :across "abc" :collect x)
+; => (#\a #\b #\c #\d)
+
+(dolist (i '(1 2 3 4))
+ (format t "~A" i))
+; => 1234
+
+
+;;;-----------------------------------------------------------------------------
+;;; 6. Mutation
+;;;-----------------------------------------------------------------------------
+
+;;; Guna SETF untuk meletakkan nilai baru untuk variable yang sedia ada. Ini sama
+;;; seperti contoh hash table di atas.
+
+(let ((variable 10))
+ (setf variable 2))
+; => 2
+
+;;; Sebaik-baiknya kurangkan penggunaan destructive function dan elakkan
+;;; mutation jika boleh.
+
+
+;;;-----------------------------------------------------------------------------
+;;; 7. Class dan object
+;;;-----------------------------------------------------------------------------
+
+;;; Takde dah class untuk haiwan. Jom buat Human-Powered Mechanical
+;;; Conveyances (Kenderaan Mekanikal Berkuasa Manusia).
+
+(defclass human-powered-conveyance ()
+ ((velocity
+ :accessor velocity
+ :initarg :velocity)
+ (average-efficiency
+ :accessor average-efficiency
+ :initarg :average-efficiency))
+ (:documentation "A human powered conveyance"))
+
+;;; Argument untuk DEFCLASS, mengikut susunan ialah:
+;;; 1. nama class
+;;; 2. list untuk superclass
+;;; 3. list untuk slot
+;;; 4. specifier optional (tidak wajib)
+
+;;; Apabile list untuk superclass tidak ditetapkan, list yang kosong bermaksud
+;;; class standard-object. Ini *boleh* ditukar, kalau anda tahu apa yang anda buat.
+;;; Baca Art of the Metaobject Protocol untuk maklumat lebih lanjut.
+
+(defclass bicycle (human-powered-conveyance)
+ ((wheel-size
+ :accessor wheel-size
+ :initarg :wheel-size
+ :documentation "Diameter of the wheel.")
+ (height
+ :accessor height
+ :initarg :height)))
+
+(defclass recumbent (bicycle)
+ ((chain-type
+ :accessor chain-type
+ :initarg :chain-type)))
+
+(defclass unicycle (human-powered-conveyance) nil)
+
+(defclass canoe (human-powered-conveyance)
+ ((number-of-rowers
+ :accessor number-of-rowers
+ :initarg :number-of-rowers)))
+
+;;; Panggilan DESCRIBE kepada class HUMAN-POWERED-CONVEYANCE di REPL akan memberi:
+
+(describe 'human-powered-conveyance)
+
+; COMMON-LISP-USER::HUMAN-POWERED-CONVEYANCE
+; [symbol]
+;
+; HUMAN-POWERED-CONVEYANCE names the standard-class #<STANDARD-CLASS
+; HUMAN-POWERED-CONVEYANCE>:
+; Documentation:
+; A human powered conveyance
+; Direct superclasses: STANDARD-OBJECT
+; Direct subclasses: UNICYCLE, BICYCLE, CANOE
+; Not yet finalized.
+; Direct slots:
+; VELOCITY
+; Readers: VELOCITY
+; Writers: (SETF VELOCITY)
+; AVERAGE-EFFICIENCY
+; Readers: AVERAGE-EFFICIENCY
+; Writers: (SETF AVERAGE-EFFICIENCY)
+
+;;; Perhatikan apa yang berlaku. CL memang direka sebagai sistem interaktif.
+
+;;; Untuk membuat method, jom kira berapa panjang lilitan untuk
+;;; roda basikal menggunakan formula: C = d * pi
+
+(defmethod circumference ((object bicycle))
+ (* pi (wheel-size object)))
+
+;;; Nilai PI memang sudah ada dalam CL
+
+;;; Katakanlah kita ingin ambil tahu efficiency value (nilai keberkesanan)
+;;; rower (pendayung) di dalam canoe (perahu) adalah berbentuk logarithmic. Ini
+;;; boleh ditetapkan di dalam constructor/initializer.
+
+;;; Untuk initialize instance selepas CL sudah siap construct:
+
+(defmethod initialize-instance :after ((object canoe) &rest args)
+ (setf (average-efficiency object) (log (1+ (number-of-rowers object)))))
+
+;;; Kemudian untuk construct sesebuah instance dan periksa purata efficiency...
+
+(average-efficiency (make-instance 'canoe :number-of-rowers 15))
+; => 2.7725887
+
+
+;;;-----------------------------------------------------------------------------
+;;; 8. Macro
+;;;-----------------------------------------------------------------------------
+
+;;; Macro membolehkan anda untuk menambah syntax language. CL tidak ada
+;;; WHILE loop, tetapi, kita boleh mencipta syntax ter. Jika kita buat menggunakan
+;;; naluri, kita akan dapat:
+
+(defmacro while (condition &body body)
+ "While `condition` is true, `body` is executed.
+`condition` is tested prior to each execution of `body`"
+ (let ((block-name (gensym)) (done (gensym)))
+ `(tagbody
+ ,block-name
+ (unless ,condition
+ (go ,done))
+ (progn
+ ,@body)
+ (go ,block-name)
+ ,done)))
+
+;;; Jom lihat versi yang lebih high-level:
+
+(defmacro while (condition &body body)
+ "While `condition` is true, `body` is executed.
+`condition` is tested prior to each execution of `body`"
+ `(loop while ,condition
+ do
+ (progn
+ ,@body)))
+
+;;; Namun, dengan compiler yang modern, cara ini tidak diperlukan; form LOOP
+;;; compile sama sahaja dan juga mudah dibaca.
+
+;;; Perhatikan ``` digunakan, sama juga `,` dan `@`. ``` ialah operator jenis quote
+;;; yang dipanggil quasiquote; operator tersebut membolehkan penggunaan `,` .
+;;; `,` membolehkan variable "di-unquote-kan". @ mengembangkan list.
+
+;;; GENSYM membuat simbol unik yang pasti tidak wujud di tempat-tempat yang
+;;; lain. Ini kerana macro dikembangkan semasa compile dan
+;;; nama variable di dalam macro boleh bertembung dengan nama variable yang
+;;; digunakan dalam code yang biasa.
+
+;;; Baca Practical Common Lisp dan On Lisp untuk maklumat lebih lanjut mengenai macro.
+```
+
+
+## Bacaan lanjut
+
+- [Practical Common Lisp](http://www.gigamonkeys.com/book/)
+- [Common Lisp: A Gentle Introduction to Symbolic Computation](https://www.cs.cmu.edu/~dst/LispBook/book.pdf)
+
+
+## Maklumat tambahan
+
+- [CLiki](http://www.cliki.net/)
+- [common-lisp.net](https://common-lisp.net/)
+- [Awesome Common Lisp](https://github.com/CodyReichert/awesome-cl)
+- [Lisp Lang](http://lisp-lang.org/)
+
+
+## Kredit
+
+Terima kasih banyak diucapkan kepada ahli Scheme yang membuat permulaan yang sangat
+bagus dan mudah untuk diguna pakai untuk Common Lisp.
+
+- [Paul Khuong](https://github.com/pkhuong) untuk review yang bagus.
diff --git a/ms-my/elisp-my.html.markdown b/ms-my/elisp-my.html.markdown
new file mode 100644
index 00000000..73dff0f4
--- /dev/null
+++ b/ms-my/elisp-my.html.markdown
@@ -0,0 +1,347 @@
+---
+language: elisp
+contributors:
+ - ["Bastien Guerry", "https://bzg.fr"]
+ - ["Saurabh Sandav", "http://github.com/SaurabhSandav"]
+translators:
+ - ["Burhanuddin Baharuddin", "https://github.com/burhanloey"]
+lang: ms-my
+filename: learn-emacs-lisp-ms.el
+---
+
+```scheme
+;; Ini adalah pengenalan kepada Emacs Lisp dalam masa 15 minit (v0.2d)
+;;
+;; Mula-mula pastikan anda sudah membaca artikel daripada Peter Norvig ini:
+;; http://norvig.com/21-days.html
+;;
+;; Kemudian install GNU Emacs 24.3:
+;;
+;; Debian: apt-get install emacs (atau lihat arahan untuk distro anda)
+;; OSX: http://emacsformacosx.com/emacs-builds/Emacs-24.3-universal-10.6.8.dmg
+;; Windows: http://ftp.gnu.org/gnu/windows/emacs/emacs-24.3-bin-i386.zip
+;;
+;; Maklumat lanjut boleh didapati di:
+;; http://www.gnu.org/software/emacs/#Obtaining
+
+;; Amaran penting:
+;;
+;; Tutorial ini tidak akan merosakkan komputer anda melainkan jika anda berasa
+;; terlalu marah sehingga anda menghempap komputer anda ke lantai. Kalau begitu,
+;; saya dengan ini tidak akan bertanggungjawab terhadap apa-apa. Berseronoklah ya!
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Buka Emacs.
+;;
+;; Tekan `q' untuk tutup mesej selamat datang.
+;;
+;; Sekarang lihat garis kelabu di bahagian bawah window:
+;;
+;; "*scratch*" ialah nama ruangan untuk anda edit.
+;; Ruangan ini disebut sebagai "buffer".
+;;
+;; Buffer scratch ialah buffer yang default setiap kali Emacs dibuka.
+;; Anda bukannya edit file: anda edit buffer yang kemudiannya
+;; boleh save ke file.
+;;
+;; "Lisp interaction (interaksi)" merujuk kepada command yang wujud di sini.
+;;
+;; Emacs mempunyai beberapa command yang sedia ada dalam setiap buffer,
+;; dan sesetengah command yang lain boleh didapati jika sesetengah mode
+;; diaktifkan. Di sini kita menggunakan `lisp-interaction-mode', yang
+;; mempunyai command untuk menjalankan dan mengendalikan code Elisp.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Semicolon akan menjadikan comment sepanjang baris tersebut.
+;;
+;; Program Elisp mengandungi symbolic expressions ("sexps"):
+(+ 2 2)
+
+;; Symbolic expression di atas dibaca begini "Tambah 2 pada 2".
+
+;; Sexps dilitupi oleh parentheses, dan boleh dalam bentuk nested (parentheses
+;; dalam parentheses):
+(+ 2 (+ 1 1))
+
+;; Symbolic expression mengandungi atom atau symbolic expression
+;; yang lain. Untuk contoh di atas, 1 dan 2 ialah atom,
+;; (+ 2 (+ 1 1)) dan (+ 1 1) ialah symbolic expression.
+
+;; Dengan menggunakan `lisp-interaction-mode', anda boleh evaluate
+;; (mendapatkan hasil pengiraan) sexps. Letak cursor selepas parenthesis penutup
+;; kemudian tekan control dan j ("C-j").
+
+(+ 3 (+ 1 2))
+;; ^ cursor di sini
+;; `C-j' => 6
+
+;; `C-j' memasukkan jawapan pengiraan ke dalam buffer.
+
+;; `C-xC-e' memaparkan jawapan yang sama di bahagian bawah Emacs,
+;; yang dipanggil "minibuffer". Secara umumnya kita akan menggunakan `C-xC-e',
+;; sebab kita tidak mahu memenuhi buffer dengan teks yang tidak penting.
+
+;; `setq' menyimpan value ke dalam variable:
+(setq my-name "Bastien")
+;; `C-xC-e' => "Bastien" (terpapar di mini-buffer)
+
+;; `insert' akan memasukkan "Hello!" di tempat di mana cursor berada:
+(insert "Hello!")
+;; `C-xC-e' => "Hello!"
+
+;; Di atas, kita menggunakan `insert' dengan satu argument "Hello!", tetapi
+;; kita boleh meletakkan beberapa argument -- di sini kita letak dua:
+
+(insert "Hello" " world!")
+;; `C-xC-e' => "Hello world!"
+
+;; Anda boleh menggunakan variable selain string:
+(insert "Hello, I am " my-name)
+;; `C-xC-e' => "Hello, I am Bastien"
+
+;; Anda boleh menggabungkan sexps untuk membuat function:
+(defun hello () (insert "Hello, I am " my-name))
+;; `C-xC-e' => hello
+
+;; Anda boleh evaluate function:
+(hello)
+;; `C-xC-e' => Hello, I am Bastien
+
+;; Parentheses kosong di dalam function bermaksud function tersebut tidak
+;; terima argument. Sekarang kita tukar function untuk menerima satu argument.
+;; Di sini, argument tersebut dinamakan "name":
+
+(defun hello (name) (insert "Hello " name))
+;; `C-xC-e' => hello
+
+;; Sekarang panggil function tersebut dengan string "you" sebagai value
+;; untuk argument:
+(hello "you")
+;; `C-xC-e' => "Hello you"
+
+;; Yay!
+
+;; Tarik nafas.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Sekarang tukar ke buffer baru dengan nama "*test*" di window yang lain:
+
+(switch-to-buffer-other-window "*test*")
+;; `C-xC-e'
+;; => [The screen has two windows and cursor is in the *test* buffer]
+
+;; Gerakkan mouse ke window atas dan klik kiri untuk pergi balik ke buffer scratch.
+;; Cara lain adalah dengan menggunakan `C-xo' (i.e. tekan control-x kemudian
+;; tekan o) untuk pergi ke window yang lain.
+
+;; Anda boleh menggabungkan beberapa sexps menggunakan `progn':
+(progn
+ (switch-to-buffer-other-window "*test*")
+ (hello "you"))
+;; `C-xC-e'
+;; => [The screen has two windows and cursor is in the *test* buffer]
+
+;; Mulai dari sekarang saya tidak akan beritahu anda untuk tekan `C-xC-e' lagi:
+;; buat untuk setiap sexp yang akan datang.
+
+;; Pergi balik ke buffer *scratch* menggunakan mouse atau `C-xo'.
+
+;; Seelok-eloknya padam buffer tersebut:
+(progn
+ (switch-to-buffer-other-window "*test*")
+ (erase-buffer)
+ (hello "there"))
+
+;; Atau pergi balik ke window lain:
+(progn
+ (switch-to-buffer-other-window "*test*")
+ (erase-buffer)
+ (hello "you")
+ (other-window 1))
+
+;; Anda boleh menetapkan value dengan local variable menggunakan `let':
+(let ((local-name "you"))
+ (switch-to-buffer-other-window "*test*")
+ (erase-buffer)
+ (hello local-name)
+ (other-window 1))
+
+;; Tidak perlu menggunakan `progn', sebab `let' juga menggabungkan
+;; beberapa sexps.
+
+;; Jom format string:
+(format "Hello %s!\n" "visitor")
+
+;; %s ialah tempat untuk meletakkan string, digantikan dengan "visitor".
+;; \n ialah character untuk membuat baris baru.
+
+;; Jom tukar function kita menggunakan format:
+(defun hello (name)
+ (insert (format "Hello %s!\n" name)))
+
+(hello "you")
+
+;; Jom buat function lain menggunakan `let':
+(defun greeting (name)
+ (let ((your-name "Bastien"))
+ (insert (format "Hello %s!\n\nI am %s."
+ name ; argument untuk function
+ your-name ; variable "Bastien" daripada let
+ ))))
+
+;; Kemudian evaluate:
+(greeting "you")
+
+;; Sesetengah function adalah interaktif:
+(read-from-minibuffer "Enter your name: ")
+
+;; Function tersebut akan memulangkan kembali apa yang anda masukkan ke prompt.
+
+;; Jom jadikan function `greeting' untuk prompt nama anda:
+(defun greeting (from-name)
+ (let ((your-name (read-from-minibuffer "Enter your name: ")))
+ (insert (format "Hello!\n\nI am %s and you are %s."
+ from-name ; argument untuk function
+ your-name ; variable daripada let, yang dimasukkan dari prompt
+ ))))
+
+(greeting "Bastien")
+
+;; Jom siapkan function dengan memaparkan result di window yang lain:
+(defun greeting (from-name)
+ (let ((your-name (read-from-minibuffer "Enter your name: ")))
+ (switch-to-buffer-other-window "*test*")
+ (erase-buffer)
+ (insert (format "Hello %s!\n\nI am %s." your-name from-name))
+ (other-window 1)))
+
+;; Test function tersebut:
+(greeting "Bastien")
+
+;; Tarik nafas.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Jom simpan senarai nama:
+;; Jika anda ingin membuat list(senarai) data, guna ' untuk elak
+;; daripada list tersebut evaluate.
+(setq list-of-names '("Sarah" "Chloe" "Mathilde"))
+
+;; Dapatkan elemen pertama daripada list menggunakan `car':
+(car list-of-names)
+
+;; Dapatkan semua elemen kecuali yang pertama menggunakan `cdr':
+(cdr list-of-names)
+
+;; Tambah elemen di awal list menggunakan `push':
+(push "Stephanie" list-of-names)
+
+;; NOTA: `car' dan `cdr' tidak ubah suai list, tetapi `push' ya.
+;; Perbezaan ini penting: sesetengah function tiada side-effects (kesan sampingan)
+;; (seperti `car') dan yang lain ada side-effect (seperti `push').
+
+;; Jom panggil `hello' untuk setiap elemen dalam `list-of-names':
+(mapcar 'hello list-of-names)
+
+;; Tukar `greeting' supaya ucapkan hello kepada semua orang dalam `list-of-names':
+(defun greeting ()
+ (switch-to-buffer-other-window "*test*")
+ (erase-buffer)
+ (mapcar 'hello list-of-names)
+ (other-window 1))
+
+(greeting)
+
+;; Ingat lagi function `hello' di atas? Function tersebut mengambil satu
+;; argument, iaitu nama. `mapcar' memanggil `hello', kemudian menggunakan setiap
+;; nama dalam `list-of-names' sebagai argument untuk function `hello'.
+
+;; Sekarang kita susun sedikit untuk apa yang terpapar di buffer:
+
+(defun replace-hello-by-bonjour ()
+ (switch-to-buffer-other-window "*test*")
+ (goto-char (point-min))
+ (while (search-forward "Hello")
+ (replace-match "Bonjour"))
+ (other-window 1))
+
+;; (goto-char (point-min)) akan pergi ke permulaan buffer.
+;; (search-forward "Hello") akan mencari string "Hello".
+;; (while x y) evaluate sexp(s) y selagi x masih pulangkan sesuatu.
+;; Jika x pulangkan `nil', kita akan keluar daripada while loop.
+
+(replace-hello-by-bonjour)
+
+;; Anda akan dapat melihat semua "Hello" dalam buffer *test*
+;; ditukarkan dengan "Bonjour".
+
+;; Anda juga akan dapat error: "Search failed: Hello".
+;;
+;; Bagi mengelakkan error tersebut, anda perlu beritahu `search-forward' sama ada
+;; perlu berhenti mencari pada suatu ketika, dan sama ada perlu diam jika
+;; tidak jumpa apa yang dicari:
+
+;; (search-forward "Hello" nil 't) selesai masalah:
+
+;; Argument `nil' cakap: carian tidak mengikut kedudukan.
+;; Argument `'t' cakap: diam saja jika tidak jumpa apa yang dicari.
+
+;; Kita guna sexp ini di function berikut, barulah tidak keluar error:
+
+(defun hello-to-bonjour ()
+ (switch-to-buffer-other-window "*test*")
+ (erase-buffer)
+ ;; Ucap hello pada nama-nama dalam `list-of-names'
+ (mapcar 'hello list-of-names)
+ (goto-char (point-min))
+ ;; Ganti "Hello" dengan "Bonjour"
+ (while (search-forward "Hello" nil 't)
+ (replace-match "Bonjour"))
+ (other-window 1))
+
+(hello-to-bonjour)
+
+;; Jom jadikan nama-nama tersebut bold:
+
+(defun boldify-names ()
+ (switch-to-buffer-other-window "*test*")
+ (goto-char (point-min))
+ (while (re-search-forward "Bonjour \\(.+\\)!" nil 't)
+ (add-text-properties (match-beginning 1)
+ (match-end 1)
+ (list 'face 'bold)))
+ (other-window 1))
+
+;; Function ini memperkenalkan `re-search-forward': anda mencari menggunakan
+;; pattern iaitu "regular expression", bukannya mencari string "Bonjour".
+
+;; Regular expression tersebut ialah "Bonjour \\(.+\\)!" dan dibaca begini:
+;; string "Bonjour ", dan
+;; kumpulan | ini ialah \\( ... \\)
+;; mana-mana character | ini ialah .
+;; yang boleh berulang | ini ialah +
+;; dan string "!".
+
+;; Dah sedia? Test function tersebut!
+
+(boldify-names)
+
+;; `add-text-properties' tambah... ciri-ciri teks, seperti face.
+
+;; OK, kita sudah selesai. Selamat ber-hacking!
+
+;; Jika anda ingin tahu lebih mengenai variable atau function:
+;;
+;; C-h v a-variable RET
+;; C-h f a-function RET
+;;
+;; Jika anda ingin membaca manual Emacs Lisp menggunakan Emacs:
+;;
+;; C-h i m elisp RET
+;;
+;; Jika ingin membaca pengenalan kepada Emacs Lisp secara online:
+;; https://www.gnu.org/software/emacs/manual/html_node/eintr/index.html
+```
diff --git a/ms-my/javascript-my.html.markdown b/ms-my/javascript-my.html.markdown
index 90e37133..9a7a23ba 100644
--- a/ms-my/javascript-my.html.markdown
+++ b/ms-my/javascript-my.html.markdown
@@ -1,7 +1,7 @@
---
language: javascript
contributors:
- - ["Adam Brenecki", "http://adam.brenecki.id.au"]
+ - ["Leigh Brenecki", "https://leigh.net.au"]
- ["Ariel Krakowski", "http://www.learneroo.com"]
filename: javascript-ms.js
translators: