Google Reader G+化改版后,颜色更单一,更刺眼了,对于重度使用者来说这非常伤眼睛,而今天正好发现出了一个 Reeder for Chrome 的插件。当然不能错过了。这其实只是GR的皮肤,原GR的功能都是完整的。
原以为可能是新出的插件不适合老版本chrome使用,于是将浏览器升级chrome 16 beta(也正好想体验一下它的多用户功能)。但是重试后发现问题还是一样。
搜索一翻后在code.google上找到问题的原因居然是没有清缓存引起的,于是清缓存,安装一切正常。
Google Reader G+化改版后,颜色更单一,更刺眼了,对于重度使用者来说这非常伤眼睛,而今天正好发现出了一个 Reeder for Chrome 的插件。当然不能错过了。这其实只是GR的皮肤,原GR的功能都是完整的。
原以为可能是新出的插件不适合老版本chrome使用,于是将浏览器升级chrome 16 beta(也正好想体验一下它的多用户功能)。但是重试后发现问题还是一样。
搜索一翻后在code.google上找到问题的原因居然是没有清缓存引起的,于是清缓存,安装一切正常。
typecho快一年多没有更新过了,虽然使用感觉还算不错,不过还是经不住wordpress庞大插件库的诱惑,因为博客本来就没有多少流量,所以也不担心负载的问题,所以就把博客转换到wordpress了。特此做一记录。
使用的转换程序都是网上找的。
转换程序适合:typecho0.8 (10.8.15)到wordpress3.03版本。
typecho2wordpress
WordPress.v3.0.3.Incl.Simp.Chinese.Pack.v1-wpcng
可转换内容:
1、博客
2、附件
3、评论
4、分类
5、标签
转换步骤:
1、在原typecho博客的主机上安装wordpress3.03版本。
2、上传typecho2wordpress转换程序,开始转换。
3、转换完后,将原typecho里面的 /usr/uploads下面的附件放到 wordpress的 /wp-content/uploads 里面。
转换后残留问题:
1、打开wordpress的媒体库,看不到图片,这是因为转换程序将附件记录的里面 post_status 没有设置成 inherit.将 post_type为attachment的posts的post_status属性改为 inherit。
2、博客文章里面的图片及附件链接没有更新,比如typecho附件的图地址为/attachment/id 图片地址为 /usr/uploads/*** 需要更新为wordpress的 /wp-content/uploads/***
于花了一点时间稍微修改了一下转换程序:
typecho2wordpress-kejibo
使用前请自行备份数据库,如果造成任何损失,本人概不负责!
成功转换到 wordpress3.03后,通过wordpress后台自动更新到wodpress最新版本3.21完全没有问题。
xz这个压缩可能很多都很陌生,不过您可知道xz是绝大数linux默认就带的一个压缩工具。
之前xz使用一直很少,所以几乎没有什么提起。
我是在下载phpmyadmin的时候看到这种压缩格式的,phpmyadmin压缩包xz格式的居然比7z还要小,这引起我的兴趣。
最新一段时间会经常听到xz被采用的声音,像是最新的archlinux某些东西就使用xz压缩。不过xz也有一个坏处就是压缩时间比较长,比7z压缩时间还长一些。不过压缩是一次性的,所以可以忽略。
xz -z 要压缩的文件
如果要保留被压缩的文件加上参数 -k ,如果要设置压缩率加入参数 -0 到 -9调节压缩率。如果不设置,默认压缩等级是6.
xz -d 要解压的文件
同样使用 -k 参数来保留被解压缩的文件。
习惯了 tar czvf 或 tar xzvf 的人可能碰到 tar.xz也会想用单一命令搞定解压或压缩。其实不行 tar里面没有征对xz格式的参数比如 z是针对 gzip,j是针对 bzip2。
创建tar.xz文件:只要先 tar cvf xxx.tar xxx/ 这样创建xxx.tar文件先,然后使用 xz -z xxx.tar 来将 xxx.tar压缩成为 xxx.tar.xz
解压tar.xz文件:先 xz -d xxx.tar.xz 将 xxx.tar.xz解压成 xxx.tar 然后,再用 tar xvf xxx.tar来解包。
之前翻译过一篇
OAuth认证协议原理分析及使用方法
,虽然 OAuth2还没有正式发布,但是国内外的OAuth2的采用情况几乎要完全替代掉OAuth1.1了。像淘宝、腾讯、人人网、百度开放平台就已经采用Oauth2,新浪微博也发来邮件说是要很快上马OAuth2,彻底替换掉OAuth1.1。目前OAuth2到了
v20草稿阶段
,最新的版本是 2011年7月25号发布的,协议变化还是很快的,所以看到国内的一些已经实现的实例,再比照官方的 oauth2,会有些出入的。
GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com
,其中response_type 值固定为 code,client_id就是客户端申请开发者的时候取得的 appkey,state是一个可选参数,可以用于保存客户端在引导用户转向前的一些状态,当回到 redirect_uri的时候会原封不动的传回来,redirect_uri是当用户确认授权应用访问的时候跳转回来的地址。
2,用户同意授权后跳转回来的的地址如:
HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
&state=xyz
&state=xyz ,其中 code就是 Authorization Code,state就是上面所说的可选参数。
3,使用取得的 Authorization Code去换取Access Token:
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
其中 Authorization是由Client id(app key)及Client password(app secret)组合成的 http basic 验证字符串,grant_type必须为 authorization_code,code是上一步取得的 Authorization Code,redirect_uri是完成后跳转回来的网址。
如果Client不能发送 Authorization信息,则可以使用下面的方式,/token这个地址必须是 https连接的,不然就有泄露 client secret的可能性:
POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
&client_id=s6BhdRkqt3&client_secret=7Fjfp0ZBr1KtDRbnfVdmIw
成功的话返回的信息为:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}
GET /authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com
这里的 response_type为 token,client_id为appkey。可以看到这里取Access token的过程中并没有像 第一种方式那样传入 client_secret。因为如果你传入 client_secret,其实就是相当于告诉用户,你应用的app secret了。
二、在成功授权后,跳转回到 redirect_uri所定义的网址
HTTP/1.1 302 Found
Location: http://example.com/rd#access_token=2YotnFZFEjr1zCsicMWpAA
&state=xyz&token_type=example&expires_in=3600
,这样应用就可以通过取地址中的 fragment部分来取得 access token。
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
grant_type=password&username=johndoe&password=A3ddj3w
这里的 Authorization是 client_id为username,client_secret为password的http basic验证码。grant_type必须为 password,username为用户名,password为用户密码。
取得的结果如下:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}
Q:为何要这种这么不安全的方式?
A:取代原来原始的 username,password的授权方式,而且不需要 client保存用户的密码,client只要保存access token就可以。主要用于客户端程序。
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
grant_type=client_credentials
其中 Authorization是client_id及client_secret组成的 http basic验证串。grant_type必须为client_credentials,
返回如下:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"example_parameter":"example_value"
}
标准的 oauth2中,使用 access token来向资源服务器发出请求,取得资源。这里的资源服务器需要使用 https协议,否则access token极可能被其它方获取。比如
GET /resource/1 HTTP/1.1
Host: example.com
Authorization: Bearer 7Fjfp0ZBr1KtDRbnfVdmIw
bearer是指 token类型
,后面的字符串就是access token。还有一种
mac类型的 token(目前v20版本的草稿里还没有文档)
,如:
GET /resource/1 HTTP/1.1
Host: example.com
Authorization: MAC id="h480djs93hd8",
nonce="274312:dj83hs9s",
mac="kDZvddkndxvhGRXZhvuDjEWhGeE="
,因为 https速度相较http慢,而且并非所有服务器或客户都支持https,所以国内一些网站采用一种http也可访问资源的方式。
淘宝开放平台的方式
:应用通过用户授权获取的AccessToken的值即等同于Sessionkey,应用凭借AccessToken调用taobao API即可。查看淘宝SDK,可以看到 其使用应用的app_secret作用密码钥来进行签名,参数里面包含了 这个Sessionkey,这样淘宝在收到这个请求的时候,根据 app_id来判断是哪个应用,根本sessionkey的值来判断是哪个用户,如果不传这个 sessionkey就用 app_id查得app_id所属的淘宝用户就行了。也就是说 sessionkey必须配合 这个 client自己的授权资料appkey appsrecet来访问资源。
百度开放平台方式
、
人人网方式
、还有腾讯也类似:在返回 access token的同时返回 sessionKey及sessionSecret。如:
{
"access_token": "1.a6b7dbd428f731035f771b8d15063f61.86400.1292922000-2346678-124328",
"expires_in": 86400,
"refresh_token": "2.385d55f8615fdfd9edb7c4b5ebdc3e39.604800.1293440400-2346678-124328",
"scope": "basic email",
"session_key": "9XNNXe66zOlSassjSKD5gry9BiN61IUEi8IpJmjBwvU07RXP0J3c4GnhZR3GKhMHa1A=",
"session_secret": "27e1be4fdcaa83d7f61c489994ff6ed6",
}
在调用资源API的时候,如下:
GET /rest/2.0/passport/users/getInfo?session_key=9XNNXe66zOlSassjSKD5gry9BiN61IUEi8IpJmjBwvU07RXP0J3c4GnhZR3GKhMHa1A%3D×tamp=2011-06-21+17%3A18%3A09&format=json&uid=67411167&sign=d24dd357a95a2579c410b3a92495f009 HTTP/1.1 Host: api.example.com
这里参数里面的 session_key,传给服务器后,用户查询 session_secret,sign使用session_secret作为密钥来加密的。可以看到这里调用的时候没有使用 client_id或client_secret信息,所以对于任何获取
"session_key": "9XNNXe66zOlSassjSKD5gry9BiN61IUEi8IpJmjBwvU07RXP0J3c4GnhZR3GKhMHa1A=",
"session_secret": "27e1be4fdcaa83d7f61c489994ff6ed6",
的一方都可以调用到API。降低系统耦合度。
看一下C++的引用参数:
#includevoid test(int &x) //引用参数 { x = 99; } int main() { int a = 1; test(a); printf("%c", a); return 0; }
纯C中如果想实现这种函数内对外部传入参数值的修改,只能这样:
#includevoid test(int* x) //指针参数 { *x = 99; } int main() { int a = 1; test(&a); printf("%c", a); return 0; }
Go语言也像C一样,没有引用参数的概念:
package main
func test(x *int) { //指针参数
*x = 99
}
func main() {
a := 1
test(&a)
println(a)
}
swig不能直接使用官方的程序,而必须打一个patch 后才能使用。svn下载swig源代码后(看版本号应该是2.0.5了),打上
swig_go_windows2.patch
这个patch。至于怎么打patch,请自行Google之。
swig的编译也是比较折腾的。因为他依赖 yodl2man yodl2html这东西,而这东西又依赖 icmake,不过后来发现这东西不要也行,虽然 swig在 make install的时候没有完全结束,但是生成的东西,已经够用了。
把C写的库包装为 GO包。
首先需要准备两个文件 test.i test.c
$ cat test.c #includedouble MyVar = 3.0; int Fact(int n) { if (n <= 1) return 1; else return n * Fact(n-1); } int MyMod(int x, int y) { return (x % y); } char *GetTime() { time_t ltime; time(<ime); return ctime(<ime); } $ cat test.i %module test %{ extern double MyVar; extern int Fact(int n); extern int MyMod(int x, int y); extern char *GetTime(); %} extern double MyVar; extern int Fact(int n); extern int MyMod(int x, int y); extern char *GetTime();
需要注意的是 C中的如果要想在Go中可以调用 ,首字母必须要 大写。开始 swig
//初始 $ ls test.i test.c //使用swig生成需要的文件 $ swig -go -windows test.i $ ls test.c test.go test.i test_dllmain.cxx test_gc.c test_wrap.c //分别编译 test.c test_wrap.c test_dllmain.cxx 为目标文件 *.o $ gcc -c test.c test_wrap.c test_dllmain.cxx //将上一步编译的结果链接成一个动态链接库 $ gcc -shared test.o test_wrap.o test_dllmain.o -o test.dll //编译 test.go $ 8g test.go //编译 test_gc.c $ 8c -I "go的pkg目录" test_gc.c //将test.8 test_gc.8 打包成go库,就是一个静态库,相当于gcc里面使用 ar 命令打包一样。 $ gopack grc test.a test.8 test_gc.8
至此万事俱备了。写个go 程序来试试。
$ cat main.go
package main
import "./test"
import "fmt"
func main() {
println(test.Fact(5))
//println(test.MyVar) //不能直接调用必须使用 getter setter来调用如下
test.SetMyVar(99) //来设置 MyVar的值
fmt.Printf("%f
", test.GetMyVar()) //取得刚设置的值。
println(test.MyMod(10, 3))
println(test.GetTime())
}
$ 8g main.go
$ 8l main.8
$ ./8.out.exe
120
1
Thu Jun 23 04:06:40 2011
现在把 test.dll改名,看看这个程序是不是真调用 了这个动态链接库。
如果要在其它地方使用只需要 test.a 及 test.dll 两个文件 。。test.a就是go的库,这是魔法所在,就是这样东西负责调用 C里面的函数。。因为Go是静态编译,所以编译好的Go程序就不需要 test.a这东西了,只要test.dll带上就行了。。
到gtk官方下载 打包好的 windows gtk bundle all-in-one包。解压后 把在本站下载的 gtk+-bundle_2.22.1.7z 解压覆盖到里面,其实只是解决 gtksourceview及libxml2的依赖。
把 go-gtk.7z 解压放到你的 go pkg库目录下。
注:本人使用的是 mingw环境。
8g version weekly.2011-06-16 8787
go-gtk 最新git下载的 revision:1193a0044982261ccf04805ff36e11002d368ad7
更新go 8g version release.r59 9087编译的版本:go-gtk-r59.tar.xz
//引入包
import "container/ring"
//创建闭环,这里创建10个元素的闭环
r := ring.New(10)
//给闭环中的元素附值
for i := 1; i <= r.Len(); i++ {
r.Value = i
r = r.Next()
}
//循环打印闭环元素的值,这里的操作方法很像javascript
r.Do(func(p interface{}){
println(p)
})
//当前元素就是
// r
//当前元素的值就是
// r.Value //这里是 1
//取得当前元素之后的第5个元素
r5 := r.Move(5) //这里是 6
//链接 当前元素r与r5,相当于删除了r跟r5之间的元素,使 r.Next() == r5
rl := r.Link(r5) //这样 r环里有 1 6 7 8 9 10
//rl 环路里有 2 3 4 5
//把rl环加回到 r环原来的位置
//要确保r的当前位置是 1,rl的当前位置为2
rf := r.Link(rl)
//这样 r就变回了 1 2 3 4 5 6 7 8 9 10
//rf则是 从 rl.Next()开始环,内容则与 r的一样。
//6 7 8 9 10 1 2 3 4 5
另外做过一次 Do()循环操作后 闭环的当前位置不变。
package main
//插入排序
func main() {
a := []int{5, 4, 3, 2, 1}
for i := 1; i < len(a); i++ {
temp := a[i]
j := i - 1
for j >= 0 && a[j] > temp {
a[j + 1] = a[j]
j--
}
a[j + 1] = temp
}
for _, v := range a {
println(v)
}
}
原理就是依顺找到每个元素在己排充部分中自己的位置,并插入。
package main
//希尔排序
func main() {
a := []int{5, 4, 3, 2, 1}
gap := 0
for gap * 3 + 1 < len(a) {
gap = gap * 3 + 1
}
for gap > 0 { //分段
for i := gap; i < len(a); i++ { //对分段进行插入排序
temp := a[i]
j := i - gap
for j >= 0 && a[j] > temp {
a[j + gap] = a[j]
j -= gap
}
a[j + gap] = temp
}
gap = (gap - 1) / 3
}
for _, v := range a {
println(v)
}
}
希尔排序就是分段了的插入排序。最大限度地提高每次对比后元素移动的距离。gap = gap * 3 + 1分隔数由实验取得。如 1 4 13之类。反顺减小到 1。