手机浏览 RSS 2.0 订阅 膘叔的简单人生 , 腾讯云RDS购买 | 超便宜的Vultr , 注册 | 登陆
浏览模式: 标准 | 列表Tag:microsoft

gentoo常用命令

由于burst上面的虚拟机经常挂掉,然后我申请要退款,burst建议我换个OS或者Reinstall看看,我一咬牙,把VPS换到了linode上面,于是 把burst上面的VPS的OS换成了gentoo,结果我ssh上去之后习惯性的ls,居然告诉我命令不存在。我晶啊。
这下子玩大了。然后找了一下资料,emerge upgrade后,才有了这个命令,我傻眼了。想装B没装成,害惨自己了。
于是,找了下资料,参考:http://hi.baidu.com/chinsung/blog/item/3d21b6deee859f5dccbf1a51.html

1. 更新系统并移除孤立依赖的软件包
# emerge --update --deep --newuse world
# emerge --depclean
# revdep-rebuild (搜索相应缺失的库,并且重新emerge相应的包,需安装gentoolkit,并需运行两次以便确认)

2. emerge常用参数:
2.0 world | system, world范围更广,包含了system,这是两个set,前面不用加--或-
2.1 -p pretend 预览
2.2 -a ask 先予询问
2.3 -c clean 清理系统
2.4 -C unmerge 卸载,与emerge相反
2.5 --depclean 深度清理,移除与系统无关的包
2.6 -h help 帮助文件
2.7 -v verbose 详细内容
2.8 -s search 查找
2.9 -S searchdesc 从文件名和描述中查找,要慢一些
2.10 -u update 升级软件包
2.11 -D deep 计算整个系统的依赖关系
2.12 -e emptytree 清空依赖树,一般不用,危险命令
2.13 -1 oneshot 一次性安装,不将其信息加入系统目录树
2.14 -o onlydeps 只安装其依赖关系,而不安装软件本身
2.15 -t tree 显示其目录树信息
2.16 -k usepkg 使用二进制包
2.17 -K usepkgonly 只使用二进制包
2.18 -f fetchonly 仅下载安装包
2.19 --sync 从指定的rsync站点更新portage树,先前所作所有portage树更改均失效
2.20 -N newuse 使用新的USE FLAG,如有必要,需重新编译
2.21 -n noreplace 更新system,但先前安装的软件不予覆盖

3. 查找最快的mirror
# mirrorselect -s3 -b10 -o -D >> /etc/make.conf
此命令对每个mirror均下载100k文件,以此确定最快源,要注意修改/etc/make.conf

4. 系统升级
# emerge --sync 或 # emerge-webrsync (更新或称同步portage树)
# emerge --update --deep --newuse world
# emerge --depclean -pv
# revdep-rebuild (需安装gentoolkit)
如果使用emerge-webrsync命令进行升级,可先下载最新的portage(以日期命名,而不要用latest命名)至/var/tmp/emerge-webrsync/目录

5. 查看安装XXX的情况,
同时列出了使用的 USE 和 LINGUAS
# emerge -pv XXX

6. 在world中增加记录,避免自己已手动编译的软件被再次编译
# emerge -n fcitx (添加fcitx至emerge tree)

7. 配置文件更新工具
# etc-update 或 # dispatch-conf

8. 查询XXX包用了什么USE(需gentoolkit)
# equery uses XXX

9. 找到 /bin/ls 所属包
# qfile /bin/ls

10. 列出 glibc 包所包含文件
# qlist glibc

11. /etc/portage/package.*应用举例

11.1 package.use

sys-apps/man-pages -nls sys-apps/pciutils -zlib media-libs/freetype bindist app-text/acroread linguas_zh_TW linguas_zh_CN linguas_en

作用:

不改变全局USE的同时,微调包的USE。 开始2个是说这2个包不使用相应的 USE,第三个说明要单独在这个包使用这个USE,最后一个是调整 LINGUAS 的,很容易明白。


11.2 package.keywords

sys-apps/hdparm ~x86

作用:

指定相应的包的 KEYWORDS。比如你想 hdparm 包用 ~x86 的版本,而不用 x86 的版本,就用这个来指定。 注意,因为 emerge 的设计,如果你的 make.conf 里边指定了 ~x86的话,你不能反过来通过指定 x86 而 不要 ~x86,只能用 -~x86 来达到目的。 引用 gentoo@freenode 上<kojiro>的话: ”ACCEPT_KEYWORDS is incremental“

11.3 package.mask

>sys-devel/libtool-1.5.23

作用:

屏蔽某个包某个版本,或者某些版本,甚至整个包。
比如 libtool-1.5.23b 在我的系统有问题,那么就屏蔽一下,只用 比 1.5.23 小的。

11.4 package.unmask

=net-www/apache-2.2.4 games-arcade/stepmania

和 mask 一样,不过效果正好相反。我要用 2.2.4 的 apache,但是 portage 把他 mask 了,所以手动 unmask 一下。

12. 往 default runlevel 里边加入 XXX 服务 (add)

# rc-update -a XXX default

13. 从 default runlevel 里边删除 XXX 服务 (delete)
# rc-update -d XXX default

14. 列出 default runlevel 所有的服务 (show)
# rc-update -s default

15. 删除过期的包
# eclean distfiles (请先 emerge gentoolkit)

16. 清除emerge过程中产生的临时文件
# rm -rf /var/tmp/portage/*

17. 清除所有安装源码包(除非太穷,否则不建议)
# rm -rf /usr/portage/distfiles/*

-------
不管它不管它,先备份,天知道以后会不会用,

Tags: vps, os, gentoo, burst, linode

瞎折腾:程序员什么时候效率最高

有人说:
"有句还挺受欢迎的话是,程序员就是把咖啡变成代码的机器。随便问一个程序员什么时候效率最高,很有可能他们会说大多是深夜的时候(中文)。 有些早点,有些晚点。常见的是:在凌晨4点起床,赶在吵闹的一天开始前完成一些工作。另外一些喜欢在凌晨4点睡觉。这种做法的目的是避免干扰。但是你可以 锁上门啊,为什么夜晚这么特别呢?swizec 的博主认为可以归结为三件事:员工的时间表、疲惫的大脑和明亮的电脑屏幕。"

其实想想不完全是这样,白天的时候在单位各种各样的事情,都有可能会导致写代码的时候被打断,这种打断其实很影响写代码,思路一断,很可能半小时一小时都不会恢复。晚上没人,外面也很安静,虽然说真的是避免干扰,但其实晚上和清晨人的大脑好象很容易集中(所以我们小时候背书一般都在凌晨,当然也有深夜)。【传说,屙扁扁的时候人的记忆力是最好的,所以那个时候看书其实很容易记得牢,无科学依据,纯粹说说】。

果然有中文版的(上面斜体字中的中文版,我复制过来了,但不复制图,要看原文请移步:http://blog.jobbole.com/10797/)

XML/HTML代码
  1. 有句还挺受欢迎的话是,程序员就是把咖啡变成代码的机器。  
  2.   
  3. 果然,随便问一个程序员什么时候效率最高,很有可能他们会说大多是深夜的时候。有些早点,有些晚点。常见的是:在凌晨4点起床,赶在吵闹的一天开始前完成一些工作。另外一些喜欢在凌晨4点睡觉。这种做法的目的是避免干扰。但是你可以锁上门啊,为什么夜晚这么特别呢?  
  4.   
  5. 我认为可以归结为三件事:员工的时间表、疲惫的大脑和明亮的电脑屏幕。  
  6.   
  7. 员工的时间表  
  8.   
  9. Paul Graham在2009年写过关于员工的时间表的问题 —— 基本上,在世界上有两种类型的时间表。传统管理者的时间表是分散地切割成小时和一个个十分钟的方式绩效,通常是按一个小时的价值给你报酬。  
  10.   
  11. 另一种,叫做员工的时间表——针对我们这些程序员。工作于大型虚拟系统时,需要把所有涉及的事都记在脑子里——有人曾经比喻这就像用昂贵的水晶建造房子,一旦有人打扰,房子就一股脑塌落并碎成一片。  
  12.   
  13. 这就是为什么当有人打断程序员的思路时,他们那么恼火。  
  14.   
  15. 由于这种巨大的精力投入,使得我们无法简单地开始工作,直到我们能连续几小时不被分散注意力才行。刚在脑中构建了整个模型,结果半小时后就毁了可不值得。  
  16.   
  17. 事实上,跟很多员工交谈后你会发现,他们感觉根本不能在白天完成任何工作。接连不断地被打扰、关注重要的事物和回复邮件都不能让他们安心工作。所以他们选择在别人睡觉的深夜来完成大部分的工作。  
  18.   
  19. 疲惫的大脑   
  20.   
  21. 就算是程序员,晚上也应该睡觉。我们不是超人。也会感到白天更机敏。  
  22.   
  23. 那为什么我们要在大脑想睡觉的时候做最复杂的工作,而在大脑最敏锐和灵活的时候做简单的任务呢?  
  24.   
  25. 与巴尔默峰值类似,疲劳让我们更易集中精力,因为当你的大脑疲劳时,它就必须集中精力!没有多余的脑力让你不集中精力。(《“10倍效率”程序员/开发人员的习惯》第5点:集中精力)  
  26.   
  27. 我似乎在喝茶过多或不合适的时间喝能量饮料后完成的工作最少。这些让我很活跃,一会儿查看Twitter,一会儿看看Hacker News,我似乎一直在到处浏览。  
  28.   
  29. 你应该在想我能很好地工作——这么有精力,这么有脑力。但是相反,我一直在阻绊自己因为我不能集中精力超过两秒。  
  30.   
  31. 然而,当我微感疲倦时,我就能坐下来编码了。用有点疲劳的大脑,我能一小时又一小时地编码,甚至都不想查看Twitter或者FaceBook。就好像互联网不存在了。  
  32.   
  33. 我觉得这适用于大多数程序员。我们有太多的精力去完成80%的工作——面对现实吧,一个好的算法,需要用10倍的代码量来营造使用它的环境。即使你做的是最高级的机器学习(或者是其他的),很多工作也仅仅只是清理数据和将结果以友好的方式呈现出来。  
  34.   
  35. 当你的大脑并不是竭尽全力地工作时,它就会找其他的事做。疲劳使你愚钝,从而使你只能顾及手头上的工作。   
  36.   
  37. 明亮的电脑屏幕  
  38.   
  39. 这条非常简单。在夜晚一直盯着明亮的光源并且使你的睡眠周期延后。你直到凌晨3点才感到疲倦。然后中午11点起床,当夜晚来临时你并不感到疲劳,因为,呵呵,你中午11点才起床!  
  40.   
  41. 经过足够多的反复,本质上是把你带到了不同的时区。更有趣的是,它会保持相对稳定,一旦你进入凌晨3、4点睡觉的节奏中,你就会一直保持那样。  
  42.   
  43. 结语  
  44.   
  45. 综上所述,程序员晚上工作是因为没人强制规定你必须什么时候停止工作,这可以给你更轻松的方式,你的大脑不再一直寻找分心的事并且明亮的屏幕使你保持清醒。 

原文链接:swizec.com   编译:伯乐在线 – 魏哲

虚拟机上iptables不支持nat转发?

在虚拟机上尝试装ppptp的时候,发现一个问题,因为最后需要设置iptables,但是在执行的时候,报了这个错:
can’t initialize iptables table `nat’ ,后面还有一句我就不贴了。

找了很多资料,发现可能是在编译内核的时候,把nat去掉了。这样我就无法转发nat了。也就是说我的pptp是没有办法成功运行了。

再google了一下,发现一些问题,如果要加上这个nat,好象非得重新编译内核。否则无法装上。当然,也看到一篇文章说直接运行某句命令就OK了。【来源:http://pearlin.info/enable-nat-module-for-vps-cant-initialize-iptables-table-nat-table-does-not-exist/】
但好象我的虚拟机不是openVZ的。。。继续哭泣

XML/HTML代码
  1. I was getting the following error which configuring NAT on a VPS server.  
  2.   
  3. =========  
  4.   
  5. # iptables -t nat -nvL  
  6. iptables v1.3.5: can’t initialize iptables table `nat’: Table does not exist (do you need to insmod?)  
  7. Perhaps iptables or your kernel needs to be upgraded.  
  8.   
  9. =========  
  10.   
  11. You can fix this by using the following commands.  
  12.   
  13. vzctl set 115 –iptables “iptable_nat iptable_filter iptable_mangle ip_conntrack ipt_conntrack ipt_REDIRECT ipt_REJECT ipt_multiport ipt_helper ipt_LOG ipt_state” –save  
  14. Saved parameters for VE 115  
  15.   
  16. # vzctl restart 115  
  17. …  
  18. # vzctl enter 115  
  19. # iptables -t nat -nvL  
  20. Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)  
  21. pkts bytes target prot opt in out source destination  
  22.   
  23. Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)  
  24. pkts bytes target prot opt in out source destination  
  25.   
  26. Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)  
  27. pkts bytes target prot opt in out source destination   

不知道VPS的提供商能不能帮我装了。如果不行,那我可能就要換VPS了。。。痛苦啊。下次还是用UBUNTU吧。方便。。。。

Tags: iptables, nat

好文推荐:五款常用mysql slow log分析工具的比较

一直在用MYSQL,因此对于慢查询就非常在意,虽然自己写代码的时候不是特别注意,但真正上线后还是要关注关注的。

最简单的看LOG就是用phpmyadmin查看一下,但这终究不是办法。所幸,工具还是很多的。javaeye上就有人贴出了工具和使用方法 :

启用 slow log

有两种启用方式:
1, 在my.cnf 里 通过 log-slow-queries[=file_name]
2, 在mysqld进程启动时,指定--log-slow-queries[=file_name]选项

比较的五款常用工具

mysqldumpslow, mysqlsla, myprofi, mysql-explain-slow-log, mysqllogfilter

mysqldumpslow, mysql官方提供的慢查询日志分析工具. 输出图表如下:
大小: 256.22 K
尺寸: 500 x 210
浏览: 2368 次
点击打开新窗口浏览全图
主要功能是, 统计不同慢sql的
出现次数(Count), 
执行最长时间(Time), 
累计总耗费时间(Time), 
等待锁的时间(Lock), 
发送给客户端的行总数(Rows), 
扫描的行总数(Rows), 
用户以及sql语句本身(抽象了一下格式, 比如 limit 1, 20 用 limit N,N 表示).

mysqlsla, hackmysql.com推出的一款日志分析工具(该网站还维护了 mysqlreport, mysqlidxchk 等比较实用的mysql工具)
大小: 211.77 K
尺寸: 500 x 268
浏览: 2237 次
点击打开新窗口浏览全图
整体来说, 功能非常强大. 数据报表,非常有利于分析慢查询的原因, 包括执行频率, 数据量, 查询消耗等.
 
格式说明如下:
总查询次数 (queries total), 去重后的sql数量 (unique)
输出报表的内容排序(sorted by)
最重大的慢sql统计信息, 包括 平均执行时间, 等待锁时间, 结果行的总数, 扫描的行总数.
 
Count, sql的执行次数及占总的slow log数量的百分比.
Time, 执行时间, 包括总时间, 平均时间, 最小, 最大时间, 时间占到总慢sql时间的百分比.
95% of Time, 去除最快和最慢的sql, 覆盖率占95%的sql的执行时间.
Lock Time, 等待锁的时间.
95% of Lock , 95%的慢sql等待锁时间.
Rows sent, 结果行统计数量, 包括平均, 最小, 最大数量.
Rows examined, 扫描的行数量.
Database, 属于哪个数据库
Users, 哪个用户,IP, 占到所有用户执行的sql百分比
 
Query abstract, 抽象后的sql语句
Query sample, sql语句
 
除了以上的输出, 官方还提供了很多定制化参数, 是一款不可多得的好工具.
 
mysql-explain-slow-log, 德国人写的一个perl脚本.
http://www.willamowius.de/mysql-tools.html
大小: 107.58 K
尺寸: 500 x 147
浏览: 2275 次
点击打开新窗口浏览全图
大小: 98.35 K
尺寸: 500 x 145
浏览: 2259 次
点击打开新窗口浏览全图
功能上有点瑕疵, 不仅把所有的 slow log 打印到屏幕上, 而且统计也只有数量而已. 不推荐使用.
mysql-log-filter, google code上找到的一个分析工具.提供了 python 和 php 两种可执行的脚本.
http://code.google.com/p/mysql-log-filter/
大小: 179.2 K
尺寸: 500 x 156
浏览: 2222 次
点击打开新窗口浏览全图
功能上比官方的mysqldumpslow, 多了查询时间的统计信息(平均,最大, 累计), 其他功能都与 mysqldumpslow类似.
特色功能除了统计信息外, 还针对输出内容做了排版和格式化, 保证整体输出的简洁. 喜欢简洁报表的朋友, 推荐使用一下.
myprofi, 纯php写的一个开源分析工具.项目在 sourceforge 上.
http://myprofi.sourceforge.net/
大小: 176.74 K
尺寸: 500 x 137
浏览: 2204 次
点击打开新窗口浏览全图
功能上, 列出了总的慢查询次数和类型, 去重后的sql语句, 执行次数及其占总的slow log数量的百分比.
从整体输出样式来看, 比mysql-log-filter还要简洁. 省去了很多不必要的内容. 对于只想看sql语句及执行次数的用户来说, 比较推荐.

总结

工具/功能 一般统计信息 高级统计信息 脚本 优势
mysqldumpslow 支持 不支持 perl mysql官方自带
mysqlsla 支持 支持 perl 功能强大,数据报表齐全,定制化能力强.
mysql-explain-slow-log 支持 不支持 perl
mysql-log-filter 支持 部分支持 python or php 不失功能的前提下,保持输出简洁
myprofi 支持 不支持 php 非常精简
---EOF---
作者:galaxystar,来自:http://www.javaeye.com/topic/242516,他现在的博客是:http://kenwublog.com/。

Tags: slow query, mysql, tools

[转载]一步一步学习Firefox扩展的开发[据说这将是一个系列]

Firefox的插件也曾经研究过,对于XUL感觉也有点痛苦,当初想研究它是为了给自己的博客增加插件,可以方便的让自己在找到好的资料的时候,可以直接通过插件发送到博客上。但最终我还是放弃了。没有什么理由。。。。

看到有人在贴一步一步学习的教程,又有点拾起了回忆,如果有可能,这个系列,我会在这个作者写的同时,也一点点的转载。
希望作者不要见怪,转载完了,我也贴点我在开发的时候遇到的问题之类。当然一切都到元旦后。。。
原文网址:http://www.cnblogs.com/uubox/archive/2008/12/25/1361278.html
作者:DOMS
内容:Firefox提供开放、强大且灵活的扩展机制,因此衍生出了大量功能丰富的扩展组件,这些扩展组件甚至可以说是某些用户爱上firefox的主要因素。
比较可惜的是firefox扩展开发的中文资料相对比较少,因此在这里我会从简单到深入介绍开发firefox扩展的一些技术及常遇到的问题。

本文主要内容:

  • 制作一个包含工具栏按钮及右键菜单的简单组件
  • 解决扩展安装后工具栏按钮却不显示的问题


因为这个组件不需要设计交互窗口,因此开发过程相对简单,下面是这个组件运行的效果图:
firefox_addons_demo1_view.jpg

在开始之前先介绍一下几个网址:

  1. https://developer.mozilla.org/en/Extensions 官方开发网,类似MSDN,是开发时的主要参考资料;
  2. https://developer.mozilla.org/en/Building_an_Extension,官方的一个基础教程,笔者通过此篇文章而入门;
  3. http://ted.mielczarek.org/code/mozilla/extensionwiz/,一个在线的创建扩展的向导,如果你想立即创建一个属于自己的扩展,可以试试用这个向导制作一个雏形,然后再自己慢慢添砖添瓦。本文所讲的例子也是用这个向导制作出来的。

另外还有本文例子的源代码:http://www.uushare.com/user/csprogram/file/1139797

好了,下面就开始讲解本文的示例组件:uusharedemo1的制作过程。

1、了解扩展组件的构成

Firefox 扩展组件是以一个xpi文件的形式发布的,而xpi文件实际上是zip压缩包文件,我们只要把Firefox扩展组件下载回来(用右键另存为即可下载), 把文件扩展名改为zip即可解压并看到所有的源代码,有时可能还会在压缩包里面看到jar格式文件,这个也是zip压缩包,改名解压即可看到源代码。因此 多下载优秀的扩展回来慢慢研究其源代码也不失为一种快速的学习方法。
一般xpi文件内部有(但不一定都有)如下目录及文件:
xpi_filetree.png
其中 uusharedemo1 为本文示例组件的名称,可以看到压缩包首层有:install.rdf及chrome.manifest两个文件以及一个chrome目录。

  • install.rdf:是该组件的安装信息,例如组件的名称、版本、作者等信息,XML格式;
  • chrome.manifest:是用于描述该组件由哪些文件组成的,即一个资源列表;


在chrome目录里就是该组件的主要内容了,一般有:content、defaults、locale、skin等目录,它们的作用如下:

  • content:这个是最主要的目录,包含组件的界面定义以及程序代码,其中xul文件是界面定义文件,类似SilverLight的XAML文件,同样是XML格式;js文件是组件功能实现的代码,全部用javascript实现的。
  • skin:存放css样式表文件及资源位图,css是用来控制组件界面外观的。
  • locale:如果想让组件能够在不同语言的firefox里显示正确的文本,则将不用的语言列表放到此目录,firefox会自动加载合适的语言文件。这点有些类似Win32PE可执行程序中的资源文件。
  • defaults:存放一些默认值,一般不要此目录也可以;


我 们可以把Firefox程序认为是一个平台,而我们看到firefox浏览器外观本身也是用跟扩展组件类似的结构搭建起来的,感兴趣的朋友可以解压 “C:\Program Files\Mozilla Firefox\chrome”目录下的jar文件观摩一下firefox浏览器外观的源代码,所以我们制作的扩展组件也会成为firefox浏览器自身 的一部分,可以实现非常强大而灵活的功能(例如Firebug这个神奇的组件)。相对来说,开发ie扩展程序显得困难多了,除非只是想做工具栏按钮和右键 菜单(用注册表即搞定),否则需要使用VC,VB,Delphi这些工具开发COM组件才能完成。

如果想了解firefox浏览器本身各个元素的定义,但又不想阅读chrome目录下的脚本代码,可以安装 DOM Inspector 这个组件,这个组件有如开发web时的FireBug,是开发具有界面的扩展组件时的神兵利器!

提醒:自己编写的组件代码文件最好用“UTF-8”格式保存,一般可以减少很多麻烦的问题。

2、认识install.rdf

install.rdf包含组件安装信息,本文例子中它的内容如下:

XML/HTML代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"   
  3.  xmlns:em="http://www.mozilla.org/2004/em-rdf#">  
  4.   <Description about="urn:mozilla:install-manifest">  
  5.     <em:id>uusharedemo1@uushare.com</em:id>  
  6.     <em:name>Uushare书签(示例)</em:name>  
  7.     <em:version>1.0</em:version>  
  8.     <em:creator>KwanhongYoung</em:creator>  
  9.     <em:description>这是一个模仿Uushare书签插件的示例</em:description>  
  10.     <em:homepageURL>http://www.uushare.com</em:homepageURL>  
  11.     <em:iconURL>chrome://uusharedemo1/content/uusharedemo1.png</em:iconURL>  
  12.     <em:targetApplication>  
  13.       <Description>  
  14.         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <!-- firefox -->  
  15.         <em:minVersion>1.5</em:minVersion>  
  16.         <em:maxVersion>3.0.*</em:maxVersion>  
  17.       </Description>  
  18.     </em:targetApplication>  
  19.   </Description>  
  20. </RDF>  



文件里有很多是固定的写法,这里就不一一讲解了。
第 5行的id是组件的一个标识符号,类似Windows里COM组件的CLSID,用于区别其他组件。可以使用 xxx@yyy.zzz 这样类似email地址的格式组成,而这个“email地址”不要求是真实或有效的。也可以用的GUID来标识,例如“{c45c406e- ab73-11d8-be73-000a95be3b12}”是WebDevelop组件的标识符。

name、version、creator、description、homepageURL分别是组件的名称、版本、创建者的姓名、组件描述、组件官方网站地址。
iconURL用于显示组件的图标,格式一般用32x32pixel的png图片。
这里出现了chrome://这样的地址,跟http://和file://协议类似,chrome://也是用来定位资源的。格式是:
chrome://组件名称/目录路径/文件名
需要注意的是,这里的组件名称可以跟em:name属性中所指定的名称(用于显示的)不一样的,并且这个组件名称需要在chrome.manifest里定义。
这些信息在安装完组件之后能够在firefox的组件管理列表显示,如下图:

firefox_addons_demo1_item.jpg

第14行比较重要,用于标识当前组件是用于哪个平台的(firefox/Thunderbird/SeaMonkey等),如果开发的组件是给firefox用的,则id={ec8030f7-c20a-464f-9b0e-13a3a9e97384}。
第 15、16行用于指定当前组件适用于firefox的哪些版本,因为firefox从1.5到3.0有些地方有所改变,所以如果你不知道自己的组件在哪些 版本下可运行的话,最好先测试一下,然后准确地指定一个范围值,上例的值表示该组件适用于firefox1.5到3.0及3.0所有修订版。版本号码不能 自己随便造,这里有一个完整的列表:
https://addons.mozilla.org/en-US/firefox/pages/appversions

3、认识chrome.manifest

这是资源列表文件,内容如下:

XML/HTML代码
  1. content    uusharedemo1    chrome/content/  
  2. locale    uusharedemo1    en-US    chrome/locale/en-US/  
  3. skin    uusharedemo1    classic/1.0    chrome/skin/  
  4. overlay    chrome://browser/content/browser.xul    chrome://uusharedemo1/content/firefoxOverlay.xul  
  5. style    chrome://global/content/customizeToolbar.xul    chrome://uusharedemo1/skin/overlay.css  



前3行每一行表示一种类型的资源的地址,格式是:
资源名称<Tab>组件名称<Tab>参数<Tab>目录路径
其中组件名称是自定义的,只要跟其他组件名不一样并且使用全小写字母即可。定义好之后,就可以使用chrome://地址来定位资源了。例如,假设当前开发文件路径是“c:/dev/uusharedemo1/”,那么:
chrome://uusharedemo1/content/uusharedemo1.png 实际指的是 c:/dev/uusharedemo1/chrome/content/uusharedemo1.png 这个文件。

第4行及第5行表示将当前组件的界面结合到系统本身的界面,因为当前组件会修改firefox本身的工具栏及右键菜单,所以需要加上这两行。

4、default/、skin/、locale/

这几个目录下的文件比较简单,下载本文的源代码查看一般能明白其中的意思,为了节约篇幅这里就不讲解了,等以后我写后续的章节时再详细介绍。

5、认识 content/firefoxOverlay.xul

Firefox的所有窗口都是使用xul文件定义的,例如在地址栏输入:
chrome://browser/content/aboutDialog.xul
(这个地址对应的源文件是:“C:\Program Files\Mozilla Firefox\chrome\browser.jar/content/aboutDialog.xul”
就可以看到firefox的“关于”对话框,在这个例子里我们用firefoxOverlay.xul定义一个工具栏按钮、右键菜单以及一个工具菜单项,源代码如下:

XML/HTML代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <!-- 下面一行指明当前窗口控件所引用的样式表文件 -->  
  3. <?xml-stylesheet href="chrome://uusharedemo1/skin/overlay.css" type="text/css"?>  
  4.   
  5. <!-- 这行指明当前窗口控件所使用的语言文件,注意这里不需指定语言的名称(即zh-CN或en-US等),只需指明文件名即可  
  6. 有了语言文件之后,所有控件的文本(即text/label等属性)都统一写到语言文件里。 -->  
  7. <!DOCTYPE overlay SYSTEM "chrome://uusharedemo1/locale/uusharedemo1.dtd">  
  8.   
  9. <overlay id="uusharedemo1-overlay"  
  10.          xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">  
  11.     
  12.   <!-- 这行用于指定当前窗口控件的事件(如单击事件)触发后所执行的代码所在的文件 -->  
  13.   <script src="overlay.js"/>  
  14.   <stringbundleset id="stringbundleset">  
  15.     <stringbundle id="uusharedemo1-strings" src="chrome://uusharedemo1/locale/uusharedemo1.properties"/>  
  16.   </stringbundleset>  
  17.   
  18.   <menupopup id="menu_ToolsPopup">  
  19.     <menuitem id="uusharedemo1-hello" label="&uusharedemo1.label;"   
  20.               oncommand="uusharedemo1.onMenuItemCommand(event);"/>  
  21.   </menupopup>  
  22.     
  23.   <popup id="contentAreaContextMenu">  
  24.     <menuitem id="context-uusharedemo1" label="&uusharedemo1Context.label;"  
  25.               accesskey="&uusharedemo1Context.accesskey;"  
  26.               insertafter="context-stop"  
  27.               oncommand="uusharedemo1.onMenuItemCommand(event)"/>  
  28.   </popup>  
  29.     
  30.   <toolbarpalette id="BrowserToolbarPalette">  
  31.   <toolbarbutton id="uusharedemo1-toolbar-button"  
  32.     label="&uusharedemo1Toolbar.label;"  
  33.     tooltiptext="&uusharedemo1Toolbar.tooltip;"  
  34.     oncommand="uusharedemo1.onToolbarButtonCommand()"  
  35.     class="toolbarbutton-1 chromeclass-toolbar-additional"/>  
  36.   </toolbarpalette>  
  37. </overlay>  

menupopup 段定义了一个位于“工具”菜单栏下的项目,其中id是菜单项的名称,我们自己添加的菜单项、按钮等结合到firefox本身的控件的id必须惟 一;label属性是菜单项显示的文本,这里因为引用了语言文件,所以真正显示的文本内容位于语言文件(uusharedemo1.dtd)里标有 uusharedemo1.label 这行定义的后面;oncommand属性定义菜单被点击后执行 overlay.js 里面的那一个方法过程。

popup 段定义了一个右键菜单项,accesskey为菜单项的快捷键(即带下划线的字母),insertafter为新菜单项所出现的位置位于id为 “context-stop”(即“停止”)这项的后面,如何得知某一项菜单项的id呢?出动Dom Inspector 吧。包括firefox工具栏上面的所有按钮的id,都可以用Dom Inspector查看得知。

toolbarpalette段定义了一个工具栏按钮,其中tooltiptext为鼠标停留在这个新按钮上面时所显示的提示文本。

上面一段代码并没有定义自己的窗口,我会在下一章再讲解。

6、认识content/overlay.js

overlay.js 文件是专门为上面的firefoxOverlay.xul服务的,(怎么知道的呢?在firefoxOverlay.xul文件的第13行有引用啊)。在 xul文件里可以看到菜单被点击之后会调用一个名叫“onMenuItemCommand”的方法过程,而工具栏按钮被点击之后会调用 “onToolbarButtonCommand”方法过程。我们想在他们被点击之后做什么事情呢?为了演示如何在js里编写调用firefox对象的代 码,这里模仿uushare书签的功能,让菜单和按钮点击之后调用Uushare.com网站上的书签服务的添加书签的接口,接口是这样的:

http://www.uushare.com/bookmark/save?v=1&client=ff10&noui=yes&jump=close&url=XXXX&title=YYYY&content=ZZZZ

其中XXXX为待收藏的网页地址,YYYY是网页的标题,ZZZZ是网页中选中的文本。所以我们需要在js里获取当前网页的URL、Title以及被选中的文本。
下面是例子中的代码:

JavaScript代码
  1. var uusharedemo1 = {  
  2.   onLoad: function() {  
  3.     // initialization code  
  4.     this.initialized = true;  
  5.     this.strings = document.getElementById("uusharedemo1-strings");  
  6.     document.getElementById("contentAreaContextMenu")  
  7.             .addEventListener("popupshowing"function(e) { this.showContextMenu(e); }, false);  
  8.   },  
  9.   
  10.   showContextMenu: function(event) {  
  11.     // 根据上下文决定显示/隐藏右键菜单项  
  12.     // see http://kb.mozillazine.org/Adding_items_to_menus  
  13.     document.getElementById("context-uusharedemo1").hidden = gContextMenu.onImage;  
  14.   },  
  15.     
  16.   onMenuItemCommand: function(e) {  
  17.     uusharedemo1.addToUushareBookmark();  
  18.   },  
  19.     
  20.   addToUushareBookmark: function() {  
  21.      //这里调用 uushare.com 书签API的接口  
  22.     var location, title, desc;  
  23.     var browser = window.getBrowser();  
  24.     var webNav = browser.webNavigation;  
  25.   
  26.     if (webNav.currentURI)  
  27.         location = webNav.currentURI.spec;  
  28.     else  
  29.         location = gURLBar.value;  
  30.   
  31.     if (webNav.document.title) {  
  32.         title = webNav.document.title;  
  33.     }  
  34.     else {  
  35.         title = location;  
  36.     }  
  37.   
  38.     var focusedWindow = document.commandDispatcher.focusedWindow;  
  39.     var winWrapper = new XPCNativeWrapper(focusedWindow, 'getSelection()');  
  40.     desc = winWrapper.getSelection().toString();  
  41.   
  42.     var serverUrl = "http://www.uushare.com/bookmark/save?v=1&client=ff10";  
  43.     var saveUrl = serverUrl + "&noui=yes&jump=close&url=" + encodeURIComponent(location) + "&title=" + encodeURIComponent(title) + "&content=" + encodeURIComponent(desc);  
  44.     window.open(saveUrl, 'uusharev1''location=yes,links=no,scrollbars=yes,toolbar=no,width=550,height=550');  
  45.   },  
  46.     
  47.   onToolbarButtonCommand: function(e) {  
  48.     uusharedemo1.addToUushareBookmark();  
  49.   }  
  50.   
  51. };  
  52. window.addEventListener("load"function(e) { uusharedemo1.onLoad(e); }, false);  



相信对于熟悉js的朋友上面的代码并不难。大部分代码跟在普通html页面里写的差不多,只是firefox提供了内置的一些对象需要翻查官方的文档才能知道它的作用及其成员。

7、打包、测试

至 此我们的扩展组件就编写完毕了,下面开始做安装测试。首先用压缩工具将install.rdf、chrome.manifest以及chrome目录打包 成一个zip格式的压缩包,要注意的是这2个文件及chrome目录必须在压缩包的顶层目录,否则安装会失败。然后将压缩包文件的扩展名更改了 “xpi”,并把这个文件拖到firefox窗口当中,firefox应该会提示安装并要求重启,重启完之后若无问题即可看到我们制作的“工具”栏菜单 项、右键菜单等。如果组件的源代码有错误,例如xul文件或js脚本文件有错误,一般什么预期的效果都看不到,这时需要重复卸载->修复错误代码 ->重新打包->安装这几个步骤。
开发firefox扩展组件最烦人的事情可能就是调试问题了,幸好firefox提供了一些工具,例如 Extension Developer's Extension 等可以减少一些麻烦。

8、工具栏按钮怎么看不到?如何解决

刚 才我们测试的时候会发现虽然右键菜单、“工具”菜单项都显示出来了,不过怎么工具栏上面的按钮没有显示呢?估计这是很多扩展组件开发者都会遇到的共同问 题,原来firefox将非系统默认的按钮都放到按钮箱里,如果想显示这些按钮,需要对着工具栏右键鼠标,选择“定制”,然后将需要的按钮拖出来才行。这 个特性某种程度上可以给用户最大的选择权,不过另一方面这特性给初级的用户带来困惑。所以我们最好能将工具栏按钮自动显示出来。下面是目前“民间”常用的 方法:
大致思路跟我们平时修改windows注册表类似。firefox工具栏上面的按钮布局被储存在firefox设置表中 navigator-toolbox/nav-bar/currentset 键下面,键的值为当前各个工具栏按钮id的以逗号分隔而连在一起的字符串。我们必须读出这个字符串,并把自己的按钮的id(本示例中按钮id为uusharedemo1-toolbar-button,见xul文件)掺和在其中,再写入新的字符串到设置表。
那 么在什么执行此连串操作呢?很明显不能在每次firefox启动时都执行,因为这样会耗时并影响firefox的启动速度,“民间”的方法是先在设置表中 检查某个自定义的键(例如extensions.uusharedemo1)的值,如果这个值为空的或者不等于当前组件的版本,则执行上述的连串操作,并 写入当前组件的版本号。所以完整的过程是:

  1. 读取某个自定义键(extensions.uusharedemo1)的值;
  2. 如果键的值为空或者不等于当前组件版本号,则下一步,否则退出过程;
  3. 读取navigator-toolbox/nav-bar/currentset键的字符串;
  4. 寻找自己按钮的id是否在字符串当中,不存在则将id连接到地址栏id(urlbar-container)的前面;
  5. 将新字符串写入键;
  6. 写当前组件的版本号到自定义键。

下面是上面过程的js代码:

JavaScript代码
  1. var uusharedemo1 = {  
  2.     strVersion : '1.0',  
  3.   
  4.     getUBKCharPref: function(strPrefName) {  
  5.         this.prefManager = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);  
  6.         try {  
  7.             return(this.prefManager.getCharPref("extensions.uusharedemo1." + strPrefName));          
  8.         } catch(e) {  
  9.             return(false);      
  10.         }  
  11.     },  
  12.       
  13.         setUBKCharPref: function(strPrefName, strValue) {  
  14.         this.prefManager = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);              
  15.         this.prefManager.setCharPref("extensions.uusharedemo1." + strPrefName, strValue);  
  16.     },  
  17.       
  18.     onLoadEvent: function()  
  19.     {  
  20.         //first load  
  21.         var strPrefVersion = this.getUBKCharPref('version');  
  22.           
  23.         if(strPrefVersion != this.strVersion) {  
  24.               
  25.             var bolWongPostButtonExists = document.getElementById('uusharedemo1-toolbar-button');  
  26.               
  27.             if(!bolWongPostButtonExists) {  
  28.                 var objToolbox = document.getElementById("navigator-toolbox");      
  29.                 var strChild = '';  
  30.                 var strSet = '';  
  31.                 var objNavBar = false;  
  32.               
  33.                 if(objToolbox) {  
  34.                     for (var i = 0; i < objToolbox.childNodes.length; ++i) {  
  35.                         if(objToolbox.childNodes[i].id == "nav-bar" && objToolbox.childNodes[i].getAttribute("customizable") == "true") {  
  36.                             objNavBar = objToolbox.childNodes[i];  
  37.                             break;  
  38.                         }  
  39.                     }  
  40.                 }  
  41.                               
  42.                 if(objNavBar) {  
  43.                     for (var i = 0; i < objNavBar.childNodes.length; i++) {  
  44.                         if(objNavBar.childNodes[i].id == "urlbar-container") {  
  45.                             if(!bolWongPostButtonExists) {  
  46.                                 strSet += "uusharedemo1-toolbar-button,"                                                          
  47.                             }  
  48.                         }  
  49.                         strSet += objNavBar.childNodes[i].id + ",";  
  50.                     }  
  51.                       
  52.                     strSet = strSet.substring(0, strSet.length-1);  
  53.                     objNavBar.currentSet = strSet;  
  54.                     objNavBar.setAttribute("currentset", strSet);  
  55.                     objNavBar.ownerDocument.persist(objNavBar.id, "currentset");  
  56.                     BrowserToolboxCustomizeDone(true);  
  57.                 }   
  58.                   
  59.                 strSet = strSet.substring(0, strSet.length-1);  
  60.                 toolbar.currentSet = strSet;  
  61.                   
  62.                 if(toolbar.setAttribute) {  
  63.                     toolbar.setAttribute("currentset", strSet);  
  64.                 }  
  65.                   
  66.                 toolboxDocument.persist(toolbar.id, "currentset");  
  67.                 BrowserToolboxCustomizeDone(true);          
  68.             }  
  69.               
  70.             this.setUBKCharPref('version'this.strVersion);  
  71.               
  72.         }//end if first load  
  73.     }  
  74. }  
  75.   
  76. window.addEventListener("load"function()                 { uusharedemo1.onLoadEvent(); }, false);  


为了简单起见,这段代码并没有整合到示例的压缩包当中,如果想查看整合后的结果,可以参考uushare书签组件的源代码:http://www.uushare.com/help/bookmark/toolbar_firefox

本文完。

Tags: xul, mozilla, plugin, addon

Records:13123