#!/usr/bin/env python
# Author: xieyanbo@gmail.com
# dump_google_apps_mail_groups.py
# export mail groups and group members from Google Apps service
import gdata.apps.groups.service
def print_all_members(email, domain, password):
group_service = gdata.apps.groups.service.GroupsService(email=email,
domain=domain, password=password)
group_service.ProgrammaticLogin()
def print_members(group_id):
for user in group_service.RetrieveAllMembers(group_id):
print user['memberId']
def shrink(str, max=20):
if not str:
return ''
str = str.replace('\n', ' ').strip().decode('utf8')
if len(str) > max:
short = str[:max-3] + '...'
else:
short = str
return str.encode('utf8')
def print_groups(groups):
for group in groups:
gid = group['groupId']
print '%s, %s, %s' % (gid, group['groupName'],
shrink(group['description']))
print '='*60
print_members(gid)
groups = group_service.RetrieveAllGroups()
print_groups(groups)
def main():
from optparse import OptionParser
parser = OptionParser()
parser.add_option('-e', '--email')
parser.add_option('-d', '--domain')
parser.add_option('-p', '--password')
options, args = parser.parse_args()
if not options.email:
parser.error('need email address to login')
if not options.domain:
parser.error('need domain to login')
if not options.password:
import getpass
password = getpass.getpass('Password: ')
else:
password = options.password or login
print_all_members(options.email, options.domain, password)
if __name__ == '__main__':
main()
2010-10-27
导出Google Apps里所有的用户组和组员
Google Apps的管理功能很不错,但用户组多了不好管理,时常要拿出来晒晒,调整一下结构。这就经常需要把所有组和组员列出来,幸亏Google提供了API,懒人的办法就是用脚本搞定。下面是python示例,输出比较简单。知道了如何做,你可以自己改成输出csv或者任何其他格式,都会容易。多说无益,上代码。
2010-07-07
在Gentoo里调试新软件包
最近又开始研究web测试的技术,迷上了西门子开发的robot framework。不过服务器用的Gentoo上还没有这东西,只好自力更生。所以先记录一下给Gentoo添加新软件包的过程,下次也好照抄,以后再说robot framework有多好。
Gentoo的包管理器叫做Portage,描述文件叫Portfile。现在的portage很讲究目录结构,就是Gentoo里的PORTDIR structure,所谓category。robot framework是用python开发的,照例是在dev-python下的某个目录中。没想到的是,现在ebuild对目录的检查很严格,即使在调试时安装本地的portfile也要遵循该结构:
然后利用底层的ebuild包管理命令,对本地包生成数字摘要、测试安装和部署:
digest是最近新增加的指令?有这个命令省事多了,调试起来很happy。
调试过程需要反复修改,得删除已经用qmerge安装到系统目录中的文件,以及portfile的缓存:
把dev-python/robotframework和dev-python/robotframework-seleniumlibrary向Gentoo提交了,不知道审核要多久。
完。
Gentoo的包管理器叫做Portage,描述文件叫Portfile。现在的portage很讲究目录结构,就是Gentoo里的PORTDIR structure,所谓category。robot framework是用python开发的,照例是在dev-python下的某个目录中。没想到的是,现在ebuild对目录的检查很严格,即使在调试时安装本地的portfile也要遵循该结构:
mkdir -p dev-python/robotframework
mv robotframework-2.5.ebuild dev-python/robotframework/
cd dev-python/robotframework然后利用底层的ebuild包管理命令,对本地包生成数字摘要、测试安装和部署:
sudo ebuild robotframework-2.5.ebuild digest
sudo ebuild robotframework-2.5.ebuild install
sudo ebuild robotframework-2.5.ebuild qmergedigest是最近新增加的指令?有这个命令省事多了,调试起来很happy。
调试过程需要反复修改,得删除已经用qmerge安装到系统目录中的文件,以及portfile的缓存:
sudo emerge -C robotframework-2.5
sudo rm -rf /var/tmp/portage/dev-python/robotframework-2.5/把dev-python/robotframework和dev-python/robotframework-seleniumlibrary向Gentoo提交了,不知道审核要多久。
完。
2009-04-26
请,给点提示吧,bitten
一直在用bitten做集成测试,效果挺好,现在天天离不了它。不过最近被它搞的很郁闷,因为bitten-slave吐出一行神秘的错误信息:
起因是因为最近升级了bitten,顺便想把以前的单个进程拆成多个,加快一下bitten的执行速度。人家说,一个和尚有水吃,两个和尚抬水吃,三个和尚没水吃,没想到软件也是这样。两个slave一块跑起来,就有了问题:有时这个出错,有时那个出错,提示都是神秘的403。观察了一下,出现错误的时候,都是某slave A先执行,B稍后也开始执行,然后A再次向服务器POST数据就会出错。猜测可能用户之间有冲突,试过了几种方式,使用各自独立的用户名,在不同目录执行,在不同机器执行,但问题依旧。今天费了些力气,把bitten的代码跟踪了半天,发现程序调用了这个函数:
幸亏代码里有注释,这才恍然大悟,原来是timeout参数在作怪。进入trac管理界面,把timeout从10秒调高到500秒,总算解决了问题。
实际上,在bitten描述客户端协议的文档中,已经指出了这一问题:
但由于未明的原因,bitten的实现用403代替了404、409,并且没有给出进一步的提示信息。要是bitten-slave能打印一条附加信息,告诉我403的原因可能跟timeout设置有关系,那该多好呀。
这个故事告诉我们,别嫌提示信息废话太多,能多写一点是一点,不定什么时候它就会节省自己和别人的若干时间。折腾了三天以后,我现在太喜欢话唠的软件啦。
[DEBUG ] Sending POST request to 'https://mytrac.com/build/5632/steps/'
[WARNING ] Server returned error 403: Forbidden
[ERROR ] HTTP Error 403: Forbidden
起因是因为最近升级了bitten,顺便想把以前的单个进程拆成多个,加快一下bitten的执行速度。人家说,一个和尚有水吃,两个和尚抬水吃,三个和尚没水吃,没想到软件也是这样。两个slave一块跑起来,就有了问题:有时这个出错,有时那个出错,提示都是神秘的403。观察了一下,出现错误的时候,都是某slave A先执行,B稍后也开始执行,然后A再次向服务器POST数据就会出错。猜测可能用户之间有冲突,试过了几种方式,使用各自独立的用户名,在不同目录执行,在不同机器执行,但问题依旧。今天费了些力气,把bitten的代码跟踪了半天,发现程序调用了这个函数:
def reset_orphaned_builds(self):
"""Reset all in-progress builds to ``PENDING`` state if they've been
running so long that the configured timeout has been reached.
This is used to cleanup after slaves that have unexpectedly cancelled
a build without notifying the master, or are for some other reason not
reporting back status updates.
"""
幸亏代码里有注释,这才恍然大悟,原来是timeout参数在作怪。进入trac管理界面,把timeout从10秒调高到500秒,总算解决了问题。
实际上,在bitten描述客户端协议的文档中,已经指出了这一问题:
To handle the case of build slaves going away at some point between having created a build and completing the build, the build master should have a configurable timeout. All in-progress builds would be checked against this timeout; if there has been no activity on the build for an amount of time exceeding the timeout, the master should cancel the build, resetting it the PENDING state. If a slave later does decide to come back to life and post results, it would get 404 (Not Found) or 409 (Conflict) errors, and should cancel the build on its side, too.
但由于未明的原因,bitten的实现用403代替了404、409,并且没有给出进一步的提示信息。要是bitten-slave能打印一条附加信息,告诉我403的原因可能跟timeout设置有关系,那该多好呀。
这个故事告诉我们,别嫌提示信息废话太多,能多写一点是一点,不定什么时候它就会节省自己和别人的若干时间。折腾了三天以后,我现在太喜欢话唠的软件啦。
2007-11-30
用于django中的缓存decorator
myproject/decorators.py代码:
使用范例1,简单的cache key:
使用范例2,cache key需要根据调用参数来决定:
使用范例3,需要只对直接调用者做缓存,递归的调用不需要,那么把要递归函数独立出来:
使用范例4,返回结果中部分需要做缓存的,首先把要缓存的部分extract出来,然后对其应用缓存机制:
只能用于静态数据的缓存,如果需要对connection.cursor等对象进行缓存,那需要函数本身做更多的处理,不是这个decorator要解决的问题。from django.core.cache import cache
def cached(cache_key='', timeout_seconds=1800):
def _cached(func):
def do_cache(*args, **kws):
if isinstance(cache_key, str):
key = cache_key % locals()
elif callable(cache_key):
key = cache_key(*args, **kws)
data = cache.get(key)
if data: return data
data = func(*args, **kws)
cache.set(key, data, timeout_seconds)
return data
return do_cache
return _cached
使用范例1,简单的cache key:
from myproject.decorators import cached
class MenuItem(models.Model):
@classmethod
@cached('menu_root')
def get_root(self):
return MenuItem.objects.get(pk=1)
使用范例2,cache key需要根据调用参数来决定:
@cached(lambda u: 'user_privileges_%s' % u.username, 3600)
def get_user_privileges(user):
#...
使用范例3,需要只对直接调用者做缓存,递归的调用不需要,那么把要递归函数独立出来:
class MenuItem(models.Model):
@cached(lambda s,u: 'user_menu_%s_%s' % (u.username, s.id), 3600)
def permit_menu_items(self, user):
return self._permit_menu_items(user)
def _permit_menu_items(self, user):
items = []
for mi in self.children():
items += [n for n in mi._permit_menu_items(user)]
return items
使用范例4,返回结果中部分需要做缓存的,首先把要缓存的部分extract出来,然后对其应用缓存机制:
class Report:
def get_summary(self, day, path='', sort='path', type='daily'):
data = self._get_summary(day, path, type)
# sort ...
return data
@cached(lambda s,d,p,t:'summary_%s_%s_%s'%(d,p,t), 3600*24)
def _get_summary(self, day, path='', type='daily'):
#...
2007-11-16
人们研究android的热情高涨
短短一天时间,又有很多新情况发生。
首先,有人测试了汉字的显示,发现可以支持。我也在模拟器里试了一下,确实很容易。系统内带了几种字体,其中有一款支持CJK字符。
其次,有人成功编译了c版本的hello world,并执行成功。使用的是arm的编译器。而且还编译了全功能的busybox,可以安装到模拟器的系统中。
另外,已经有人成功编译linux放入android模拟器中运行。
邮件列表里很多人都在打听、讨论能不能用C/C++/Python/Ruby之类的语言代替java来开发。今天去jython的项目主页看了看,惊奇的发现项目复苏了,jython 2.2已经正式发布。期待高手把jython打包集成进android吧。
首先,有人测试了汉字的显示,发现可以支持。我也在模拟器里试了一下,确实很容易。系统内带了几种字体,其中有一款支持CJK字符。
其次,有人成功编译了c版本的hello world,并执行成功。使用的是arm的编译器。而且还编译了全功能的busybox,可以安装到模拟器的系统中。
另外,已经有人成功编译linux放入android模拟器中运行。
邮件列表里很多人都在打听、讨论能不能用C/C++/Python/Ruby之类的语言代替java来开发。今天去jython的项目主页看了看,惊奇的发现项目复苏了,jython 2.2已经正式发布。期待高手把jython打包集成进android吧。
2007-11-15
Django+Cheetah
最近在用Django做东西,考虑到现在的流行程度,用Django在稳定性、bug修正速度、参考资料等方面很有优势。但它的模板系统很被一些人诟病,很多用python开发者第一次使用Django都会对它发点牢骚。Python语言的魅力之一就是它的开发,甚至对象实例在运行中都可以随时被改变。但Django因为一些考虑,人为的限制了模板系统的功能,不允许它过于强大。作为一种设计思想,增加限制可以简化问题的复杂程度、提高效率和代码安全性等等,好处不少。但我们是Python程序员,不受拘束、流畅而连贯的书写代码是我们的一贯风格(或说是追求目标),反正我可不愿被当孩子一样限制不许做这、不许做那。用最快的速度,写出糟糕但是能运行的代码,也是程序员应该争取的一个权利--有了可以跑的代码,才能有生存的机会,才能有后续的优化。所以我要寻找一种Django模板的替换方案。
从编写者的舒适角度来看,zpt等类似php的语法写起来感觉都恩罗唆,逻辑之外要码的累赘字符太多了,不够爽快。类似webpy、Cheetah的模板用起来更简单,而且有着类似python的语法风格,个人比较喜欢。据测试,Cheetah的速度也非常快,历史又很悠久,社区活跃,使用起来基本没有后顾之忧。所以我选择Cheetah。参考了Eric Florenzano的文章,在Django中使用Cheetah非常简单。首先要在settings.py中配置模板目录:
然后编写一个使用Cheetah模板的render_to_response函数,用来代替Django自带的:
我是把上面这段代码放在myproject/shortcuts.py文件中。使用起来是这样子:
从编写者的舒适角度来看,zpt等类似php的语法写起来感觉都恩罗唆,逻辑之外要码的累赘字符太多了,不够爽快。类似webpy、Cheetah的模板用起来更简单,而且有着类似python的语法风格,个人比较喜欢。据测试,Cheetah的速度也非常快,历史又很悠久,社区活跃,使用起来基本没有后顾之忧。所以我选择Cheetah。参考了Eric Florenzano的文章,在Django中使用Cheetah非常简单。首先要在settings.py中配置模板目录:
TEMPLATE_DIRS = (
'/path/to/myproject/templates',
)然后编写一个使用Cheetah模板的render_to_response函数,用来代替Django自带的:
import os.path
from Cheetah.Template import Template
from django.conf import settings
from django.http import HttpResponse
def render_to_response(template_name, context=None, **kwargs):
for template_dir in settings.TEMPLATE_DIRS:
path = os.path.join(template_dir, template_name)
if os.path.exists(path):
template = Template(file = path, searchList = (context,))
return HttpResponse(unicode(str(template), 'utf-8'), **kwargs)
raise ValueError, 'Could not find template for %s' % template_name
我是把上面这段代码放在myproject/shortcuts.py文件中。使用起来是这样子:
from myproject.shortcuts import render_to_response
def index(request):
return render_to_response('index.tmpl', {'title': 'index')
Dell 640m的双显示器配置
参考了一下Ubuntu论坛里一个帖子,配置好了双显示器,也算是把多出来的一个显示器利用上了。这里是xorg.conf的后半部分:
Xinerama模式非常好用,笔记本屏幕的和外接的DELL LCD显示器都可以打到最大分辨率;如果按ctrl_alt_"num +"或者ctrl_alt_"num 1",还可以即时切换鼠标指针所在屏幕的分辨率,在外接投影仪时很方便。让我很纳闷的是,配置里“Screen "Screen[0]"”这一句必须写在screen[1]的后面,不知道是什么原因。
Section "Device"
BoardName "945 GM"
BusID "0:2:0"
Driver "i810"
Identifier "Device[1]"
Option "MonitorLayout" "CRT,LFP"
Screen 1
VendorName "Intel"
EndSection
Section "Device"
BoardName "945 GM"
BusID "0:2:0"
Driver "i810"
Identifier "Device[0]"
Screen 0
VendorName "Intel"
EndSection
Section "Monitor"
DisplaySize 340 270
Identifier "Monitor[0]"
ModelName "DELL 1708FP"
VendorName "DELL"
Option "DPMS"
HorizSync 31-80
VertRefresh 56-75
EndSection
Section "Monitor"
DisplaySize 305 230
Identifier "Monitor[1]"
ModelName "DELL 1280X800 LAPTOP"
VendorName "DELL"
Option "DPMS"
HorizSync 30-67
VertRefresh 30-60
EndSection
Section "Screen"
Device "Device[0]"
Identifier "Screen[0]"
Monitor "Monitor[0]"
DefaultDepth 24
SubSection "Display"
Modes "1280x1024" "1152x864" "1024x768" "800x600" "720x400" "640x480"
EndSubSection
EndSection
Section "Screen"
Device "Device[1]"
Identifier "Screen[1]"
Monitor "Monitor[1]"
DefaultDepth 24
SubSection "Display"
Modes "1280x800" "1024x768" "800x600" "640x480"
EndSubSection
EndSection
Section "ServerLayout"
Identifier "Default Layout"
InputDevice "Generic Keyboard"
InputDevice "Configured Mouse"
Option "Clone" "off"
Option "Xinerama" "on"
Screen "Screen[1]" leftof "Screen[0]"
Screen "Screen[0]"
InputDevice "Synaptics Touchpad"
InputDevice "stylus" "SendCoreEvents"
InputDevice "cursor" "SendCoreEvents"
InputDevice "eraser" "SendCoreEvents"
EndSection
Section "DRI"
Mode 0666
EndSection
Xinerama模式非常好用,笔记本屏幕的和外接的DELL LCD显示器都可以打到最大分辨率;如果按ctrl_alt_"num +"或者ctrl_alt_"num 1",还可以即时切换鼠标指针所在屏幕的分辨率,在外接投影仪时很方便。让我很纳闷的是,配置里“Screen "Screen[0]"”这一句必须写在screen[1]的后面,不知道是什么原因。
2007-11-14
android真是热火朝天呀
才一天,android的google group里就600多主题了。可惜blogsearch.google.com里还现在搜不到任何andriod主题的blog文章,但我已经四处看到不少文章了。我也下载了一个sdk,用起来很不错。模拟器是基于qemu的,速度很快。不过浏览豆瓣会有文字重叠或者被压缩成条的问题,跟豆瓣的css和 layout table有很大关系,看来要改善在手机的webkit浏览器上的效果,豆瓣还要做很多努力。
google groups里有人在问,能不能用python语言来做开发。但从架构来看,官方会提供的应该只有java。所以有人建议用jython来做,一样能访问所有的api,这个主意倒是不错,但jython项目现在还活跃吗?用五六年前的python语法和类库来开发程序,还是让我死了好啦。
不知道有没有提供像XIM之类的输入法api,但是既然和中国电信、日本docomo这些公司合作,应该会有人在做CJK的输入法吧?可是对他们的开发出来东西的质量表示怀疑,各个智能手机平台上好用的中文输入法大多是个人开发的,这个功能需要好的用户体验才能,这些大公司往往欠缺的就是替用户着想的能力或说是动力。
google groups里有人在问,能不能用python语言来做开发。但从架构来看,官方会提供的应该只有java。所以有人建议用jython来做,一样能访问所有的api,这个主意倒是不错,但jython项目现在还活跃吗?用五六年前的python语法和类库来开发程序,还是让我死了好啦。
不知道有没有提供像XIM之类的输入法api,但是既然和中国电信、日本docomo这些公司合作,应该会有人在做CJK的输入法吧?可是对他们的开发出来东西的质量表示怀疑,各个智能手机平台上好用的中文输入法大多是个人开发的,这个功能需要好的用户体验才能,这些大公司往往欠缺的就是替用户着想的能力或说是动力。
2007-10-28
让程序只能启动一份
有时写的程序因为资源等等原因,应该只启动一份。利用指定的文件锁,可以实现这样的功能。
再附上一份perl的代码:
顺便再抱怨两句,perl5补丁摞补丁的语法很怪异,异常处理机制竟然要用if...unless,类的写法也搞得跟写dll一样。不得不说,perl的语法离现代语言太远了。一个优美的语言可以提高开发效率,期待一下perl6最终出来的样子。
import os
import fcntl
import errno
def lock_file(filename):
fd = os.open(filename, os.O_CREAT | os.O_WRONLY, 0666)
try:
fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
return True
except IOError, e:
if e.errno in (errno.EACCES, errno.EAGAIN):
return False
if not lock_file('/tmp/test.lock'):
print "another instance is running"lock_file('/tmp/test.lock')
再附上一份perl的代码:
use Fcntl qw(:flock);
my $lockdir = 'lock';
if (!-d $lockdir) {
mkdir $lockdir, 0755;
my $status=$!;
die "Failed to create $lockdir: $status\n" if (!-d $lockdir);
}
my $lockfile="$lockdir/test.pid";
if (!open(PID, ">$lockfile")) {
die "can not open pid file\n";
}
unless (flock(PID, LOCK_EX|LOCK_NB)) {
die "can not lock pid file\n";
}
print "locked\n";
顺便再抱怨两句,perl5补丁摞补丁的语法很怪异,异常处理机制竟然要用if...unless,类的写法也搞得跟写dll一样。不得不说,perl的语法离现代语言太远了。一个优美的语言可以提高开发效率,期待一下perl6最终出来的样子。
在python和perl程序中启用logging记录日志
写一些脚本程序的时候,合理的记录日志是必不可少的,尽量不往stdout乱打印信息为好,这时python的logging模块很用用处。不过调试时为了方便,还是希望日志也打印到stdout一份,这样出现什么问题一目了然;否则就只有再开个terminal,用tail -f my.log来检查了。
这样程序就会知道检查环境变量DEBUG,往合适的地方打印信息了。调试程序时执行方法:
最近还写了一些perl代码,和上面差不多功能的perl代码也贴出来:
这里用到log4perl模块,需要提前安装:
虽然适应了一段时间,但perl满眼$@%这些助记符,还是很阻碍阅读和思维连贯,不习惯。
import logging
def _init_logging(logfile, debug=False):
if debug:
level = logging.DEBUG
else:
level = logging.INFO
logging.basicConfig(level=level, format='%(asctime)s %(message)s',
datefmt='%Y-%m-%d %H:%M:%S', filename=logfile, filemode='w')
if debug:
console = logging.StreamHandler()
console.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s %(levelname)-8s %(message)s')
console.setFormatter(formatter)
logging.getLogger('').addHandler(console)
if __name__ == "__main__":
import os
debug = os.environ.get('DEBUG') and True or False
_init_logging('my.log', debug=debug)
logging.info('start')
logging.info('end')
这样程序就会知道检查环境变量DEBUG,往合适的地方打印信息了。调试程序时执行方法:
$ DEBUG=1 ./my.py
2007-10-22 17:30:59,917 INFO start
2007-10-22 17:31:02,027 INFO end
最近还写了一些perl代码,和上面差不多功能的perl代码也贴出来:
use strict;
use Log::Log4perl qw(:easy);
my $log_file = "/tmp/my.log";
if (exists $ENV{DEBUG} && $ENV{DEBUG}) {
Log::Log4perl->easy_init(
{file => ">> " . log_file, level => $DEBUG},
{file => "STDOUT", level => $DEBUG},
);
} else {
Log::Log4perl->easy_init(
{file => ">> " . $log_file, level => $DEBUG},
);
}
INFO("start...");
这里用到log4perl模块,需要提前安装:
sudo perl -MCPAN -e'install Log::Log4perl'
虽然适应了一段时间,但perl满眼$@%这些助记符,还是很阻碍阅读和思维连贯,不习惯。
2007-10-11
睡觉还是思考,这是个问题
晚上回家,意外发现被防盗门挡在了屋外。防盗门不防小偷,倒防主人,真是奇怪。叫来开锁公司,师傅跟铁门叫了一个多小时的劲,最终还是无功而返,我们一起被楼上吵得忍无可忍的邻居给轰走了。无奈之下,只有回办公室委屈一夜了,真是郁闷。
以前熬夜的时候,要么整晚不睡,要么是办公室有沙发,可以当成临时的床。现在的办公室没沙发这个设备,经过一番调研,决定用三个椅子拼在一起。按从电视看到的经验,这应该是办公室临时床铺的经典模式,不少人应该都这么干过,不过睡到上面的感觉可是只有自己心知肚明了。中间的椅子正好硌着腰眼,肩膀也只能有半个放到椅子面上,感觉别提多难受了。可就在这时,明明已经累的够呛,眼皮都酸的不想抬起来了,脑袋里的思想倒活跃起来了,平常做沙发上闭目沉思都没这时候想法多。可见现今哲学家变少是有道理的,只有睡硬板床的人各种稀奇古怪的想法才能层出不穷,有了席梦思睡的谁还瞎琢磨事呀,早呼呼大睡了。就在辗转反侧--俗称“烙饼”--之际,已经把手机里GTD软件里的事情又review了一遍,这次效率真高,很高兴;但是又发现严重拖延的事情非常多,继续郁闷...下半年其实过得不好,事实证明计划不如变化,现在离梦想中的幸福生活似乎更加遥远了...烙饼到第九圈,还是睡不着。人生苦短,可竟然还得睡觉。据说达芬奇天天打盹,加起来每天只睡两三个小时,看他能研究那么多领域也就不足为奇了。我不求达到奇人的地步,只要让我今晚少睡几个小时,明天照样能精神起来就好了。
这个故事告诉我们,家里床铺不好的人有可能得腰锥疾病,也有可能成为一代大家,切记切记。
以前熬夜的时候,要么整晚不睡,要么是办公室有沙发,可以当成临时的床。现在的办公室没沙发这个设备,经过一番调研,决定用三个椅子拼在一起。按从电视看到的经验,这应该是办公室临时床铺的经典模式,不少人应该都这么干过,不过睡到上面的感觉可是只有自己心知肚明了。中间的椅子正好硌着腰眼,肩膀也只能有半个放到椅子面上,感觉别提多难受了。可就在这时,明明已经累的够呛,眼皮都酸的不想抬起来了,脑袋里的思想倒活跃起来了,平常做沙发上闭目沉思都没这时候想法多。可见现今哲学家变少是有道理的,只有睡硬板床的人各种稀奇古怪的想法才能层出不穷,有了席梦思睡的谁还瞎琢磨事呀,早呼呼大睡了。就在辗转反侧--俗称“烙饼”--之际,已经把手机里GTD软件里的事情又review了一遍,这次效率真高,很高兴;但是又发现严重拖延的事情非常多,继续郁闷...下半年其实过得不好,事实证明计划不如变化,现在离梦想中的幸福生活似乎更加遥远了...烙饼到第九圈,还是睡不着。人生苦短,可竟然还得睡觉。据说达芬奇天天打盹,加起来每天只睡两三个小时,看他能研究那么多领域也就不足为奇了。我不求达到奇人的地步,只要让我今晚少睡几个小时,明天照样能精神起来就好了。
这个故事告诉我们,家里床铺不好的人有可能得腰锥疾病,也有可能成为一代大家,切记切记。
2007-08-28
怪序字符?
最近人们流行贴怪序字符,想必用Linux的人不会大惊小怪。其实大家贴的这就是三个unicode的字符:\u202d\u202e\u0489,前两个叫做控制字符LRO和RLO,也就是“从左到右覆盖”和“从右到左覆盖”。这些控制字符是给阿拉伯语等特殊书写顺序的语言准备的,没有什么稀奇。所有用Linux系统的人都可以在gedit等编辑区的右键菜单中任意添加这些控制字符,以方便阿拉伯语、希伯来语等书写,以及它们同其他语言的混合录入。
2007-08-27
原来还有个脚本叫ssh-copy-id
才发现openssh-client里有个脚本叫做ssh-copy-id,看了看openssh官方CVSweb中的代码,也没有找到,它从那里冒出来的?根据Debian包里的ChangeLog记录,1999年这个脚本就被加进去了,奇怪一直都没注意到它。原来都用这个脚本来把自己的ssh公钥发布到服务器上:
#!/bin/sh
ssh "$target" 'test -d .ssh || mkdir -m 0700 .ssh ; cat >> .ssh/authorized_keys && chmod 0600 .ssh/*' < ~/.ssh/id_rsa.pub
现在可以舍弃了,据说ssh-copy-id兼容性更好。
2007-08-20
2007-08-19
广而告之:诈骗信一封
发到我的gmail邮箱里来了,诈骗、传销、垃圾邮件,都被占全了。第一次收到以创业为诱饵的中文诈骗信,广而告之一下。不知道网上有没有向公安机关举报的地址呢?
邮件信头:
from: Oafkow
to: xiexiege@163.com
date: Aug 18, 2007 8:34 PM
subject: m创业邀请函
亲爱的朋友:
您好!
关于“筹集创业资金互助”活动的通告
请静下心把这封信仔细看完,然后马上行动!!!
各位辛勤创业的同仁:
我们没有钱,所以我们要挣钱,所以我们要创业,但是创业的艰难在于启动资金筹措问题上,而互助却是中华民族的传
统美德。这项由创业同仁们自发组织的互助活动的目的是要帮助所有自愿加入该互助活动的朋友完成心愿,筹集创业资金,达
到创业的目的。只要你参与,并严格按规则操作,你必将得到丰厚的资助。你不但自己可以得到几十万、上百万的资金,也支持
了其他的创业者.如果说创业是人生的转折点,那么有幸参加这次互助活动就是我们的一个人生转折点.然而毕竟多数的创业者
收不到这封信,而为之遗憾!所以,当你得到无数创业人的资助时,别忘了还有更多和我们一样正在为创业而痛苦的朋友!给他
一封信,助他度过难关。其实创业的艰难在于启动资金筹措问题上,而互助却是中华民族的传统美德,所以我认为很有必要
参与。
一、创业资金筹措的方法:
就是依据《二八法则》,使10元变成100万元 !如果你花10元钱买彩票,得头等大奖的概率是千万分之一,而你只要汇出十块
钱,有百分之百的把握得到100万回报。这个活动的可行性在于它严格遵守《二八法则》。世上有很多奇妙的事,《二八
法则》就是其中之一:社会上80%的财富在20%的人手里,20%的财富在80%的人手里。只要花费10块钱,然后
发200个E-mail,你就可以验证《二八法则》的灵运,同时将得到100万的收入。
二、“筹集创业资金联谊互助”活动的原理:
本活动采用著名的“倍增扩散法”,这种方法没有永远的第一和穷尽.这种方法是每个人都有平等的机会从第四位升到第一
位,只要参加活动,就可以100%获得可观效益,这并不像彩票一样只有千万分之一的运气,而是收到信并积极响应者都必然得到
巨额回报。每人按规则向100人(或更多的创业者)发出联谊信,按20%的反馈率算,用“倍增扩散法“计算一下,可想而知其效
果。
三、互助联谊排序表:
1号 中国工商银行 卡号: 95588 04000 15516 1751 康国平
2号 中国农业银行 卡号: 62284 80120 07038 3514 魏 芬
3号 中国工商银行 卡号: 95588 04000 16530 4243 陈 瑜
4号 中国招商银行 卡号: 6225 8800 0122 7850 王志华
表中四位创业者的编号为1号、2号、3号、4号,你收到信后,以最短的时间给1号寄去10元(寄钱的时间越长,扩散就越慢,你升
级到1号的时间也越晚.世间之事有时也是很微妙的,诚实的人也有诚实的回报,别因小失大哦!)然后将编号为1的创业者删
掉(此时1号已经被资助完毕),请你将2、3、4号的创业人依次递进,成为1、2、3,再把你的姓名和卡号,加在4号的位置上(注意
你一定要在资助完1号才可以将你的卡号加上去),你就成了第4号,排好后把些信分别发给200位或尽量更多各地创业人,当这
200位再发出信时,你就是200X200=40000封信中的3号了,依次类推,当你变成1号时,扩散人数可想而知,对你的回报是惊人
的.而且你寄出仅仅10元的投入,且是寄给1号的创业人。你就会开始得到朋友们资助的创业资金了!当然发出的信越多效果就
越佳,建议你多坚持发信一段时间!前面的劳动都是你应该做的,也是在为你增加资助的人数,所以不要跳级,这样只会让
你得到的资助变少几百倍!
以下是对倍增扩散法的图例说明(注意,本图以每位创业者发两封邮件为例)
☆(你-创业者1)
↓
↓
↓ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄↓
★ ★------4级
↓ ↓
↓ ̄ ̄ ̄ ̄ ̄ ̄  ̄ ̄ ̄↓ ↓ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄↓
★ ★ ★ ★-----3级
↓ ↓ ↓ ↓
↓ ̄ ̄ ̄ ̄↓ ↓ ̄ ̄ ̄ ̄ ̄↓ ↓ ̄ ̄ ̄ ̄ ̄↓ ↓ ̄ ̄ ̄ ̄ ̄↓
★ ★ ★ ★ ★ ★ ★ ★-----2级
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
↓ ̄ ̄↓ ↓ ̄ ̄↓ ↓ ̄ ̄↓ ↓ ̄ ̄↓ ↓ ̄ ̄↓ ↓ ̄ ̄↓ ↓ ̄ ̄↓ ↓ ̄ ̄↓
★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★------1级
收到你发出的信件的人是处于4级的创业者--2人(这时你的银行卡号是排在4号位)
当4级的创业者将信件发出时收件人是3级的创业者--4人(这时你的银行卡号是排在3号位)
当3级的创业者将信件发出时收件人是2级的创业者--8人(这时你的银行卡号是排在2号位)
当2级的创业者将信件发出时收件人是1级的创业者--16人(这时你的银行卡号是排在1号位)
若以每位创业者发100封邮件的话当你的银行卡号排在1号位时就有100X100X100X100=100000000人收到邮件
四、注意:
在你给1号创业人打钱后,,请按原格式递进,消除1号,将其余号按顺序递进,增加你为4号,重新把互助联谊信修改一下,尽快发,
务必认真校对清楚,众人拾柴火焰高,如在你处中断,实在太可惜.本来我们都是公布创业者的地址和姓名,但应广大创业者的
要求,我们把创业者的名字和地址做自愿处理,愿意公布的也可以,不愿意的也可以匿名从事。对一些主动返回信息的资助
者作报道:到目前为止,收到较多创业资金的有:
重庆市石桥铺达飞苑南华街423号赵东林(邮编:400039 电话:023-61613581),他发了235份邮件,收到资助款72万元;南京市
珠江路373号-5A韦良栋(邮编:210018 电话:025-86871956)发出联谊信220封,三个月后收到120万元;天津大港中学李万祥
(邮编:300270)发了330份邮件,两个月收到100余万元;湖南长沙市东区政协委员刘振时(邮编:410011)发出220封联谊信,三
个月收到130万元。
五、来信选登:
我是山东筑港工程公司一名工程师,业余时间搞了摩托车防松气门等十余项发明并申请专利,始终无法成功转让,自己仅靠工资
收入,无起步资金,连专利年费都交不起,可幸运的是今年一月我收到了一位创业者发来的“互助联谊信“,当时我未在乎,后我
认真阅读,分析了一下它的原理,认为可行,不就10块钱?况且又是互助,我就按信中要求的操作规律,给1号寄了10元,我把排序
表重新排好,发了100份,约两个月后,真让我高兴,我陆续收到各地创业者来的资助.打过来的资助,现已累计了180万元,我并
未花费多少精力,竟然得到如些丰厚回报,我谨向支持我的创业者同仁和组委会表示我的诚挚的感谢!(山东省筑港工程总公司
段兴 通信地址:表惠路8号 邮编: 265032)我是一名政协委员,我怀着万分感动的心情给你们写信,表达我对创业互助联谊活动
的感谢!因我喜爱搞发明,1983年我发明的“新型无钥匙保险锁“,1990年获得湖南省新技术博览会一等奖,但我平时的工资仅
500多元,家中还欠了不少债,当我收到“互助联谊信“后,觉得有道理,怀着试试的心情发出了 120份互助联谊信,大概过了两
个月,仅三个月我的卡里就收到全国各地创业人资助款160万元,我好兴奋!我不仅还清了所有债务,还用这笔资金办了一个企
业-长沙市龙江超级保险柜有限公司,我未想到我仅汇出10元,得到如此回报,互助的力量无穷!说心里话,我还后悔发的太少
了…...(通信地址:湖南长沙市东区政协转刘振时 邮编:410011)
也许有人不会相信,但自然法则造就的事实。顺便提醒一下,当你收到了超过1千元的时候,请给收到信时排序表上的4
人各寄上20元,因为他们是你生命中的贵人,是值得你感恩的。
致
礼!
182007邮件信头:
Received: by 10.114.196.20 with SMTP id t20cs632823waf;
Sat, 18 Aug 2007 05:34:16 -0700 (PDT)
Received: by 10.35.110.13 with SMTP id n13mr4677532pym.1187440455920;
Sat, 18 Aug 2007 05:34:15 -0700 (PDT)
Return-Path:
Received: from ccicards.com ([206.173.124.181])
by mx.google.com with ESMTP id e1si1799104nzd.2007.08.18.05.34.15;
Sat, 18 Aug 2007 05:34:15 -0700 (PDT)
Received-SPF: neutral (google.com: 206.173.124.181 is neither permitted nor denied by best guess record for domain of lqwd@ccicards.com) client-ip=206.173.124.181;
Authentication-Results: mx.google.com; spf=neutral (google.com: 206.173.124.181 is neither permitted nor denied by best guess record for domain of lqwd@ccicards.com) smtp.mail=lqwd@ccicards.com
Received: from 8017A300191F4BE [116.24.119.199] by ccicards.com with ESMTP
(SMTPD-9.04) id A7311730; Sat, 18 Aug 2007 07:33:53 -0500
Message-Id: <200708180733380.SM12488@8017A300191F4BE>
From: "Oafkow"
Subject: =?GB2312?B?bbS00rXR+8fruq8=?=
To: xiexiege@163.com
Content-Type: text/plain
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Date: Sat, 18 Aug 2007 20:34:00 +0800
2007-08-03
强烈推荐OpenDNS
今天收到 grsync 作者给翻译人员的一封信,要求大家都去一个专为这个项目建立的 forum 上。直接点击地址,打不开。莫非是域名还没生效?dig了一下,发现二级域名和顶级域名都找不到,好像不对吧,从web archive上看,人家的网站2003年就有了。新装的机器上一直都没设置使用 OpenDNS 呢,修改 /etc/resolv.conf,加入两行:
被这样搞掉的网站有多少?实在不好统计。总之学个教训,Tor好用,但还要记得DNS安全,别让人把你劫持了。DNS直接返回无效算是容易发现的,有人要是有目的的域名劫持,后果就可怕了,所以还是提前防备一下的好。虽然咱不干犯法的事,但谁知道呢,现在遍地的条条框框,你能保证不会有一天被它给框进去?
p.s. 预测一下,什么时候 OpenDNS 会流行起来?什么时候它也会被河蟹掉?被河蟹也可以算是一种另类的受欢迎指数吧 -__-
nameserver 208.67.222.222
nameserver 208.67.220.220再试,果然,是因为“有人”把这个域名给河蟹了。接下来又撞上了一堵墙,这次只能用 Tor 翻墙了。被这样搞掉的网站有多少?实在不好统计。总之学个教训,Tor好用,但还要记得DNS安全,别让人把你劫持了。DNS直接返回无效算是容易发现的,有人要是有目的的域名劫持,后果就可怕了,所以还是提前防备一下的好。虽然咱不干犯法的事,但谁知道呢,现在遍地的条条框框,你能保证不会有一天被它给框进去?
p.s. 预测一下,什么时候 OpenDNS 会流行起来?什么时候它也会被河蟹掉?被河蟹也可以算是一种另类的受欢迎指数吧 -__-
2007-08-02
“GPS技术在气象学中的应用”
昨天被大雨所困,想起了F1赛事精准的天气预报和GPS。今天上网查了一下,GPS早就被气象部门用来采集数据了,GPS技术在气象学中的应用还真少。不过,这些家伙搞的都是观测系统,什么时候有公司能根据个人GPS提供的方位为我们实时传送气象预报呢?我记得有些手机是有GPS配件的,等过两年GPS变成了手机的标配,再在手机上加几个温度湿度气压之类的传感器,手机就变成全能的气象终端啦,既可以给观测系统提供实时的数据,又可以接收精度很高的个人化天气预报。看起来国外已经有人在做这事了,有气象专家的研究,也有商业公司的系统;国内不知道是不是因为卫星系统国有,没有人冒风险去研究这种偏门的项目,好像没有这方面的消息。人家已经快要开始搞产品商业化时,我们这边的新闻还是某地又建了几个“高科技”的GPS气象采集基站,各部门领导很有面子云云。难道是我们又输在起跑线上了?
2007-08-01
果真是天有不测风云
早晨看到阳光灿烂,赶紧把昨天洗完晾在房间里的衣服挂到外面的晾衣绳上。晚上下班了,忽然听到外面淅沥哗啦,又开始下雨啦!怎么昨天的暴雨还没下够?今年北京的雨水可是下足了。上网看看北京今天的天气预报,也是说晴转多云,就没提到会下雨这回事。话说天有不测风云,果然不错。前几天看F1德国站的比赛,那两场雨预报的,准确的让人瞠目结舌。不过特定地点、特定时间的预报会比大范围的预报容易做一些吧,什么时候通过GPS就能实时接收这么准确的气象预报就好啦,呵呵。顶着早晨的大太阳,我可没想到晚上会被大雨困在办公室:可怜,完全没想到要带雨伞 :(
多等一会,雨停了后回家再把衣服洗一遍吧....
多等一会,雨停了后回家再把衣服洗一遍吧....
2007-07-29
收拾心情,继续似水流年中的流水帐
我写blog是因为时常有跟别人分享点什么东西的冲动,写出来也许能跟人产生共鸣;或是指望帮人解决碰到的同样问题,自己心里也能有些窃喜。不过自打GFW愈演愈烈,访问国外blog的人全都会撞上一堵墙,偏巧我又只信任国外的blog服务...本来就拙于写字,如此有中国特色的blog体验更是让人心里烦躁,blog也就慢慢荒废了。
不过今年的见闻让我又有所领悟,当撞墙已经成为常态,练就翻墙绝顶轻功的人岂不是会越来越多?也许有一天世界又会大同,blog在墙里还是墙外还有什么分别。干脆抛开这些烦人的事情,哪怕铜墙铁壁终于铸成,起码墙外的人还能知道墙里的人曾经有这样的生活。
不过今年的见闻让我又有所领悟,当撞墙已经成为常态,练就翻墙绝顶轻功的人岂不是会越来越多?也许有一天世界又会大同,blog在墙里还是墙外还有什么分别。干脆抛开这些烦人的事情,哪怕铜墙铁壁终于铸成,起码墙外的人还能知道墙里的人曾经有这样的生活。
2007-07-28
在Ubuntu上安装用Windows目录服务做认证的Subversion服务
最近需要架设一台svn服务器,在Ubuntu Feisty(7.04)上安装了一下,非常容易。网上有很多相关资料,不过我需要让用户使用Windows的目录服务(Active Directory)来认证身份,参照了这篇LDAP Authentication for Subversion on Ubuntu Feisty文章,在这里做个文档备份:
dav_svn.conf文件,指明svn仓库在那里,如何认证用户身份:
参考《Apache2 SSL and Subversion in Debian》,给服务添加SSL支持。助记如下:
其实生成证书用apache的命令
2007-08-01再补充,
参考svn bug #2753,在使用 authz 的情况下,
# sudo apt-get install libapache2-svn subversion subversion-tools
# cd /etc/apache2/mods-enabled
# sudo ln -s /etc/apache2/mods-available/dav_svn.load
# sudo ln -s /etc/apache2/mods-available/ldap.load
# sudo ln -s /etc/apache2/mods-available/authnz_ldap.load
# sudo /etc/init.d/apache2 restart# cd /etc/apache2/mods-enabled
# sudo touch dav_svn.conf
# sudo vi dav_svn.conf其中加粗的两个命令是启用ldap相关的apache模块,这是参考的文章中没有提到的,否则会出现:“Unknown Authn provider: ldap”的错误提示。dav_svn.conf文件,指明svn仓库在那里,如何认证用户身份:
authz.conf文件,定义用户的组和访问不同项目仓库的权限:
<Location /svn/>
DAV svn
SVNParentPath /home/svn
AuthType Basic
AuthName "Subversion Repository"
AuthBasicProvider ldap
AuthLDAPBindDN "cn=readuser,ou=dep,dc=mydomain,dc=com"
AuthLDAPBindPassword "password"
AuthLDAPURL "ldap://adserver:3268/ou=dep,dc=mydomain,dc=com?sAMAccountName?sub?(objectClass=user)"
AuthzLDAPAuthoritative Off
Require valid-user
SVNListParentPath on
AuthzSVNAccessFile /home/svn/authz.conf
</Location>
[groups]
svnadmin = xieyanbo
erpadmin = user1
[/]
* =
@svnadmin = rw
[sandbox:/]
* = rw
[repos1:/]
@erpadmin = rw
为了创建项目方便,写了一个脚本add_project.sh做一些琐碎的事情,比如目录权限、配置文件的修改等:#!/bin/bash
project_name="$1"
if [ x"$project_name" = "x" ]; then
echo "$0 PROJECT_NAME"
exit 1
fi
sudo mkdir /home/svn/"$project_name"
sudo svnadmin create /home/svn/"$project_name"
sudo chown -R www-data:www-data /home/svn/"$project_name"
sudo chmod -R go-rwxs /home/svn/"$project_name"
sudo sh -c "echo 'auth-access = write' >> /home/svn/$project_name/conf/svnserve.conf"
sudo sh -c "echo '['$project_name':/]' >> /home/svn/authz.conf"
sudo sh -c "echo >> /home/svn/authz.conf"
补充,增加SSL支持
参考《Apache2 SSL and Subversion in Debian》,给服务添加SSL支持。助记如下:
sudo apt-get install openssl
sudo mkdir /etc/apache2/ssl
export RANDFILE=/dev/random
sudo openssl req $@ -new -x509 -days 365 -nodes \
-out /etc/apache2/ssl/apache.pem \
-keyout /etc/apache2/ssl/apache.pem
sudo chmod 600 /etc/apache2/ssl/apache.pem
cd /etc/apache2/sites-available/
sudo cp default ssl
sudo a2ensite ssl
sudo a2enmod ssl
sudo vi /etc/apache2/ports.conf # add Listen 443
其实生成证书用apache的命令
apache2-ssl-certificate很方便,但Ubuntu从Debian继承的一个bug把它给搞丢了,可惜...下面是ssl的apache配置文件/etc/apache2/sites-available/ssl的内容:<VirtualHost *:443>
SSLEngine On
SSLCertificateFile /etc/apache2/ssl/apache.pem
Include /etc/apache2/mods-enabled/dav_svn.conf
</VirtualHost>
2007-08-01再补充,SVNListParentPath on的bug临时应对方案
参考svn bug #2753,在使用 authz 的情况下,
SVNListParentPath on这个设置会失效,apache总是报告权限错误。避免这种情况的临时方案:把<Location /svn>改成<Location /svn/>,路径的最后面增加一个斜线。还真是个古怪的bug呀。
标签:
apache,
ldap,
subversion,
ubuntu
订阅:
博文 (Atom)