iovxw

Linux下Wacom数位板相对定位画笔移动速度的设置

折腾

新买的Wacom CTL680,因为折腾驱动还换了几遍linux内核

具体驱动折腾过程就不说了,旧版内核害死人啊。

好不容易弄好驱动和数位板设置成相对定位模式之后(实在不习惯绝对定位)

发现xsetwacom貌似没有提供设置画笔移动速度的选项?

又是各种查资料

找到了如下设置办法:


首先找到画笔的ID

xsetwacom --list

Wacom Intuos P M Pen stylus             id: 17        type: STYLUS    
Wacom Intuos P M Pen eraser             id: 18        type: ERASER    
Wacom Intuos P M Pad pad                id: 19        type: PAD  

我这里的ID是17

然后xinput watch-props 17

输出:

Device 'Wacom Intuos P M Pen stylus':
        Device Enabled (137):        1
        Coordinate Transformation Matrix (139):        1.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 1.000000
        Device Accel Profile (261):        0
        Device Accel Constant Deceleration (262):        1.000000
        Device Accel Adaptive Deceleration (263):        1.000000
        Device Accel Velocity Scaling (264):        10.000000
        Device Node (257):        "/dev/input/event15"
        Wacom Tablet Area (637):        0, 0, 21600, 13500
        Wacom Rotation (638):        0
        Wacom Pressurecurve (639):        0, 0, 100, 100
        Wacom Serial IDs (611):        803, 1, 0, 0, 0
        Wacom Serial ID binding (612):        0
        Wacom Pressure Threshold (613):        27
        Wacom Sample and Suppress (614):        4, 4
        Wacom Enable Touch (615):        0
        Wacom Hover Click (640):        1
        Wacom Enable Touch Gesture (616):        0
        Wacom Touch Gesture Parameters (617):        0, 0, 250
        Wacom Tool Type (399):        "STYLUS" (395)
        Wacom Button Actions (618):        "Wacom button action 0" (619), "Wacom button action 1" (620), "Wacom button action 2" (621)
        Wacom button action 0 (619):        1572865
        Wacom button action 1 (620):        1572866
        Wacom button action 2 (621):        1572867
        Device Product ID (256):        1386, 803
        Wacom Debug Levels (636):        0, 0

找到我们要设置的Device Accel Constant Deceleration后面括号里的数字

xinput set-prop 17 262 2.5

就搞定啦

后面的值(就是那个2.5)设置的越大笔移动速度就越慢

Nim语言尝试

几乎没人用

从solidot看到,稍微尝试了一下

打开官网后,第一感想是:

诶这个代码高亮的配色不错

然后看了语法什么的,觉得还算顺眼,就把首页的所有链接全部点开了

第一个版本发布的日期是2008-08-22,比go还早一点,但是没什么人用。(果然还是得拼爹啊)

教程方面,只有Tutorials栏里的两个是最新版本的,其他都是旧版

语法层面还没深入研究,就不说了

不过有两个比较有意思的特性,大体介绍一下

首先是各种命名方法可以互相兼容

就是说不管你是喜欢帕斯卡命名法还是驼峰命名法,都一样用

比如标准库里的system.hostOS,你在使用的时候可以写成system.host_os或者system.host_OS再或者system.h_Os_tOS都是可以的。除了首字母以外其他地方都不区分大小写,而下划线只要不是首尾字母,其他地方也是可以随便插入的

然后是foo(bar)可以写成bar.foo() (这个我还没用到,但是好像会很有用?)

至于编辑器支持方面,不要去看官网FAQ里的,那里面也是好久没更新了

可以直接看github上的wiki https://github.com/Araq/Nim/wiki/Editor-Support

最新更新的就是emacs的插件和官方的IDE Aporia

emacs的插件我怎么弄自动补全也没搞定,虽然有提供一个ac-nim.el

Aporia的master分支里的完全不能用!有很多严重问题。比如这个,还有自动补全和定义转跳完全不起作用(以及里面的nimrod还没有更名为nim,虽然官方开了一个分支修改名字吧)。不知道是我配置问题还是怎么着(也根据提示设置nim路径了),开发者有一个答复是nim的idetools本身挂掉了,看了下Aporia的源码照着打了几句nim idetools命令也没什么输出

去翻更新记录找到了https://github.com/nim-lang/nimsuggest这个东西,好像是0.10.3以后会用它代替idetools。于是开始折腾

先是升级nim和Aporia到0.10.3开发版,然后用nimble install nimsuggest来安装nimsuggest。但是出现错误提示~/.nimble/pkgs/compiler-0.10.3/compiler/nimfix/prettybase.nim(10, 7) Error: cannot open 'ast'

重试几遍无果,手动编译了一下compiler,发现没问题啊

浪费掉十几分钟后发现是编译器没有读取cfg?直接把源码扔到compiler文件夹里编译,成功。

我激动的打开Aporia开始尝试语义转跳,刚按下快捷键

……

Error: unhandled exception: 拒绝连接 [OSError]

窗口吡的一下就关掉了!

关!掉!了!

我还没有放弃,手动开启nimsuggest服务

再试

Traceback (most recent call last)
nimsuggest.nim(197)      nimsuggest
nimsuggest.nim(187)      handleCmdLine
nimsuggest.nim(149)      mainCommand
nimsuggest.nim(132)      serve
nimsuggest.nim(106)      action
modules.nim(203)         compileProject
modules.nim(151)         compileModule
passes.nim(197)          processModule
passes.nim(137)          processTopLevelStmt
sem.nim(450)             myProcess
sem.nim(419)             semStmtAndGenerateGenerics
semstmts.nim(1340)       semStmt
semexprs.nim(893)        semExprNoType
semexprs.nim(2196)       semExpr
importer.nim(171)        evalImport
importer.nim(161)        myImportModule
modules.nim(164)         importModule
modules.nim(151)         compileModule
passes.nim(197)          processModule
passes.nim(137)          processTopLevelStmt
sem.nim(450)             myProcess
sem.nim(419)             semStmtAndGenerateGenerics
semstmts.nim(1340)       semStmt
semexprs.nim(893)        semExprNoType
semexprs.nim(2196)       semExpr
importer.nim(171)        evalImport
importer.nim(161)        myImportModule
modules.nim(164)         importModule
modules.nim(151)         compileModule
passes.nim(197)          processModule
passes.nim(137)          processTopLevelStmt
sem.nim(450)             myProcess
sem.nim(419)             semStmtAndGenerateGenerics
semstmts.nim(1340)       semStmt
semexprs.nim(893)        semExprNoType
semexprs.nim(2189)       semExpr
semstmts.nim(1134)       semProc
semstmts.nim(1074)       semProcAux
transf.nim(788)          transformBody
transf.nim(773)          processTransf
transf.nim(761)          transform
transf.nim(104)          transformSons
transf.nim(706)          transform
transf.nim(472)          transformFor
lambdalifting.nim(1022)  liftForLoop
ast.nim(941)             []
SIGSEGV: Illegal storage access. (Attempt to read from nil?)
*** Error in `aporia': free(): invalid pointer: 0x00007f1f16667700 ***
SIGABRT: Abnormal termination.

我仿佛已经知道十万只草泥马在心中奔腾而过的感觉了

可能永远也不会续的未完待续

坑开的有点多了

吐槽

又过了很长时间没写博客了

这次真不是因为懒

各种忙

然后还不小心开了几个大坑


近期做过的事:

先是帮go-zh翻译了一个package(只有几行的翻译量,结果还各种不准确,几乎都是minux纠正过来的)

又写了个各种意义上都弃坑了的golang下载package

一旦下载超大文件就会直接挂掉,是因为线程分配的问题(直接平均分配给每个线程,所以缓冲区会爆掉),但是也懒得改了。要是有人发现了,发个issue可能会给我点动力

然后又为了给coding.net的PaaS弄个Dart的Buildpack

用着电信的渣出口从google code拖了1.7G的源码,编译了最新的Dart SDK

又因为各种原因以及buildpack原作者的脚本有些许问题,弄了2天才下载好了完整的源码

简直生不如死

关键是,最后部署的时候,才想起来dart的包管理网站 被!墙!了!

于是所有的package都要预先下载好再改包管理路径然后全部提交到git

又涉及到了协议什么的一大堆东西,果断还是弃坑不维护了

在用go写一些小程序的时候需要用到图形界面。而go的ui库我基本都用遍了

缺点大致如下(部分问题可能有解决方法,如果知道还请留言告诉我哈):

于是!

就开始写一个用node-webkit做框架的ui库

用html+js做控件,然后可以自定义css,前后端通信用websocket

依赖只有一个nwjs,基本什么平台都可以用

然后支持很方便的自定义控件(只要实现一个方法即可,会自动用反射来调用),以及写一个自定义控件的教程(计划中)

来一段例子:

	var w *Window
	w = &Window{
		Title:  "window",
		Width:  800,
		Height: 600,
		Controls: []interface{}{
			&Button{
				ID:   "btn0",
				Text: "button",
				OnClick: func() {
					println(GetConByID("btn0").(*Button).Text)
				},
			},
			&Button{
				ID:   "btn1",
				Text: "button",
			},
		},
	}
	w.Show()

当然这个库还只是写了个框架(就是说上面说的大部分功能都还没实现(别激动别激动))

控件什么的也只写了一个按钮和一个自定义窗口边框来做演示

上张图(实际运行截图):

img

然后就在这货刚写完框架之后

我又开了个坑(因为Stepladder在长链接下会有几率始终占满一个CPU线程的使用率(具体触发原因不明),然后因为是tcp所以延迟什么的还比较大)

于是准备重写个基于udp的

在github上翻了一遍发现这货https://github.com/skywind3000/kcp

以浪费10%流量为代价换取更低的延迟?

貌似不错

还有人弄了个go版本的https://github.com/vzex/dog-tunnel

就是里面的ikcp,貌似是直接用的c2go转换的,所以编码风格还是有点奇怪

c版本的源码协议是GPL,但是这个是转换的所以貌似可以不用?

总之拖了一份到本地,然后修改了一下编码风格

这货就诞生了https://github.com/go-ukcp/ukcp(里面的ikcp文件夹)

只是把编码风格转换了一下,然后ukcp本来是想封装一下的

但是因为发送端的判断什么的(还要传给kcp所以识别很麻烦),就又弃坑了……

(不过里面的ikcp还是可以单独拿出来用用的)

当然还不能放弃,开始自己封装一个udphttps://github.com/iovxw/rudp

然后嘛……现在为止还没写完


就这么多了,坑还是慢慢填吧

2014浏览器A-Z

冬天好冷啊

好吧其实也算不上一年的

因为中途从Firefox换到了Chrome(谁让Flash不支持了嘛),然后导入的记录没有浏览次数记录

Golang类型switch

语法强迫症

在群里讨论到了这个问题

然后下面这是官方给出的例子

var t interface{}
t = functionOfSomeType()
switch t := t.(type) {
default:
    fmt.Printf("unexpected type %T", t)       // %T prints whatever type t has
case bool:
    fmt.Printf("boolean %t\n", t)             // t has type bool
case int:
    fmt.Printf("integer %d\n", t)             // t has type int
case *bool:
    fmt.Printf("pointer to boolean %t\n", *t) // t has type *bool
case *int:
    fmt.Printf("pointer to integer %d\n", *t) // t has type *int
}

里面有几点要注意一下

switch t := t.(type)

switch的其实是t.(type)而不是被创建的t

然后t := t.(type)创建的是类型为t.(type),值为t的值的一个变量

里面所使用的t都是switch里新建的那个t


等于下面这个例子

var t interface{}
t = functionOfSomeType()
switch t.(type) {
default:
    fmt.Printf("unexpected type %T", t)       // %T prints whatever type t has
case bool:
    t := t.(bool)
    fmt.Printf("boolean %t\n", t)             // t has type bool
case int:
    t := t.(int)
    fmt.Printf("integer %d\n", t)             // t has type int
case *bool:
    t := t.(*bool)
    fmt.Printf("pointer to boolean %t\n", *t) // t has type *bool
case *int:
    t := t.(*int)
    fmt.Printf("pointer to integer %d\n", *t) // t has type *int
}

更新了下模板

瞬间高大上

除了50行的custom.css和几行html修改之外全部都是直接找的模板哇咔咔

虽然上上上次说要重新写一个静态博客生成工具,而且Golang的模板工具和页面模板已经写完了。但是最近又开了个坑所以就……

无限延期吧……

LevelDB储存过程解析

写的乱糟糟的

本文是研究LevelDB结构之后为了加深印象写的,然后主要是写存储过程的细节(其实本来像画个gif来实现的,但是太麻烦了……)。细节部分都是靠各种资料总结的,然后推荐先看一下文章底部的资料,因为有些重复部分没写

如有理解错误,还请指出


首先收到一个添加key的请求,先直接写入log文件(追加写入)

然后插入到内存的储存区(内存储存区内按照key的顺序排列),等到内存储存的数据达到一定大小后(1M),将内存内的数据写入level为0的sst文件内,然后删除log(这里说一下需要注意的是level0内的数据都是直接从内存写入的,所以不同sst文件的key可能会有重复,和其他level不同,其他level在合并的时候都会去掉重复key,不过level0不经过合并这个步骤(当然要是每次从内存写入的时候都更新一下也行,但是io消耗太大,不如在合并到level1的时候进行操作)。所以说level0和其他level相比,更像一个缓存数据用的)

等到level0级别的sst文件达到一定数量后,挑选其中一个sst文件合并到level1(如果没有level1那么就生成level1,其他level也是这么来的。然后因为level0会有重复key(上面也说过原因),所以合并到level1的时候会先去掉和被选中的sst文件内重复的key再合并(所以可能会涉及到level0级别的多个sst文件更新))

合并的时候会检查level0中的key是否和level1中的key有重合,如果有重合那就读取重合的文件和level0中被挑选的sst文件进行更新key,然后排序key之后再按照2M一个sst文件写入level1(这里就可以看出key按照顺序排列的好处了,因为挨着的key基本都在一个文件里,从level0里选择sst文件的key是挨着的,level1的也是,更新的话只需要更新1~2个文件,能减少需要读取的sst文件个数。比如level0抽取的sst文件key是A1~C3的,和level1里面A1~C5的sst刚好能重合,就只需要读取一个文件进行合并了。如果是按照插入顺序之类的乱序,可能会从N个文件里找到重复的key,合并需要读取的文件也就会更多了)

等到level1的文件数据达到10M时(每个级别最大数据量为10^level,level1为10M,level2就是100M),就选择其中一个sst文件合并到leve2。合并方法也是找到重复的key更新,排序,然后生成sst。不过这一层的sst单个文件不再是2M,而是更大一些,每增加一层sst文件最大限制都会扩大。这样设计是为了一层满了之后不至于逐层更新。

剩下的level层也是像上面那样进行更新,所以level最大的一层,数据也是最旧的

删除操作和更新操作基本也都是直接插入数据,只不过删除操作插入的是删除标记,更新操作是直接重新插入一遍数据(在level合并的时候会进行处理更新)

在进行读取key的时候,会先从内存查找是否有这个key,然后再到level0查找,如果还是没有就会到更高层level挨个查找,因为越高层数据越旧,没有被更新到的可能也就越大(比如一个储存在level3的key被在level2标记了删除,但是还没更新到。那么当查找这个key的时候就会优先找到在level2的删除标记(当然level3的key也会在多次合并操作之后被删除掉))

本文章配合以下资料阅读更佳:

http://blog.nosqlfan.com/html/2882.html

http://www.cnblogs.com/haippy/archive/2011/12/04/2276064.html

Golang 模板工具

生成器

就是上一篇文章里说的那个,写完之后发现挺奇葩的

项目地址:https://github.com/iovxw/GoHTML

介绍什么的直接扔README了:


GoHTML

 ██████╗         ██╗  ██╗████████╗███╗   ███╗██╗
██╔════╝  █████╗ ██║  ██║╚══██╔══╝████╗ ████║██║
██║  ███╗██╔══██╗███████║   ██║   ██╔████╔██║██║
██║   ██║██║  ██║██╔══██║   ██║   ██║╚██╔╝██║██║
╚██████╔╝╚█████╔╝██║  ██║   ██║   ██║ ╚═╝ ██║███████╗
 ╚═════╝  ╚════╝ ╚═╝  ╚═╝   ╚═╝   ╚═╝     ╚═╝╚══════╝

Golang HTML模板,非正式项目

基本就是写着玩的

可以将Golang和HTML写在一起,然后用本工具转换成Golang文件

基本功能就是将<a>转换成buffer.WriteString("<a>")

例子

转换前:

package tpl

import (
	"fmt"
	"bytes"
)

func Index() string {
	_buffer := new(bytes.Buffer)

	<a>Text</a>

	for i:=0; i<10; i++ {
		<a>{​{string(i)}}</a>
	}

	var t string = "2"
	fmt.Println(t)

	print:=func() {
		<a>text</a>
	}
	print()

	test1(_buffer)
	test2(_buffer, t)

	return _buffer.String()
}

func test1(_buffer *bytes.Buffer) {
	<a>test1</a>
}

func test2(_buffer *bytes.Buffer, t string) {
	<a>test{​{t}}</a>
}

转换后:

package tpl

import (
	"fmt"
	"bytes"
)

func Index() string {
	_buffer := new(bytes.Buffer)

	_buffer.WriteString("<a>Text</a>")

	for i:=0; i<10; i++ {
		_buffer.WriteString("<a>")
		_buffer.WriteString(string(i))
		_buffer.WriteString("</a>")
	}

	var t string = "2"
	fmt.Println(t)

	print:=func() {
		_buffer.WriteString("<a>text</a>")
	}
	print()

	test1(_buffer)
	test2(_buffer,t)

	return _buffer.String()
}

func test1(_buffer *bytes.Buffer) {
	_buffer.WriteString("<a>test1</a>")
}

func test2(_buffer *bytes.Buffer, t string) {
	_buffer.WriteString("<a>test")
	_buffer.WriteString(t)
	_buffer.WriteString("</a>")
}

然后就可以直接调用里面的函数作为http.HandleFunc

使用帮助

$ go run GoHTML.go

 ██████╗         ██╗  ██╗████████╗███╗   ███╗██╗
██╔════╝  █████╗ ██║  ██║╚══██╔══╝████╗ ████║██║
██║  ███╗██╔══██╗███████║   ██║   ██╔████╔██║██║
██║   ██║██║  ██║██╔══██║   ██║   ██║╚██╔╝██║██║
╚██████╔╝╚█████╔╝██║  ██║   ██║   ██║ ╚═╝ ██║███████╗
 ╚═════╝  ╚════╝ ╚═╝  ╚═╝   ╚═╝   ╚═╝     ╚═╝╚══════╝
=====================================================
GoHTML使用帮助:
===============

命令结构:
  命令 [参数] <模板文件夹路径>

参数:
  -dl <字符串>     | 默认:{{      | 左分隔符样式
  -dr <字符串>     | 默认:}}      | 右分隔符样式
  -suffix <字符串> | 默认:gohtml  | GoHTML模板文件后缀
  -buffer <字符串> | 默认:_buffer | 缓冲器变量名称

举例:
  $ gohtml -dl <{ -dr }> -suffix temp -buffer buf /home/iovxw/gocode/web/view
   | 则会将
   | /home/iovxw/gocode/web/view
   | 里面所有temp为后缀的文件转换为go文件后放到同一文件夹内
   | 将缓冲器变量名称设为“buf”
   | 并设置左分隔符为“<{” ,右分割符为“}>”

备注:
  方括号[]为选填项目,尖括号<>为必填项目

源码规范

作为http.HandleFunc的函数,必须返回值只有一个string(因为多了就不符合http.HandleFunc的要求了)

然后里面必须创建一个类型为*bytes.Buffer的变量,变量名称需要和设置的一样(默认是_buffer)。这个缓冲器是用于存放要输出的HTML代码的

然后作为http.HandleFunc的函数的返回值需要是_buffer.String(),如果你自定义了缓冲器变量名称,需要相应的改变

负责处理部分html的函数,推荐写成上面例子里的样式(接收一个缓冲器变量),就像:

func test1(_buffer *bytes.Buffer) {
    <a>test1</a>
}

因为会转换成:

func test1(_buffer *bytes.Buffer) {
    _buffer.WriteString("<a>test1</a>")
}

这个样子

当然你要是写成函数里新建一个缓冲器变量然后再return也是没问题的

不过那样就需要在使用函数的地方再加一个输出了(相当麻烦)

所以就乖乖按照标准写吧

然后还有一点要注意

就是分隔符输出变量那里,比如{​{t}}

这里的分隔符只有在HTML中才会被转换,就像<a>{​{t}}</a>

写在别的地方是不会转换的,比如:

<a>
if i==0 {
    {​{t1}}
}else{
    {​{t2}}
}
</a>

必须写成

if i==0 {
    <a>{​{t1}}</a>
}else{
    <a>{​{t2}}</a>
}

这样才可以

自动转换

每次更新完模板后都要手动执行一次转换工具一定是超麻烦的

所以需要自动的工具

这里推荐UnknwonBRA(名字好像有点奇怪?),当然其他相似功能的工具也是可以的(如果有更好的还拜托推荐一下)

具体使用方法这里就不说了,自己去看吧

下载

Gobuild Download

在写一个新的静态博客生成工具

轮子、轮子、轮

目标是“完全没有可定制性”

模板已经写好了

但是后端基本没写

而且因为Golang本身的template包实在不好用

于是准备重写一个(又是大坑)

然后……

估计就没有然后了……

换了一个高亮插件

还是因为懒……

这个高亮脚本就叫做highlightjs

因为主题比较多

所以就直接换成这个了

支持92种语言和49种高亮主题

官网:
https://highlightjs.org

主题列表&预览: https://highlightjs.org/static/test.html

package main

import (
	"fmt"
	"math/rand"
	"sync/atomic"
	"time"
)

type readOp struct {
	key  int
	resp chan int
}
type writeOp struct {
	key  int
	val  int
	resp chan bool
}

func main() {

	var ops int64

	reads := make(chan *readOp)
	writes := make(chan *writeOp)

	go func() {
		var state = make(map[int]int)
		for {
			select {
			case read := <-reads:
				read.resp <- state[read.key]
			case write := <-writes:
				state[write.key] = write.val
				write.resp <- true
			}
		}
	}()

	for r := 0; r < 100; r++ {
		go func() {
			for {
				read := &readOp{
					key:  rand.Intn(5),
					resp: make(chan int)}
				reads <- read
				<-read.resp
				atomic.AddInt64(&ops, 1)
			}
		}()
	}

	for w := 0; w < 10; w++ {
		go func() {
			for {
				write := &writeOp{
					key:  rand.Intn(5),
					val:  rand.Intn(100),
					resp: make(chan bool)}
				writes <- write
				<-write.resp
				atomic.AddInt64(&ops, 1)
			}
		}()
	}

	time.Sleep(time.Second)

	opsFinal := atomic.LoadInt64(&ops)
	fmt.Println("ops:", opsFinal)
}