2007年12月26日星期三

Picasa upload tool

以前在Windows用Picasa的时候,用客户端上传图片到picasaweb很方便,现在发现Linux版本的Picasa客户端没有上传功能。
所以我自己用API写了一个小程序,Java代码70行,支持创建相册、批量上传,使用及其简便。下面是ReadMe:

PicUp version 1.0 Readme

-What does this application do?
-Simple tool for picasa web. It helps you to create albums and upload picture files easily, just in console.

-How to install?
-Take these steps:
step 1)
Download the zip package from this URL
http://code.google.com/p/picasup/
and then extract all into a path whichever you like, for example /home/todwong/workspace/picUp/
step 2)
create an shell script file in $PATH, such as /home/todwong/bin/picup, type these into it:
/home/todwong/workspace/picUp/picup
step 3)
chmod +x /home/todwong/workspace/picUp/picup /home/todwong/bin/picup

-How to use?
cd into your folder with picture files, such as /home/todwong/pic/hangzhou/
execute this shell directly
picup
which refers /home/todwong/bin/picup
Now, input your picasa account info, and then determine whether to create a new album.
If you do, input y, and then it will create it with the title equals the current folder name.
Otherwise, just input Enter, in which case you means there exist the album with the title equals the current folder name already.
After that, the program will upload each jpg file in current folder onto this album, one after another.

-Can I use it in windows?
-Of course, but you have to create .bat files for convenience. Picasa client for windows might be a better choice, if you don't matter about his background process;p

Thanks to
http://code.google.com/apis/picasaweb

2007年12月23日星期日

resize jpeg in console

每次出去照相,回来就要处理很多照片,分批重命名可以在gThumb很方便的完成,但是他的"改变大小"工具一次只能改变一个文件。如果要批量压缩用于上传,则只好使用其他工具,我发现用命令行的convert命令非常快捷~
首先要安装convert,为了判断是否已经安装,可以测试convert --help
如果提示未找到该命令,则按照提示
sudo apt-get install ImageMagic
如果看到了好几屏的帮助信息,就表明已经安装了

然后进入你的图片的目录,随便找一个文件测试,比如叫test.jpg,执行
convert -resize 30% -quality 85% test.jpg test2.jpg
则转换好的文件命名为test2.jpg,去看看效果如何
可以调整参数resize和quality,感觉resize和文件大小呈2次方关系,quality和文件大小呈线性关系,没有严格统计过,因为后者应该和图片内容有关,resize后的尺寸到1024x768就够了,再大就马赛克了,除非你的相机真的很厉害(感觉现在傻瓜数码相机就是像素高,镜头差感光器也差,所以2MB的照片放大到100%根本没法看……)。quality不要设的太低,因为它和视觉体验不是线性关系,就是说,当你把quality从90%调成80%时,感觉图片没糙多少,但是从80%调成70%时,就觉得图片明显变糙了。(谁来做个视觉心理学实验?)


最后就是批量转换,最爽的时刻到了。参考http://www.ibm.com/developerworks/cn/linux/l-graf/
mkdir resized
for img in `ls *.jpg`
do
convert -resize 30% -quality 85% $img resized/$img
done
[预告:下一篇将接着这个话题讲述如何利用picasa api编写java桌面程序,上传你的照片文件夹到你的picasa网络相册]

2007年12月21日星期五

Tunet的gtk托盘

为了方便地一键上下线,我给命令行的tunet客户端包装了一个gtk托盘小程序,在ubuntu7.10下测试通过。python代码只有40行。
操作非常简单:左键点击托盘文字切换上下线状态,右键退出托盘小程序。托盘文字显式Off时表示不在线(假设没有运行其他tunet进程),此时点击后上线,托盘文字变为On,此时再点击则下线,文字变回Off。
代码如下:

#!/usr/bin/env python
#usage nohup ./trayTunet.py &
import os
import gtk
import egg.trayicon

class TrayTunet:
   
    def __init__(self):
        self.txt = gtk.Label("Off")
        self.icon = egg.trayicon.TrayIcon("Tray for Tunet")
        self.eventbox = gtk.EventBox()
        self.eventbox.add(self.txt)
    self.eventbox.connect("button-press-event", self.clicked)
        self.icon.add(self.eventbox)
        self.icon.show_all()

    def clicked(self,widget,event):
        if event.button == 1:
            if self.txt.get_text() == "Off":
                self.txt.set_text("On")
                self.getOnline()
            else:
                self.txt.set_text("Off")
                self.getOffline()
        elif event.button == 3:
            os.system("kill " + str (os.getpid()))

    def getOnline(self):
        os.system("/home/todwong/bin/tunet -p /home/todwong/bin/bao-wangyuantao -t o > nul &")

    def getOffline(self):
        os.system("ps -C tunet o pid= | grep -m 1 . | xargs kill")

    def start(self):
        gtk.main()

if __name__ == "__main__":
    tray = TrayTunet()
    tray.start()

2007年12月13日星期四

Ubuntu起步随笔

掐指算来,从小学用DOS6,到后来一路win3.2,95,98,me,xp,2k3,我的操作系统升级换代很多次,但和许多人一样,始终没有脱离M$的圈子。第一次接触Linux,是去年在做Merssenger的时候,合作的需要,服务器是Linux,还要感谢王慧文,很多命令就是当时在实战中他教我的,还要感谢黄驰,他帮我澄清了许多Linux基本的概念。今年夏天在实习的时候,开发机是Linux,接触的更多些,掌握了Web开发所需要的基本操作。不过第一次用Linux做桌面,仅仅是从上周开始。

其实对于很多人来说,用Linux做桌面最大的障碍不是可能命令记不住,而是担心在Windows下干得很顺手的事情变得麻烦。其实真做起来的时候,会发现没有那么麻烦,下面是我这周的一些随笔,记录了我刚刚开始使用Linux的一点经验和心得,当然也走了不少弯路。谨备忘,分享。

起因是我的win2k3装了太多的东西,已经跑不动了,忽然又中了莫名其妙的病毒。于是鼓起勇气决心彻底换掉windows。我用的是Ubuntu7.10, 从自动化FTP上down的。下文假设已经安装好了,而且选择了中文登录。

上网第一
在学校上外网要用某客户端,称为tunet,俗称二校门,Linux版的有二个编译好的不需要安装的可执行文件,tunet和tunetpasswd,后者用来生成登录的用户名密码的密文,存在一个本地文件里,前者用这个文件登录,不用每次输入密码。还有要改一下配置,因为老楼这边不用端口认证。把
/etc/tunetclient/tunet.conf
里的enabledot1x设为0
搞定后准备一个登录批处理,省得每次输入老长的命令。
./bin/tunet -p ./bin/bao-wangyuantao -t o
-t是type的意思,o表示open开放登录

中文输入第二
默认中文输入法是没有的,要自己安装。
在新立得中安装这些:scim-tables-zh,scim-pinyin
然后在支持的语言中选上Chinese。
之后可能需要注销或重启一下。

打开方式第三
RAR
下一个rarlinux-3.7.1,把rar和unrar两个可执行文件复制到/bin下。据说40天过期,我还没想好怎么办。
chm添加程序xChm即可
Firefox多线程下载插件downthemall,超快
IBM智能辞典没有Linux版,推荐用stardict,很强大

开发第四
实习时虽然开发机是Linux,但是通常我是在Windows下code好后ci,然后在dev上update,有点小问题就用vim简单改一下,复杂的就不行了。
jdk我下的jdk-6u3-linux-i586.bin在命令行chmod后运行安装,一路yes。
下载Eclipse的压缩包,和Windows的一样解压缩后就能直接运行了,很方便:)
MySQL的Admin和Browser可以直接添加程序,但是Server要自己装,用下面一句话搞定
sudo apt-get install mysql-server
python解释器默认内置了哈哈,添加程序里还有IDLE。
gcc自带的居然不能用,需要这样
sudo apt-get install build-essential
然后还需要插入安装的光盘

虚机第五
有些事情还得回Windows做,我装了VirtualBox
去官方下载virtualbox_1.5.2-25433_Ubuntu_gutsy_i386.deb
双击运行安装
命令行输入sudo VirtualBox启动

综上,我还是比较菜鸟的。
话说回来,连我这样的菜鸟都能用Ubuntu做桌面,可见Linux普及已经指日可待啦~

2007年12月10日星期一

JavaScript 数组的 uniq 方法

一篇Blog中,realazy提到了这样一个问题:
给Array本地对象增加一个原型方法,它的用途是删除数组条目中重复的条目(可能有多个),返回值是一个包含被删除的重复条目的新数组。

形式化描述:
input
Array(size=N)
output
Array1=Array的无重复保序的子集,
无重复是指,对任意a,b属于Array1,a!=b
保序是指,若a在Array的下标小于b在Array的下标,则a在Array1中的下标也小于b在Array的下标
Array2=Array-Array1,保序
realazy给出了一个新解,思路非常清晰:顺序遍历访问每个元素,如果这个元素的值已经访问过了,则加入Array2,否则加入Array1。判断当前元素的值是否已经访问过所采用的方法是顺序遍历已经访问过的所有元素。
易见该算法复杂度约O(N^2)。

我在他的算法框架下稍微做了一些改进,关键在于遍历过程中如何判断当前元素的值是否已经访问过。在原数组值域为正整数且极差(range=max value-min value)不太大的条件下,可以采用简单的"桶"算法。
准备一个长度为range的boolean数组b,初始化全为false。对于原数组中每个值value,如果b[value]=true,则表明这个值访问过,放入Array2,否则放入Array1同时令b[value]=true。
这显然是O(N)的算法,代价是额外的空间复杂度range,而且要求原数组值域为正整数。
不难推广到值域为整数的情形,事实上只需考察桶号value-min(Array)即可转化为正整数的情形。

为了避免range太大造成的空间的浪费,在"桶"算法基础上改进为散列算法,具体说来是线性同余开散列法。目的是将值域压缩映射到一个可控的小的连续正整数子集中,同时保证不同的原象对应的相同的象的概率要尽可能小,也就是说桶与桶之间要尽量负载均衡。
例如这是一个值域为实数的散列函数:
key=hashFun(value)=Math.floor(value)*37%91
这仍然是O(N)的算法,(显然O(N)是所有uniq算法的复杂度下界),好处是可以控制空间的开销,而且可以适应非整数值域,只需要设计相应的散列函数即可。



下面是桶(bucket)算法的实现:
   var resultArr = [],
       returnArr = [],
       origLen = this.length,
       resultLen;
   var maxv=this[0],minv=this[0];
   for (var i=1; i<origLen; ++i){
       if(this[i]>maxv)maxv=this[i];
       else if(this[i]<minv)minv=this[i];
   }
   var blen=maxv-minv+1;
   var b=new Array(blen);
   for(var i=0;i<blen;++i)b[i]=false;
   for (var i=0; i<origLen; ++i){
       if (b[this[i]-minv]){
           returnArr.push(this[i]);
       } else {
           resultArr.push(this[i]);
           b[this[i]-minv]=true;
       }
   }
   resultLen = resultArr.length;
   this.length = resultLen;
   for (var i=0; i<resultLen; ++i){
       this[i] = resultArr[i];
   }
   return returnArr;
下面是散列(hash)算法的实现
var shuffler = 37
var beta=0.007;
var origLen=this.length
var bucketSize=Math.ceil(origLen*beta);
var hashSet=new Array(bucketSize);
var hashFun = function(value){
var key = (Math.floor(value)*shuffler)%bucketSize;
return key;
}
//init hashSet
for(var i=0;i<bucketSize;i++)hashSet[i]=new Array();
//
var ret=[],self=[];
var key,value;
var bucket,openLen;
var everConflict;
for(var i=0;i<origLen;i++){
value=this[i];
key=hashFun(value);
bucket = hashSet[key];
openLen=bucket.length;//if(openLen>1)return;
everConflict=false;
for(var j=0;j<openLen;j++){
 if(bucket[j]==value){
  ret.push(value);
  everConflict=true;
  break;
 }
}
if(!everConflict){
 bucket.push(value);
 self.push(value);
}
}
   selfLen = self.length;
   this.length = selfLen;
   for (i=0; i<selfLen; ++i){
       this[i] = self[i];
   }
//compute average bucket size
var lens=[],sum=0;
for(var i=0;i<hashSet.length ;++i){lens.push(hashSet[i].length);sum+=hashSet[i].length};
average=sum/hashSet.length;//watch lens,average
   return ret;


用k*10000个0~k*100的随机整数测试计算时间(ms)
k 1 2 3 4 5
realazy 240 693 1399 2301 3807
bucket 55 101 141 219 293
hash 214 411 654 844 1083
测试框架借鉴了http://realazy.org/lab/uniq.html
测试环境Firefox2.0.0.6/Ubuntu7.10/2.66GHzP4/1024MBDDR

2007年12月4日星期二

[笔记]豆瓣校园宣讲会

宣讲会上透露了不少信息,以下是断章取义。

一、概述
远景:帮助每个人发现最适合自己的未知事物。
用户群:中高端,千万人。不包括在网吧用QQ的。
盈利模式:和电子商务(当当、卓越等)分帐。未来要定向投放广告。
前辈:学亚马逊做推荐,现在GR也有推荐。推荐引擎在工业界和学术界都很领先。
核心:阿北,老板,搞物理的,洪强宇,技术,精仪的,王守�,算法,自动化的,搞TSP出身的。
创业精神:对风险的态度显著区别于IBM。
团队:纵向划分,每个人看一个产品,从最后台的SQL到最前台的HTML。scrum.sprint每周迭代。
有钱:不再找风投的话,而且没有意外扩张的话,豆瓣现有的钱还够折腾四五年。
有人:20人精英团队,技术7,算法3,运营5,产品3,营销2。其中6人来自清华。年龄平均27.2,中位数25。明年要翻番到40人。

二、技术
技术:前瞻性,第一个版本零访问的时候就能支持百万级了。
硬件:15台服务器全部自己攒,用指环王人物命名,数据挖掘有专用服务器,5台支撑起5M的PV
开发:python=很算法,为了性能一些挖掘算法用C实现,分布式:Web服务,缓存memcache,DB=mysql,存储。容器=lighttpd。搜索引擎=xapian。应用框架=quixote。
后台:大量脚本,monitor和spider。

三、算法
海量数据:十万电影,百万书,千万RSS,亿URL。
实验场:数据挖掘应用于社会化过滤器,协同过滤,聚类,关联规则,机器学习,文本挖掘,教科书上见得到的都有实验,此外最强的一点是利用社会网络进行挖掘,效果显著。
数据挖掘效果评估:不用学术界常用的指标hit rate而是用户反馈。
algorithm should facilitate rather than replace social processes

四、杂项
社会化:豆瓣的社会化网络是实用主义的,不构滥交友,也不复制真实关系,而是按兴趣把人们聚在一起。
开放:即将开放更多API,是Atom格式。暂时不打算开放数据,因为现在只有五千万,不够多?和netflix还比不了。

五、进去之后什么样儿
工作:每周40个小时。一三五要到公司,上午10点到下午6点。其他时间可以在家上班。要上班是为了保证足够的沟通时间。
讨论会:叫做Hall of fire,也是典出指环王。
腐败:每周有一笔钱必须一起糟掉。

六、怎么进
加入豆瓣意味着:高风险高回报机会。
待遇:比不过Google,但是相当有竞争力。(都说自己的待遇有竞争力)
简历:非常看重对open sourse的贡献。
面试:行业证书起副作用,看能力。问你以前做的事过程中,表现出你的聪明之处。问你一道编程题,考你逻辑思维能力。