创意验证码
行走网上,不免看到好的服务,想要使用,于是第一道门槛就是注册,而且现在为了防止机器自动注册,大多采用了验证码,就此一验证码,各家是各有特色啊,一般的纯字母数字组合的不再提,而Yahoo,Google的要是碰上了的话,是个人都半天认不出来,更不要说机器了,传说这才是真正功能强大的验证码,但是人都认不出来怎么办,来个声音提示,读一遍就行了。
记得以前看到过一个新奇验证码的集合,不过不记得地方了,也没有收集下来,大概记得有个叫计算极限的比较有意思,类似这种
请输入下列式子的答案:
这样的我觉得创意已经够好了,结果今天看到一个更绝的:
这个应该还好吧,不过我刷新了一下,看这个
上面那个还可以用眼睛看出来,这个就得好好花一点功夫了,非geek不会玩这种东东。
一般都会跑一下这个程序来得到结果,这里有在线服务可以办到这事,强强的codepad就可以。
消失的11天
最近做一个万年历的作业,粗粗了解了下历法,做农历的时候发现农历没有固定的算法,只能查表来计算,中华人民共和国提供了1800-2100三百年间的标准农历供使用,于是一下子限制了我的程序的查询范围。所以想着公历的准确,计算的容易,可是正想着公历算法的好呢,发现了一个问题,那就是以前公历不大完善的时候,也有问题。
比如这个,在linux下打入这个命令(windows限制时间范围是1980-2099,所以看不到这个现象)
crane@debian:~$ cal 9 1752
September 1752
Su Mo Tu We Th Fr Sa
1 2 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
cal 9 1752就是查询1752年9月的日历,于是很跌眼镜的发现,2号后面就是14号,少了11天,怎么回事呢?
查了下资料,发现是因为历法调整的问题。
1582年2月,罗马教廷要求从1582 年10月中减去10天,因此1852 年10月4日后面紧跟着就是15日。在意大利、西班牙等国家都这样处理了。其他天主教国家也很快跟着这么做了,但是新教国家不愿意修改,而且希腊等东正教 国家直到20世纪初才修改,所以这个改革在英国及其殖民地(包括美国)在1752年9月才被执行。这样 1752 年9月2日后面跟着的就是1752 年9月14日。 这就是为什么cal会生成上面输出的原因了。
这里有个问题,上面说教廷说的是减去10天,但是刚才发现1752年9月减了11天,这是为什么呢?
这是历法转换的问题,现行公历叫格里历(Gregorian calendar),这是十六世纪的罗马教皇Gregorian XIII (格里十三世)针对当时使用的儒略历 (Julian calendar)进行修订后,于1582年10月开始实行的。所以就出现了上面的1582年10月调整10天的情况。但是由于写cal的是美国人,cal是从AT&T的Unix中出来的,前面说到过,美国跟从英国的历法是从1752年才开始改的,所以不太一样,所以还牵涉了1600-1800年的一些问题。
根本原因是因为1800年以前的闰年计算的问题,我们知道闰年是4年一闰,百年不闰,400年再闰,但是1800年以前(所以不包括1800年)没百年不闰,所以就出现了偏差,比如我们可以看一下
crane@debian:~$ cal 2 1700
February 1700
Su Mo Tu We Th Fr Sa
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
crane@debian:~$ cal 2 1600
February 1600
Su Mo Tu We Th Fr Sa
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
可以清楚地看到,1600和1700年2月都是29天,一眼看去,想当然的认为多算了17天,其实实际上多算了13天,因为400,800,1200,1600是闰年,2月应该有29天。但是为什么调整的时候只少了11天呢,有个很纠结的原因,由于儒略历 (Julian calendar)公元前闰年的不规则,少算了2个闰年,从13天中去掉2天,所以在cal中看到的是少了11天。
话说回来,做万年历的时候这可是陷阱啊,得小心才是。
超级快速关机方法
最近不知什么问题,发现有时关机时停在windows正在关机那里时间比较长,而且是偶尔快偶尔慢,吃不准是什么原因,于是就想着有什么好的快速关机的方法。
首先想到的就是那个经典的操作技巧,打开任务管理器,在关机菜单中按住ctrl的同时点关闭,片刻间,机子就关了。
算算这个所费的时间,打开任务管理器(不管是任务栏右键打开还是快捷键),再选菜单,点关闭,得10秒左右吧!
程序员的话就会多想一点,这个玩意用程序怎么实现呢?那个开始菜单关机函数和任务栏的肯定不是一样的,开始菜单的比较优雅一点,提醒保存数据,通知程序退出,然后关机,而任务管理器的就相对粗暴一点,什么也不做,直接就关机,不过速度绝对一流,呵呵,我喜欢,就要这个速度。
查了下资料,一般用的是ExitWindowsEx这个函数,可能也会用InitiateSystemShutdownEx,这里交待下ExitWindowsEx的用法,查MSDN,可以看到函数原型如下:
BOOL ExitWindowsEx(
UINT uFlags, // shutdown operation
DWORD dwReason // shutdown reason
);
其中uFlags有这些选项:
EWX_LOGOFF 注销
EWX_POWEROFF 关闭系统并关闭电源
EWX_REBOOT 关机重启
EWX_SHUTDOWN 关机并指出现在可以安全关机了
还有
EWX_FORCE
EWX_FORCEIFHUNG
强制关机,可能会丢失数据。
dwReason很多,主要这么几个
SHTDN_REASON_MAJOR_APPLICATION Application issue.
SHTDN_REASON_MAJOR_HARDWARE Hardware issue.
SHTDN_REASON_MAJOR_OPERATINGSYSTEM Operating system issue.
SHTDN_REASON_MAJOR_OTHER Other issue.
SHTDN_REASON_MAJOR_POWER Power failure.
SHTDN_REASON_MAJOR_SOFTWARE Software issue.
SHTDN_REASON_MAJOR_SYSTEM System failure.
但这不是这篇文章的重点,这里要说的武器不是公开的,在MSDN中查不到,这是微软的秘密武器,ZwShutdownSystem函数,藏在ntdll.dll中。
利用ZwShutdownSystem(2)关闭电源,这个函数要求有SE_SHUTDOWN_PRIVILEGE权限,因此要先用RtlAdjustPrivilege函数来设置SE_SHUTDOWN_PRIVILEGE,SE_SHUTDOWN_PRIVILEGE的值为0x13,ZwShutdownSystem函数不通知应用程序和服务程序,就直接关闭系统了,关机速度非常快,但是如果有程序没有保存数据的话,是不会有任何提示的。
完整的程序可以这样写:
#include<windows.h>
#define SE_SHUTDOWN_PRIVILEGE 0x13
int main()
{
int nRet;
int en;
HINSTANCE hs=NULL;
typedef int (*SHUTDOWN)(int);
SHUTDOWN ZwShutdownSystem;
typedef int (*RTL_ADJUST_PRIVILEGE)(int,int,int,int *);
RTL_ADJUST_PRIVILEGE RtlAdjustPrivilege;
hs=LoadLibrary("ntdll.dll");
if(hs==NULL)
{
MessageBox(NULL,"Cannot load DLL file!","error",MB_OK);
}
ZwShutdownSystem=(SHUTDOWN)GetProcAddress(hs,"ZwShutdownSystem");
RtlAdjustPrivilege=(RTL_ADJUST_PRIVILEGE)GetProcAddress(hs,"RtlAdjustPrivilege");
nRet=RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,TRUE,TRUE,&en);
if(nRet==0x0C000007C)
nRet = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,TRUE,FALSE,&en);
nRet=ZwShutdownSystem(2);
FreeLibrary(hs);
return 0;
}
编译运行,一个黑框一闪,机子就关了,像台式机拔电源一样快速。再多想一下,给它创建一个快捷方式,换个图标,然后设置为最小化运行,就看不到黑框了,再加个快捷键,这样的话,按个键,哗一下机子就黑了,光速关机啊!
弱弱的想一下,两个方法是不是本质上是一样的呢?
C语言有点变态
直接看这个程序
int f(int x)
{
printf("%d\n",x);
}
int main(void)
{
int (*pf)(int);
pf=f; //正常用法
pf(5);
(**pf)(5); //这是什么
(****************f)(5); //这个变态啊
pf=&f; //这个也没问题
pf(6);
pf=*****f; //这是干什么
pf(7);
system("pause");
return 0;
}
看着很神奇,至少有些我从来没那样写过,但是这些全部是合法的,可以编译通过。
VHDL编程之可逆计数器
数字逻辑学了一个学期,始终都是一堆的门元件和触发器接来接去,实在是搞得人有点晕乎,到了最后大规模集成电路的时候,终于不用(好像也不可能)那些方法了,话说coding the world不是没有道理的,这大规模的电路设计最后还是得软件来搞,可惜还没到CPLD/FPGA的地步,我们就搞了一个用VHDL做的4位(其实用VHDL 的话这个位数只是个数字而已)可逆计数器,觉得蛮有意思,代码丢在这里,万一以后想到查呢?
题目是这样的:
设计一个能清0,置数和进位输出的增1/减1的4位二进制计数器。
输入信号clr为清0端,低电平有效,信号ld为置数端,也是低电平有效,将A,B,C,D的输入值送到计数器中,并立即在Qa,Qb,Qc,Qd中输出。输入信号m为模式选择端,m=1时为加1计数,m=0时为减1计数。当cp端输入一个上升沿信号时进行一次计数,有进位/借位时qcc输出一个负脉冲。
代码如下
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
entity counte is
port(cp,clr,ld,m:in std_logic;
abcd:in std_logic_vector(3 downto 0);
qcc:out std_logic;
qcount:out std_logic_vector(3 downto 0));
end;
architecture count of counte is
begin
process(cp,clr,ld)
begin
if(clr='0')then
qcount<="0000";
if(m='0')then
qcc<='0';
end if;
elsif(ld='0')then
if(abcd="0000" and m='0')then
qcount<=abcd;
qcc<='0';
elsif(abcd="1111" and m='1')then
qcount<=abcd;
qcc<='0';
else
qcount<=abcd;
qcc<='1';
end if;
elsif(cp'event and cp='1')then
if(qcount="1110" and m='1')then
qcount<="1111";
qcc<='0';
elsif(m='1')then
qcount<=qcount+1;
qcc<='1';
end if;
if(qcount="0001" and m='0')then
qcount<="0000";
qcc<='0';
elsif(m='0')then
qcount<=qcount-1;
qcc<='1';
end if;
end if;
end process;
end count;
其中字母基本上和上面要求对应,就是上边的qcount对应Qa,Qb,Qc,Qd。
感觉这样的begin和end的配对,而且整个程序看起来和PASCAL还是有点像的。