代码手工艺人

Joey 写字的地方

作为程序员,和命令行打交道很频繁,设置一个赏心悦目的命行行 prompt 或者 Vim 的 status line 主题就很有必要了,不过一般这些漂亮的主题都会用到一些 icon 字符,这些 icon 字符一般的字体里是没有的,今天我们就来聊聊一些带有 icon 字符的字体。

为了有个直观的认识,我们来看一下设置命令行 prompt 特殊主题前后的对比:
prompt_theme

Read more »

一、什么是 atime、ctime、mtime?

Linux/Unix 系统会为每个文件保存一些时间戳信息,我们可以根据这些时间戳来判断文件什么时候被读取过,什么时候被修改过内容,以及什么时候被修改过文件的权限。以下是 atime,ctime,mtime 三个时间戳的介绍。

  1. atime (last Access time)

    最近一次访问文件的时间,访问指的是 读取或者执行文件 / 文件夹的时间

  2. ctime (last Change time)

    最近一次 metadata 修改的时间,这里修改有两层意思:

    1. 修改文件 / 文件夹的 metadata,比如 user/group 或者访问权限(比如 chmod)
    2. 修改文件内容
  3. mtime (last Modify time)

    最近一次修改的时间,这里的修改 专指文件的内容修改

注意:

  1. 当创建文件时候,atime、ctime、mtime 都会修改为当前创建的时间
  2. 当修改文件内容的时候,ctime、mtime 都会更新为修改时间
Read more »

AudioStreamBasicDescription 简称 ASBDASBD 是 CoreAudio 用来指定线性 PCM 格式,或者使用 CBR 编码的等大小声道的格式。如果使用的是 VBR,或者使用非等大小的 CBR,需要对每个 packet 独立设置 AudioStreamPacketDescription进行描述。

在分析 ASBD 每个字段之前,我们先来搞懂几个概念:

  • Audio Stream: 一个 audio stream 表示一个声音的连续数据,比如一首歌
  • Channel:声道,一个声道是一个独立的音轨,单声道音频流只有一个 channel,立体声音频流有两个 channel
  • Sample:采样,一个采样对应一个 channel 里的一个具体的数字
  • Frame:一个 frame 包含一组相同时间的samples集合,比如一个线性立体声 PCM 文件每个 frame 包含两个 samples(左声道 sample 和 右声道 sample)
  • Packet: 一个 packet 包含一个或者多个连续的frame,在给定的音频数据格式的情况下,一个 packet 定义了一个最小有意义的 frame 集合,也是最小可测量时间的数据单位。 对于线性PCM音频这类非压缩格式,一个packet只包含一个frame
    对于压缩格式,一个 packet 通常会包含多个 frame,比如 AAC 可能会包含 1024 个 frame。
    对于某些格式,比如 Ogg,一个 packet 对应的 frame 数量可能是变化的,该字段填充 0。
Read more »

这两年来,WebRTC 越来越多地出现在人们的视野,在在线教育,在线医疗等领域的应用也越来越多。大家研究 WebRTC 的热情也越来越高涨,不过 WebRTC 的入门门槛个人觉得稍微有些高,特别是各种概念,比如 NAT 穿越,ICE,STUN,TURN,Signaling server 等等,刚开始可能会觉得比较繁杂,不易理解。然后建立连接的整个过程,异步调用比较多,很容易搞混。那么这篇文章里我们会根据 WebRTC 的官方 demo AppRTC 的 iOS 版本来分析一下 WebRTC 从进入房间到建立音视频连接的过程,为了便于了解,我们本次的讨论不涉及到底层的具体实现。

1. 相关概念

我们首先来简单地了解几个概念:

1.1 NAT 穿越(NAT Traversal)

因为 WebRTC 是 P2P 的,很多时候 peer 是隐藏在 NAT 之后的,没有外网的 IP 地址,如果两个 peer 都在 NAT 后面,都没有外网的 IP (或者说都不知道自己的外网 IP),是无法建立连接的。那么 NAT 穿越就是用来解决这个问题的,NAT 穿越也俗称 “P2P 打洞”。常见的两种穿越方式是 STUN 和 TURN。

Read more »

TURN server 可以解决点对点通信里的 NAT 穿透,并提供中继(relay) 的服务。coturn 是一个开源的 TURN 和 STUN 服务器,是基于 rfc5766-turn-server 进化过来的,目前比较成熟。之所以安装 coturn 是借助它提供的 TURN 服务,解决 WebRTC P2P 通信中 STUN 服务器解决不了的复杂内网的问题。比如我尝试过移动 4G 和 联通 WIFI 有时候无法通过 STUN 服务穿越内网连接,通过 TURN 服务的中继就可以解决这个问题。下面我们就来介绍一下 coturn 的安装,配置以及测试的过程。

Install coturn

coturn 安装可以参考官方的安装文档,按该文档安装即可。如果是 Ubuntu 系列,可以直接通过 apt 安装,安装完成后会放在 /usr/bin/turnserver

1
apt install coturn

网络配置

以阿里云服务器为例,配置网络安全组 / 防火墙,开放 3478 的 UDP/TCP 端口,这个我们我们会作为 TURN/STUN 服务器的监听端口,并开放 40000~60000 的 UDP 端口,STUN 和 TURN 可能会使用随机的 UDP 端口。

Read more »

这篇 blog 来自我们内部的分享,内容比较精简,需要更多的细节信息,请参考 WWDC 2016 - 401 的视频

相信每一个开发者在初学 iOS 的时候,都有过被 Code Signing 坑过的经历,特别是当旁边没有人指导的时候,这也是当时我个人学习 iOS 的时候最困扰的地方,证书,provisioning profile, code signing 等等这些和实际的开发无关的概念,现在还记得苦苦看文档的经历。

Image1 icon
iOS 证书申请和签名打包流程图,图来自这里

Read more »

我们知道 Swift 语言支持函数式编程范式,所以函数式编程的一些概念近来比较火。有一些相对于 OOP 来说不太一样的概念,比如 Applicative, Functor 以及今天的主题 Monad. 如果单纯的从字面上来看,很神秘,完全不知道其含义。中文翻译叫做单子,但是翻译过来之后对于这个词的理解并没有起到任何帮助。

我的理解很简单,Functor 是实现了 map 函数的容器,Monad 就是实现了 flatMap 方法的容器,比如在 Swift 里,Optional, CollectionType 等等都可以称为 Monad。

既然有了 map, flatMap 又有什么作用呢?两者有什么联系和区别呢?

map vs flatMap

map 和 flatMap 的共同点都是接受一个 transform 函数,把一个容器转换为另外一个容器。

下面主要从维度这一块来解释两者的区别,我们先来简单的定义一下维度

对于类型 T,如果类型 S 是一个容器,且元素的类型包含 T,那我们就说:
S (维度) = T (维度) + 1

举个🌰, [Int] (维度) = Int (维度) +1, Int? (维度) = Int (维度) + 1.

Read more »

花了几个小时把 Blog 平台引擎从 Jekyll 迁移到了 Hexo 上,换成 Hexo 的主要原因是 Jekyll 用起来总是出问题,比如提交到 GitHub 上生成的静态页速度很慢,以及一些莫名其妙的错误,和对 MarkDown 支持的比较差等等。

找了一圈综合对比,最终发现 Hexo 能完全满足我的需求,功能强大,插件和主题比较丰富,支持多种平台一键部署,比如 GitHub Pages, Heroku, AS3, 甚至直接 rsync, 有了之前的教训,我果断选择了通过 rsync 放在了自己闲置的一台 Digital Ocean 的 VPS 上。更吸引我的是 Hexo 是基于 NodeJS 的,我对 Node 和 EJS 模版引擎比较熟悉,有无法满足的需求时,就直接顺手添加上了,比如这次分页的方式,对友言的评论的支持,以及 UI 上的一些改动等等。

Read more »

今天科比正式退役,在未来的日子里,也许还会有像科比一样有天赋又努力的球员出现,但我们却不再有青春去追随了。
— 沃茨・其索特

1 什么是协变与逆变

刚开始看到协变 (Covariance) 和逆变 (Contravariance) 的时候,差点晕菜,反复查了一些资料,才稍有些自己的体会,难免有理解不对的地方,欢迎指出 :]

在计算机科学和类型的领域内来看,变化 (variance) 这个词指的是两个类型之间的关系是如何影响从它们衍生出的两种复杂类型之间的关系的。相对于原始类型,这两种复杂类型之间的关系只能是不变 (invariance),协变 (covariance) 和逆变 (contravariance) 之中的某一种。

这段比较拗口,我们一步一步拆解,既然上面提到了两个类型之间的关系,在主流的编程观念里,类型之间的关系中通常会包含子类型 (subtype) 和 父类型 (supertype)。

首先假设 Cat 是 Animal 的子类,就是说 Cat 是 Animal 的 subtype,可以看作上面的 “原始类型”,然后有两个衍生出来的 List<Cat>List<Animal> 类型,就是从 Cat 和 Animal 衍生出来的两种复杂类型。

那么我们就可以这么来解释协变和逆变了:

  • 协变:如果说 List<Cat> 也是 List<Animal> 的 subtype,也就是衍生类型的关系和原来类型( Cat 与 Animal)的关系是一致的,那我们就说 List 是和它的原来类型协变(共同变化)的。
  • 逆变:如果说 List<Cat>List<Animal>supertype,也就是衍生类型的关系和原来类型( Cat 与 Animal)的关系是相反的,那我们就说 List 是和它的原来类型逆变(反变)的。
  • 不变:如果说 List<Cat> 既不是 List<Animal> 的 subtype,也不是 supertype,也就是说没有关系,则说是不变的。
Read more »

介绍

FLEXLoader 是一个我在上周末写的一个可以动态加载 FLEX 的开源越狱插件,它以加载动态库的方式注入到系统 App 和用户的 App 中 (欢迎使用 star, fork, clone 等一切方法蹂躏我~~)。FLEX 全称是”Flipboard Explorer”,是 Flipboard 团队开发一组调试和探测 App 的开源工具,功能非常强大,比如查看和修改 View 的层级结构,查看和修改堆内存中的对象信息等等,更多 FLEX 介绍和使用信息参考这里

FLEXLoader 参考了 RevealLoader,顾名思义,它是一个加载 Reveal 动态库的越狱插件,是一款非常方便的插件,如果你经常用 Reveal 来查看和调试,一定不要错过。我把它的源码做了一些修改,把 Reveal 的动态库改成了 FLEX 的动态库,因为 FLEX 官方只提供了源代码,所以我参考了 Tony 的这篇文章编译了一个动态库,如有有兴趣,也可以直接用我已经构建好的 Xcode 工程 FLEXDynamicLibProject 来编译。

安装 FLEXLoader

有下面两种安装方式:

  1. 在 Cydia 中搜索 Flipboard FLEX loader 并安装 (BigBoss 源)
  2. 如果安装有越狱的开发环境,比如 theos,可以自己来编译安装,配好环境变量后,make package install 一下 (也可以自己编译 FLEX 的动态库替换掉工程中的 FLEXDylib.dylib).
Read more »
0%