Posts by author thinkbase

使用 nginx 实现后端 HTTP 服务器的故障转移(failover)

一般情况下,nginx 的 upstream 通常的用途是实现负载均衡:

但是实际上,nginx 对 upstream 的多个设备可以设置不同的状态参数:

  • weight 默认为1. weight越大,负载的权重就越大;
  • max_fails : 允许请求失败的次数默认为1. 当超过最大次数时,返回proxy_next_upstream 模块定义的错误;
  • fail_timeout: max_fails 次失败后,暂停的时间;
  • down 表示当前的server暂时不参与负载;
  • backup: 其它所有的非 backup 机器 down 或者忙的时候,请求 backup 机器(所以这台机器压力会最轻);

因此,upstream 同样可以用于配置 “故障转移”的服务器集群,一般用于这类场景:一般情况下优先使用服务器1,只有这台服务器出故障后才转移到其他的服务器(因为其他服务器性能、网络速度不如服务器1等原因),下面就是一个配置的例子:

worker_processes 1;

events {
    worker_connections 1024;
}

http {
    default_type  application/octet-stream;
    client_max_body_size 4m;
    
    keepalive_timeout 65;
    upstream backend_servers {
        server localhost:7001 max_fails=3 fail_timeout=30s;
        # 下面两行 "backup" 只有在上面 "7001" 服务器失败后才会被访问(此时两台服务器会采用同样的权重进行负载均衡)
        server localhost:7002 max_fails=3 fail_timeout=30s backup;
        server localhost:7003 max_fails=3 fail_timeout=30s backup;
        # 如果为上面两行 "backup" 设定悬殊的 "weight" 参数,可以控制 failover 的顺序(比如设置只有 "7002" 宕机后才会访问到 "7003")
        #server localhost:7002 max_fails=3 fail_timeout=30s backup weight=2000000000;
        #server localhost:7003 max_fails=3 fail_timeout=30s backup weight=1;
    }

    server {
        listen 8001;
        server_name example.com;

        location / {
            proxy_pass http://backend_servers;
        }
    }
}

附件 test-http-server.pynginx.conf 是用于测试的 Python HTTP 服务器和 nginx 配置:

  • 首先依次通过如下命令启动 3 台后端 HTTP 服务器:
    python test-http-server.py 7001
    python test-http-server.py 7002
    python test-http-server.py 7003
    
  • 然后使用如下命令启动 nginx 服务器:
    # 启动 nginx
    nginx -c `pwd`/nginx.conf
    # 停止 nginx
    nginx -c `pwd`/nginx.conf -s quit
    
  • 通过浏览器访问类似这样的 URL: http://localhost:8001/TEST/001
    • 正常结果应该是 localhost 7001;
    • 如果停止相应的服务器,可以看到浏览器上的输出切换到后续其他服务器(输出 localhost 7002localhost 7003)

历史 - 无意中访问到 jQuery 的 trac

看起来 jQuery 历史上使用过 trac 来进行开发管理,具体地址访问这儿: https://bugs.jquery.com/ , 我是通过 stackoverflow这个问题 不小心进入的.

看起来,这个 trac 两年前就不再使用了.



纪念 Codehaus - ... and eventually GitHub has overtaken all of them

在这个 Github 如火如荼的年代,sf.net 已经式微,而 Google CodeCodehaus 已经不再继续了。


这里有篇文章:《Codehaus: The once great house of code has fallen》:

  • Codehaus was overtaken by SourceForge and Google Code and eventually GitHub has overtaken all of them.

然而有价值的项目仍然在延续,挑几个比较熟悉的:

当然也有不怎么被使用的项目:

看起来,Codehaus 上原来的所有项目都已经转移到了 Github,如果需要去寻找历史的话,可以访问 https://github.com/codehaus

将自己的域名绑定到 GitHub Pages

以近期实现的一个站点 http://bizobj.org/ 为例,记录一下如何实现将自己的域名绑定到 Github 的 Pages

首先,在你的 github 中建立一个 域名.github.io 的库

建立过程中,可以使用系统的自动创建 Page 的功能

可以直接在网页上使用 markdown 语法编辑页面内容

然后可以选择页面风格

为了可以直接使用你自己的域名访问,需要编写一个 CNAME 文件,内容就是域名

然后去设置你的 DSN 指向 github 吧

具体 DSN 应该指向哪个 IP,github 提供了相关的帮助说明

We are back ! - 现在 thinkbase.net 运行在 Docker 之上

PortableTrac 已经支持 Linux(从 https://github.com/thinkbase/PortableTrac/commit/bc2702cc9ed56f566a43b9d00137ae81dafdb395 开始),于是 http://thinkbase.net 终于迁移到 Linux 上,并且使用 Docker 来进行运行环境。

基于 Docker 容器技术,要运行 thinkbase.net 的 Trac 系统只需要如下简单的几步即可:

  1. 在服务器上安装 docker:
    # 安装 docker.io
    sudo apt-get install docker.io
    
    # 将当前用户加入 docker 组,以便非 root 用户也可以使用 docker
    sudo gpasswd -a ${USER} docker
    sudo service docker restart
    
  1. 从 github 获取相关的 Dockerfile,构建运行镜像
    # [运行目录: ~/github$] - 获取需要的 Dockerfile 定义
    git clone -v --progress https://github.com/thinkbase/Dockerfiles
    
    # [运行目录: ~/github/Dockerfiles/01-init/01-ubuntu14.04$] - 构建基于 ubuntu 的基础镜像
    docker build --force-rm -t ubuntu:14.04-sshd .
    
    # [运行目录: ~/github/Dockerfiles/90-servers/trac-thinkbase.net$] - 构建 thinkbase.net trac 镜像
    docker build --force-rm -t trac-thinkbase.net:1.0 .
    
  1. 下面就可以创建容器并运行了:
    docker run -d -p 80:8080 -v ~/trac/private:/private --name trac-tk trac-thinkbase.net:1.0
    

Linux shell 之计算圆周率

http://blog.devep.net/virushuo/2014/01/21/delllinux_kernel_bugcpu.html (Dell服务器和Linux kernel bug造成的CPU性能下降问题) 看到的,本意是通过计算圆周率确认服务器的CPU性能,只需要如下简单的一行命令:

time echo "scale=5000; 4*a(1)" | bc -l -q

在我的笔记本上执行的情况如下:

3.141592653589793238462643383279502884197169399375105820974944592307\
81640628620899862803482534211706798214808651328230664709384460955058\
22317253594081284811174502841027019385211055596446229489549303819644\
28810975665933446128475648233786783165271201909145648566923460348610\
45432664821339360726024914127372458700660631558817488152092096282925\
40917153643678925903600113305305488204665213841469519415116094330572\
70365759591953092186117381932611793105118548074462379962749567351885\
75272489122793818301194912983367336244065664308602139494639522473719\
07021798609437027705392171762931767523846748184676694051320005681271\
45263560827785771342757789609173637178721468440901224953430146549585\
37105079227968925892354201995611212902196086403441815981362977477130\
99605187072113499999983729780499510597317328160963185950244594553469\
08302642522308253344685035261931188171010003137838752886587533208381\
42061717766914730359825349042875546873115956286388235378759375195778\
18577805321712268066130019278766111959092164201989380952572010654858\
63278865936153381827968230301952035301852968995773622599413891249721\
77528347913151557485724245415069595082953311686172785588907509838175\
46374649393192550604009277016711390098488240128583616035637076601047\
10181942955596198946767837449448255379774726847104047534646208046684\
25906949129331367702898915210475216205696602405803815019351125338243\
00355876402474964732639141992726042699227967823547816360093417216412\
19924586315030286182974555706749838505494588586926995690927210797509\
30295532116534498720275596023648066549911988183479775356636980742654\
25278625518184175746728909777727938000816470600161452491921732172147\
72350141441973568548161361157352552133475741849468438523323907394143\
33454776241686251898356948556209921922218427255025425688767179049460\
16534668049886272327917860857843838279679766814541009538837863609506\
80064225125205117392984896084128488626945604241965285022210661186306\
74427862203919494504712371378696095636437191728746776465757396241389\
08658326459958133904780275900994657640789512694683983525957098258226\
20522489407726719478268482601476990902640136394437455305068203496252\
45174939965143142980919065925093722169646151570985838741059788595977\
29754989301617539284681382686838689427741559918559252459539594310499\
72524680845987273644695848653836736222626099124608051243884390451244\
13654976278079771569143599770012961608944169486855584840635342207222\
58284886481584560285060168427394522674676788952521385225499546667278\
23986456596116354886230577456498035593634568174324112515076069479451\
09659609402522887971089314566913686722874894056010150330861792868092\
08747609178249385890097149096759852613655497818931297848216829989487\
22658804857564014270477555132379641451523746234364542858444795265867\
82105114135473573952311342716610213596953623144295248493718711014576\
54035902799344037420073105785390621983874478084784896833214457138687\
51943506430218453191048481005370614680674919278191197939952061419663\
42875444064374512371819217999839101591956181467514269123974894090718\
64942319615679452080951465502252316038819301420937621378559566389377\
87083039069792077346722182562599661501421503068038447734549202605414\
66592520149744285073251866600213243408819071048633173464965145390579\
62685610055081066587969981635747363840525714591028970641401109712062\
80439039759515677157700420337869936007230558763176359421873125147120\
53292819182618612586732157919841484882916447060957527069572209175671\
16722910981690915280173506712748583222871835209353965725121083579151\
36988209144421006751033467110314126711136990865851639831501970165151\
16851714376576183515565088490998985998238734552833163550764791853589\
32261854896321329330898570642046752590709154814165498594616371802709\
81994309924488957571282890592323326097299712084433573265489382391193\
25974636673058360414281388303203824903758985243744170291327656180937\
73444030707469211201913020330380197621101100449293215160842444859637\
66983895228684783123552658213144957685726243344189303968642624341077\
32269780280731891544110104468232527162010526522721116603966655730925\
47110557853763466820653109896526918620564769312570586356620185581007\
29360659876486117910453348850346113657686753249441668039626579787718\
55608455296541266540853061434443185867697514566140680070023787765913\
44017127494704205622305389945613140711270004078547332699390814546646\
45880797270826683063432858785698305235808933065757406795457163775254\
20211495576158140025012622859413021647155097925923099079654737612551\
76567513575178296664547791745011299614890304639947132962107340437518\
95735961458901938971311179042978285647503203198691514028708085990480\
10941214722131794764777262241425485454033215718530614228813758504306\
33217518297986622371721591607716692547487389866549494501146540628433\
66393790039769265672146385306736096571209180763832716641627488880078\
69256029022847210403172118608204190004229661711963779213375751149595\
01566049631862947265473642523081770367515906735023507283540567040386\
74351362222477158915049530984448933309634087807693259939780541934144\
73774418426312986080998886874132604720

real	0m21.420s
user	0m21.397s
sys	0m0.001s

Linux shell 获得当前脚本文件所在的目录

这基本上是一个非常常见的需求,不过考虑到兼容性: 1)目录或者文件名中空格;2)对通过link的形式引用;3)通过. ./test.sh这样的方式调用,要做出一个比较完美的方案也不是那么容易。

首先看看主流的做法:

另外一个来源:

  • http://www.cyberciti.biz/faq/unix-linux-appleosx-bsd-bash-script-find-what-directory-itsstoredin/
    #!/bin/bash
    # Name: /tmp/demo.bash : 
    # Purpose: Tell in what directory $0 is stored in
    # Warning: Not tested for portability 
    # ------------------------------------------------
     
    ## who am i? ##
    _script="$(readlink -f ${BASH_SOURCE[0]})"
     
    ## Delete last component from $_script ##
    _base="$(dirname $_script)"
     
    ## Okay, print it ##
    echo "Script name : $_script"
    echo "Current working dir : $PWD"
    echo "Script location path (dir) : $_base"
    
  • 这个脚本只支持 bash,经测试,对空格的支持存在问题。

考虑实际情况(总是在 bash 下面),对上面脚本修改一下,我最终使用的方案是:

#!/bin/bash

if [ -z $BASH ]; then
    echo "This shell script MUST run under bash."
    exit /b -1
fi
_script="$(readlink -f "${BASH_SOURCE[0]}")"
_script_dir="$(dirname "$_script")"
echo "Directory portion of $_script : $_script_dir"

Linux 卡死怎么办

摘自 http://forum.ubuntu.org.cn/viewtopic.php?f=15&t=450926

  • Ctrl-Alt-F1 切换到 TTY1 ;
    • 如果你用的是常规版ubuntu,setsid unity重启下unity基本就解决了
  • Ctrl-Alt-Backspace 关闭 X Server;
  • Alt-SysRq + R、E、I、S、U、B 无敌 reisub
    R:unRaw     将键盘从X Server抢回来
    E:tErminate 给除INIT外的所有进程发送 SIGTERM 信号
    I:kIll      给除INIT外的所有进程发送 SIGKILL 信号
    S:Sync      将所有数据同步至磁盘
    U:Unmount   将所有分区挂载为只读模式
    R:reBoot    重启
    O:shutdOwn  关机
    

Oracle 数据库导入时 ORA-12899 错误的处理

原因分析和 http://wuhuizhong.iteye.com/blog/740553 一样:

一般设计数据库的时候,我们都考虑一个汉字占用两个字节。所以设计数据库的时候,如果认为某字段最长要存四个汉字,该字段都会定义为varchar2(8)。

SQL> create table t1 (col1 varchar2(8));
Table created.

但是测试插入三个汉字的时候就报错了。

SQL> insert into t1 values('一二三');
insert into t1 values('一二三')
*
ERROR at line 1:
ORA-12899: value too large for column T1.COL1 (actual: 9, maximum:8)

检查相关参数及环境变量。

SQL> select * from nls_database_parameters where parameter like 'NLS%CHARACTERSET';
PARAMETER                 VALUE
------------------------- --------------------
NLS_CHARACTERSET          UTF8
NLS_NCHAR_CHARACTERSET    UTF8

原来数据库使用的是UTF8字符集,难怪一个汉字占用3个字节。这样一来原先按一个汉字占两个字节设计的数据库,应用的时候很多字段都会因长度不够,出现ORA-12899错误。

解决办法比较直接,就是直接修改 dump 文件中数据库表定义的文本,把 CHAR(n) 改为 NCHAR(n), VARCHAR2(n) 改为 NVARCHAR2(n):

sed 's/ CHAR(/ NCHAR(/g'  export.dmp > export1.dmp
sed 's/ VARCHAR2(/ NVARCHAR2(/g'  export1.dmp > export2.dmp
# 在 Window 32 位平台上有 NVARCHAR2 不能大于 2000 的限制
sed 's/ NVARCHAR2(3000)/ NVARCHAR2(2000)/g'  export2.dmp > export3.dmp
sed 's/ NVARCHAR2(4000)/ NVARCHAR2(2000)/g'  export3.dmp > export4.dmp
sed 's/ NVARCHAR2(2200)/ NVARCHAR2(2000)/g'  export4.dmp > export5.dmp

PortableTrac 类似的系统

通过对比选择最佳开源的基于Web的项目管理工具 看到:

Trac 目前还无法同时管理多个项目,但如果作为一个单一项目的管理工具,它是一个很好的选择。大家可以使用 BitNamiTurnkey virtual appliance

发现这两个项目和现在 PortableTrac 的目标比较接近:

  • http://bitnami.com/stack/trac
    • 提供了一键安装的 Trac 安装程序和虚拟机映像,甚至还包括在上部署 Trac 服务器。
    • 提供了 Windows、Linux 和 OS X 上的安装程序;
  • http://www.turnkeylinux.org/trac
    • TurnKey Linux是基于Ubuntu的虚拟应用程序库,它将一些最好的开放源码软件集成到完备可用的解决方案中。每一个虚拟应用程序都为易用性进行了优化,并能 在数分钟内就部署在裸机、虚拟机及云中,每一个虚拟应用都可以光盘镜像或是虚拟机镜像的形式获得(来自 http://baike.baidu.com/view/9300243.htm )。

Portable Trac 简单介绍 - 兼谈为什么不选择 Redmine

Trac是一个轻量级的软件项目管理环境,如果在工作中涉及一个开发团队的管理并且关心项目管理工具的话,相信都在 TracRedmine 等工具之间进行过比较,网上简单搜索一下就可以查到以下有代表性的文章:

一般来说这些比较都认为 Redmine 更为优秀,尤其是

  • 可以同时管理多个项目;
  • 安装和部署比较方便(利用rake、rails的db migration安装很方便,Trac则要用到命令行的trac-admin进行配置,以及每个项目有单独的ini配置文件);
  • 使用比较简单(trac的很多功能都需要通过trac-admin在命令行方式下进行配置,不易上手,这方面Redmine则十分方便);

总体来看,缺乏内置的"多项目管理"功能支持算是 Trac 的硬伤,其他方面:

  • 对于开发者而言,命令行不是特别严重的问题,而且 Trac 的插件机制比较完善,http://trac-hacks.org/ 上有大量的插件可以实现基于 Web 界面的管理需求(例如: AccountManagerPlugin实现了内置的用户管理、TracIniAdminPanelPlugin支持通过Web方式调整Trac配置、SvnAuthzAdminPlugin支持Web方式调整SVN权限等等), Python 语言也算比较大众化,自己写一个插件也没有太大压力;
  • Trac 将维基融入了核心组件, 支持的更加彻底,而且其 Wiki 语法 功能强大并且可以通过插件扩展,这对于需要撰写大量文档的情况有不少帮助;而 Redmine 的 Wiki 功能实在太弱,实际使用的时候很不方便;事实上功能丰富的 Wiki 是 Trac 最大的优势;

本文介绍的 PortableTrac 其实是针对官方 Trac 的重新打包发布(目前只支持 Windows),其目的主要是简化 Trac 的安装配置过程,方便用户的使用,这方面的改进和增强包括:

  • 内置中文说明;
  • 自带的Python环境,已安装大量的常用插件,实现开箱即用,不再需要繁琐的安装和配置过程;
  • 已实现与 Apache httpd、SVN、Git 的集成;
  • 提供标准的数据备份和恢复功能;
  • 更详细的介绍可以参见 PortableTrac

下图演示如何简单的在几分钟之内解压并运行一个 Trac 实例(参考 PortableTrac/install),尤其适合初学者:
.

如果需要了解更多信息,请参考 在线演示站点.

动态写入内容到 iFrame 并执行其中脚本

How to - Injecting HTML into an IFrame

其实实现思路比较简单,与动态打开一个窗口并使用 document.write(...) 写入内容的做法类似,IFrame 内部包含的 window 对象也可以使用同样的方法写入 HTML 内容,并且可以执行其中的脚本。

主要参考

  • stackoverflow "Creating an iframe with given HTML dynamically"

  • Dojo 的 Reference Guide 采用类似做法来运行示例代码
    • 经过分析可以看到 Dojo Reference Guide 是采用一个 src=javascript:[页面内容] 的方式来打开 iframe,例如:
      javascript:%20'<!DOCTYPE%20html>\n<html%20>\n<head>\n\n<link%20rel="stylesheet"%20href="../_static/js/dojo/../dijit/themes/claro/claro.css">\n\n<script>dojoConfig%20=%20{async:%20true}</script><script%20src=\'../_static/js/dojo/dojo.js\'></script><script>require([\n%20%20%20%20"dojo/ready",%20"dojo/_base/window",%20"dojo/store/Memory",\n%20%20%20%20"dijit/tree/ObjectStoreModel",%20"dijit/Tree"\n],%20function(ready,%20win,%20Memory,%20ObjectStoreModel,%20Tree){\n\n%20%20%20%20//%20Create%20test%20store,%20adding%20the%20getChildren()%20method%20required%20by%20ObjectStoreModel\n%20%20%20%20var%20myStore%20=%20new%20Memory({\n%20%20%20%20%20%20%20%20data:%20[\n%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'world\',%20name:\'The%20earth\',%20type:\'planet\',%20population:%20\'6%20billion\'},\n%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'AF\',%20name:\'Africa\',%20type:\'continent\',%20population:\'900%20million\',%20area:%20\'30,221,532%20sq%20km\',\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20timezone:%20\'-1%20UTC%20to%20+4%20UTC\',%20parent:%20\'world\'},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'EG\',%20name:\'Egypt\',%20type:\'country\',%20parent:%20\'AF\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'KE\',%20name:\'Kenya\',%20type:\'country\',%20parent:%20\'AF\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'Nairobi\',%20name:\'Nairobi\',%20type:\'city\',%20parent:%20\'KE\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'Mombasa\',%20name:\'Mombasa\',%20type:\'city\',%20parent:%20\'KE\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'SD\',%20name:\'Sudan\',%20type:\'country\',%20parent:%20\'AF\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'Khartoum\',%20name:\'Khartoum\',%20type:\'city\',%20parent:%20\'SD\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'AS\',%20name:\'Asia\',%20type:\'continent\',%20parent:%20\'world\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'CN\',%20name:\'China\',%20type:\'country\',%20parent:%20\'AS\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'IN\',%20name:\'India\',%20type:\'country\',%20parent:%20\'AS\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'RU\',%20name:\'Russia\',%20type:\'country\',%20parent:%20\'AS\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'MN\',%20name:\'Mongolia\',%20type:\'country\',%20parent:%20\'AS\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'OC\',%20name:\'Oceania\',%20type:\'continent\',%20population:\'21%20million\',%20parent:%20\'world\'},\n%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'EU\',%20name:\'Europe\',%20type:\'continent\',%20parent:%20\'world\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'DE\',%20name:\'Germany\',%20type:\'country\',%20parent:%20\'EU\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'FR\',%20name:\'France\',%20type:\'country\',%20parent:%20\'EU\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'ES\',%20name:\'Spain\',%20type:\'country\',%20parent:%20\'EU\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'IT\',%20name:\'Italy\',%20type:\'country\',%20parent:%20\'EU\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'NA\',%20name:\'North%20America\',%20type:\'continent\',%20parent:%20\'world\'%20},\n%20%20%20%20%20%20%20%20%20%20%20%20{%20id:%20\'SA\',%20name:\'South%20America\',%20type:\'continent\',%20parent:%20\'world\'%20}\n%20%20%20%20%20%20%20%20],\n%20%20%20%20%20%20%20%20getChildren:%20function(object){\n%20%20%20%20%20%20%20%20%20%20%20%20return%20this.query({parent:%20object.id});\n%20%20%20%20%20%20%20%20}\n%20%20%20%20});\n\n%20%20%20%20//%20Create%20the%20model\n%20%20%20%20var%20myModel%20=%20new%20ObjectStoreModel({\n%20%20%20%20%20%20%20%20store:%20myStore,\n%20%20%20%20%20%20%20%20query:%20{id:%20\'world\'}\n%20%20%20%20});\n\n%20%20%20%20//%20Create%20the%20Tree.%20%20%20Note%20that%20all%20widget%20creation%20should%20be%20inside%20a%20dojo.ready().\n%20%20%20%20ready(function(){\n%20%20%20%20%20%20%20%20var%20tree%20=%20new%20Tree({\n%20%20%20%20%20%20%20%20%20%20%20%20model:%20myModel\n%20%20%20%20%20%20%20%20});\n%20%20%20%20%20%20%20%20tree.placeAt(win.body());\n%20%20%20%20%20%20%20%20tree.startup();\n%20%20%20%20});\n});</script>\n</head>\n<body%20class="claro">\n%20%20%20%20\n</body>\n</html>'
      

实现实例

参考 fill-iframe-with-string.html, 要点解释如下:

  1. 基本流程就是:
    • IFrame 内部 document.open();
    • IFrame 内部 document.write(...);
    • IFrame 内部 document.close();
  2. 示例中实现了向 IFrame 内部窗口传递参数的功能。注意在 IE 中,document.open() 会清除 IFrame 内部 window 对象上的属性,因此参数的设置需要在 document.open() 之后进行;
  3. 关于脚本的执行:
    • 按照一般的习惯,在页面头部会使用诸如 <script src="./jquery-ui-1.10.3/jquery-1.9.1.js"></script> 这样的写法引入外部 js,然后在 HTML 元素之后使用嵌入的 javascript 脚本执行与页面元素相关的操作;
    • 在 Firefox 和 Chrome 中,<script> 的执行是按照在页面中的先后顺序进行的, 因此处于文档后部的嵌入 javascript 脚本可以使用外部 js 中定义的变量(比如:jQuery 的 "$");
    • 但是在 IE 中情况正好相反,在执行嵌入的 javascript 脚本时,引入的外部 js 还没有执行,这样就造成嵌入 javascript 脚本出现 "找不到 $ 对象" 之类的错误;
    • 解决方法是在 IFrame 内部页面上定义 bodyonload 事件,在这个事件中执行页面中的嵌入 javascript 脚本。

实际效果见 在线演示

讨论:不同浏览器的差异

总的来说 IE9、Firefox 和 Chrome 的差别很小,倒是 IE8 与其他浏览器存在不小的差别,主要包括:

  • 安全模型:上面提到的示例 html 文件无法通过 IE8 直接在本地打开(如下图),但是其他浏览器可以正常打开,而发布到 Web 服务器上之后,IE8 也可以正常打开;

    另外如果 IFrame 中引用的是来自网络的 js 外部文件,IE8 可以正常运行(见这个例子:fill-iframe-with-string-online-test.html);
  • IFrame 相关对象, 以及页面高度检测:下面对不同浏览器中 iframe.documentWindowiframe.contentWindowiframe.Documentiframe.contentDocument.body.offsetHeightiframe.Document.body.scrollHeight进行了比较,可以看出来,IE8 与其他几个浏览器的差异比较明显:
    • IE8, WindowsXP:
    • IE9, Windows 7:
    • Firefox19, Windows 7:
    • Firefox20, Ubuntu:
    • Google Chrome 6, Windows 7:
    • Chromium25, Ubuntu:

END

PortableTrac and thinkbase.net - upgrade to Python 2.7.4

Original plan was upgrade to Portable Python 2.7.3.2, unfortunately this version is incompatible to mod_wsgi(See below error screenshot), the error message in stdout is :

>>> call "I:\thinkbase.net\github\PortableTrac\httpd\Apache2.2\bin\httpd.exe"
httpd.exe: Syntax error on line 504 of I:/thinkbase.net/github/PortableTrac/httpd/Apache2.2/conf/httpd.conf: Cannot load B:/Apache2.2/modules/mod_wsgi-win32-ap22py27-3.3.so into server: \xb6\xaf\xcc\xac\xc1\xb4\xbd\xd3\xbf\xe2(DLL)\xb3\xf5\xca\xbc\xbb\xaf\xc0\xfd\xb3\xcc\xca\xa7\xb0\xdc\xa1\xa3

The reason is the version of the Microsoft C/C++ compiler(http://code.google.com/p/modwsgi/wiki/InstallationOnWindows#Compiling_From_Source_Code To compile from source code you will need Microsoft C/C++ compiler for Windows. This must be the same version of the compiler as used to build the version of Python being used.).

So finally we chose the official python distribution(Python 2.7.4) and embeded the python runtime into PortableTrac, this is the construction of embeded python runtime, following is the way to embed official python:

  1. Download Python 2.7.4 Windows Installer''(python-2.7.4.msi)'', and install it to C:\Python27(Or else other folder you like);
  1. Download setuptools 0.6c11''(setuptools-0.6c11.win32-py2.7.exe)'' and install it.
  1. Copy files and folders in C:\Python27 into PortableTrac's PortablePython\App folder;
    • Before copy, delete *.pyc and *.pyo files;
  1. Copy %windir%\system32\python27.dll into PortableTrac's PortablePython\App folder;
  1. To make it work on Windows XP, copy following files into PortablePython\App folder:
    • VC90.CRT:
      c:\WINDOWS\WinSxS\x86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.21022.8_x-ww_d08d0375\msvcm90.dll
      c:\WINDOWS\WinSxS\x86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.21022.8_x-ww_d08d0375\msvcp90.dll
      c:\WINDOWS\WinSxS\x86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.21022.8_x-ww_d08d0375\msvcr90.dll
      
    • The manifest(PortablePython\App\Microsoft.VC90.CRT.manifest), Copy from:
      c:\WINDOWS\WinSxS\Manifests\x86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.21022.8_x-ww_d08d0375.manifest
      
  1. That's all, we commit the whole python runtime into PortableTrac Repository.

The benefit of embeding python runtime is the easy-trac-deploy: Just download from Github and uncompress it, python runtime is there ready.

Please follow the installation guide, download, then play it, best regards!

在 Basic 认证下多个 Trac 服务器之间的单点登陆

由于 Trac 目前只能支持单个项目,所以,很多时候需要在多个 Trac 服务器间进行链接等的互相关联,Trac 对这种需求的回答是 InterTrac(中文) ,不过 InterTrac 并不处理多个 Trac 服务器之间的统一登陆问题;

原理

在使用 Apache httpd 的Basic 认证模式下,如果多个 Trac 服务器使用相同的认证来源(比如使用相同的LDAP服务器,或者相同的passwd文件),那么就可以比较方便的实现多个 Trac 服务器间的单点登陆,要点包括:

  1. 一般情况下与 Trac 服务器集成的 httpd 会设置对 .../login 地址的用户认证,如果在当前服务器中设置一个指向其他服务器的反向代理,并且对反向代理后的 url 设置一个当前服务器的 LocationMatch 认证控制,那么:
    1. 如果用户已经登陆当前 Trac,那么访问反向代理后的 url 就可以自动获得已有的 Basic 认证信息(因为二者是一个服务器地址);
    2. 在已经具有 Basic 认证信息的情况下,通过反向代理访问到真正的服务器时,Basic 认证信息同样可以传递,从而可以直接登陆到外部服务器,不需要用户再次输入用户名/密码;
  2. 借用 Trac 处理 .../login 时对 referer HTTP 参数的 redirect_back 特性,如果在访问 .../login 时使用参数 ?referer=....,那么完成 Basic 认证后,可以重定向到需要显示的页面;
  3. 通过在 trac.ini 中设置类似 prj1.url = /trac/prj1/login?referer=/trac/prj1InterTrac URL,可以保证使用 InterTrac 语法编写的 TracLinks 通过 .../login URL 实现自动登陆然后跳转到具体页面,从而完成单点登录;

具体实现举例

  • httpd.conf
    LoadModule proxy_module modules/mod_proxy.so
    LoadModule proxy_http_module modules/mod_proxy_http.so
    ProxyRequests Off
    # ================================================= 
    # Proxy to http://another-server/trac/prj1
    # =================================================
    <proxy http://another-server/trac/prj1>
        AllowOverride None
        Order Deny,Allow
        Allow from all
    </proxy>
    ProxyPass /trac/prj1 http://another-server/trac/prj1
    ProxyPassReverse /trac/prj1 http://another-server/trac/prj1
    # ================================================= 
    # Proxy to http://another-server2/trac/prj2
    # =================================================
    <proxy http://another-server2/trac/prj2>
        AllowOverride None
        Order Deny,Allow
        Allow from all
    </proxy>
    ProxyPass /trac/prj2 http://another-server2/trac/prj2
    ProxyPassReverse /trac/prj2 http://another-server2/trac/prj2
    
    # 这里定义的 AuthType 必需是 Basic, 其他的配置项与当前 Trac 要保持一致,即这几个 Trac 需要使用同一个用户认证机制和认证来源
    # 具体需要几个 LocationMatch,取决于反向代理配置是的 URL 设置情况,这里因为反向代理的两台服务器都被定义在 /trac 下,所以可以使用一个 LocationMatch 来进行用户认证
    <LocationMatch "/trac/[^/]+/login">
        AuthType Basic
        AuthBasicProvider "ldap"
        AuthLDAPUrl "ldap://domain-server/DC=thinkbase,DC=net?sAMAccountName?sub?(objectClass=*)"
        AuthLDAPBindDN "CN=trac-ldap-user,OU=ServerAccountsGroup,DC=thinkbase,DC=net"
        AuthLDAPBindPassword "**********"
    
        AuthName "Trac 1.0.1"
    
        Require valid-user
    </LocationMatch>
    
  • trac.ini
    [intertrac]
    P1 = prj1
    prj1.title = Project 1 Trac
    prj1.url = /trac/prj1/login?referer=/trac/prj1
    P2 = prj2
    prj2.title = Project 2 Trac
    prj2.url = /trac/prj2/login?referer=/trac/prj2
    

另外一种方式

如果两个 Trac 服务器的认证来源不一致(比如一个使用 LDAP 认证,一个使用 passwd 文件认证,用户名和密码都不相同),是否可以实现类似的效果呢?

答案是可以的,不过需要有一个前提,就是使用固定的用户/密码访问另外那个 Trac 服务器,具体来说,在 httpd.conf 中可以省去 <LocationMatch 定义认证方式的部分,而是在 <proxy 中通过 HTTP Header Authorization 写死 Basic 认证的用户名和密码:

  • httpd.conf
    LoadModule proxy_module modules/mod_proxy.so
    LoadModule proxy_http_module modules/mod_proxy_http.so
    LoadModule headers_module modules/mod_headers.so
    ProxyRequests Off
    # ================================================= 
    # Proxy to http://another-server/trac/prj1
    # =================================================
    <proxy http://another-server/trac/prj1>
        AllowOverride None
        Order Deny,Allow
        Allow from all
        # 这里固定设置反向代理转发时的 Basic 认证用户名和密码, dXNlcjE6cGFzc3dkMQ= 是命令行 'echo -n user1:passwd1 | base64' 的运行结果
        RequestHeader set Authorization "Basic dXNlcjE6cGFzc3dkMQ="
    </proxy>
    ProxyPass /trac/prj1 http://another-server/trac/prj1
    ProxyPassReverse /trac/prj1 http://another-server/trac/prj1
    

演示

就 thinkbase.net 站点的两个 trac 环境作了一个示例。当然,因为这两个 trac 环境是部署在同一个 apache httpd 上的,所以不需要在 httpd.conf 中增加配置。

参考

END

nginx 反向代理功能介绍及在Windows下使用的Portable版本

想做一个公网访问内网的反向代理,但是在公网机器上的 Apache 怎么也安装不上(那个机器已经安装了两个 Apache,不知道是不是这方面的原因),于是就研究了一下如何使用 nginx 来实现反向代理。

搜索了一下资料,发现 nginx 似乎比 Apache 更好用,包括:

  • 配置的方式类似 json,比较容易阅读;
  • 运行简单,Windows 平台上的二进制文件本身就是解压即可运行,够 “Portable”;
  • 在网上找到了使用 Windows Service Wrapper 将 nginx 转为一个 Windows 服务的方法,经试验简单有效,见 Nginx Windows Service

nginx 自然在其 官网下载,本文使用的是 Stable version, nginx/Windows-1.2.7;

winsw(Windows Service Wrapper)原来 host 在 https://kenai.com/,不过Oracle 收购 Sun 之后这个网站似乎受到一些影响,目前已经转到了 github 上: https://github.com/kohsuke/winsw/ (是用 C# 编写的,呵呵), 其二进制文件可以在 Nginx Windows Service 文中提到的地点 http://download.java.net/maven/2/com/sun/winsw/winsw/ 下载(似乎是一个 maven 的仓库?);

本文附件中的 “PortableNgnix” 只是简单的将解压后的 nginx Windows 程序和 winsw 合并在一起而已,其中包含一个简单的 proxy 写法示例(将 http://localhost/main/browser/AdminShells/ 反向代理连接到 http://thinkbase.net/main/browser/AdminShells/ ):

#user  nobody;
worker_processes  1;

events {
    worker_connections  1024;
}


http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  logs/access.log  main;

    keepalive_timeout  65;

    server {
        listen       80;
        server_name  localhost;
        location / {
            root   html;
            index  index.html index.htm;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        location /main/browser/AdminShells/ {
                proxy_pass              http://thinkbase.net/main/browser/AdminShells/;
                proxy_redirect          off;
                proxy_set_header        X-Real-IP       $remote_addr;
                proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}

其实很多时候还有更简单的写法,比如下面这个反向代理 svn 服务器的例子:

#user  nobody;
worker_processes  1;

events {
    worker_connections  1024;
}


http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  logs/access.log  main;

    keepalive_timeout  65;

    server {
        listen       81;
        server_name  localhost;

        location / {
                proxy_pass              http://192.168.0.77:8080/;
                proxy_redirect          off;
                proxy_set_header        X-Real-IP       $remote_addr;
                proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}

使用 winsw 创建 Windows Service 的过程也很简单,附件 PortableNginx.7z 中的例子是假设 nginx 解压后在 D:\PortableNginx 目录下的情况:

<service>
    <id>nginx-reverse-proxy</id>
    <name>nginx reverse proxy</name>
    <description>nginx reverse proxy</description>
    <executable>D:\PortableNginx\nginx\nginx.exe</executable>
    <logpath>D:\PortableNginx\nginx\logs</logpath>
    <logmode>roll</logmode>
    <depend></depend>
    <startargument>-p D:\PortableNginx\nginx -c D:\PortableNginx\nginx\proxy.conf</startargument>
    <stopargument>-p D:\PortableNginx\nginx -s stop</stopargument>
</service>

更多细节可以继续研究附件(参见其中的 readme.txt),或者把附件解压后自己体验,下面是 winsw 产生的 Windows Servicce 以及 Service 运行时产生的相关文件截图,供参考: .

Windows: 定义以较短时间间隔重复运行的计划任务

增强Windows计划任务执行用户的安全性 里面提到了如何增强计划任务的安全性, 其实计划任务中存在很多灵活应用的地方, 比如如何让一个任务以较短的时间间隔重复运行, 比如一个每小时执行一次的任务, 呆板地为每次运行设置一个日程安排条目(那么就有12个日程安排, 如果是每隔5分钟运行一次呢?!!!)显然不是最好的方案.

附图是在 Windows Server 2008(Win7、Win8 的计划任务设置界面也是这样的)中设置每5分钟执行一次的任务时的触发器定义, 供参考.

附加说明:截图中的"1430分钟"是这样计算的:1430/60 = 23.83 小时 = 23 小时 50 分钟.

在 Trac 中集成 Git 版本库

按照 [TracGit] 的说明, 把现有的几个 Github 上的 Git Repositories( https://github.com/thinkbase )集成到 thinkbase.net.

主要操作记录如下:

  1. 将 Git 引入运行环境. git.exe 来自 Git for Windows, 具体的安装版本是 Git-1.8.1.2-preview20130201.exe, 安装后只需要保留 bin 目录即可.
  2. 修改 trac.ini 及 增加版本库:
    • 按照 [TracGit] 的说明, 在 trac.ini[components] 小节增加:
      tracopt.versioncontrol.git.* = enabled
      
    • 在 Trac 的 管理: 版本库 中添加版本库:
    • 注意, 在添加版本库时, Trac 会提醒需要执行 trac-admin $ENV repository resync ... 命令(参见上图的提示), 经过实际检验, 这些命令并不是必须的, 可以通过设置 [trac] 小节的 repository_sync_per_request 属性来自动同步源代码库(可能对性能有一定的影响), 例如:
      repository_sync_per_request = PortableTrac, dev-thinkbase.net, trac-thinkbase.net
      
    • 详细的修改参见 97b08e...

thinkbase.net 升级到 Trac 1.0.1

Trac 1.0 分支已经发布版本 1.0.1(参见 http://trac.edgewall.org/wiki/TracDev/ReleaseNotes/1.0#MaintenanceReleases), 因此今天将 http://thinkbase.net 站点(及其运行环境 PortableTrac)升级到这个版本.

主要工作

升级过程的主要工作包括升级 Trac 1.0.1 egg 包升级 Trac 环境, 详细步骤参见 TracUpgrade 或者 http://trac.edgewall.org/wiki/TracUpgrade ;

1. 安装 Trac 1.0.1

由于安装之前需要测试, 因此安装过程是在测试系统中进行的, 安装测试成功后, 将调整后的 PortableTrac 提交到 PortableTrac GitHub Repositories, 然后在正式系统中更新这个运行环境;

  • 主要命令:
    I:\thinkbase.net\github\PortableTrac-git>easy_install --upgrade Trac==1.0.1
    

2. 升级 Trac 环境

升级过程直接在正式系统中进行(此前已经在测试系统中经过测试了).

  • 主要命令:
    D:\thinkbase.net\PortableTrac-git>set SITE_BASE=D:\thinkbase.net\trac-thinkbase.net-git
    D:\thinkbase.net\PortableTrac-git>trac-admin.cmd trac upgrade
    D:\thinkbase.net\PortableTrac-git>trac-admin.cmd main upgrade
    D:\thinkbase.net\PortableTrac-git>trac-admin.cmd trac wiki upgrade
    D:\thinkbase.net\PortableTrac-git>trac-admin.cmd main wiki upgrade
    

详细操作日志

I:\thinkbase.net\github\PortableTrac-git>easy_install --upgrade Trac==1.0.1
[Current timestamp: 2013-02-18 周一 13-52-58.93]

>>> call easy_install.exe --prefix="I:\thinkbase.net\github\PortableTrac-git\trac" --upgrade Trac==1.0.1
Searching for Trac==1.0.1
Reading http://pypi.python.org/simple/Trac/
Reading http://trac.edgewall.org/
Reading http://trac.edgewall.org/wiki/TracDownload
Reading http://trac.edgewall.com/
Reading http://projects.edgewall.com/trac
Reading http://projects.edgewall.com/trac/wiki/TracDownload
Best match: Trac 1.0.1
Downloading http://download.edgewall.org/trac/Trac-1.0.1.win32.exe
Processing Trac-1.0.1.win32.exe
Deleting d:\temp\easy_install-yza88_\Trac-1.0.1-py2.7-win32.egg.tmp\EGG-INFO\scripts\trac-admin-script.py
Deleting d:\temp\easy_install-yza88_\Trac-1.0.1-py2.7-win32.egg.tmp\EGG-INFO\scripts\trac-admin.exe
Deleting d:\temp\easy_install-yza88_\Trac-1.0.1-py2.7-win32.egg.tmp\EGG-INFO\scripts\tracd-script.py
Deleting d:\temp\easy_install-yza88_\Trac-1.0.1-py2.7-win32.egg.tmp\EGG-INFO\scripts\tracd.exe
creating 'd:\temp\easy_install-yza88_\Trac-1.0.1-py2.7-win32.egg' and adding 'd:\temp\easy_install-yza88_\Trac-1.0.1-py2.7-win32.egg.tmp' to it
Moving Trac-1.0.1-py2.7-win32.egg to i:\thinkbase.net\github\portabletrac-git\trac\lib\site-packages
Removing trac 1.0 from easy-install.pth file
Adding Trac 1.0.1 to easy-install.pth file
Installing trac-admin-script.pyc script to I:\thinkbase.net\github\PortableTrac-git\trac/Scripts
Installing tracd-script.pyc script to I:\thinkbase.net\github\PortableTrac-git\trac/Scripts
Installing trac-admin-script.py script to I:\thinkbase.net\github\PortableTrac-git\trac/Scripts
Installing trac-admin.exe script to I:\thinkbase.net\github\PortableTrac-git\trac/Scripts
Installing trac-admin.exe.manifest script to I:\thinkbase.net\github\PortableTrac-git\trac/Scripts
Installing tracd-script.py script to I:\thinkbase.net\github\PortableTrac-git\trac/Scripts
Installing tracd.exe script to I:\thinkbase.net\github\PortableTrac-git\trac/Scripts
Installing tracd.exe.manifest script to I:\thinkbase.net\github\PortableTrac-git\trac/Scripts

Installed i:\thinkbase.net\github\portabletrac-git\trac\lib\site-packages\trac-1.0.1-py2.7-win32.egg
Processing dependencies for Trac==1.0.1
Finished processing dependencies for Trac==1.0.1

I:\thinkbase.net\github\PortableTrac-git>

================================================================================
================================================================================

D:\thinkbase.net\PortableTrac-git>set SITE_BASE=D:\thinkbase.net\trac-thinkbase.net-git

D:\thinkbase.net\PortableTrac-git>trac-admin.cmd trac upgrade
[Current timestamp: 2013-02-18 星期一 15-12-12.14]

>>> call python.exe  "D:\thinkbase.net\PortableTrac-git\trac\Scripts\trac-admin-script.py" "D:\thinkbase.net\trac-thinkbase.net-git\tracenv\trac" upgrade
Database is up to date, no upgrade necessary.

D:\thinkbase.net\PortableTrac-git>trac-admin.cmd main upgrade
[Current timestamp: 2013-02-18 星期一 15-12-26.48]

>>> call python.exe  "D:\thinkbase.net\PortableTrac-git\trac\Scripts\trac-admin-script.py" "D:\thinkbase.net\trac-thinkbase.net-git\tracenv\main" upgrade
Database is up to date, no upgrade necessary.

D:\thinkbase.net\PortableTrac-git>trac-admin.cmd trac wiki upgrade
[Current timestamp: 2013-02-18 星期一 15-12-35.62]

>>> call python.exe  "D:\thinkbase.net\PortableTrac-git\trac\Scripts\trac-admin-script.py" "D:\thinkbase.net\trac-thinkbase.net-git\tracenv\trac" wiki upgrade
  CamelCase is already up to date
  InterMapTxt already exists
  InterTrac is already up to date
  InterWiki is already up to date
  PageTemplates imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\PageTemplates
  RecentChanges is already up to date
  SandBox is already up to date
  TitleIndex is already up to date
  TracAccessibility is already up to date
  TracAdmin is already up to date
  TracBackup is already up to date
  TracBatchModify is already up to date
  TracBrowser is already up to date
  TracCgi is already up to date
  TracChangeset is already up to date
  TracEnvironment is already up to date
  TracFastCgi imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\TracFastCgi
  TracFineGrainedPermissions is already up to date
  TracGuide is already up to date
  TracImport is already up to date
  TracIni is already up to date
  TracInstall is already up to date
  TracInterfaceCustomization imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\TracInterfaceCustomization
  TracLinks is already up to date
  TracLogging is already up to date
  TracModPython is already up to date
  TracModWSGI is already up to date
  TracNavigation imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\TracNavigation
  TracNotification is already up to date
  TracPermissions imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\TracPermissions
  TracPlugins is already up to date
  TracQuery is already up to date
  TracReports imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\TracReports
  TracRepositoryAdmin imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\TracRepositoryAdmin
  TracRevisionLog is already up to date
  TracRoadmap is already up to date
  TracRss is already up to date
  TracSearch is already up to date
  TracStandalone imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\TracStandalone
  TracSupport is already up to date
  TracSyntaxColoring is already up to date
  TracTickets is already up to date
  TracTicketsCustomFields is already up to date
  TracTimeline is already up to date
  TracUnicode is already up to date
  TracUpgrade imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\TracUpgrade
  TracWiki is already up to date
  TracWorkflow imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\TracWorkflow
  WikiDeletePage is already up to date
  WikiFormatting is already up to date
  WikiHtml is already up to date
  WikiMacros imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\WikiMacros
  WikiNewPage imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\WikiNewPage
  WikiPageNames is already up to date
  WikiProcessors imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\WikiProcessors
  WikiRestructuredText is already up to date
  WikiRestructuredTextLinks is already up to date

D:\thinkbase.net\PortableTrac-git>trac-admin.cmd main wiki upgrade
[Current timestamp: 2013-02-18 星期一 15-12-46.85]

>>> call python.exe  "D:\thinkbase.net\PortableTrac-git\trac\Scripts\trac-admin-script.py" "D:\thinkbase.net\trac-thinkbase.net-git\tracenv\main" wiki upgrade
  CamelCase is already up to date
  InterMapTxt already exists
  InterTrac is already up to date
  InterWiki is already up to date
  PageTemplates imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\PageTemplates
  RecentChanges is already up to date
  SandBox is already up to date
  TitleIndex is already up to date
  TracAccessibility is already up to date
  TracAdmin is already up to date
  TracBackup is already up to date
  TracBatchModify is already up to date
  TracBrowser is already up to date
  TracCgi is already up to date
  TracChangeset is already up to date
  TracEnvironment is already up to date
  TracFastCgi imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\TracFastCgi
  TracFineGrainedPermissions is already up to date
  TracGuide is already up to date
  TracImport is already up to date
  TracIni is already up to date
  TracInstall is already up to date
  TracInterfaceCustomization imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\TracInterfaceCustomization
  TracLinks is already up to date
  TracLogging is already up to date
  TracModPython is already up to date
  TracModWSGI is already up to date
  TracNavigation imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\TracNavigation
  TracNotification is already up to date
  TracPermissions imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\TracPermissions
  TracPlugins is already up to date
  TracQuery is already up to date
  TracReports imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\TracReports
  TracRepositoryAdmin imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\TracRepositoryAdmin
  TracRevisionLog is already up to date
  TracRoadmap is already up to date
  TracRss is already up to date
  TracSearch is already up to date
  TracStandalone imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\TracStandalone
  TracSupport is already up to date
  TracSyntaxColoring is already up to date
  TracTickets is already up to date
  TracTicketsCustomFields is already up to date
  TracTimeline is already up to date
  TracUnicode is already up to date
  TracUpgrade imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\TracUpgrade
  TracWiki is already up to date
  TracWorkflow imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\TracWorkflow
  WikiDeletePage is already up to date
  WikiFormatting is already up to date
  WikiHtml is already up to date
  WikiMacros imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\WikiMacros
  WikiNewPage imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\WikiNewPage
  WikiPageNames is already up to date
  WikiProcessors imported from C:\Documents and Settings\Administrator\Application Data\Python-Eggs\trac-1.0.1-py2.7-win32.egg-tmp\trac\wiki\default-pages\WikiProcessors
  WikiRestructuredText is already up to date
  WikiRestructuredTextLinks is already up to date

D:\thinkbase.net\PortableTrac-git>

使用 x3dom 框架及 WebGL 在浏览器上显示 3 维模型

如果需要在浏览器上显示 3D 画面的话, 现在一般会使用 WebGL, 典型的例如 three.js(http://mrdoob.github.com/three.js/), 但是 WebGL 对浏览器版本以及显卡的要求比较高, 很多客户端无法正常使用 ———— 当然现在新买的机器是毫无压力的.

后来在网上查找到了 X3DOM(http://www.x3dom.org/), 通过使用不同的后端(backend), X3DOM 可以兼容较低版本的浏览器(主要是指 IE 系列), 也可以在没有显卡支持的情况下运行, 常用的非 WebGL 后端是 Adobe Flash Player 11, IE 也可以通过使用 Google Chrome Frame 实现对 WebGL 的支持, 注意 Flash 11 以下的版本是不能正常运行的.

X3DOM 通过在标准的 HTML5 DOM 中加入 X3D 格式的 XML 元素, 实现将 X3D 格式的 3D 模型嵌入到 HTML 页面的功能; 在 http://www.x3dom.org/ 网站上有丰富的示例以及较详细的文档, 不过彻底搞懂估计需要一些 3D 建模的知识, 比如 fieldOfView 这样的专业术语.

另外 web3D Consortium 也有大量关于 X3D 的资料, 尤其是 X3D tooltips(http://www.web3d.org/x3d/content/X3dTooltips.html), 是一份全面的 X3D 节点元素速查手册(有中文版)(不知道为什么 www.web3d.org 被 GWF 了, 如果要下载也可以到 这里);

在初步了解 x3dom 的基础上, 以显示货物装箱为例, 对 x3dom 进行了简单的封装, 重点关注 货物在集装箱等容器中的堆放方式的显示, 可以实现以 "Box" 的方式加入不同尺寸的货物(长方体), 以不同的角度查看堆放情况, 以及对这些长方体的选择/加亮显示等等, 具体代码可以到 https://github.com/thinkbase/dev-thinkbase.net/tree/master/.research/x3dom-container-fill 下载, 注意测试用的 html 文件不能直接在本地打开, 必须部署到 HTTP 服务器上才能正常运行; 如果不想麻烦的话,在这里可以看到 在线演示.

实际显示的效果如下图所示(使用 Flash backend 的效果, 如果系统支持 WebGL 的话效果应该要好很多):

DocFetcher 1.1.5 试用及 zip 文件中文问题解决

自从接触 DocFetcher 以来, 就一直使用它来搜索自己的各类文档, 当时也总结过这个软件存在的问题, 详见 桌面搜索工具 DocFetcher 试用笔记;

概况

最近发现 DocFetcher 已经发布了 1.1.5 版本, 根据网站上的介绍, 1.1 版本经过完全重写(rewritten from scratch), 增加了大量的新特征(详见 http://docfetcher.sourceforge.net/wiki/doku.php?id=changes_in_v1.1), 包括我在 桌面搜索工具 DocFetcher 试用笔记 中所关注的:

  • Archive indexing: DocFetcher can now traverse archives. The following archive formats are supported: zip and zip-derived formats, 7z, rar, SFX zip, SFX 7z - 实际实验确认可以支持搜索压缩包中的内容, 而且支持嵌套压缩, 具体可以查看下面的截图;
  • Indexing of and searching in filenames - 可以按照文件名查找;

经过简单试用, 觉得这个版本还是值得升级的, 随后发现在搜索 zip 格式压缩包里面的内容时, 中文文件名会变成乱码. 具体现象如下图所示, 虽然可以索引压缩文件中的内容, 但是 zip 格式压缩包中中文文件名显示为乱码, 而 7z 和 rar 格式则显示正确:

下载代码(git clone http://git.code.sf.net/p/docfetcher/code docfetcher-code)研究了一下, 发现 DocFetcher 使用了 truezip 来进行 zip 格式压缩文件的搜索(支持 jar|tar|tar.bz2|tar.gz|tb2|tbz|tgz|zip 等多种格式), 而在 truezip 中, zip 格式默认使用的字符集为 IBM437:

... ...
public class ZipDriver
extends FsCharsetArchiveDriver<ZipDriverEntry>
implements ZipOutputStreamParameters, ZipFileParameters<ZipDriverEntry> {

    private static final Logger logger = Logger.getLogger(
            ZipDriver.class.getName(),
            ZipDriver.class.getName());

    /**
     * The character set for entry names and comments in &quot;traditional&quot;
     * ZIP files, which is {@code "IBM437"}.
     */
    private static final Charset ZIP_CHARSET = Charset.forName("IBM437");

    private final IOPool<?> ioPool;

    /**
     * Constructs a new ZIP driver.
     * This constructor uses {@link #ZIP_CHARSET} for encoding entry names
     * and comments.
     *
     * @param ioPoolProvider the provider for I/O entry pools for allocating
     *        temporary I/O entries (buffers).
     */
    public ZipDriver(IOPoolProvider ioPoolProvider) {
        this(ioPoolProvider, ZIP_CHARSET);
    }
    ... ...

而日常我们使用的 zip 压缩文件都是使用本地字符集进行压缩的(在中文环境下, 一般就是GBK), 继续研究发现, DocFetcher 使用 truezipTFile, 实现与 java.io.File 相似的方式统一访问文件系统目录和压缩文件(也就是把压缩文件看作一个目录), 而 TFile 内部则通过一个 TArchiveDetector 类型的成员变量来依据后缀名确定使用那种 "Driver" 操作具体的压缩文件;

默认情况下, 通过 TConfig.getArchiveDetector() 得到的 ArchiveDetector 是 TArchiveDetector.ALL, 此时在 TArchiveDetector 中实际使用 FsDriverLocator.SINGLETON 来获得所有加载的 "Driver", FsDriverLocator 会通过 ServiceLocator 查找并加载所有可用的 Driver, zip 格式相关 Driver 的定义实现在 ZipDriverService 中:

@Immutable
public final class ZipDriverService extends FsDriverService {

    private static final Map<FsScheme, FsDriver>
            DRIVERS = newMap(new Object[][] {
                { "zip", new ZipDriver(IOPoolLocator.SINGLETON) },
                { "ear|jar|war", new JarDriver(IOPoolLocator.SINGLETON) },
                { "odt|ott|odg|otg|odp|otp|ods|ots|odc|otc|odi|oti|odf|otf|odm|oth|odb", new OdfDriver(IOPoolLocator.SINGLETON) },
                { "exe", new ReadOnlySfxDriver(IOPoolLocator.SINGLETON) },
            });

    @Override
    public Map<FsScheme, FsDriver> get() {
        return DRIVERS;
    }
}

从上面这段代码可见, 系统默认得到的 ZipDriver 使用的是默认字符集 IBM437, 所以, 会产生中文问题;

另外, 从源代码还可以看到, JarDriver 默认使用的字符集是 UTF-8;

解决这个问题的方式是对 ZipDriverService 进行一定的调整, 以便通过环境变量或者 Java 系统属性来调整 ZipDriver 的默认字符集, 然后把这个 class 以 jar 补丁的形式, 放到 CLASSPATH 的最前面. 修改后的 ZipDriverService 代码如下:

@Immutable
public final class ZipDriverService extends FsDriverService {
        private static final String SYS_PROP_ZIP_CHARSET = ZipDriverService.class.getPackage().getName() + ".ZIP_CHARSET";
        private static final String ENV_VAR_ZIP_CHARSET = "TRUEZIP_ZIP_CHARSET";

        private static final ZipDriver buildZipDriver(){
                String charset = System.getProperty(SYS_PROP_ZIP_CHARSET);
                if (null!=charset && charset.trim().length() > 0){
                        return new ZipDriver(
                                        IOPoolLocator.SINGLETON, Charset.forName(charset.trim()));
                }
                charset = System.getenv(ENV_VAR_ZIP_CHARSET);
                if (null!=charset && charset.trim().length() > 0){
                        return new ZipDriver(
                                        IOPoolLocator.SINGLETON, Charset.forName(charset.trim()));
                }
                
                return new ZipDriver(IOPoolLocator.SINGLETON);
        }

    private static final Map<FsScheme, FsDriver>
            DRIVERS = newMap(new Object[][] {
                { "zip", buildZipDriver() },
                { "ear|jar|war", new JarDriver(IOPoolLocator.SINGLETON) },
                { "odt|ott|odg|otg|odp|otp|ods|ots|odc|otc|odi|oti|odf|otf|odm|oth|odb", new OdfDriver(IOPoolLocator.SINGLETON) },
                { "exe", new ReadOnlySfxDriver(IOPoolLocator.SINGLETON) },
            });

    @Override
    public Map<FsScheme, FsDriver> get() {
        return DRIVERS;
    }
}

编译后的 jar 补丁可以到附件中下载, 此 jar 文件可以放到 DocFetcher-1.1.5 的 patches 目录下, 然后按照下图的样子修改 DocFetcher.sh:

修改后即可正常处理 zip 格式压缩文件中的中文文件名了:

总结

补充说明

本文所提供的补丁没有在 Windows 系统上进行测试, 如果要在 Windows 系统中使用, 建议设置系统环境变量 set TRUEZIP_ZIP_CHARSET=GBK 后运行, 效果应该与 Linux 下一致;

顺便说一下, DocFetcher 对 rar 文件的解析是通过 java-unrar 实现的, 与 zip 压缩文件不同, rar 和 7z 压缩文件是通过所谓 SolidArchiveFactory 来处理的, SolidArchive 模式需要将文件解压到临时目录后再进行索引处理;

END

快速上传附件 - TracDragDropPlugin 插件

TracDragDropPluginhttp://trac-hacks.org/ 上面的一个 Trac 插件, 其主要功能就是使用 HTML5 drag-and-drop 方式, 快速上次附件.

前面一篇 Blog(这里) 具有 171 个截图, 这些图片附件就是使用 TracDragDropPlugin 批量上传的:
.

CentOS 6.0 虚拟机安装日志(截屏)(补 20111203)

在虚拟机中安装 CentOS 6.0

从 DVD1 iso 文件启动


安装开始界面


开始安装





















磁盘分区










选择"最小桌面"安装方式










安装完成, 重启







安装后的设置步骤

基本设置项目






Kdump 无法启用



进入系统




设置网络








虚拟机安装结束


重启, 检查更新













































安装 gcc 和内核头文件等










安装 vmware-tools

尝试


系统安装时已自带 vmware-tools


安装 telnet 命令






验证 sshd 已安装


安装 svn (客户端)








安装 7-zip 支持

































防火墙(iptables)设置








END

批处理中很有用的命令 WMIC(补 20120503)

原文来自 https://code.google.com/p/thinkbasenet/wiki/20120503_WMIC

最典型的用法

通过命令行中的一些内容查找程序

wmic process where "( (CommandLine LIKE '%_notepad_%') AND NOT(CommandLine LIKE '%_wmic_%' ) )"
  • 为了防止有 '%notepad%' 这样的环境变量, 所以使用了 '%_notepad_%' 这样的查询语法, 一般情况下, 直接使用 '%notepad%' 也是可以的.
  • 另外, 查询条件中 LIKE 操作符是不区分字符串的大小写的.

将 wmic 的输出由 unicode 转为 ascii

wmic 输出到 stdout 和 stderr 的内容都是 unicode 的,因此重定向到文件后,看起来会是这个样子:

使用如下的代码可以将 wmic 的输出由 unicode 转为 ascii:

:: 需要将 wmic 的输出由 unicode 转为 ascii
set TMP_WMIC_OUT=%TEMP%\wmic-process-list.txt
wmic /output:"%TMP_WMIC_OUT%" process where name="cmd.exe" get sessionid,commandline
cmd /A /C type "%TMP_WMIC_OUT%"

通过命令行中的一些内容结束程序

wmic process where "( (CommandLine LIKE '%_notepad_%') AND NOT(CommandLine LIKE '%_wmic_%' ) )" delete

参考

  • 关于 wmic 命令输出的 unicode 转 ascii
  • MSDN:
  • Microsoft TechNet
  • 来自 http://lgj573.iteye.com/blog/327432
    # wmic 获取硬盘固定分区盘符:
    wmic logicaldisk where "drivetype=3" get name
    
    # wmic 获取硬盘各分区文件系统以及可用空间:
    wmic logicaldisk where "drivetype=3" get name,filesystem,freespace
    
    # wmic 获取进程名称以及可执行路径:
    wmic process get name,executablepath
    
    # wmic 删除指定进程(根据进程名称):
    wmic process where name="qq.exe" call terminate
    # 或者用
    wmic process where name="qq.exe" delete
    
    # wmic 删除指定进程(根据进程PID):
    wmic process where pid="123" delete
    
    # wmic 创建新进程
    wmic process call create "C:\Program Files\Tencent\QQ\QQ.exe"
    
    # 在远程机器上创建新进程:
    wmic /node:192.168.1.10 /user:administrator /password:123456 process call create cmd.exe
    
    # 关闭本地计算机
    wmic process call create shutdown.exe
    
    # 重启远程计算机
    wmic /node:192.168.1.10/user:administrator /password:123456 process call create "shutdown.exe -r -f -m"
    
    # 更改计算机名称
    wmic computersystem where "caption='%ComputerName%'" call rename newcomputername
    
    # 更改帐户名
    wmic USERACCOUNT where "name='%UserName%'" call rename newUserName
    
    # wmic 结束可疑进程(根据进程的启动路径)
    wmic process where "name='explorer.exe' and executablepath<>'%SystemDrive%\\windows\\explorer.exe'" delete
    
    # wmic 获取物理内存
    wmic memlogical get TotalPhysicalMemory|find /i /v "t"
    
    # wmic 获取文件的创建、访问、修改时间
    @echo off
    wmic datafile where name^="c:\\windows\\system32\\notepad.exe" get CreationDate^,LastAccessed^,LastModified
    
    # wmic 全盘搜索某文件并获取该文件所在目录
    wmic datafile where "FileName='qq' and extension='exe'" get drive,path
    
    for /f "skip=1 tokens=1*" %i in ('wmic datafile where "FileName='qq' and extension='exe'" get drive^,path') do (set "qPath=%i%j"&@echo %qPath:~0,-3%)
    
    # 获取屏幕分辨率
    wmic DESKTOPMONITOR where Status='ok' get ScreenHeight,ScreenWidth
    
    # 获取U盘盘符,并运行U盘上的QQ.exe
    @for /f "skip=1 tokens=*" %i in ('wmic logicaldisk where "drivetype=2" get name') do (if not "%i"=="" start d:\qq.exe)
    
    # 获得进程当前占用的内存和最大占用内存的大小:
    wmic process where caption='filename.exe' get WorkingSetSize,PeakWorkingSetSize
    # 把内存大小改成KB(MB的话可能有小数)
    @echo off
    for /f "skip=1 tokens=1-2 delims= " %%a in ('wmic process where caption^="conime.exe" get WorkingSetSize^,PeakWorkingSetSize') do (
    set /a m=%%a/1024
    set /a mm=%%b/1024
    echo 进程conime.exe现在占用内存:%m%K;最高占用内存:%mm%K
    )
    pause 
    

Ubuntu 10.04 上通过无线共享互联网连接(补 20120222)

原文来自 https://code.google.com/p/thinkbasenet/wiki/20120222_Ubuntu_Wifi_Ad_hoc

参考页面

http://hi.baidu.com/myl71/blog/item/75bb0944bb44362acefca318.html ;

其主要内容如下:

首先准备好带无线网卡的笔记本电脑一台;

Ubuntu10.04操作系统一套;

能正常连接网络的网线一根;

进入ubuntu 10.04后在右上角工具栏的网络连接上点右键,点“新建连接” ,
然后输入你想新建的无线路由器的名字,之后设定加密方式,如果是想满足宿舍
内的网络共享你只需要设置一个wep的加密方式,然后就可以新建成功了,之后
您就可以叫您的朋友搜索无线网络了,然后连接就可以了。

经我的观察,ubuntu下面新建的wifi效果非常的好,网络稳定,网速也非常的
快。适合喜欢无线冲浪的您。

新建的网络连接属性(截屏)

其他信息

  • 其他电脑连接时不需要设置IP, 采用DHCP自动获取IP地址即可;
  • 实际连接后 Ubuntu 机器的网络情况如下, 其中 10.42 网段应该是系统自动分配的, 通过 Wifi 连接到 Ubuntu 上的其他机器的地址应该都在这个网段.
    .

END

Linux 下定期屏幕截屏脚本(补 20111120)

原文来自 https://code.google.com/p/thinkbasenet/wiki/20111120_ScreenRecorderShellInLinux

概述

在上一篇 Windows 和 Linux 下定期屏幕截屏的方法 中提到了可以使用 ImageMagickimport 命令完成截屏过程, 本文基于 import 命令, 提供两个脚本, 分别用于定期截取当前活动窗口, 以及定期截取指定窗口;

脚本

主要技术说明

import 命令

  • -screen 参数: 不了解 X 的细节, 猜测对于一个典型的 X 窗口, 其中的工具提示、菜单等其实是有独立的 window id 的, 那么在指定 window id 截屏时, 可能是截取不到这些内容的, 使用 -screen 参数可以解决这个问题:
    • 没有 -screen 参数时的内容:
    • 加上 -screen 参数:

取得窗口的 window id 和 process id

  1. 获取当前活动窗口的 window id:
    • xprop -root | grep "_NET_ACTIVE_WINDOW(WINDOW)"| cut -d ' ' -f 5
  2. 使用 xwininfo 选择一个窗口并获取其 window id:
    • xwininfo | grep "xwininfo: Window id:" | cut -d ' ' -f 4
  3. 获取窗口($WIN_ID)对应的进程 ID:
    • xprop -id $WIN_ID | grep "_NET_WM_PID(CARDINAL)" | cut -d ' ' -f 3

比较截屏文件是否一致

  • 使用 cmp 命令即可.

END

Windows 和 Linux 下定期屏幕截屏的方法(补 20101114)

原文来自 https://code.google.com/p/thinkbasenet/wiki/20101114_ScreenShotAsFilesInWindowsAndLinux

截屏并存储到文件的方法, 主要是可以用于录制操作视频, 或者日志重要系统操作过程, 以及测试过程等.

简介

一直以来使用 Wink 作为屏幕录制的首选软件, 但是 Wink 存在一个很麻烦的问题, 就是在录制途中, 所有的屏幕截屏都存储在内存里, 因此在很长时间的操作中, 往往会造成内存溢出, 导致前功尽弃.

有一个想法是写一个录制屏幕并且及时存储到图片文件的软件, 最初的想法是使用 Java 来写, 但是一直都没有开始; 今天无意中看到了 nircmd 这个软件, 其中的命令 savescreenshot 可以较好的完成这个要求:

nircmdc.exe loop 1000 2000 savescreenshot c:\temp\scr~$currdate.MM_dd_yyyy$-~$currtime.HH_mm_ss$.png 

loop 1000 2000 代表循环 1000 次, 间隔时间 2 秒(2000 毫秒);

使用 nircmdc 可以保证 1000 次循环完成之前, 命令行一直停留在这个命令上, 方便不需要的时候使用 Ctrl-C 结束截屏过程;

另外还可以使用 savescreenshotwin 命令保存当前活动窗口的命令;

Linux 下的处理方法

使用 nircmdc 可以在 Windows 下实现定时截屏的要求, 但是在 Linux 下又如何实现呢? 经过一番搜索, 大致的解决方案如下:

  1. 基于 ImageMagick, 使用其 import 命令完成截屏过程, 基本语法为:
    import -window <Window ID> <FileName>.png
    
  2. 如果需要截取整个屏幕, 可以使用 root 作为 Window ID, 例如:
    import -window root MyScreenshot3.png
    
  3. 如何实现截取当前活动窗口呢? 可以使用如下命令得到当前活动窗口 ID:
    xprop -root | grep "_NET_ACTIVE_WINDOW(WINDOW)"| cut -d ' ' -f 5
    
  4. 20111120 添加 - Linux 下定期屏幕截屏脚本;

下载

其它

  1. 减少文件大小
    • 如果屏幕内容一直不变, 那么就会出现重复录取同一个画面的情况, 应该可以通过一个脚本使用 md5sum 等命令检查两张图片是否完全一样, 删除重复内容的图片, 这样就可以实现减少文件大小的目的了.

参考资料

  1. http://tips.webdesign10.com/how-to-take-a-screenshot-on-ubuntu-linux
    • "How to Take a Screenshot in Linux (Ubuntu)", 描述了在 Ubuntu 上几种截屏的方法;
  2. http://www.charry.org/docs/linux/ImageMagick/ImageMagick.html
    • "我的ImageMagick使用心得", ImageMagick 的中文介绍;
  3. http://www.ruby-forum.com/topic/165740#728314
    • "Title from current active window", Ruby-Gnome 2 论坛的讨论;

END

桌面搜索工具 DocFetcher 试用笔记(补 20110416)

最初发布在 https://code.google.com/p/thinkbasenet/wiki/20110416_DocFetcherTrialRun ;

简介

在 Ubuntu 上一直使用 Beagle Search( http://beagle-project.org/ )来对一些有用的文档进行全文检索, 今天想起这件事, 上网找了一圈, 发现 DocFetcher( http://sourceforge.net/projects/docfetcher/ ) 也是不错的一个桌面搜索工具.

在 sf.net 网站可以下载到的 DocFetcher 最新版本是 1.0.3 (2010-03-18 更新), 提供了 Win32 安装程序、Linux deb 包, 以及一个可用于 Windows 及 Linux 环境的 "portable" 版本, 解压后即可使用, 运行时产生的配置及索引数据都存放在程序目录下, 方便存放到 U 盘等移动设备上使用 :)

主要特色

  • 基于 Java SWT 开发, 跨平台;
  • 支持 txt、html、MS Office、Open Office、PDF等常用的文件格式, 基本上够用了;
  • 界面比较简单, 但是使用很方便, 基本上只要两步:
    1. 添加要索引的目录, 建立索引;
    2. 输出要查询的字符串, 进行查找;
  • 中文支持不错;

需要解决的问题

  • 最主要的缺点(我认为)是不能检索压缩包, 这样对那些压缩打包后的文档就比较难搜索了;
  • 不支持对文件名进行查找;
  • 对 UTF-8 格式的文本文件, 似乎只能认识英文;

中文化

  • 这个版本的 lang 目录下有 fr、de 等几种语言的资源文件(.properties), 但是没有中文语言的资源文件, 不过很容易通过对 Resource.properties文件翻译产生中文语言包.
  • 今天大致翻译了一下, 如果需要有这个中文语言包的话, 可以在这里下载;

后记

  • 20110416
    • Puggle( http://puggle.sourceforge.net/index.html )也是一个简单易用的 Java 桌面搜索工具, 而且支持 zip 和 rar 格式文档的搜索, 以及针对文件名字的查找(不过, 似乎不支持扩展名 :$).
  • 20121203
    • 发现目前 DocFetcher 已经升级到 1.1.5 版本了, 已经支持对 zip、7z、rar 等格式的压缩文件进行索引, 具体情况有待试验:

      Between version 1.0.3 and version 1.1 beta 1, DocFetcher was rewritten from scratch, resulting in a large number of new features and changes. This page gives an overview of the most important ones.

END

thinkbase.net 站点 logo / favorites icon 调整

默认情况下 PortableTrac 的 logo 为 http://trac-hacks.org/chrome/site/trachacks_banner.png, favorites icon 则为 Trac 默认图标 /chrome/common/trac.ico.

现在 thinkbase.net 的 logo 和 favorites icon 是在 OpenOffice 相关图标的基础上修改得到的, 来源为下面两个图标:

  • logo 的来源:
    • 本网站 logo 的来源文件
  • favorites icon 的来源:
    • 本网站 favorites icon 的来源文件

logo 上的文字是使用 GIMP 修改上去的, 使用的是 文泉驿等宽正黑 字体, GIMP 源文件 (.xcf 格式) 见附件 thinkbase-logo.xcf;

关于这两个图标的详细来源和 License, 请详细参考 ICON FINDER 上的相关页面:

站点 logo / favorites icon 调整的方法参考 ZhTracInterfaceCustomization ;

常用的 PuTTY 和 WinSCP 设置

现在的 Linux 服务器一般都是使用 UTF-8 作为文件系统编码, 同时开放 SSH 供远程访问, 这种情况下, PuTTYWinSCP 就是很有用的 SSH 客户端, 但是默认情况下它们的配置不够合理, 包括会出现 Linux 系统中的中文文件名显示为乱码等现象, 针对这些问题, 需要进行的设置调整如下.

PuTTY

  1. 设置 PuTTY 使用 UTF-8 编码访问服务器, 解决 ls 等命令看到中文文件名是乱码的现象:
    ;
  2. 设置 PuTTY 的 "选中内容鼠标右键处理". 此项设置也非常重要, 因为默认情况下 PuTTY 的处理是 "复制到剪贴板 + 粘贴", 如果万一选中的是多行, 在 shell 中右键操作往往会造成粘贴多行字符串, shell 会当作多个命令去执行, 很容易发生执行错误命令的危险!
  3. 增加 PuTTY 的回滚行数. 默认情况下 PuTTY 的回滚行数很小, 在程序输出大量信息的情况下, 经常会无法看全程序输出的信息, 为此需要把这个行数设大:

WinSCP

  • WinSCP 中将 文件名UTF-8编码 开启就可以解决中文文件名乱码的问题:

补充说明

在 PuTTY 中, 如果在针对打开后的 "Default Settings" 进行设置修改并保存, 那么这些修改就可以作为默认设置保留下来.

END

Json.NET 文档的离线版本

Json.NET( http://json.codeplex.com/ )是 .Net Framework 下一个很有用的 JSON 解析和操作类库,支持 .Net 对象与 JSON 字符串之间的序列化/反序列化,但是其各个 Release 中并没有包含离线文档(只能通过 http://james.newtonking.com/projects/json/help/ 访问其在线版本)。

通过 Firefox 的插件 ScapeBook (可以从 这里 下载), 抓取了一份离线版本, 见附件(Json.NET-Documentation-20121124-james.newtonking.com.7z)。

如何让 .Net 程序能够在网络驱动器上运行

直接双击执行网络驱动器上的 .Net 桌面程序会发生安全异常, 解决方法如下图:

增强Windows计划任务执行用户的安全性

为了避免计划任务执行与当前登录到Windows桌面的用户操作之间的相互干扰(在Win2003上, 如果计划任务的执行用户和当前桌面登录用户相同, 计划任务执行时的命令执行窗口会显示在该用户登录的桌面上, Win2008似乎没有这个问题), 一般需要为计划任务专门指定一个用户, 我习惯于叫cron;

为了方面任务的执行, 通常会简单的把这个用户归到Administrators组, 考虑到Administrators组用户的权限很大, 因此对这个cron帐号需要进行一定的安全控制, 简单的来说就是"限制该用户登录到服务器":

  • 用于计划任务执行用户的创建:
  • 该用户划入管理员组:
  • 通过"组策略编辑器"(gpedit.msc)设置"拒绝本地登录":
  • 通过"组策略编辑器"(gpedit.msc)设置"拒绝从网络访问":
  • 终端服务配置中设置RDP-Tcp连接的访问权限:

经过以上配置, 实际测试该用户无法使用终端服务登录服务器, 这个帐号可以比较安全的用于计划任务了:

使用 w32tm 命令定期同步服务器时间

有时候因为各种原因, Windows服务器的时间可能不准, 比如虚拟机中服务器的时间会受主机时间的影响, 或者机器的BIOS时钟不准确等;

可以简单通过Windows计划任务, 使用 w32tm.exe /resync 命令就可以实现定期自动同步服务器时间的功能:

  • 在"计划任务"中设置执行的命令:
  • 设置定期执行:

如果发现定期时间同步不起作用, 建议直接在命令行中执行 w32tm.exe /resync 命令进行测试, 如果报错 "此计算机没有重新同步,因为没有可用的时间数据。", 可以在 日期和时间 属性 中选择其他的服务器试试:

  • 通过双击 Taskbar 右边的时间显示区域, 或者执行控制面板的"日期和时间", 都可以进入 日期和时间 属性:

VMware vSphere Hypervisor (ESXi)的功能限制

由于一直免费使用 VMWareESXi 虚拟化方案, 因此比较关心其对 CPU 和 RAM 的限制.

来自 http://quicklinux.sinaapp.com/2012/04/14/57.html :

版本4方面(ESXi)物理机 最大两路CPU,最大8核心,(也就是1个8核或者2个四核的CPU)256GB的内存,虚拟机最大4个vSMP,内存不限制(也可以认为成虚拟机合计256GB)

版本5方面(也就是你标题的VMware vSphere Hypervisor )物理机CPU和核心都不限制,内存最大1TB,虚拟机最大8vSMP,但是你注意了,内存合计32GB,理解深刻些,就是如果你有1台虚拟机是32GB内存,那么你只能虚拟出一台虚拟机。如果1台虚拟机的内存是1GB,你可以虚拟32台

VMWare ESXi 5 的正式文档上相应的说明如下:

跨平台的 Git 客户端

最近将一些工作迁移到了 GitHub, 在 Windows 环境下, 使用 TortoiseGit 作为客户端, 配合 msysgit 后端, 使用还是比较习惯的.

但是上述环境不够"便携"(Portable), 而且仅适用于 Windows, 所以一直在寻找合适的跨平台方案, 经过试用, 觉得 Eclipse-platform + EGit 是一个比较可用的组合.

目前最新版本(4.2.1)的 eclipse-platform 可以到这里下载, platform 下载的文件不到 60M, 相对 eclipse JDT 等安装包小了不少;

EGit 的安装和使用可以参考 Git with Eclipse (EGit) - Tutorial.

关于 thinkbase.net

thinkbase.net 一直是一个技术型的 Wiki/blog 站点, 最初使用 VQWiki, 期间使用过 GoogleCode(遗址), 也尝试基于 GitHub 构建自己的站点(遗址), 不过都没有坚持下来, 目前转移到 Trac 上.

  • 之所以不使用 GoogleCode, 最主要的原因是不习惯其 Wiki 语法, 与 Trac 相比, GoogleCode 在语法上的灵活和丰富程度还是不够的.
  • 基于 GitHub 的 blog 基本上是采用 Jekyll 方案, 比较详细的方式参见 阮一峰:搭建一个免费的,无限流量的Blog----github Pages和Jekyll入门, 考虑到 编写->生成->上传 过程比较繁琐(另外就是没有什么心思去设置 _config.yml 以及模板文件), 而且这个方案对评论功能的支持比较弱, 所以最终也没有使用.

参考: