bpython
之前介绍过IPython,这个bpython有些类似,也是一个交互的python shell,他的强项在于动态的帮助提示,用下来感觉某些地方更好用,在有时不记得一些python函数时,会很方便,下面是在运行时的截图:
我在Ubuntu下安装bpython非常方便,因此没有在Windows下试用。要是有个IDE能做到bpython的功能,那该多好…
之前介绍过IPython,这个bpython有些类似,也是一个交互的python shell,他的强项在于动态的帮助提示,用下来感觉某些地方更好用,在有时不记得一些python函数时,会很方便,下面是在运行时的截图:
我在Ubuntu下安装bpython非常方便,因此没有在Windows下试用。要是有个IDE能做到bpython的功能,那该多好…
很意外,Leopard(OSX 10.5)下居然预装了Ruby 1.8.6,虽然版本比较老,足以显示OSX对开发人员的关照,一顿捣鼓下,安装了Rails (v3.1.1) ,结果很完美,过程很曲折,记录一下:
RVM
ruby的包管理器叫做gem,有些类似Linux的apt-get,leopard下已经预装gem,不过版本号实在不敢恭维: 1.0.1,一个让人不太信任的数字,所以第一步就是刷新gem,不过对于系统已经安装的ruby和gem,替换不太好,幸好有rvm这个极好的工具,可以让你在个人的目录下管理ruby和gems。
安装的方法参见rvm的网站,基本上就是下面的一条bash命令。
bash < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer )
上面是安装了rvm到你的个人目录下,要使用rvm,还需要设置bash的初始化文件,同样的,一条命令:
echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm" # Load RVM function' >> ~/.bash_profile
别忘了重新登录,以生效上面的profile。
Ruby
有了rvm,可以很方便的安装ruby了,如下:
rvm install 1.9.2
将1.9.2设置为缺省的ruby:
rvm use 1.9.2 --default
Rails
有了ruby和gem,就可以安装rails了,理论上直接 gem install rails就可以了,不过因为一个你能懂的原因,我发现先装好socksify_ruby这个gem要好很多,所以:
socksify_ruby localhost 8888 `which gem` install rails
注,上面的引号是反引号,不是单引号,
注2,localhost 8888 你也应该懂的。
Sqlite3
本来装好了rails,就可以开工了,不过在OSX 10.5下,下面这个特殊的步骤需要先做一下,以解决sqlite版本过老的问题,先安装homebrew这个极好的OSX包管理器:
/usr/bin/ruby -e "$(curl -fsSL https://raw.github.com/gist/323731)"
然后刷新sqlite
brew install sqlite
开工
下面就可以使用真正开工了,这样:
rails new test_app
为了到达这一步,上面的步骤我反反复复运行了不下10次,走了N次的弯路,总结在此,望对其他有需要的人有些帮助。
注:在我接触过的开源项目中,rails是给我留下了深刻印象的一个,原因不详述,只是推荐一下,值得一看。
家中的HTPC需要一个遥控器,我没有无线鼠(实际上我也不觉得无线鼠标在沙发上会好用),所以需要一个软件解决方案。RemoteDroid就是这样一款软件,可以装在Android设备中,正好家里有装电信宽带时送的一款Android手机,装上客户端和服务器端之后,遥控就没有问题了。
RemoteDroid只提供了Android的客户端,而没有iPhone,Symbian,Windows等客户端,虽然我用不上,但我还是在想为什么需要装一个客户端?如果使用浏览器控制,岂不是非常美妙,尤其是现在的智能手机浏览器大多基于Webkit,应该“比较容易”开发基于浏览器的客户端。
服务器端
要做这个事情,必须要基于Http开发一个服务器端软件,这个并不难,Java、Python都可以很好的完成任务, 我选择了Java,除了更好的跨平台的特性之外,Java在做这个东西上有两个优势:
很快,我做好了键盘和鼠标控制的部分,并打包为一个jar,在Windows和Mac OSX上都实验了一下,通过http输入一些URL已经可以控制键盘和鼠标了,很棒。
客户端
要方便易用的遥控客厅的PC,自然不能通过输入长长的URL来干这件事情,需要通过Javascript来开发一点可以在浏览器中运行的“客户端”,象一个真正的鼠标那样去操作。我在这里花了不少时间,因为手机上的浏览器并不象我想象的那么容易搞定。我找了JQuery Mobile来做,界面部分,倒不困难(因为也不需要复杂的界面)。
问题在于触摸事件,我的设想是用浏览器发出的触摸事件来触发到服务器端的鼠标移动,遗憾的是,在我实验用的Android手机上,这个“手指滑动”的事件总是很不配合,总是有各种各样的问题。要么不发出事件,要么就是滑动手指超出一定范围之后就不发事件了,我换了多个方法,也没有彻底解决这个问题,只好作罢。
因为没有搞定浏览器端,我的服务器端程序就成了摆设了,让我心有不甘,只得做一个Android客户端吧,捣鼓了几天,写了一个Android客户端,因为没有达到我的预期,这个也就草草收场了。
最终的结果是:我开发了一个基于Http的服务器端程序,却和一个Android专有客户端搭配着,完成了遥控我的客厅PC的事情,真是有点…
现在的计算机CPU已经足够强劲,以至于大部分时间,即便你在工作、上网、看碟,CPU也是闲着的,这常让我想把闲置的CPU发挥起来,最近得到了一个新任务–去某某商城抓取打折信息,我发现这个倒是挺适合闲置的CPU的。
任务分析
我曾经写过这个命令行的程序,可以统计商城里的商品信息,为了这个新任务,我改写了程序,让它可以抓取打折信息,并排序,所有这些都通过命令行来完成,这个程序在执行的时候非常花时间,但不占用CPU(这是很多网络分析程序的特点),我曾经优化过这个程序,让它可以使用多线程来抓取数据,不过即便是用5~10个线程,完整的抓取商城的全部商品,大概也需要两个小时的时间,所以非常适合用闲置的CPU来做。
发送邮件
首先,我想到的方法是用操作系统的计划任务来执行我的程序,Linux下用cron,可这次的任务要在Windows下完成,所以需要使用Windows的计划任务,在计划执行的时候,最好是把程序的输出用email发送出来,这样才方便以后看结果,所以需要一个可以在命令行下发送邮件的程序,我找到了sendemail,因为他支持tls,所以就可以使用gmail的smtp来发送邮件了。下面是sendemail使用gmail发送邮件的命令:
sendemail -f xxx@gmail.com -t yyy@gmail.com -s smtp.gmail.com -o tls -xu xxx@gmail.com -xp xxxpassword -u subject -m body
计划任务
接下来,创建这个计划任务,我最初的方法是用管道,将抓取程序的输出送给sendemail(sendemail不加-m参数,它会自动从管道中读取邮件正文),象这样:
top360buy.py -p -s -n 50 | sendemail ...
可是这样的命令在命令行可以执行,但在计划任务中却不能执行,会直接退出。我不知道是什么原因,但google说,这个可能是计划任务对于复杂命令行支持的bug(未经证实),懒得和微软纠缠,直接将上面的命令写入一个bat,在计划任务中指定这个bat,搞定。
隐藏运行
现在可以了,每到指定的时间,或者PC空闲了(取决于计划任务的设置),就会自动跑这个打折抓取器并发邮件给我,很不错。但随即发现,这个任务运行时,会弹出一个命令行窗口,直到运行结束,这显然有些不和谐,况且这个窗口要存在两个小时,所以要找到一个隐藏运行任务的方法。
幸运的是,Windows的计划任务提供了一个简单的方法,达到这个目的,就是更改计划的“执行用户”,只要计划任务以另一个用户身份运行,就可以完美隐藏了,我把这个用户设为SYSTEM,确定,任务就完美了。
最终的效果是,这台PC只要开机,就会在空闲时去抓取打折信息,无声无息,然后将抓到的商品信息发送给我。
很早以前想过这个问题,为什么那些基于网络的client程序启动时都要输入服务器地址,这对于有些用户来说实在有些“多余”,且容易出错,比如我在家里开了一个ftp,我自然希望家里的ftp client启动时就可以自动连接到服务器了,省得我去找服务器的ip。
其实在Mac的世界里,早就实现了这个,基于dns-sd,并且非常广泛的使用了,Windows和Linux现在也都支持,OSX的几乎每一个服务都支持自动发现,比如在OSX命令行输入:
dns-sd -B _rfb._tcp
就可以自动找到局域网内开了远程桌面服务(OSX的一个服务)的计算机了,后面的_rfb._tcp是服务类型和协议类型。
显然,我想到如何给自己的client-server程序加上自动发现,这样看起来会很不错,找寻了一番,发现了jmDNS,纯java实现的dns-sd,使用起来非常方便,下面示例:
服务器端
服务器端自然需要注册一个服务,在启动时这么来做:
jmDNS = JmDNS.create(); jmServiceInfo = ServiceInfo.create("_nuservice._tcp.local.", "NuWebService", 8080, ""); jmDNS.registerService(jmServiceInfo);
上面的ServiceInfo就是服务的参数了,依次是类型,服务名,端口号和 一段描述文本,类型必须是一个类型名加协议的格式。
客户端
客户端要发现这个服务,需要使用服务类型来查找:
JmDNS jmDNS = JmDNS.create(); ServiceInfo si[] = jmDNS.list("_nuservice._tcp.local."); if (si.length > 0) System.out.println("Service 0:" + si[0].getName() + "--" + si[0].getPort() + "--" + si[0].getNiceTextString() );
这样就可以发现服务器了,因为可能有多个,所以list是返回了一个数组,上面简化的代码输出了第一个服务器的信息,在si中可以取到地址、端口、类型、服务名等信息,后面就很好办了。
也可以用OSX的dns-sd命令来发现服务器:
dns-sd -B _nuservice._tcp
其他
上面的代码只是最重要的部分,一些回收的工作,比如 jmDNS.close(),没有列出。所有的代码只需要一个jmdns.jar就可以工作了。
因为家里在用峰谷电,要考虑买一个可以定时开关的插座,我们家有三个地方用到:
这些定时功能,有些电器已经做到了,比如叫做“预约”什么的,但是我们家的热水器、电炖锅等都没有,研究了一下,后来买了这个东西:

这个东东很好的满足了定时开关的需求,定时设置很方便,不过他的那个万用插是不能插16A插头的,这个我也是买了之后才意识到,无奈,为了接热水器,又买了一个10A转16A的转换插座。
为了搞清楚这几个概念,研究了一下:
以上两个概念均有例外:
就是这样,推而广之: Python也是有32位和64位之分,但第三方的很多Python库使用了非“纯”Python的实现(比如用C来写扩展),那么在用64位Python时,可能某些扩展会找不到64位版本(Java也有这样的问题,但比Python少很多),所以Python的话,还是建议使用32位的(除非要用到4G内存)。
PS很久没有研习了,最近因为用到,学习了CS2后添加的一个重要的新功能 – smart objects(这个名字起的很模糊),还是比较有用的。
动态的滤镜效果
老版本中,做滤镜时,图层的内容就直接被修改了,没有后悔药可吃,有了smart objects,先把图层转换为smart objects,然后再做滤镜时,就会发现和Adjustment Layer类似,滤镜也变成一个附加的“层”,可以随时调整参数或是取消了。
实际的操作很简单,先用图层的右键菜单将图层转换为smart objects,然后直接使用滤镜就可以了,下面是使用了两个滤镜之后,图层上的标示(Layer 0的缩略图的右下角的那个图标,就表示这个图层是一个smart objects):

对象和引用
上面的动态滤镜让人很难理解为什么叫做“smart object”,其实真正帮助理解这个名字的功能,是smart objects可以被复制,但仅仅是一个引用,以前版本的PS,拷贝一个图层,新的图层就可以随便修改而不影响老的图层,而smart objects图层拷贝之后,每次修改,所有的“拷贝”都会一起变化,这对于用PS做用户界面非常有用,因为很多重复的元素,比如按钮什么的,一次修改,处处生效。
这两个功能让我大悦,我的PS7也该升级了…
断断续续用Swing做了几个程序,畏惧慢慢转换为喜爱了,Swing的学习曲线很平坦,API很“现代”,和我接触过GUI库相比,大约和wxWidgets是处于类似的层次,远比Gtk,MFC等要清晰。
JRE内置Swing是一个巨大的优势,可以写很“小巧”和容易发布的GUI程序,在这点Python非常遗憾,直到现在也没有一个好用的GUI库内置(Tk不能算),作为通用跨平台语言,真不知道为什么。。很多程序员在pyGtk,pyQt,wxPython间犹豫,浪费大量时间,不论最终用那个,写一个hello world,可能就得几十兆的安装包了,真是情何以堪啊。
语言内置GUI库的好处很多,比如IDE就会有很更好的支持,现代的Java IDE,Eclipse和Netbeans对Swing都有极好的支持,Netbeans是内置的GUI Builder,一直都口碑非常好。Eclipse可以使用Google开放的WindowBuilder插件(Google收购来后,给广大程序员的福利),WindowBuilder是个技术上很有特点的GUI构造器,因为它不需要专属格式保存界面设计,它直接从源代码做逆向分析,这个真是很牛啊。我用过几个项目下来,确实不错,除了动态构建的界面,大部分Swing界面,WindowBuilder可以非常准确的逆向出来。
Look&feel是GUI的表现出的特性,就是界面的Theme,早期的Swing,这方面很差,做出的界面在每个系统下感觉都有些格格不入,Java6之后,Swing支持了本地Look&feel,看起来就好很多,不过不知道是不是考虑兼容,缺省的Look&feel居然没有变,还是难看的金属风格。慢慢的,在每个版本中进化中,Java逐渐加入一些好看的Look&feel,下面这个是在Java6 Update10之后出现的,我觉得很不错:

Layout是Gui库的另一个很重要的方面,就是在窗口中如何排放控件以及处理窗口的缩放,早期的GUI库比如MFC都是用坐标来排放控件,这给程序员带来非常繁杂的工作量,且窗口不能缩放,而现在的GUI库已经很少直接使用坐标来定位了,都是通过某种Layout来自动处理控件的位置关系和缩放,Swing的Layout很多,我喜欢其中的GridBagLayout,兼具了灵活性和简易性。MigLayout是另一个口碑非常好,且强大的Layout,只可惜还不在Java标准之中。
让我坚守Firefox的两个理由是 稳定及扩展。不过我随时都在使用chrome,看看是否在这两个方面达到firefox的高度。现在来看,由于设计原则的不同,chrome的扩展很值得注意。
chrome的扩展看起来更像是应用程序,它似乎不能对chrome本身做太多修改,而只是一个在独立进程中跑的程序,chrome中内嵌有一个进程管理器,看看下图:

而firefox的扩展才应该叫扩展,它几乎毫无限制的修改firefox本身的任何地方,这样的设计差异导致了:
所以,看起来chrome更像是一个平台(想象下java),上面缺省跑了一个应用叫做浏览器,你可以通过chrome扩展安装额外的应用,如果把chrome当成一个唯一的应用,所有其他应用都跑在chrome下,那就是chrome os了,准确的说,应该是chrome shell。