HTML5中声音和桌面通知特性的简单应用

2013-08-06 • 技术文章

HTML5中引入了audio标签和桌面通知的特性,这样我们就可以给用户更好的消息通知了,下面用代码简单说明声音和桌面通知在JavaScript中的应用。

声音

1
2
var msg = new Audio("msg.ogg");
msg.play();

通知

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
30
31
32
33
34
35
36
37
38
39
40
41
42
// old for chrome
function notify(msg) {
    if(window.webkitNotifications && window.webkitNotifications.checkPermission() == 0) {
        var notify = window.webkitNotifications.createNotification('icon.png', 'Notice', msg);
        //设置定时撤销机制,防止通知长时间显示不被关闭
        notify.ondisplay = function(event) {
            setTimeout(function() {
                event.currentTarget.cancel();
            }, 10000);
        };
        //下面是定义点击事件,类似地还可定义其它事件
        notify.onclick = function() {
            window.focus();
            this.cancel();
        };
        //弹出
        notify.show();
    } else if(window.webkitNotifications) {
        window.webkitNotifications.requestPermission(notify);
    }
}
 
// new for standard
function notify(msg) {
    if (Notification.permission === "granted") {
        spawnNotification(msg);
    } else {
        Notification.requestPermission(function (permission) {
            if (permission === "granted") {
                spawnNotification(msg);
            }
        });
    }
}
 
function spawnNotification(msg) {
    var n = new Notification('Notice', {
        body: msg,
        icon: 'icon.png'
    });
    setTimeout(n.close.bind(n), 4567);
}

参考资料

MDN:Notification

下载的Office文档无法打开,提示“内存不足”的解决

2013-06-21 • 技术文章

在Windows 8/Server2012中,由于权限比较严,下载的Excel、Word文档在使用Office打开时会提示“内存不足”或者其它诡异问题,原因在于权限,而非真正的内存不足。解决办法是:右击该文件,在属性中点击“解除锁定”按钮。

UEFI模式+GPT硬盘实现Windows 8与Ubuntu双系统启动

2013-03-24 • 技术文章

在部分使用GPT硬盘并启用(U)EFI模式已安装Windows 8/Server2012的计算机上,在未分配空间追加安装Ubuntu操作系统时(12.04.2和12.10以后的64位版本支持EFI),可能发生Ubuntu安装后无法实现Grub引导Ubuntu启动的问题。如果想转换GPT为MBR降低事情的难度,请参考这篇博客;如果想继续用GPT,请继续向下阅读。

这种情况发生时,我们可以利用LiveCD模式进行处理,从而实现双启动。但是这必须破坏Windows原有的启动引导来完成,尚不清楚这是否违反微软的用户协议,但为了解决Ubuntu启动的问题,暂时仅能这样处理了。

在UEFI模式下,在GPT硬盘(GPT硬盘对分区有特别要求,但只要使用支持GPT的新系统安装包重新分区一般可以解决)分区情况一例如下:

1
2
3
4
5
6
7
/dev/sda1 (恢复分区)
/dev/sda2 efi (boot分区)
/dev/sda3 
/dev/sda4 Windows
/dev/sda5 /boot 
/dev/sda6 /
/dev/sda7 linux-swap

在使用Ubuntu可引导安装介质照常安装完Ubuntu(启动引导器放在/dev/sda,若放在他处可能需要根据需要改变下面的操作步骤)后,我们挂载/dev/sda2会发现在该分区中,Ubuntu已经将自己的EFI启动文件grubx64.efi写入了ubuntu目录中,但仍然仅有Windows可以启动。部分网上的方案是使用EasyBCD 2.2进行处理,虽然该版本自称可以支持EFI,但事实并非如此,请直接略过该软件。在/dev/sda2分区中,我们可以发现共有三个文件夹:Boot、Microsoft、ubuntu,下面为了能够让ubuntu顺利启动,我们要用先重命名Windows本身的efi文件并用ubuntu的efi文件将其替换掉。

以上就是我们的思路,下面是利用LiveCD启动并进入Try Ubuntu(试用)后的终端处理步骤(#后为注释):

1
2
3
4
5
6
7
8
sudo -i #提权
mkdir /mnt/temp #新建挂载目录
mount /dev/sda2 /mnt/temp #挂载efi分区,根据实际情况选择sda的分区号
cd /mnt/temp/EFI/Microsoft/Boot/ #进入Windows启动文件所在目录
cp bootmgfw.efi win.efi #备份Windows启动引导文件
cd ../..
cp ubuntu/grubx64.efi Microsoft/Boot/bootmgfw.efi #用ubuntu启动文件替换掉Windows引导文件
exit

此时,重启移除引导设备,你应该就可以看到Grub启动菜单了,即使你看到了Windows启动菜单,请不要选择,ubuntu生成的那个启动项并不能真正的启动Windows 8以及更新的操作系统,因为这些新系统的启动方式已经变动,而ubuntu仍然使用了旧的方法生成Windows启动项。选择ubuntu系统进入,然后提权编辑/etc/grub.d/40_custom文件,在文件尾部追加以下几行:

1
2
3
4
5
6
menuentry "Windows 8" { #引号内的内容随便填,总之就是新启动条目的名字
    insmod part_gpt
    insmod ntfs
    set root='(hd0,gpt2)' #这里的GPT2的2就是efi分区的sda编号
    chainloader /EFI/Microsoft/Boot/win.efi #这里指定我们先前备份的Windows引导文件
}

在终端中执行sudo update-grub即可更新启动菜单。重新启动后,Windows的系统时间可能发生问题,采用太平洋时间而不是东八区,这时需要在/etc/default/grub中将UTC=yes改为UTC=no。之后,重新启动你就会看到支持双启动的Grub菜单。

如果是更多重启动,也可采用类似方式进行编辑。

当前12306订单确认时全部提示无票的解决方案

2012-12-26 • 技术文章

校内不少同学反映,即使12306查询有票,学生订票时点完提交订单也全部无票无法点击“确定”。对于此问题可使用以下方式解决。

1. 安装Chrome内核浏览器并通过https://dynamic.12306.cn/otsweb/main.jsp(一定是这个地址,否则Chrome打不开)访问12306;2. 在“确定”按钮附近位置右击选择“审查元素”;3. 找到代码中的disabled字符,双击disabled编辑源代码,删掉这个disabled;4. 点击空白处自动保存更改后的源代码,再点一下“确定”就完成了订票。

注:本方法仅用于解决12306空调系统故障恢复上线后产生的BUG,目前BUG已不存在,本方法失效。

C++类内静态变量的使用

2012-10-15 • 技术文章

近日在编写一个C++的用户类用来检查用户是否合法时遇到编译错误。源代码如下:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include<iostream>
#include<cstring>
using namespace std;
 
class User
{
public:
        User(char *name,char *pass)
        {
                strncpy(username[num],name,strlen(name));
                username[num][strlen(name)]='\0';
                for(int i=0;i<strlen(pass);i++)
                        password[num][i]=(i+pass[i])%256;
                password[num][strlen(pass)+1]='\0';
                num++;
        }
        static void User::AddUser(char *name,char *pass)
        {
                strncpy(username[num],name,strlen(name));
                username[num][strlen(name)]='\0';
                for(int i=0;i<strlen(pass);i++)
                        password[num][i]=(i+pass[i])%256;
                password[num][strlen(pass)+1]='\0';
                num++;
        }
        static int User::loggin(char *name,char *pass)
        {
                for(int i=0;i<num;i++)
                        if(strcmp(username[i],name)==0)
                        {
                                for(int j=0;pass[j]!='\0';j++)
                                        if(password[i][j]!=(j+pass[j])%256)
                                                return -1;
                                return i;
                        }
                return -1;
        }
private:
        static char User::username[10][20];
        static char User::password[10][20];
        static int User::num;
};
 
int User::num=0;
 
int main()
{
        char name[20],pass[20];
        User u1("LiWei","liwei99");
        u1.AddUser("ChenHanfu","20090911");
        User::AddUser("Zhanggaolin","198845");
        cout<<"Input username:";
        cin>>name;
        cout<<"Input password:";
        cin>>pass;
        if(User::loggin(name,pass)>=0)
                cout<<"success login!"<<endl;
        else
                cout<<"login fail!"<<endl;
        return 0;
}

编译时,产生如下错误:

1
2
3
4
5
6
7
8
9
10
11
12
A:\Homework\CPP\Stu\Debug\4.o: In function `ZN4UserC1EPcS0_':
A:\Homework\CPP\Stu\4.cpp:(.text$_ZN4User6logginEPcS0_[User::loggin(char*, char*)]+0x2b): undefined reference to `User::username'
A:\Homework\CPP\Stu\4.cpp:(.text$_ZN4User6logginEPcS0_[User::loggin(char*, char*)]+0x65): undefined reference to `User::password'
A:\Homework\CPP\Stu\4.cpp:(.text$_ZN4User7AddUserEPcS0_[User::AddUser(char*, char*)]+0x2d): undefined reference to `User::username'
A:\Homework\CPP\Stu\4.cpp:(.text$_ZN4User7AddUserEPcS0_[User::AddUser(char*, char*)]+0x59): undefined reference to `User::username'
A:\Homework\CPP\Stu\4.cpp:(.text$_ZN4User7AddUserEPcS0_[User::AddUser(char*, char*)]+0x8b): undefined reference to `User::password'
A:\Homework\CPP\Stu\4.cpp:(.text$_ZN4User7AddUserEPcS0_[User::AddUser(char*, char*)]+0xf2): undefined reference to `User::password'
A:\Homework\CPP\Stu\4.cpp:(.text$_ZN4UserC1EPcS0_[User::User(char*, char*)]+0x2d): undefined reference to `User::username'
A:\Homework\CPP\Stu\4.cpp:(.text$_ZN4UserC1EPcS0_[User::User(char*, char*)]+0x59): undefined reference to `User::username'
A:\Homework\CPP\Stu\4.cpp:(.text$_ZN4UserC1EPcS0_[User::User(char*, char*)]+0x8b): undefined reference to `User::password'
A:\Homework\CPP\Stu\4.cpp:(.text$_ZN4UserC1EPcS0_[User::User(char*, char*)]+0xf2): undefined reference to `User::password'
collect2: ld returned 1 exit status

从编译错误提示信息“undefined reference”(未定义的依赖)可以看出问题出在User::username和User::password的定义上。

对于类内的三个成员,其中num变量并没有报错,而username和password出错,这是因为num在类外进行了初始化赋值。对类内的三个成员来说,类内仅仅是对他们进行了声明,而并没有进行定义。我们需要注意:定义(definition)=声明(declaration)+存储空间(storage allocation)。没有进行定义的类内变量显然无法调用,所以我们需要在类外进行一次定义即可解决问题,这不是违反单一定义法则(One-definition Rule),而恰恰是满足该法则。

1
2
3
int User::num=0;
char User::username[10][20];
char User::password[10][20];

另外,对于类内的静态变量,以本题代码为例,无论是User u1这个对象中还是User域中进行函数操作调用的都是相同的存储在静态数据区的变量。而诸如“extern int n;”这样的语句也不是定义,其仅仅是说明了变量n的有效范围。

这个问题折腾了半个星期,以后应当注意对象是否真正完成了定义。