按 ‘ infotech ’ 分类归档

简单的图片循环播放器

WordPress不让我痛痛快快地在正文里写JavaScript(例如会把&符号编码,弄得我没法说“and”),所以我把示例播放器的页面放在这里了。打开页面,右击,可以看源代码。

代码说明:

首先这个程序需要jQuery的支持:

<script type='text/javascript' src='/js/jquery.min.js'></script>

其次,CSS需要用“position:absolute;”,使要播放的图片事先重叠在一起。

<style>
	.slide {
		position: absolute;
		left: 0px;
		top: 0px;

		width: 600px;	/* Customizable */
		height: 420px;	/* Customizable */
	}
</style>

下面这个不算代码,其实是HTML的正文部分,图片在这里被HTML使用。关键的三点:

  1. 顶层<div>的id需要和播放函数(等下会提到)的参数一致(示例是“YadingPhoto”)。
  2. 每张图片不是直接挂在顶层<div>下的<img>,而是放在一个子<div>里的,这是为了让播放器有播放文字的功能(<div>里想写啥都是可以的,不只可以放图片)。
  3. 包装图片的<div>的class要和上头的CSS代码保持一致(示例是“slide”)。
<div id='YadingPhoto' style='position:relative;width:600px;height:420px;'>
	<div class='slide'>
		<img src='../pic/xianuoduoji-slidedemo.jpg' alt='XiaNuoDuoJi' title='XiaNuoDuoJi'>
		<div style='text-align:center;'>Yading - Xia Nuo Duo Ji</div>
	</div>
	<div class='slide'>
		<img src='../pic/xiannairi-slidedemo.jpg' alt='XianNaiRi' title='XianNaiRi'>
		<div style='text-align:center;'>Yading - Xian Nai Ri</div>
	</div>
	<div class='slide'>
		<img src='../pic/yangmaiyong-slidedemo.jpg' alt='YangMaiYong' title='YangMaiYong'>
		<div style='text-align:center;'>Yading - Yang Mai Yong</div>
	</div>
</div>

最后是播放器本身的JavaScript代码,由于jQuery的selector和hide/show的淡入淡出效果都已做好,这个程序可以写得很短。程序的主要思路,是每隔几秒钟,就把排头的<div>挪到队尾去,这样排第二的那个<div>的内容就露出来了。

两个小函数接受的参数,其实并不精确地是id,而是一个jQuery selector,示例中,是“#YadingPhoto”,这是为了更广泛地利用jQuery强大的页面元素定位功能。

<script type='text/javascript'>
	initSlide('#YadingPhoto');	// Customizable, must equal to the slide show top div's ID.
	setInterval("switchSlide('#YadingPhoto')", 5000);	// Customizable.

	function initSlide(slideID)
	{
		if ($(slideID + " > div").length <= 1)
			return;
		var selector = slideID + " > div";
		$(selector).hide(0);
		$(selector).css("z-index", "-1");
		$(selector + ":first").show(0);
	}

	function switchSlide(slideID)
	{
		if ($(slideID + " > div").length <= 1)
			return;
		var selector = slideID + " > div";
		$(selector + ":first").next().fadeIn("slow");
		$(selector + ":first").fadeOut("slow");
		$(selector + ":first").appendTo($(slideID));
	}
</script>

判断夏时制的JavaScript代码

“三月的第二个星期日”这种表达,用计算机语言说起来很复杂的。所以不辞辛苦写了段代码,用来判断世界的其他地方现在是不是夏时制。

函数需要两个参数:

  • timezone是想要计算的地方所在的时区,是一个数字,用正数表示东半球,用负数表示西半球,零表示本初子午线附近。此数字可以是小数,为了照顾加德满都这种“东5小时零45分钟”的时区。
  • summerrule是所需要使用的规则,此参数是一个字符串,目前这段JavaScript代码支持两种规则:“EUR”和“USA”。

如果所计算地点的当前时间,按照规则被认为是落在夏时制期间,则函数返回true,否则返回false。

function isDaylightSaving(timezone, summerrule)
{
    var today = new Date();
    var localtime = today.getTime() + timezone * 3600 * 1000;
    var localday = new Date(localtime);
    var hour = localday.getUTCHours();	// 0-24
    var month = localday.getUTCMonth();	// 0-11
    var date = localday.getUTCDate();	// 1-31
    var wkday = localday.getUTCDay();	// 0-6
    var summer = false;
    if (summerrule == "EUR") {
        if (month > 2 && month < 9)
            summer = true;
        else if (month == 2 && date - wkday > 24 && (wkday != 0 || hour > 0))
            summer = true;
        else if (month == 9 && (date - wkday < 25 || wkday == 0 && hour < 1))
            summer = true;
    } else if (summerrule == "USA") {
        if (month > 2 && month < 10)
            summer = true;
        else if (month == 2 && (date > 14 || date - wkday > 7 && (wkday != 0 || hour > 1)))
            summer = true;
        else if (month == 10 && (date < 8 && (date - wkday < 1 || wkday == 0 && hour < 2)))
            summer = true;
    }
    return summer;
}

简单的验证码图片生成器

下面的PHP程序可以生成如  这样的简单验证码。把它存成一个PHP文件,例如captcha.php,使用<img src=’captcha.php’ />显示它,然后,你在服务器端把用户的输入和$_SESSION[‘captcha’]做比较即可:

<?php
    session_start();

    $charset = 'ABCDEFGHJKLMNPQRSTUVWXY3456789';
    $maxpos = strlen($charset) - 1;
    $captcha = '';
    $im = imagecreate(60, 24);
    $white = imagecolorallocate($im, 0xff, 0xff, 0xff);
    for ($i = 0; $i < 4; $i++) {
        $imchar = imagecreate(15, 24);
        $white = imagecolorallocate($imchar,mt_rand(0xe0, 0xff), mt_rand(0xe0, 0xff), mt_rand(0xe0, 0xff));
        $color = imagecolorallocate($imchar, mt_rand(0x00, 0x70), mt_rand(0x00, 0x70), mt_rand(0x00, 0x70));
        $captcha .= substr($charset, mt_rand(0, $maxpos), 1);
        imagestring($imchar, 5, 0, 0, $captcha[$i], $color);
        $imchar = imagerotate($imchar, mt_rand(-10, 10), $white);
        imagecopymerge($im, $imchar, mt_rand(1, 5) + $i * 15, mt_rand(0, 8), 0, 0, 15, 24, 100);
    }
    for ($i = 0; $i < 15; $i++) {
        $x1 = mt_rand(0, 59);
        $y1 = mt_rand(0, 23);
        $x2 = $x1 + mt_rand(-2, 2);
        $y2 = $y1 + mt_rand(-1, 1);
        imageline($im, $x1, $y1, $x2, $y2, mt_rand(0x000000, 0xffffff));
    }
    $_SESSION['captcha'] = $captcha;
    header('Content-type: image/gif');
    imagegif($im);
?>

使用的字符集里没有I、O、1、0、Z、2,因为担心它们互相混淆。思考:S和5是不是也挺像的?纠结。

为了让验证码有“看不清,换一个”的功能,现实中的<img>写得要稍微复杂些,下面代码里的’captcha.php?’+now.getTime()是为了欺骗浏览器,让它以为是一张新的图片进来了,强迫它刷新captcha.php产生的图片,而不是从缓存里获得:

<img src="captcha.php" title="click for a new one"
onclick="now=new Date();src='captcha.php?'+now.getTime();" />

“分享到新浪微博”按钮

在博客的每篇博文后都加入了“分享到新浪微博”按钮。方法是编辑monochrome的主题(theme),在header.php的</head>前加入这么一段代码:

<script type="text/javascript">
jQuery(function() {
    jQuery('div.post_content_wrapper').each(function() {
        var urlstr = jQuery(this).find('h2.post_title > a').first().attr('href');
        if (typeof(urlstr) == 'undefined') {
            urlstr = location.href;
        }
        var _w = 72 , _h = 16;
        var param = {
            url:urlstr,
            type:'3',
            count:'1',                  // 是否显示分享数
            appkey:'',
            title:'',
            pic:'',
            ralateUid:'1691250947',     // 关联用户的微博用户号码
            language:'zh_cn',
            rnd:new Date().valueOf()
        };
        var temp = [];
        for (var p in param) {
            temp.push(p + '=' + encodeURIComponent(param[p] || ''));
        }
        buttonstr = '<div style="width:100%;text-align:right;">';
        buttonstr += '<iframe allowTransparency="true" frameborder="0"';
        buttonstr += ' scrolling="no" src="http://hits.sinajs.cn/A1/weiboshare.html?';
        buttonstr += temp.join('&') + '" width="'+ _w+'" height="'+_h+'"></iframe></div>';
        jQuery(this).find('div.post_content').first().after(buttonstr);
    });
});
</script>

这个代码也许只在monochrome主题下工作,而对于其它的主题,需要稍事修改。

iframe所要显示的参数是从新浪微博开放平台获得的。

程序的小难点在于:显示单篇博文的时候,博文题目只是个简单的header,header上没有链接页面的URL。而显示多篇博文时,每个博文的题目上都链接了其单篇的URL。获取这个URL就需要一个条件判断,也就是这段代码:

var urlstr = jQuery(this).find('h2.post_title > a').first().attr('href');
if (typeof(urlstr) == 'undefined') {
        urlstr = location.href;
}

在自己机器上调好之后,把代码放到博客上时,还遇到一个惊奇。分享按钮根本不显示,好像这段代码根本未被调用一样。后来发现,在我的机器上,可以使用jQuery的缩略写法$(),而在博客网站上,必须老老实实写成jQuery()。

http_response_code或Status code的重置问题

在写一个产生短链接的程序。短链接本身对应的文件当然不是直接存在域名根目录下的,而是通过.htaccess的404 ErrorHandler转交给检索程序,由检索程序把真正的文件输出出来。这里需要把404号Status code覆盖掉。

在家里机器上写的PHP代码是:

header("Content-type: $mime", FALSE, 200);

其中200是代表OK的状态码。

这句话在家里的机器上工作得挺好,但上传到公共网站上之后,程序工作方式就不是那么回事了。404号状态码并未被覆盖掉,如果输出文件是图像,还能勉强显示。但如果是个下载附件,就看到了404号“网页不存在”的错误信息。

经过反复调试,找到解决方法如下:

header("Status: 200 OK");    // Reset the status to OK (200).
header("Content-type: $mime", FALSE, 200);

这两句话缺一不可,如果少第一句,则公共网站上的程序不干活。如果少第一句,则家里的程序不干活。

Bug-free development: Source code readability

Source code readability is important. Even nobody else will read your source code in the future, you will read it one day. Dirty code provides good shield for bugs for they become harder to find. Dirty code may also mislead other programmers to think they find a bug, and by “fixing” it, they create a real bug.

Indention

One good reason I like Python is, no matter the programmer is amateur or professional, at the first glance, the source code is so clean. If the source code is not properly indented, then it may not run at all. Well-indented source code helps the reading speed, and makes the bugs easy to reveal.

There are many code beautifiers that standardize the code style. For example, in UNIX there is a command called “cb” (C Beautifier), and in Visual Studio, there are shortcuts standardizing the code format as well. When I programmed in C, I always ran the “cb” command and compared the output with my source code, and made sure no differences were found between the two. Call me obsession, but once I got used to it, it became very natural to write well formatted code at typing.

Explicitness

Being explicit means, for example, if part of the code is supposed to do nothing, then, instead of writing nothing, do put some code or comments to speak out: “I am here to tell you, nothing should be done. I did not forget to consider this case.”

Here is an alarm clock program. It used to work before but is not working now. Instead of triggering the alarm by the desired time, it does the inverse logic – keep ringing the alarm until the time is reached. The investigation shows that the latest version is like this:

for (time() < desiredTime)
    puts(“wake up”);

Then no surprise why it keeps sending the alarm. Why the code is like this? One week ago Susan read the code and discovered that the code was like:

for (time() < desiredTime);
puts(“wake up”);

and she thought that the “;” at the end of the “for” statement was a typo, so she removed the “;” wrongly, and this “fix” ultimately reserved the logic.

To avoid this misunderstanding, Mike, the author of the previous version, should have written his code as below, so if Susan saw this code, she would have been thought twice, or picked up her phone to quickly confirm with Mike, before applying the “typo correction”.

for (time() < desiredTime)
    ;
puts(“wake up!”);

A even more explicit code is like this. The “NULL” statement does not generate any extra code, but it explicitly tells the audience “I mean to do nothing here.”

for (time() < desiredTime)
    NULL;
puts(“wake up!”);

Other examples: The NULL statement in the “else” block makes explicit that no actions should be taken if neither A nor B is met. The “fall through” comment in the “switch” block makes explicit that the “break” statement is not forgotten here, but the programmer intends to execute do_this() and do_that() when a equals to 0.
猛击阅读全文

Bug-free development: Understand the differences between the physical world and the computer world

It is important to understand the differences between the physical world and the computer world, and keep the differences in mind.

A computer, most times, is only simulating the actual world. As a result, if the simulation is not well designed, then a program may get incorrect, inaccurate, and/or inconsistent result. A function once worked one month ago may no longer work today, or its behavior varies from one computer to another. If I said these in front of a programmer, he/she would probably agree. This does not mean he/she would keep this in mind, though. I have seen many cases when the program inaccurately simulated the world, its master’s first instinctive reaction was to check somewhere else, but not their own code.

  • In the physical world there are axioms and laws, while in the computer world there are standards and conventions.
  • In the physical world there are math and physics, while in the computer world there are algorithms.
  • In the physical world numbers can be infinitely large or infinitely small, while in the computer world numbers are represented by limited bits.

When writing programs, the developer have to keep alert of these differences, and when introducing his/her code to others, he/she can easily tell which items are representing the physical world, and which can stand true only on a computer.
猛击阅读全文

LEGO赤道仪

老胡拿LEGO零件做了一个赤道仪。只要在图片上方的齿轮大孔里装一个寻星镜,并对准北极星,那么,左上角的螺钉上安装的照相机相对星空就是静止的,可以避免长时间曝光的星体拉丝现象。赤道仪有马达驱动,齿轮大孔的旋转速度是每天360°。整个部件仅仅重五百克。

盛赞老胡!

Equatorial Mount built with LEGO pieces

Equatorial Mount built with LEGO pieces

Bug-free Development

A myth says, and lots of people believe, that every program has bugs.

This is only a myth, however. Consider this program:

void     main(void)
{
}

This program has no bugs, because it does not do anything. This program has lots of unsupported features, however. It does not do whatever we can think of, or in other words, the entire world is its complement.

You may say this is a quibble, and tweak the statement a little bit and say: Every acting program has bugs.

Then please consider this famous program, which does nothing but printing “hello, world” followed by a line-feed:

#include <stdio.h>

void     main(void)
{
   puts(“hello, world”);
}

We acknowledge that this program has lots of unsupported features as well. It cannot print “good morning, world”, “goodbye, world”, etc. However, again, it has no bugs.

A program may have unsupported features, but can be bug-free. In my 19-year programming life, no post-release bugs were discovered from my codes. I worked for a company that manufactured semiconductor measurement instruments. I wrote a program that made the company’s program looked like sequential execution, but actually run in parallel way. The patent-owning program had over 2000 lines, and since the day its first version was written (2003), the company’s QA team did not find any bug from it. Two years after I left the company, I talked with my ex-colleague by chance. He told me that the guy, who was assigned the QA to audit my code, did not find a single bug. But since the QA believed the myth “Every program has bugs” so blindly, he preservered with it for two years, and ended up with nothing.

When I was young and arrogant, I drafted a “bug-free guarantee” and attach it to every piece of my source code, and said:

If anyone finds the first bug in my code, I would pay him/her 1 dollar, then for the second bug he/she finds, I would pay 2 dollars. 4 dollars for the third, 8 dollars for the fourth, and the number increases exponentially.

Nobody ever got a buck from me.

In theory, in reality, bug-free development is possible. I am planning to share ideas about bug-free programming in some of my future blogs. Such blogs will use “bug-free” tag.

天文软件的最稳定参照系

如果要写一个天文软件,那么,两万年内最稳定的参照系是黄道面。黄道星座从古到今都是那些,而指极星却在不停地偷换。

指极星的改变是地轴进动的结果,并带来所有恒星赤经赤纬的变化。赤纬变化的原因很明显——指极星都变了。赤经变化是因为地轴进动带来的春分点(黄道和赤道的交点之一)的进动。

地球的公转轨道只有一个开普勒元素是在明显改变的,就是近日点幅角。而轨道倾角、升交点黄经、离心率和半长轴都基本不变。