Gih's Blog

Personal posts, tech notes, and things I am playing with.


2015-04-06 by gihnius, tagged as internet
今天更新了式样, 添加了 Disqus 评论系统, 欢迎评论. 链接也采用标题描述取代原来的日期方式.


2015-04-02 by gihnius, tagged as web 是一个用 Go 语言写的知识分享的社区网站, 运行已经有大半年, 今天把它给关了,因为我完全不懂也没有足够的时间去好好运营一个社区网站. 就像博客一样, 也是当年 (2011) 一时心血来潮搭起来的. 当时自己并没有想过怎样去写好博客, 就拿一些技术记录来充数, 到现在也一样, 只不过都运行这么几年了, 关闭了有点可惜.


Thrush calls in Common Lisp

2014-09-19 by gihnius, tagged as lisp

Implement the "->" operator of Clojure: in CL, that's funny.


Threads the expr through the forms. Inserts x as the second item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the second item in second form, etc.

(defmacro -> (x &optional (form nil form-supplied-p) &rest more)
  (if form-supplied-p
      (if more
          `(-> (-> ,x ,form) ,@more)
          (if (listp form)
              `(,(car form) ,x ,@(cdr form))
              (list form x)))

How does it works?

CL-USER> (-> 1
             (+ 1)
             (+ 2)
             (+ 3))


=== (+ (+ (+ 1 1) 2) 3)

See another example:

CL-USER> (-> 10
             (- 5)
             (- 5)
             (- 5))

=== (- (- (- 10 5) 5) 5)

How if I want (- 5 (- 5 (- 5 10)))?

There is ->> to do this.


Threads the expr through the forms. Inserts x as the last item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the last item in second form, etc.

(defmacro ->> (x &optional (form nil form-supplied-p) &rest more)
  (if form-supplied-p
      (if more
          `(->> (->> ,x ,form) ,@more)
          (if (listp form)
              `(,(car form) ,@(cdr form) ,x)
              (list form x)))

This one looks more useful sometimes.

CL-USER> (->> (list 1 2 3 4 5)
              (reduce '+)
              (* 2)
              (- 5))

=== (- 5 (* 2 (reduce '+ '(1 2 3 4 5))))

Move from Sr-SpeedBar to NeoTree

2014-09-17 by gihnius, tagged as emacs

NeoTree is more lightweight and simple.

;; (require 'sr-speedbar)
;; (make-face 'speedbar-face)
;; (set-face-font 'speedbar-face "DejaVu Sans Mono-11")
;; (setq speedbar-use-images nil)
;; (setq sr-speedbar-delete-windows t)
;; (setq sr-speedbar-right-side nil)
;; (setq sr-speedbar-width-x 25)
;; (setq sr-speedbar-width-console 25)
;; (setq sr-speedbar-max-width 30)
;; (setq speedbar-verbosity-level 0)
;; (setq sr-speedbar-skip-other-window-p t)

;; install neotree by ELPA
;; use neotree instead
(require 'neotree)
(setq neo-window-width 28)

how they looks?

A complete brief notes on setting up 3 nodes HBase cluster.

2014-09-17 by gihnius, tagged as linux

Here is an experience on setting up a 3-nodes-hbase-cluster(1 name-node and 2 data-node)  on AWS EC2.

Read more »

Secure your cookies of Hunchentoot in Common Lisp.

2014-09-17 by gihnius, tagged as lisp

Encrypt and decrypt cookies in hunchentoot. What is COOKIE?

Hunchentoot - The Common Lisp web server formerly known as TBNL

Hunchentoot is a web server written in Common Lisp and at the same time a toolkit for building dynamic websites. As a stand-alone web server, Hunchentoot is capable of HTTP/1.1 chunking (both directions), persistent connections (keep-alive), and SSL.

By default, hunchentoot supports cookies, but all cookies will be exposed once a request was done from the client. And there is not a solution to secure the cookies transform by now in hunchentoot. So the temporary choice is using the hunchentoot session:

Read more »

create small emacs window

2014-09-08 by gihnius, tagged as emacs

create a small "mini pad" from emacs by make-frame function.

(defun make-mini-pad ()
  (make-frame '(
                (name . "mini")
                (width . 72)
                (height . 39))))

M-x make-mini-pad

这么玩 lisp,实在让人蛋疼!

2014-09-08 by gihnius, tagged as lisp


(defun getenv (var)
  #+cmu (cdr (assoc (if (symbolp var)
                        (intern var :keyword))
  #+sbcl (sb-ext:posix-getenv (string var))
  #+lispworks (hcl:getenv var)
  #+clisp (ext:getenv (string var))
  #+allegro (sys:getenv (string var))
  #-(or cmu sbcl lispworks clisp allegro)
  (error "GETENV not implemented for your Lisp platform."))

Speeding up fsck on the disk of TimeMachine

2014-09-06 by gihnius, tagged as mac

Why fsck?

Sometimes the file system get corrupted and hence you may unable to boot your system. In such case you will need to repair the corrupted file system. In Linux you can repair it using fsck command. In windows we have command chkdsk. In OSX we have "fsck", "fsck_hfs".

There are several reasons behind the file system corruption. For example, improper shutdown, suddenly cut off the power supply, a storage device was removed when system is in process to write the data on it, accidental system file deletion and viruses can cause file corruption and unstable system. Some file corruptions are less harmful and user can continue working. However it is important to run a “fsck” once in a while as a practice.

Why time machine?

Time Machine is Apple's built-in backup solution for OS X that creates hourly backups of all files on the system. It takes many snapshots of your local drive, copies many millions of files to the backup disk volume.  By default, Checking the time machine disk volumes with Disk Utility,  can be painfully slow, taking many hours or days to complete, if it completes at all.


Find the time machine disk, open, type diskutils list, find the line contains Apple_HFS YOUR_DISK_NAME, get the device name from the last column below IDENTIFIER, for example, disk3, disk4...

Run fsck_hfs with 2G memory cache:(adjust less than the system memory)

sudo fsck_hfs -f -y -c 2g /dev/disk3

The key is to increase the size of the cache used by fsck_hfs. see more from manual:

-c size Specify the size of the cache used by fsck_hfs internally.  Bigger size
        can result in better performance but can result in deadlock when used
        with -l option.  Size can be specified as a decimal, octal, or hexadec-
        imal number.  If the number ends with a ``k'', ``m'', or ``g'', the
        number is multiplied by 1024 (1K), 1048576 (1M), or 1073741824 (1G),

Learn about using Disk Utility to verify or repair disks.

Another way to make memoization function in Go

2014-09-03 by gihnius, tagged as go

Cache any function calls in Go without using reflect, very simple idea, use a normal memory cache.

Here is what I do:

package memoize

import (

type memo struct {
    Timeout time.Time
    Result interface{}

type MemoPool struct {
    Pool map[string]*memo
    mutex *sync.RWMutex

var mp *MemoPool

func init() {
    var m = map[string]*memo{}
    mp = &MemoPool{Pool: m, mutex: new(sync.RWMutex)}

// memorize result return from caller() block, timeout in N seconds
func Memoize(key string, caller func() interface{}, timeout uint) interface{} {
    if timeout == 0 {
        // do not memoize
        return caller()
    memoized := mp.Pool[key]
    // reached timeout or not memoized
    if memoized == nil || memoized.Timeout.Before(time.Now()) {
        result := caller()
        if result != nil {
            duration := time.Duration(timeout) * time.Second
            mp.Pool[key] = &memo{
                Timeout: time.Now().Add(duration),
                Result: result,
        return result
    return memoized.Result

func UnMemoize(key string) {
    delete(mp.Pool, key)

func UnMemoizeAll() {
    for key, _ := range mp.Pool {
        delete(mp.Pool, key)

Check out the code from github:


import "memoize"
// cache a function call for TimeOut (>= 0) seconds
memoize.Memoize("Cache_Key", func() interface{} {
  cache_return_value, err := your_function(args)
  if err != nil {
    // handle err
    // won't cache if return nil
    return nil
  return cache_return_value
}, TimeOut)

// save result
result := memoize.Memoize("Cache_Key", func() interface{} {
  // call your function(s)
  cache_return_value, err := your_function(args)
  if err != nil {
    // handle err
    // won't cache if return nil
    return nil
  return cache_return_value
}, TimeOut).(your_function_return_type)

// cache a long time calc subroutine
func calc_sub(i int, s string) (string, err) {
  // ...
result := Memoize("calc_sub", func() interface{} {
  res, err := calc_sub(1000, "string to process")
  if err != nil {
    return nil // not memoized
  return res
}, 60) // cache for 1 minutes

// re-fetch the memoized(cached) result with the same call.

// remove a cached call
// remove all cached calls


git clone
cd gomemoize
# or
VERBOSE="-v" ./

It works well but not so functional.

More about  Memoization from Wikipedia.