一般的键盘中,Caps按键位于“A”的左侧,长期占据着键盘上的一个重要位置。而它的使用繁率确非常的低。对于Linux下的用户,尤其使用Emacs与Vim的用户,Control按键是使用非常多的一个按键,所以将Caps变为Control是一个很好的想法。

码农神器HHKB Pro2的键位设计就是把Control放在了“A”键的左侧。

HHKB Pro2

在Linux下面,可以利用xmodmap交换键盘上面的键位。

  1. 获取keycode,通过命令 xev |grep keycode 可以获取按键的keycode.

    xev |grep state 0x10, keycode 66 (keysym 0xffe5, Caps_Lock), same_screen YES, state 0x12, keycode 66 (keysym 0xffe5, Caps_Lock), same_screen YES, state 0x10, keycode 37 (keysym 0xffe3, Control_L), same_screen YES, state 0x14, keycode 37 (keysym 0xffe3, Control_L), same_screen YES,

  2. 编辑 ~/.xmodmaprc ,填写如下内容

    clear Lock clear Control keycode 37 = Control_L keycode 66 = Control_L keycode 108 = Caps_Lock add Control = Control_L Control_R

将Caps与左Ctrl全部设置为Control_L,将右Alt设置为了Caps_Lock

  1. 使用命令 xmodmap ~/.xmodmaprc 生效

  2. 通过 xmodmap -pke |grep -i Control 查看修改后是否生效

通过以上步骤可以将键盘上面的铵键交换。但是,我发现当键盘USB重插时设置就不生效了,需要重新执行 xmodmap ~/.xmodmaprc

发现udev可以提供让设备在指定条件下执行指定的脚本。规则配置位于 /etc/udev/rules.d

在这个目录下新建个文件,比方说20-usb-keyboards.rules,格式为

#!bash
ACTION=="add", ATTRS{idVendor}=="1006", ATTRS{idProduct}=="0022", OWNER=="imbugs", RUN+="/home/imbugs/.udev.sh"

你需要把里面的内容替换一下,首先需要知道你的键盘的 USB 设备号,用 lsusb 可以看到,例如我的键盘对应的是这行

#!bash
Bus 003 Device 012: ID 046a:010d Cherry GmbH

里面的 046a:010d 分别对应 ATTRS{idVendor}ATTRS{idProduct}

后面的 OWNERRUN 好理解,是用户名和要执行的脚本

RUN 里的 /home/imbugs/.udev.sh 可以这么写

#!bash
#!/bin/bash
sudo -u imbugs /usr/bin/xmodmap -display :0 /home/imbugs/.xmodmaprc >/dev/null 2>&1 &

注意 OWNER 是判断条件,而非赋值,无论如何 RUN 里的脚本都是以 root 身份执行的。 为了让 /etc/udev/rules.d 里的配置生效,还需要命令

#!bash
sudo udevadm control --reload-rules

现在重装插拔 USB 键盘应该都能正常了

java.io.IOException: error=12, Cannot allocate memory

有时我们需要在java中执行一些bash命令,可以通过Java的ProcessBuilder与Runtime.getRuntime().exec()来实现。一般在其它语言中执行一个bash命令时,需要首先调用fork(),通过复制当前过程来创建一个子进程。然后调用exec()来改变进程的执行内容,实际上是在子进程执行不同的代码。

在java中创建新进程时报错:java.io.IOException: error=12, Cannot allocate memory,这个问题其实是fork()的时候产生的。

当使用Java创建一个新进程时,需要复制整个Java JVM,所以我们需要申请与JVM内存大小相等的新内存。当我们在一个内存不太充足的机器上,假如有512M内存,并且JVM占用了350M内存,如果此时去创建一个新的进程,则需要申请新的350M内存,但机器的内存只有512M,已经不足以提供新进程所需要的350M内存,即使我们只执行一条很简单的命令: ls, “ls”命令本身并不需要使用到350M内存,但是要执行它却需要向内存申请350M。

Over-commit

每次在fork()的时候,操作系统会检查是否有足够的内存提供给子线程,我们可以把这个安全检查关闭,让操作系统在即使没有足够内存的情况下也允许我们创建出来子线程。因为我们执行的命令不需要那么大的内存,因此系统能够正常运行下来。启用操作系统的over-commit功能我们可以解决这个问题。

临时性的打开over-commit:

echo 1 > /proc/sys/vm/overcommit_memory

计算机启动时打开over-commit,编辑 /etc/sysctl.conf 添加下面的行:

vm.overcommit_memory = 1

更多相关阅读:
Forking the JVM
How to solve “java.io.IOException: error=12, Cannot allocate memory” calling Runtime#exec()?

TestNG在执行完用例后会在test-output目录下生成一些结果文件,其中testng-results.xml与testng-failed.xml是我们经常会关注的。

testng-results.xml是描述了TestNG整个执行结果。相当于eclipse中的小红条与小绿条。文件中记录了用例执行的异常信息,可以用来排查出现问题的用例。

testng-failed.xml是记录了上一次所有执行失败的用例,如果想重新运行一遍失败的用例,这个文件就派上用场了。testng-failed.xml可以直接拿来使用TestNG执行,对于一些不稳定的用例就很有用。

通常我们使用TestNG会用到数据驱动的功能,同一个脚本可以传递许多个不同的参数。如果其中某几次失败了,我们再次运行用例时只需要执行失败的用例就可以了,而成功的用例不希望再次去执行。TestNG解决这个问题的方法是记录一个Method第几次被调用时失败了,反应到testng-failed.xml文件中就是invocation-numbers(调用编号)这个属性。

假如有一个脚本是这样写的:

#!java
public class Script {
    @DataProvider(name = "providerMethod")
    public Object[][] providerMethod() {
        return new Object[][] {
            { "001" },
            { "002" },
            { "003" },
            { "004" },
        };
    }
    @Test(dataProvider="providerMethod")
    public void testFoo(String caseId) {
        assertNotEquals(caseId,"002");
    }
}

传递的参数依次为:001, 002, 003, 004,很明显的是当caseId=002时,用例会失败。那么记录在testng-failed.xml文件中应该是这个样子的:

#!xml
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite1" verbose="1" >
  <test name="Nopackage" >
    <classes>
      <class name="Script">
        <methods>
          <include name="setUp"/>
          <include name="testFoo" invocation-numbers="1"/>
        </methods>
      </class>
    </classes>
  </test>
</suite>

testng-failed.xml文件中的invocation-numbers="1",表示这是第2次调用方法testFoo时用例失败了(invocation-numbers是从0开始计数的)。使用testng-failed.xml重跑用例时,如果使用了数据驱动,将只会执行执行失败的那一行数据。秘密就在这个XML中的 invocation-numbers参数。

这个方法固然方便,但有一个问题必须注意,比如原始的testng-failed.xml中invocation-numbers="1 2",表示执行第2、3行的数据,但如果第2行数据再次执行失败的话,invocation-numbers 变成了 "0",这个时候,如果再去执行 testng-failed.xml,含义就变了,不再是预期的执行第2行数据,而是执行第1行数据。也就是说使用testng-failed.xml重跑用例的操作方式只有1次利用价值

还是用上面的示例,当使用上面的testng-failed.xml去执行用例的时候,只执行caseId="002"的那一行,用例仍然会报错,但此时再次生成出来的testng-failed.xml是这样子的:

#!xml
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite1" verbose="1" >
  <test name="Nopackage" >
    <classes>
      <class name="Script">
        <methods>
          <include name="setUp"/>
          <include name="testFoo" invocation-numbers="0"/>
        </methods>
      </class>
    </classes>
  </test>
</suite>

这个二次生成的testng-failed.xml是不能重新利用了,必须要进行一定的修正才可以再次使用。

用mvn进行工程管理时往往会被复杂的依赖关系搞的晕晕的,但是如果掌握住mvn的一些技巧就可以使这件事简单起来。

pom

mvn的依赖可以简单的在pom里配置

<groupId/>
<artifactId/>
<version/>

依赖传递

当mvn依赖了一个jar包,那么这个jar包的依赖关系也就被引入进来了。依赖传递使得依赖变复杂化,比如A依赖了B,B依赖了C那么A也就间接依赖了C,如果不想让A依赖到C,则需要在配置依赖关系时使用exclude排除C的依赖

插件

mvn中有一个专门用来进行依赖管理的插件,它就是dependency,通过这个插件可以查看mvn中的依赖树,在查询某个工程是否依赖某版本的jar包时就很有用了。这个插件的通常用法如下

mvn dependency:tree
mvn dependency:list

通过插件可以很清楚看出依赖关系是怎么样的。

markdown是一种最近比较流行的语法,在Workpress中已经有很多markdown插件了。这篇blog就是使用markdown写出来的。简单介绍一下如何在wordpress中使用markdown

安装插件

比较推荐使用WP-Markdown,可以即时显示效果,在写文章的同时可以直接看到展现效果还是比较爽的。

  • 在wordpress中搜索插件:wp-markdown并安装
  • 在“设置”->“撰写”中启用markdown,一定要进行设置才可以使用的

代码高亮

WP-Markdown的代码高亮使用prettify,如果想使用SyntaxHighlighter,需要安装一个插件:wp-markdown-syntaxhighlighter,另外需要勾选SyntaxHighlighter插件的Load All Brushes选项


### Ruby Hello World!
    #!ruby
    class Foo < Bar
      def hello
        puts "Hello World!"
      end
    end
![Markdown](http://blog.imbugs.com/wp-content/uploads/auto_save_image/2013/04/114010dft.jpg)


Ruby Hello World!

#!ruby
class Foo < Bar
  def hello
    puts "Hello World!"
  end
end

Markdown