跳转至

software

实现 VSCodeVim 中支持中文分词的单词移动

最近用 VS Code 写中文 LaTeX 比较多,但是编辑起来总是比较麻烦,不能用各种带 w 的 motion,不然整行都没了。于是 @xalanq 提出能不能拿一个 JS 的分词库,魔改一下 VSCode Vim 来得到同样效果?答案是可以的。

最后代码在 jiegec/VSCodeVimChinese 里,还没有合并到上游的打算。不定期根据上游发版本同步更新,在 Github Release 里发布 vsix 文件,目前版本为 v1.0.1。在 VS Code 里 Extensions: Install from VSIX... 即可安装。

经过对代码的研究,发现对 motion w 的处理都是通过 getWordLeft getWordRightgetCurrentWordEnd 完成的。于是我修改了这三个函数,根据原来的返回值把字符串喂给分词器,再返回的新的位置。一开始用的是 nodejieba ,但是因为需要用到 node-gyp 遇到了 Node 版本不兼容的问题,于是换了一个纯 Node 的实现 node-segment ,就完成了这个功能。

Grafana 中可视化 Ping 时把 Timeout 显示为指定值

刚遇到一个需求,就是用 Telegraf 收集 ping 信息,然后在 Grafana 里可视化当前的延迟,如果超时了,就显示一个指定值,如 999,这样就可以放到一个 Gauge 里面可视化了。但是,问题在于,Telegraf 的 ping input 在超时的时候只会在 result_code 里写一个 2 ,其他项都是空的,因而如果直接用 GROUP BY time(interval) fill(999) 会导致最新的一个数据经常得到 999。这意味着需要根据 "result_code" 来进行区分 Timeout 的情况。最后捣腾了很久,得到了这个方案:

 select "average_response_ms" * (2 - "result_code") / 2 + "result_code" / 2 * 999 from (select "average_response_ms", "result_code" from ping where $timeFilter fill(0))

最后的方法很粗糙:当 "result_code" 是 0 也就是成功的时候,得到延迟,而当 "result_code" 是 2 也就是超时的时候,直接得到 999。这样就解决了这个问题。

调整 Alacritty 的 Powerline 字体显示偏移

今天体验了一下 Alacritty,以前一直在用 iTerm2,但是它的高级功能我都没用到。于是现在用了下 Alacritty,把 Solarized Dark 配置了,发现 Inconsolata for Powerline 字体显示有点偏差,于是调整了一下:

# Font configuration (changes require restart)
font:
  # Normal (roman) font face
  normal:
    family: Inconsolata for Powerline
    # The `style` can be specified to pick a specific face.
    #style: Regular

  # Bold font face
  bold:
    family: Inconsolata for Powerline
    # The `style` can be specified to pick a specific face.
    #style: Bold

  # Italic font face
  italic:
    family: Inconsolata for Powerline
    # The `style` can be specified to pick a specific face.
    #style: Italic

  # Point size
  size: 18.0

  # Offset is the extra space around each character. `offset.y` can be thought of
  # as modifying the line spacing, and `offset.x` as modifying the letter spacing.
  offset:
    x: 0
    y: 0

  # Glyph offset determines the locations of the glyphs within their cells with
  # the default being at the bottom. Increasing `x` moves the glyph to the right,
  # increasing `y` moves the glyph upwards.
  glyph_offset:
    x: 0
    y: 3

主要是这里的 glyph_offset 设置为 3(2 也可以,我更喜欢 3) ,这样箭头就基本对齐了不会突出来。

然后按照官方 Wiki,配置了 Solarized Dark 配色:

## Colors (Solarized Dark)
colors:
  # Default colors
  primary:
    background: '0x002b36' # base03
    foreground: '0x839496' # base0

  # Normal colors
  normal:
    black:   '0x073642' # base02
    red:     '0xdc322f' # red
    green:   '0x859900' # green
    yellow:  '0xb58900' # yellow
    blue:    '0x268bd2' # blue
    magenta: '0xd33682' # magenta
    cyan:    '0x2aa198' # cyan
    white:   '0xeee8d5' # base2

  # Bright colors
  bright:
    black:   '0x002b36' # base03
    red:     '0xcb4b16' # orange
    green:   '0x586e75' # base01
    yellow:  '0x657b83' # base00
    blue:    '0x839496' # base0
    magenta: '0x6c71c4' # violet
    cyan:    '0x93a1a1' # base1
    white:   '0xfdf6e3' # base3

真香

Grafana Variable 的 regex 过滤方式

用 InfluxDB 收集到 Mountpoint 数据的时候,经常会掺杂一些不关心的,如 TimeMachine,KSInstallAction 和 AppTranslocation 等等。所以,为了在 Variables 里过滤掉他们,需要用 Regex 进行处理。网上有人提供了方案,就是通过 Negative Lookahead 实现:

/^(?!.*TimeMachine)(?!.*KSInstallAction)(?!.*\/private)/

这样就可以把不想看到的这些 mountpoint 隐藏,节省页面空间了。当然了,这里其实也可以用白名单的方法进行处理,直接写 regex 就可以了。

《加速奔向 2019》小程序编写和运营回顾

前言

关注清华的同学可能知道,昨天,“清华大学”公众号发了一篇名为《2018,我们共芳华丨@THUers 致相伴一年的你,请查收这份心意》的推送,内容大概就是,有那么 100 个新年台历礼品要送出去,大家如果想要的话,就扫描小程序。小程序模仿了火车抢票的病毒式营销的模式,要求大家分享到群聊或者朋友圈,让别人给自己加速,加速到 2019 的前 100 名即可填写信息领取奖品。

然后大家就在推送里看到了我。就酱。

开始

这件事情据说策划了有一段时间了,只是因为各种原因一直没有做,最后这个锅就路由到了我的头上。一开始说就是个加速小程序,逻辑很简单,但后来逐渐发现需求越来越多,主要是界面上的,动画上的,还有一些非技术因素的功能,嗯。这其实算是一个不大好的软件工程案例。

过程

线上的问题与解决方案

然后就是上线了。大概是昨天(2018-12-27)中午的时候推送发出去,很快流量就开始来了。很快,在朋友圈看到有同学在转发了,也有人反映说,网络有点卡,加载资源有点多。我去机器上用 iftop 看了下,流量大概是 250Mb/s,没打到千兆。我一开始看了下,CPU 和内存占用都良好,以为是网络出口限制的问题,就想着没办法了,就这样吧,扛过去再说。不过,忽然有了转机。

TUNA 技术群里,忽然有人在讨论 SOMAXCONN 的问题,我想到,会不会是有些参数没开够大,导致了性能瓶颈,又受到啊荣的点拨,立马调整了这些变量:

net.core.somaxconn
fs.file-max
net.core.netdev_max_backlog
net.ipv4.tcp_max_syn_backlog
nginx: worker_rlimit_nofile
nginx: event.worker_connections

很快带宽从 200Mb/s 左右打到了 400Mb/s 多,在 iftop 中看到的峰值接近 600Mb/s,见下图:

事后回来看,发现配置一套科学的监控系统真的很有用,如 TCP 连接的状态图:

这里最高的黄线代表的是 TIME_WAIT,意味着很多的 TCP 连接都卡在了等待资源上,而一当我修改参数以后,立刻就降了下来,ESTBALISHED 的连接有了显著的提升。这个问题从另一个图也可以明地看出:

这个图是 TCP Handshake Issues,可以看到无论是 activeopen 还是 passiveopen,都很高,意味着这里无论是发还是收都遇到了问题。而修改参数以后,这些问题立马得到了很好的改善。

其实这些本应该在上线前做好的,但我低估了清华大学的影响力,没有做好相应的准备,还是在优秀的运维人员的指点下得到了较好的效果。

用户数据分析

当然了,除了 Grafana+InfluxDB+Telegraf 这一套监控系统,我们也部署了 ElasticSearch+Logstash+Kibana,只不过我们还是用 Grafana 做了 ElasticSearch 的前端了。通过对 Nginx 日志的分析,我们得到了这些关键的数据(从 12-26 12:00 到 12-27 12:00 一天时间):

除了这些,还有很多有趣的数据,例如用户里北京的最多,也可以大致地看出各个地方网络和手机的普及程度;用户使用的手机的机型里前几名都是苹果的,从单项占领了排名的前很多位,之后则是华为小米 OPPO 等,但总体上反而是安卓用户更多。

微信小程序官方也提供了一些数据统计可供参考。例如页面的访问次数信息,一共大约有二十多万次,打开小程序有十三万多次,访问人数是五万多,还有女性用户比男性用户多等等。这个时代,有数据确实能够得到许多有价值的判断。

反思

这次学到了很多东西,验证了监控系统的必要性,它能够实时看到服务的运行状态并进行调优,事后也可以回过头来进行进一步的分析和总结。不足的是,遇到大客户量的时候,静态资源就应该用 CDN 服务而不应该自己搭建,成本不高而且用户体验会很好。这次后端在数据库操作都用了原子操作,没有出现大的问题,但如果以后遇到更复杂的需求的时候就没有这么容易了。

配置 homebridge-mi-aqara 并添加为 telegraf 的数据源

最近有了设备,想把设备拿到的数据都导一份存到 influxdb 里,但是目前找到的只有 homebridge-mi-aqara 可以访问并拿到数据,然后它又提供了 mqtt 的数据获取方案,于是自己写了个脚本去读取这些数据。

首先当然是配置一下 homebridge-mi-aqara,按照网上的教程来,这个不难。然后本地开一个 MQTT Broker(如 mosquitto),配置为本地监听,然后我编写了脚本 telegraf-mi-aqara.py ,使用前需要 pip install paho-mqtt,并且按照实际路径修改一下内容。验证能够跑起来后,写一个 telegraf 配置:

[[inputs.exec]]
        commands = ["/usr/bin/python3 /path/to/telegraf-mi-aqara.py"]
        timeout = "5s"
        data_format = "influx"

现在就可以读取到各项信息,如温度,湿度,是否开门,开关用电情况等等。

2018-12-16 更新:

研究了一下绿米网关局域网通信协议,得到了第二个版本 telegraf-mi-aqara-v2.py,它与第一版的区别是,第一版是主动向网关读取信息,而这一版则是监听组播包,等待网关发消息。这个脚本负责把读取到的组播信息发送到 MQTT,再让 telegraf 从 MQTT 里解析 JSON 消息,写入数据库。Telegraf 配置如下:

[[inputs.mqtt_consumer]]
        servers = ["tcp://127.0.0.1:1883"]
        qos = 0
        connection_timeout = "30s"
        topics = [
                "/telegraf-mi-aqara"
        ]
        persistent_session = true
        client_id = "Telegraf"
        data_format = "json"
        json_string_fields = ["model", "sid", "status"]
        tag_keys = ["model", "sid", "short_id"]

由于设备不全,有些字段可能不完整。如果大家自己要用的话,可能需要自行修改一下。

Grafana 可视化实践:清华大学 2018 年度人物评选

最近这段时间,清华内部正在投票选出今年的年度人物,想到最近刚好在学习使用 Grafana+InfluxDB+Telegraf 全家桶,于是想着能不能写个爬虫把数据都拿下来,然后用 Grafana 画出来,就可以得到一个投票随时间变化的趋势。爬虫很简单,就是登录,获取页面信息,然后按照 InfluxDB 的输入格式进行输出即可。代码放在了 jiegec/student-tsinghua-vote18 下。

接着就是用 Grafana 进行可视化,大概得到了这样一个曲线:

为保护隐私,把名字隐去了。实际上的投票时间是从 12-3 号开始到 12-7 号结束,但由于宿舍停电的原因所以采样的点在半夜的时候都没有,所以看起来有点奇怪,但还是能够反应总体的趋势的。比如可以看到前两名很早就一马当先,而后一直遥遥领先,下面的选手则排名变动很大,特别是截止前最后一段时间,大家都在拼命拉票,可见大家都是 DDL 选手啊。如果对上面这个图求个导,看看变化率的话:

这显现出了很有意思的一个趋势,就是每天十二点左右都有一个高峰期,然后在零点前大概熄灯附近的时间也是一个高峰期,另外就是截止前最后的抢票阶段,大家都在疯狂拉票,从中午拉到最后时刻。由于停电的原因,在零点附近的数据都比较的鬼畜,不过影响不大,趋势一目了然。

Grafana 真香!期望可以学到更多高端的查询语法和可视化的骚操作,现在有很多东西不知道该怎么可视化,比较苦恼,不知道大家有没有什么经验可以分享。

编写 010 Editor 的 FLV Template

最近在做 FLV 和 H264 方面的研究,研究了很多标准和文档,然后用 010 Editor 对着文件进行分析。这个软件真的很好用,对研究二进制结构用处特别大。不过它自带的 FLV.bt 功能不是很好,我对它加上了 H264(AVC) 的部分支持,放在了 myFLV.bt 里。我也写了 H264 的解析,不过效率不高,大文件要卡好一会。

除此之外,很多格式,010 editor 都有支持,特别好用,它的解析器语法也很好写。

强制启用 Google Chrome 原生的 Dark Mode

Mojave 的 Dark Mode 真香,但是 Google Chrome 并不会随着系统的 Dark Mode 设置变化,所以 NightOwl 只能让部分软件按照时间变更 Dark/Light Mode。一番搜索,发现其实 Google Chrome 其实已经支持了 Dark Mode,但只能设置,不能按照系统的状态自动切换,命令如下:

$ open -a Google\ Chrome --args --force-dark-mode

然后就可以看到 Google Chrome 已经是 Dark Mode 了。但可惜并不能自动切换。

配置 Grafana+InfluxDB+Telegraf 并添加 MIIO 数据来源

之前一直想配一个监控系统,现在有机会了,就简单配了一下。发现真的特别简单,用 Homebrew 安装这三个软件并且都跑起来,然后稍微动一下配置,就可以得到可观的效果了。

然后想利用 miio 配置一下,把宿舍的空气净化器各项参数拿到,以 Telegraf 的插件形式定时上报,然后通过 Grafana 进行可视化。插件放在了 jiegec/tools 下,就是一个简单的 Python 脚本。配置方法如下:

编辑 /usr/local/etc/telegraf.d/miio.conf

[[inputs.exec]]
    commands = ["/usr/local/bin/python3 /Volumes/Data/tools/telegraf/miio.py MIID_HERE"]
    timeout = "5s"
    data_format = "influx"

默认了 miio 路径为 /usr/local/bin/miio

Mac 上安装 Arch Linux,ZFS 真香

最近在 Mac 上装了 Arch Linux,按照 Mac - Arch Linux Wiki 一路一路走,创建单独的一个 EFI 分区给 Arch Linux 放 GRUB 和内核,一个 ext4 作为根分区。由于 Arch ISO 不支持 Broadcom 的无线网卡,于是先拿 Apple Ethernet Adapter 连到路由器上装机。然后把一些需要的驱动装上了,桌面用的 KDE Plasma,Trackpad 用的 xf86-input-mtrack-git,HiDPI 设置为 2x Scale,各种体验都还可以,就是 Wi-Fi 的 802.1X 没配置好,然后 kwalletd5 老是崩没找到原因。常见的应用除了微信基本都有,也终于可以体验 Steam Play,利用 Proton 在 Linux 上跑一些只支持 Windows 的游戏,不过我已经很少玩游戏了。

然后我就想,怎么做 macOS 和 Linux 之间的文件共享。典型的操作可能是 exFAT,但是作为数据盘的话,这还是不大适合。或者就直接用 ext4,配合 extFS For Mac by Paragon 使用,也可以,最后我选择了 ZFS。

在 macOS 上安装 OpenZFS on OSX ,在 Linux 上安装 ZFS on Linux 。具体命令就是:

$ brew cask install openzfs # macOS
$ yay zfs-dkms-git # Arch Linux

由于硬盘空间所限,我只用了一个分区作为 vdev,没有采用 mirror、raidz 等方案。我首先在 macOS 上创建了一个 zpool,参考 Creating a pool - OpenZFS on OSX

$ sudo zpool create -f -o ashift=13 Data diskxsy

此时应该能够看到 /Volumes/Data 上已经挂载了一个 ZFS Dataset。我采用 cbreak-black/ZetaWatch 在菜单栏里查看 ZFS 信息。此时回到 Arch Linux 上,通过 zfs import 可以找到并且挂载这个 ZFS Dataset 到 /Data 处。

我还尝试创建了一个加密的 ZFS Dataset,对加密的部分的粒度控制可以很细。另外,我参考 Time Machine Backups - OpenZFS on OSX 也在移动硬盘上划出一个新的分区作为 ZFS,在上面创建了一个加密的 Sparse Bundle,把它作为 Time Machine 的目标。之后还会尝试一下 zfs send 作为替代的备份方案。

USB/IP 实践

之前一直想玩 USB/IP,但是一直没有找俩 Linux 设备然后共享,今天终于尝试了一下,没有什么大问题。这次采用的设备是 Raspberri Pi 3 和 SaltedFish Pi。一开始尝试从后者向前者共享,但总是出现这个错误:

libusbip: error: udev_device_get_sysattr_value failed
usbip: error: open vhci_driver

然后我反过来做就好了,比较神奇。

主要过程如下:

  • pacman -S usbip 安装用户态软件
  • systemctl enable --now usbipd 启动 USB/IP 的端口监听 daemon
  • usbip list -l 查看本地有哪些 USB 设备可以共享
  • usbip bind -b [BUS_ID] 把指定的 USB 设备共享出去,其中 BUS_ID 从上个命令中查看
  • usbip list -r [IP] 在另一个设备上查看这个设备共享的 USB 设备,可以看到许多信息
  • usbip attach -r [IP] -b [BUS_ID] 把对方共享的 USB 设备 attach 到本地

效果:把一个 U 盘成功映射到了本地:

$ lsusb -t
/:  Bus 04.Port 1: Dev 1, Class=root_hub, Driver=vhci_hcd/8p, 480M
    |__ Port 1: Dev 2, If 0, Class=Mass Storage, Driver=usb-storage, 480M
$ lsblk
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda           8:0    1 14.9G  0 disk
`-sda1        8:1    1 14.9G  0 part /tmp/mnt

尝试 mount 什么的,也都没有问题。以后可以考虑把本地的 LicheeTang 通过这种方式穿透到远端,然后在远端用它的 IDE 进行编程。

UPDATE: LicheeTang 烧写有一些问题,直接 JTAG 写上去没有作用,但是 SPI Flash 是可以成功写入并且有作用的,虽然需要强制打断。感觉还是网络延迟导致了一些问题。

使用 HomeBridge 把小米空气净化器加入到 HomeKit 中

受 @NSBlink 安利,自己部署了一下 HomeBridge ,然后在 iOS 的家庭上就可以看到它。然后,通过 homebrdige-mi-airpurifiermiio 按照教程进行配置。然后就可以在家庭里看到小米空气净化器,包括空气质量,湿度,睡眠模式,温度,打开状态。然后我就可以做一些配置,如离开宿舍的时候自动关闭空气净化器,回来的时候自动打开。不过由于自己没有一个一直放在宿舍的 iPad、Apple TV 或者 HomePod,失去了中枢,这个功能可能会打折扣。

后续想买一些智能的灯啊,然后就可以用 Siri 进行打开 / 关闭了。

此外,我又试了下,可以用 homebridge-camera-ffmpeg 把摄像头配置到 HomeKit 中。这样,就可以远程查看视频流了。

部署 adminMongo 的 Docker 镜像

之前在软工的平台上部署了一个 MongoDB,但是自然是仅内网访问,想要浏览内容只能通过网页上的 Console 进去看,体验特别不好。所以想着能不能找一个在线的 MongoDB 浏览器。由于软工平台只能部署 Docker 镜像,所以我找到了mongo-expressadicom/admin-mongo。但软工平台现在还没实现环境变量的配置,所以我选了后者。

首先本地创建一个 app.json,让它监听 0.0.0.0:80,通过 deployer 传到平台上的配置,然后再把配置 mount 到 /app/config 路径上。现在就可以成功地在网页上浏览 MongoDB 了。

软工平台踩坑记

老师要求我们搞 CI/CD,CI 自然是很快就搞好了,不过 CD 还得配一下。今天研究了一下它的 Deployer 架构,发现了若干易用性问题:

  1. 缺乏文档
  2. 只有样例配置没有讲解
  3. 已有的文档 语焉不详
  4. 官方对此回复:功能太多,还没忙过来写文档

于是只好经常戳助教然后尝试理解这个东西。。然后遇到了很多的 BUG:

  1. 容器没有重启功能。。。
  2. 容器死了还是活着看一个图的颜色。。。毫无说明
  3. 容器虽然有 Console,但是输入过长后直接回到行首没有换行。。。
  4. 容器对外的域名里有下划线。。。Django 上来就一句 Invalid HTTP_HOST header: 'xxxx_xxx.app.secoder.net'. The domain name provided is not valid according to RFC 1034/1035. Express 直接就 Invalid Host header 放弃治疗。。。
  5. 助教对上一条的回复是,等我忙完 DDL 有空再做吧。。。也就是说现在要做只能自己再开一个 Nginx 容器然后自己在 proxy_set_header 上做手脚。。。

绕过 GPGMail 的激活检测

前段时间 GPGMail 宣布不再免费,在三十天的试用期后就不给用了。唉,可能是官方实在没钱维护了,也可能是官方想赚钱了。不过,既然 GPGMail 采用的是自由的许可证,意味着我们可以自己对代码进行更改。和许可证验证相关的代码如下:

- (BOOL)hasActiveContract {
    NSDictionary *contractInformation = [self contractInformation];
    return [contractInformation[@"Active"] boolValue];
}

我们只要改成 return TRUE ,在自己的电脑上手动编译、并复制到 /Library/Application Support/GPGTools/GPGMail 下即可。

另:还有一个直接对二进制打 patch 的方法(仍然符合许可证),利用了最近打 CTF 学到的一些知识。找到以上这个函数,然后把返回值修改成非零即可。这里就不提供方法了。最后的更改:

$ radiff2 -D
--- 0x0000282f  410fbec7
- movsx eax, r15b
+++ 0x0000282f  4c89e090
+ mov rax, r12
+ nop

当然了,还需要额外 codesign --remove-signature 一下。

谨慎对非自由软件采用这个方法。可能有法律风险。

在 Ubuntu 上跨版本迁移 MongoDB

由于 MongoDB 只支持当前版本和上一个版本的数据库格式,然后刚刚滚系统升级的时候升级到了 3.6.x,而数据库格式仍然是 3.2.x 的,于是需要先安装回 3.4.x 版本的 MongoDB,输入命令把数据库升级到 3.4.x 版本后,再用 3.6.x 的数据库进行升级。

以 从 Ubuntu 14.04 LTS 升级到 Ubuntu 18.04.1 LTS 为例,方法如下:

$ wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1604-3.4.17.tgz
$ tar xvf mongodb-linux-x86_64-ubuntu1604-3.4.17.tgz
$ cd mongodb-linux-x86_64-ubuntu1604-3.4.17/bin/
$ sudo ./mongod --config /etc/mongodb.conf &
$ mongo
> db.adminCommand( { setFeatureCompatibilityVersion: '3.4' } )
{ "ok" : 1 }
$ fg
^C
$ sudo chown -R mongodb:mongodb /var/lib/mongodb
$ sudo systemctl start mongodb
$ mongo
> db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )
{ "featureCompatibilityVersion" : { "version" : "3.4" }, "ok" : 1 }
> db.adminCommand( { setFeatureCompatibilityVersion: '3.6' } )
{ "ok" : 1 }
> db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )
{ "featureCompatibilityVersion" : { "version" : "3.6" }, "ok" : 1 }
$ # Okay now

在 Xcode 9 上启用 Vim 模拟(XVim 2)

作为一个不用 vim 编辑会死星人,用 Xcode 总是止不住自己想 Escape 的心。于是找到了 XVimProject/XVim2 进行配置。

大致方法如下:

  1. 按照 Signing Xcode 对 Xcode 进行重签名。套路和对 GDB 进行签名一样。不过这次,签名完成的时间可长多了,毕竟 Xcode 这么大。
  2. 接着按照项目的 README,首先 git clone 然后 make ,第一次打开 Xcode 的时候选择 Load Bundle 即可。

终于可以满足我 Escape Xcode 的欲望了。

Screen Capturing Tips in macOS

I'm sure many people have already known this. But i haven't memorize it yet.

How to screen capture:

Shift+Command+3: Capture fullscreen.
Shift+Command+4: Capture region.
               : Press space to capture window. 
               : Hold option and drag, then
               : you will capture a region with its center in where you started dragging 
               : and one of its corners under your cursor.
Ctrl+OneOfTheTwoAbove: Capture to clipboard.
defaults write com.apple.screencapture location: Change the default location storing the images.

Apps enhancing the snapshots: Snappy and Mapture.

See more detailed here.