新出的 Wireguard 很多人都想尝试,这里 VPN 到底适不适合用来翻墙我们先不讨论,先来看看怎么快速在 vps 上起一个 wireguard 服务。很多人听说这个服务配置起来特别复杂,所以望而却步,实际上很简单。
环境
这里我用最新的 ubuntu 18.04.2 来配置,首先你得有一个 vps,创建好后最好按照我的 购买了VPS之后你应该做足的安全措施里配置ssh的证书访问。
新出的 Wireguard 很多人都想尝试,这里 VPN 到底适不适合用来翻墙我们先不讨论,先来看看怎么快速在 vps 上起一个 wireguard 服务。很多人听说这个服务配置起来特别复杂,所以望而却步,实际上很简单。
这里我用最新的 ubuntu 18.04.2 来配置,首先你得有一个 vps,创建好后最好按照我的 购买了VPS之后你应该做足的安全措施里配置ssh的证书访问。
在开发落格输入法 macOS 的时候,我遇到了一个比较奇葩的问题,这个问题一直困扰我到现在——当有些地方需要垂直居中显示一排文字的时候,如何让这些字真正的“居中”?
乍看之下这似乎没什么道理,垂直居中嘛……等等,macOS 上的 NSTextField 还真没有办法让你的一行文字垂直居中……🤷♂️
后来,我[……]
作为 iOS 开发者的你,肯定是知道 Promo codes 这个东西的,也就是我们常说的兑换码。(当然,作为 iOS 用户兴许你也对此不陌生)
这次,我们就来看看,这个看似无穷无尽的兑换码,到底有哪些限制。
苹果后台生成的兑换码有效期一直是一个谜,虽然官方的说法的 4 周,也就是 28 天,但实际上如果这期间你的 app 更新了,那么兑换码很可能就会失效[1]。
&nbs[……]
在使用 Swift 进行开发落格输入法时,我遇到了一个很有意思的问题——去重。
众所周知,输入法的候选在计算出来后总会有可能是重复的选项(比如码表和词库中都有某个词,也许他们编码不同,但字是一样的之类),这时候就需要去重,但又要保持候选的先后顺序不变。
如果你去网上找,那么你可能找到的是这样的:
1 2 3 4 5 |
extension Array where Element : Hashable { var unique: [Element] { return Array(Set(self)) } } |
来源:[……]
办公软件这东西,文字处理、表格编辑、还有著名的“ppt”幻灯片,毕业后我几乎就没再碰过微软系了,偶尔需要文字编辑用的也是苹果的 iWork 系列(当然写论文什么的就别想了),总之,这次我要软一次,推一下 Office 365.
其实就是微软的办公套件,各位可能还在用盗版——这次是绝佳的机会把它洗白——价格足够便宜。
我的 落格输入法 macOS 2 的中国区[……]
在两年前,我曾写过一篇名为《ios 为视障用户支持 VoiceOver》的文章,里边主要介绍了 iOS 端该如何为 VoiceOver 进行必要的支持,后来我又开发了 macOS 端的落格输入法,但很遗憾由于 macOS 自身系统 bug,第三方输入法根本无法获得 VoiceOver 焦点(主要是 10.13 及以下版本),所以我也就没有过多关注——甚至直到这款输入法整个生命周期结束也没能实现 V[……]
用 Linux 的朋友可能会对这个命令比较熟悉,它可以在脚本里快速和批量地对文本文档进行操作,比如改动某一行或者替换具体内容……
macOS 自然也是有这个命令的,但有一点不太一样,如果你执行 sed -i ,那么多半你会得到一个奇怪的报错 sed: 1: “…”: invalid command code 。
[……]
2018年11月02日 更新,切换到 DoT 一天后,所有 stubby 内置服务器运行异常缓慢,直到日常使用都难……只好放弃。
2018年11月01日 更新,使用了 5 天 DoH 后,由于目前提供此服务的服务器只有 1.1.1.1,这个地址在我这里被运营商屏蔽了。
1 2 3 4 5 6 |
PING 1.1.1.1 (1.1.1.1): 56 data bytes Request timeout for icmp_seq 0 Request timeout for icmp_seq 1 ^C --- 1.1.1.1 ping statistics --- 3 packets transmitted, 0 packets received, 100.0% packet loss |
三年前[……]
废话不多说,直接上代码。
GET:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// 创建一个会话,这个会话可以复用 let session = URLSession(configuration: .default) // 设置URL let url = "http://127.0.0.1/api/" var UrlRequest = URLRequest(url: URL(string: url)!) // 创建一个网络任务 let task = session.dataTask(with: UrlRequest) {(data, response, error) in do { // 返回的是一个json,将返回的json转成字典r let r = try JSONSerialization.jsonObject(with: data!, options: []) as! NSDictionary print(r) } catch { // 如果连接失败就... print("无法连接到服务器") return } } // 运行此任务 task.resume() |
POST:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
// 这个session可以使用刚才创建的。 let session = URLSession(configuration: .default) // 设置URL let url = "http://127.0.0.1/api/" var request = URLRequest(url: URL(string: url)!) request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") request.httpMethod = "POST" // 设置要post的内容,字典格式 let postData = ["email":"user@xxx.com","password":"123456"] let postString = postData.compactMap({ (key, value) -> String in return "\(key)=\(value)" }).joined(separator: "&") request.httpBody = postString.data(using: .utf8) // 后面不解释了,和GET的注释一样 let task = session.dataTask(with: request) {(data, response, error) in do { let r = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSDictionary print(r) } catch { print("无法连接到服务器") return } } task.resume() |
[……]