Archive for 十一月, 2010

printf(“(char)48 = %c\n”, (char)48);
printf(“(int)’0′ = %d\n”, (int)’0′);
printf(“convert ‘0’ to 0: %d\n”, b_atoi(‘0′));
printf(“convert 0 to ‘0’: %c\n”, b_itoa(0));

在不严谨的情况下,可以如上写。

有的时候,我们会希望能够把1、 2 、 3这样的数字作为字符直接存储到字符串中。如果直接(char)2的话,你得到的不会是字符’2’,它更像一些乱码。

由于字符’0’对应int型的48,所以可以利用这个特性来进行int和字符字面上的转换。

上午,在推荐和seo脚本服务器上,整理了crontab,加上一些磁盘使用监控程序,停止一些分析日志和数据的脚本。

就像一手带出来的孩子,现在最后一次梳理它们。 希望之后,它们还有机会能够为用户提供服务。

现在,准备整理搜索服务器。

想开始学习ios开发,并且希望今年能够在技术上有个大进步,所以决定以后都晚点走,留点安静的时间学习。

今天是第一天,坚持到现在就受不了了,不过只要继续下去,应该就会习惯。

如果能回到当年考研的状态,或者在那个小公司被压迫的状态,就好了。那会激发我的潜力吧?

给自己的今年定的目标:

1、 collaborative filtering库开发完毕,完成性能调优,能够让自己满意

2、 基本掌握ios的开发,熟悉语法、工具

还有一个多月,这个目标应该还合适。

加油!

cf库计划:

基本功能已经完成,之后:

整理test代码,完成一个功能测试流程

整理test代码,完成一个性能测试流程,作为性能调优的基准点

调整库接口的易用性

调整数据结构的易用性

调整性能

上线测试,跟踪用户点击率等动作,尝试反馈回算法

ios计划:

阅读online的帮助文档

使用公司的mac熟悉xcode环境,看sample code

尝试写个简单的hello world,放到我的ipad上测试

阅读一个略大的实际项目code

尝试跟一个公司的项目

Continue reading ‘7点第一天’ »

写代码前,缺乏设计,仅考虑了以下问题:

1、 概念上理解了CF算法

2、 脑子里大致有了user based cf的流程图,没有画出来

3、 大致想清楚了稀疏矩阵的存储方式,和必要的操作(后来发现还是漏了些)

欠缺的:

1、 打算实现user based和item based的cf算法,但是没有对此有整体的设计和理解

2、 没有将整个算法实现分隔为模块,比如输入、输出模块、算法模块等

3、 没有对数据结构进行很好的封装,写入方式过多,不利于效率优化和控制

总而言之,是缺乏整体性的考虑,也缺乏对细节的关注。(细节不清楚也是因为整体理解不足)

我现在的编程习惯是,写出一个函数,测试;然后继续。这样能够保证每个函数功能完备,但是等到把函数串联起来的时候,会发现当初设计的函数功能可能有偏颇,于是又需要再调整。

有的函数过长,会等到写完之后再拆分。

考虑学习一些设计模块相关的概念,传统的瀑布开发和敏捷开发方式,孰是孰非?

如果是敏捷方式的话,首先要能够把整个需求分隔为一个一个的故事,给出每个故事的预估开发时间。这应该也是架构和设计。

之后呢?TDD?我先写出测试代码,然后再写实现代码,自己TDD试试?

还是算了吧,应该还是从自己最熟悉的方式入手。还是太久没写C了。

先从整体上设计出我想要实现的CF算法,模块化,画出流程图,具体到细节。

请教了leader,得到以下建议:

1、 部署:是否要多台服务器,都是怎样的角色,完成怎样的功能?

2、 出错处理、log、输入、输出、信号:标准linux程序需要的部分

3、 层次化:目录、文件、函数;模块化,分层,层与层之间怎样通信,是否允许层内通信、跨层通信等

4、 数据结构:算法的核心

5、 单元测试

url中,#号之后的部分被认为是锚点,仅用于页面定位,而不被视为url的有效成分。

一般浏览器,都不会将#号后的部分发送给web服务器,所以web服务器的log的request part中,一般不含有#。但是,当某些应用程序,直接发送含有#号的url时,web服务器(至少apache)会忠实的记录下来,这时,在log里你就会发现#号了。

从SEO的角度来看,google、baidu是会忽略#号和它之后的成分的。

以google的一个帮助页面为例:

http://www.google.com/intl/zh-CN/help/features.html#local

http://www.google.com/intl/zh-CN/help/features.html#essentials

以上两个完整的url都没有被“收录”,而http://www.google.com/intl/zh-CN/help/features.html是被收录的。

据说,现在包含#号的url,在flash、ajax、html5中的应用比较多,因为这样可以不刷新浏览器,而由程序控制,向后台请求数据,重绘页面。从而保证较好的用户体验。

ps:本文由MySpace.cn的音乐新产品Play触发。该页面的url组成为:http://music.myspace.cn/play/#/1300348224

emerge相关的配置:

/etc/make.conf

/usr/portage/profiles

如果emerge从镜像下载安装包过慢,可以手工下载下来,放在/usr/portage/distfiles下,emerge会自动从这儿获取安装。

通过emerge –pretend 可以看到其依赖包。

在同一个svn本地副本里,执行:

svn log –verbose

svn log –verbose https://svn-host/path/to/this/

显示的日志却是不同的,究其原因,是svn log的默认参数不同造成的。

当使用svn log –verbose时,默认是查看当前目录对应的日志信息,而默认版本是BASE:1,即从本地基线版本到最开始所有的日志。

svn log –verbose https://svn-host/path/to/this/,默认版本是HEAD:1,即从svn仓库最新版本到最开始的日志,可能会多于BASE:1。

我习惯用svn log –verbose https://svn-host/path/to/this/,能够查看到所有日志。

相关文章:

将SVN利用到实际-1 介绍了SVN常用的命令

将SVN利用到实际-2 具体介绍了怎样解决一次SVN冲突

这次,说说怎么使用SVN的分支概念。了解完这些概念之后,就可以看看怎样将SVN应用到项目的合作开发和上线流程中了。

首先,要了解SVN的版本概念:

Subversion的修订号是针对整个目录树的,而不是单个文件。每一个修订号代表了一次提交后版本库整个目录树的特定状态,另一种理解是修订号N代表版本库已经经过了N次提交。当Subversion用户讨论“foo.c的修订号5”时,他们的实际意思是“在修订号5时的foo.c”。

请注意:SVN的特定版本是包含了整个目录树的。

这里需要注意的两种版本:

BASE,工作副本的基线版本,记录在.svn目录里。HEAD,版本库中的最新版本,需要与SVN服务器通信以获得。

比如说,你从SVN获取了最新版本的a.txt,版本是23;之后,有其他人对a.txt做了一些修改,并提交了,这时服务器里a.txt的版本是24。那么,对你而言,a.txt的BASE=23, a.txt的HEAD=24。

在什么情况下会用到分支呢?

理想情况下,一个项目,就我一个人负责,没有人会来打扰我的清净世界,SVN仅仅是我自己的一个代码备份工具而已。但是现实是残酷的,总会有人同你合作,会有人在你不知情的时候偷偷修改了你的代码,你和别人的修改混杂在一起,而且产品经理还要求你们在不同的时间点上线……

所以,你需要一个分支,这个分支,只有你和你的team在合理分工的情况下操作,你们保持良好的SVN习惯,每天早晨来update,每天下班commit正确无误的代码(听起来也有点不现实,是吗?),你们维护的这个版本是同进退的。

恩,那首先了解下trunk和branch的概念吧。Trunk是一个项目的主干,大多数时候,大多数人都工作在trunk上。Branch是不得已的情况下才创建的,它基于这一时间点的trunk,之后与trunk暂时脱离关系,一般只有少数人工作在这儿,也只存在一段时间,之后会merge回trunk,然后被删除。

引入branch的概念,你需要使用到的SVN命令有:

svn cp

svn log

svn diff

svn merge

svn ci

怎样创建一个分支

比如现在的trunk代码在:https://host/svn/thisprj/trunk,所有的分支代码被规划为https://host/svn/thisprj/branchs的子目录。则:

svn cp https://host/svn/thisprj/trunk https://host/svn/thisprj/branchs/1.0.0-keyword

会在branchs下创建一个名称为1.0.0-keyword的分支,你可以使用版本号和一些有意义的词语命名该分支。

然后就快乐的在分支下工作吧:

svn co https://host/svn/thisprj/branchs/1.0.0-keyword /path/to/your/work/dir; cd /path/to/your/work/dir

你和其他人的工作现在是分隔的,互不影响了。你可以提交你的任何修改到这个branch里。

不过,切记:不要离trunk太远!!你最终是需要回归到trunk的!!所以,经常(比如每天)从trunk获取最新的更改merge到你的分支来(如果有人在trunk上搞代码,但是又不让上线,最好建议她也branch吧)!

怎样合并主干(trunk)的代码到当前分支?

保持每天从trunk获取最新代码,merge到你的分支中,这会是一个良好的习惯。不过事先,你最好同trunk维护的同事沟通好,得到他们merge的许可。

有个好习惯,merge前先update自己的修改:

cd /path/to/your/work/dir;svn ci -m ‘some comment’

查看trunk有哪些修改:

svn diff  -roldversion:newversion https://host/svn/thisprj/trunk

如果确定这些修改你是需要的,那么试试合并它们会不会带来冲突:

svn merge –dry-run  -roldversion:newversion https://host/svn/thisprj/trunk

OK了?那么merge吧:

svn diff  -roldversion:newversion https://host/svn/thisprj/trunk

然后就是测试,可能会有修改,然后提交:

svn ci -m ‘some comment’

如果在这过程中,出现了冲突,请参考前文解决冲突。

当branch上的工作完成之后,一定要将代码合并到trunk上去,以保证一个项目仅有一个主干。

怎样将branch合并到trunk

branch仅是临时之计,所以最终它的命运是回归主版本,然后自我消亡。

首先同trunk的维护人员沟通好,然后从trunk获取一份最新的代码:

svn co https://host/svn/thisprj/trunk /path/to/your/merge/dir; cd /path/to/your/merge/dir

获取分支的起始和结束版本号:

svn log –verbose –stop-on-copy https://host/svn/thisprj/branchs/1.0.0-keyword

在合并前,你可能会想查看分支代码修改了哪些内容:

svn diff -r startversion:endversion https://host/svn/thisprj/branchs/1.0.0-keyword

或者看看主干与分支现在有什么区别:

svn diff https://host/svn/thisprj/trunk https://host/svn/thisprj/branchs/1.0.0-keyword

然后,试试如果merge,会不会有冲突:

svn merge –dry-run -r startversion:endversion https://host/svn/thisprj/branchs/1.0.0-keyword

合并:

svn merge  -r startversion:endversion https://host/svn/thisprj/branchs/1.0.0-keyword

测试,修改bug。最后确定合并完了,而且功能正确了,就可以提交咯:

svn ci -m ‘merged branch/1.0.0 from rstartversion to rendversion into the trunk’

以上就是与分支相关的一系列操作。当然,你的项目可能会很复杂,很多项目,很多人,但是原理是相同的。

最后,需要说明的是,分支很好用,但是太多分支也会让人崩溃!

另外,复制分支很廉价,一个项目的分支、版本之间共享很多很多数据,它们共同占用磁盘。

——————————-

回滚操作(回滚到版本11):

svn  merge -r HEAD:11 https://host/svn/branches/1.0/app/controllers/product_controller.php controllers/product_controller.php

上一篇博客简单介绍了常用的SVN命令,但是遗留了冲突解决和branch、merge。

这里,先说说冲突解决。

怎么会发生冲突呢?

两个人修改了不同文件?不会有冲突,他们不相关。

两个人同时修改了同一个文件的不同位置?不会有冲突,SVN很聪明。

两个人同时修改了同一个文件的相同位置?Bing!冲突来了。

工程师A修改了a.txt的第一行,提交了。

工程师B也修改了a.txt的第一行,然后执行svn up,这时SVN提示了:(以下,你开始扮演工程师B的角色了)

$ svn up
在 “a.txt” 中发现冲突。
选择: (p) 推迟,(df) 显示全部差异,(e) 编辑,
(mc) 我的版本, (tc) 他人的版本,
(s) 显示全部选项:

我一般选择p(推迟),即引入冲突到本地,不过不会影响到SVN服务器端,可以放心。

OK,开始解决冲突了。

这时,会生成几个文件:

a.txt  a.txt.mine  a.txt.r6328  a.txt.r6336

其中a.txt中包含了工程师A、B的所有修改,以<<<<<<<、=======、>>>>>>>分隔。

a.txt.mine是工程师B的修改,也就是未update前的a.txt。

a.txt.r6328 是工程师A提交前的版本,即未导致冲突的版本。

a.txt.r6336是工程师A提交后的版本,即导致冲突的版本。

一般,查看a.txt就可以看到冲突的详情了:

[yicheng@chengyi svntest]$ cat a.txt

<<<<<<< .mine

i also modify ,agndagnagasdg;

=======

i modify this line;

>>>>>>> .r6336

以上,<<<<<<< .mine和=======之间是工程师B(当前的“你”)修改的内容,=======与>>>>>>> .r6336之间是工程师A修改的内容。这时,最好的办法是,叫上工程师A,你们一起确定这些修改是否都需要,是否相互兼容,然后留下需要的部分,删除<<<<<<< .mine、=======和>>>>>>> .r6336。

然后,测试,测试!确定没问题之后,就可以告诉SVN,你解决冲突了:

svn resolve –accept working a.txt (该命令会删除a.txt.mine  a.txt.r6328  a.txt.r6336)

svn ci -m ‘some comment’ a.txt

这里需要注意的是,a.txt.mine  a.txt.r6328  a.txt.r6336这几个文件的存在代表着有冲突产生。如果不解决冲突,就手工删除它们,SVN服务器也会很傻的认为你解决了冲突,允许你继续之后的工作。但是,冲突依旧存在,你的a.txt中不但有别人的修改,还有那些讨厌的<=>符号。

在冲突未解决前,试图提交代码是肯定会失败的:

$ svn ci -m ”

svn: 提交失败(细节如下):

svn: 提交终止: “/path/to/svntest/a.txt” 处于冲突状态

SVN,全称Subversion,是一种版本管理工具,支持Linux、Windows环境等。具体概念性的知识,可以google得到。

这里,仅介绍下,怎样将SVN应用到实际项目中,怎样帮助一个小规模的开发团队建立流畅、安全的上线流程。以下,全部建立在Linux的bash环境下,因为我是命令行的坚决拥戴者。

在最初学习使用一项工具时,最应该学会的,就是它的help命令。在Linux下,输入svn help,可以看到svn所有命令的帮助;如果要查询具体某一命令的帮助,则输入 svn help 命令名,比如svn help commit。另外,svn的很多命令,都有对应的缩写,比如commit对应着ci,两者完全等同(至少我没发现不等同的情况)。

那么svn的这些命令,都是做什么用的呢?以下先简要介绍下。

add

把文件和目录纳入版本控制,通过调度加到版本库。它们会在下一次提交时加入。

比如,svn add test.php会把test.php提交到本地版本库,注意,这时它并没有被提交到SVN的服务器端;需要通过svn ci -m ‘some comment’ test.php才会真正进行提交。

如果在add之后,想要撤销,可以通过svn revert test.php。

一个新文件,在svn add之前,它的状态是未知(?),在add之后,它的状态会变成已添加(A)。

blame (praise, annotate, ann)

输出指定文件或URL的追溯内容,包含版本和作者信息。这里的追溯内容,包括了具体每个版本修改了哪些文字,事无巨细都会列举出来,所以对于大文件,blame的输出可能会很多。以下是一个例子:

[yicheng@chengyi svntest]$ svn blame b.txt

6331 flykobe I add this this time

6332 flykobe ANd now this

以上输出表明,我在版本6331的b.txt里添加了一行“ I add this this time”,在版本6332添加了另一行“ANd now this”。如果想看更详细的内容,可以用svn blame -v b.txt。看指定版本的修改:svn blame -v b.txt@6331,或者svn blame  -r 6331 -v b.txt。

cat

输出指定文件或URL的内容。这个没什么好说的,就是访问SVN仓库,拿到最新版本的文件查看。

比如,在本地修改了文件b.txt,但是没有提交,那么这时svn cat b.txt,不会看到你修改了的内容的。

checkout (co)

从版本库签出工作副本。

正常情况下,我们会想拿SVN服务器中的最新版本的代码到本地,则:svn co https://svn-host/path/to/workdir ,那么workdir目录会被签出到本地,名称仍叫workdir,它会作为SVN的本地工作副本存在,通过.svn的隐藏目录与SVN服务器间建立起联系。如果想给本地目录换个名称,则:svn co https://svn-host/path/to/workdir newdirname,那么workdir在本地就叫newdirname,除了名称上,没有其他任何影响。

在某些情况下,我们还想签出某个指定版本,则:svn co https://svn-host/path/to/workdir@6331。其中6331会被替换为你想要的版本号。你可能会有疑问,需要哪个版本呢?请看svn help log。并且让你的工程师在提交代码的时候,写上良好的comment。

cleanup

递归清理工作副本,删除锁,继续未完成操作,等等。这个命令,在正常情况下,应该不会用到。如果遇到文件被锁等情况,可以酌情使用。(我想不清了怎样制造这种情况了,无法给出例子,sorry)

commit (ci)

把工作副本的修改提交到版本库。该命令会强制你写上一些提交日志(当然你可以输入空,但是强烈不建议,这会给你和其他人造成N多困扰!!!)。

默认情况下,它提交你所有的修改:svn ci -m ‘some comments’。

如果仅想提交某些修改:svn ci -m ‘some coments’ filename filename1 filename2

这个命令会经常使用,但是最好确保你提交的代码是正确的,进过自己测试的。

copy (cp)

在工作副本或版本库中复制数据,保留历史。

用法: copy SRC[@REV]… DST

当复制多个源时,它们作为 DST 的子节点增加, DST 必须是目录。

SRC 和 DST 可以是工作副本路径(WC)或版本库地址(URL):

WC   -> WC:  复制和调度增加(包含历史),像是cp src dst; svn add dst,所以这个dst还没有被提交到服务器上。

WC   -> URL: 立即提交工作副本到版本库,像是svn add + svn ci,直接把本地的文件提交到服务器上。

URL  -> WC:  检出 URL 到工作副本,调度增加,如svn cp https://svn-host/path/to/another-workdir/another.file local.file,即获取了SVN服务器端的某个文件,添加到本地工作目录,有点像cp /local/path/to/another-workdir/another.file local.file; svn add local.file

URL  -> URL: 完全服务器端复制;一般用于分支和标签,如svn cp https://svn-host/path/to/workdir https://svn-host/path/to/workdir-release-version,常用来打标签,准备上线目录等

所有 SRC 必须是同一类型。

delete (del, remove, rm)

从版本库中删除文件和目录。

diff (di)

显示两个版本或路径的差异。可以比较不同版本间的文件差异,或者本地文件与SVN服务器端各个版本间的区别。总是觉得它同blame在某种程度上有重合。习惯linux diff命令的,对于这个svn diff应该很习惯了。

export

产生一个无版本控制的目录树副本。线上环境怎么可以有SVN隐藏文件呢?所以用这个命令,可以生成一个干净的,没有.svn隐藏目录的副本。

没有.svn隐藏目录,就是说,这个副本,断开了同SVN服务器端的一切联系了,不能ci,不能blame,不能svn咯!

比如:svn export https://svn-host/path/to/workdir-release-version online-work-dir

help (?, h)

查看帮助。

import

将未纳入版本控制的文件或目录树提交到版本库。仅仅在新建项目的时候,需要用到这个命令。

比如:svn new-work-dir https://svn-host/path/to/new-work-dir。注意,如果url中不含有new-work-dir,那么new-work-dir下的文件会被直接提交到https://svn-host/path/to/下去,惨不忍睹哦!

info

显示本地或远程条目的信息。

比如:svn info 会列出当前本地副本的版本信息,包括版本号、svn中的路径、状态等。

list (ls)

列出版本库中的目录内容。与Linux的ls命令很相似,自己揣摩吧~

lock

锁定版本库中的路径,使得其他用户不能向其提交修改。当确定了一个待发布版本的时候,lock它,会不会更安全点?一个文件同时只能被一个人加锁。

log

显示一组版本与/或文件的提交日志信息。这里的“日志信息”,就是svn ci时填写的comment信息,所以,如果想要日志更可读,就在ci的时候多写几句有意义的comment吧!

merge

将两个源差异应用至工作副本。这是个很重要的命令,但是它太复杂了,后面我会专门写它。关于merge、branch。

mergeinfo

显示合并的相关信息。

mkdir

创建纳入版本控制的新目录。

move (mv, rename, ren)

在工作副本或版本库中移动或改名文件或目录。我一般用它来改名。

resolve

解决工作副本中目录或文件的冲突。解决冲突后,执行svn resolve –accept working conflict-file-name删除冲突产生的临时文件。

resolved

删除工作副本中目录或文件的“冲突”状态。

本子命令不会依语法来解决冲突或是删除冲突标记;它只是删除冲突相关的附加文件,让 PATH 可以被再次提交。它已经过时,被 “svn resolve –accept working conflict-file-name”取代。

revert

将工作副本文件恢复到原始版本(恢复大部份的本地修改)。比如,在本地修改了文件test.php,但是这些修改时错误的,不想保留(本地也不要了)也不想提交到SVN服务器了,则:svn revert test.php,这时test.php会变成SVN服务器的最新版本,你的修改消失了。

status (stat, st)

显示工作副本中目录与文件的状态。我一般用svn st -u,这样可以看到本地有哪些文件同SVN服务器端不一致。如果svn st -v 则会列出所有文件的状态。

第一栏: 表示一个项目是增加、删除,还是修改

“ ” 无修改

“A” 增加

“C” 冲突

“D” 删除

“I” 忽略

“M” 改变

“R” 替换

“X” 未纳入版本控制的目录,被外部引用的目录所创建

“?” 未纳入版本控制

“!” 该项目已遗失(被非 svn 命令删除)或不完整

“~” 版本控制下的项目与其它类型的项目重名

第二栏: 显示目录或文件的属性状态

“ ” 无修改

“C” 冲突

“M” 改变

第三栏: 工作副本目录是否被锁定

“ ” 未锁定

“L” 锁定

第四栏: 已调度的提交是否包含副本历史

“ ” 没有历史

“+” 包含历史

第五栏: 该条目相对其父目录是否已切换,或者是外部引用的文件

“ ” 正常

“S” 已切换

“X” 被外部引用创建的文件

第六栏: 版本库锁定标记

(没有 -u)

“ ” 没有锁定标记

“K” 存在锁定标记

(使用 -u)

“ ” 没有在版本库中锁定,没有锁定标记

“K” 在版本库中被锁定,存在锁定标记

“O” 在版本库中被锁定,锁定标记在一些其他工作副本中

“T” 在版本库中被锁定,存在锁定标记但已被窃取

“B” 没有在版本库中被锁定,存在锁定标记但已被破坏

第七栏: 项目冲突标记

“ ” 正常

“C” 树冲突

如果项目包含于树冲突之中,在项目状态行后会附加行,说明冲突的种类。

以上标红、标粗的状态是通常会遇到的,重点注意冲突相关的就可以了。冲突发生时,不但文件状态会改变,还会生成多个冲突文件。

switch (sw)

更新工作副本至不同的 URL。没用过,貌似是在SVN不同项目间切换。

unlock

解除工作副本或URL的锁定。

update (up)

将版本库的修改合并到工作副本中。这个命令也很常用,最好每天开始工作前,都更新一下本地工作副本,把别人的修改更新到本地。

更新后的提示信息中,会包含涉及到的文件的状态,我们需要注意的是C,即有冲突出现了。之后,我们需要解决冲突,提交修改。

A  已添加

D  已删除

U  已更新

C  合并冲突

G  合并成功

E  已存在