给作者编号

给作者编号

Author Number

http://zhanxw.com/author

 

最近写了一个网页,主要解决写文章给作者编号的问题。这个问题怎么来的呢?现在的文章需要提供作者,作者工作单位和作者的贡献,但是提供的方式是给每个作者单位按照作者出现的顺序编号。比如我的文章有79个作者,现在突然要加一个新的合作者,把他拍到第50位,那么从第51位到最后一位作者的编号可能都需要改变。这个过程很容易出错。我想写个软件给所有人用,顺便凑个热闹,学习一下jQuery + Django,最后的作品放到我的网页(link)。在这个过程中,还学习了Nginx, Emacs web-mode, 这篇笔记主要是把我的经验记录下来。

 

1. 学习Django

Django是Python语言实现的Web架构,它最开始是用于展示新闻(Newroom),国内的豆瓣也用Django。作为Python的“粉丝”,我学一下Django,希望以后可以把有用的工具放到网上。

想入门,最好最省时间的方法是Django tutorial,就在Django的官方网页。这个Tutorial一共有六个部分,介绍的常用Django的功能,包括: 模型(Model),模板(Template),视图(View),静态文件(Static),管理界面(Admin),网址分发(URL Dispatching)等等。学习之后,我感到Django的强项是利用Python语言做到来简化数据库使用。对于一个简单的App,基本开发的流程是: (1)设定project 的settings.py 和urls.py,注册新的app ;(2)设定urls.py来确定网址和视图(View)的关系;(3)用HTML开发模板(/template/app/XXX.html)同时实现各种需要的视图(views.py)

架设Django,一般简易使用uWSGI。我使用的是Nginx处理静态页面,同时用uWSGI处理Django相关界面。简易先在本机用uWSGI调好程序,再放到服务器上并配置Nginx和uWSGI。

Djano默认使用Unicode,而我们一般都用str(),这是ASCII编码。两种编码对于字符串处理来讲(包括join, index)没有什么区别,但在print的时候,Unicode的字符应该先转成UTF-8字符,比如: print u”aaa”.encode(‘UTF-8’)

 

2. 学习jQuery

用jQuery的主要目的是用Ajax来更新网页数据,这样用户用起来有行云流水的感觉。jQuery有.get 和 .post两个方法,使用起来和访问网页很相似。不过这里面有几个陷阱。第一个是GET方式适合小数据,对于Django来讲,默认的大小是4096个字符,大一点的数据应该用POST;第二个陷阱就是POST,为了安全(CSRF: cross-site request forgery),Django要求POST的数据必须有csrftoken,一般的HTML表格Form必须有csrf的标记才会被Django接收。

为了调试Ajax的输入输出,简易用Firefox下的FireBug或者最新版本的Firefox,它们都可以显示Ajax请求的参数和返回值。最新版本的Firefox还可以给Javascript设置断点,这就更加降低了调试的难度。

jQuery的功能很多,这个网页把jQuery 1.9以及之前版本的功能用不同颜色区分出来,很方便查询(link)。

在这个网页中,我还用了handsontable,这是一个在jQuery的基础上开发的实用的javascript spreadsheet,语法简单,使用方便。

3. 一点Nginx经验

对Nginx来讲,我们的配置是用location语句来把特定的网址传给uWSGI进程。注意Nginx设置里如果有多个location语句,Nginx并不一定选择最先匹配的网址,而是选择最长的网址。比如:

location ~* /author/static/.+.(jpg|jpeg|gif|css|png|js|ico|xml)$ {
root /var/django/zhanxw/; # STATIC_ROOT
expires 30d;
}

location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico|xml)$ {
access_log        off;
expires           30d;
root /var/www;
}

如果第一个location写成: “location /author/static”,那么.jpg之类的文件会被第二个location处理,这就不是Django static文件的正确处理方式。

 

4. 一点Emacs web-mode经验

用Emacs写Django的模板HTML,最好用的不是django-html-mode,而是web-mode。只有这个mode可以识别 “{% static ‘polls/index.html’ %}”这样的记号,并正确缩进。

此外web-mode可以自动补全HTML tab,比如你在<p>后面打</,web-mode会帮你补全</p>。还可以用C-c C-e b 和C-c C-e e跳到一对tag的最前面(beginning)和最后面(end)。

 

5. 一般性经验

最开始设计应该以最少功能,最小实现为好,不要一下子把界面设计复杂。可以想几个用例(Use Case),保证最基本最重要的功能,其他功能应该越少越好。

网页的布局应该少用<br/>这种硬回车。在有Bootstrap的情况下,完全可以用<div>和<p>来用更少的HTML tag来实现更自然、自动的布局。

 

iTerm2和Emacs的Meta Key

How to set up Meta appropriately for iTerm2

学校的电脑是Mac,Mac下最好的terminal是iTerm2;我用的编辑器是Emacs,但Terminal下的Emacs不能正常工作,比如M+/是我设置的hippie-expand,我不能用Alt/Command + /按出来,一定要用Esc+/ 。
被困扰了好久之后,我终于下定决心彻底解决这个问题。
NOTE:Alt/Command 指的是一个按键,在windows键盘上是Alt,Mac键盘上叫做Command,上面有一个四瓣的小花(Apple Clove)

首先要弄清楚流程:
1. 我按的键能不能传入iTerm2?
2. iTerm2如何把我的击键传到远处的Linux Terminal?
3. 远端的Terminal里的Emacs能不能正确解析击键?

1. 我按的键能不能传入iTerm2?

在Mac系统,一些组合键还真不一定能传到iTerm2,举个例子:Alt/Command + / ,这个是iTerm2里Find Cursor的Shortcuts,就是我一按这个组合键,就执行Find Cursor的功能,iTerm里的shell是收不到我的按键的。
解决方法:详细见这个邮件列表 http://groups.google.com/group/iterm2-discuss/browse_thread/thread/e960f5098ff3c4a0
就是增加一个系统级别的设置,把Find Cursor的组合键Overwrite掉。

顺便说,我顺便发现一个工具ShiftIt,就是用组合键安排窗口,比如:把窗口最大化,放在左边1/2,右边1/2…… 非常顺手。

2. iTerm2如何把我的击键传到远处的Linux Terminal?

下面是假设我按下键了,iTerm2会把我的击键传到Linux Terminal上。注意这个过程并不简单,因为我的按键会被remap,也会被改动。
举例来说,如果我按下Alt/Command,如果有remap(比如在iTerm2里设置了,或者用Double Command等设置了Remap),实际打出的可能是Option(就是Windows键盘上的Win键)。
还有一种可能是我的击键是Alt/Command,但Linux Terminal不认识Alt/Command,只有强制iTerm2把Alt/Command输出成+Esc 才成。

简单来说,在iTerm2 针对每个Session的设定里,在设定keys时,选择Preset xterm;然后把左右Option Key都选成+Esc。
另外在Linux Terminal中.inputrc文件中加入:
set input-meta on
set output-meta on
set convert-meta off

更多资料,参见在iTerm2里设置Emacs 和 paredit以及 iTerm2官方讲Keybinding的wiki

其中官方wiki指出了一个技巧,Ctrl+V,然后击键,可以看出到底快捷键具体是什么,比如Ctrl+v,然后按Esc,就会出现:”^[“, 说明Esc对应 ^[

3. 远端的Terminal里的bash/Emacs能不能正确解析击键?

Bash 常用的一个功能是backward-kill-word,就是说用快捷键向前删除单词,一般可以用Ctrl+W,还有一种常用的快捷键是Alt+Backspace。比如在iTerm2里可以Remap Alt+Backspace,但是怎么才能输入Alt+Backspace呢?直接输入时,Backspace会删除上一个字符,这时候通过查ASCII表,可以看到Hex 0x17对应backspace,那么我在iTerm2里设置0x17就可以了。

现在在Terminal 方式的Emacs里面(emacs -nw方式),应该可以用Option来代替Meta键,比如Meta+/可以用Option+/来输入。但如果我还是习惯用Alt/Command+/怎么办?
为了不在Emacs里设置,可以在iTerm2中设置 Alt/Command + / 为发送Escaped sequenced: ^[ /

假设我们按了快捷键,只有要Emacs事先知道快捷键对应什么功能才行。(例如可以用Ctrl+h k来看我们输入的快捷键对应的功能)。

经过以上三步,现在如果我需要在Emacs里输入Alt/Command + /, 可以按Esc+/ , Alt/Command + /, 或Option + / .
当然好处不止如此,比如在Emacs里各个窗口移动,可以很方便的用Shift+ArrowKey; 在一个文档快速移动,可以用Ctrl+ArrowKey。当然最大的好处是可以用Option作为Meta,以后按键就方便多了。

2016-12-09补充
如果在GNU screen里用Emacs,需要在.screenrc里加入这两行:
term xterm
c1 off

这是为了确保GNU screen不会改变键盘上输入的Escape sequence。
换句话说,可以保证“Shift+向右的箭头”可以从键盘送到Emacs程序。

GDB 使用经验(二)

GDB 使用经验(二)
Hints of using GDB inside Emacs

继续前文GDB 使用经验, 这里介绍在Emacs中使用GDB的一点经验。

(1) GDB many windows mode 【1】

在M-x gdb 启动Emacs 中的GDB mode 之后,我们可以 M-x gdb-many-windows, 将GDB comand(GDB 命令)、local variable(局部变量)、source code(源程序代码)、stack(堆,用于检查函数调用的层数)、breakpoints(所有已经设置的断点)这5个有用的窗口排列起来。

如果想少打几个键,可以把下面的代码放到~/.emacs,这样以后M-x gmw 就等于是M-x gdb-many-windows了。

(defun gmw ()
"start gdb-many-windows"
(gdb-many-windows))

(2) 快捷键 Short cuts

在GDB中, 常用的命令包括continue, next等等。在Eamcs中的快捷键因窗口的不同而不同。例如,在GDB command窗口,next 的快捷键是C-x C-a C-n,而在source code窗口, next的快捷键是C-c C-n。但我们可以总结规律为基本命令都是prefix + key 的形式。

在GDB command 窗口的prefix 都是:C-c
在source code 窗口的prefix 都是:C-x C-a

key对应于next命令是: C-n
key对应于step命令是: C-s
key对应于until命令是: C-u
key对应于continue命令是: C-r
key对应于finish命令是: C-f
key对应于watch expression命令是: C-w (光标所在的变量会被watch,会出现另外一个窗口显示该变量)
key对应于print expression命令是: C-p (需要先mark一个region,这个region表示的expression表达式会被打印出来)
key对应于temporary breakpoint(临时断点)命令是: C-t
key对应于delete breakpoint(删除断点)命令是: C-d (如果当前行有断点,则删除之)

(3) Enable tools tips 【2】

在Visual Studio中另一个有用的功能是:当鼠标移动到一个变量上时,这个变量的值会通过tooltip的方式显示出来。
这个功能在GDB中也能实现。
在GUD菜单中选中”Show GUD tooltips”即可。使用效果如下:

【1】Fancy Debugging
【2】Tooltips

学习和应用Google C++ Coding Style Guide (in Emacs)

Learning and applying coding style from Google (in Emacs)

今天李开复的博客转发了一条围脖,大意是:Google C++ Coding Style是最好的Coding Style,没有之一。
以前虽然经Paul提示过,但当时的我并没有提起足够的重视,现在重新看了一下,受益匪浅。
http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml Google C++ Style Guide

这个Style Guide不仅提示并规定了如何格式化代码,还对C++中的特性做了对比和使用建议。例如:
(1) 对于引用(reference)的参数,应该尽量使用const来做修饰,否则我们不知道程序中修改的值会不会有超出该函数的作用;
(2) 对于要修改值的参数,则提倡使用指针。
(3) 还有,对于构造函数Constructor,Google 认为应使用explicit关键字来修饰,这样防止编译器做隐式的类型转换,同时构造函数必须明确的写出来,即使是与default的形式是相同的。
(4) 对于头文件的引用,Google 建议使用Forward declaration(提前声明)来减少包含过多的文件次数

在这个Style Guide之中,还提到了一个有用的工具cpplint.py, 这个Python工具可以对照Google Style Guide去检查你的代码是否符合规范。我是一个Emacs fans,那么如何把Google Style Guide 和 我们的.emacs配置结合起来呢?
首先你需要下载这个文件: google-c-style.el
之后考虑到我所在的小组要求Tab-indent是4个空格,并且要求用空格替代Tab,那么我们的.emacs配置如下:

(require 'cc-mode)
(require 'google-c-style)
(defun my-build-tab-stop-list (width)
  (let ((num-tab-stops (/ 80 width))
	(counter 1)
	(ls nil))
    (while (<= counter num-tab-stops)
      (setq ls (cons (* width counter) ls))
      (setq counter (1+ counter)))
    (set (make-local-variable 'tab-stop-list) (nreverse ls))))
(defun my-c-mode-common-hook ()
  (c-set-style "google")
  (setq tab-width 4) ;; change this to taste, this is what K&R uses :)
  (my-build-tab-stop-list tab-width)
  (setq c-basic-offset tab-width)
  (setq indent-tabs-mode nil) ;; force only spaces for indentation
  (local-set-key "\C-o" 'ff-get-other-file)
  (c-set-offset 'substatement-open 0)
  (c-set-offset 'arglist-intro c-lineup-arglist-intro-after-paren)
  )
;; google sytle is defined in above function
(add-hook 'c-mode-common-hook 'my-c-mode-common-hook)
(add-hook 'c++-mode-common-hook 'my-c-mode-common-hook)

如何配置.emacs里并加入cpplint功能呢?只需在.emacs里加入如下代码:

(defun cpplint ()
  "check source code format according to Google Style Guide"
  (interactive)
  (compilation-start (concat "python ~/bin/cpplint.py " (buffer-file-name))))

我们只需要执行M-x cpplint就可以得到格式检查的结果。用C-x `,或者M-g n, M-g p可以上下切换。

另一个常用的功能是如何将多个源文件通过Emacs来调整格式的(batch indent source code)?
参考 Batch Indentation with Emacs,文中提到的方法可以用默认的代码风格来格式化源文件。
但我们的目标是用Google风格来格式话代码,那么只需要稍作改变:
~/bin/emacs-format-function

;;; File: emacs-format-file
;;; Stan Warford
;;; 17 May 2006
;; from: http://www.cslab.pepperdine.edu/warford/BatchIndentationEmacs.html

;; Adopt by Xiaowei Zhan 2011 from .emacs
(require 'google-c-style)
(defun emacs-format-function ()
  "Format the whole buffer."
  (setq tab-width 4) ;; change this to taste, this is what K&R uses :)
  (setq c-basic-offset tab-width)
  (c-set-offset 'substatement-open 0)
  ;; next line is strange, I copied it from .emacs, but it cannot find c-lineup-arglist-intro-after-paren
  ;; however, disable this line seems working as well.
  ;;(c-set-offset 'arglist-intro c-lineup-arglist-intro-after-paren) 
  (indent-region (point-min) (point-max) nil)
  (untabify (point-min) (point-max))
  (save-buffer)
  )

~/bin/my-indent

#!/bin/bash
# File: my-indent
# Opens a set of files in emacs and executes the emacs-format-function.
# Assumes the function named emacs-format-function is defined in the
# file named emacs-format-file.

if [ $# == 0 ]
then
   echo "my-indent requires at least one argument." 1>&2
   echo "Usage: my-indent files-to-indent" 1>&2
   exit 1
fi
while [ $# -ge 1 ]
do
   if [ -d $1 ]
   then
      echo "Argument of my-indent $1 cannot be a directory." 1>&2
      exit 1
   fi
   # Check for existence of file:
   ls $1 2> /dev/null | grep $1 > /dev/null
   if [ $? != 0 ]
   then
      echo "my-indent: $1 not found." 1>&2
      exit 1
   fi
   echo "Indenting $1 with emacs in batch mode"
   emacs -batch $1 -l ~/emacs/google-c-style.el -l ~/bin/emacs-format-file -f emacs-format-function
   echo
   shift 1
done
exit 0

#from http://www.cslab.pepperdine.edu/warford/BatchIndentationEmacs.html

值得注意的是Google除了C++ Style Guide, 还提供JavaScript Style Guide, Objective-C Style Guide, and Python Style Guide。对这些语言感兴趣的朋友可以到Google Style Guide发掘。