这个版本的主要更新如下
1.带代码编码检测功能,常见的编码都能自动检测分析出来,中文不再悲剧
2.带代码编码选择功能,机器也会出错,万一检测出错,还可以手动选择编码,双保险
3.支持更多代码文件,基本上常见不常见的代码都能高亮,而且无序保证代码后缀名,直接自动探测代码语言
然后就感谢以下开源项目带来的帮助:
http://code.google.com/p/google-code-prettify
http://cpdetector.sourceforge.net/
详情请查看官方更新页面
安静的做技术,宁静的搞摄影,平静的写文章
这个版本的主要更新如下
1.带代码编码检测功能,常见的编码都能自动检测分析出来,中文不再悲剧
2.带代码编码选择功能,机器也会出错,万一检测出错,还可以手动选择编码,双保险
3.支持更多代码文件,基本上常见不常见的代码都能高亮,而且无序保证代码后缀名,直接自动探测代码语言
然后就感谢以下开源项目带来的帮助:
http://code.google.com/p/google-code-prettify
http://cpdetector.sourceforge.net/
详情请查看官方更新页面
52 views
首先放上项目地址
http://code.google.com/p/codebrowser-android/
源代码是平板版本的,其实都一样,只要改变sdk就可以在不同的版本跑:)希望大家生活愉快~
CodeBrowser是我第一个认真设计的Android程序,一路走来也快2年了吧,从一开始只是为了满足简单的代码浏览功能,到现在基本上能够实现常用代码舒适的阅读,中间点点滴滴太多太多。再次感谢各位帮助测试和帮忙提建议的同学朋友们:)
105 views
首先,如果你嫌麻烦而且没有VPS而且对推送的内容不需要包含图片的话,那么你可以直接去下面这个网站:
直接用你的Google帐户登陆就好,一步搞定,不过推送过来的东西没有图片,所以很不爽。那么就按照我的步骤来一步步完成这个事情吧。
首先我们需要做一个准备工作,因为CentOS上面的Python是2.4的很多库都木有,然后呢一个个去装又比较麻烦,所以我就直接升级了CentOS上面的Python到2.7.1,步骤很简单,登陆到VPS的SSH后步骤如下:
1.从官网下载Python 2.7
1 | wget http://www.python.org/ftp/python/2.7.1/Python-2.7.1.tar.bz2 |
2.安装
1 2 3 4 | # tar -jxvf Python-2.7.1.tar.bz2 cd Python-2.7.1 ./configure (如不指定 --prefix,默认安装在/usr/local/lib/python2.7) make && make install |
3.设定默认版本
1 2 | mv /usr/bin/python /usr/bin/python24 ln -s /usr/local/bin/python2.7 /usr/bin/python |
好的,这里开始你的VPS上面的Python就是2.7.1的了,下面就开始我们的正题咯~首先我们要准备的东西如下:
1.kindlereader
https://github.com/jiedan/kindlereader
这个是用来抓取Google Reader的一个小程序,Python写的,git管理,可以直接在VPS上用命令:
1 | git clone https://github.com/jiedan/kindlereader.git |
但是由于后面有些东西要修改而且还要添加一些内容,所以推荐在本地先同步下来测试好在和后面的文件一并打包上传到vps里面。同步下来的文件这些是有用的:
kindlereader.py 、lib(文件夹)、feed2mobi.py、config.ini(同步下来是config.sample.ini,改名为config.ini)
把上述文件放到一个文件夹里面。
2.Kindle Publishing Programs
下载地址:http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000234621
这个是用来生成图文并茂的kindle的mobi文件用的,必须包含,因为要跑在CentOS上面,所以选择Linux版本下载下来,并且把压缩包里面的kindlegen这个文件放到刚git 获取下来的 kindlereader 文件夹里面(注意,需要和kindlereader.py同目录)
到这里,准备工作就好了,下面开始配置工作。
配置工作非常简单,主要就是修改config.ini文件,里面都有中文的注释也不用多讲,我这里就贴官方的sample了~:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | [general] ; 是否自动退出, 1 要, 0 否, 计划任务一般都要自动退出 auto_exit = 0 ; 输出格式,支持 epub 和 mobi,默认为 mobi ; TODO:epub计划中还不支持 output_format = mobi ; 输出 kindle格式的类型: book 或 periodical kindle_format = book [reader] ; google reader 用户名 username = yourname@gmail.com ; google reader 密码,可以不写提示时再输入 password = ; 需要抓取的分类,此项优先于 skip_categories, 仅当此项为空时 skip_categories 设置有效 select_categories = ; 跳过分类,用英文逗号隔开, 例如:label1,label2 skip_categories = ; 是否要标记为已读: 1 标记, 0 不标记 mark_read = 0 ; 每个feed中最多抓取条目 max_items_number = 20 ; 排除已读 1 是 0 否, 如果设置为是则为只加载未读条目,反之亦然 exclude_read = 1 ; 每篇文章最多下载图片数数目, -1 为不限, 图片太多可能需要时间很长并且造成mobi过大无法发送 ; 如果下载图片需要kindlegen支持,请确保kindlereader.exe所在目录中包含kindlegen.exe max_image_per_article = 5 ; 邮件发送设置 [mail] ; 是否发送邮件,如果不发送可以直接拷贝 /data/ 中相应文件到kindle: 1 发送, 0 不发送 ; 下载图片一般mobi会很大,建议不要发送邮件了,直接到/data目录拷贝mobi文件至kindle mail_enable = 0 ; 发件人,请使用亚马逊注册邮箱,或你的"Your Kindle's approved email list"中的其他邮箱 from = youremail ; 亚马逊提供的投递邮箱地址,注意 @free.kindle.com只能投递到wifi, @kindle.com可以投递到3G但要收费,也可以填写一个其他邮箱地址,由该邮箱转发到你的kindle邮箱地址 to = "name"@free.kindle.com ; smtp服务器地址可以使用gmail的smtp服务器 host = smtp.gmail.com ; smtp服务器端口, 不加密一般为 25, 加密一般为 465 port = 465 ; smtp服务器是否需要 ssl: 1 需要, 0 不需要, 请根据你使用的smtp实际情况选择 ssl = 1 ; smtp服务器需要认证时请填写下面两项,任何一项不填写则认为你的smtp服务器不需要认证 username = password = |
这里还有一个小小的修改,因为我们是在vps上面做计划任务,所以不管程序执行结果如何我们都是希望程序自动退出的,这样就不需要人工干预了。所以,对于kindlereader.py这个程序,我们还需要修改一点点代码。
第731~737行原来是这样的
1 2 3 4 5 6 7 | try: if self.config.get(section, name).strip() in ['1', 1]: auto_exit = True else: auto_exit = False except: auto_exit = False |
修改为
1 2 3 4 5 6 7 | try: if self.config.get(section, name).strip() in ['1', 1]: auto_exit = True else: auto_exit = True except: auto_exit = True |
好了,到此我们就完全配置好了,之后就是把所有文件上传到服务器某个目录下面,比如/home/kindle/这个目录
然后写这样一个脚本文件:
1 2 3 | #!/bin/sh cd /home/kindle/ python kindlereader.py |
保存为start.sh 赋予执行权限
1 | chmod a+u start.sh |
然后修改cron任务,执行
1 | crontab -e |
添加这么两行
30 7 * * * sh /home/kindle/start.sh
30 23 * * 0 rm -r /home/kindle/data/
第一条的意思是每天7点半给我推送,第二条是每周日23点30分删除掉之前的所有data(这个文件夹里面放的都是这周产生的缓存文件)
至此一切完美,睡觉去吧。。。然后第二天早上你的kindle里面就有推送过来的东西咯~
723 views
最近几天,过的还算充实,学了不少东西。
比如为了写胶片摄影小助手,不得不引入sqlite数据库,然后把sql语句复习了遍。终于有了现在的0.5版本,还不错,主要功能都有了,详情可以去这里下载
http://www.zerob13.in/photographyhelper/
然后呢,就是编程空闲时间,除了和上网和人胡扯胡扯求交往求勾搭神马的以外,还顺便拼了张大图。就是上次去拍渔民的全景。
本来我是很少用非常规画幅的照片的,不过,偶尔拼贴一下,也是不错的么:O
21 views
发布页地址:http://www.zerob13.in/photographyhelper/
这是一个帮助那些玩胶片的摄影师的一个实用的小工具
通过输入现场的数据,计算出较适合的快门速度,方便摄影师估测曝光
洗胶片的时候总是把握不好时间,有了这个小小的定时器,这些都不是问题了:)
正在开发中的功能:
57 views

288 views
Arduino是什么?
不知道自己google去,简单的说就是一个给我这种嵌入式完全不懂的文盲来做机器人之流的电子小玩意的平台,开发很简单,就是类似与c语言的语法,上手极快,关键是还可以通过一定的手段和Andriod联动。
好吧,这次和Andriod无关,只是我突发奇想罢了。我一直希望有个小屏幕可以监视我的系统状态,比如CPU占用,内存占用等等。可惜最便宜的usb屏幕也要1000多块,太贵了,不实惠,于是就萌发用Arduino自己做一个。
设备很简单,就是一块Arduino的板子,一块LCD1602屏幕,一台MAC。我就只做了一个简单的CPU占用的东西,如图:
先说说我的思路吧,首先从Mac上通过一个程序读取到CPU占用率,然后通过串口发送到板子上,板子上缓冲一下,再输出到LCD屏幕。流程非常简单。不过问题还是蛮多。
首先,怎么读取CPU占用率?
我先是打算用Cocoa的系统函数来调用,查了半天Mac的资料后果断放弃,太复杂了,而且我Object-c又不是很熟悉。之后的想法是打算利用shell程序来完成,通过C和shell中的top命令交互来实现。这里有个小插曲,因为Linux下面其实读取这些可以直接去/proc/这个虚拟目录下读取,但是Mac这类系统是没有这个虚拟目录的,所以只能用top,而且Mac的top函数的参数又和Linux之类的GNU的top不同。总之折腾了很久,才有了下面这句销魂的shell命令
1 | $ top -n0 -l1 |
啥意思?很简单,就是不要显示进程,top执行一次就自动退出,就那么简单。至于为什么可以达到这样的效果,请有mac或者别的BSD系统的同学man top一下就好。
有了这个就方便的多了,c语言部分去掉串口通讯的就只很简单的一部分了,就是调用shell函数,返回,字符串处理,这几个问题。串口通讯的代码早就很熟悉了,最近一直开发这种东西(其实python下面串口通讯会简单的多,不过我比较熟悉C,所以还是选择了C)
关键代码如下:
1 2 3 4 | FILE *fp; char a[256]; fp=popen("top -n0 -l1","r"); fgets(a,sizeof(a),fp) |
之后的过程势如破竹,Arduino平台上的更加容易,就是简单的读写罢了。直接上代码就好:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #include <Wire.h> #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x27,16,2); byte line = 0; // track which line of the display we are on void setup(){ // set up the LCD's number of columns and rows: lcd.init(); lcd.backlight(); // initialize the serial communications: Serial.begin(9600); lcd.setCursor(0,0); lcd.clear(); } void loop() { char input; while(Serial.available() > 0) { input = Serial.read(); switch(input) { case 0: // line feed lcd.clear(); break; default: if(input>31) lcd.print(input); } } } |
最后再上一个图~哈:
507 views
首先么,这是个人风格,完全不是权威之说。
第二,记录下来只是感觉自己这样蛮舒服,分享而已。
第三,别拿某为谭姓叫兽的文章来说事情,不解释。
第四,这里的 C 语言不是狭义的指 C 这门语言,也包括 C++,object-c,甚至 Java 等类似与 C语法的语言
────────────────────────────────
好了,下面进入正文。比较琐碎,所以就想到什么讲什么了。
先说说一个判断 0 的问题吧,或者称为判断空值。一般空值常规的来思考分那么几种,NULL,0,0.0 以及 false(可能还有别的,但是常规就这些了,所以就讲这些)。那么这些分别有什么区别呢?
首先说说,写判 0 的风格是为了什么,因为 C 语言可以直接用这么一句话来表示几乎所有的空值
if(!a){}
那么,我要把判 0 的语句分开写,就是为了区别变量的类型,方便阅读代码
倒过来讲,先解释 false 的变量,一般这个变量都是布尔型的变量,那么这个变量就两个值,真或者假。所以我一般选择上面那种
if(!a){}
的方式来表示这个变量为假的时候执行什么。理由吧,个人偏好,也有一点认为,!作为一个逻辑运算符,而布尔是逻辑变量,所以凑在一起刚刚好。
然后是 0.0,这一般指 float 或者 double 的变量,这种变量的一个特点就是不精确。如果你直接用
if(a==0.0){}
之类的方法来表述,可能会出现不可意料的问题。所以这里我也选择一种比较流行的处理方法,就是让一个实型变量和一个极小的误差值 EPS 做比较。比如如下代码:
#define EPS 1e-9
if(fabs(a-0.0)
就是这种方式,对于一个实型变量,最好把相等的比较转化成为大于小于的比较,原因么,不赘述了,学过组成原理就知道了。
整数变量不多说,最常规的方法
if(a==0)
{}
然后是指针一类的,空值为 NULL 的,大家都知道 NULL 就是 0,但是书写的时候,还是最好把 NULL 写上了,这样可读性大大的增加。例:
if(a==NULL)
{}
判断0的问题大约就想到那么一些,然后说说几个小点。
第一个是一个规范问题,一般很多人都喜欢把函数声明和实现都放在一起。特别是类的成员函数,别的函数也一样。其实这个习惯不是很好,C语言也好,C++ 也好,都分为 .h 和 .c(.cpp) 两种文件,一般 .h 文件里面放声明,.c 文件里面放实现,包括成员函数。这个主要是方便别的利用你代码的人方便,不需要繁杂的翻看你的整个实现,只要看 .h 文件就可以对你的函数如何使用一目了然。
第二个是一个小细节,就是 void 参数的使用,这里说的不是
void main()
个人是很反对这种写法的,因为 main() 函数作为系统直接调用的函数,你如果不返回一个值给系统,系统怎么知道你的程序是正常还是不正常的结束的?个人感觉,我很反感用 void 来声明 main() 函数。
那么,这里的 void 指什么呢?就是指没有参数表的函数,希望在函数的参数表里面填写一个 void 原因吧,难说,这样写的确我说不上特别的好处,但是感觉会舒服很多,可能就是一个个人偏好吧。,原因是,加了void后,这个函数就被限制成为不能传入任何参数的函数了,如果你强行传入参数,编译会失败。如果不加在 C语言会认为这个函数可以传入任何参数的函数,区别还是很大的。(感谢蔡大牛提醒)。
int GetOne(void)
{
return 1;
}
第三点 就是解释一下 char* strcpy(char*,char*); 这个函数的返回值,然后抛砖引玉的来说说返回值的重要性。这里也许有些朋友会费解,明明 strcpy 的返回值已经给了第一个参数了,为什么还要最后 return 回来?这个不是“脱了裤子放屁──多此一举”么。其实不然,我们看如下代码就明白为什么了。
int length =strlen (strcpy(str,"zerob13"));
这个返回值就是为了这样的灵活性而考虑设计的,所以设计一个好的返回值对于一个好的函数也是非常重要的。
第四点,也是介绍一个神气的东西,叫做空循环。也许很多人学了c语言后一直不理解,为什么还要有个 do-while 循环,感觉有 while 不是已经够了么,这个东西似乎有点多此一举,其实不然。大家都知道,C语言是为了系统而出现的语言,这个 do-while 也自然和这个挂钩了。比如,你总是能够在 linux 的内核里面看到类似如下的宏。
#define DUMP_WRITE(addr,nr) do{memcpy(bufp,addr,nr);bufp+=nr;}while(0)
总所周知,do-while 是先执行后判断循环,这里的while(0)也就是这个代码等价于:
#define DUMP_WRITE(addr,nr) memcpy(bufp,addr,nr);bufp+=nr;
那么,我们为什么要套上这么一个 do-while 空循环呢?显然不行,一个小例子就可以说明,比如这个
if(OK)
DUMP_WRITE(addr,nr);
else
break;
如果,没有空循环,代码会变成这样子。
if(OK)
memcpy(bufp,addr,nr);
bufp+=nr;;
else
break;
然后,就悲剧了。但是,当你加上了 do-while 空循环的时候,整个循环被当作单独的一句语句,这样就可以达到正确的效果,如下:
if(OK)
do{
memcpy(bufp,addr,nr);
bufp+=nr;
}while(0);
else
break;
56 views
贝兹曲线(Bézier curve),貌似学图形学就肯定逃不出这个玩意。。。介绍什么的我也就不浪费笔墨了。直接看wiki好了
http://zh.wikipedia.org/zh/%E8%B2%9D%E8%8C%B2%E6%9B%B2%E7%B7%9A
然后呢,我们图形学课老师上机貌似要做这个,所以就提前写出来了。贴一下,加了详细的注释,也方便自己复习用~
对了,如果你是windows记得改一下头文件位置,这是unix下的头文件。。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | /* * homework1.cpp * OpenGLhello * * Created by zerob13 on 10/13/10. * Copyright 2010 __MyCompanyName__. All rights reserved. * */ #include<stdio.h> #include <stdlib.h> #include<GLUT/GLUT.h> double x[4],y[4];//存放输入的四个控制点 /* *用以绘制曲线的函数 * */ void Bezier(double X0,double Y0, double X1,double Y1, double X2,double Y2, double X3,double Y3) { double xx,yy,X,Y; xx=X0;yy=Y0; glColor3f(1.0, 0, 0.0);//设定曲线颜色 /*for循环绘制曲线*/ for (double t=0.0; t<= 1.0;t=t+0.0001)//步长设置为0.0001,足够了 { X=xx;Y=yy; xx=(1-t)*(1-t)*(1-t)*X0+3*t*(1-t)*(1-t)*X1+3*t*t*(1-t)*X2+t*t*t*X3; yy=(1-t)*(1-t)*(1-t)*Y0+3*t*(1-t)*(1-t)*Y1+3*t*t*(1-t)*Y2+t*t*t*Y3;//最主要的两个方程,用以计算曲线的点 glPointSize(1.0); glBegin(GL_LINES);//描短直线成曲线 glVertex2f(X, Y); glVertex2f(xx, yy); glEnd(); glFlush(); } } /* *用以显示曲线以及辅助线的函数 * */ void display() { glClear(GL_COLOR_BUFFER_BIT);//清屏 glColor3f(0.0, 1, 0.0);//设定辅助线颜色 glPointSize(1.0);//设定点大小 glBegin(GL_LINES);//画辅助线 glVertex2f(x[0],y[0]); glVertex2f(x[1], y[1]); glVertex2f(x[1],y[1]); glVertex2f(x[2], y[2]); glVertex2f(x[2],y[2]); glVertex2f(x[3], y[3]); glEnd(); glFlush(); Bezier(x[0],y[0],x[1],y[1],x[2],y[2],x[3],y[3]); } /* *主函数 * */ int main(int argc,char ** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowPosition(0, 0); glutInitWindowSize(500, 500); glutCreateWindow("Zerob13's Bezier Demo"); printf("Please input 4 Points:\n"); scanf("%lf %lf %lf %lf %lf %lf %lf %lf",x,y,x+1,y+1,x+2,y+2,x+3,y+3); glutDisplayFunc(display); glutMainLoop(); return 0; } |
76 views
今天下午没课,正好想起一个比较蛋疼的事情可以做,就是玩c语言的main函数递归。
首先还是说一下我的编译环境,哪些用m$的c语言编译器的朋友可以忽略这个文章了,放心吧,正常情况下是编译不通过的。。。
我的gcc版本是4.2.1。
先贴上代码~
1 2 3 4 5 6 7 8 9 | #include<stdio.h> #define ____ int #define _o_ double #define _O_(x) printf("%c",x) #define ___(x) 1.0+1199.0*x/12.0-799.0*x*x/24.0+55.0*x*x*x/12.0-5.0*x*x*x*x/24.0 main(____ __) { _o_ _;if(!__)main(1);else if(__==6)return;else{_=___(__);_O_((____)(_+0.5));main(__+1);} } |
跑出来就是一个不换行的Hello
哈哈,这个代码看着很恶心吧。好吧,让我给你翻译一下~如果我把上述代码的define还有一些变量整理一下,那就是这样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #include<stdio.h> int main(int argc) { int x; double ans; if(argc==0) main(1); else{ x=argc; if(x==6) return; else{ ans=1.0+1199.0*x/12.0-799.0*x*x/24.0+55.0*x*x*x/12.0-5.0*x*x*x*x/24.0; printf("%c",(int)(ans+0.5)); main(x+1); } } } |
现在看明白了么?
关键就是这句
ans=1.0+1199.0*x/12.0-799.0*x*x/24.0+55.0*x*x*x/12.0-5.0*x*x*x*x/24.0;
这个通项正是有穷数列72,101,108,108,111的通项。那么我是如何得到这个表达式的呢?
很简单,用多项式的拉格朗日插值公式就可以解决这个问题。
先把公式贴上来。

至于这个公式是怎么推导出来的,你可以看看这篇论文,讲解的很详细,这里就不复制过来了,哈哈
http://www.lw23.com/pdf_d659df85-fb38-47e6-ac02-147a12d2bab3/lunwen.pdf
有了这个通项就简单了,只要不断递归main函数,理论上可以答应出任意的函数出来。
ps:我求通项的时候用Mathematica来计算的,毕竟当数据多了,展开是个很麻烦的事情。。。然后又先用python写了个函数验证了通项正确后才改写成c的本身递归模式。囧
165 views