May 15th, 2009ie css selector issue

最近写了一些html, 遇到一个很郁闷的问题, 大致是下面的, 我写了一些链接, 大致如下:

<a class="actionlink" onclick=’myfunction(this);'>mylink</a>

为它写了一个css, 如下:

a.actionlink {

    display:block;

    text-decoration: none;

    color:  #62C2CC;

    outline: none;

    }

a.actionlink:hover {

    display:block;

    color: blue;

    text-decoration: underline;

    }

a.actionlink:visited {

    display:block;

    color:  $62c2cc;

    }

a.actionlink:active {

    display:block;

    color:  red;

    }

链接在firefox下面显示的完全正常, 可是在ie7/8下却死活无法正常显示在鼠标移上去时的颜色, 网上找了很久, 看到一些相关的ie8的bug, 像css selector的问题, 这里有一个列表, 本来以为其中的一个css子对象选择符的bug是这个有关, 但是我已经把它改成了直接的类, 所以应该不是那个问题.

两天郁闷的尝试都没有成功, 今天再看相关的文档, 在看到选择符的时候, 偶然看到这么一句:

The document language determines which elements are hyperlink source anchors. For example, in HTML4, the link pseudo-classes apply to A elements with an "href" attribute. Thus, the following two CSS 2.1 declarations have similar effect:

a:link { color: red }
:link  { color: red }
这回忽然注意到其中红色的部分, 难道真和这个有关? 于是试着加上href="#", 之后, 果然一切都好了!……
<a href=”#” class="actionlink" onclick=’myfunction(this);'>mylink</a>

April 22nd, 2009闪屏问题

今天又接到了一个问题:-| 最近的问题有点多哈!

问题是这样的, 朋友的一个程序(VC++编写)它会在上面显示一个背景图片和自己绘制的一个计时的时间显示表, 程序在开发的阶段运行一切正常, 但是客户反映讲此程序运行的相当不稳定, 总是在过了一段时间后会出现背景变灰, 并且窗口界面开始不停的闪烁. 朋友经过测试也发现有类似的状况, 在朋友的机器上程序大概运行三分钟后就会出现客户说的情况, 据朋友描述说有时也两分钟左右就会出现闪烁的情况, 只是这种情况比较少, 但三分钟是一个比较保险的使问题重现的时间.

刚听到这个问题, 比较没有头绪, 找不到问题, 于是让朋友把相关的代码发过来, 看了代码心中大概有了一个概念:

  1. 界面完全是由自己的代码绘制的,
  2. 为了显示计时器的时间, 在代码里加了一个计时器, 并在onTimer ()时重新绘制整个窗口
  3. 绘制时钟是通过装载对应的位图绘制数字的

看到这里, 心里大概能猜测到了一个可能的原因: 句柄泄漏, 一想到这一点, 所有的问题都可以解释了: 极有可能是在窗口绘制的代码里出现了句柄泄漏的情况, 在刚开始的时候没有问题, 但由于每秒钟都会定时绘制一下界面, 所以随着时间的推移, 泄漏的句柄数越来越多 — 这样当所有可用的句柄都泄漏完之后, 当再次尝试申请句柄资源以创建相关的位图对象的时候就会失败, 这样就会导致画不出相关的图片来, 于是整个界面就会是灰/白色了, 至于闪烁的问题, 应该是由于每次刷新失败导致的问题. 这么一讲还真可以讲的通. 再仔细看一下代码吧:) 下面是一段类似于朋友ontimer函数的代码:

void CMyDlg::OnTimer(UINT nIDEvent)
{
    if (nIDEvent == MY_TIMER_EVENT)
    {
        //
        // draw the clock
        //
         CDC *pDC = GetDC();
        CDC CompatibleDC;
        CompatibleDC.CreateCompatibleDC(pDC);
        CBitmap bmp;
        bmp.LoadBitmap(IDB_DIGITS);
        BITMAP bitmap;
        bmp.GetBitmap(&bitmap);
        CompatibleDC.SelectObject(&bmp);
        //
        // draw minutes/seconds, using hte digits in the bitmap...
        //
        pDC->StretchBlt(200,565,87,135, &CompatibleDC,(bitmap.bmWidth/12) * minute,
                0, bitmap.bmWidth/12,bitmap.bmHeight,SRCCOPY);

        ReleaseDC(pDC);
    }
}

初看貌似没有什么问题, dc对象被正常释放了, 不过再仔细看一下! 注意这里的CBitmap以及selectObject, 这里是有泄漏的,或许你会说CBitmap的析构函数会释放它使用的gdi 对象, 在msdn里的LoadBitmap的方法说明里也是这么讲的:

The loaded bitmap is attached to the CBitmap object.

If the bitmap identified by lpszResourceName does not exist or if there is insufficient memory to load the bitmap, the function returns 0.

You can use the CGdiObject::DeleteObject function to delete bitmap loaded by the LoadBitmap function, or the CBitmap destructor will delete the object for you.

但是请注意下面的一行!

Caution:

Before you delete the object, make sure it is not selected into a device context.

这里提到请注意在删除一个对象之前请确认它没还没当前的设备上下文选中! 如果删除一个当前被使用的对象会有什么后果? 虽然没有找到文档, 但照猜测的话那就是删除失败! 所以毫无疑问每次都会导致一个CBitmap的gdi对象的泄漏! 所以修好这个问题应该是在使用完这个bitmap对象后再使用selectObject把选择原来的gdi 对象, 原来的gdi对象可以通过CompatibleDC.SelectObject(&bmp);的返回值得到. 所以修改后的代码应该是这样:

        CBitmap* oldObject = CompatibleDC.SelectObject(&bmp);

        //
        // draw minutes/seconds, using hte digits in the bitmap...
        //
        pDC->StretchBlt(200,565,87,135, &CompatibleDC,(bitmap.bmWidth/12) * minute,
                0, bitmap.bmWidth/12,bitmap.bmHeight,SRCCOPY);
        pDc->SelectObject (oldObject);  //select the old object.!
        ....

这样应该就可把这个问题修好啦! (没有机会测试, 但应该没有问题…).

再另外, 朋友告诉我他们找了一个人修了一下, 他们的方法是把那个CBitmap对象变成一个全局对象, 这样只要load一次, 所以也不会出现严重的泄漏情况(顶多一个gdi 对象, 另外效率相对每次都要load要好一些), 所以也可以算一个方法:)

近日一个朋友发过来一个页面, 说是上面有一段代码执行慢, 想看看能不能用一些方法让这个等待过程不要这么久, 看了一下代码, 朋友所指的代码大概像下面一段:

if (cond)

{

$query = “select id, name from demoTable where age >= “ . $age . “ and score >= “. $score . “ “;

$result = mysql_query($query);
list( $id,$name) = mysql_fetch_row($result);
print &quot;<td class="text">&quot;.$id.&quot;</td>
print &quot;<td class="text">;&quot;.$name.&quot;</td>;

}

另外的信息是, 数据库的记录大概是三十多万条, 由于这个查询语句要在一个循环语句里执行多次, 当循环十次的时候速度会很明显的很慢.

据俺已有的知识和对mysql的理解, 对于十万量级的记录, 数据库的效率应该没有问题, 首先想到的便是从优化数据库开始, 第一条当然是建立索引了, 于是建议他用age + score做一个索引, 但朋友讲做过索引后没有太大影响(我怀疑他是单独为age 和 score做了索引, 我的意思是为age/score做一个综合索引, 但后面这个就没机会尝试了). 于是再尝试一些新的方法, 回过头去分析这段代码, 可以发现, 这里只是用到了返回结果集的第一条记录(或者原来的作者只期望得到一条记录), 毫无疑问, 把所有的记录查询下来是很破费时间/内存的, 于是从这里入手, 我们把查询改成只查一条记录.

于是修改后的查询语句就是

$query = “select id, name from demoTable where age >= “ . $age . “ and score >= “. $score . “  LIMIT 1“;

让朋友尝试新的代码, 果然速度提升了很多, 基本不用再做其他的优化了. 那我们分析一下加上LIMIT 1之后相对能优化了多少次的查询, 这里我们假设每条记录被查询到的机率相同(不然还要再具体分析就太麻烦了…)

1. 假设没有索引, 那么对于原始查询, 基本是遍历整个表, 时间复杂度为O(n), 而对于优化后的查询来讲, 它会找到第一条匹配的记录后返回, 平均时间复杂度为(1 + n) / 2, 相当于优化了一半的时间.

2. 假设分别建立了age和score的索引, 对于原始的查询, 平均时间复杂度(二分法)应该大致在log2(n) + (log2(n/2) 左右, 这个需要根据具体的查询来分析, 不过这个值应该也算差不多, 而对于优化后的查询时间复杂度大致为 log2(n) + log2(n/2) = 2 log2(n) – 1, 貌似并没有优化掉多少时间 (是不是这里错了???? )…….

至于空间复杂度, 如果对于每次查询只可能有一条记录满足条件, 则都为O(1), 如果是有可能有多匹配记录, 当然对于优化后的查询会好很多.

April 14th, 2009my shell tips

最近无聊的时候记下来的两个小tip:)

1. login的时候随即打印一个ASCII的图案。

这个比较无聊,基本原理就是把一些预先准备好的ASCII图案分别写成一个文件,在登陆的时候就是随机选取一个文件然后cat就可以啦.

Sample code:

#print out a logo to the screen...
logoDir="~/.logo"
if [ -d $logoDir ] ; then
cd $logoDir
# '*' is a filename wildcard to match all files in the current directory
set *
# Use the syntax for arithmetic expressions.  "%" is the modulo operator
# Shift arguments by a random number between 0 and the number of files
shift $(($RANDOM % $#))
echo -e '\e[0;32m'
cat "${logoDir}/$1"
echo -e "\e[0m"
fi

上面的代码就是把所有的ASCII图案放在~/.logo下面,然后再登陆的时候首先使用cd进入~/.logo目录,然后用set *来默认匹配所有文件名,
shift $(($RANDOM % $#)) 则是随即一个整数然后和文件数取模并选择对应的文件名,
echo -e '\e[0;32m' 这一句是用来是后面的字符为绿色(因为白色的图案不好看啊…)
echo -e "\e[0m" 中止前面的改变字体颜色的效果,这样就不会影响后面的打印结果。

当然, 要记得去找一些ascii 图片放到你的.logo目录里啊:)

2. 动态更新putty的窗口标题

使用putty的ssh的同学们都会想putty可以向其他的终端模拟器一样根据当前目录啥的动态更新标题栏,其实这个也可以再putty里实现,这里需要注意两点:

a. 确保没有打开putty的禁止远程改变窗口标题的选项,这个选项可以在Terminal==>Features 里找到。

putty

b. 在你的登陆脚本里export 一个名为PROMPT_COMMAND的变量,顾名思义它需要是一个命令,下面是我的配置(注意开始的和末尾的数字都是必须的):

PROMPT_COMMAND='echo -ne "\033]0;${HOSTNAME}: ${PWD} -$USER\007"';export PROMPT_COMMAND

打印的格式为:hostname: /home/pangwa/src – pangwa

重新登陆或者source一下你的初始化脚本就可以了:)

January 8th, 2009colinux && xming (part 3)

上篇, 下面进行xming的安装和使用

首先来介绍一下xming, xming是一个免费的Windows下的X server程序. 它是Windows源生程序, 不是使用minggw/cgywin之类的东西封装后的linux API实现的, 这样相比速度应该还是占优势的.

废话不多讲, 下面就开始下载xming, 我下载的是6.9.0.31的最新版本, 下载后运行安装. 不用多讲, (这里建议把xming的字体包也安装上, 据说会省却不少奇怪的问题, 不过我暂时没有遇到因为字体原因造成的问题), 安装后就准备开始运行xming吧.

首先找到xming的安装目录, 运行xlaunch, 在出来的窗口里, 选择Multiple Windows, Display number采用默认值0 (这里是在一个机器上可以同时有多个xserver, 就是通过这个数字来区分具体的xserver), 然后下一步, 选择Start no client, 下一步, 在这一页把No Access Control的选项勾上 (这是一个不推荐的选项, 会有安全问题, 这里为了简单起见先把它选上, 后面后解释), 然后点完成, 这时xming就会启动, 可以在系统托盘可以看到它的图标.

这时我们启动linux, 登录系统.

运行以下命令

export DISPLAY=192.168.0.102:0

这里的ip地址是你windows机器的ip地址(就是xming所用机器的ip), :后面的数字就是在前面xlaunch中设置的Display Number, 在我们这里是0. 然后试试命令 xterm吧, 应该可以看到会有一个窗口显示在你的windows里啦:). 如果想以后默认就用这个作为显示, 可以把这一行放到~/.bash_profile中去, 这样在登录的时候就会自动把它export了.

简单的设置完成, 我们来继续讲刚才的No Access Control的选项, 因为这个选项有安全问题, 在xming的说明上是不推荐使用的. 那么如果尝试把这个选项在xlaunch里取消的, 你会发现你的程序会无法打开显示, 并且会在xming的log中发现类似”Xming: client 4 rejected from IP”的消息, 这是因为在有Access Control的情况时, xming会拒绝不被信任的来源ip, 那么我就需要把colinux所在的机器的ip加入到xming的信任的ip里去. 在xming的安装目录中找到Xn.hosts (其中n为你的Display Number对应的值), 在里面新加一行colinux的ip 地址(这个文件中每个ip占一行) ,  之后重新启动xming就可以生效了.

上面讲的是单显示一个窗口的配置, 如果想要打开一个类似于远程桌面的东西, 可以使用xdmcp, 则需要修改colinux xdm/gdm/kdm之类的登陆程序的配置文件, 把xdmcp打开, 对于gdm, 则修改/etc/gdm/gdm.conf, 找到[xdmcp]这一段, 加入Enable=true一行, 然后重启gdm即可

[xdmcp]
Enable=true

这时候使用xlaunch, 在第一页选择除了Multiple window之外的一个选项(因为它不支持xdmcp.), 下一步选项Open session via XDMCP, 下一步选择connect to host, 把ip填为colinux的ip, 然后再一步, 点Finsh就成了. 这样应该就可以看到linux的图形化登录界面了. 其他就不用多讲啦.

最后赞一下xming, 效果很不错, 很好用, 不过在我的window7下偶尔会有程序崩溃的情况. 但是窗口的显示都和本地窗口区别不大, 下面是我的一个对比图, 图里分别是colinux通过xming显示的emacs, 另外一个是本地的emacs窗口. 你知道哪个是本地的窗口哪个是xming显示的窗口没? :P

emacs

January 8th, 2009colinux && xming (part 2)

上篇, 下面来进行网络设置, 这里我们采用共享的方式连接网络.

colinux后会创建一个虚拟的网卡设备, 名字应该是 以“TAP-Win32 Adapter V8”开始的, 首先把这个网卡改成英文名像linuxNet以确保在配置文件中引用的时候不会出现中文的啥问题. 如果你安装colinux后没有发现的新的网络连接, 请检查安装时是不是有网络相关的选项上没选上:)

首先把你的本地网卡的那个连接(假设它的名字为本地连接)禁用, 不然无法共享, 右键本地连接, 选择属性, 在打开的窗口中选择 “共享”那一页, 勾上”允许其他网络用户通过此计算机的Internet连接来连接”, 并在出现的下拉列表中选择”linuxNet”, 这样你的linuxNet就可以通过本地连接访问网络了. 在这之前再做最后一步, 编辑linuxNet的属性, 注意linuxNet的ip地址是不是和你网关的ip相冲突, 如果冲突就把它改成其他的ip, 例如, 假设网关ip为192.168.0.1, 那就把liuxNet的ip改成192.168.1.1就成了.

编辑linuxcfg.txt, 加入如下行:

eth0=tuntap,”linuxNet”

这里就相当于把linuxNet映射为colinux中的eth0设备.

启动colinux, 这样应该就可以正常识别eth0了.

登录系统后需要修改一下linux系统的网络配置:

auto eth0
iface eth0 inet static
address 192.168.1.102  #ip要和gateway在一个网段
netmask 255.255.255.0
gateway 192.168.1.1  #gateway的值就是你linuxNet的ip

然后/etc/init.d/networking restart 重新启动eth0(这里或者使用ifconfig来搞, 就请自己研究吧:) ), 这时应该就可以连到网络了.  可ping一下网关看看通没通.

ping 192.168.1.1 来看看网络是不是连通

最后是更新/etc/resolve.conf文件, 指定域名服务器为网关地址就好

$cat /etc/resolve.conf

nameserver 192.168.0.1 #这里的地址根据实际情况作相应修改.

另外colinux的网络连接还有另外一种方式, 有时间再写.

再接下来的问题, colinux不支持X, 所以我们会发现只能使用命令行, 这样的colinux当然不是我们想要的, 于是让我们明天再开始下一篇 xming和colinux.


© 2007 pangwa's Blog | iKon Wordpress Theme by Windows Vista Administration | Powered by Wordpress