Yodao Blogender
有道又推出一件有意思的服务:博客男女,借此测了一下我的三个博客。
1.http://mu-er.spaces.live.com
Yodao Blogender
有道又推出一件有意思的服务:博客男女,借此测了一下我的三个博客。
1.http://mu-er.spaces.live.com
以前我只承认自己是 “Google 的忠实用户“,不过现在我决定把自己上升为“温和的 Google Fans”。所以呢,博客主阵地也将转移到 Google: http://solrex.blogspot.com ,但 MSN SPACE 仍将保持同步更新。MSN 之所以没有失去我这个用户,应该感谢中国伟大的 GFW。比较易记的: http://blog.solrex.cn 会一直指向我主博客,谢谢。
唉,放弃原来的博客也是有点舍不得,在我的苦力经营下日点击量已经趋近 40,虽然大部分是 google 和 baidu 带来的,不过,这些数字又有什么用呢?后悔当时为博客选择域名不谨慎,其实,每个人都不应该把自己的幸福寄于他人,理智的人应该遵从 Adam Smith 的指导,在不伤害别人的前提下寻求自身利益的最大化。
本人下一个目标是努力争取在研究生阶段进入 Google 中国做实习生,我知道自己现在和 top coder 还相差很远,今后会努力提高在数学和算法领域的知识水平。我将不放过任何一个进入 Google 的机会,朋友们有任何和 Google 实习有关的消息都请 email 我一份,我会非常感谢。
真郁闷,真郁闷,真郁闷啊!!!
NND一个 BFD library 里的函数太变态了,前面 abfd 的地址还保存在 $ebx 中,紧接着一句调用函数的参数中 abfd 地址就变成 $ebi 中的了,这 TNND 是怎么优化的啊,还出现在特定的 target 中,发指发指,要崩溃了。
PS:发泄帖,就想骂两句,莫回,下次删。
公司牛了就是不一样。前些天在网上申请了 Intel 的几本 manual ,寄到手里才发现人家真实诚,六本书,11磅,沉甸甸的,摞起来半尺。一分钱没要,FedEx 过来,还先给我发了封 eMail,我这两天就 track 着它的路径等过来了。
Jan 26, 2007 10:18 AM Delivered BEIJING CN
8:52 AM At local FedEx facility BEIJING CN
8:44 AM On FedEx vehicle for delivery BEIJING CN
Jan 25, 2007 7:24 PM Int’l shipment release BEIJING CN
Jan 24, 2007 8:51 AM Departed FedEx location ANCHORAGE, AK
8:06 AM Arrived at FedEx location ANCHORAGE, AK
2:37 AM Departed FedEx location MEMPHIS, TN
12:40 AM Arrived at FedEx location MEMPHIS, TN
Jan 23, 2007 8:12 PM Left origin DENVER, CO
6:07 PM Picked up DENVER, CO
12:00 AM Package data transmitted to FedEx
同样是做芯片的,我们公司什么时候能让人免费申请 Manual,免费申请样片,那就牛了。
日子过得重复,也没什么好写的。GDB 的 target dependent 写得差不多了,下面准备把 BFD 的 Elf back-end 完全移植到我们的 CPU 上。原来虽然也有,但只是对 MIPS 做了修改,而没有定义新的 target。然后把 disassembly 功能实现了,再根据 Dwarf2 debug information 把 frame cache 的事情解决了,整个工作也就完成了。其实早就可以做的,但是因为还正在发展中,很多因素不确定,就像现在连 magic number 还没有,只好慢慢来了。反正我又不急,学什么都是学,进度压力小我自己支配的时间就多些,可以多消化一些。
等做完了再写几篇日志记录一下,坚持我的知识共享原则,而且这方面中文的内容也少,台湾做了不少工作。
Copyright © 2005-2007 Solrex Yang. All rights reserved.
最近心情很 low,从愤青态度和在百合上和别人讨论问题的情绪化就可以看出来。再加上因为某些原因休息不好,居然在导师给我讲 simulator architecture 的时候感到一阵头晕目眩,差点晕倒,只好请求他坐下给我讲。又该调整自己了。
CPP版上老在讨论错误的程序奇怪输出,而且在公司也做编译器的测试,我也找一些例子小研究一下,这个例子是错误的去掉const属性带来的后果。
Program:
#include <iostream>
using namespace std;
int main()
{
const int a = 1;
int *p = const_cast<int*>(&a);
*p = 2;
cout << "value a=" << a << endl;
cout << "value *p=" << *p << endl;
cout << "address a=" << &a << endl;
cout << "address p=" << p << endl;
return 0;
}
这个程序,从语法上看,没有任何问题(当然,这种用法不提倡 deprecated )。但是输出结果却是这样的:
value a=1
value *p=2
address a=0xbfe9efb4
address p=0xbfe9efb4(depends on machine)
奇怪了,a和p既然指向同一块地址,为什么输出的内容却不一样呢?
在调试的时候发现,在运行完*p=2时,调试器打出的a的地址和p是一样的,而且a和*p的内容都是2。但为什么输出时候会a=1呢?
还是看汇编代码吧,相关部分:
subl $8, %esp
pushl $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
subl $12, %esp
//将直接数1压栈
pushl $1
//栈顶指针减12
subl $12, %esp
pushl $.LC0
pushl $_ZSt4cout
.LCFI7:
//这句是"value a="这个字符串的输出函数,char
call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
//栈顶指针增加20
addl $20, %esp
pushl %eax
//这句是a的值输出,int
call _ZNSolsEi
addl $20, %esp
pushl %eax
.LCFI8:
//这句是输出的endl
call _ZNSolsEPFRSoS_E
addl $16, %esp
看完之后,有人会问了:怎么没看到a在哪里输出的啊,那么请你注意上面“栈顶指针增加20”这个注释,增加20之后它到哪里了?注意上面就会发现,前面有两次压栈,指针减4*2=8,一次指针减12,然后再加上20,这时候栈顶指针就到了“将直接数1压栈”下面了,显然进入输出函数后,它会从栈中找输出某个值,这里显然是数字1。
这就是为什么会输出a=1了,因为编译器根本没去找a的值,因为a是const int型,编译器认为它的内容不会变,所以干吗非得去内存中找啊,多麻烦,直接把值放到code里输出不就行了!
从某种意义上来说,const 相当于宏定义,但是程序为变量分配了存储空间,这样就可以进行类型检查。所以说很多 C++ 书籍作者提倡用 const 来代替 define,而且反对对 const 做 cast。就算要做 cast,也请尽量使用 C++ 的 cast 而不是 C 的类型转换。
恶劣的编程风格会带来不可预测的后果。类型转换之类的C留下来的习惯在编写高效率的程序时候是很有用的,但一定要确保知道采用这种方式会产生什么结果再去使用。对于那些 undefined 和 deprecated 的东西可以去利用,但是脑子中一定要有 idea。
Copyright © 2005-2006 Solrex Yang. All rights reserved.
在进入正文之前先说几句题外话:最近有个新闻很火,是21岁才女被聘为跨国公司副总裁的事情。且不说新闻内容的真实程度有多少,其实我看到新闻时候就对里面的东西产生怀疑了,但是有几点是无法否认的:人家确实被聘为副总裁了,这点在Topcoder的网站上可以得到证实,至于这个副总裁手下有几个人,和事实没关系;人家确实有过三项发明专利,至于专利内容,和事实也没关系;人家确实是ACM主席成员,至于这个ACM和ACM/ICPC的缩略语的区别,和事实也没有关系;还有人家获得过29届ACM 国际大学生程序设计竞赛亚洲总决赛银牌,至于这个奖牌含金量有多高,和事实也没关系。
这几点已经让我崇拜有加了,Topcoder不是什么太牛的公司,但是起码也不烂;发明专利可能不是很高科技,但是我没有一个;ACM/ICPC主席团没有ACM主席高级,那不是废话吗?谁不知道啊,ACM/ICPC和ACM奖差远了,但是交通大学获奖后不也经常缩写吗?我连校ACM队都进不了,就别歧视人家奖牌了。对于新闻的炒做大家心里都有底,没有必要非得整出来《神话通常是由于低素质产生的》这种无耻文章来做所谓“揭露”,你可以写事实,但不要用这种口吻。还有一些别有用心的人拿所谓高考中考成绩说事,有意思吗?人家不容易。
读心理学专业能把计算机学那么好,还兼职干过那么多事情,能力啊,相比而言真让我受打击!更打击我的是今天在小百合上看到有认识的人说吴莹莹的男朋友是Stanford的王颖(2006 google 全球编程挑战赛亚军)............我只能 keep 无语了。
好了,下面进入正题,今天在小百合上和别人争了一番,争论是争论,总得留下点东西不,不然白费口舌了。
Program 1:
#include <stdlib.h>
int main(void)
{
char a[] = "abcd";
char b[] = "efg";
strcpy(b, "efghi");
printf("a=%s
", a);
printf("b=%s
", b);
return 0;
}
gcc build and run:
a=i
b=efghi
Program 2:
#include <stdlib.h>
int main(void)
{
char a[] = "abcd";
char b[] = "efgh";
strcpy(b, "efghij");
printf("a=%s
", a);
printf("b=%s
", b);
return 0;
}
gcc build and run:
a=abcd
b=efghij
ANSI C/ISO-IEC-9899-1999 在 7.21.2.3 The strcpy function 章节中指出
7.21.2.3 The strcpy function
Synopsis
1 #include <string.h>
char *strcpy(char * restrict s1,
const char * restrict s2);
Description
2 The strcpy function copies the string pointed to by s2 (including the terminating null
character) into the array pointed to by s1. If copying takes place between objects that
overlap, the behavior is undefined.
Returns
3 The strcpy function returns the value of s1.
所以上面的两个程序都有错误,但是我们这里只分析为什么会导致奇怪的输出。
第一个例子,运行时内存的内容是这样的(请注意方括号中的内存单元内容,冒号前是内存地址):
a,b赋完值:
0xbffd7778: 0xbffd7798 [0x00676665] [0x64636261] 0x006dff00
执行完strcpy:
0xbffd7778: 0xbffd7798 [0x68676665] [0x64630069] 0x006dff00
第二个例子:
a,b赋完值:
0xbfef6ca8: 0xbfef6cb8 0x080482b5 [0x68676665] 0x00000000
0xbfef6cb8: 0xbfef6cd8 0x0804843a [0x64636261] 0x006dff00
执行完stycpy:
0xbfef6ca8: 0xbfef6cb8 0x080482b5 [0x68676665 0x00006a69]
0xbfef6cb8: 0xbfef6cd8 0x0804843a [0x64636261] 0x006dff00
奇怪输出的原因找到了,是因为第一个程序把a,b放到连续的空间里导致了覆盖。那么为什么第二个程序中a,b不放到连续空间中呢?
再看看汇编代码,只关注相关部分:
第一个例子:
.LC1:
.string "efg"
...
movl .LC1, %eax
movl %eax, -28(%ebp)
...
第二个例子:
.LC1:
.string "efgh"
...
movl .LC1, %eax
movl %eax, -40(%ebp)
movb .LC1+4, %al
movb %al, -36(%ebp)
...
哦,这时候我们可以看到,由于efg只有三个byte,没有超过计算机的字长,所以eax容纳了它结尾的�,而且可以把b放到一个内存单元(word)中去,所以编译器就把a,b挨着放了。
而efgh有四个byte,一个内存单元(word)不能容纳全部字符串(放不下结尾的�),所以编译器就多为它预留了一段空间,既然留了,就留大点,就是4个word了。程序输出就变成正确的了。
所以就可以看到为什么没有放到连续空间中了。至于这个预留空间的策略,就不得而知了,那得看编译器的逻辑了。
Copyright © 2005-2006 Solrex Yang. All rights reserved.
quine [名字源于逻辑学家 Willard van Orman Quine, via Douglas Hofstadter] ,指的是一种运行后生成自身源代码拷贝的程序,也叫self-reproducing programs(自我复制程序)。今天无意中搜到 Ken Thompson 的一篇经典演讲 Reflections on Trusting Trust,好奇心下就小探索了一番。
answers.com 上有一个c语言的例子:
char*f="char*f=%c%s%c;main(){printf(f,34,f,34,10);}%c";main(){printf(f,34,f,34,10);}
运行之后直觉得好奇,为什么它能把自身源代码输出啊?想着可能是某种特技,结果在Linux下,在Win下编译反编译调试比较汇编代码,折腾了半天。到最后看发现实在太繁,还是静心读一下源代码吧,才发现,原来如此的简单:
printf中的第一个参数f,就是格式化字符串,34就是双引号的"ASCII码,10就是换行符的ASCII码,很显然f就是一个用它自身去格式化自身的字符串而已。技术看起来简单,但是要实现完全相同的代码输出,在编排上还真得下一番工夫。
Gtalk上碰见yutian,给他发了过去,还打赌他肯定看不出来运行结果,现在才发现自己幸亏没真赌上。:D,不过人那,还是感情的动物啊,都有一种习惯性思维,看到貌似复杂的东西自己就先限制住思路了,结果他也没看出来,哈哈。
看来,把复杂的事情搞简单,还真不是件容易的事儿。做人,还是简单点好,遇事想那么多干吗,给自己找烦恼。
PS:
谁要对 quine 还感兴趣,这里 有几乎所有语言的一种 quine 实现,这东东好象对写恶意代码很有用啊。
Copyright © 2005-2006 Solrex Yang. All rights reserved.
这篇是要赞一下GoogleReader的。今天忽然发现这个功能,太方便了。以前用RSS客户端,在重装系统时候忘记了备份feeds,订阅了那么多人的博客,一下子就没了,要不是幸亏有次把全部feeds的OPML文件上传到了gmail信箱里,就损失惨重了,不过还是少了很多增量更新的。现在有了googlereader,再也不担心丢失feeds列表了,嘎嘎嘎嘎。Google出来的每一项功能总让人耳目一新,真是赞。
最好的是GoogleReader还可以订阅到无法访问的博客,就比如blogspot.com(这几天被GFW禁了)上的博客,不知道这个功能是因为blogspot.com属于google的缘故,还是Reader的订阅本身就是Google服务器的行为,不管你客户端是否能访问该博客站点,因为Google的服务器肯定能访问那。
一个截图,哎,简直跟RSS客户端没什么区别呀!(BTW:这截图用的是Firefox Save As Image插件,方便。)
买了一个域名,四年。现在还没有主机空间,先定义了几个域名转向:
http://solrex.cn和http://www.solrex.cn都指向Google Page:http://solrex.googlepages.com。
http://blog.solrex.cn指向Live Space:http://mu-er.spaces.live.com。
哈哈,以后记个人主页和博客地址都方便多了,不用记那么长了。不过各位要注意是.cn中国域名,不是.com啊。.com让一个美国人注走了,但好象一直都没用,所以输入solrex.com什么也打不开。
Administrative Name ............. Phil Griffith
Administrative Organization ..... Private
Administrative Address .......... 194 W. 24th St. Holland, MI 49423 US
Administrative City ............. Holland
Administrative Province/State ... MI
Administrative Postal Code ...... 49423
Administrative Country Code ..... US
Administrative Phone Number ..... 616-395-9397
Administrative Email ............ peesed_off@hotmail.com
Expiration Date ................. Thu, Mar 15, 2007
源于Google的一道笔试题:给出两个升序排列的n维整数数组,求这2n个数中的第n大数。(算法导论:Exercise 9.3-8)
笔试的时候有一个想法,但是写的很草率,回来仔细想了下,把它写出来。我想这个应该是别人已经做过的东西,但我也不知道怎么查,第一次自己写查找算法,在我这就把它叫做“顺序存储双有序列的二分折叠查找算法”吧。其实这个算法好象没什么实际作用,有序列的查找嘛,计算量都不大。
算法描述太累赘了,就写个基本思想吧:把每个数组尾部的指针向前移动n/2个数,然后比较这两个数的大小,如果a中的大,就把这个数与b从尾部开始比较直到某个数小于它,这样,第n个数肯定不在两个指针后面,把两个指针后面的数字个数加起来,作为count。n-count就是执行下次类似查找的n。主要工作量节省在每次跨n/2上。至于最后如何选择第n个数,需要分析一下具体情况。
int search4n(int *a, int *b, int n)
{
int *p,*q,*p1,*q1,range;
p = a+n;
q = b+n;
if( a[0]>b[n-1] ) return a[0];
if( b[0]>a[n-1] ) return b[0];
while(n>1)
{
range = ( n+1 ) / 2;
p1 = p-range;
q1 = q-range;
if( *p1>*q1 ){
n -= range;
p = p1;
q--;
while( *q>*p1 ){
q--;
n--;
}
}
else{
n -= range;
q = q1;
p--;
while(*p>*q1){
p--;
n--;
}
}
}
if( n==0 ) return *p > *q ? *p : *q;
else if( n==1 ) return *(--p) > *(--q) ? *p : *q;
else return 0;
}
其实这个算法可以推而广之到任意两个有序列的第n大数查找,见下面。但是为了控制指针越界需要浪费一些判断语句,其实有很多判断语句只有在足够接近边界时候才起作用。这算法也可以推广到链表,但似乎效率要低些。
int search4n(int *a, int *b, int an, int bn, int n)
{
int *p, *q, *p1, *q1, range;
p = a+an;
q = b+bn;
if( a[0]>b[bn-1] ) return n <= an ? a[an-n] : b[an+bn-n];
if( b[0]>a[an-1] ) return n <= bn ? b[bn-n] : a[an+bn-n];
while( n>1 ){
range = ( n+1 ) / 2;
p1 = p-range>a ? ( q==b ? p-n : p-range) : a;
if(q1==b && *q1>*(p-1)) return *(p-n);
q1 = q-range>b ? ( p==a ? q-n : q-range) : b;
if(p1==a && *p1>*(q-1)) return *(q-n);
if( *p1>*q1 ){
n -= (p-p1);
p = p1;
q--;
while( *q>*p && q>b ){
n--;
q--;
}
*q>*p ? q : q++;
}
else{
n -= (q-q1);
q = q1;
p--;
while( *p>*q && p>a ){
n--;
p--;
}
*p>*q ? p : p++;
}
}
if( n==0 ) return *p<*q ? *p : *q;
else if( n==1 ) return (p1==a || q1==b) ? ( p1==a ? *(--q) : *(--p) ) : ( *(--p)>*(--q) ? *p : *q );
else return 0;
}
算法复杂度:
时间复杂度,显然最优状况下,比较只需要常数次(如果比较次数不包括各种边界条件的比较);最坏状况下,比较主要在中间那个while双循环,假设n对应的比较次数为f(n),则f(n)=1+k+f(n-[(n+1)/2]-k),其中1=<k<[(n+1)/2];f(1)=1;f(2)=2。则f(n)的最大值就是最差情况下的比较次数,我估计不出来,所以无法说它的平均算法复杂度了,但由f(n)的下降速度可以看出比较次数是介于log(n)和n之间的,究竟是多少数量级不太清楚,回头再想想怎么估计平均复杂度,应该是需要考虑k的分布。
空间复杂度,需要4个指针空间和1个整型变量空间,常数级。
我估计这个算法应该不是最优的,尤其对题目来说这种算法肯定不是最优的,因为求中位数的话可以更简单,但它可以推广到任意两有序列的查找,也算是一种途径。不过我觉得这个算法里可能还有漏洞,只是我没检查出来,也该有优化的可能,以后再慢慢想吧。
Copyright © 2005-2006 Solrex Yang. All rights reserved.
接着前上面的“静态主页使用Ajax”,发现同样的网页Ajax请求返回内容,在Opera中就能显示,而在IE、Firefox、Netscape里只有本机建的服务器上可以显示,上传到Google Page就无法显示,但是XML文件确实是已经下载下来了,为什么?
示例网页:http://solrex.googlepages.com/index.htm
Copyright © 2005-2006 Solrex Yang. All rights reserved.
数学建模三天,比二年级那次轻松多了,还打了场球,每天睡了五六个小时,不过还是很累,早上把论文交上去以后,倒头睡到下午6点。
还是蛮有收获的,下面是一些经验:
1.使用SQL删除冗余或者重复记录
由于A题给的是5个两万八千多条记录的Excel表,为了处理方便,我们都导入到Access数据库里,使用SQL查询语言处理数据。里面有一些重复的记录,但不是全部重复,大概在十几个字段里有几个不会重复,而且不能全部删除,必须得保留一条。 由于牵涉的是数据的纵向比较,以前没有做过,不知道怎么写,从网上查查,也没有查到合适的方法,后来自己琢磨出来一种方法可以删除冗余数据:
先从表里查出来哪些是冗余记录,查出重复字段,并且取重复记录主键字段的最小值,加到重复字段里存到临时表temp1中:
SELECT min(ID) AS tid,问卷编号 AS t1,Q2e AS t2,Q2g AS t3,Q2h1 AS t4,Q2j AS t5 INTO temp1 FROM 2001 WHERE Q2d=1 GROUP BY 问卷编号,Q2e,Q2g,Q2h1,Q2j HAVING count(ID)>1;
再从表里把所有冗余记录选出来,存到临时表temp2中:
SELECT * INTO temp2 FROM 2001,temp1 WHERE 问卷编号=t1 AND Q2e=t2 AND Q2g=t3 AND Q2h1=t4 AND Q2j=t5;
把主键字段在临时表temp2中(表明是重复记录),且不在temp1中(表明是冗余记录)的记录删除。如果只是删除重复数据的话,就把后面一个判断去掉就可以了。
DELETE * FROM 2001 WHERE ID IN (SELECT ID FROM temp2) AND ID NOT IN (SELECT tid FROM temp1);
其实不同的数据库软件有不同的方法,因为各个数据库有自己的SQL语言支持,有的数据库定义了自己的SQL语句或者特征字段,可以非常容易的删除重复字段。由于ACCESS对SQL的支持比较弱,既然上面的方法对ACCESS都可以适用,应该能应用于很多数据库软件。
2.Java连接ACCESS的方法
因为数据的处理语句太多,而且近似,用手工的方法太笨也太慢,我就写了一个JAVA程序来自动进行查询。还是应了那句话,磨刀不误砍柴工。
下面是JAVA连接ACCESS的设置:
try{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
String DBUrl="jdbc:odbc:driver={Microsoft Access Driver (*.mdb)};DBQ=dataBaseAddress";
Connection con=DriverManager.getConnection(DBUrl,"","") ;
Statement stmt=con.createStatement();
} catch (Exception e) {
e.printStackTrace();
}
接着就可以像别的数据库一样执行查询了,但是最奇异的是我发现ACCESS不接受JAVA程序里带转义双引号的查询语句,查询语句里只能使用单引号。
其实Ajax技术并不是只有那些动态页面可以使用,在静态页面里也可以有很大用处,当然,这里面只牵涉到了静态xml文件,而不可能是动态生成的了。
在我的页面里,由于主要是放些文章,是采用的这样的方法,xml文件的结构是:<solrex_shuffling>
<article>
<title><![CDATA[]]></title>
<info><![CDATA[]]></info>
<content><![CDATA[]]></content>
</article>
</solrex_shuffling>
把所有的文章都放到一个xml文档里,用CSS控制显示格式,用Ajax技术控制显示内容。本来是想一下子读取出来所有的节点内容,放到变量里,这样使用起来就不用再去访问服务器了。对于小型的应用,这样做是可以的,但是对于像文章这种长字符串存储到变量里是不可行的。这样就只好使用一个笨方法,每次去request这个xml文件,使用全局变量来控制取出的内容。
IE和Firefox在这方面又表现出了不同,当把xml文件取回来的以后,IE就不会去再访问服务器了,只使用缓存里的文件,速度比较快。但是Firefox是会再去访问,取回最新的文件。其实可以对文件的访问进行控制,让浏览器只访问更新的文件,但是这又得是服务器端和网页程序配合下才可以,对于静态页面来说,就不用考虑那么多了,如果访问量在一定范围内的话,其实速度还是可以的。而且Firefox可以在本地执行request,不需要访问服务器,而IE就不行。
IE和Firefox在处理xml内容的时候也会有不同,例如取出底层节点内部文本的时候,IE是用node.text,而Firefox是用node.textContent。我不知道有没有一个统一的接口,我是在调试JS代码的过程中发现的这两个不同,就用我自己的方法实现了,很简单,先判断节点具有不具有node.textContent属性,具有就采用Firefox处理方式,不具有就用IE的处理方式。
还有值得注意的是,Firefox会把xml中两个标签之间的空格和换行符当作是一个节点,而IE不会,所以为了通用性考虑,xml中的标签之间尽量不留空,不要像HTML编程一样为了看清楚格式放很多空白字符。
在节点内部使用<![CDATA[]]>是为了能不让解析器解析里面的内容,比如HTML格式的文本。
在编码过程中我还发现,用Object.innerHTML写入的内容仍然可以被getElementById()方法访问,这样就说明是可以循环嵌套写入代码了。
Sam Stephenson的Prototype JavaScript framework对JS和Ajax开发都是很有帮助的,利用它可以节约很多劳动。
做完以后发现,只用一个htm文件和一些xml文件就可以显示非常丰富的内容,用起来非常舒服。但是发现在我电脑上的本地服务器运行得好好的,上传到googlepage却没办法运行,猜想可能是google禁用了一些javascript脚本。反正至少在google提供的在线HTML编辑的话,一些JS代码是不能用的。
Copyright © 2005-2006 Solrex Yang. All rights reserved.
说明:
cookie是保存在用户计算机上的变量。每次相同的计算机请求该页时,它(计算机)就会发送cookie。通过JS可以建立和检索cookie的值。
格式类似于:User=solrex; expires=Thu,01-Jan-70 00:00:01 GMT; domain=www.google.com; path=/; secure;
cookie使用:
基本的cookie在用户关闭浏览器时会被自动删除,因为通常的域只允许在用户的机器上保留20个cookie.如果希望将cookie保存在用户的机器上就需要设置一个cookie失效的时间,它的格式是一种叫做GMT的特殊格式.
例如:Mon, 27-Jul-2006 00:00:00 GMT
要正确设置GMT不是件容易的事,需要计算好某个日期是星期几.Javascript有一个日期的方法叫做toGMTString可以解决这个问题.下面是设定某个时间的一个例子:var the_date = new Date("December 31, 2008");
var the_cookie_date =the_date.toGMTString();
一旦设置了cookie的失效期,必须在cookie设置里加入这条信息. cookie_name=cookie_value;expires=date
我在使用中发现,FireFox对cookie格式的限制比IE要宽松很多,用IE时,失效日期必须严格的按照GMT格式来写,否则设定日期不起作用或者浏览器根本不接受这个cookie,而FireFox可以接受一些日期格式不是很规范的cookie。
缺省情况下cookie只能被在同一服务器上的同一路径下设置了该cookie的网页读取.例如,如果在"http://localhost/vstock/index.jsp"询问了用户的姓名,可能需要另一个网页中访问它.所以就必须设定该cookie的路径.路径"path"用于设置可以读取一个cookie的最顶层的目录.将cookie的路径设置为最顶层目录可让该目录下的所有网页都能访问该cookie.
方法:在你的cookie中加入path=/; 如果只想让"vstock" 目录中的网页可以使用该cookie,则加入path=/vstock;.假如网站有许多小的域名,例如:"a.localhost","b.localhost" 和"c.localhost",缺省情况下只有"localhost" 域下的网页可以读取该cookie.如果想让"localhost"下的所有虚拟主机都可以读取该cookie,必须在cookie中加入 "domain=localhost" .
我使用的cookie操作函数,有些cookie类使用起来其实并不方便,还有一些缺陷,不如直接用函数:function setCookie(c_name,c_value,c_expiredays,c_path,c_domain,c_secure)
{
var c_expires = new Date();
c_expires.setTime(c_expires.getTime() + c_expiredays*86400000);
document.cookie=c_name+ "=" +escape(c_value)
+((c_expiredays==null) ? ("") : (";expires=" +c_expires.toGMTString()))
+((c_path==null) ? ("") : (";path="+c_path))
+((c_domain==null) ? ("") : (";domain=" +c_domain))
+((c_secure==null) ? ("") : (";secure"));
}
function getCookie(c_name)
{
if (document.cookie.length>0)
{
c_start=document.cookie.indexOf(c_name + "=");
if (c_start!=-1)
{
c_start=c_start + c_name.length+1;
c_end=document.cookie.indexOf(";",c_start);
if (c_end==-1) c_end=document.cookie.length;
return unescape(document.cookie.substring(c_start,c_end));
}
}
return null;
}
function delCookie(c_name)
{
var c_value=getCookie(c_name);
if(c_value!=null)
{
var c_expires = new Date();
c_expires.setTime(c_expires.getTime() - 1);
document.cookie= c_name + "="+""+";expires="+c_expires.toGMTString();
}
}
Copyright © 2005-2006 Solrex Yang. All rights reserved.
虚拟目录优先级问题
当新建一个虚拟目录时,如果是通过在$CATALINA_HOMEconfCatalinalocalhost目录下添加一个xml文件,例如:ajaxlab.xml,内容为:<Context path="/ajaxlab" docBase="D:ajaxlabwebapps" debug="0" privileged="true"></Context>添加后,偶尔系统会自动在$CATALINA_HOMEconfserver.xml中添加一条 <Context path="/ajaxlab" reloadable="true" docBase="D:ajaxlab" />这种情况不经常出现,也不知道是什么原因引起的。当更改相应的虚拟目录时候,就会造成访问错误。似乎server.xml的优先级比$CATALINA_HOMEconfCatalina下的文件高一些。
服务器端Cache
$CATALINA_HOMEworkCatalina下保存有服务器上运行的各个虚拟目录的临时文件,有时候在重新编译类的时候,没有更新的cache会引起一些问题。关闭服务器后,可以完全删除它们,服务器运行时也可以删除,不过正在运行的网页还会自动生成。
方便的话可以写一个批处理文件,比如:rmdir /S /Q workCatalinalocalhost
Log的循环备份分期备份和删除过期Tomcat日志的批处理脚本: del /Q logsak4*
move logsak3*.log logsak4
move logsak2*.log logsak3
move logsak1*.log logsak2
move logs*.log logsak1每隔一段时间执行一次,在服务器关闭时执行,不然move命令不起作用。需先在日志目录下建立四个目录bak1,bak2,bak3,bak4,也可以用条件语句写入脚本中。
Monitor Tomcat的右键菜单问题
当主机上已经注册了Apache Tomcat服务时候,如果服务的启动类型设置为“已禁用”,Monitor Tomcat的右键菜单的"Start Service"和"Stop Service"都会变成灰色不可选,无论此时Tomcat的服务是否启动。把服务的启动类型改为“手动”可以解决问题。
Copyright © 2005-2006 Solrex Yang. All rights reserved.
在JAVA中使用正则表达式
其定义在包java.util.regex里,使用举例: String accountRegx = "^[A-Za-z0-9][\w\.]{1,18}[A-Za-z0-9]$";
Pattern accountPattern = Pattern.compile(accountRegx);
Matcher accountMatcher = accountPattern.matcher(account);
boolean accountMatches = accountMatcher.matches();这样语句比较麻烦,但是编译好后比临时再构造要快。在JAVA中使用正则表达式时,注意的转义,需写为\。
无href属性的A对象的CSS属性问题
在CSS1中,对于无href属性(特性)的a对象,伪类:link,:hover,:active,:visited均不发生作用,而且在CSS1中这几个伪类只能用于a对象。在CSS2中,这几个伪类可以用于其它对象。
在使用中发现,Firefox1.5以上是支持CSS2的,而IE6.0支持不完全。
例如在使用无href属性的a对象时候,鼠标移动到链接上时,在IE里什么都不发生,在Firefox里,鼠标变为选择光标,:hover属性会起作用,即可以变色。
针对这样的问题,可以采用定义a的cursor方法解决,即在样式表中添加上这样一条:
a {
cursor:pointer;
}
此处的cursor不适合用hand,因为浏览器支持不一样,但是用pointer的话,当鼠标移动到链接上时候均能变成手型。
Copyright © 2005-2006 Solrex Yang. All rights reserved.
被这个问题困扰三天了,查了不少资料,写了不少测试,真是痛苦啊。不过总算基本解决,赶紧把方法写下来,留待以后参考。
使用的软件版本:
Tomcat:Apache Tomcat 5.5.12
MySQL:MySQL Server 5.0.16
JDK:J2SE Development Kit 5.0
JRE:J2SE Runtime Environment 5.0
JDBC Driver:mysql-connector-java-3.1.13-bin.jar
别名:
$CATALINA_HOME: Tomcat的安装目录,例如D:serveTomcat 5.5
$APP_HOME:JSP网站工程所在的根目录,例如D:vstock
总问题:
问题一:JDBC驱动到底应该放在哪里?
这个问题网上有很多回答,但是根据我的测试,根本不需要把JDBC驱动放到$CATALINA_HOMEcommonlib目录下,这个目录里面是进行Tomcat的全局配置的。为了程序的可移植和适应性考虑,只需要把JDBC的驱动mysql-connector-java-3.1.x-bin.jar放到$APP_HOMEWEB-INFlib下就可以实现在网站工程的JSP文件和$APP_HOMEWEB-INFclasses下的java bean的class里使用JDBC驱动。
问题二:应该使用哪个驱动?
有很多人不知道,jar文件其实是一种把class文件压缩到一起的一种压缩包。mysql-connector-java-3.1.x-bin.jar里一般包含两个包,一个是com.mysql.jdbc,另一个是org.gjt.mm.mysql。用WinRAR解压后可以发现,前者下面有很多class,而后者下面只有一个Driver.class,怀疑后者应该是为了兼容而设计的,而具体实现仍是在前者的包里实现,故虽然说两者使用结果上无甚区别,但最好还是用com.mysql.jdbc.Driver。
问题三:如何进行MySQL数据库的连接?
下面给出两个例子,分别是只在JSP文件里使用数据库连接和在class里使用连接。先是测试数据库的建立,后是两个MySQL数据库连接测试源文件。运行以后均输出一句话:Evil:Japanese。
1.测试数据库的建立(大小写无所谓):
进入mysql,执行以下语句:
drop database IF EXISTS datasource;
CREATE DATABASE datasource;
use datasource;
CREATE TABLE user(username varchar(50) NOT NULL,password varchar(50),PRIMARY KEY (username));
INSERT into user(username,password) values("Japanese","evil");
2.JSP文件里连接数据库,测试页面testDB.jsp,位置$APP_HOME下
testDB.jsp内容:
<%@ page contentType="text/html;charset=GB2312" %>
<%@ page import="java.sql.*" %>
<%@ page import="javax.sql.*" %>
<%@ page import="javax.naming.*" %>
<%@ page session="false" %>
<html>
<head>
<title>test</title>
<meta http-equiv="Content-Type" content="text/html;charset=gb2312">
<link href="vstock_style.css" rel="stylesheet" type="text/css">
</head>
<%
String driverName = "com.mysql.jdbc.Driver";
String userName = "MySQLuser";//你的MySQL用户名
String userPassword = "Password";//MySQL密码
String dbName = "datasource";
String tableName = "user";
String url = "jdbc:mysql://localhost/"+dbName+"?user="+userName+"&password="+userPassword;
try{
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection conn = DriverManager.getConnection(url);
Statement state = conn.createStatement();
String strSql="select * from user";
ResultSet rs=state.executeQuery(strSql);
while(rs.next()){
out.print("Evil:"+rs.getString(1));
}
out.println("True");
}catch(Exception e)
{
out.println("Error");
}
%>
</head>
<body>
</body>
</html>
3.class里连接数据库,测试文件testDB.java,位于$APP_HOMEWEB-INFclassesJavaBean目录下,测试文件test.jsp,位于$APP_HOME下。
testDB.java内容:
package JavaBean;
import java.sql.*;
public class testDB{
public testDB(){}
String driverName = "com.mysql.jdbc.Driver";
String userName = "MySQLuser";
String userPassword = "Password";
String dbName = "datasource";
String tableName = "user";
String url = "jdbc:mysql://localhost/"+dbName+"?user="+userName+"&password="+userPassword;
public ResultSet getConn()
{
ResultSet rs = null;
try
{
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection conn = DriverManager.getConnection(url);
Statement state = conn.createStatement();
String strSql="select * from user";
rs = state.executeQuery(strSql);
}
catch(Exception e)
{
System.out.println("Error");
}
return rs;
}
}
test.jsp内容:
<%@ page contentType="text/html;charset=GB2312" %>
<jsp:useBean id="test" scope="page" class="JavaBean.testDB"/>
<%@ page import="java.sql.*" %>
<html>
<head>
<title>test</title>
<meta http-equiv="Content-Type" content="text/html;charset=gb2312">
<link href="vstock_style.css" rel="stylesheet" type="text/css">
</head>
<%
ResultSet rs = test.getConn();
while(rs.next())
{
out.print("Evil:"+rs.getString(1));
}
%>
<body />
</html>
问题四:可能的错误类型
一定要检查变量名、变量类型、函数的拼写,大小写,函数的括号,包的包含关系,数据库的路径。不要从网页上直接拷贝,最好手动输入,要检查全角的空格。唉,教训惨重啊!
结论:用以上的方法,可以把JDBC驱动只放到用户的网站工程里,移植时只需要在Tomcat里建立一个虚拟网站目录和把MySQL数据库拷贝到服务器的数据库目录下即可,不需要再有其他配置。
Copyright © 2005-2006 Solrex Yang. All rights reserved.
看JavaScript到现在
睡不着
随便晃晃别人的space
给自己的加上了天气预报的自定义HTML代码
在最下面
可恨Microsoft已经推出了显天气预报的Gadgets
可惜不支持中文市场
挺漂亮的,还没广告
找到一个非常好的备份Space和其它一些Blog的软件
Maikr(http://www.maikr.com)国产软件
注册一下才能使用,不过是免费
非常好用,连评论也能下载
把自己space全部下下来
153篇文章,hoho
勤劳的部落哥儿
强烈推荐大家去备份一下
免得哪天被Microsoft耍
哭都来不及
Copyright © 2005-2006 Solrex Yang. All rights reserved.
俗务缠身,准备考试,申报优秀班级材料,还有作业,不说了。写不了那么多,但BLOG里老是些技术文章也挺碍眼的,就在这推荐个比较欣赏的BLOG吧。
这个BLOG里主要是关于投资咨询方面的文章,尤其是我们系那么多想考金融的研究生,看了估计能有些好处,主人是易凯投资咨询公司的CEO王冉,有许多对投资事务分析,而且写的条理非常明确,值得一看,许多分析方法也可以学习一下。更新也很频繁。
Web地址是:http://blog.sina.com.cn/m/wangran
如果你有RSS阅读器,这是RSS种子,直接复制添加即可:http://blog.sina.com.cn/myblog/index_rss.php?uid=1197890497
说开源这个词是个玩笑,意思是把自己做的吴朝阳老师的课的作业大家共享一下,不然也是老有人要。
声明:共享不是说同意抄袭。只是大家为了准备期中考试那么忙,而且不是有太多人坚持上了吴老师的课,做起来可能有些生疏。我只是提供一个可以运行的例子,让大家知道大致该是怎么写,希望不要原模原样的COPY。写的时候还可以参考一下我前一篇文章。也希望大家都能拿到学分,尤其是还有好多学分不够的同学,希望能尽量拿这4分。如果谁能告诉我有些更好的解决方法的话,非常感谢。
下载地址:我的BLOG左侧最上方的个人主页链接,下载就放在主页上。还有一个《STL_Programmer_Guide》的英文文档,对没有MSDN的同学可能有点用处。
注:我的作业使用的头文件和老师要求的不一样,但相似,仅供参考,grade2.txt文件本与grade.txt相同,估计是老师让自己修改为作业格式。吴老师信箱是:wu_zy@nju.edu.cn,讲义和作业在公共信箱里。
Copyright © 2005-2006 Solrex Yang. All rights reserved.
读到一句让我特别感动的话:
I am moving forward as part of the new company with a huge smile on my face and a small tear in my eye.
——David Intersimone
Vice President of Borland, Developer Relations and Chief Evangelist
大陆翻译为:
泪水离开了我们的眼睛,但微笑将留在我们脸上。
台湾的翻译是:
我臉上會帶著巨大的笑容,但是我眼中也有一顆小小的淚珠。
壮士断腕的悲壮,直面困境的勇气,竞取未来的信念。
叹服!
希望Borland在它选择的路上能继续走好。
又想起KING KONG,也有句话印象尤为深刻:If you really love her, you will jump.
If you really love her 唉,HE!
虽然发了愿要一个星期不开电脑,可软弱的我在被室友的诱惑和干扰下还是打开了电脑,装上街头篮球。
可大概是报应吧,我系统根本不允许我玩,运行就出错,然后自动重启。
这样也好,给了我一个理由不去玩它。
随着软考日期的逐渐临近,发现缺少的还不是一点两点东西,这几天看的不少。
小时候老爸就说我是小聪明,不是大聪明,从前也许不怎么相信,越大越明白了。
老爸还说,大聪明应该是通过努力获得的,而不是靠些许天生的聪慧。
微言大义,还真是知子莫如父。只可惜现在无处得此教益了。
总之,还是要踏踏实实做学问,认认真真做人。
Copyright © 2005-2006 Solrex Yang. All rights reserved.