Code Monkey home page Code Monkey logo

kaiye.github.com's People

Contributors

kaiye avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

kaiye.github.com's Issues

全新 Mac 安装指南(通用篇)

很多刚开始接触 Mac OS X 的同学都很难适应新操作系统的习惯,如没有鼠标右键、找不到开始菜单等等,导致常年在 Mac 系统中使用 Windows 虚拟机。我在《为什么说每个程序员都应该有台Mac电脑》一文中提到,Mac 秉承了苹果一贯的高水准体验设计,堪称「完美」的典范。

猫哥从 08 年底开始使用 iMac ,至今从周围的小伙伴身上以及书籍资料中积累了大量经验。Mac 用的好的话,既能大幅提升逼格,又能大幅提升工作效率。

推荐设置

总的来说,Mac 系统不需要做什么特别的设置,但以下几条建议对逼格提升很有帮助。

1、设置语言为英文

因为很多软件和系统设置的叫法用英文更为统一,所以可以很好的利用 Mac 内置的强大搜索功能。

System Preferences 搜索演示:

图:系统设置里的搜索体验

Help Search 搜索演示:

图:通过 Help 搜索来寻找菜单

2、开启 Hot corners

Mac 系统可以自定义一个事件是当鼠标移至屏幕的四个角落时触发一个预设的系统动作。通过该设置可以极快的(操作上甚至快过键盘)执行某一个动作,以下截图演示了,如何将屏幕左下角设置为屏保。当需要离开座位时,只需将鼠标(或触摸触控板)划至屏幕左下角即可开启屏保功能。

图:配置 Hot corners

再在隐私权限中设置相应的锁屏延迟时间,保证 Mac 在唤醒时需要输入登录密码才能使用。

图:自动锁屏时间设置

3、设置鼠标右键

Mac 系统下使用鼠标,默认只有左键没有右键,需在系统偏好设置(System Preferences)中自行开启。

图:设置鼠标右键

如果是 MacBook 系列,建议在 Trackpad 下设置触摸点击,设置后轻触(无需完全按下)触控板即可完成点击事件。同时建议设置双指触摸时响应鼠标右键菜单。

4、MacBook 上开启三指拖拽窗口

操作 Mac 窗口无需像使用 Windows 系统那样如同在手术台上给病人开刀一样地小心翼翼。

  • 滚动窗口。只需把鼠标移到相应的应用程序窗口的任意位置(千万不要移到右侧滚动条的上方!这样很圡!!),滚动鼠标滚轮即可(Magic Mouse 更加自然,直接上下左右滑动)。更赞的是,你不需要点击激活需要滚屏的应用程序窗口,因此你可以一边让光标保持在文本编辑器中输入文字,一边滚动浏览器窗口查看网页。
  • 开启 Trackpad 三指拖动窗口特性:System Preferences -> Accessibility -> Mouse & Trackpad -> Trackpad Options -> Enable dragging -> Three Finger Drag

5、设置菜单快捷键的方法

Mac 有一种设置菜单快捷键的方法,可以设置任意应用程序的顶部菜单栏快捷键。我们只需要在 System Preferences -> Keyboard -> Shortcuts -> App Shortcuts 中点击「+」键,选中对应的应用程序,并输入需要定义快捷键的「菜单名」,系统会根据该名字自动匹配对应的菜单功能,来实现快捷键的设置。具体可参考设置 System Preference 快捷键、设置 Merge All Windows 快捷键的案例。

通过该方法我重设了 QuickTime Player 的屏幕录制快捷键:

图:自定义任意菜单栏快捷键

以下快捷键是 Mac 系统中(部分 Unix/Linux 也是这样)常用的全局快捷键,各位同学应该多多使用,记住它们:

  • 系统级别
    • command + w 关闭窗口
    • command + m 最小化窗口
    • command + q 退出当前程序
    • command + c 复制
    • command + v 粘贴(粘贴文本时,同时按住 shift 键与 option 键,可清除格式)
    • command + option + v 移动,类似「剪切」(在「复制」操作后使用)
    • command + , 当前程序设置面板
    • command + + 放大内容
    • command + - 缩小内容
    • command + ↑(方向键上) 滚动至文件顶部
    • command + ↓(方向键下) 滚动至文件底部
    • command + s 保存
    • command + tab 不同应用程序间切换(切换过程中可直接 command + q 退出指定的程序,切换中按 command + 1 可再选择程序组中的窗口)
    • command + ~ 同一应用程序的多个窗口间切换
    • command + option + h 隐藏除当前程序外的其他所有程序
    • command + delete 删除文件(同时按住 shift 可清空回收站)
    • control + f 光标前进一格
    • control + b 光标后退一格
    • control + p 光标向上一行
    • control + n 光标向下一行
    • control + d 向前删除
    • control + h 向后删除
    • control + e 到行尾
    • control + a 到行首
    • control + off(键盘右上角键) 显示重启、休眠、关机等选项
  • 终端
    • control + w 按单词删除已输入内容
  • 浏览器
    • command + r 刷新
    • command + l 进入地址栏

6、其他 Mac Tips

MacTalk·人生元编程》一书上记载了 200 多条 Mac 小技巧,对 Mac 和编程话题感兴趣的同学可以看下。以下是我从这本书中摘录的几则 tips:

  • 17 > 稍后阅读软件,ReadKit、Pocket
  • 30 > 在大部分程序中,使用 command + shift + y 快捷键,可以将选中的文本快速新建为便签
  • 34 > 先按住 command 键,再拖拽窗口,可以不激活被拖拽的窗口(保持窗口的层叠顺序)
  • 35 > 在 Finder 中选中多个文件后打开右键菜单,再按住 option 键,菜单项会动态改变,这种方法可以查看多个选中文件的总大小
  • 36 > 使用 control + 鼠标滚轮 放大/缩小 屏幕。记得在 System Preferences -> Accessibility -> Zoom 中先勾选「Use scroll gesture with modifier keys to zoom」
  • 38 > 使用 time 命令可以查看某个程序的耗时,如 time ls
  • 39 > 特殊符号的输入,如使用 option + y 输入人民币符号 ¥ 。更多符号的输入,首先点击顶部菜单右上角输入法图标,选择「Show Keyboard Viewer」后会出现一个模拟键盘,按住 option 键或 shift + option 键,即可看看大量符号的输入组合,如下图:

图:使用 keyboard viewer 查找特殊符号

  • 40 > 光标移到一个单词上面,三指轻拍可调用系统词典来翻译。在 System Preferences -> Trackpad 中设置

  • 42 > 使用 pmset noidle 命令可以使电脑不进入休眠状态

  • 51 > 使用 cnflags hidden ~/Desktop/* 命令可隐藏桌面文件。基于该 tips 我写了个 Alfred 插件,可快速 显示/隐藏 桌面文件,下载地址 workflows-hide-desktop

  • 52 > option + F1 可以快速调出屏幕设置面板

  • 55 > 根据自己的分类习惯有效的利用 Finder 的颜色标签功能

  • 67 > 使用 Finder -> File -> New Smart Folder 可以新建智能文件夹,通过新增过滤条件,将搜索条件保存为一个文件夹方便下次快速进入

  • 71 > 在 Finder 中,使用列表试图(command + 2)且设置不排序,点击文件夹前的小箭头的同时按住 option 键,可展开该文件夹下所有子文件夹

  • 108 > HTML5Player 将网页中的 Flash 播放器转换成 HTML5 video 标签播放

  • 119 > XLD(X Lossless Decoder)可以进行无损音频转换

  • 128 > 开启 AirDrop 有线传输。有线肯定比无线要稳定,但 AirDrop 默认需要 Wi-Fi 开启才能使用。运行以下命令后(可能需要重启下电脑),可以让 AirDrop 通过有线传输:

    defaults write com.apple.NetworkBrowser BrowseAllInterfaces 1
    killall Finder
    
  • 删除右键菜单「Open With」中的重复项。Photoshop 等部分软件在删除之后可能还出现在打开项中,使用以下命令可以重建打开项索引(注意:Keyboard->Shortcuts 中的系统快捷键也会被重置):

    /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -kill -r -domain local -domain system -domain user
    killall Finder
    
  • Mac 内置的 apache 服务可能会占用本地 80 端口,可使用 sudo apachectl stop 命令关闭

软件安装

Mac OS 中的常用软件制作都十分精良,这得益于苹果为 Mac 开发者们提供了统一的开发工具 Xcode 与设计指导规范。

软件下载有三种方式,推荐使用第 2 种:

  1. App Store 下载安装。网络好的同学推荐使用此方式;
  2. 去软件的官方站点下载安装;
  3. 第三方网站下载,例如 小众软件、macx 上可以下载到很多常用软件,但需注意版权与安全性问题。

软件下载完成后,安装方法也相当简单。通常只需两步:

  1. 双击运行 .dmg 下载包;
  2. 将出现的应用程序拖入 Applications 文件夹。应用程序图标通常都十分漂亮,这个是苹果的设计指导规范的要求,包括使用什么规格尺寸、从哪个角度打多少高光。

注:某些开发类与设计类的软件,在执行步骤 1 之后,可能需要继续双击其中的应用程序包(通常是默认的硬盘图标)。在同意一系列协议之后,程序会自动安装至 Applications 目录。千万不要自己新建目录存放应用程序,所有的应用程序均应在 Applications 文件夹,以便于统一管理。在软件开发领域,我们称之为 COC 原则,即这是一条 约定俗成 。Mac OS 中有不少约定俗成,它们能极大的提升用户操作效率。

安装来源不明类软件(有风险),需开启相应权限,方法如下:

  1. 点击左上方的苹果图标,打开 System Preferences ;
  2. 进入 Security & Privacy ;
  3. 点击左下方的锁图标,输入登录密码进行解锁(Mac 有着完善的权限控制机制,高危操作通常都需要输入管理员密码);
  4. 在 Allow apps downloaded from 下选择 Anywhere ,确认之后再点下锁图标锁定好;
  5. 鼠标右键点击应用程序图标(某些软件直接双击不行),选择打开(Open),这样可以赋予首次运行权限,以后直接双击即可运行。

推荐软件

macOS 内置了大量优秀的应用程序,能与 iOS 通过 iCloud Drive 进行数据同步,满足大部分日常工作的要求。

  • Pages,文档编辑,对应 Office Word
  • Keynote,幻灯片制作,对应 Office PowerPoint
  • Numbers,表格数据处理,对应 Office Excel
  • Notes,备忘录文档管理,能代替 Evernote
  • Stickes,临时便签,Command + Q 退出后能自动保存临时文档状态
  • Reminders,提醒事项,可以设置周期性的任务提醒,例如信用卡还款、水电煤缴费
  • Calendar,与内置的 Contacts、Mail 结合很好,能记录日程安排与联系人生日

除了以上内置应用外,接下来推荐一些常用的第三方软件:

1、1Password

极好用的密码管理工具,推荐购买。

2、Alfred

Mac 必备工作流神器,可用它来代替系统默认的 Spotlight 搜索功能,配合上付费版的 Powerpack 之后,可以在一个输入框内完成 计算、文件搜索、网页搜索、应用程序搜索、任意脚本程序执行、任意快捷键执行自定义复杂交互。

3、百度输入法

用来代替系统默认的中文输入法。安装完成后点击右上角的输入法图标,可以通过 Open Keyboard Preferences -> Input Sources 来添加或删除其他的输入法。(找不到设置入口的同学可以试试前文提到的 System Preferences 搜索Alfred 搜索

建议设置以下快捷键:

  • Keyboard -> Shortcuts -> Spotlight 关闭 ⌘Space⌥ ⌘Space
  • Keyboard -> Shortcuts -> Input Sources 勾选 ⌘Space ,开启输入法切换快捷键

4、Mac QQ

运行 Mac QQ 后可以按下 control+command+a 使用截图功能(顺便提一下,系统默认的截图快捷键为 shift+command+4 ,如果要截图至剪切板,则还要同时按上 control 键)。如果已经安装了 Alfred 的话,建议关闭 Swiftly ,步骤如下:

  1. 点击屏幕左上方 QQ 菜单,选择 Preferences... 进行程序设置( Mac 系统默认所有应用程序的配置选项快捷键均为 ⌘,,这是一条 COC );
  2. 切至 Swiftly 面板,将 Launch Swiftly 设置为 Empty 。

5、Reeder

集成了Feedly (RSS 阅读)、Instapaper (书签收藏稍后阅读)等大量第三方阅读管理工具,浏览与同步体验较好,推荐购买。

6、MindNode

脑图工具,免费版有节点限制,推荐购买。其他免费的有 Freemind百度脑图

7、Parallels Desktop

虽然强烈建议各位不要在 Mac 上装 Windows 操作系统,但某些场景下,还不得不使用 Windows,这款虚拟机软件,在 Mac 下最好用。免费的推荐使用 VirtualBox

8、Spectacle

免费的窗口大小快捷调整工具。

9、Typora

优秀的免费 Markdown 写作软件,以很好的形式将源码编辑和预览功能整合在一起。对比其他同类软件:

  • Macdown 自称「抄袭」了 Mou 的开源软件。不过预览窗口的自动滚屏的定位不准确,影响长文多图的写作体验。
  • Mou,免费,保存时假死卡顿的问题一直没有解决,不推荐
  • Ulysses,$44.99,中文排版难看,不推荐
  • Byword,$11.99,排版很好看,但源码和预览是分开的操作,体验不完美
  • nvALT,免费,界面很难看,知识文档分类管理
  • Quiver,$9.99,类似轻量版的 Evernote ,体验不错,同步似乎有点问题
  • Day One 2,¥128.00,一款支持 Markdown 的日记类软件,体验不错

10、其他(按需安装)

注:爱好编程的朋友浏览完此文后请继续参考阅读 《全新 Mac 安装指南(编程篇)》,更多编程相关知识,欢迎关注我的微信公众账号「猫哥学前班」。

各位同学在使用 Mac 过程中,如有什么问题或者经验,欢迎留言分享:)

买苹果设备需要注意哪些坑

明天(6月14日)凌晨 1 点,苹果将会举行 WWDC 夏季新品发布会,如果 Mac 系列有更新的话,就是购入的最佳时机。即使没有更新,相信在九、十月的秋季发布会上也一定会更新,建议各位朋友这段时间不要着急入手。

08 年开始我陆陆续续用过很多苹果设备,包括 iPod Shuffle、iPod Touch、MacBook Pro、iMac、iPhone、iPad、iPad Mini、MacBook Air、MacBook、Apple Watch,算得上是一名标准的果粉。今天这篇文章我将会结合实际使用体验,来告诉大家如何正确地选购苹果设备。

一、When to Buy(何时买)

知名果粉网站 MacRumors.com 结合苹果产品的更新周期和各路媒体新闻,给出了选购时机的建议。若选购的设备即将发布新品,会给出「DONT'T BUY」的建议。反之,若产品发布时间不长,则给出「BUY NOW」的建议。

所以在决定购买苹果设备之前先查一下购买指南,可以避免购买到即将过期的老一代机型。

MacRumors Buyer's Guide

此外,部分型号的苹果产品在每年 1 月份的苹果优惠日,会给予一定的折扣优惠。同时在每年八九月的开学季,也会有针对学生群体的优惠活动。

二、Where to Buy

苹果设备直接在其官网下单即可,可以避免买到水货或者翻新机,但如果有港版的购买渠道,强烈建议购买港版

**首先,香港作为免税港,其苹果产品的售价在全球范围来看,属于最便宜的梯队。**以 iPhone 6s 64G 为例,其苹果香港官网价格为 6388 港币(当前港币对人民币汇率 0.845,约 5400 人民币),而**官网价格为 6088 人民币(其中包含 891 元增值税),二者价格相差 688 元。

**其次,从兼容性来看,香港毕竟属于**,港版苹果设备通常都能在**大陆地区正常使用。**包括设备输入电压、网络制式、时区和语言设置。相反,美欧日等海外版本的 iPhone 手机要么网络制式不支持全网通 4G,要么是属于运营商绑定的有锁待破解版,购买这些型号的设备会带来诸多不便和安全隐患。同样,海外版本的 Mac 电脑的键盘可能不是标准美式键盘布局,用起来分分钟让人抓狂。

最后,港版苹果设备也能在大陆享受一年期的保修。

三、iPhone、iPad 购买建议

先说结论,iPhone 建议购买 6 或 6s,iPad 建议购买 mini 2 或 iPad Pro 。

1、按屏幕尺寸选购

手机作为高频使用的手持设备,通常为单手持机操作,因此十分注重尺寸对手感的影响。iPad 使用频率相对较低,通常是外出游玩和儿童使用,则无需考虑尺寸因素。

对于一般用户来说,4.7 英寸的 iPhone 6/6s,其手感较好、操作便利。

因为在 iPhone 的界面规范中,App 的「返回」按钮总是固定在屏幕的左上角,这导致习惯右手持机的用户,很难通过单手操作点击到此按钮。虽然可以轻按两下 Home 键触发「单手操作模式」,但这种为了「返回」需要每次都多两次点击操作的体验,十分糟糕。相比之下,使用屏幕边缘的侧滑返回手势(interactivePopGestureRecognizer)更加实用,但也可能出现部分 App 未按设计规范支持该手势的情况。

轻触 Home 键两次,触发单手操作模式

**如果不限定为苹果手机,个人认为 5.0 或 5.2 英寸手机更适合男性用户。**这是因为, 4.7 的手感像 (.)(.),5.2 则像 ( . )( . ),5.5 虽然更大 ( o )( o ),但没法一把 hold 住……

对于喜欢使用各种新奇特手机壳以及习惯双手持机的用户,建议购买 5.5 以上尺寸的手机,屏幕越大体验越好。

2、3D Touch 与 Apple Pencil

3D Touch 是 iPhone 6s 新增的特性,它将 App 常用的操作和功能入口集成在 3D Touch 手势上(即,用力按压),可以类比成移动设备的「鼠标右键」。

iPhone 的 3D Touch 启动速度非常快,在快速支付、扫码等场景中能极大的提升操作便利性,十分适合支付宝和微信的重度使用者。

支付宝 3D Touch 很实用

补充说明下,当前某些安卓设备同样支持类似 3D Touch 功能,但从我实际体验来看,不但大部分应用未做支持,而且启动速度极慢(应该是系统架构的问题),根本无法和苹果手机相比。

据说 iPad Pro 当前并不支持 3D Touch,但借助 Apple Pencil 的高灵敏度压力传感器,能让 iPad Pro 识别出不同力度的按压,从而模拟出逼真的绘画笔触体验。如果你是爱好绘画的用户又想买个 iPad,可以考虑购买 iPad Pro。

3、指纹识别

考虑到手机高频操作对便捷度和安全性的要求,指纹识别应当作为一款手机的标配功能,没有指纹识别的手机建议不要购买。

但 iPad 之类的平板电脑附带指纹识别的意义不大,因为它没有移动支付这样的指纹识别场景。且由于平板使用较为低频,甚至都可以考虑不加数字解锁密码,自然不需要指纹解锁。所以对于 iPad,如果不准备购买 iPad Pro,建议直接购买 iPad mini 2 ,而非带指纹识别的 iPad mini 4。

除以上三个因素以外,手机和平板设备通常应尽量选择金属机身和厚度较薄的设备,能大幅提升设备整体质感与美感。在容量选择上,注意一定不要购买 16G 的,一旦需要相机功能就会发现不够用。

四、MacBook、iMac 选购

在《为什么说每个程序员都应该有台 Mac 电脑》中有讲到 Mac 是最优秀的个人电脑,对于程序员和设计师们来说,拥有一台自己的 Mac 电脑是走向优秀的捷径。

Mac 电脑的一体化金属机身与优雅外观,最接近美的原型,大部分影视作品中的电脑道具都喜欢使用 Macbook 或者 iMac,如果柏拉图再世的话,相信会是一名坚定的果粉。

在 Mac 电脑的选购方面,建议购买 13 英寸 MacBook Pro with Retina 256GB 和 27 英寸 iMac Retina 5K。

1、Retina 还是非 Retina

毫无疑问,一定是选 Retina(高清视网膜屏幕)。Retina 屏有着优秀的文字图片浏览体验,这是多年以来 Mac 和 Windows 的显著区别之一。凡是用过 Retina 屏的,就再也没有回去过。

如今大部分 Mac 电脑都配备了 Retina 屏,未使用 Retina 屏的型号包括 2015 年之前的 MacBook、2012 年中之前的 MacBook Pro 、非 4K/5K 屏的 iMac 以及全系列的 MacBook Air。

2、13 or 15 英寸?21.5 or 27 英寸?

MacBook Pro 作为一款笔记本电脑应当优先考虑其携带便捷度,所以选择 13 英寸的小尺寸;iMac 作为固定办公的台式机,屏幕越大其可操作区域就越大,27 英寸刚好是人的视线可以覆盖到的最大尺寸。

如果不打算购买 iMac,则可以考虑给 MBP(MacBook Pro)外接一个显示器,在腾讯公司内部,使用的是可以自由旋转升降的 Dell IPS 屏,值得入手。

但需要注意的是,**一般只有 4K/5K 的外接显示器才有 Retina 的显示效果。**我尝试过 Dell P2715Q 27 英寸 4K 屏,无需配置直接支持 Mac 的 Retina,只可惜显示效果不佳,有一种把 1280800 分辨率的屏幕调成了 1024768 分辨率的放大感。

为了能达到 27 英寸 iMac 5K 的效果,需要购买售价高达 15000 元的 Dell UP2715K,那还不如直接买台 iMac 了。

3、12 英寸的 MacBook 体验如何

我的 MacBook 与 MBP985

12 英寸 MacBook 略小于一张 A4 纸的大小,重量不到 1 公斤,拥有和 iPad 一样的便捷性。

由于使用了无风扇设计的英特尔新一代 CPU 酷睿 M,MacBook 能保持着美男子一般的安静与持久。如果你和我一样是个只注重外表的肤浅之人,同时工作上没有大功耗的使用需求(如编辑大于 2G 的 Photoshop 文件、开发复杂的 iOS 应用),则可以考虑购买。

**但总的来说,MacBook 性价比并不高。**除了低功耗 CPU 以外,它的 USB-C 接口也有诸多问题。

一方面,你需要购买昂贵的USB-C 转 HDMI 转接头,才能外接 HDMI 线和 U 盘。

另一方面,MacBook 外接显示器的体验十分糟糕。如果是外接前文提到的 Dell P2715Q 4K 屏,虽然可以渲染出 Retina 的高清屏效果,**但屏幕刷新频率只有 30Hz 而非正常的 60Hz,在移动鼠标和观看网页动画时会有明显的失帧感。**同时,由于没有 USB-C 和 Thunderbolt 的转换配件,导致它无法像 MacBook Pro 一样直接通过 Thunderbolt 接口与 iMac 共享显示屏。

最后大家在选购 Mac 电脑时还需要注意:一定要选择 256GB 或 256GB 以上硬盘空间的型号,128GB 的硬盘肯定会不够用;Mac 电脑还有一个专门的教育购买渠道,能享受到九五折的优惠,可以找学生或老师朋友帮忙代买。

五、Apple Watch 与配件选购

Apple Watch 大概是我用过的最鸡肋的一款产品。据我所知,苹果表的使用场景有以下几个,而我现在主要的用途只剩第一条:

  • 手表功能,用来看时间;
  • 消息提醒,能即时同步 iPhone 上的消息提醒,省去掏手机、唤醒屏幕、查看提醒的步骤。其实大部分提醒都不需要查看,或者不需要被即时的查看,而且 Apple Watch 到现在还没有一款好用的股价提醒 App;
  • 运动计步,可直接同步运动数据到 iPhone 中,只需要把手表绑在宠物狗的腿上放出去浪一天,轻轻松松刷到微信运动榜第一名;
  • 站立提醒,能定时的提醒你站起来走动下,不要久坐,起到预防劲椎病和前列腺保健的效果;
  • Siri 服务,受限于国内网络环境,你会发现使用手表上的 Siri 和使用 iPhone 上的一样困难;
  • 偷拍功能,由于苹果表可以唤起 iPhone 上的相机,这样你可以事先把 iPhone 对准你要拍摄的对象,调整好一个恰当的角度,然后假装在手表上看时间……这个功能我只是听说,没用过,真的。

**在款式方面,尽量选择不锈钢表盘,质感比运动款的要好很多。**如果只打算买运动款的,那就买白色表盘的(因为黑色表盘的不好搭配表带),再配上一条 5600 元的爱马仕表带,——完美!

Apple Watch 表带搭配

最后,关于苹果配件的选购,我有过多次的购买和退货经验。总结出以下几条:

  1. iPhone 不用带套,iPad 需要带套,淘宝上购买即可,款式很多;
  2. 购买电源、转接线、鼠标、键盘等配件尽量在苹果官方店购买,能保证质量和品质,以及体验的一致性。尤其是苹果表带,京东上的质量都很糟糕;
  3. Mac 电脑绝对不要上保护壳,太 Low,同样也绝对不要贴键盘膜,还是太 Low;
  4. 只有两千块以上的背包才能衬托起 MacBook 的气质,切记!

第1章:初识编程

写在前面

之前答应过不少朋友今年要写个《猫哥极简编程入门》的系列,帮助各位对编程感兴趣的新人和非程序员,快速掌握一些实用的编程技巧,以便快速入门编程以及应付一些日常的工作需要。

眼看着 2017 年只剩下几天了,所以是时候展现真正的技术了……

本系列将会采用小说故事的写法,在一个个具体的故事场景中带入编程相关的知识,欢迎各位在文末留言自己的心得与建议。

猫哥极简编程入门系列

新的任务

小鱼是 M 公司的一位产品经理,她的日常工作主要是「各种打杂」。最近老板给她安排了一个新的任务:每天早上 9 点半在钉钉群里给同事分享前一天的(科技)行业头条。

经过各种搜罗和同事的推荐,最终小鱼在新华网的科技首页上找到了合适的新闻来源:

http://www.xinhuanet.com/tech/index.htm

新华网科技频道

她对新闻的整理流程如下:

首先,用鼠标选中新闻标题,将它复制到新的文档:

“千机变”之2017年的手机代表们

然后,在新闻标题上点击鼠标右键选择「复制链接地址」,将新闻链接粘贴在了下面一行:

“千机变”之2017年的手机代表们
http://news.xinhuanet.com/tech/2017-12/20/c_1122138478.htm

接着,选中摘要,粘贴至新的一行

“千机变”之2017年的手机代表们
http://news.xinhuanet.com/tech/2017-12/20/c_1122138478.htm
截止到12月,依旧有新品手机发布,如此来看,2017年手机市场已经趋于饱和。细分市场下的手机产品有更加精确的对应,百元至万元的手机比比皆是,供选择的可能性太多也造成了行业产品冗余。

最后,使用同样的方法,将当天的其他新闻都粘贴进去

“千机变”之2017年的手机代表们
http://news.xinhuanet.com/tech/2017-12/20/c_1122138478.htm
截止到12月,依旧有新品手机发布,如此来看,2017年手机市场已经趋于饱和。细分市场下的手机产品有更加精确的对应,百元至万元的手机比比皆是,供选择的可能性太多也造成了行业产品冗余。

积极探索家电领域消费维权新途径
http://news.xinhuanet.com/tech/2017-12/20/c_1122137921.htm
在上海市消保委对外公布去年受理的122453件消费者投诉中,涉及家用电器、旅游及相关服务方面的消费投诉最多。为进一步剖析家电领域问题,家电办积极联系媒体、行业专家、维权志愿者,共同加入到消费体察队伍中去。

工业APP打破创新“围墙”
http://news.xinhuanet.com/tech/2017-12/20/c_1122137639.htm
工信部信息化和软件服务业司副司长李冠宇表示,加快推进工业软件发展,增强工业软件技术、产品研发能力和服务支撑水平,有助于推进我国工业互联网创新发展,促进软件业与工业协同发展。

...

毫无疑问,这是一件「简单而又枯燥」的事情。

初识编程

今天小鱼在整理新闻时,恰好被公司的程序员老司机猫哥看到了。

猫哥:如果你会编程的话,这些重复性的操作,只需要一行代码就可以搞定。

小鱼:啊?!不会吧!

猫哥:来,我给你演示下。

说完,猫哥接过了小鱼的电脑。

步骤1:用**「QQ浏览器」**重新打开新闻页面:http://www.xinhuanet.com/tech/index.htm

步骤2:在新闻标题「“千机变”之2017年的手机代表们」上按下鼠标右键,选择「检查(N)」

步骤3:浏览器的右侧打开了「开发者工具

步骤4:鼠标右键点击 <a href="http://news.xinhuanet.com/tech/2017-12/20/c_1122138478.htm" target="_blank">“千机变”之2017年的手机代表们</a> ,菜单中选择 Copy -> Copy Selector

开发者调试工具

步骤5: 按下 Esc 键,打开 Console 面板

步骤6: 输入 $$(''),在两个单引号之间粘贴刚才复制的字符串,即 $$('#showData0 > li:nth-child(1) > h3 > a'),按下回车

步骤7:重新输入 $$('#showData0 > li > h3 > a') ,按下回车。控制台打印出了当前页面所有的热点新闻标题和链接

开发者调试工具

小鱼:刚才删掉的 :nth-child(1) 是什么?

猫哥:噢,那个是 CSS 伪类选择器。你现在只需要记住,把拷贝出来的 Selector 中类似 :nth-child(*) 的字符删除掉,就能选中所有标题了。

步骤8:重新输入 $$('#showData0 > li > h3 > a').map(a => a.innerText + '\n' + a.href).join('\n\n') ,回车运行。控制台打印了以下格式:

"“千机变”之2017年的手机代表们
http://news.xinhuanet.com/tech/2017-12/20/c_1122138478.htm

积极探索家电领域消费维权新途径
http://news.xinhuanet.com/tech/2017-12/20/c_1122137921.htm

工业APP打破创新“围墙”
http://news.xinhuanet.com/tech/2017-12/20/c_1122137639.htm

国家科技奖励改革应重在彰显荣誉
http://news.xinhuanet.com/tech/2017-12/20/c_1122137455.htm

从引力波到抗癌新希望
http://news.xinhuanet.com/tech/2017-12/20/c_1122137446.htm

...

小鱼:哇塞!

猫哥:你把打印出来的文本复制到新的文档中就可以了,记得删除掉开头和结尾的双引号。

小鱼:可是没有打印出新闻的摘要呀?

猫哥:别急,我先和你说下这行命令的相关概念,听完后你看能不能自己改写下命令,输出摘要。

小鱼:好!

主要概念

属性、方法、参数

本例中使用的编程语言为 JavaScript,简称 JS,属性、方法(或称函数)、参数基本是所有编程语言都具备的。

编程的过程实际上就是运行各类对象的方法,将对象的属性与给定的数值或字符进行运算的过程。例如,猫哥.头 通过 . 点号,取得了「猫哥」这个对象的「属性」「头」,猫哥.吃饭(),通过. 点号,取得了对象「猫哥」的「方法」「吃饭」,通过() 运行了猫哥的「吃饭」方法。

通常「方法」还可以接受任意数量的「参数」,例如,猫哥.吃饭(砂锅粥),表明对象「猫哥」运行了「吃饭」方法,吃的「参数」是「砂锅粥」。

CSS 选择器

本例中,#showData0 > li:nth-child(1) > h3 > a

网页中的元素,从代码的角度来看,就是一个树状的结构,从根节点从分出子节点,再从子节点中分出孙子节点。这些节点通过浏览器渲染成网页中的标题、文本、链接、图片等等,我们把网页元素的这种树状结构称为 DOM 树。

CSS 选择器可以用来标识定位 DOM 树中的一个或一组 DOM 元素。

DOM 方法

本例中,$$

$$ 是开发者工具中内置的方法,能接受一个 CSS 选择器 ,返回匹配这个选择器的元素数组

所有的 DOM 元素上都有一个 querySelector() 方法,该方法接受一个 CSS 选择器 ,用来在该 DOM 元素的所有子孙节点中查找匹配选择器的 DOM 元素。
通过 DOM 元素的 parentNode 属性,可以获取到当前元素的父元素。

同时,本例中还使用了 DOM 元素的 innerText 属性,该属性能获取 DOM 元素里的文本内容,即本例中的新闻标题文本。

数组方法

本例中,.map().join() 都是数组方法。如果你问我数组是什么?

简单来说,数组就是包含了多个元素的集合,用中括号和逗号来表示 [元素1,元素2,元素3]

map 用于遍历数组中的所有元素,将传入的函数(函数 function,我们可以把不属于某个对象的方法叫做函数)应用于每个数组元素上,返回新的数组。

join 接收一个字符串参数,将所有的数组元素使用该字符串进行拼接。

字符串拼接

本例中,使用 + 号可以将 + 号两边的字符进行拼接成新的字符串。其中 \n 表示换行符,注意字符串要使用单引号或双引号括起来。

箭头函数

本例中,a => a.innerText + '\n' + a.href 为一个具体的箭头函数,箭头函数的形式通常为

(参数1,参数2) => {
	其他执行语句
	return 返回值
}

本例中只有一个参数 a,可以省略(),且只有一行执行语句,且该语句的执行结果就是返回值,所以可以直接省略 { }return

猫哥:好了,讲完这些概念,你自己写行命令输出下所有新闻摘要试试。

小鱼:嗯……应该替换掉你这个例子里的 CSS 选择器和箭头函数的内容就可以了吧。

于是小鱼在开发者工具的控制台(console)中输入以下语句,顺利地得到了所有的新闻摘要。

$$('#showData0 > li > p').map(a => a.innerText).join('\n\n')

小鱼:哇塞,我也学会编程了!

猫哥:干得漂亮!以后遇到这种重复性的工作,记得使用这类编程范式来解决哦。

小鱼:好滴!……可是,我要怎么样才能把新闻摘要和刚才的新闻链接放在一起呢?

猫哥:你可以试试我刚才说的 CSS 选择器以及 DOM 的 querySelector 方法。

猫哥:一会我把答案放在我的微信公众号「猫哥学前班」里,你关注之后回复消息 js1 就能获得了。如果有不清楚的,百度一下或者直接来找我吧。

小鱼:猫哥,不如你收我做关门弟子,我以后跟你学编程吧~

猫哥:哈哈,收你做徒弟没问题,可是为什么要「关门」呢?

这游戏玩通关了绝对能月薪上万

因为能独立玩通关这款游戏的人,要么是一名优秀的程序员,要么已经具备了优秀程序员的编程能力,转行做程序员的话,月薪绝对轻松过万。

这是一款模拟编程的手机游戏,名叫「人力资源机器」(英文名 Human Resource Machine)。由于关卡难度递进的很合理,所以也可以作为一门学习编程(有点类似汇编)的课程来玩。

我们先来感受下这诡异的情节和画风:

诡异的情节和画风

接下来,我来做个简短的介绍,帮助「完全不会编程」又想学编程的同学入个门先。

游戏最基本的玩法是:每次执行 「inbox」命令时,小人会取出左侧 INBOX 中最上面的一个方块放在手中,每次执行「outbox」命令时,小人会把手中的方块放到右边的 OUTBOX(输出)上。玩家需要按照任务的要求,把所有 INBOX 中的值一个个经程序正确处理后,输出到 OUTBOX 中去。

游戏场景布局说明图

实现方式如上图所示,将「命令语句」中的多个命令按一定的顺序拖入到「程序主体」中,完成后按下「执行」按钮,这些命令就会以「从上到下」的顺序一步步执行(注意函数体前面的 01、02、03…… 这些数字我们在程序中称为「行号」)。如果执行的结果(即,放在「输出」带上的方块)不满足任务的要求,老板就会给出相应的提示,此时可以按下「停止」按钮,重新调整「程序主体」后,再次尝试执行。

上图中间有标号的地板区域为临时中转区,通过「copyfrom」(把某个格子的方块复制到手中)、「copyto」(将手中的方块复制一份到某个格子中去)语句可以在这块区域存放程序临时的计算结果,这个区域有点类似电脑「CPU寄存器」和「内存地址」。

对于零编程基础的玩家来说,想玩通关这个游戏,需要了解以下三个概念:

程序中的因果轮回

由于我们人类能感知时间的流逝,所以我们有「因果认知论」,前一秒发生的某件事会导致下一秒某件事情的发生,我们把前面的事件称为「因」,后面的事件称为「果」

**「因果决定论」在计算机程序中的表现形式就是「if 条件语句」。**例如,把本文的标题用「程序」表达出来,就是下面这段代码:

if( 能把游戏玩通关 ) {
  那么就能成为程序员;
}
if( 是程序员 ){
  那么就能月薪过万;
}

这个游戏中有两个 if 条件语句,它们分别是 「jump if zero」(如果为「零」则跳转至)、「jump if neg」(如果为小于零的「负数」则跳转至)。其中的**「jump」(跳转至)**既可以跳转到当前语句之前(过去的时间),也可以跳转至当前语句之后(未来的时间)。

当跳转至当前语句之前(过去)时,程序会按照「行号」(即,时间线)继续从上到下执行,那就可能会再次执行到之前的「jump」语句,从而实现了一个「循环」重复的效果。我们也可以把它理解成「轮回」。

电脑和人类相比,有两个明显的优势,一个是超快的运算速度和能力,另一个就是「能重复地、循环地甚至是永无止境地做某件事情」,就像希腊神话中那个不断把石头从山脚下搬到山顶上的「西西弗斯」一样。

在一般的编程语言中,会有专门的 forwhile 语句来实现循环的功能,但在这个游戏中,我们需要借助「jump」来模拟实现,所以说这个游戏更像一门简易的汇编语言

引用

如果前面介绍的都看懂了,那应该能顺利玩到「第 29 关 仓库楼层」,到这一关之后,针对「copyfrom」和「copyto」命令,出现了一个新的特性:地址引用。

copyfrom 命令的引用开关

如图所示,点击「copyfrom」命令结尾的开关后,语句会在 copyfrom 10copyfrom [10] 两种形式之间切换。

这两种形式的区别是,copyfrom 10 表示将地板上,下标为 10 的格子上的方块复制到手中;copyfrom [10] 表示找到地板上下标为 10 的格子上的方块的数字后,再次在地板上找到下标为这个数字的格子上的方块复制到手中。我们也可以这样理解:*copyfrom [10] 等效于 copyfrom (copyfrom 10) *

在一般的编程语言中,会有一类数组类型的数据,可通过[] 中括号运算符来引用对应下标的数组元素。例如以下代码的含义是:

a = [1,2,3];
b = a[0];

把一个有 3 个元素的数组赋值给变量 a,把变量 a 所指向的数组的下标为 0 (编程语言中数组的下标从 0 开始,它指向数组的第一个元素)的数字赋值给变量 b,所以 b 实际上等于 1。

零编程基础同学请注意,以上等于号「=」与数学中的「=」含义是不同的,在程序代码中一个「=」号叫做「赋值」(即,把「右边的值」赋给「左边的变量」),两个等于号「==」才是「等于」的意思。

算法

当游戏中的王五跳楼之后,游戏难度上升到了最高层级,即使你已经很清楚所有命令的使用方法,但要完成关卡的任务却绝非易事,需要超强的逻辑分析和推演能力才行。

这其中还会涉及到程序「算法」方面的知识,在编程领域有很多优秀的算法由早期的计算机大神们总结而来(可以看下这个「插入排序算法」的视频了解下什么是算法,这个也是本游戏最后一题的解法),而这些知识点许多普通程序员也没能掌握好。

// JavaScript 插入排序算法参考
function insertion(input) {
  for(var i = 1, len = input.length; i < len; i++) {
    for(var j = i; j > 0; j--) {
      if(input[j] < input[j - 1]) {
        input[j] = [input[j - 1], input[j - 1] = input[j]][0];
      }
    }
  }
  return input;
}

我单独列这条出来,就是想告诉编程爱好者们,千万不要灰心和气馁,只要保持兴趣和持续地学习,终究都能够掌握。

当然,如果实在是很想通关,又觉得身体被掏空力不从心的话,可以给「猫哥学前班」留言,我会把我的解题思路和答案发出来给大家参考。

四月是最残忍的一个月

图:The Man Who Sold the World

APRIL is the cruellest month, breeding
四月是最残忍的一个月,荒地上

Lilacs out of the dead land, mixing
长着丁香,把回忆和欲望

Memory and desire, stirring
参合在一起,又让春雨

Dull roots with spring rain.
催促那些迟钝的根芽。

—— T. S. Eliot, The Waste Land (《荒原》,赵萝蕤译)

每年四月,总会不经意间忆起三个人:张国荣、Kurt Cobian 和王小波。

四月是他们的忌日,也是我的生辰;是清明祭祖之时,也是万物生长之际。

张国荣:一只无脚的鸟

图:《东邪西毒》剧照

我对张国荣最早的记忆源于中学时家里的一张情歌精选 VCD,当中有一首张国荣和陈淑桦合唱的《当真就好》。但那首歌我从来不听,因为青春期的少年看到 MV 中你侬我侬的画面,难免害臊。

后来有一次表哥来我家里玩,唱了那首歌,问我唱的像不像。我猛然发现他们俩确实很像,尤其是那双忧郁而又深邃的眼睛。

关于张国荣的第二段记忆,是他去世的那一个愚人节。当时学校开始流行过西方节日,愚人节自然是最有意思的节日之一,有个同学撒了一个谎:「张国荣死了」。

关于张国荣的第三段记忆,已经是他逝世后六周年的忌日。我偶然间看到了他的「2000 热·情演唱会」片段,他们说「这是一个人妖的表演」。

从那时开始,我便不再过愚人节。人们每天都在撒谎,愚人节存在的意义又是什么呢?

我听别人说这世界上有一种鸟是没有脚的,它只能够一直的飞呀飞呀,飞累了就在风里面睡觉,这种鸟一辈子只能下地一次,那一次就是它死亡的时候。

—— 张国荣,《阿飞正传》

那些年,表哥做生意被骗,工厂倒闭,婚姻破裂。他从此黯淡了下去,将自己锁在一个无窗的小屋里。大年初一我去给他拜年,也终究没能敲开那扇门。

医生说,那是抑郁症,飞得太累了,想落地休息。

Kurt Cobain:Smells Like Teen Spirit

图:Kurt Cobain Journals, P206 The many moods of Kurdt Kobain

Kurt Cobain(科特·柯本)是 Nirvana 的灵魂,他被粉丝们称为「摇滚之神」。在滚石杂志「史上最佳 500 专辑」中《Nevermind》排名第 17,与此同时,迈克尔·杰克逊(Michael Jackson)的《Thriller》排名第 20。

Kurt 饮弹自杀的那天是清明节,在现场发现的遗书中,结尾写着这样的一句话:

It's better to burn out than to fade away.
与其苟延残喘,不如从容燃烧。

他也是「一只无脚的鸟」。与张国荣不同的是,Kurt 身上散发着更多的 Teen Spirit,正如他翻唱的那首 《The Man Who Sold the World》所写的那样:

I thought you died alone
A long long time ago

Oh no, not me
I never lost control

—— David Bowie

他始终不愿与另一半自己 Teen Self 妥协,他情愿 Sold the World 也不愿 Sold his Soul,即使偏执到 lost control。

王小波:紫色天空的见证者

图:伦敦国会大厦,莫奈,1904,苏黎世美术馆

与张国荣、Kurt Cobain 不同的是,王小波没能预见自己在四月里的死亡。

在其杂文集《沉默的大多数》中,他立志一定要写出一部能超越杜拉斯《情人》的伟大小说。值得庆幸的是,我们(至少我和他)都认为,他的《黄金时代》做到了。

对于这本书,我在微信读书上给出的评价是:「读完这本书,可以弄清楚三个问题:女人、**以及如何治疗好一个阳痿病人」。

对于一个男人来说,那就是关于生活的全部真相。

我喜欢张国荣,喜欢 Kurt Cobain,喜欢王小波。

然而,我并不崇拜他们。

因为张国荣和我一样,敏感、脆弱;Kurt Cobain 才貌双全,却已是堕落天使;王小波的文字能让我勃起,但五官实在长得有点飘逸。

后来,表哥终于在木匠和篮球的帮助下,从阴影走向了阳光,从软的时期走向了硬的生活。我相信,再也没有什么能击垮一个像他这样的英雄。

正如罗曼·罗兰所说:

真正的英雄主义只有一种,就是明白生活的真相后,依然能热爱生活。

H5 游戏开发 1:Egret 文档有多难用

来源:猫哥学前班

微信公众号平台

最近猫哥开始转行做游戏开发,主要的业务场景是 Hybrid H5 休闲游戏。作为游戏行业的新人,自然少不了一些精彩的技术预研和踩坑经历,今天开始挖个“H5 游戏开发系列”的坑,每周分享一下。

技术选型

国内有三大 H5 游戏引擎,Cocos、Egret 和 Laya,他们都能支持使用 TypeScript 编写跨平台(H5、各类小游戏平台、Native App)的游戏。

具体引擎的对比细节不属于本文探讨的主题,我直接抛出(个人)结论:

2D 游戏选 Egret,3D 选 Laya,其他选 Cocos Creator。

上面的“其他”指的是,你一脸懵逼,不知道怎么选的时候:)

Egret 白鹭引擎

Egret 联合创始人马鉴是 Flash (原属 Macromedia 公司,后被 Adobe 收购)团队的第一位**员工,也是 Adobe **第一位 Technology evangelist。

为了能获得最好的游戏性能和开发灵活性,我们当前的这款游戏选用的是 Egret 白鹭引擎。

然而,生活中总是充满着意外和惊喜,从看开发文档到安装 IDE 上手开发调试,Egret 一点都没让人省心。

今天我们来吐槽下 Egret 的文档有多难用,以及我对它的改造方法,希望能启发大家解决技术文档类问题的思路。

1. CDN 资源不稳定

Egret 文档中的图片主要存放在 cdn.dev.egret.com 域名,而这个服务器经常不可用,同时 cdn.www.egret.com 域名也经常连接超时。怎么办?

借助两条 Whistle 配置搞定:

# 将 CDN 地址转发至源服务器目标地址
http://cdn.dev.egret.com/ http://developer.egret.com/cn/data/upload/
# 将经常连接超时的素材直接返回 404
https://cdn.www.egret.com/official/new-egret/img/ statusCode://404

补充:如果你还不知道 Whistle,可以看下猫哥以前的文章:《8102 年的程序员不需要 Hosts 和 Fiddler》、《使用 Whistle 作为 API 服务网关

2. 文档打不开

很难想象作为一个小有名气的游戏引擎厂商, Egret 的文档站点能做到如此的不靠谱:中文文档站点经常无法访问,所有页面重定向到首页;文档搜索功能不可用,搜索结果直接跳转报错页。

虽然 Egret 还提供了英文文档站点(将 URL 上的 cn 改为 en 即可),但其缺乏及时更新,且无法解决文档搜索问题。

中文 Hello World 地址:http://developer.egret.com/cn/github/egret-docs/Engine2D/getStarted/helloWorld/index.html

英文 Hello World 地址:http://developer.egret.com/en/github/egret-docs/Engine2D/getStarted/helloWorld/index.html

好在 Egret 文档是基于其 Github 仓库 egret-labs/egret-docs 生成的,所以我们可以直接将其下载至本地,使用 VSCode 进行预览和搜索,或者使用 Chrome Sourcegraph 扩展来在线预览和搜索文档。

Sourcegraph

如上图所示,为 Sourcegraph 的过滤搜索功能

3. API 文档搜索功能太弱

Egret API 文档 反人性的地方在于,它只提供了按照 Class 类名的搜索功能,这对初学者相当的不友好。

初学者通常是只知道某些属性或方法名,或它们的描述关键词,然后想通过 API 文档来搜索出具体的类名和使用方法。

由于它的 API 文档没有开源在 Github 上,所以猫哥只好基于它的文档站点设计了一个 API 搜索增强脚本。

API Search 增强

如上图红框所示,使用该增强脚本后,将支持 Egret API 文档的全文搜索。脚本具体实现思路如下:

使用 AJAX 将所有 API 文档内容缓存至本地 indexedDB 数据库(不使用 localStorage 是因为数据大小可能会超过其容量上限),再使用正则匹配用户输入的关键词,过滤出包含内容的 Class 列表,最后复用原先的搜索交互。

脚本的注入方式,仍然推荐使用 Whistle,只需加入两条配置:

# 在 API 站点中插入一个 JS script(若脚本更新需注意替换 url) 
/developer\.egret\.com\/\w+\/apidoc\/(?!ajaxcontent)/ jsAppend://https://gist.githubusercontent.com/kaiye/207728f7c9f187cd886353e7678197f4/raw/09e543a735da2a7212e22d967f2ce40eb2d63b8c/injectEgretApiDoc.js
# 将 gist 站点上该脚本的 content-type 设置为 javascript,解决类型嗅探错误
/injectEgretApiDoc\.js/ resType://js

注:请从 gist 上获取最新脚本源码,并注意替换以上配置中 raw 文件的路径https://gist.github.com/kaiye/207728f7c9f187cd886353e7678197f4

完成注入后,首次使用时,点击“Preload Docs into Local Cache” 按钮,浏览器会依次发出 200 多条 API 文档内容的请求,并将其缓存至本地。后续无需重新下载,即可直接搜索使用。

以上是猫哥对 Egret 文档站点改造的全部内容,在下一期我将会介绍实际的游戏开发,看看 Egret 的 IDE 和调试工具有多难用,感谢关注:)

从 RegExp 构造器看 JS 字符串转义设计

banner

多年前我第一次入职腾讯的时候,DC 从杭州给我寄来了一本他刚翻译出炉的《高性能 JavaScript》。那段时间为了帮忙校对,我仔细阅读了书中的每一个段落,结果积累了不少 JavaScript 基础知识。现在还依稀记得书中提到的几个知识点: IE7 浏览器在大字符串处理时的极致性能优化;位运算符用于 config 配置的各种 trick;以及今天想聊的 RegExp 构造器的第一个参数设计问题。

上周接到一个需求,根据页面 url 来决定是否出现一个弹窗提示。为了方便管理这个特性,我将 url 列表配置在了后台,前端通过接口取得列表再进行校验。

其中有一条规则是「所有机构首页需要弹窗」,因为机构会有自己的独立二级域名,所以这里必须要用到location.host 对应的正则表达式 \w+\.ke\.qq\.com

new RegExp(/\w+\.ke\.qq\.com/).test('ktmaster.ke.qq.com') // 返回 true

// 由于正则表达式字符串是 cgi 接口中返回的,所以第一个参数只能用 string 类型
// 而 RegExp 构造器使用 string 参数时,其中的 \w、\ 等特殊含义字符是需要使用反斜杠再做一层转义,这样同时导致正则语义变得很不清晰
new RegExp('\w+\.ke\.qq\.com').test('ktmaster.ke.qq.com')  // 返回 false
new RegExp('\\w+\\.ke\\.qq\\.com').test('ktmaster.ke.qq.com')  // 返回 true

然而,需求真正落地实现后发现:RegExp 构造器 string 参数需要转义的知识点,其实基本用不到。

1、通过接口返回的字符串在变量赋值时无需转义

前端 AJAX 请求取到的接口数据一定是 string 类型的,这种未通过字符串字面量形式赋值给变量时是无需转义的。以 fetchAPI 为例:

// 1. 其中 data 接口返回的内容是 \w+\.ke\.qq\.com
fetch('/data')
  .then(res => res.text())
  .then(resText => {
    console.log(new RegExp(resText)) // 正确实例化了 /\w+\.ke\.qq\.com/
  })

// 2. 字面量形式定义的字符串不转义,会与期望不符
const regText = '\w+\.ke\.qq\.com' // 字符串定义时 \ 会与后面一个字符合并解析掉
console.log(regText === 'w+.ke.qq.com') // 返回 true
console.log(new RegExp(regText)) // 返回的是 /w+.ke.qq.com/

现在大部分的接口数据会使用 JSON string,接口返回后通过 JSON.parse 成 JavaScript Object ,再通过 key 来取值。而对于 JSON 数据来说,后端 JSON.stringify 时,\ 字符是一定会经过一层转义的(这样才符合 JSON 规范)。以 PHP 为例:

<?php
$regText = '\w+\.ke\.qq\.com'; // 注意 PHP 中单引号内的字符串不会经过解析
echo json_encode(array('pattern' => $regText));
// 返回的是 {"pattern":"\\w+\\.ke\\.qq\\.com"}

所以接口场景下,同样不存在 RegExp 构造器的 string 参数转义问题。

2、表单输入项的字符串赋值给变量时也无需转义

假设页面中存在输入框 <input id="test"> ,在输入框中输入字符 \w+\.ke\.qq\.com,则通过 JS 获取到的值可以直接传入 RegExp 构造器,同样无需考虑转义问题。

const regText = document.getElementById('test').value
new RegExp(regText) // 返回 /\w+\.ke\.qq\.com/

因为表单项中的字符串也是直接赋值,而非通过引号字面量的字符串定义方式赋值。

3、JS 代码中的转义处理

另外一种可能用到 RegExp string 参数的场景是:基于 JS 逻辑,动态创建正则表达式。例如正则表达式 /\w{3}/ 中的数字 3,是通过某个变量来传递的。那么在写正则时需要写成:

let n = 3
new RegExp('\\w{' + n + '}') // 这里的 \w 为特殊字符,需要经过 \ 转义

Python 语言中是通过 raw string 修饰符来解决字符串转义问题,在字符串前加上 r 标记,表示这个字符串的内容不经过解析。即 print r'\n' == '\\n' 返回 True。

为了解决模板字符串的解析和转义问题,ES6 模板字面量中引入了反引号(`)和 tag function(知名「CSS in JS」 库 styled-components 中大量使用了这种语法)。这里的场景就可以写成十分类似 Python 的风格,当需要转义的内容比较多时,能保持较好的正则表达式语义:

const r = String.raw
let n = 3
new RegExp(r`\w{${n}}`)

不过这种使用场景十分罕见,我至今还没有遇到过。

回过头来看,JS 正则表达式构造器的参数设计问题,其实不是 RegExp 引起的,而是 JavaScript String 的设计缺陷:单引号和双引号非但没有参考 PHP/Shell 之类的设计,反而给前端社区留下「应该使用单引号还是双引号」的代码风格争论。反观 Golang, 在这块的约束就做得非常好。

99%的程序都没有考虑的网络异常

绝大多数程序只考虑了接口正常工作的场景,而用户在使用我们的产品时遇到的各类异常,全都丢在看似 ok 的 try catch 中。如果没有做好异常的兼容和兜底处理,会极大的影响用户体验,严重的还会带来安全和资损风险。

接口异常,通常可以分为以下三类:

  • CGI 逻辑出错。 如调用方入参缺失类业务逻辑报错;
  • 服务不稳定。 如服务器不稳定导致 nginx 各类 500、502,cgi 路径调整导致的 404
  • 用户网络环境差。 如,网络不稳定、网速慢、运营商劫持等

那么,我们在写代码时,如何快速的模拟这些接口异常,做好程序的兼容处理呢?

今天向大家介绍网络调试神器 whistle 的网络异常调试方法,如果你还没用过 whistle,请参考《8102 年的程序员不需要 Hosts 和 Fiddler》。

假设我们有以下前端页面 index.html,放置在自己的本地路径:

<p id="success" style="color:green;"></p>
<p id="fail" style="color:red;"></p>
<script>
  fetch(`/mock?r=${Math.random()}`)
    .then(response => {
      return response.json()
    })
    .then(v => {
      document.getElementById('success').innerHTML = v.data;
    }).catch(err => {
      document.getElementById('fail').innerHTML = err.message;
    })
</script>

接下来,打开 whistle Rules 配置面板 http://127.0.0.1:8899/#rules ,配置模拟的 demo page 和 mock CGI:

*/mock file://({"code":0,"data":"success"}) # 配置 mock cgi 为模拟的 json 数据
example.com file:///Users/kaiye/Projects/Markdown/20181213/ # 配置任意域名到本地 demo 目录,这里注意替换成自己的路径

打开 http://example.com ,正常逻辑下页面展示出了绿色的 success ,现在我们开始加入一些网络异常。

1、业务逻辑异常处理

例如 CGI 没有返回 data 字段,而是返回了一个错误码 code 和对应的 message,针对这种业务逻辑异常我们只需在第二个 then 中做好 code 值的判断即可(注意,这里的 code、message、data 只是示例,实际业务 CGI 中的 JSON 结构体的字段名很可能不同):

fetch(`/mock?r=${Math.random()}`)
  .then(response => response.json())
  .then((v) => {
    // 业务逻辑异常处理
    if (v.code !== 0) {
      return Promise.reject(new Error(`ERROR_LOGIC_CODE:${v.code}`));
    }
    document.getElementById('success').innerHTML = v.data;
  })
  .catch((err) => {
    document.getElementById('fail').innerHTML = err.message;
  });

相应的 whistle 配置如下:

*/mock file://({"code":12345,"message":"some_logic_error"}) # 模拟业务逻辑异常

2、服务器异常处理

如果服务器直接抛出了 502 错误码,我们希望代码能给用户提示的同时,再做一个异常上报。

fetch(`/mock?r=${Math.random()}`)
  .then((response) => {
    // 服务器异常处理
    if (response.ok) {
      return response.json();
    }
    return Promise.reject(new Error(`ERROR_STATUS_CODE:${response.status}`));
  })
  .then((v) => {
    // 业务逻辑异常处理
    if (v.code !== 0) {
      return Promise.reject(new Error(`ERROR_LOGIC_CODE:${v.code}`));
    }
    document.getElementById('success').innerHTML = v.data;
  })
  .catch((err) => {
    const [type, value] = err.message.split(':');
    // 异常类型上报
    console.log(type, value);
    document.getElementById('fail').innerHTML = err.message;
  });

通过 whistle 的模拟配置如下:

*/mock statusCode://502 # 模拟 HTTP 状态码异常

3、接口被劫持注入

如果 CGI 被运营商劫持注入,可能导致接口返回一个不合法的 JSON 结构,最前面的 response.json() 会抛异常,我们可以提前 catch 住:

fetch(`/mock?r=${Math.random()}`).then((response) => {
  // 服务器异常处理
  if (response.ok) {
    return (
      response
        .json()
        // 接口数据解码异常处理
        .catch(err => Promise.reject(new Error('ERROR_DECODE_JSON')))
    );
  }
  return Promise.reject(new Error(`ERROR_STATUS_CODE:${response.status}`));
});

whistle 模拟配置如下:

*/mock file://(<div>hijacking</div>{"code":0,"data":"success"}) # 模拟接口被劫持注入 1

借助 htmlAppendvalues 配置,可以模拟更复杂的注入示例:

*/mock file://({"code":0,"data":"success"}) htmlAppend://{hijacking.html} # 模拟接口被劫持注入 2
​```hijacking.html
<script>
alert('hijacking')
</script>
​```

4、用户网络不稳定

如果我们要模拟请求发出 10 秒后断网或网络不通的情况,可以通过 whistle 这样配置:

*/mock reqDelay://10000 enable://abort # 模拟 10 秒超时后网络不通

让用户苦苦等待 10 秒,再报错的体验太糟糕。我们可以封装一个能配置超时时间的请求发送函数,同时把上面提到的错误异常都一起配置进来。

<p id="success" style="color:green;"></p>
<p id="fail" style="color:red;"></p>
<script>
  function myFetch(url, configOptions) {
    const options = Object.assign(
      {
        timeout: 3000
      },
      configOptions
    )
    const { timeout } = options
    return new Promise((resolve, reject) => {
      // 超时异常处理
      const timer = setTimeout(() => {
        reject(new Error(`ERROR_TIMEOUT:${timeout}`))
      }, timeout)
      fetch(url, options)
        .then(data => {
          clearTimeout(timer)
          resolve(data)
        })
        .catch(err => {
          clearTimeout(timer)
          reject(err)
        })
    })
      .then(response => {
        // 服务器异常处理
        if (response.ok) {
          return (
            response
              .json()
              // 接口数据解码异常处理
              .catch(err => Promise.reject(new Error('ERROR_DECODE_JSON')))
          )
        } else {
          return Promise.reject(
            new Error(`ERROR_STATUS_CODE:${response.status}`)
          )
        }
      })
      .then(v => {
        // 业务逻辑异常处理
        if (v.code !== 0) {
          return Promise.reject(new Error(`ERROR_LOGIC_CODE:${v.code}`))
        } else {
          return v.data
        }
      })
      .catch(err => {
        const [type, value] = err.message.split(':')
        // 异常类型上报
        console.log(type, value)
        return Promise.reject(err)
      })
  }
  myFetch(`/mock?r=${Math.random()}`)
    .then(data => {
      document.getElementById('success').innerHTML = data
    })
    .catch(err => {
      document.getElementById('fail').innerHTML = err.message
    })
</script>

这样,自定义的 myFetch 只需关注业务具体逻辑,针对不同的 catch error 做对应的处理。

除以上提到的协议命令字外,**whistle 还支持 resSpeed 用于模拟低网速传输(单位:kb/s),tpl 协议则可以根据请求传入参数来动态模拟不同的数据。**在 Frames 面板,还可以对 WebSocket/Socket 请求进行暂停、延迟等网络异常的模拟。

小程序 fetch API 实现

最后,留一道思考题。

近来微信小程序开发非常火,小程序原生提供的 wx.request API 能用于发送 HTTPS 请求,请在它的基础之上进行封装,支持 promise 调用和 timeout 超时时间定义(小程序默认的请求超时定义在 app.json 中,不够灵活),并针对以上提到的 HTTP 状态码异常、接口劫持注入、慢网络、无网络状态等各种网络异常进行兼容处理。

欢迎留言分享你的代码实现,在公众号「猫哥学前班」中回复关键词 request ,可以参考我的实现和 whistle rules 配置。

banner

猫哥网络编程系列:HTTP PEM 万能调试法

注:本文内容较长且细节较多,建议先收藏再阅读,原文将在 Github 上维护与更新

在 HTTP 接口开发与调试过程中,我们经常遇到以下类似的问题:

  • 为什么本地环境接口可以调用成功,但放到手机上就跑不起来?
  • 这个接口很复杂,内部调用了好几个其他接口,如何定位问题究竟出在哪一步?
  • 后端开发还没有把接口提供好,前端开发任务无法推进……

「猫哥网络编程系列」最核心的任务便是向各位分享一个我从多年的前后端项目中总结而来的「万能」HTTP 调试法,掌握并从网络编程原理上理解它,能让我们顺利定位并解决所有 HTTP 接口问题。由于该方法主要涉及到的知识点包括 HTTP 代理(Proxy)、编辑(Edit)与数据模拟(Mock),因此我称之为「HTTP PEM 调试法」。

接下来,我们就针对前面提出的几个问题,详细讲解下 PEM 调试法的思路。

如何调试线上 App 中的 H5 页面?

「HTTP PEM 调试法」之 Proxy

在上一期《猫哥网络编程系列:详解 BAT 面试题》中,我们有介绍到 Windows 下的 Fiddler 和 Mac 下的 Charles 这两款 HTTP 抓包工具,其实它们就是两个 HTTP 代理服务器(HTTP Proxy Server)。由于 HTTP 是一种符合 REST 架构风格(Representational State Transfer)的协议,具有无状态(Stateless)与统一接口(Uniform Interface)的架构约束,因此其代理机制的实现十分的简单。

打个比方,我们可以把 Proxy Server 理解成一个快递中转站,当一个包裹经过中转站时,包裹的信息(发件人、收件人与包裹里的货物)通常不会做任何的改动,直接发往下一个中转站或顾客手中。但中转站完全有能力修改快递单信息、拆箱检查货物,甚至是私吞或调换货物。

当我们需要快速定位「线上产品的接口问题」时,如果没有源码、数据、依赖服务和足够的时间去搭建一个测试环境,则通常会使用 HTTP 代理服务器来进行快速抓包调试。

Fiddler 默认只允许本地 IP(127.0.0.1)使用代理服务,通过设置「Tools -> Connections -> Allow remote computers to connect」可以开启其他 IP(通常是同一局域网内的其他设备)使用代理服务。

Fiddler 开启 Remote Proxy

Charles 默认开放代理服务,但陌生设备首次连接时需要授权确认,通过以下配置可以设置成无需授权。

授权所有设备使用 Charles 代理服务

以上两款软件默认的代理端口均是 8888 ,软件开启之后,我们可以在对应的平台终端下通过 ipconfig(Windows) 或 ifconfig(Mac)命令查询本机的局域网 IP,还可以使用 telnet 命令检查代理通道是否可用。(注:Win7 下如何开启 telnet 命令请参考百度经验。)

以下是 Windows 下 CMD 终端的使用截图,Mac 系统下请类比参考。

CMD 下 ipconfig 与 telnet

接下来,我们将手机的 Wi-Fi 代理设置为上述的 IP 与 端口号,以下是 iOS 的设置截图( Android 系统通常是长按已连接的 Wi-Fi ,在弹出的高级设置菜单中配置代理服务器)。

iOS 下设置 HTTP 代理

至此,手机上任意应用发起的 HTTP 请求都将会被代理服务器(本例中的 Fiddler/Charles 软件)监听到。

「HTTP PEM 调试法」之 Edit

通过代理服务器监听到 HTTP 请求之后,我们可以通过浏览报文的详细信息,定位出可能的接口问题。Fiddler 与 Charles 都具有同样强大的 HTTP 编辑(Edit)、重发(Replay/Repeat)、断点(Breakpoints)功能。Charles 的基础与高级用法请参考《Charles 从入门到精通》,Fiddler 教程可以参考 OSChina 专题《HTTP调试代理 Fiddler》,以下介绍 Fiddler 的部分常见用法。

Fiddler Edit 与 AutoResponder

抓到手机 HTTP 请求之后,通过编辑(Unlock For Editing)和重发(Replay)操作可以不断地调试接口的响应是否符合预期。

Fiddler 手动修改调试请求

通过设置自动响应规则(AutoResponder Rules)可以将响应头设置成常见状态码的返回,或将响应体映射成本地文件,通过外部编辑器修改文件内容进行调试。其中,若设置响应为 *bpu*bpafter 可以在请求前与响应前的事件触发时进行断点调试,十分方便。

Fiddler 将请求映射本地文件

需要注意的是,在 Fiddler 中使用 Replay 功能重发请求时,请求由 Fiddler 代理重新发起而非手机,因此手机 App 中的 H5 不会有任何变化。只有重新刷新 App 的 H5 页面,配合 HTTP 断点调试(Breakpoints )的方式才可以让修改后的 HTTP 响应体在 App中生效。这里介绍另外一种配合 Weinre 的调试用法。

Weinre 基本用法

Weinre 属于知名 Hybrid 框架 Cordova 中的一款 Web App 远程调试工具。通过在页面中注入一段 JS 脚本,可以在 PC 和手机端的 H5 页面之间建立一个 Socket 双向数据传输通道。原理上可以理解为,当我们在 PC 端的后台进行 debug 时,相关的操作被序列化成一组 JSON 字符串,数据经由通道传输给手机端中的 H5 页面,页面在接收到这些数据之后反序列化成相应的 JS 脚本操作,在其 window 上下文中执行,并将执行的结果回传给通道,PC 端的 Chrome 通过监听通道获取到相应的数据在 debug 后台中展现出来。

以下介绍 Weinre 的基本用法:

  1. 通过 npm 全局安装 weinre: npm install -g weinre
  2. 在本地 8081 端口上启动 weinre 服务:weinre --boundHost 0.0.0.0 --httpPort 8081 。通常在 Node.js 的服务中绑定 IP 为 0.0.0.0 而非 127.0.0.1(本地 IP),意味着可以让任意来源的 IP 访问该服务
  3. 通过上文介绍的 ipconfig(Mac 为 ifconfig)命令获取本机 IP 后,在本机 Chrome 浏览器中访问 Weinre 管理后台:http://10.2.69.47:8081 (本例中我的 IP 为 10.2.69.47,请注意将其替换成自己的局域网 IP)
  4. 在管理后台我们能看到相关使用说明,要求将以下脚本插入需要调试的 H5 页面中:<script src="http://10.2.69.47:8081/target/target-script-min.js#anonymous"></script>
  5. 将以上脚本插入进 H5 页面后,我们在 PC 端 Chrome 中,通过 http://10.2.69.47:8081/client/#anonymous 后台点击进入相应的客户端调试界面

问题是,我们「如何将 Weinre Script 自动注入到手机的 H5 页面中」?

HTTP Script 注入

想必用过**电信宽带的同学都有过这样的体验:在刚开始浏览网页时,会自动跳出一些「宽带升级优惠」、「宽带缴费提醒」之类的页面。这种耍流氓的方式便是宽带运营商在 HTTP 代理层面的 Script 注入行为。前面已经提到 HTTP 协议是一种 REST 风格的架构,并且他的头部与主体报文为字符串文本流(对比二机制、十六进制数据流),在不使用 HTTPS 的情况下,很容易被中间路由或代理网关进行消息篡改。

通过 Fiddler Script 特性,我们可以自动对经过 Fiddler 的 HTTP 流量进行二次修改,注入任意内容(Mac 用户若已了解相关知识点,请直接跳至下方的 Charles 截图)。

打开 Fiddler 菜单「Rules -> Customize Rules… 」,如果是首次开启会要求先下载安装 Fiddler ScriptEditor。打开 Fiddler ScriptEditor 之后,找到以下代码块(或使用菜单「Go -> to OnBeforeResponse」):

static function OnBeforeResponse(oSession: Session) {
    if (m_Hide304s && oSession.responseCode == 304) {
        oSession["ui-hide"] = "true";
    }
}

Fiddler Script 使用的编程语言是 JScript.NET(JavaScript 和 C# 的混合语法,类似 TypeScript),OnBeforeResponse 是 HTTP Response 响应前的事件函数,我们只需要在这里判断「如果开启了 Weinre Debug 功能,那么就在所有的 HTML 响应体中注入 Weinre Script」,以下是我修改的示例代码,覆盖以上代码块即可。

public static RulesOption("Enable Weinre Script")
var m_EnableWeinreScript: boolean = true;

public static var g_weinreScriptString: String = '<script src="http://127.0.0.1:8080/target/target-script-min.js#anonymous"></script>';

public static ToolsAction("Config Weinre Script")
function ConfigWeinreScript(){ 
    g_weinreScriptString = FiddlerObject.prompt("Text beblow will inject into HTML pages when 'Enable Weinre Script' rule is Enabled.", g_weinreScriptString , "Please Input the Weinre Script");
}

static function OnBeforeResponse(oSession: Session) {
    if (m_Hide304s && oSession.responseCode == 304) {
        oSession["ui-hide"] = "true";
    }
    if (m_EnableWeinreScript && oSession.oResponse.headers.ExistsAndContains("Content-Type","text/html")){
        oSession.utilDecodeResponse();

        if(oSession.utilFindInResponse("</html>", false)>-1){
            oSession["ui-backcolor"] = "#5E30B5";
            oSession["ui-color"] = "white";
            oSession.utilReplaceRegexInResponse("<\/html>", g_weinreScriptString + '</html>');
        }
    }
}

修改保存后重启 Fiddler(或使用菜单「Tools -> Reset Script」)以生效规则,接下来运行「Tools」菜单中新出现的「Config Weinre Script」,将 127.0.0.1:8080 替换成自己本机的局域网 IP 与 weinre 服务端口号,同时开启菜单「Rules -> Enable Weinre Script」。至此,所有 HTML 页面将会被自动注入 Weinre Script,之后我们就可以在 weinre 后台中开始调试相关页面。以下是参考截图:

Fiddler 中的 HTTP Script 注入

可以看到 HTTP 响应体中已经被动态注入 Weinre Script。

在 Mac Charles 下的 Script 注入配置更加容易,只需利用其 「Rewrite」功能进行简单的配置即可,参看下图:

Charles Rewrite 配置 HTTP Script 注入

通过 Fiddler/Charles 代理工具将 JS 脚本注入成功后,我们便可以通过前文提到的 weinre 后台开始 debug 相应的页面,以下是在 iPhone 模拟器中调试新浪微博界面的截图:

Weinre 后台 debug Webview H5 页面

使用该方法可以调试 Android 和 iOS 中「任意 App 的 H5 页面」,但由于主要使用了 weinre 服务,其原理决定了该方法无法像真正的 Chrome DevTools 一样支持 JS 断点调试、Profiles 性能分析等功能,具有一定的局限性。在实际 Web App 开发过程中,推荐使用以下工具进行调试 :

由此可见,「HTTP PEM 调试法」是一个通用的 HTTP 接口调试方案,可以用来快速定位线上接口问题,对于开发人员来说掌握其背后的 HTTP 协议及其代理机制的原理更加重要,接下来我们聊聊常见的 HTTP 接口开发协作方法与 Mock 思路。

我的开发任务没法推进,因为某某的接口还没提供给我。

「HTTP PEM 调试法」之 Mock

希望新手程序员在看完这一章节之后,不要再向你的项目组和上级反馈这样的说法,因为 HTTP Mock(接口数据模拟)是一项网络编程的基础技能,从实际项目经验来看,大部分基于 HTTP 接口的任务都可以并行开发。

最简 HTTP API

不同岗位(例如前端开发与后台开发)或不同业务(例如订单系统与账户系统)的开发人员开始并行开发任务之前,首先要做的应该是对耦合和相互依赖的任务进行边界划分与规则约定。具体到某个 HTTP API 接口的约定上,至少应该明确以下信息:

  1. 是否按照 RESTful API 的约定来设计接口
  2. 接口的路径、提交方法、参数、编码类型(Enctype/Content-Type)
  3. 接口返回的错误码(code)、消息说明(message)、业务数据(data)

针对以上三条信息,我设想的「最简」 HTTP API 包含以下几条原则,供各位参考:

1、不使用 RESTful API 来设计接口

RESTful API 实际上是利用 HTTP 协议的语义(提交类型、返回码、Hypermedia Link)来将所有接口操作抽象化为一系列资源对象。这要求 API 的设计者与调用者都具备深厚的 HTTP 协议功底、语义化与抽象化能力。

  • RESTful 作为一个 Buzzword(流行词),其含义已经被曲解。HTTP 协议和 REST 架构的设计者 Roy Fielding 很反感这一点,还专门开了博客以正视听。大多数人只将 HTTP 当做一种传输协议来使用(既成事实),并不能真正理解 REST 架构风格;
  • RESTful API 将所有请求抽象化为资源名词(Resources)的做法争议很大。这种做法总会让我回想起上个世纪用 FrontPage 做网页的经历,「设置一个超链接,从某个资源跳到另外一个资源」。在经过 Web 2.0 浪潮,进入移动互联网时代后,这种 API 设计容易给人带来困惑。例如「登录、注册」这样的「动词」如何抽象成「名词」(还好有 Github API 可以参考 )。而刻意的使用 「HTTP CRUD」(POST/GET/PUT/DELETE Method)操作「资源化」之后的接口,并未带来更多实质上的收益;
  • HTTP 状态码的分层思路在 RESTful API 模式下被破坏了。HTTP 1.0 中定义的常见状态码已经足够网络中间组件(代理、网关、路由)使用,HTTP 1.1 中加入的很多状态码缺乏实际场景(例如 306 状态码的废弃),它们增加了中间组件以及浏览器对规范理解与实现的要求。尽可能的将状态码交给相应的接口逻辑层而非 HTTP 协议层,能够将问题简化;
  • 对比以英文为母语的国外开发者而言,国内开发者对语义化的认知难度更高,例如 RESTful 建议资源命名用复数形式,那收货地址单词 address 的复数形式是什么?address or addresses ?address-list or address-lists?(没过英语八级的同学已经哭晕在厕所 T_T)
  • 每个人对 RESTful API 的理解都不同,在 HTTP 协议层面做扩展与实现,不如交给接口设计者与调用者自己来约定数据结构(或者参考 JSON-RPC 规范)。把 HTTP 只当做传输协议来使用的好处是,当后端服务间的接口需要直接基于 TCP 传输层来做性能优化时,可以十分方便的切换成 Socket 的实现(之前在腾讯做微博相关项目时,微博开放平台对外只提供 HTTP 的 Open API,但对内可以提供更高频率与频次调用的原生 Socket 协议)。

2、只使用 GET/POST Method

由于 HTTP 1.0 尤其是 HTML 的规范与应用已经深入人心。大部分开发者能够很自然的这样理解:「GET」 表示「读」操作,「POST」 表示「写」操作。这样既可以保证中间组件与浏览器很好的利用 GET 的缓存机制,又能降低接口设计的复杂度。HTTP 之父 Roy Fielding 也说过「It is okay to use POST」:

Some people think that REST suggests not to use POST for updates. Search my dissertation and you won’t find any mention of CRUD or POST. (很多人认为 RESTful 建议不要使用 POST 用于提交更新,去翻一翻我的论文,压根就没提到过 POST 和其他「增查改删」方面的内容。)

但使用 POST 方法时尤其要注意:「使用统一的 Content-Type」。这是一个容易被新手忽略的细节,也是接口设计中经常出错的点。在上一期的《猫哥网络编程系列:详解 BAT 面试题》中有问到:

一个 POST 请求的 Content-Type 有多少种,传输的数据格式有何区别?

以下举例一些常见类型的 HTTP POST Request 报文,请注意其中的 Content-Type 与 Body 的对应关系(已手动删除无关 HTTP Header)

POST /test.php HTTP/1.1
Host: 127.0.0.1:8080
Content-Length: 54
Content-Type: application/json

{"weixin_id":"imgXQB","weixin_name":"猫哥学前班"}
POST /test.php HTTP/1.1
Host: 127.0.0.1:8080
Content-Length: 74
Content-Type: application/x-www-form-urlencoded

weixin_id=imgXQB&weixin_name=%E7%8C%AB%E5%93%A5%E5%AD%A6%E5%89%8D%E7%8F%AD
POST /test.php HTTP/1.1
Host: 127.0.0.1:8080
Content-Length: 259
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryl60ti7CVoBj2kxfX

------WebKitFormBoundaryl60ti7CVoBj2kxfX
Content-Disposition: form-data; name="weixin_id"

imgXQB
------WebKitFormBoundaryl60ti7CVoBj2kxfX
Content-Disposition: form-data; name="weixin_name"

猫哥学前班
------WebKitFormBoundaryl60ti7CVoBj2kxfX--

只有客户端 POST 请求体的消息格式与其请求头声明的 Content-Type 一致时,服务端才能正确的接收与响应。因为许多后端的 Web 应用框架会遵照 HTTP 协议的内容协商原则(Content Negotiation)对响应体进行预处理,以提升开发体验。例如,Python 的 Flask 框架 封装了 request.jsonrequest.formrequest.data 等一系列属性用于存放不同类型的来源数据。

3、接口 URI 与参数命名风格的一致性

  • API URI 应该全小写。屏蔽掉 Linux/Windows 操作系统对文件名大小写敏感度不一致的问题;
  • URI 命名上应该使用连字符「-」来间隔,而不是使用下划线「_」或驼峰式。这是出于视觉美观度和英文语义方面的考虑,英文域名规范规定可以使用连字符,但不能使用下划线,API 路径应该和 Domain 命名风格一致;
  • URI 使用「动词+名词」或者「名词+动词」均可,但选定一种之后应该保持一致。接口风格的一致性,可以降低使用者的理解成本,好的 API 命名风格能让人「以一知万」,能从一个 API 猜测出所有其他 API 的命名形式;
  • 参数命名上应该使用下划线「_」而非连接符「-」。这点主要是从数据库字段设计的统一性和后台应用程序框架的易用性来考虑;
  • 不同接口的相同参数命名应保持统一,并考虑扩展要求。例如,收集用户信息的参数可以统一叫「ua」,为了便于扩展可以约定将客户端分辨率、浏览器型号等信息使用「||」字符串连接,如 ua=1280x768||chrome,当需要添加操作系统字段时,客户端只需按规则追加信息到原来的参数上,如 ua=1280x768||chrome||windows。该条原则还有许多其他的方法来实现,不再一一举例。

4、返回数据结构的一致性

基本的返回体结构,可参考以下示例代码。

{
    "code": "0",
    "message": "success",
    "data": {
        "id" : "1",
        "list" : []
    }
}

寥寥的几行代码饱含了几部深刻的血泪史:

  • 出于一致性的考虑,code 表示返回码(也可以理解成错误码),成功时返回 "0" ,出错时按预设的错误码规则返回(微信的返回码规范设计的并不好,因为没有内建的规律和语义);
  • 同上,可以理解 messagedata 的设计。需要注意的是 data 只具有 Object 一种类型。无数据的时候返回一个空对象 {}(而非 null),有多条数据的时候将 Array 类型数据放在其内部的 list 之类的属性中;
  • 所有原始数据类型建议统一使用字符串类型,包括布尔值用 "0""1"。原因是前后端对浮点数运算精度不一致,会导致商品价格的计算与展示出错;iOS/Android 客户端对 JSON null、布尔类型转换的不一致会导致频繁的 App Crash。

当然,也有许多其他的方案可以解决上面提到的问题,但出于「最简」的原则,这样约定的理解成本最低。

最简 Mock Server

有了最简 API 的约定之后,实现最简 Mock Server 就相对简单多了。

1、编写返回的模拟数据

首先,我们按照 API 接口约定来新建一些模拟数据文件。例如新建一个 「mock-data.json」 的文件,将以上返回体数据保存其中。

2、运行 php 内置服务器

在命令行模式下运行 php 命令,Mac 用户直接打开终端即可,Windows 用户需要先安装 XAMPP 套件,并将 php.exe 所在的目录配置到系统环境变量中,再使用 CMD 运行以下命令:

php -S 0.0.0.0:8080 mock-data.json

开启之后访问任意 API 地址(http://127.0.0.1:8080/any-api-uri-you-want/)均会返回 mock-data.json 的数据响应体。通过将 8080 端口换成 80 端口(Mac 需要使用 sudo 权限),再设置类似 127.0.0.1 www.example.com 的 HOST 配置,便可以模拟 API 的 Domain Host(http://www.example.com/any-api-uri-you-want/)形式。

当然,也可以自己编写一个 index.php 的入口文件来实现一个基于 URL Path 规则的简单 Rewrite 功能,用来同时支持多个 API 的数据模拟。

使用 Fiddler/Charles 的 Map Local 功能

Fiddler/Charles 的 Map Local(本地映射)不光是用于 HTTP Edit,同样可以用于 HTTP Mock,当一个 404 请求(还未真正实现的 API)被代理服务器捕获后,可以设置映射到本地自定义的 mock-data.json 模拟数据文件,从而被模拟成一个正常的 200 请求。

自动化 Mock System 构想

迄今为止,我还未发现一个理想中的 Mock API 开源系统,如有哪位同学有见到过请在 Github 上留言周知,以下是我对最理想 Mock System 的构想:

  1. API 录入后台。包含一个按项目(一般是 Domain)维度进行 API 管理的后台。可以在后台上录入「请求 URI、参数、多种业务数据响应体、全局错误码、API 错误码」等接口信息;
  2. API 接口文档。能够基于 API 后台数据,生成在线的 API 文档平台;
  3. Postman 导入/导出。能够基于 API 数据导出生成 Postman Collections,以便导入 Postman 中进行 API 调试;
  4. Mock Server。能够基于 API 数据快速搭建类似 MockServer 的本地服务,或提供远程模拟接口服务。

「HTTP PEM」系统分析利器

这个接口很复杂,内部调用了好几个其他接口,如何定位问题究竟出在哪一步?

对于新人来说,最快的成长方式是不断地在新项目中实践,从头到尾参与到项目的每个系统细节的设计与讨论。如果能参与到重点、大型项目中,甚至幸运地得到大牛的亲自指导,成长速度将会突飞猛进。

但更多的情况是,新人作为离职程序员的补充力量来接手一个老项目甚至是烂摊子。面对一个复杂的陌生系统,吐槽与抱怨无济于事。这时,如果能使用「HTTP PEM 调试法」,从接口设计与调用的角度来剖析、理解整个系统的设计,就能快速上手业务。例如,PHP 程序员可以在项目代码中所有的 curl 调用点,将「CURLOPT_PROXY」设置成 Fiddler/Charles 的代理服务,然后一步步调试,从接口字段上理解数据库设计和 Controller 背后的业务逻辑。

最后,欢迎各位给我留言分享更多关于「HTTP PEM」和其他调试方法的经验与体会。

Git 进阶指南(2019 修订版)

点此前往电子书《Git 进阶指南》: https://yekai.net/gb


目录

概念

常见问题

Git Alias Cheat Sheet

Alias Command Remark
grv git remote -v 查看远程分支列表
gf git fetch
gl git pull
gup git pull --rebase
gupa git pull --rebase --autostash
glum git pull upstream master
grb git rebase
gm git merge
gba git branch -a
gsu git submodule update 更新子仓库
gst git status
gaa git add -all 将当前版本库所有改动提交至暂存区
gp git push
ggp git push origin "${*}" 可指定分支或标签名,默认当前分支
ggsup git branch --set-upstream-to=origin/$(git_current_branch) 当前分支与远程同名分支关联
gcmsg git commit -m
gco git checkout
gcb git checkout -b 从当前分支新建并转向新分支
glol git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' 格式化版本号、提交时间、作者信息的日志
gwip git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit --no-verify -m "--wip--" 将当前新增与改动的文件做一次临时提交
gunwip git log -n 1 | grep -q -c "--wip--" && git reset HEAD~1 从上一次 gwip 恢复
grhh git reset HEAD --hard
gclean git clean -df
gpristine git reset --hard && git clean -dfx 注意 .gitignore 里的 node_modules 也会被清除
gsta git stash save
gstl git stash list
gstp git stash pop
gtv git tag | sort -V
gdct git describe --tags `git rev-list --tags --max-count=1` 当前最近 tag 版本信息
gca! git commit -v -a --amend 将当前修改追加至上一次提交,并修改提交记录

注:本书所有章节 git 命令行代码,会在行内注释中标注对应的 zsh alias 。

拥有一架 Google 的小飞机是一种怎样的体验

我有个同学在深圳航空开飞机的,我问他:「开飞机是一种怎样的体验?」
他说:「就像鱼儿游进了大海,鸟儿挣脱了牢笼……两个字:自由。」

Great Firewall

本文将要介绍的「小飞机」是辅助大家上网学习的神兵利器,借助飞出墙外的小飞机,我们可以了解到许多优秀的国外开源项目(如下图所示的 hardseed)。由此可见,一个好的网络环境,对我们的学习和工作是多么的重要。

hardseed

在免费试用了 60 天的 Google VM 后,我确信它是最快最稳定的云服务器,强烈推荐给大家。它的特点是:

  • 速度快。Google 亚洲机房的 TTL 是 40 左右,Linode、Vultr、DigitalOcean 通常是 200 多;
  • 费用低。Google VM 最低配置的价格与 Vultr 相同,都是 $5 / 每月;
  • Google Console 很强大,它的默认 tutorial 是教人怎么跑一个 node server,很有情怀。

其实,它在国内的访问速度之所以辣么快,是因为「Google 亚洲机房就在**」,厦门正对面的**省彰化县

接下来,请先准备好一张「可支付美元的信用卡」,然后 follow 我魔鬼般的步伐,开始搭设一架属于自己的 Google 小飞机吧~

1、打开 Google Cloud

首先,用浏览器打开网址 cloud.google.com ,如果出现 「无法显示此网页」、「连接被重置」或「连接超时」的提示,那就对了,说明我们是在**,没错。

解决这个问题的办法有三个:

  1. 去美国拉斯维加斯或者澳门的赌场,连接下他们的 Free Wi-Fi
  2. 坐在电脑前等 30 年
  3. 临时使用个国外的 VPN 或 HTTP 代理服务

以上三种方法,我推荐方法 3。

VPN 服务

推荐使用「Green 网络加速器」,可免费使用 200M 的流量。注册完成后在「线路列表」中找到服务器地址,然后使用注册的用户名与密码创建一个 VPN 拨号登录。VPN 不会配置的同学请参考下图:

百度一下

HTTP 代理服务

推荐使用「土行孙」,注册完成后会在后台得到一个 PAC 地址(不要用我截图的地址,已经过期了的),将其配置成系统的代理服务即可。Windows 用户请参考下图:

Windows PAC 配置

Mac 用户配置如下:

Mac PAC 配置

再试试 cloud.google.com 应该可以打开了。

友情提醒:请务必在 100M 免费流量用完前的当天完成以下所有步骤!别迫不及待的访问 1024 社区!

2、申请 Google VM instance

**步骤一:点击「TRY IT FREE」免费试用,使用 Google 帐号登录。**没有 Google 帐号就按流程一步步注册一个。

登录

**步骤二:登录之后,点击「My Console」进入控制台。**Google Cloud 除了提供 VPS 服务以外还提供 Google Maps、Advertising APIs 等服务,可以在一个 Project 下统一管理,如果之前没建过 Project 的话,按系统要求创建一个即可。

进入控制台

**步骤三:按系统要求填下支付表单。**按表单要求填写即可,因为是免费试用,所以只验证信用卡信息,不扣费。注意国家可直接选成「China」,英文不会填的话,直接写拼音或者汉字,不会被系统鄙视的。

填写支付信息

**步骤四:创建一个 VM instances,选择指定的配置。**其中,Zone(机房区域)一定要选择亚洲机房 asia-east1,深圳电信线路个人测试结果是访问 c 节点要稳定点。以下截图是最低配的主机类型,用来搭小飞机和个人站点完全够用。

创建 VM 实例

稍等几秒后,Google VM 就会自动创建完成了。

3、安装「小飞机」服务

步骤一:打开在线终端。

从管理页面找到刚创建好的 VM 主机,点击 SSH 按钮,在新窗口中打开在线终端。

打开在线 SSH 终端

步骤二:运行安装命令。

由于 Google VM 的权限控制比较严格,因此所有的命令前面都得加上 sudo ,Linode 等其他 VPS 提供商则不需要。

sudo yum -y install python-setuptools
sudo easy_install pip

以上命令依次安装了 easy_install、pip,它们都是 python 的模块包管理工具。参照下图 sudo pip install 命令,即可安装我们的「小飞机」:

pip install 小飞机

步骤三:使用以下命令启动小飞机服务。

开启小飞机服务

注意其中的 mgxqb 是密码(我的微信公众号「猫哥学前班」的拼音首字母),下面客户端连接时需要用到。当然也可以配置成其他端口、密码和加密类型。

到这里差不多就完成了,很简单吧?

步骤四:最后一步,配置自启动配置文件。

补充一下,据我观察 Google 的 VPS 会一个月重启一次,我们可以将小飞机服务添加到系统自启动脚本中,以便在服务器重启时自动开启服务。运行命令 sudo vim /etc/rc.local 编辑自启动配置文件。加入以下代码:

rc.local 配置

步骤五:……真的是最后一步,配置防火墙,允许外部 IP 访问 8388 端口。

如果是 Linode 等其他 VPS 服务商,可直接运行以下命令修改,但 Google VM 这样配置不会生效。

iptables -A INPUT -p tcp  --dport 8388 -j ACCEPT
/etc/init.d/iptables save
/etc/init.d/iptables restart

因为 Google VM 的防火墙配置统一由在线后台完成。如下图,找到对应 VPS 的「Network -> default」:

修改网络配置

添加一条防火墙规则,允许外部所有来源 IP(Allow from any source),使用本地 tcp:8388 端口。

添加防火墙规则,允许 tcp:8388

步骤六:好吧……最后配置静态 IP。

由于 Google VM 默认使用动态 IP,服务器重启后 IP 可能会发生改变。因此需要参照下图,将该台 VM 配置成静态 IP:

配置静态 IP

4、安装「小飞机」客户端

Google 小飞机在云上搭建好之后,本地需要一个客户端与它连接,以便建立一个双向通讯的加密通道。

Mac OS X

Mac 用户请点击此处下载 ,下载安装后,可参考下图进行配置。(请替换成自己的 IP、端口、加密方式、密码,图中的 IP 已过期)

Mac 客户端配置

Windows

Windows 用户请点击此处下载 ,配置方法与 Mac 类似。

安装完成后,小飞机有两种运行模式:

  • 自动代理模式(Auto Proxy Mode)。配置原理类似前文「打开 Google Cloud」部分所介绍的 PAC 代理模式,服务开启后,小飞机会自动修改系统代理为一个本地 PAC 地址。当访问 Google、Facebook、Twitter 等国外网站时,它会自动将请求转发到本地 1080 端口的 SOCKS5 代理通道。
  • 全局代理模式(Global Mode)。访问的所有网站均使用本地 SOCKS5 通道,当 PAC 配置未及时更新时,可选择使用。

此外,使用 Google Chrome 插件 Proxy SwitchyOmega ,可以更加灵活的进行代理配置,使用方法请自行 Google。

如有其他上网问题可访问简书的「科学上网」专题。

虽然我不知道开飞机是一种怎样的体验,但我相信大家在拥有一架 Google 的小飞机之后也能体验到什么叫,——自由。

猫哥网络编程系列:详解 BAT 面试题

从产品上线前的接口开发和调试,到上线后的 bug 定位、性能优化,网络编程知识贯穿着一个互联网产品的整个生命周期。不论你是前后端的开发岗位,还是 SQA、运维等其他技术岗位,掌握网络编程知识均是岗位的基础要求,即使是产品、设计等非技术岗位,在灰度环境体验产品时也需要理解页面缓存、Host 切换等网络基础概念。

「猫哥网络编程系列」一直是我想沉淀的一个技术知识点,因为我认为:网络编程相关知识(尤其是 HTTP 协议),是互联网产品开发当中最重要的基础知识(没有之一)。掌握这方面的基础知识,对一个新手程序员来说至关重要。本系列将会在我的微信公众号「猫哥学前班」上连载,并在 Github 上维护更新。

使用「详解 BAT 面试题」作为本文的副标题,是为了吸引更多的技术新人浏览此文,然而本文并非标题党。掌握本文所提到的知识点必将大幅提升程序员的面试成功率,因为「网络编程」方面的基础知识,是 BAT 面试的必考项目。

从 BAT 面试题说起

2009 年我在支付宝做前端开发时,参与草拟了一份非正式的前端岗位招聘要求。

这里有:

  1. 国内最大的第三方支付舞台,体验亿万资金穿梭代码的快感;
  2. 一群热爱前端技术的伙伴,最快的成长经历;
  3. 持续的培训体系,完善的项目开发环境,最具潜力的UED团队。

你需要:

  1. 热爱前端,热爱设计,对新鲜事物充满好奇心,喜欢捣鼓各种互联网应用;(兴趣、学习能力、创新能力)
  2. 自我管理能力强,健康的创业心态,乐于分享与沟通;(心态、分享、性格)
  3. 具备基本的前端素质,了解WEB标准化、性能优化方法,了解可用性、可访问性;(基本技能)
  4. 能和设计师谈产品设计,和后端开发研讨技术实现方案,制定服务接口,崇尚团队合作;(向前向后能力)

当时在面试时最流行问的前端技术问题是:Web 标准化、AJAX 与 YSlow

  • 问:一个 AJAX 请求从开始创建到最后的响应阶段,在其整个生命周期中,使用到了哪些 JavaScript 对象与方法?
  • 问:YSlow 的 34 条性能优化建议中,哪些与 HTTP 协议相关,请尽可能多的列举出来,并说说你的理解?

2011 年我开始成为腾讯的前端开发面试官,负责腾讯电商的前端开发(网页重构方向)笔试出题与面试工作。在 2012 年的校招过程中,我发现不论是我出的笔试题,还是其他面试官出的题目,HTTP 协议相关的知识都是必考项。例如,

  • 问:HTTP 协议中与缓存相关的 HTTP Header 有哪些?
  • 问:列举出你所知道的 HTTP 状态码,并描述它们的含义与发生的场景?

后来我在学习百度 FIS 框架的过程中,无意间看到百度 FEX 团队的这份开源前端开发面试题,不出所料,同样有一道与网络编程相关的题目:

一个页面从输入 URL 到页面加载完的过程中都发生了什么事情?越详细越好

由此可见,网络编程相关知识的确是 BAT 前端面试题中的必考项,而对于负责输出 API 接口的后台开发岗位来说,更是如此:

  • 问:一个 POST 请求的 Content-Type 有多少种,传输的数据格式有何区别?
  • 问:什么是 RESTful API,如何设计一个 Open API 的接口?

解题思路

接下来我们一起探讨下具体的解题思路,浏览完本文之后,你将会首先掌握 HTTP 协议相关的前后端基础知识。

要掌握 HTTP ,就需要先看到 HTTP 到底长什么样?(不了解「网络七层协议模型」和 TCP 的同学先不着急,本系列的后面几篇会涉及到。)

1、安装 HTTP 抓包工具

在 Chrome 开发者工具下我们可以看到,打开一个网页后,浏览器会发起许多 HTTP 的请求(HTTP Request),这些请求经过服务器端处理后会返回对应的数据(HTTP Response),浏览器会按照这些数据的类型将它们渲染出来。

Chrome Network Panel

Chrome 中看到的 Request/Response Header 是其格式化之后的形式,要看到它们的原始模样(Raw Source),我们需要借助两个 HTTP 接口调试利器。

其中 Windows 系统下使用 Fiddler,Mac 系统下使用 Charles。Fiddler 具体的安装与使用教程,请自行百度(安装 Fiddler4 还需同时安装 .NET Framework 4),Charles 相关教程,推荐参考 iOS 大神唐巧的《Charles 从入门到精通》。使用 Linux 系统的说明已经是网络编程方面的大牛了,不需要继续往下看 :P

2、查看 HTTP 详细报文

运行 Fiddler(或 Charles) 之后,使用 Chrome 浏览器打开「猫哥学前班」的新浪微博主页:http://weibo.com/mgxqb

在 Fiddler 左侧面板下选中该条 HTTP 请求,再将右侧面板的请求部分和响应部分都切换到 Raw 标签页。如下图所示:

Fiddler Panel

Charles 下的操作与 Fiddler 类似:

Charles Panel

HTTP 协议规范由 W3C 制定,与具体的抓包工具无关,接下来我们主要以 Charles 为例,详细讲解下 HTTP 的报文格式,这对理解基于 HTTP 的 API 接口设计和网页性能优化有很大帮助。

我们先看一下请求头的源码(Request Raw),为了防止隐私泄露,我已删除部分 Cookie 信息:

GET /mgxqb HTTP/1.1
Host: weibo.com
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.73 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,zh-CN;q=0.6,zh;q=0.4
Cookie: YF-Page-G0=f70469e0b5607cacf38b47457e34254f; _s_tentry=passport.weibo.com



仔细观察以上源码,我们能大概总结出 HTTP 协议的格式规范:

  • 第一行定义了请求类型(GET)、请求路径(/mgxqb)与协议类型及其版本号(HTTP/1.1),使用一个半角空格间隔这三块信息;
  • 示例源码的最后是两个空行。由于 HTTP 规范中要求一个合法的 HTTP 报文至少包含有一个空行,其中第一个空行用来间隔报文的头部信息(HTTP Request/Response Header)和主体信息(HTTP Request/Response Body)。在空行的下一行是报文的主体信息,由于本例为 GET 类型请求,其主体(Body)信息通常为空,这便是第二个空行的含义;
  • 余下的部分有着相同的格式,即 「HTTP Header 字段名+半角冒号+半角空格+值」,我们可以把它看成 YAML 格式的简易版。其中 HTTP Header 在规范中有着明确的定义,具体参见 HTTP头字段列表

这便是一个 HTTP 协议报文的源码格式,以下我们简单讲解下最常见的 HTTP header 的含义。

3、常见 HTTP header

User-Agent:客户端身份标识

User-Agent (以下简称 UA)字段记录了访问当前网页的用户浏览器的类型与版本、操作系统类型与版本。根据不同的 UA 信息,提供不同的站点内容是使用 UA 的常见场景。例如,如果用户使用手机访问魅族官网 www.meizu.com,浏览器会自动跳转至魅族手机官网 m.meizu.com。这种跳转实现既可以由前端 JavaScript 完成,也可以通过后端返回 302 重定向来完成。

JavaScript 访问 window.navigator.userAgent 属性即可获取该信息。虽然该属性是只读的,但有很多前端手段可以伪造 UA 。如下图,Chrome 开发者工具在模拟不同的手机机型时,也会改变浏览器 UA 值。由此可见,通过检测 HTTP User-Agent Header 来识别是否为爬虫程序,不是一个有效的方法。

使用 Chrome 开发者工具模拟不同手机设备 UA

在 PHP 中,所有的 HTTP Header 字段信息都保存在 $_SERVER 对象中,通过访问 $_SERVER['HTTP_USER_AGENT'] 即可获取 User-Agent 的值。

Cookie:用户身份标识

由于 HTTP 协议最初被设计成一种无状态的数据传输协议,服务器端无法判断每次处理的请求相互之间以及与之前处理的请求之间的关系,Cookie 的设计就是为了解决这个问题。

用户在浏览器中首次访问一个站点时,会通过请求响应头或页面JS脚本生成一些用于标识用户身份的 Cookie 信息,这些信息会按照域名分类,存放在浏览器本地缓存文件当中。例如 Windows 系统下通过访问 「C:\Users<用户名>\AppData\Local\Microsoft\Windows\Temporary Internet Files」 目录可以查看到 IE 浏览器保存在本地的 Cookie 文件。当用户再次访问该站点时,这些 Cookie 信息会被浏览器自动添加到 HTTP Request Header 的 Cookie 字段中,服务器通过读取这些信息,来区分当前请求的用户身份与状态。

浏览器可以通过读写 document.cookie 属性来添加或删除 Cookie 信息,服务器端可以通过 HTTP Response Header(响应头)中的 Set-Cookie 来改写客户端的 Cookie 信息。每一条 Cookie 属性通常都会设置一个过期时间,过期之后的 Cookie 浏览器将会自动清理它们,不会再被携带在 HTTP Request Header(请求头)中。

例如,以下 PHP 语句可以通过设置 Cookie 过期时间为前一个小时来触发客户端 Cookie 过期,达到删除 Cookie 的目的:

setcookie('key', '', time() - 3600, '/'); 

由于 Cookie 通常用于记录用户「帐号信息」和用户的「操作记录」,所以泄露 Cookie 会带来个人帐号与隐私泄露的风险。这也是为什么你在百度上搜索「贷款」的关键词之后,访问其他网站时就能看到相关的推荐广告,甚至第二天就会有各种放贷电话找上门来。

又由于 Cookie 可以随意被客户端修改(通过修改 document.cookie 属性),因此浏览器厂商们一起制定了 HttpOnly 的 Cookie 机制。服务器端在 setcookie 时,通过设置 HttpOnly 的标识,可以防止客户端通过 JavaScript 修改 Cookie 的信息。不过这种方法对于基于 HTTP 协议进行篡改的方法来说无法防范,在之后的猫哥网络编程系列中,我将会介绍如何通过监控 Wi-Fi 流量来截取、伪造用户身份。

在 YSlow 性能优化最佳实践中,有两条与 Cookie 相关的建议:

虽然浏览器对 Cookie 的大小与数量有着较为严格的限制,但很多网站(尤其是包含登录态的)的 Cookie 信息量通常比其他所有 HTTP Header 加起来的还要多。为了减少不必要的 HTTP 数据传输量,YSlow 给出了以上两条优化建议。由于网页的静态资源(图片、CSS、JS)文件无需记录用户状态,因此通常会使用一个额外的域名(Cookie 是按域名来分类存储)来存放静态资源文件。

我们使用 Chrome 开发者工具查看「猫哥学前班」新浪微博主页,可以看到新浪微博使用了 img.t.sinajs.cn 的域名来存放它的 CSS 文件,这个域名发起的 HTTP Request Header 中没有自动带上 Cookie 字段信息 (因为前后端脚本都没有在这个域名上设置 Cookie,而是设置在了 weibo.com 域名上):

Use Cookie-free Domains

这里还需要引申一个知识点:Session,它和 Cookie 有什么关系?由于 Session 与本文所讲的 HTTP 协议关系不大,相关知识点请自行百度。

Cache-Control:浏览器资源缓存标识

网站性能优化中,最为关键的是缓存机制(又是没有之一)。在服务器端通常会使用 Memcached、Redis 等服务来缓存经常访问的数据。例如在一个电商网站中,用户经常访问的热卖商品数据会被缓存在内存中,用户在一定时间内访问商品详情页时,后台程序直接从缓存服务中获取这段数据,这种方法可以大幅降低数据库的访问压力。

在用户端,浏览器会有一系列机制通过缓存来提升页面加载速度。例如 IE/Chrome 都会缓存 GET 类型的 AJAX 请求,IE 甚至会缓存 POST 类型的请求,需要通过增加时间戳参数的方式来强制清除缓存。对于所有的静态资源文件来说,最佳实践是为它们增加一个 「Never Expires」(永不过期)的强(长)缓存,以下是一个强缓存静态资源服务器的 Nginx 配置示例:

server {
    listen 80;
    server_name yekai.net;
    root /var/www/yekai.net;

    location / {
        index index.html index.htm;
    }
    location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|js|css)$ {  
        expires 365d;  
    }
}

通过配置 「expires 365d」,HTTP Response Header(响应头)中会返回 「Cache-Control: max-age=31536000」 的头字段,配合 Last-Modified 头字段。浏览器便可以自动完成资源的强缓存。

Cache-Control 是浏览器缓存机制中最为重要的一个配置,以下是浏览器加载静态资源文件时的缓存检查机制流程:

浏览器缓存检查机制流程

由此可见,静态资源缓存优化的最佳状态是:直接从本地缓存中读取 > 304 状态 > 200 状态。关于 HTTP 状态码,与网站性能优化有关的主要是以下几个。

  • 尽量减少 200 状态码的请求。200 表示是一个正常的请求返回,此条优化规则要求尽可能多的减少页面的 HTTP Request 数量。常见的方法有:合并打包静态资源、使用 CSS Sprite 雪碧图合并、缓存 AJAX、使用 LocalStorage/UserData/Manifest 等本地缓存技术。
  • 清理返回 301/302 状态码的入口链接。301 表示永久重定向,302 表示临时重定向。服务器端使用重定向返回通常是为了兼容一个旧的入口链接。我们能做的优化是,将调用旧入口的场景进行清理,直接调用重定向之后的新 URL 地址。
  • 304 表示静态资源未更新,浏览器可直接使用本地缓存文件。通常 304 的产生与浏览器的处理机制以及服务器缓存头配置有一定的关系。304 虽然未传输文件主体内容,但 HTTP 请求的建立依然是一个可以避免的性能损耗。腾讯 KM(内部知识分享平台)上有一篇文章通过在真实海量业务场景(没记错的话是 Qzone 业务)中,正交验证 HTTP 1.0 与 1.1 协议中与缓存相关的 HTTP Header 配置,结合日志分析得出了一个最佳实践:**关闭 Etag 配置,只启用 Cache-Control 与 Last-Modified 响应头。为了兼容老浏览器,可保留 Expires。**因为 Etag 的缓存方案,在经过 CDN 及网关代理服务器后,会导致缓存命中率下降。从以上「浏览器缓存检查机制流程」图上可以看出,使用强缓存(Cache-Control max-age 设置为一年)后浏览器在资源过期前不会发起 HTTP 请求,那如何保证静态资源在服务器上更新后本地的缓存也能同步更新呢?可参考百度 FIS 的「文件指纹」方案。
  • 清理返回 404 状态码的入口链接。静态资源文件的 404 调用需严格避免,而入口页面的 404 则在所难免。通过在全站 404 页面进行产品引导与体验优化,并结合数据上报记录来源页(HTTP Referer Headerdocument.referrer),可以找到并清理 404 来源入口。对于由搜索引擎进入的来源,可通过主动提交新索引至搜索引擎,或使用 301/302 重定向的方式,有效利用起这些「被浪费的流量」。
  • 502 服务器出错。如果是 Nginx + FastCGI 的常见架构,通常是由于 Nginx 缓冲区溢出或服务器资源被耗尽引起,针对不同的业务场景进行 Nginx 的配置优化能显著提升服务器抗压性能。

如果你对上文提及的「网络性能优化」的知识点十分感兴趣,建议你通读 Steve Souders 的《高性能网站建设指南》与《高性能网站建设进阶指南》,Steve Souders 的个人网站上积累了很多性能优化的方法与案例。

如果你能看到这里,相信你已经知道如何解答前文提到的几道 BAT 网络编程面试题中,关于 「HTTP 协议、状态码、缓存与性能优化」相关的问题。

在下一章节中,我们会继续 HTTP 协议的话题,并详细讲解 HTTP POST 相关的网络编程细节与调试技巧,相信看完之后你将能轻松定位并解决所有接口联调的问题与 Bug:)

「手写识字」小程序功能介绍

上周猫哥发布了个人独立设计与开发的一款微信小程序「手写识字」,经过一周的线上数据观察与功能优化,产品体验已趋于稳定,今天发文将「手写识字」小程序推荐给大家。

banner

「手写识字」源于我个人的一些需求:

  • 看书和玩游戏时,偶尔会出现一些不认识的汉字,需要手写来查询;
  • 教小娃认识自己的名字,需要能书写笔画,回放笔画的顺序;
  • 年纪大的讲方言的长辈,可以查询汉字的标准普通话发音;
  • 帮亲戚朋友给新出生的小孩取名,需要查询汉字的五行和释义;

经过一段时间的预研,我利用小程序 Canvas 绘图 API,结合腾讯的手写识别库、百度的汉字查询库以及阿里的阿里云 Node 后端服务,开发出了这款微信小程序「手写识字」。

这款小程序的操作十分简单,只需用手指在屏幕上方的画布区域书写,即可查询所写汉字的「拼音、五笔、五行和释义」。

cool

小程序在使用过一次后,可以通过「下拉微信聊天列表」,从顶部的小程序任务栏重新进入。因为没有额外的页面切换和广告干扰,所以操作的效率非常高,符合微信之父张小龙对其「用完即走」的定义。

当前版本的「手写识字」实现了以下功能点:

  1. 手写识别文字;
  2. 识别后,最多可切换六个相似的候选词;
  3. 点击拼音格子,能朗读当前发音;遇到多音字时,可左右滑动释义区域来切换拼音与释义;
  4. 分享所书写的汉字给微信好友,好友点击进入时,能重播汉字的书写笔画。

基于上面提到的最后一项功能,你甚至也可以把它当做「画板」来使用,创作包含有隐藏含义的图像文字发送给好友。

funny

上周小程序刚上线时,收到了不少用户的反馈,这里我把常见的问题汇总解答一下:

  1. 如果你的微信无法进行手写识别,请更新微信到最新版本(6.6.2 及以上);
  2. Android 手机可以将小程序添加到桌面当做 app 来使用,iPhone 手机没有开放这个权限,这个是手机操作系统的设计限制,与微信和微信小程序无关;
  3. 受限于使用的识别引擎,部分繁体体、会意字、生僻字无法识别,如:葉、*、氼。如果用户反馈较多,后续版本会考虑更换识别引擎;
  4. 识别引擎会同时校验笔画的书写顺序,不同的书写顺序会影响识别的结果;
  5. 如果创作的图案过于复杂(笔画过多),会造成无法分享;
  6. 最后,我在这个小程序里种下了两个彩蛋,当手写识别两个预设的汉字时会触发,欢迎挖掘:)

以下是「手写识字」的小程序码:

code

如果觉得好用,希望你能将它分享给更多的亲朋好友,如果有改进的建议,欢迎在公众号「猫哥学前班」给我留言,谢谢。

网络慢?看看路由器设置对不对

在上一篇《为什么房间的 Wi-Fi 信号这么差》中,猫哥从微波炉、相对论、人存原理出发,介绍了影响 Wi-Fi 信号强弱的几大因素,接下来猫哥再给大家介绍几种不用升级带宽套餐也能提升网速的路由器优化方法。

  • 防蹭网
  • 开启 UPnP
  • QoS 与网络限速
  • 设置正确的 MTU 值
  • 使用路由器交换机模式
  • 使用无线中继扩展 Wi-Fi 信号

1、防蹭网

这是最最首要的一条:确认没有陌生人在蹭网!

被蹭网意味着你的 Wi-Fi 密码被泄露(看看是不是不小心用万能钥匙把自家 Wi-Fi 共享出去了?),或者你的路由器已经被入侵。入侵者如果稍微懂一点黑客技术的话(「猫哥学前班」以后也会介绍),只需通过 DNS 劫持或 ARP 欺骗技术,就能轻松获取你所有的上网信息和账户密码。

我们可以先通过以下方式,确认自家 Wi-Fi 的安全性。

进入路由器管理后台

参考以下截图,在手机的 Wi-Fi 网络设置中找到路由器的 IP 地址,一般默认 IP 是 192.168.1.1

查看路由器 IP 地址

用浏览器打开以上 IP 地址(本例中为 http://192.168.199.1/ ),在弹出的登录窗口中,输入用户名和密码。如果确认自己没有设置过,那可以尝试默认的用户名 admin 和密码 admin

如果提示密码错误,可以查看路由器设备背面标签,上面有注明初始的用户名和密码。如果依然提示密码错误,说明你的路由器已经被人入侵过了,可以长按路由器上的 reset 按钮超过 10 秒,进行初始化重置。

注意:宽带拨号用户在初始化重置之前,请先确认有记录好宽带账号和密码。

路由器背面标签会标识默认用户名和密码

如果你的路由器密码一直用的默认的 admin,一定要重新设置一个较复杂的密码。因为大部分路由器的安全性做的并不好,通过简单的 CSRF 技术就能轻松劫持路由器的 DNS。

查看「设备管理」

在路由器的管理后台中,有一个「连接设备」或「客户端列表」的界面,点进去后就可以查看到所有连接到该台路由器上的联网设备,包括手机、电脑、路由、电视盒等等。

查看路由器设备连接状态

找找看,是不是每台设备你都认识。如果发现有陌生设备,那说明你的 Wi-Fi 已经泄露了,赶紧重设一个 Wi-Fi 密码先!

注意:路由器后台密码和 Wi-Fi 密码是两个概念,当然你也可以把两个密码设置成一样的。

在无线 Wi-Fi 密码设置界面中,通常有个选项是选择加密算法,**记住一定不要选择 WEP 加密。**因为这种模式很容易被程序暴力破解,八位长度以下的密码分分钟就能破解掉。

设置好密码之后,我们再来看看其他的路由器优化方法。如果看不懂的话也没关系,因为即使看懂了也很可能用不上:)

2、开启 UPnP

如果有经常挂机下载岛国爱情动作片的习惯,那应该特别留意这条优化方法,因为它通常能够挑战宽带的极限速度。

先普及个宽带常识,假如你办的宽带套餐是 20M,但发现迅雷下载速度只有 2.5M/s,并没有到达 20M/s,这是正常的,因为二者的计算单位不同。

宽带运营商所说的 20M 是指「每秒比特数」为 20 兆(即 20M bps),而软件下载速度 2.5M/s 指的是「每秒字节数」为 2.5 兆(即 2.5M Bps)。其中的小 b 为 bits,大 B 为 Bytes,换算方法为 :8 bits = 1Bytes,1KB = 1024 Bytes,1024KB = 1M。

但实际情况是,你的下载速度通常都达不到理论最大值(即使你已经开了迅雷 VIP 会员)。因为路由器作为局域网网关,需要同时处理局域网内所有上网设备的流量负载与分发,会导致在流量管理上出现一定的损耗。

这时,我们可以尝试开启路由器的 UPnP 功能,它能够让上网设备直接通过端口映射的方式连接外网,减少在局域网环节的性能损耗,从而提升下载速度。

登录路由器管理后台,在转发规则、端口映射或高级设置菜单中找到一个「UPnP 设置 」的选项,将其设置为「开启」状态,再试试下载速度是否有所提升。

3、QoS 与网络限速

如果局域网内的某些设备经常挂迅雷下载,就会影响其他设备的上网和游戏体验,通过 QoS 和网络限速可以解决这一问题。

在路由器的管理后台中,找到并开启 QoS 设置。开启后,路由器能「自动」将流量「合理地」分配给需要的上网设备,从而避免整个局域网出现网络拥堵的情况。

开启智能 QoS 网络质量管理

通常设置 QoS 的时候,会要求填写「上行带宽」和「下行带宽」,也就是所办宽带套餐的最大上传速度和最大下载速度。这两个值可以通过「QQ 电脑管家」的网络测速工具,或者百度上搜索「宽带测速」进行在线测试。测试的时候,记得断掉其他的上网设备,确保能测到准确的最大值。

另外填写的时候,注意认清默认的流量单位,是大 B 还是小 b,是 Kb 还是 Mb,具体换算规则参看上一章节。

某些路由器会提供基于 IP 或 MAC 地址的限速功能,开启后能限制某台设备的最大下载和上传带宽。但如果开启的话,会同时增加路由器流量分发规则的复杂度,带来一定的性能损耗。所以一般来说,如果你和其他使用宽带的人没有什么血海深仇的话,最好不要开启 IP 网络限速功能,使用 QoS 即可。

4、MTU 设置

这条规则不大常用,如果没有出现连接 VPN 后「打开百度很快,但其他网站很慢」的奇特现象,或者没有使用多台路由器组建子网的情况,那就请务必不要使用该条策略。

以上问题通常是由于路由器的 MTU 值设置不合理引起的,一般来说,使用 VPN 时,应当把 MTU 设置在 1444 左右;其他情况下将所有路由器的 MTU 值统一设置为 1500 。

MTU 的全称是 Maximum Transmission Unit,即数据帧的「最大传输单元」。当我们玩游戏、看直播、聊微信的时候,我们的操作会被应用程序封装成一个个数据包。网卡将这些数据包传输给路由器,路由器再通过以太网将数据包传输给目标服务器。

这些数据包有大有小,为了确保网络的最大化传输效率,超过一定大小的数据包在数据链路层(通常指 Ethernet 层,参看 OSI 七层模型)会被切分成一个个数据帧。Ethernet (以太网)标准规定一个数据帧的最大值为 1518 字节,除去 Ethernet 协议层所占用的 18 字节后(6 字节来源 MAC 地址 + 6 字节目标 MAC 地址 + 2 字节协议类型 + 4 字节协议结束标识 FCS),剩下的 1500 字节即是 MTU,它通常是指 IP 协议层及其 Payload 数据。

Ethernet 数据帧的标识划分

早期国内的 ADSL 宽带拨号采用的是 PPPoE 协议(Point to Point Protocol over Ethernet),该协议需要额外占用 IP 层 8 个字节用于标识 PPP 协议,所以传统的 TP-LINK 路由器的默认 MTU 为 1492 字节(1500 - 8)。但如今大部分家庭和企业都是使用的光纤入户或光猫拨号,因此直接保持 MTU 为 1500 能确保最快的上网体验。

而使用 VPN 之后,各种协议的标识头封装变得更加复杂,如果遇到 MTU 引起的上网问题,通常需要使用 ping 工具来检测出最合适的 MTU 值

如下图,通过 ping 命令(注意 -f 后面的参数是字母 l 不是数字 1),我们能发现当数据包为 1472 字节时可以恰好不用拆包直接一次传输。由于 ping 命令使用的是基于 IP 协议之上的 ICMP 协议,所以 MTU = 1472 字节 + 8 字节 ICMP 协议头 + 20 字节 IP 协议头 = 1500 字节。

使用 ping 命令行检测网络最大 MTU 值

5、使用路由器交换机模式

当联网设备较多、网络覆盖区域较大的时候,通常都需要组建子网。使用路由器「交换机模式」接入法,会比常见的 「WAN-LAN-WAN 级联」接入法的性能更优。

如下图,左图为「交换机模式」接入法,将父路由器 A 的 WAN 口(通常为蓝色)直接连接光纤或拨号猫,LAN 口与子路由器 B 的 LAN 口进行连接;右图为「WAN-LAN-WAN 级联」接入法,将父路由器 A 的 LAN 口与子路由器 B 的 WAN 口进行连接,从而组成子网。

路由器的两种不同组网模式

当使用「交换机模式」时,连接路由器 B 的设备在物理层上与连接路由 A 的设备出于同一网段,所以网络传输效率更高。

使用「交换机模式」之前,需注意将电脑单独连接路由器 B(LAN 口),进行以下设置:

  1. 登录路由器 B 管理后台,关闭 DHCP 服务,避免开启多个 DHCP 服务器造成的 IP 冲突问题;
  2. 将路由器 B 的 IP 分配方式改为「自动分配」。

6、使用无线中继扩展 Wi-Fi 信号

一般来说,将无线路由器摆在房屋中间位置,能达到最佳的信号覆盖效果。但如果某些区域信号不强,则需要加多一个无线路由器或无线中继器来扩展 Wi-Fi 的覆盖范围。

无线中继器的原理可参考下图(图片借鉴自极路由中继说明图):

无线中继的正确使用位置

当无线 Wi-Fi 信号无法覆盖到 B 点时,可以通过在 Wi-Fi 可覆盖的范围内部署一个无线中继器,来达到信号扩展的效果,从而将信号「中继」至 B 点。

大部分的路由器都具有无线中继功能,配置方式也比较简单。在路由器管理后台的无线网络设置中,开启「无线中继」模式,扫描需要被中继的 Wi-Fi 信号,勾选之后输入 Wi-Fi 密码即可扩展成功。由于各个路由器厂商的设置方法存在较大差异,具体方法请自行百度。

以上六种路由器优化方法中,通常我们只需关注方法 1 中提到的路由器安全问题。

在路由器的选用方面,需要针对不同使用场景选择不同功能的路由器,才能让网络架构和体验更加符合实际的要求。如果是办公环境使用,一般选择 TP-LINK 、磊科(netcore)、水星(MERCURY)、网件(NETGEAR)等传统企业路由器;如果是居家环境使用,则建议选择极路由、小米、魅族等智能路由器品牌,其后台管理与配置会更加简单方便。

如有其他路由器优化技巧与问题,欢迎留言讨论:)

别忘了你的知识产权

昨晚微信终于给我开通了原创和评论的内测功能,所以今天写篇文章来测试下看看,如果你有幸看到了这篇文章,那么恭喜你!你将有希望抢到「猫哥学前班」有史以来的第一个官方认证沙发、板凳和地板:)

恰好今天是「世界知识产权日」,那就给大家分享下我申请专利、商标、域名和著作权等知识产权方面的一些经验吧。

一、专利,流氓与创新

关于专利大家都不陌生,个人或企业一旦拥有某项专利后,其他人想使用这项技术则必须获得专利所有人的授权,否则会造成侵权。

**的专利类型分发明、外观、新型和授权四种,产品的外形、包装、工艺都可以申请专利,程序员写的算法、软件、系统也同样可以申请专利,即使这个系统还只是脑海中的一个想法。

不过需要注意的是,设计师的设计作品(如,软件操作界面)如果只用于在电子设备上展示,而没有被制作成印刷制品,则无法在**申请专利(但拥有著作权,这个待会再说),但在欧美国家却可以。

1、为什么腾讯的专利比阿里的多

09 年我做个人版支付宝项目的时候参与过两个功能的开发,一个是基于 Spring MVC 框架的模板层 UISVR 组件;另外一个是基于页面 URL 的精准帮助投放系统,支付宝网站「交易记录」页面底部的「使用遇到问题?」模块,就是这个功能的具体实现。

等到我和开发同学找法务同事准备申请技术专利时,结果被要求提供一份**「规范的」专利申请文档**。然后,就没有然后了……

在腾讯工作期间大不一样,公司大力鼓励员工进行微创新和专利申请。

只要提交一份 500 字的专利申请稿(「不规范的」文字概述)就能拿到 500 块钱,真是「小手一抖,五百到手」。

专利申请稿内部初审通过后,公司法务会联系专利代理事务所安排专人(通常是懂技术的妹纸)对接,撰写完成国家专利局需要的那份「规范的专利申请文档」,申请人只需与代理人电话沟通、校对文档即可。

并且在专利流程流转至每个新阶段(受理、初步审查、公布、实质审查、授权)时,公司还会按照专利的内部评级奖励几千到上万不等的奖金。

算下来,如果我的「微博监控系统」(专利号:CN104063390A)和「自动化排班算法」(专利号:CN104112175A)能走完全部流程的话,妥妥地能拿到一万块的奖金。虽然后来我被卖给京东没机会拿到钱,但那两项专利或多或少帮我通过了那年的通道晋级评审。

可见,腾讯的专利数量之所以超过阿里和百度的总和,和公司的创新激励制度还是大有关系。

2、苹果公司的奇葩专利

在一次法律培训课上,我有幸见看到了「苹果滑动解锁」操作流程的专利(专利号:US 8,046,721)。

unlock

为了绕过这个简(ě)单(xīn)的专利,安卓手机系统不得改用了九宫图解锁、扇形滑动解锁、向上滑动解锁、向左滑动解锁、向下滑动解锁(就是不能向右滑动解锁……)等方案。

后来我才知道,苹果除了这个专利之外,还有一系列奇葩专利:

  • 「Home 键凹型按钮专利」(专利号:US 7,902,474)
  • 「屏幕界面图形专利」,即圆角图标专利(专利号:US D604,305)
  • 「手持设备圆角矩形外观专利」(专利号:US D670,286)

这些富有争议的专利,成功的遏制了其它手机厂商的发展,三星甚至因为这些专利侵权,被判赔偿苹果 10 个多亿的美金。

iPhone 作为世界上最赚钱的手机,苹果行使专利权保护其外观免被山寨,的确无可厚非。但某些小厂确通过一些专利诉讼案进行炒作,却颇有「专利流氓」的嫌疑。对于大公司来说,专利通常是作为一种防御性手段,而非垄断性武器。

专利数量通常会作为一个企业和城市的创新力指标,深圳在 2015 年的专利总量就已超 10 万件(其中华为、中兴、腾讯三家占 90% 以上),位列「2015 **十大创新城市排行榜」榜首。

但其实靠专利数量来评价创新力意义不大,就像前几年用 GDP 考核官员的绩效一样的道理。

我简单搜索了下和「前端 CSS 技术」相关的专利(使用 css 关键词搜索),居然连代码合并(专利号:CN102622376A)、雪碧图技术(专利号:CN104516971A)、CSS 样式复写(专利号:CN104866570A)都能申请成专利,可见这里面的水分有多大。

我感觉,就像吃了一坨翔一样。

有两个经济学研究生甲和乙,二人在路上走,发现一坨狗屎。

甲对乙说:你把它吃了,我给你5000万。

乙一听,这么容易就赚5000万,臭就臭点吧,大不了拿了钱去洗胃,于是就把屎吃了。

二人继续走,心里都有点不平衡,甲白白损失了5000万,什么也没捞着。

乙虽说赚了5000万,但是吃了坨屎心里也堵得慌。

这时又发现一坨屎,乙终于找到了平衡,对甲说:你把它吃了,我也给你5000万。

甲一想损失的5000万能赚回来,吃坨屎算什么,乙不是也吃了吗?于是也把屎吃了。

按理说这下二人该平衡了,但是他们越琢磨越觉得不对劲,两个人的资本一点也没有增加,反而一人吃了一坨屎。

于是就去找教授,教授听了他们的诉说,安慰他们:同学们,你们应该高兴啊,你们仅仅吃了两坨屎就为咱们国家贡献了1个亿的GDP!

二、商标,侵权可能会坐牢

因为我之前想做一款陌生人交友类的社交产品,所以还找过代理公司注册商标。

通常互联网社交类的产品商标注册在第 9 大类(电子计算机及其外部设备)和第 45 大类(提供人员服务)。若大类中存在「近似商标」,则商标注册申请有可能被驳回,且被驳回后商标局不会退还注册费用

当然找一家靠谱的商标注册代理公司会省事很多,一个大类的费用(可包含 10 个小类)大概是 800 - 1500 之间。

商标具有极强的辨识性和排他性,一旦造成侵权,企业可能会赔得个破产清算,这点创业公司的小伙伴们需要注意。尤其是「驰名商标」具有全行业(甚至全球)的广泛排他性,如果申请的域名和驰名商标一致也会被判定成无效。

三、域名,不错的投资渠道

域名注册一般直接使用国内的阿里云注册即可,价格实惠、备案方便。

但今年 3 月份工信部出了个《互联网域名管理办法(修订征求意见稿)》,部分网友反映第 37 条大有想建立中华人民共和国局域网白名单的嫌疑,这里我也只能表示墙裂关注了。

第三十七条 在境内进行网络接入的域名应当由境内域名注册服务机构提供服务,并由境内域名注册管理机构运行管理。
在境内进行网络接入、但不属于境内域名注册服务机构管理的域名,互联网接入服务提供者不得为其提供网络接入服务。

另外我手头几个不错的域名,感兴趣的同学可以留言,价格好商量,绝对不超过一千万 :P

四、著作权,人人享有

copyleft

著作权也就是版权,我国法律规定著作权采用「自动保护原则」。

作品一经产生,不论整体还是局部,只要具备了作品的属性即产生著作权,既不要求登记,也不要求发表,也无须在复制物上加注著作权标记。

例如我这篇文章,一经发表我就自动享有著作权。不论我的文章有没有打「原创」标签,也不论我有没有去国家机关登记。只要是未经作者许可,擅自转载的,就构成侵权。

著作权保护的范围非常广,它包括文字作品、口述作品、音乐、舞蹈、美术、建筑、摄影、电影、模型作品、计算机软件和代码以及前面提到过的设计师的 PSD 设计图,甚至是一条段子、微博也受著作权的保护。

作品被侵权后,如何证明你才是作者,而非剽窃者,法律上主要采取时间先后顺序的判定原则。

这里给设计师朋友们提个醒:如果担心 PSD 被人盗用,可以在作品完成之后,**立刻通过自己的邮箱给自己发一封邮件,并将作品作为附件。**这样相当于通过第三方(邮件提供商)证明了这个作品最先由你创作完成。

不过比较苦逼的是,剽窃者只需要稍微改动下图形的角度、大小、颜色,就可以规避侵权。

对于文字类的作品,很多剽窃者会通过修改部分用词和短语的手段,来规避抄袭。高手如郭小四者,则可能直接抄袭故事情节。但实际上,计算机完全可以通过技术手段(例如,分词和海明距离算法)来识别两篇文章的相似度,从而判定是否为抄袭,也许微信公众平台已经使用了这项技术也说不定。

对于音乐类的作品,这两年国内的各大互联网公司和唱片公司合作的非常不错,现在很少会有盗版音乐,用户基本上也养成了购买正版音乐的使用习惯。

对于电影类的作品,现在国内整体质量偏低(尤其是电视剧),没有侵权的价值。

对于代码类的作品,MIT (开源软件许可协议)是主流趋势。

最后,对于收费软件,我呼吁大家(尤其是 IT 同行)尽量不要使用破解版了,这不安全,也很不体面。

2016 年最适合投资 P2P

猫哥学理财系列文章

最近央视「e 租宝非法集资」、「招行跟进农行关闭P2P支付接口」相关的报道铺天盖地,P2P 的话题又开始成为大家关注的焦点。

面对这个话题大概可以分成两种人,一种是喜闻乐见派,——因为他们没有投 P2P 理财产品(当然也没有从 P2P 赚到钱),「连 P2P 都敢投?想钱想疯了吧!」;另一种是投了 P2P 的,即使赚了钱,心里也难免嘀咕:「我投的这家 xx 宝(xx 所),会不会也出问题啊?」

作为一名爱学习的业余投资者,猫哥当然是投了 P2P 的。我从 2014 年年中开始到现在一直在投,平均年化收益保持在 14% 左右,写这篇文章的目的就是想结合自身投资经验,向周围的亲戚朋友们科学的、系统的阐述「P2P 是一种低风险、高收益的理财方式」,教会投资新人如何投资靠谱的 P2P。

声明:本文作为猫哥学理财系列的第二篇,会连载在我的微信公众号「猫哥学前班」上,转载请注明出处。另外,本文引述的大量法律法规均源自政府权威网站,但部分个人事例进行了些许艺术加工,仅供参考:)

一、为什么会有 P2P

1、从民间借贷说起

我有个亲戚长辈投资很有一手,他有个习惯是喜欢拿自己的大部分钱「借」给他一个朋友投资。

说是「借」,其实是收利息的,——月息三分。1 块钱的本金每个月收 3 分钱的利息,也就是月收益率是 3%,年化收益 36%,对比余额宝、理财通年化 3 - 4% 左右的收益,大家感受一下。

我问他,那这样借钱有风险吗?他说不会的,他朋友也是「借钱」给需要的人,如果那些人还不起钱,他有一百种方法可以去「要」回来。

我恍然大悟,「难道是传说中的民(gao)间(li)借贷?」。

长辈笑了一笑,再没说什么了。

电视剧《征服》剧照

第二十六条 借贷双方约定的利率未超过年利率24%,出借人请求借款人按照约定的利率支付利息的,人民法院应予支持。

借贷双方约定的利率超过年利率36%,超过部分的利息约定无效。借款人请求出借人返还已支付的超过年利率36%部分的利息的,人民法院应予支持。

第三十条 出借人与借款人既约定了逾期利率,又约定了违约金或者其他费用,出借人可以选择主张逾期利息、违约金或者其他费用,也可以一并主张,但总计超过年利率24%的部分,人民法院不予支持。

——《最高人民法院关于审理民间借贷案件适用法律若干问题的规定》,自2015年9月1日起施行

请注意以上法规中提到的两个数值 24% 和 36% ,总结一句话:欠债还钱天经地义,收 24% 的利息还真不算多。

2、小微企业与普惠金融

为什么小微企业是带动我国国民收入的无名英雄呢?目前我国中小企业占比超过99%,对税收的贡献超过了50%,对GDP的贡献超过60%,同时还提供了80%的城镇就业岗位和82%的新产品开发。

今年有一系列的降准降息,但是从我们的统计来看,央行降息以后,49%的小微企业的产品利率是超过了3%,高利贷还是比较高的,小小企业的融资环境并没有得到宽松。

造成这样的原因,一方面央行的利率降低了,但是银行对企业的审核标准并没有降低。按照传统的审核标准情况下,小微企业实际上很难符合银行放贷的一些基本要求。

——《2015**小微企业普惠指数报告发布

当前**经济的现状是,大量小微企业需要钱,但银行出于风控成本考虑又不可能借钱给他们。所以就出现了 P2P 这种理财产品,说好听点叫做「互联网金融借贷」,说难听点那是「高利贷 O2O 模式」。

那么,国家政策对 P2P 的态度是怎样的?

防范风险、推进创新。加强风险监管,保障金融安全,维护金融稳定。坚持监管和创新并行,加快建立适应普惠金融发展要求的法制规范和监管体系,提高金融监管有效性。在有效防范风险基础上,鼓励金融机构推进金融产品和服务方式创新,适度降低服务成本。对难点问题要坚持先试点,试点成熟后再推广。

……

(一)鼓励金融机构创新产品和服务方式。

推广创新针对小微企业、高校毕业生、农户、特殊群体以及精准扶贫对象的小额贷款。

——《国务院关于印发推进普惠金融发展规划(2016—2020年)的通知

普惠金融的总体原则是八个字,——「防范风险、推进创新」,P2P 不但可以搞,而且要大搞,但是在这个过程当中,监管与风控是基础。

2016 年 1 月 27 日,银监会发布的《网络借贷信息中介机构业务活动管理暂行办法(征求意见稿)》正式截至意见反馈。据某业余砖家预测,2016 年将成为 P2P 行业正规化元年,并且将在 18 个月的过渡期后成为**普通民众最主要的投资渠道之一。

接下来,我们一起看看经过正规化之后的、「真正的」 P2P 究竟是怎样的。

二、真正的 P2P 是怎样的

1、跑路的都不是 P2P

郎咸平教授在「财经郎眼 :聚焦互联网金融」这期节目中,讲到一个很重要的观点:「跑路的都不是 P2P」,我深以为是,所以才敢在文章开头说 P2P 「风险低、利率高」。

早在 P2P 网络借贷平台还未出现之前,首先冲击银行业的是支付宝、财付通这样的「第三方支付平台」。这些平台在上线之初,就明确受到了银监会的监管。

2008 年,我在支付宝实习期间,做过一个和资金归集有关的项目(作为一个有职业操守的专业码农,我是不会透露这个项目的任何细节的)。

各位有没有想过,为什么我们敢把钱从银行卡转入支付宝账户中存放?万一支付宝的数据库被(黑客)人为修改的话,那支付宝岂不是成印钞机了?

支付宝资金由银行托管

其实,支付宝账户虽然是虚拟账户,但它所承载的资金在各大银行中都是有真实的银行账户托管的。

第三条 支付机构接收的客户备付金必须全额缴存至支付机构在备付金银行开立的备付金专用存款账户。

第四条 客户备付金只能用于办理客户委托的支付业务和本办法规定的情形。

任何单位和个人不得擅自挪用、占用、借用客户备付金,不得擅自以客户备付金为他人提供担保。

——**人民银行公告〔2013〕第 6 号,《支付机构客户备付金存管办法

这就意味着支付宝这样的第三方支付机构所吸收的客户资金,是随时受银行部门监管的,且除了吃活期、定期利息外,不可以将这些资金用于股票、基金、债券等任何投资用途(注意,余额宝的模式与这些情况不一样)。支付宝内部有一个「资金结算部」,她们(经证实,这个部门都是美女)的任务就是在银行每天下班后,将支付宝对账单与银行流水进行核对,并将对账结果提交给银行。了不起的是,支付宝这么多年的对账结果一直都是零资损。

可想而知,在银行的实时监管之下,即使支付宝想跑路,也很难跑得了。

(十四)客户资金第三方存管制度。除另有规定外,从业机构应当选择符合条件的银行业金融机构作为资金存管机构,对客户资金进行管理和监督,实现客户资金与从业机构自身资金分账管理。客户资金存管账户应接受独立审计并向客户公开审计结果。人民银行会同金融监管部门按照职责分工实施监管,并制定相关监管细则。

——人民银行等十部门发布《关于促进互联网金融健康发展的指导意见

P2P 也是一样的道理,所有未经过银行(或第三方支付机构,这点存有争议)进行资金存管的 P2P 都是「伪 P2P」,都是不合法的。真正的 P2P 不会、也无法选择「跑路」,希望在监管细则出来之后,能够从制度上彻底封杀 P2P 跑路的可能性。

「e 租宝」最核心的问题就出在资金监管这条,它谎称《e租宝与兴业银行签署资金存管协议》,但实际上资金账户并未受银行监管,所以央视新闻最后对它的定性是非法集资,而非 P2P。这一点大家在选择 P2P 平台的时候一定要擦亮眼睛,不要轻易相信 P2P 平台自吹自擂的所谓「第三方托管」,一定要亲自进行核实。核实方法大概有以下几种:

  • 要求 P2P 平台客服提供详细的托管协议并与第三方存管机构官方客服确认核实;
  • 在网上银行后台交易记录中确认「充值」与「提现」的对象确实为第三方存管机构而非 P2P 平台账户;
  • 若第三方存管机构有提供资金管理后台,客户应可以「脱离 P2P」平台直接存取这些资金。(不得不说,汇付天下在这一方面的确做的比较好,接入其资金托管的 P2P 平台还未出现过跑路的。)

此外,给小公司的朋友们提个醒:

像「e 租宝」这种公司账户与老板私人账户不分的行为,违反了《中华人民共和国公司法》第一百四十八条、《人民币银行结算账户管理办法》第三十九条与六十五条相关规定,同时公司财务部门与监事会未尽到应有的监督义务,均需承担法律责任。

第一百四十八条 董事、高级管理人员不得有下列行为:

(一)挪用公司资金;

(二)将公司资金以其个人名义或者以其他个人名义开立账户存储;

——《中华人民共和国公司法》

2、P2P 的风险与收益关系

在我看来 P2P 平台根据借款人的不同又可以细分为:个人对企业(P2B)和个人对个人(P2P)两种。

1)收益率 14.4% 以下的 P2P 平台风险低于银行

可能有不少人了解过信用卡的信用贷款,甚至尝试过支付宝「蚂蚁借呗」之类的小额贷款功能,以下是我前几天收到的一条垃圾短信:

【中信信用卡】#现金随时借,最快秒级到账#您最高可申请预借现金1000000元(需账户无欠款),7-20天任您选择,1万元日手续费仅需4元,推荐您借20天,手续费仅需856元,立即致电4006995558或登录官网随借金页面办理,2月9号前办理有效。

以 1 万元日手续费 4 元来计算,转换成年化利率为 4 x 30天 x 12个月/10000 = 14.4%,作为一个信用超级良好的用户(从未还款逾期和套现),银行都会收如此之高的贷款利息,那些「收益率低于 14.4%」的 P2P 平台,又何愁没有市场,何来高风险一说呢?

我有个腾讯前同事现在在一家 P2P 平台公司做高管,大老板是腾讯财付通出来的产品总监,他们的模式是通过给在校大学生提供小额信用贷款,再将这些债权在其 P2P 平台上出售。

他们平台上「锁定期 12 个月」的 P2P 产品的年化收益是 12%,3 个月的是 8%,与上面提到的银行信用贷款利息相比低很多,所以违约与坏账率也远低于银行信贷产品(银行的坏账率有多高?可以看看这期财经郎眼节目《财经郎眼之银行业变局》)。

2)P2B 收益率 18% 属合理值

我还有个朋友,投资也很有一手,家里是开宾馆的。

头几年他家里承租了个火车站地铁口旁边的宾馆,那生意真是好得不得了。最高的时候一个月的收益有 5 - 7%,200 万的本金能有 10 到 15 万的月收益,对比平均年化收益 20% 的股神巴菲特,——不好意思,他早已哭晕在厕所。可惜后来房东眼红,把房子收回去转给了其他出价高的承租人。

由此可见,地段对于房地产来说有多么的重要,这一点我后面讲到「房地产投资」的时候再细说。

不过,现在他们家的宾馆在一所中学旁边,钟点房的生意也还算不错(你懂的),平均每个月下来 3% 左右的收益还是有的。

如果把我朋友的宾馆当做一个小微企业,我们投钱他开宾馆,利润五五分,——**人比较容易接受的比例,最终我们投资者能分到的收益大概是年化 3% x 12 x 50% = 18%

2015年度创业板492家上市公司预计实现平均净利润1.16亿元至1.36亿元,同比增长19.2%至39.2%。其中,299家公司净利润同向增长,占比61%;30家基本持平,10家扭亏为盈,131家同向下降,22家亏损。

中小板777家上市公司预计实现平均净利润1.85亿元至2.34亿元,较上年同期增长8.86%至37.88%,表明在宏观经济面临较大压力的背景下,中小板上市公司保持了一定的经济活力,整体实现了业绩稳定增长。其中,净利润同比增长的有307家,占比为 近40%,120家公司的净利润增长率超过30%,71家公司亏损。

—— 深圳证券交易所,《深交所创新型、成长型企业2015年业绩实现较快增长

从上述深交所 2015 年中小板、创业板上市公司业绩报告来看:好的小微企业保持年均 30% 的增长,不成问题。这也是为什么 A 股跌成狗的时候,创业板总能充当反弹急先锋。

请注意我的前提,——「好的」小微企业,在投资 P2B 标的的过程中,必须确认借款企业是「信用好、财务好、经营好」的三好企业,才可以放心大胆的投,这就要求 P2P 平台所提供的信息必须完全真实透明。

三、如何选择靠谱的 P2P 平台

第一,不要赔钱;第二,永远记住第一条。

—— 巴菲特的投资忠告

保守主义投资策略的第一原则是「不要赔钱」,P2P 投资也是一样。了解完「为什么会有 P2P」以及「什么是 P2P」之后,我们大概能够提炼出一个靠谱的 P2P 平台应该具备的几项特征。

注:以下观点主要由郎咸平教授在《三个条件认清 P2P》中总结而来。另外,我在学习投资的过程中,受郎教授和「财经郎眼」的启发颇多,特此给各位新人推荐一下。

1、三个条件认清 P2P

1)第三方托管

第二十八条 [客户资金保护] 网络借贷信息中介机构应当实行自身资金与出借人和借款人资金的隔离管理,选择符合条件的银行业金融机构作为出借人与借款人的资金存管机构。

——《网络借贷信息中介机构业务活动管理暂行办法(征求意见稿)》

「第三方托管」这几个字是郎教授的原话,但《意见稿》中提到的却是「资金存管」,二者的法律含义是不同的。但不论是存管还是托管,一定要选择那些「出借人与借款人的资金与 P2P 平台的银行账户隔离」的 「真 P2P」平台,这样才能有效防止「伪 P2P」平台的卷款跑路。

2)足额担保

借款人(或企业)必须提供有效的债权抵押物,如,土地、房产、汽车、股票、生产设备等,当借款人还款逾期或无力偿还时,P2P 平台的「第三方担保机构」可代为催款或拍卖借款人的抵押物,保证投资人的权益。

「真P2P」平台虽然不会跑路,但可能由于风控不到位,导致部分投资标的出现坏账。投资者应尽量选择那些「足额」担保的标的,这样就能在谁都不愿意看到的坏账发生后,最大限度的避免损失。

需要留意的是,现在几乎所有的 P2P 平台都宣称是「100% 本息保障」,投资者一定要确保所投项目的「第三方担保机构」与借款人、P2P 平台三方之间均无商事主体关系。这一点可以通过全国各地的「市场监督管理局」进行在线查询。

3)信息透明

你的钱谁借去了?用去干嘛了?什么时候还?这个月还了,下个月还有没能力还?还不起怎么办?一个靠谱的 P2P 平台必须确保这些信息的真实性,并承担好向出借人披露信息的责任。

第三十条 [融资信息披露及风险揭示] 网络借贷信息中介机构应当在其官方网站上向出借人充分披露以下信息:

(一)借款人基本信息,包括但不限于年收入、主要财产、主要债务、信用报告;

(二)融资项目基本信息,包括但不限于项目名称、类型、主要内容、地理位置、审批文件、还款来源、借款用途、借款金额、借款期限、还款方式及利率、信用评级或者信用评分、担保情况;

(三)风险评估及可能产生的风险结果;

(四)已撮合未到期融资项目有关信息,包括但不限于融资资金运用情况、借款人经营状况及财务状况、借款人还款能力变化情况等。

——《网络借贷信息中介机构业务活动管理暂行办法(征求意见稿)》

以下是我投资的某款年收益 18% 的 P2P 标的的信息披露截图:

透明的 P2P 信息披露

不过,如果真遇上「e 租宝」这种连合同契约(商业文明的基础)都敢伪造的骗子公司,那还真是没办法。

2、我的 P2P 平台选择思路

1月新上线平台数量为59家,新增问题平台88家。截至2016年1月底,累计问题平台达到1351家,P2P网贷行业累计平台数量达到3917家(含问题平台)。

——**P2P网贷行业2016年1月月报(第三部分)

在我看来,今年网贷行业监管细则出台之后,P2P 平台将会像 11 年团购行业的「千团大战」一样,步入一个并购与整合的发展期,大部分没有背景和实力的 P2P 平台都将被淘汰出局。

因此,除了以上提到的「第三方托管、足额担保、透明」三个条件外,我们还需要设定更为严格的筛选条件,以便从现有的 2000 多家平台中挑选最靠谱的那两三个。

1)陆金所的我不想再投

毋庸置疑,陆金所的网贷业务是所有 P2P 平台中相对最安全的,——有平安集团背书,但它的灵活性和利率十分不适合我这样激进型的投资者。

  • **灵活性太低。**因为陆金所大部分的网贷投资标的期限都是 1-3 年,虽然对于平台来说能降低风险,但对于投资者来说缺乏灵活性。我手头的两个「稳盈-安e」项目,转让多次都没有转让成功,最后只能放弃转让等三年期满。
  • **利率太低。**和其他 P2P 平台比起来,8.4% 的年化收益,基本可以排到所有 P2P 平台的倒数第一。不过,那些收益率高于 20% 的 P2P 平台我也一定不会去投,因为对借款人的负债过重,会提高违约的风险。「不要赔钱」永远是最重要的。

另外,我手头的两个「稳盈-安e」项目中,其中一个还发生了逾期,而其他投资过的四五家 P2P 平台都未出现过这种问题,不知道是我运气背还是陆金所的风控能力有问题。

2)只投资有信用背书的平台

「国资系、上市系、银行系、风投系」四大有背景的 P2P 平台中,我通常会选择投资「上市系」和「风投系」,因为国资系和银行系通常利率都和陆金所一样无法吸引我,而且平台体验做的比较糟糕。

上市系和风投系中,我只选择两类:

  • 所有 P2P 平台排名前 30 名,且有著名风投、上市公司或互联网大佬投资的平台;
  • 有信用靠谱得爆表的且懂 P2P 的朋友推荐的平台。

这里要特别推荐网贷之家的 P2P 数据与网贷档案栏目,它能有效的帮助 P2P 投资者全面了解所有 P2P 平台的基本面和运营状况。投资者可以在网贷之家论坛与 P2P 平台运营商以及其他投资者进行交流与提问,还可以通过某 P2P 平台的利率、成交量等数据走势评估短期风险。

网贷之家数据走势图

在以上筛选思路的基础上,我最终挑选了三家 P2P 平台,并将投资资金分成了 「443」三部分:40% 资金用于投资 6 -12 个月的项目(平均年化收益率 15% - 18% ),40% 资金用于投资 1-3 个月的投资项目(平均年化收益率 9% - 14% ),30% 资金用于投资半个月或随存随取的项目(平均年化收益率 6 - 8% )。

作为一个有操守的业余分析师,这篇文章中是不会推荐任何 P2P 平台的,但如果您的诚意高到愿意分享此文,并关注微信号「猫哥学前班」,且回复「p2p」,那么会出现一个没有操守的机器人,偷偷告诉你它已经买了很久的几款高收益率 P2P 产品……

温馨提示:「理财有风险,投资需谨慎」。猫哥学前班,教你把钱赚:)


本文是一篇「P2P 入门级」的投资指南,希望能加深各位投资新人对 P2P 的了解。从全球范围来看,**特色的 P2P 网贷投资具有风险低、收益高的特点,这是此轮普惠金融改革的红利。待国家逐渐完善投资和融资渠道后,相信网贷行业利率也会逐步降低,回归一个更合理的区间。

再过两三天就到农历春节了,猫哥提前祝大家猴年大吉!合家安康!!来年赚钱猴腮雷!!!

Visual Studio Code 配置指南

Visual Studio Code (简称 VS Code)是由微软研发的一款免费、开源的跨平台文本(代码)编辑器。在我看来它是「一款完美的编辑器」。

本文是有关 VS Code 的特性介绍与配置指南,相关设置主要针对 Mac OS X 平台。在快捷键部分, ⌘ 指 Command 键,⇧ 指 Shift 键,⌃ 指 Control 键,⌥ 指 Option/Alt 键。

1. Visual Studio Code 特性简介

1.1 Git 集成

VS Code Git 集成

如上图所示,VS Code 默认集成了 Git 版本管理。

切换至 Git 面板,点击左侧被修改的文件,即可进行版本对比。默认为左右窗口对比视图(Side by Side View),点击编辑器窗口右上方「…」图标可切换至行内对比视图(Inline View)。

鼠标移至 Git 面板中的文件列表上时,会出现「+」图标,点击后即可将文件添加至暂存区(Stage),点击右上方的「…」图标可以完成常用的 pull/commit 操作。

点击窗口左下角的 git 分支信息,即可快速切换至其他分支。

更多 Git 参考资料请阅读《Git 进阶指南》和 VS Code 官方文档《Version Control》章节。

1.2 多窗口实时编辑与预览

多窗口实时编辑与预览

VS Code 最多可同时开启三个子窗口。若多个子窗口中打开的文件为同一文件时,则修改其中任意窗口内容,其他窗口都可以实时同步变更。

如上图,左侧子窗口是一个 Markdown 文件,右侧子窗口是该文件的 Markdown 预览模式(快捷键 ⇧⌘V),如此即可实现类似 MacDown/Mou 等软件的编写体验。

1.3 代码提示与引用分析

虽然是一款轻量级编辑器,但 VS Code 却有着 IDE 级别的代码高亮、语法检测、引用分析功能,十分适合编程初学者和大型项目开发。在其官网上列出了它默认支持的语言列表。

图:VS Code 支持的编程语言种类

借助 Typings ,VS Code 还支持了 Node.js、ES6、AngularJS、ReactJS,十分适合前端开发人员。为了能更好的和其他开源框架融合,VS Code 有意削弱了原有的 JavaScript 语法校验功能,建议用户使用 ESLint 来定制个性化代码校验需求。

除此之外,VS Code 的 Debug 功能也是十分强大。以下是其 Node.js Debug 的演示:

图:VS Code Node.js Debugging

借助「Debugger for Chrome」插件,还可以直接在编辑器中打断点调试 web。

1.4 命令行调用

VS Code 提供了一个 code 命令,用来在 shell 环境下调用编辑器。使用快捷键 ⇧⌘P(或 F1) 唤起命令面板,输入以下命令即可完成安装。

图:安装 code 命令行

code 命令后可接多个路径或文件:

code pro6.js pro6.scss ../

文件对比:

code -d new-file.js old-file.js

打开文件并跳至指定行:

code -g source/cn/static/global/tracker.js:15

更多 code 命令行使用方法,参见《Additional Command line arguments》。

1.5 更聪明的 Emmet

VS Code 内置了 Emmet,且在其基础之上做了进一步增强,极大的提升了 CSS、HTML 编写效率。
例如,在一个 CSS 选择器中书写以下属性后,按下 tab 键,均可自动补全为 overflow:hidden

ov:h
ove:h
of:h

更多 Emmet 缩写,请参考《Emmet Cheat Sheet》。

2. 快捷键与插件配置

2.1 所有快捷键列表

注:VS Code 的快捷键有很多是 Fn 功能键,不符合 Mac 用户习惯,建议各位通过 Preferences -> Keyboard Shortcuts 重设快捷键。

所有快捷键列表请参见《Key Bindings for Visual Studio Code》,其中较为常用的快捷键有以下这些:

文本选择

  • ⌃⇧⌘→ - AST (Abstract Syntax Tree) 抽象语法树选择展开一级
  • ⌃⇧⌘← - 抽象语法树选择缩小一级
  • F2 - 重命名当前对象,或使用鼠标右键菜单
  • ⌘F2 - 重命名当前字符串(包含作为子字符串的情况),或使用鼠标右键菜单
  • ⌥→ - 以单词为单位向后移动光标
  • ⌥⇧→ - 以单词为单位向后选中文本

单行编辑

  • ⇧⌘K - 单行操作,删除光标所在行
  • ⇧⌥↓ - 复制光标所在行到下一行
  • ⌥↓ - 将光标所在行移至下一行

多行编辑

  • ⌥⌘↓ - 向下插入一个光标,或者使用 ⌥ + Click
  • ⇧⌥ + 鼠标拖动 - 多列区块选择,再配合 ⇧⌘→ 可选中至结尾处
  • ⇧⌘L - 选择相同文本
  • ⌘F2 - 选择相同单词,或者使用 ⌘D 依次加入选中

代码定位

  • ⇧⌘\ - 跳转至对应匹配括号处
  • ⇧⌘O - 跳转至对象、属性、方法
  • ⌃G - 跳转至指定行
  • ⌘↓ - 跳转至文件结尾
  • ⇧⌘M - 显示当前文件的错误与警告信息
  • F12 - 跳转至定义行
  • ⌥F12 - 浮窗打开定义行(可直接修改)
  • ⌥⌘ + Click - 新开侧边窗口跳转至定义行
  • ⇧⌘G - 选中上一次的查找结果

代码展示

  • ⌥Z - 开启/关闭代码自动换行,还可通过 editor.wrappingColumn 配置单行最大字符数
  • ⌥⌘[ - 代码折叠,⌘K ⌘0 为全部折叠
  • ⌥⌘] - 代码展开,⌘K ⌘J 为全部展开
  • ⇧⌥F - 代码格式化

窗口操作

  • ⌘1 ⌘2 ⌘3 - 切换至对应的子窗口
  • ⌃Tab - 切换当前子窗口的标签页
  • ⌃` - 打开内置 Terminal 窗口
  • ⌘⇧U - 打开/关闭 Output 窗口,可查看 Extensions/Git/Task 输出
  • ⌘0 - 焦点进入侧边栏项目目录,进入使用快捷键 J 向上、K 向下、H 折叠、L 打开
  • ⌘K E - 焦点进入侧边栏当前文件列表,进入后使用快捷键同上

2.2 插件推荐

3. 常见问题

3.1 如何支持 PHP Smarty Template 语法

VS Code 能识别大部分主流代码文件,当需要进行关联语法设置时,可通过 Preferences -> Workspace Settings (或 User Settings)配置文件进行设置。

例如,以下代码可以将后缀为 .tpl 的 Smarty 模板文件关联成 PHP 语法:

"files.associations":{
	"*.tpl": "php"	
}

3.2 如何在 sidebar 隐藏编译后文件

设置 Preferences -> Workspace Settings (或 User Settings)配置文件,将需要隐藏的文件按 glob 匹配模式进行配置,例如以下是 Angular2 TypeScript 项目中隐藏 .js 与 .js.map 文件的配置:

{
    "files.exclude": {
        "**/._*": true,
        "node_modules/": true,
        "app/*.js.map": true,
        "app/*.js": true
    }
}

3.3 如何搜索 node_modules 文件夹中的文件

VS Code 的默认搜索规则中会排除 **/.git, **/.DS_Store, **/bower_components, **/node_modules 目录,可以在用户配置文件(User Settings)中加入以下配置,来关闭或启用这些规则:

{
	"search.exclude": {
		"**/node_modules": false,
		"**/bower_components": true
	}
}

3.4 使用 VIM 插件有哪些注意事项?

如果你熟悉 VIM ,可以尝试 VIM for VS Code 插件。插件安装后,通过 Toggle VIM Mode 命令可以开启/关闭 VIM 模式。

  • 长按 hjkl 方向键无法响应的问题,解决方法终端运行

    defaults write com.microsoft.VSCode ApplePressAndHoldEnabled -bool false
    
  • 如何让 VIM yank 至剪切板的内容通过 ⌘V 粘贴出来,配置如下 setting:

    "vim.useSystemClipboard": true,
    
  • 系统默认的 ⌘D 向后删除键失效了。在 Keyboard Shortcuts 中清除掉 extension.vim_ctrl+d 的按键绑定即可

  • ctrl+f, ctrl+b 等方向键失效。在 settings 中增加以下配置,让这些快捷键不被 vim 插件复写

    "vim.handleKeys": {
        "<C-a>": false,
        "<C-e>": false,
        "<C-b>": false,
        "<C-f>": false
    },
    

阿里的月饼,技术的荒诞

既然你已经点进来了,那想必你也看到今天知乎上的这则神贴了:

😂 阿里昨天内部抢购月饼,剩的 100 盒。。有四个安全部的人利用漏洞刷单抢到了……结果被开除了……被开除了……开除了……开除……除……

来源:https://www.zhihu.com/question/50600301

其中一位当事人还匿名作了答:

作为事件的当事人,忍不住说几句,第一次经历这种事情也是有点懵逼。……
好吧,这是我经历过最快的离职,也许也是可以排进逗逼榜了。

在帖子评论中,一边是以宇宙最强王者「阿里 HR」为代表的非技术群体,另一边是以程序猿为代表的技术群体,两方爆发了激烈的冲突。

这个冲突在我看来,主要是各方对「编程技术」的一种认知偏差。使用技术抢购到底算不算「作弊」?程序员的价值观到底有没问题?阿里 HR 的做法是对是错?

我们从三个不同的角度一起来看下。

程序员的角度

这 HR 实在是 SB,用技术手段抢月饼就是违反了公司规定?哪条规定?是你们的 gui 腚吧!

双十一活动能抢到商品的,你以为真的是靠单身十八年练就的手速来抢的吗?

去年过年前你用火车票 App 抢回家车票的时候,我是不是应该报警抓你啊?因为你用技!术!手!段!抢!购!车票了啊!

用技术手段怎么了?和我请人帮忙是一样的道理啊,只不过这个人是我自己造的机器人啊!

这和我在公司群里发了个红包,吼一嗓子,让同事帮我抢盒月饼,是一样的道理啊!你们要不要把全公司的人都开除掉啊?因为我找人帮忙了啊!我不诚信啊!大家价值观有问题啊!!都要开除啊!!!

LZ 成天需求这么多,一大堆 BUG 要写,哪有你们这种闲功夫人!肉!抢!月!饼!

你们身为诺大一个互联网公司的 HR,没写过代码,还没听过 JS 刷单吗?这技术有那么牛逼?有那么不平衡吗?连打扫我工位的清洁阿姨都会写 NodeJS 了啊!是你们自己蠢,不愿意学点编程知识,还是我人品差、价值观有问题?

// 举例:以下 JS 代码可实现在按钮可点击时,迅速提交表单,浏览器按 F12 粘贴运行即可
var timer = setInterval(function () {
  var button = document.querySelector('button');
  if (!button.disabled) {
    button.click();
    clearInterval(timer);
  }
}); 

(注意:以上言论只为模拟一名情绪较为激昂的程序员口吻,不代表猫哥学前班观点!)

HR 的角度

(再次声明:以下内容纯属虚构,只为艺术创作需要。大家一起吃个瓜,不许打人!)

这位同学请不要激动,您不是当事人,且听我慢慢道来。

这次公司除了人手一份月饼之外,多出了 100 盒。本想秉着公平公正的原则,通过「抢购」活动的形式,作为员工福利发放给大家,但这 5 个自作聪明的程序员刷了 124 盒……

他们的行为导致其他同事无法正常参与活动,群众反响激烈,我们这么做也是为了维护公司范围的平等原则。

你们有没想过,公司一半的员工都是程序员,为什么只有他们 5 个人用技术手段去刷单?他们刷单是牛逼了,你让只会闷声作图的设计师怎么想?让只会提需求的产品策划怎么想?让只会催进度的项目经理怎么想?让我们这种什么都不会的 HR 怎么想??( HR 同学说话太谦虚了……)

知乎匿名答主我们能理解他,但制度就是制度,即使他没有主观恶意,即使他能够主动上报情况。但其他几个同事呢?如果他们有人刷了单还付了款,甚至还准备倒卖限量版月饼。面对这种行为,我们作为公司的执法部门,能坐视不管吗?

况且他们当事人也都承认了自己的过错,所以请大家不要做过多解读。

我们知道技术没有对错,但我们奉劝那些有能力使用技术的人,请在对的场合使用它!

月饼的角度

Life was like a box of chocolates, you never know what you’re gonna get.
生活就像是一盒月饼,你永远不知道等待你的将会是什么。

—— 改编自《阿甘正传》台词

作为一个月饼,我十分心疼答主 T_T

我怎么也想象不到,在这中秋佳节团圆之际,居然会有如此优秀的程序员,会因为我,而猝不及防地领了盒饭……

我相信今天发生在我身上的事情,将会在**互联网史上留下荒诞的一笔。

**所谓「抢购」,实质上是一种分配「有限资源」的活动形式,在未明文限定规则的基础之上,应当是「八仙过海各显神通」。**能用技术手段是一项本事,能发红包找同事朋友帮忙也是一项本事,在这一点上大家都是平等的。HR 同学不能因为我是职业 LOL 玩家,手速快到稳拿第一,就剥夺我参与活动的资格对吧?

如果认为这种资源分配方式不公平,那就不应该采用这种活动形式,Math.random() 随机分配就能很好地解决这个问题。

实话说,作为一个月饼,与其被一双双眼睛虎视眈眈,与其浪费大家时间守着电脑屏幕,我更希望 HR 同学能采取拍卖的形式,这样才能体现出我作为一个月饼应有的尊严!

最后我想说,我有一个梦想:

若干年后,人人都会编程,人人都会使用技术手段来抢购月饼。
如果那样的话,人们将会有更多的时间陪伴自己的家人和朋友。

而不需要像现在这样,看一个月饼的笑话……

RMB 玩家的金钱观

我有一个梦想,30 岁之前赚到人生的第一个 100 万,这个梦想我已经实现一半了,就是,——我已经 30 岁了。

故事的引言已经为本系列定下了悲情的基调,虽然我无法以一个成功者的上帝视角来指导大家实现「财务自由」,但我相信我这些失败的经验,对许多职场新人与投资新人来说,还是十分有借鉴意义的,况且在还未成功之时,来分享这些经验也不容易被人误解。

本文作为「猫哥学理财」系列的第一篇,将会从我的网游经历开始讲述所谓「正确的金钱观」,对游戏不感兴趣的同学可直接跳至文末结尾处。

何谓财务自由?

财务自由就是一个人(家庭)不靠工薪和他人施舍能维持既往的生活方式。要获得财务自由,你必须既不必工作又能有足够多的收入,而且这个收入不是来自他人(如馈赠或遗产),不是来自每月上班的薪水。

—— 刘军宁,《投资哲学》

我的游戏史

第一块金

如果不算小学生时期打弹珠、拍画片赢过的钱,以及替同桌写作业后请我吃雪糕的钱。我的第一「块」金(太少了,不能说「桶」),应该是和老弟一起玩「梦幻西游」赚来的。

拍画片

由于我和老弟不是富二代(爸,这个不怪你),所以生活十分节俭,表现在玩游戏上,那就是根正苗红的「非 RMB 玩家」。小时候接触红白机、小霸王比较早,所以也特别喜欢玩电子游戏。

我街机玩的不错,经常一个游戏币能玩一下午(大部分游戏通关之后还能继续玩,例如小飞侠、名将、三国志、越南战争等等)。记得小学五年级有一次,为了省一块钱的过早钱留着打街机,我没吃早饭,中午还在同学家饿着肚子玩「街头霸王」,到下午两点钟才准备回家吃午饭。结果回家路上饿得头晕眼花,最后迷迷糊糊地趴在地上爬到家。

所以现在看到新闻说有人沉迷电脑游戏,玩到猝死的,我是丝毫不怀疑其真实性。

讲到这里,可能有人想提醒我是不是偏题了猫哥?没有。我铺垫这么多是想说:我不但游戏「玩的好」,而且我还能「不要命」地玩。

当一件事情你比别人擅长,而且还能专注地投入其中,那就一定能从中赚到钱。

事情是这样的,那是 2005 年的暑假,我老弟刚参加完高考,就跑到我的大学宿舍说梦幻西游开新区了,要去冲新区,混个首席弟子玩玩。

结果事情进展的很顺利,我们兄弟二人轮番上阵,每人轮班「工作」12小时,再加上寝室损友们的大力支持(帮带盒饭、泡面),顺利的当上了新区服务器第一任大唐首席弟子,全服排名前二十!

当你有了实力(等级高)又有了名声(首席称谓)之后,来钱就很容易。

后来凭借此号帮人过剧情怪、刷宝图,前前后后也赚了几十张网易点卡,还换来了两个七位数的 QQ 号。可惜老弟后来就走上了这条不归路,经常无聊到刷一天的宝图来赚钱。

当时梦幻西游这游戏除了普通的交易系统以外,还有很先进的商会系统。做师门任务时,经常就是,「徒儿,为师有点寂寞,去给俺弄个花妖来耍耍」,然后你要么花上十几二十分钟亲自去大雁塔五层慢慢抓花妖,要么一个飞行旗去商会的宠物店花 8000 钱买一只回来。

再后来,我就花钱收购了一家宠物店,专卖花妖宝宝。我用这些赚来的梦幻币兑换成网易点卡,在淘宝上换来了个六位数的 QQ 号,一直用到现在。

我这种赚钱的方式,虽然比老弟打宝图赚钱来得快,但还是体力劳动。区别在于我是「开个门面」,老弟是「摆摊」,好在游戏里没有城管收保护费,所以都没什么风险。

后来我意识到,真正赚钱快的是那些「投机倒把」的商人。例如,我朋友雷黑子十分关注全服的房屋交易信息,有一次他用 300 多万收购了一套「紫气东来」的房子,——品质最高的房屋,属「稀缺资源」,再以 700 多万转手,收益率 130% 。更不用说那些「垄断」了全区金刚石、定魂珠(超级宝图兑换材料「必需品」)的那些实力玩家,在投入大笔资金买断某种特殊材料之后,直接拥有了物品定价权。

好在网易的数值系统及时地发现了这些问题,通过临时提高被垄断物品的副本掉落概率(改变「供求关系」),稳定住了整个游戏金融市场,那些「金融大亨」也因为「政策」的改变,而亏得血本无归。

做一名 RMB 玩家

虽然从游戏的交易系统中我观察和学习到了不少经济学现象,然而最大的收获,却是在我「堕落」成一名 RMB (人民币)玩家之后。

2010 年暑假那段时间,我辞了工作,在家玩「天下2」。那种 3D RPG 网游(类似魔兽世界)的代入感很强,我经常玩到天昏地暗,沉迷其中不可自拔,结果女朋友也弃我而去。

当时我是全服第二大势力(公会)的长老级人物,经常组织违反治安管理处罚条例的事情,参与打架斗殴更是家常便饭。

说起约架,没一把趁手的菜刀怎么行?

一把趁手的菜刀

通常一场架最终是输是赢,从一开始的阵容就能猜的出来。在「天下2」的世界里,「红翅膀」多的一方获胜。

「红翅膀」是什么?简单来说就是 RMB 玩家。

装备的强弱与装备等级、成色和加护值有关。等级和成色,一般花时间刷副本都能拿到合适的,加护值则需要用大量真金白银才能给装备强化上。玩家身上共 18 件装备,每件装备都可以加护 18 级,每次打强化石可能加护成功或者失败,已强化的钻石越多失败概率越大,每次失败还会让加护值减 1。其中,1 至 4 级使用「日钻」强化,5 至 8 级使用「月钻」, 9 至 18 级使用「雷钻」。三种钻当时的游戏币价格折合人民币大概是,¥1、¥15、¥85 。当全身加钻数量超过 234 个时,就会出现一个「红色的翅膀」。

为了这种虚荣感,为了给势力撑门面,我也是愤然投身「RMB 玩家」之列,成为全服魍魉门派前三。同时,由于我手持天域武器,在上线游戏时系统还会在世界频道通告:「出没无常」携「天诛地灭」登陆大荒。

那种「荣耀 X5」感,无以言表……

晒张图,给各位感受下我的淫威。噢,补充说明一下,虽然那段时间我变性了,不过我始终是以直男身份本色出演,很多 90 后妹纸可以作证。

红烧出没无常

在我连任门派首席大弟子十多次后,终于有玩家私聊我希望能给新人一点机会……

以下是支付宝交易记录截图:

网易点卡交易记录

我充其量只能算一个入门级 RMB 玩家,当时全服第一玩家(煤老板)全身 18 钻,花了人民币大概 200 到 300 万。

……大家感受一下……

这段游戏经历有趣而又深刻,我个人的价值观也受到了「拜金主义」的洗礼。

正确的金钱观

1. 钱是「万能」的

法国现代小说之父巴尔扎克曾说:「每笔财富背后,都隐藏着罪恶」,教科书中也不只一次提到:「金钱是万恶之源」,「资本家为了追逐利润,压榨工人」。数千年来的**文化中,存在着一种畸形的金钱观,一方面广大人民群众「仇富排富」,认为「无商不奸」;另一方面,朋友圈炫富,跪舔「马云爸爸」、「思聪老公」的人也是比比皆是。

那段游戏经历让我深深体会到了有钱与没钱的巨大悬殊,包括精神层面与肉体层面……是选择带着一群狗腿子调戏良家妇女,还是选择被人杀得像落水狗一样亡命天涯?

那些说金钱买不来幸福的人,估计和我一样还没有实现「财务自由」。金钱虽然买不来友情、亲情,但能买来许多生活必需品,衣服、食物、房子、车子。没有这些,生活会很不方便,甚至会很不幸福。如果自己或者家人再生一场大病,这辈子还有什么盼头?

建议金钱观不正的同学读一读刘军宁的《投资哲学》,它会告诉你:金钱是道德的,财富是思考的产物;金钱是自由的保障,财务自由是幸福的源泉。

2. 「自卑」是最大的动力

个体心理学创始人阿德勒认为,人生来就是有缺陷的,有缺陷(包括身体缺陷)就会产生自卑。自卑一方面能摧毁一个人,使人自暴自弃甚至成为精神病患者;另一方面它也能使人发愤图强、超越自己,以此来填补自身的缺陷。

这么多年了,我还在做通讯工具,这让我相信一个宿命,每一个不善沟通的孩子都有强大的帮助别人沟通的内在力量。

—— 微信之父,张小龙

从张小龙的演讲视频能看出,他和大多数程序员一样不善言辞,但他所创造的微信却是全**最伟大的沟通工具,每天帮助超过 5.7 亿人相互交流。

装备不够耀眼(长得丑)、技术又不厉害(无一技之长),所以我自卑,所以我要更努力地刷副本(赚钱)。

自卑是人性中最原始的力量,要让它成为我们成长的动力,而非阻力。

3. 理财需要靠系统的学习

仅靠简单的「开源」、「节流」是永远无法实现「财务自由」的,金钱是一种工具,如何让工具发挥其最大效用,——而不是放在银行卡和钱包里躺着,才是实现财务自由的关键。

财务自由的标志是被动的收入大于主动的收入。

争取财务自由,就是从无到有、不断增加被动的收入。被动的收入通常来自股票(份)、债券、基金等金融工具以及土地、房产、版权等。争取财务自由的过程就是主动地制造被动收入、把主动收入的结余通过正确的投资转化为被动收入的过程。

—— 刘军宁,《投资哲学》

我从玩网游的经历中开始学习「投机」和「经商」,知名理财畅销书《富爸爸,穷爸爸》中也推荐了一款「现金流游戏」来辅助学习理财知识。

如何在老鼠赛跑中胜出

有个朋友曾经跟我分享过他的第一桶金。08 年村子里下大雪,他在去外婆家的路上看到很多电线杆倒了,线也断了,想到山沟沟里交通不方便,但住户又很多,晚上没电肯定不行。于是,他赶紧跑到县城批发了 2 万根蜡烛,并且以 0.5 元/每根 的价格收购了其他商铺里的所有蜡烛。果然那些天也是大面积停电,村民跑遍全村只有他那里有蜡烛卖,最后他以 2 元/每根 大量倒卖,赚到了自己的第一桶金。

还有个年纪与我相仿的朋友,他在 10 年暑假赚到了第一桶金。他先是在网上看到有温州皮鞋厂的老板在甩一批尾货,在看到样品质量不错之后便全都订下了这批货,约定了 30 天的交款期。结果不到一个星期就全部转售给了非洲的买家,就这样「空手套白狼」赚了 10 万。那一年,我的银行存款却是 -2000 元……

他们这些经历,看似简单,实则不易。这需要从小耳濡目染,学习经商之道,才能发现并把握住赚钱的机会。

对于大部分和我一样非「资本家」出身的普通工薪阶层,则需要更主动地学习、实践理财与投资知识,才有那么一点点可能「在 30 岁之前实现财务自由」。

从下一章开始,我将会分享近些年我在股市、房地产、P2P、基金等金融工具中的实践经验,供各位对理财感兴趣的同学参考。如有需要,敬请关注我的微信公众号「猫哥学前班」。

我敢保证,当大家看到我从股市 5178 点摔到 3373 点的痛苦经历,一定会很开心。

学英语和写工具

「学英语」的重要性已不言自明,「写工具」则是新人从小鲜肉成长为老师傅的捷径。本文在推荐一些优秀的 Mac 词典软件的同时,也会告诉新人如何打造一款属于自己的个性化软件和工具。如果你是一名 Windows 用户,可直接跳至「Windows 效率工具」章节。

Mac 词典软件推荐

Mac 系统默认配有 Dictionary 词典软件,你可以在任意应用程序中直接选中英文单词,按下快捷键 command + ctrl + d 后,在弹出层中查看相关翻译内容。

Mac 默认 Dictionary 应用程序

并且它还内置了牛津英汉汉英、现代汉语等官方规范词典,以及大量其他语言词典,只需要在其 Preferences 中配置启用、设置顺序即可。

Dictionary Preferences

但由于 Dictionary 属于内置离线词典,很多新的网络流行用语和专业词汇无法实时收录其中,因此我们还需要一个能支持在线搜索的词典。「有道词典」与「欧路词典」是两个不错的选择。

可以说在界面外观、搜索准确度上,两款词典都是词典类软件的标杆,并且在跨终端方面,都提供有 Web / Windows / Mac / iOS / Android 等平台版本,十分方便。

更难得的是他们都提供了「单词本云同步」功能,我们可以在电脑端将不熟悉的单词加入单词本(生词本),然后在手机端进行温习和巩固

特性 系统 Dictionary 欧路词典 Mac 版 有道词典 Mac 版
在线搜索
屏幕取词 ☆☆☆ ★★☆ ★☆☆
划词搜索 ★★★ ★★★ ★☆☆
单词本同步
价格 免费 ¥98.00 免费

「屏幕取词」在 Mac 上的性能都不是很好,欧路词典在部分软件中存在取词定位不准、偶尔无响应的问题,有道词典更是完全没有成功使用过,不过这个功能使用场景很少比较鸡肋,不要也罢。「划词搜索」方面,Dictionary 和欧路比有道的体验好很多,但由于快捷键设置的原因,操作效率都不高。

如果不考虑价格因素,Mac 版欧路词典几乎可以说是最好的选择了,然而我想说的更好用的词典软件并不是它。

因为,更好用的软件一定是「免费的、好看的、功能稳定的、占用资源少的、操作效率高的、能够个性化订制的」。两款功能相似的软件,一旦其中一款在以上一项或几项中超过了另外一个软件时,那么它将成为「更好用的软件」。

自定义 Alfred Workflows

接下来我要介绍的这款词典软件,其实是一款基于 Alfred 的 Workflows 插件工具。为什么说它是「Mac 下更好用的词典软件」?因为它是猫哥根据自己的需求定制的,它包含以下特点:

  • 免费
  • 查词准确(使用了「有道在线翻译 API」)
  • 操作效率极高(Alfred 全局快捷键与搜索框)
  • 有道单词本在线同步

接下来,我们来看下它的使用流程。插件的下载地址与具体使用方法,请查看我的 Github :https://github.com/kaiye/workflows-youdao/

1、双击选中任意应用程序中的文本,按两下 command 键,Alfred 搜索框会自动开启并进行翻译。选中需要的释义项,按下 enter 键,相关的单词、音标和释义会自动同步至有道在线单词本。

Alfred Dict

2、若未配置有道帐号信息,则会保存在本地的单词本 XML 文件中。使用 Windows 版有道词典的导入功能,可以将该文件补充导入至有道单词本。

Import Dict

3、在手机上温习新单词。一般每天睡前温习一下即可,需要英语考级的同学可以参考「艾宾浩斯遗忘曲线」制定更科学的复习计划。

有道词典手机版

接下来详细介绍一下 Alfred 和其他常用的效率工具开发方法,供大家参考。

Alfred 插件开发

Alfred 是一款类似 Spotlight 的文件搜索和 Web 搜索的软件。

Alfred 文件搜索

它最强大的地方在于,可以设置任意全局快捷键、运行任意应用程序和 Shell 脚本,通过简单的设置来实现复杂的自动化操作。它被称为 Mac 下的「神兵利器」,即便是毫无编程基础的同学,也可以自己动手快速实现一款插件来满足自己的个性化需求。

leIP 插件

由于操作太过简单,Alfred 官方甚至都没有提供详细的入门指南和工具类,基本上记住以下两条知识点即可开始自己动手编程了。

Workflows 工作流

  1. 常用功能可以直接基于 Examples 和 Templates 创建出来。例如当我们需要制作一个插件,以实现「使用全局快捷键来显示/隐藏一个应用程序」的功能时,可以参考上图所示的模板;
  2. Workflows 工作原理类似 Linux 管道命令。前一模块的标准输出会自动作为后一模块的参数输入,使用 {query} 即可引用。模块与模块之间的管道通过 GUI 拖拽操作可视化生成。

更多 Alfred Workflows 推荐,请参看「猫哥学前班」前几期的《全新 Mac 安装指南(编程篇)》。插件开发入门指南可以参看 Dean Jackson 的「Alfred Workflow 指南」(指南是英文的,不熟悉的同学可以用到前文提到工具),以及他提供的 Python 工具类,PHP 同学则可以用 David Ferguson 的 PHP 工具类

Windows 效率工具

Windows 下如果需要实现 Alfred 这样的文件搜索、快捷键定义、自动化脚本编写的工作流,需要借助以下三款效率工具。

  • Everything 。Windows 下最强大的搜索利器,搜索速度与体验好过系统默认搜索功能一个数量级;
  • AutoHotKey 。可以说 AHK 是 Windows 下的「神兵利器」,其自动化与自定义脚本功能与 Alfred 一样强大;
  • Win+R。win+r 是 Windows 系统 运行 对话框的快捷键,它是 Windows 下最绿色最高效的效率工具

以上三款工具,均是我多年前从「善用佳软」学习而来,xbeta 是国内 Windows 「效率工具」方面的顶尖高手和最佳启蒙老师,强烈推荐给 Windows 新人。

不过,如果你是一名新手程序员,建议还是尽早使用 Mac 或者 Ubuntu 操作系统。如果你是一名游戏爱好者,还可以学一下「按键精灵」,自己编写的(合法)外挂程序,能让你在游戏中获得更大的 Imba 感和成就感:)

跨平台插件开发

从趋势上来看,基于 HTML5 API 和 Node.js 的跨平台插件开发是未来的主流方向。

  • Chrome App 。从 Github 上下载一些 chrome app sample 示例,简单浏览一下教程(墙内的墙外的)和官方 API 文档 ,不出半天时间就能开发出一款插件。
  • npm 命令行工具。npm 模块除了在 node 环境下作为依赖模块被引用以外,还可以直接作为命令行工具使用。通过 package.json bin 字段定义,在全局安装时即可自动注册为全局命令行。例如,这款用于生成字体的 makefont 命令行模块。
  • NW.js 。将 webkit 和 node 集成打包使用的跨平台方案。当前 Mac 版的「夺命追魂钉」用的就是这个方案。node + webkit 方案最终将会取代 Adobe AIR ,这是 HTML5 对 Flash 的胜利。
  • Electron 。微软新出的 Visual Studio Code 编辑器和 Github 的 Atom 编辑器使用的内核引擎,与 NW.js 的区别参看这里

我常常对新人说:「当一件事情重复做了三次,那么一定要想办法将它工具化以提升效率。」概括起来就是 DRY(Don't Repeat Yourself )和 DIY(Do It Yourself )。

「写工具」能同时提升我们的产品设计能力和开发编程能力。因为,当我们同时作为工具的制造者和使用者时(我们便从猴子进化成了人类),我们能够真正「站在用户的角度」去思考需求、设计产品;在进行工具插件的编写的同时,我们可以尝试不同的编程语言和设计模式,以提升自己的编程视野。

对于程序员来说,这是一个非常好的全栈实践之路。

猜猜我今年炒股亏了几千万

今天是 2018 年的最后一个工作日,应个别同学的强烈要求,这几天整理了下自己的股票投资心得,给「猫哥学理财系列」填个坑。

我手头的股票有三类,一类是前东家给的还未行权的经济收益权(类似股票期权),只有前东家顺利上市后,才能兑换成上市流通的股票;第二类是前东家给的 RSU(已上市的限制性股份单位),这部分主要在港股和美股;第三类是我在国内 A 股市场购买的股票和股票分级基金,A 股操作简单,且正处于历史低位,推荐还未入市的同学尽早开户实践。

先贴出我 A 股账户近四年的实盘收益数据,持仓资金 1000 万以下,5000 元以上…

持仓收益率

从上图可以看出,我的股票入门期很短,大部分时段都能跑赢大盘,最高收益接近 100%。

这得益于股神 《巴菲特与索罗斯的投资习惯》,以及三位神秘股票大佬的亲自传授。接下来我会分为三个故事,把这些股票投资经验连载在我的公众号「猫哥学前班」,欢迎订阅。需要说明的是

  • 投资有风险,入市需谨慎。文中提到的股票代码,猫哥当前并未持仓,不作为推荐股票,更无内幕交易;
  • 本故事基于个人经历改编,但为了创作需要,数据和情节已进行艺术加工,请勿信以为真,找我借钱。

这三位神秘的股票大佬,首先登场的是「大户 Y 姐」,另外两位我将在下一期介绍,他们是「技术流 S 哥」和「基金公司大佬 D 总」。

大户

大户是指那些资金实力雄厚、投资额巨大、交易量惊人、能够左右行情控制市况的投资者。

大户 Y 姐是我的同学,有一个词用在她身上十分贴切,那就是——「白富美」。

Y 姐的老爸是某大银行的(大)行长,她从小就耳濡目染投资学问,现在是国内某知名保险公司的高管,金融人脉甚广。

07 年那轮牛市,我还在读大学,靠自己的编程手艺,每个月能赚 500 块零花钱;而她,拿着 10w 的零花钱,在股市里赚了 20w。

15 年 4 月,我跟随炒股(韭菜)大军正式投身股市。在兴奋地往证券账户里存入 5w 初始资金后,面对一排排红红绿绿的股票代码,却不知如何下手。

我想到了 Y 姐,于是在微信上给她发了条信息:「最近有没什么股票推荐?」

她的回复简单、有力、专业、纯粹:「600662,15.10 入,17.40 出」

我喜欢。

那段时间,她每天 9 点前会给我同步一份早报。说是来自某大户内幕交流群,群主来头不小,号称**某部委的内部人士。早报的内容通常分为三段,第一段是今日大盘走势预测,第二段是即将出台的国家和行业政策,第三段则是荐股名单。

就这样,我跟着大户 Y 姐吃过不少涨停板,没多久账户浮盈超过本金。为了早日实现暴发户的梦想,我又追加了不少子弹。

但好日子没过多久,就迎来了我的梦醒时分:公元 2015 年 6 月 5 日,上午 11 点 11 分 18 秒。

我听从 Y 姐推荐,以 20.86 买入了 68 手(1 手 = 100 股,A 股最低交易单位) 603366,准备继续吃它几个涨停板。

股灾前的大户陷阱

然而,从买入开始,股价非但没有起飞,反而逐步下行翻绿,并在接下来的几个交易日开始大幅下挫。眼看着账户浮盈从 5w 开始逐步趋近于 0,我不禁开始慌乱起来。吃饭没有了胃口,上班没有了心思,睡觉也没有了甜蜜蜜。

Y 姐告诉我,「这股原本有 5 个大户股东,群里约好一起拉涨停,但其中最大的庄家却突然反向操作,借高位出货,她也上当受骗了。那位最大的庄家认为大盘已经见顶,所以提前出货离场。」

故事的结局是,在我买入一周后的 6 月 12 日,上证迎来了 5178 点的历史高峰,我虽躲过了第一波大跌,但在 4800 、4200、3600 反复加仓抄底,最终浮亏 36.9% 割肉离场。

这段炒股经历,教会了我两条宝贵的经验。

牛市期,要听「内幕消息」

作为一名成年人,当然要知道投资有风险,找人荐股,后果自负的道理。但问题是,买哪一只股,什么价格买,对于新手真的很难抉择。《大时代》中,股神叶天曾教过方展博:

股票不是投资,也不是投机,股票是人的游戏,所以它千变万化,但也有迹可循。

(视频播放地址:https://v.qq.com/x/page/e0502zoxqak.html

股神巴菲特那句「别人恐惧时我贪婪,别人贪婪时我恐惧」,也道出了股票中所包含的「人性的弱点」。

在大牛市行情中,筹码低位集中,大家账面都是浮盈,场外观望的资金按耐不住逐渐入场,于是僧多粥少,股民开始惜售股票,促使股价逐步走高,账面浮盈激增,市场上贪婪的情绪越来越重,又进一步刺激场外资金入场形成正向循环。

这是股民的狂欢,即使人人心知肚明,击鼓传花一定会有终点,但自己绝不会是最后那个接盘的**。

所以这时候,跟着各类似是而非、道听途说的「内幕消息」,买题材股、买 ST 垃圾股、买主力高度控盘的妖股,会比买大盘蓝筹股、低市盈率绩优股来钱快得多。

现在价格 2.49 的乐视网在 15 年股灾前曾涨到过 179 块(不复权),市场的疯狂程度可见一斑。

「危」、「机」均源自暴跌

面对千股跌停、三次熔断、国家队(证金公司、社保基金)屡次出手带领大小机构为国护盘,结果依然全军覆没。

A 股简明攻略

在经历过多次满仓跌停后,我明白一个道理:面对真正的大崩溃,任何人都无法阻挡趋势,市场上没有赢家。但,暴跌中一定蕴藏着巨大的投机和投资机会。

这里面最大的难点在于,当我们走入历史时间线暴跌的那一天,如何识别今日的暴跌是危险还是机遇,是牛市的起点还是新一轮暴跌行情的起点?

2016 年 6 月 24 日英国脱欧公投,引发了第二天 A 股的暴跌。我注意到这是一个深 V,一条长长的下引线。同年 11 月 9 日中午美国大选,特朗普当选新任美国总统,上证当日又走出一个深 V,一条长长的下引线。

虽然我预测到了美国大选对股市的影响,但当时面对指数的快速下探,我脑海里浮现的是 5178 的大崩溃,根本不敢下单抄底。

长下引线筑底信号

但 2017 年 1 月 16 日的暴跌「长下引线」被我再次注意到,我预测牛市筑底成功,所以在 17 日开始逐步建仓,收获了 17 年整年的小牛行情,也就是本文开头收益率图中的顶峰。

总结一下暴跌行情的具体操作技巧,仅供参考:

  1. 暴跌当天的 14: 50 前所有时段,不论当前持股还是持币,都不做任何操作;
  2. 如果当天大盘指数走出深 V 的长下引线形态,持股者无需操作,持币者在 14:55 - 14:57 之间,下单买入。这里之所以选择 14:57,是因为收盘前最后 3 分钟是「集合竞价」时间,无法确保是否成交。若当天没有成交,也可以选择在第二天尾盘建仓入场;
  3. 如果当天没有走出深 V,而是单边下行,持币者切勿抄底。持股者则切勿装死,可选择斩半仓或清仓,或等待接下来三个交易日内的反弹小高点出逃;
  4. 接下来的几个交易日,持股者需尽可能利用反弹浪,完成高抛低吸的波段操作;而持币者需要耐心等待,等待反弹完成,再等待第二次暴跌完成,再抄底入场,而且抄底仓位不宜过重。

为什么通常暴跌后会出现反弹和第二次暴跌?

这里需要引入一个概念叫做「艾略特波浪理论」,属于炒股技术流派的范畴,我在下一期的「猫哥学理财系列」中再详细分享「技术流 S 哥」教会我的一些经验,感谢阅读和关注。

最后祝大家元旦快乐,2019 年的 flag 都能实现!

H5 游戏开发 2:搭建 Egret 开发环境

搭建 Egret 开发环境

来源:猫哥学前班

微信公众号平台

在上一期的“H5 游戏开发”教程中,猫哥介绍了如何通过 Whistle 工具对 Egret 文档进行资源修复和搜索增强。本期,我们以 Hello World 项目为例,看看如何搭建一个好用的 Egret 项目开发环境。

1. 使用 Egret Launcher 创建项目

游戏开发是一个复杂的工程,它涉及到代码、UI 界面和动效三者的结合。Egret 官方为开发者和设计师提供了丰富的系列工具产品,帮助提升游戏开发体验和效率。

我们可以通过 Egret 官网下载最新版 Egret Engine Launcher 客户端,再通过 Launcher 来安装 Egret 引擎和工具链。

Egret Launcher

  • DragonBones:用于编辑龙骨动画(类似 Flash 的关键帧补间动画)
  • Egret Feather:粒子效果编辑器
  • Res Depot:资源管理器,用于对游戏资源进行定义、分组,编辑九宫格图片
  • Texture Merger:图集打包工具,可生成关键帧动画资源(Movie Clip)、图集(Sprite Sheet)、位图字体(Bitmap Font)
  • Egret Inspector:Egret Chrome 扩展工具,用于开发调试
  • Egret Wing:Egret IDE

除此之外,Launcher 还提供了 GUI 界面的项目创建和发布功能。

你可以先通过 Egret Launcher 安装一个最新稳定版的 Engines,然后参考官方文档或自行摸索,创建一个 HelloWorld 项目,并使用 Egret Wing 将其打开。

2. 使用 VSCode 代替 Egret Wing

打开 Egret Wing 后,你会发现它的界面和 VSCode 十分相似,事实上 Wing 是在 VSCode 基础之上定制而来。除了 VSCode 的代码编辑功能以外,Wing 还默认集成了游戏预览和发布的快捷工具栏,以及简化版的 Res Depot 资源管理功能。

然而,由于 Egret 团队当前的工作重心在于集美术场景界面编辑和程序开发为一体的 Egret Pro IDE 上(类似 Cocos Creator),所以 Egret Wing(以及即将废弃的 Egret UI Editor)已经相当长时间未得到更新。

这里,我们可以直接使用 VSCode 来代替 Egret Wing 作为游戏开发的 IDE,以便提升开发体验。

2.1 命令行自动编译

使用 VSCode 打开项目目录后,借助 Egret 命令行我们可以方便的实现项目的自动编译。打开 VSCode Terminal 面板(快捷键 Ctrl `),运行以下命令,可以在本地启动一个 Egret HTTP Server 服务:

egret run -a

其中,a 参数代表监听到文件变化后自动编译 autoCompile。服务启动后,会自动使用浏览器打开项目的局域网 IP 预览地址(你也可以选择使用本地 IP http://127.0.0.1:3000/index.html 来访问)。

补充:使用 port 参数能改变项目的监听端口(默认为 3000),使用serverOnly 参数能禁用打开 Chrome 浏览器的默认行为。如:

egret run -a -port 3333 -serverOnly

2.2 VSCode Chrome Debugger

在 Chrome 浏览器中,虽然我们可以直接通过 Sources 面板来对 JS 文件进行断点调试,但实际上使用 VSCode 的 Debug 面板,体验会更好。

首先,我们在 VSCode 中安装一个 Debugger for Chrome 扩展。安装完成后,运行 Start Debugging(快捷键 F5),VSCode 会在项目根目录的 .vscode 目录中自动创建一个 launch.json 配置文件。其默认内容如下

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "chrome",
            "request": "launch",
            "name": "Launch Chrome against localhost",
            "url": "http://localhost:8080",
            "webRoot": "${workspaceFolder}"
        }
    ]
}

我们只需要将上面的 url 属性值替换成 2.1 中提到的本地预览地址 http://127.0.0.1:3000/index.html 即可。

Egret 和大部分的 H5 游戏引擎类似,默认使用 TypeScript,所以我们还需要确保项目生成了 SourceMap,能将浏览器中运行的 JavaScript 和编辑器中的 TypeScript 关联起来。

所以,我们需要修改项目根目录的 tsconfig.json 文件,在 CompilerOptions 中加入 SourceMap 的配置。

示例如下:

{
    "compilerOptions": {
    
        "target": "es5",
        "outDir": "bin-debug",
        "experimentalDecorators": true,
        "lib": [
            "es5",
            "dom",
            "es2015.promise"
        ],
        "types": [],
        "sourceMap": true
    },
    "include": [
        "src",
        "libs"
    ]
}

注:修改了 tsconfig.json 文件后,本地的 Egret HTTP Server 服务会自动终止,需要重新执行 egret run -a 来启动。

VSCode Debugging

最终,如上图所示,我们实现了 Egret 项目的 VSCode Debugging 功能,它比 Egret Wing 的体验更好。

在实际的游戏开发过程中,Debugging 断点调试用的不多。更多时候,我们需要确认游戏 UI 元素的层级和布局渲染是否正确。这就需要用到 Egret Inspecter Chrome 扩展。

3. Egret Inspector Chrome 扩展

由于 H5 游戏界面都是渲染在 Canvas 画布中,因此仅使用 Chrome DevTools 默认的 Elements Inspect 功能只能看到一个孤零零的 Canvas 节点,而无法看到所有 UI 层级细节。

Egret 官方提供了一个 Chrome 扩展,安装完成后,我们能通过 Chrome DevTools Egret 面板查看到具体的元素层级和布局信息。

3.1 安装 Egret Inspector

我们只能使用 Chrome 开发者模式手动安装 Egret Inspector 扩展:

  1. 使用 Egret Launcher 下载 Egret Inspector 插件,下载完成后打开目录;
  2. 将插件 zip 包解压缩,选中名字为 EgretInspector-install 的子目录;
  3. 打开 Chrome 浏览器的扩展程序管理界面,将右上角的“开发者模式“开关打开;
  4. 将 EgretInspector-install 目录拖入至 Chrome 浏览器,完成安装。

Egret Inspector

最终效果如上图所示。在使用时,需要注意两个问题:

  1. Egret 虚拟画布节点通常不会自动刷新,需要手动点击“选中点击对象”后的刷新按钮来强制刷新;
  2. 控制台偶尔会报错 Uncaught TypeError: this.addChild is not a function

这是 Egret Inspector 插件的一个 Bug。插件依赖页面中的 Egret 引擎,当它在加载时,游戏页面中的 Egret 引擎可能还未完全加载,所以调用 this.addChild 方法导致报错。

3.2 解决 this.addChild is not a function 报错

前文提到过 Egret 官方团队工作重心已放在新架构的设计上,很多引擎和工具链上的问题,需要开发者自己动手解决。好在 Egret 源码开放,问题分析和解决起来并不复杂。

我们找到上文提到的 EgretInspector-install 目录中的 contentScripts.min.js 文件,将压缩后的代码进行格式化还原。再将还原后的 313 - 320 行代码进行替换,原代码:

        if (EGRETRELEASE) {
          n = ["injectScripts.min.js"];
        }
        e.addScript(n);
        window.setTimeout(function() {
          t.startInspectIfDevToolOpen();
        }, 200);

替换后代码:

        if (EGRETRELEASE) {
          n = ["injectScripts.min.js"];
        }
        
        window.setTimeout(function() {
          e.addScript(n);
          t.startInspectIfDevToolOpen();
        }, 500);

接下来,我们通过 Chrome 扩展程序管理界面将该插件重新加载更新、关闭/开启,以确保修改已经生效。

最后,我们重新关闭/打开 Chrome DevTools Egret 面板,问题得到修复。

4. Egret Live Reload 配置

在进行 Web 项目开发时,很多时候我们需要一边编写代码,一边刷新预览页面的呈现效果,H5 游戏开发也不例外。借助 Whistle Live Reload 插件,我们能很容易的实现这个功能。

4.1 安装 Whistle & Live Reload

# 全局安装 whistle 及其 live reload 插件
npm i -g whistle whistle.livereload
# 启动 whistle 服务
w2 restart

服务启动后,我们可以使用以下任意一种方式,将浏览器代理设置为 Whistle 服务地址 127.0.0.1:8899

  • 使用 Chrome SwitchyOmega 插件设置浏览器代理;
  • 使用 Proxifier 配置指定应用程序的代理服务;
  • 直接修改系统代理服务为 127.0.0.1:8899

(注:如果你不知道如何使用 Whistle,请参考 Whistle 官网或 “猫哥学前班” 网络编程系列相关教程。)

4.2 添加 .whistle.js 配置

代理配置成功后,我们在游戏项目根目录新建 .whistle.js 文件,其内容如下:

(注:本配置中包含了 Egret 文档增强功能,具体参看“H5 游戏开发”教程 1

const currentPath = __dirname
const projectName = currentPath.split('/').pop()

exports.name = `[${projectName}]本地环境配置`
exports.rules = `
http://game.local http://127.0.0.1:3000 whistle.livereload://${currentPath}/bin-debug/

# 将 CDN 地址转发至源服务器目标地址
http://cdn.dev.egret.com/ http://developer.egret.com/cn/data/upload/

# 将经常连接超时的素材直接返回 404
https://cdn.www.egret.com/official/new-egret/img/ statusCode://404

# 在 API 站点中插入一个 JS script(若脚本更新需注意替换 url)
192.30.253.118 gist.github.com
/developer\\.egret\\.com\\/\\w+\\/apidoc\\/(?!ajaxcontent)/ jsAppend://https://gist.githubusercontent.com/kaiye/207728f7c9f187cd886353e7678197f4/raw/09e543a735da2a7212e22d967f2ce40eb2d63b8c/injectEgretApiDoc.js
# 将 gist 站点上该脚本的 content-type 设置为 javascript,解决类型嗅探错误
/injectEgretApiDoc\\.js/ resType://js
`

我们运行 w2 add 命令后,将会在 Whistle Rules 面板中添加一组规则。打开 http://127.0.0.1:8899/#rules 配置后台,可查看具体的配置细节。

在这份配置中,我将 127.0.0.1:3000 默认绑定到了 game.local 域名,以解决局域网 IP 变动后需要变更 IP 配置的问题,因此你可以通过 http://game.local/index.html 来预览游戏界面。

你可以通过 Whistle Rules 自定义这个域名,或者直接将其删除,使用默认的局域网 IP 端口访问方式。

你需要注意以下技术细节:

  • 受操作系统限制,localhost 和 127.0.0.1 本地 IP 无法被 Whistle 和其他代理服务抓包,所以只能使用域名或者局域网 IP;
  • 由于 Live Reload 使用了 WebSocket 来实现监听通知,因此需要确保勾选了 Whistle HTTPS 菜单项中的 “Capture TUNNEL CONNECTs” 选项,以实现 TLS 通道抓包;
  • 勾选以上选项,还需要正确安装 Whistle CA 证书,确保其他 HTTPS 网站能正常访问。

以上配置完成后,当你在 VSCode 中修改游戏代码时,egret run -a 进程会实时监听项目文件的变化,自动编译新的代码到项目的 bin-debug 目录。此时,Whistle Live Reload 进程正在实时监听 bin-debug 目录的变化,在收到变化通知后,通过 WebSocket 通知浏览器页面进行自动刷新,从而实现我们所需的开发体验。

以上是搭建 Egret 开发环境的全部内容。在下一期,猫哥将会介绍 H5 游戏引擎的技术实现原理,希望对大家理解游戏开发有所帮助,感谢关注:)

为什么房间的 Wi-Fi 信号这么差

最近把家里主卧整成了个小影院,由于之前房子装修时网线端口与电源插口布置太少,导致家庭网络架设变得麻烦起来,最后终于通过「无线中继」技术达到了全屋满格 Wi-Fi 的效果。

在 Wi-Fi 架设过程中,我遇到了不少信号优化的问题,同时也理清了 2.4GHz 与 5GHz 的区别,接下来就和大家分享一下。

一、为什么 Wi-Fi 容易被干扰

Wi-Fi 是由 Wi-Fi 联盟组织持有的商标名,现在通常用来指代 IEEE 802.11x 网络标准中的无线局域网技术。常见的 Wi-Fi 工作频率为 2.4GHz,非常容易与周围其他设备发生信号干扰的问题。

微波炉与 ISM 频段

2.4GHz 这个数值最早来源于「微波炉」的工作频率(参考这里)。

1945 年,美国雷神公司一位工程师在研究微波雷达的时候,无意中发现 2.4GHz 频段的电磁波会使得口袋中的巧克力融化,从而发现了微波的热效应,发明了微波炉。

大量实验测量表明,2.450GHz 频率电磁波能很好的使得水分子等极性分子跟随电磁波发生振荡,从而在宏观上表现为食物被加热。

之后 2.4GHz 逐渐成为了各国通用的「ISM频段」之一,大量的工业、科研、医学、家用无线设备的工作频率都在这一频段,包括我们常见的蓝牙设备(2.402GHz - 2.480GHz)。

由此可见:

  1. 在雨天等潮湿环境下,Wi-Fi 信号会因为被水分子吸收而变差;
  2. 很多无线设备在 2.4GHz 频段下工作,导致 Wi-Fi 信号很容易被干扰。

信道阻塞

IEEE 802.11b/g/n 标准规定 2.4GHz Wi-Fi 的工作频率为 2.412 至 2.484GHz 之间,共 14 个不同中心频率的信道。大部分国家(包括**)允许 1 至 13 号信道的使用,从下图可以看到除了 1、6、11 号信道以外,其他信道的工作频率都可能会与相邻信道频率发生冲突。

2.4GHz Wi-Fi 信道划分

不同无线路由器之间通过「**载波侦听多路访问/碰撞避免」(CSMA/CA)**策略来解决信道冲突的问题,当发生信道冲突时,随机一段等待时间再进行重试。

大部分路由器都会提供「自动选择信道」功能,我们也可以通过软件分析周围 Wi-Fi 环境,再手动选择一个最合适的信道。如下图,可通过 WiFi Explorer 分析周围 Wi-Fi 信号强度与信道选择情况。

WiFi Explorer 可分析 Wi-Fi 信道与信号强度

二、Wi-Fi 如何传播

Wi-Fi 信号本质上和电台广播、可见光、x 射线一样,是一种电磁波。

波长计算

科学家们通过光速公式 c = λf 测量出了光速 c,约为 3 乘 10 的 8 次方米每秒,计为 c = 3e8 m/s。

光速公式从实验的角度证明了「光速不变原理」,在此原理基础上,爱因斯坦推导出了广义相对论,推翻了「绝对时间」的概念,从而使时空旅行和时光机器在理论上成为可能。

c = λf

已知公式中,Wi-Fi 信号在空气中的传播速度约等于光速 c ,2.4GHz Wi-Fi 的频率 f = 2.4 x 1000 x 1000 x 1000 Hz,计为 2.4e9 Hz,代入以上公式解得, λ = c/f = 3e8 / 2.4e9 = 0.125m,即 12.5 厘米。

Wi-Fi 的波长介于 1毫米至 1米之间,属于「微波」类型,日常生活中的大部分物品大小也属于这个范围。

电磁波谱的特征分布

波的衍射与穿透

衍射现象,是指波在传播时,如果被一个大小接近于或小于波长的物体阻挡,就绕过这个物体,继续进行。如果通过一个大小近于或小于波长的孔,则以孔为中心,形成环形波向前传播。

由此可见,衍射也是 Wi-Fi 的一个主要传播方式。

由于 Wi-Fi 信号的主要传播方向垂直于路由器天线的方向,所以虽然衍射能够改变波的传播方向,但一般来说,将路由器的多根天线垂直90度放置,能取得更多方向上的信号覆盖效果,如下图所示。

Wi-Fi 天线方向与波的方向

Wi-Fi 和光波一样,也会以反射、直射穿透的形式进行传播,在传播过程中,介质的吸收会造成信号能量的损失。

尽量减少 Wi-Fi 的(墙体)阻挡次数,能有效降低 Wi-Fi 信号的损失量,这也是影响 Wi-Fi 信号强弱最主要的因素。

Wi-Fi 在室内的传播路径模拟

上图模拟了 Wi-Fi 信号在房屋中的反射与衍射路径,图片来源于此处

三、5GHz Wi-Fi 的优劣势

为了减少信道冲突的发生,也为了提升 Wi-Fi 传输率和稳定性,IEEE 802.11 先后制定补充了 5GHz Wi-Fi 相关技术标准。

国内的现状是,一方面大部分的智能手机都能支持 5GHz Wi-Fi 频段(只要网卡参数项中有支持 802.11a/n/ac 标准);另一方面,大部分的无线路由器却只支持 2.4GHz 频段。

从维基百科的「WLAN信道列表」上来看,在**至少可以使用 13 个互不干扰的传输信道。因此,使用 5GHz Wi-Fi 能有效减少 Wi-Fi 信号干扰的情况。

5GHz Wi-Fi 穿墙能力更弱

这条有点难理解,因为物理课上有学到**「电磁波频率越高,穿透性越强」**,但从实际观测数据来看,我们日常生活中的木质家具和钢筋混凝土墙,更容易吸收 5GHz 的 Wi-Fi

5GHz 与 2.4GHz Wi-Fi 穿透能量损失对比

这主要是因为:不同频率的电磁波在穿过不同的介质时,其吸收率各有不同。

一般来说,x 射线、γ 射线等频率高于可见光的射线,粒子能量较高(参考光子能量计算公式 E=hv),在穿过物体时,会使得其原子分子发生「电离辐射」现象,表现为较强的穿透性。

所以医院拍 x 光的地方通常要做特殊隔离,避免高频射线穿透人体,引起体内细胞电离,从而危害健康。同样的原因,如果不是因为地球大气层阻挡了来自宇宙的高频射线,我们人类也不可能出现。

而微波由于频率相对较低,粒子能量无法引起「电离辐射」和「电子能级跃迁」,在穿过物体时被吸收能量的多少取决于物体中导电介质的分布情况和主要介质的分子结构。

除此之外,我个人猜测可能还有个更普遍的规律:

频段越靠近可见光的电磁波,越容易被自然界中的生命体和物体所吸收。

所以人类眼睛中感光细胞的直径范围刚好和可见光波长范围(0.39~0.70μm)一致,所以我们的世界是彩色的。这多少有点像霍金在《时间简史》中提到的「人存原理」:

我们之所以看到的宇宙是这个样子, 是因为如果它不是这样的话,我们就不会在这里去观察它。

介绍完影响 Wi-Fi 信号强弱的各种因素之后,接下来我会介绍如何通过配置路由器来提升网络质量,欢迎各位继续关注。

全新 Mac 安装指南(编程篇)

注:本文专门用于指导对计算机编程与设计(尤其是互联网产品开发与设计)感兴趣的 Mac 新用户,如何在 Mac OS X 系统上配置开发与上网环境,另有《全新 Mac 安装指南(通用篇)》作为本安装指南的基础篇。

在 《为什么说每个程序员都应该有台Mac电脑》一文中我有提到 Mac 系统的命令行环境与 Linux 系统十分类似,这是因为 Mac OS X 的操作系统内核是 Darwin,它和 Linux 一样是一种优秀的类 Unix 系统。掌握 Linux Shell 命令行的使用,可以说是全栈工程师的基本要求之一,而使用 Mac 的初学者会比使用 Windows 系统的有着更大的优势。

接下来,我们先来了解几个 Mac (及 Linux )下的基础概念 环境变量Shell 终端SSH 远程连接

环境变量

环境变量(environment variables)是所有操作系统中的一个通用概念,简单来说就是系统启动之后,会预设一些全局的变量信息供所有应用程序来使用。打个比方,如果我声明「接下来文章里说的 env 是表示 environment variables 的意思」,其实就是在这篇文章的环境下,定义了一个环境变量 $env = "environment variables"

在一个操作系统中,可以把一个目录名、命令行语句、数值或字符串定义成一个环境变量。以下截图展示了 Windows 操作系统中预设的一些环境变量:

windows系统环境变量

其中有一个比较特殊的环境变量叫做 系统 path 变量,它的用途是定义一组全局目录路径。当在命令行终端下运行一个命令行时,若当前路径中不存在该命令,则会在系统 path 变量所定义的目录中按先后顺序一一查找,查找到则执行,如果遍历完 path 中所有目录都未查找到,则返回无法找到该命令。

Windows CMD 与 Mac Terminal 下打印系统 path 变量

Shell 终端

Shell 可以用来执行命令行,在 Mac 下打开 Terminal(终端)程序,会自动开启一个 Shell 命令行界面,而 Shell 每次在被打开(或执行)的时候会自动加载默认配置文件。Mac 和 Linux 默认的 shell 都是 bash,其中 Mac 的 bash 默认配置文件是 .bash_profile ,Linux 的是 .bashrc 。Mac 下通过修改 .bash_profile 文件可以进行一些环境变量的配置。

接下来实际操作演示如何使用 Terminal 在 .bash_profile 中配置 ll 快捷命令,其中我会顺带使用一些常用命令,它们含义如下:

  • cd 跳转至目录
  • ls 列出当前目录下的文件及文件夹
  • ls -l ls 命令加 -l 参数表示列出更多详细信息
  • mv 移动 / 重命名文件
  • touch 新建文件
  • rm -r 删除文件,-r 参数表示递归删除目录
  • pwd 显示当前目录
  • ~ 波浪号表示当前用户根目录,一般用户的配置文件都放在这里
  • echo 打印字符串或变量
  • > 将结果输出至某文件中
  • cat 输出文件全文内容
  • du -sh * 查看某目录下各子文件和目录的大小
  • source 执行某一个文件,通常 .bash_profile 修改之后需要执行下 source 命令(或者新开一个 shell)来保证配置生效

Terminal Shell 演示

此外,管道命令 | 也是 Shell 中十分常用的命令,它用于将前一个命令的输出结果作为后一个命令的输入参数

例如使用以下命令查看 7070 端口是否有进程占用:

netstat -an | grep 7070

Mac 下默认的 Terminal + bash 不够强大,推荐换成 iTerm2 + zsh ,以下是具体的配置方法:

1、安装 iTerm2

安装后打开 iTerm2,使用 ⌘d 可横向切分成出两个窗口,使用 ⌘t 可以新建一个窗口标签。按下 ⌘, 进行以下配置可提升逼格:

  • iTerm2 的命令行指示标记可以通过 Preferences -> Profiles -> Terminal -> Shell Integration 取消勾选 Show mark indicators 来关闭

  • 设置窗口透明度。如下图,Preferences -> Profiles -> Window -> Window Appearance 设置 Transparency

    iTerm2 窗口透明度设置

  • 设置打开窗口快捷键。Preferences -> Keys -> Hotkey 推荐把快捷键设置成「键盘左下角+左上角」组合成的快捷键,如下图为 control+反引号(数字1左边那个键)。

    iterm2-hotkey

当 iTerm2 未启动时,以上窗口打开快捷键不会生效,使用自定义 Alfred Workflows 会是一个更好的方案(更多 Alfred 内容参看本文「常用软件推荐」部分):

Alfred-iterm

双击上图的 「Launch Apps / Files 」将 iTerm2 程序拖至浮层区域,并勾选「Toggle visibility for apps」选项。该配置方法可以实现 macOS 下使用任意快捷键显示(隐藏)任意应用程序的功能。

Alfred-iterm

2、安装 zsh

安装完成后还需要进行一定的配置,让 zsh 复用 bash 的环境变量配置,具体步骤如下:

  • 在线自动安装 zsh 。在 iTerm2 中执行以下命令 sh -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
  • 使用 vim 编辑器打开用户 zsh 配置文件,vim ~/.zshrc ,vim 与普通编辑器有很大差异,使用方法可自行百度学习
  • 文件打开后,先按字母键大写 G(跳至文件末尾),再按下字母键小写 o(新插入一行,同时进入编辑模式),输入以下字符 source ~/.bash_profile ,然后按下 Esc 键退出编辑模式,再依次按下 :wq 保存关闭文件
  • zsh 提供了大量扩展插件,推荐启用其中的 osx 插件,启用后可使用 ofd 命令将当前 shell 窗口在 Finder 中打开,使用 cdf 可在 shell 中直接跳转至当前 Finder 窗口所在的路径
  • zsh 的 zsh-autosuggestionszsh-syntax-highlighting 插件能够将 zsh 扩展成与 fish 类似的操作体验 (tmux 下使用时需注意这个 bug
  • zsh 的默认主题 robbyrussell 无法展示完整的当前工作路径,可修改配置文件的主题行,如 ZSH_THEME="gnzh" 设置成其他主题

3、安装 brew

Mac 安装其他命令行,需要一个类似 Linux apt-get 这样的包管理工具,运行以下命令即可自动完成安装 brew 命令:

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

安装完成后,如想安装 wget 命令行(一款常用的爬虫下载工具),只需在 shell 中运行 brew install wget。大多数命令行都可以通过 brew 进行安装和管理。

SSH 远程连接

ssh 是 Mac/Linux 下一个远程连接主机的命令行工具,两台机器建立一个 ssh 连接之后可以进行一系列的加密指令和数据传输。ssh 十分重要,每个爱编程自由的人都应该掌握。

在开始学习 ssh 之前,我们需要有一台 Linux 的主机(或者另外一台 Mac 电脑)用来作为远程被访问的机器。由于国内的 阿里云、腾讯云 价格略高,建议可以买一个国外的 VPS(虚拟独立服务器),Linode / Vultr 加州机房在国内的访问速度不错,Vultr 最便宜的主机 30RMB/月,不过网速最快的还属 Google Compute Engine 。使用 Google 的云服务需要解决这样一个悖论:一方面你需要能打开 Google 的网站才能购买他的 VPS 服务,另外一方面你需要有了他的 VPS 主机才能通过 SSH 打开他的网站。(这是老大哥留给我们这代人的难题)。

假设你已经有了另外一台 Linux 主机,IP地址 为 1.2.3.4,用户名为 root ,使用以下命令可发起建立 ssh 连接:

ssh [email protected]

此时会要求输入 root 用户的密码,输入完成后即可登录至远程机器。如果不想每次都输入密码,则可以使用 ssh 密钥文件鉴权。在使用 git/scp/rsync 等命令时,配置 ssh 密钥文件能省去每次输入密码的麻烦,其配置方法只需三步:

  1. 安装 ssh-copy-id 命令行工具 brew install ssh-copy-id
  2. 生成本机密钥/公钥文件 ssh-keygen -t rsa
  3. 将本机公钥上传到远程服务器上 ssh-copy-id [email protected]

注:ssh 端口映射

ssh 协议默认使用 22 端口连接,通过 -D 参数可指定将该 ssh 连接通道映射到本机的某个端口,并且该加密通道支持 SOCKS 代理协议,这意味着本地应用程序通过此端口传输数据时,实际上是使用远程服务器的网络请求的数据。以下命令行演示了静默映射 ssh 连接至本地 7070 端口:

ssh -g -N -D 7070 -f [email protected]

接下来我们验证下是否映射成功。打开 System Preferences -> Network ,点击当前使用中的网卡 -> Advanced..(高级) 配置面板,进行以下设置:

配置 SOCKS

设置完成后在百度搜索IP看看本地网络是否变成了远程机器的IP。使用 Vultr VPS 的同学可以尝试打开下 Google.com 透透气,学会使用 Google/Stackoverflow/Github 找到技术问题的解决方案,是高级程序员的基础素质。

常用软件推荐

在了解了 环境变量Shell 终端SSH 远程连接 之后,基础的命令行编程环境和网络环境已经配置完成。以下是我常用的开发软件,推荐给各位,希望有所帮助。

通用

  • SwitchHost HOST切换工具
  • LICECap / GifGrabber 极简录屏工具,直接生成 gif 格式
  • Beyond Compare 文件对比、合并工具,推荐购买
  • DevDocs 各类开发语言框架 API 文档,推荐使用 nativefier --name "DevDocs" "http://devdocs.io/" 打包成本地应用使用(可配置成离线版本)
  • FileZilla FTP/SFTP 客户端。收费的推荐 Transmit
  • Github Desktop / SourceTree Git GUI 客户端
  • SmartSVN,SVN GUI,注意版本号对应关系,一般使用与 Mac 命令行相同的版本(当前为 svn 1.7
  • Quick Look Plugins Mac 系统中使用「空格键」可快速预览选中的文件,下载相关 .qlgenerator 插件拖至 /Library/QuickLook/ 目录即可完成安装
  • Autojump 目录快速跳转命令行工具,告别苦逼的 cd cd cd …… 需要注意的是,如果通过 brew install autojump 安装,在完成安装后,还需要进行配置,以下方法二选一:
    • ~/.bash_profile 文件中加入语句 [[ -s $(brew --prefix)/etc/profile.d/autojump.sh ]] && . $(brew --prefix)/etc/profile.d/autojump.sh
    • ~/.zshrc 文件中,修改 plugins=(git) 插件配置行,以开启 zsh 对 autojump 插件的支持 plugins=(git autojump)
  • tmux 终端复用命令行工具,经常 ssh 到远程服务器的同学必备
  • SpechtLite A rule-based proxy app for macOS,自动选择最快的上网通道

Alfred Workflows

Alfred 是 Mac 下的「神兵利器」,以下是部分 Workflows 推荐:

以下是其他集合推荐:

编辑器IDE

网络编程

前端开发

服务端开发

其他

  • Synergy 局域网内共享鼠标键盘
  • Keycastr 屏幕上显示按下的快捷键
  • OmniFocus / OmniPlan 任务、项目管理
  • Poedit 语言文件编辑工具
  • Dropbox Dropbox 同步文件不会出错,不过要先学会设置代理

另外,相信不少程序员朋友有听说过神之编辑器 Emacs 与编辑器之神 VIM,在 Mac 下有一个十分关键的隐藏配置,开启之后,可助普通程序员直接步入大神级别。关注微信公众号 「猫哥学前班」,回复 hhkb 关键词即可揭晓答案:)

有组织的捅马蜂窝违法了吗

今天的朋友圈被《我承认,我们是有组织攻击马蜂窝的》刷屏了。自媒体「小声比比」作者梓泉和「乎睿数据」的三名技术人员组成的「四人豪华犯罪团伙」,通过爬虫技术结合大数据分析,披露马蜂窝 2100 万条用户评论数据中的 1800 万条为造假数据,被马蜂窝以名誉权纠纷为由状告法院。

在我看来,以下几个要点可能会影响案件判罚结果:

  • 案件管辖权分配
  • 证据保全公证
  • 爬虫获取数据是否违法

一、案件管辖权

今年上半年今日头条和腾讯因为抖音被微信屏蔽事件,双方大战了 300 个来回,最终都向法院提起了诉讼。有意思的是,如果腾讯是原告,通常会向深圳市南山区人民法院起诉,而今日头条则会优先选择北京市海淀区人民法院。

这是为什么呢?(提示:可以从纳税人的角度思考)

当然是为了判罚的公正性嘛。

所以这个案子,很多人会建议深圳的「乎睿数据」团队向法院提请「管辖异议」,案件的管辖权应当由「北京市朝阳区人民法院」转给「深圳市南山区人民法院」。

第十五条 侵害信息网络传播权民事纠纷案件由侵权行为地或者被告住所地人民法院管辖。侵权行为地包括实施被诉侵权行为的网络服务器、计算机终端等设备所在地。侵权行为地和被告住所地均难以确定或者在境外的,原告发现侵权内容的计算机终端等设备所在地可以视为侵权行为地。

——《最高人民法院关于审理侵害信息网络传播权民事纠纷案件适用法律若干问题的规定》,https://www.chinacourt.org/law/detail/2012/12/id/146033.shtml

二、证据保全公证

文章还提到,马蜂窝清理脏数据的效率十分迅猛,涉嫌造假的 1000 多万条数据分分钟就清完了(给马蜂窝未雨绸缪的技术架构点个赞)。

事实上,在互联网 big brother watching big data 时代,信息残留无处不在。以网站数据为例,不但云服务器上会留下各种 backup,各大搜索引擎也会 cache 数据,Web Archive 上甚至还能查到许多站点 10 年前的版本(例如 2005 年的支付宝首页)。

诉前证据保全公证工作(以及各种作品和数据的原创保护)甚至都不用去线下找公证处,通过在线的第三方服务就能完成,因为网上的数据流是有时间属性的。例如,你可以给自己的 QQ 邮箱发送一封带附件的邮件,用来证明这个附件里的内容你是全网首发,从而来保障自己的著作权。

**科学院国家授时中心提供了一个在线的「联合信任时间戳服务」(http://www.tsa.cn),只需要 10 块钱,任意大小的数据包上传打个时间戳,就能完成法院认可的证据保全公证程序。

三、爬虫获取数据是否违法

前几年猫哥在外创业,团队里有个从快播来的技术大牛,那爬虫技术是相当优秀。

公司让他们用爬虫抓了不少 1024 小电影和未经授权的影视作品,后来在一次突击检查中,服务器被查获了,领导们也进了局子。

技术人员写爬虫程序,抓取第三方站点数据,是一项很常见的操作,但同时也是一个高危操作。

1. 不遵守 robots.txt 违反《反不正当竞争法》

robots.txt 爬虫协议是国际通用的商业惯例,任何站点可以通过 robots.txt 来引导爬虫,站点上哪些内容是开放的,哪些是禁止抓取的。

2012 年百度诉 360 违反 robots 协议案,以 360 败诉告终。

马蜂窝估计也考虑到这个问题了,今天下午 5 点 38 分 42 秒(Last-Modified: Tue, 23 Oct 2018 09:38:42 GMT)更新了站点的 robots.txt 协议,将原来未做限制的爬虫 UA 和目录进行了限制。

2. 抓取涉及用户隐私与商业机密的数据违反《网络安全法》

根据《网络安全法》与相关司法解释,爬虫如果抓到了涉及用户隐私与商业机密的内容必须予以删除,情节严重的要负刑事责任。

(三)非法获取、出售或者提供行踪轨迹信息、通信内容、征信信息、财产信息五十条以上的;
(四)非法获取、出售或者提供住宿信息、通信记录、健康生理信息、交易信息等其他可能影响人身、财产安全的公民个人信息五百条以上的;
(五)非法获取、出售或者提供第三项、第四项规定以外的公民个人信息五千条以上的;

—— 《关于办理侵犯公民个人信息刑事案件适用法律若干问题的解释》第五条, http://www.spp.gov.cn/xwfbh/wsfbt/201705/t20170509_190088.shtml

3. 非法获取计算机信息系统数据罪

爬虫如果采用类似黑客暴力破解手段获取数据,或因此导致对方站点服务不可用,可能触犯「非法获取计算机信息系统数据罪」。

第二百八十五条 违反国家规定,侵入国家事务、国防建设、尖端科学技术领域的计算机信息系统的,处三年以下有期徒刑或者拘役。
违反国家规定,侵入前款规定以外的计算机信息系统或者采用其他技术手段,获取该计算机信息系统中存储、处理或者传输的数据,或者对该计算机信息系统实施非法控制,情节严重的,处三年以下有期徒刑或者拘役,并处或者单处罚金;情节特别严重的,处三年以上七年以下有期徒刑,并处罚金。
提供专门用于侵入、非法控制计算机信息系统的程序、工具,或者明知他人实施侵入、非法控制计算机信息系统的违法犯罪行为而为其提供程序、工具,情节严重的,依照前款的规定处罚。{刑法修正案(七)增加第二款、第三款}

—— 中华人民共和国刑法(修订),http://www.spp.gov.cn/spp/fl/201802/t20180206_364975.shtml

所幸的是,以上三条爬虫红线,梓泉和乎睿团队都没有违反。不知马蜂窝大佬接下来将如何应对?

我相信,借助技术和法律的力量,小个体总有扳倒大集团的那一天。


身为技术人,我们一直以来关注的都是技术和能力,这既是我们安身立命的本钱,也是自身价值的体现。但专业技能不是生活的全部,真遇到一个与法律有关的烦心事,或许会让你无心上班甚至失去工作。

而事实上,法律是人人都要面对的话题。比如,翻墙有风险吗?期权被坑怎么办?用盗版图有什么后果?突然被 HR 叫进办公室说要辞退你,该怎么应对?办公室性*扰,怎么对抗?发生交通事故,怎么处理?

猫哥作为「极客时间」的重度用户,在此向各位新老技术同学推荐一门新上线的《白话法律42讲》专栏。该专栏由从业十余年的资深律师周甲德开设,选取职场、技术、生活三个领域里与程序员联系最密切的40个法律问题,讲解每个社会人都应该知道的的法律知识,并给到你实用有效的处理办法。这是市面上第一个,也是目前唯一一个专门面向程序员群体的法律课程

感兴趣的朋友可以去看看

Apple Pay 背后的技术与制度设计

这两天相信各位的微博、微信朋友圈应该是被「Apple Pay 入华」的消息给刷屏了,**银联作为支付行业老大被支付宝和微信支付等第三方支付小弟恶心了这么多年,终于有希望借助「洋人的枪炮」出口恶气了。

按常理,猫哥学前班是不屑于写新闻时评的,但作为一名资深脑残果粉,我决定这一次不按常理出牌。所以在 Apple Pay 入华的第一天(2月18日),我特意绑定了张信用卡去 KFC 奢靡了个肯德基豪华套餐,认真体验了一番 Apple Pay。

关注微信公众号「猫哥学前班」,回复「pay」,即可看到我的体验视频。相信支付宝的前同事们看到如此便捷的支付体验,一定会吓得虎躯一震:)

如果你(或你朋友)的 iPhone6/6s 中的 Wallet 无法添加(有银联标识的)银行卡的话,请尝试打开 「设置 -> 通用 -> 语言与地区 -> 地区」将其设置成「美国」试一试,应该就 OK 了。

Apple Pay 看起来很时髦,但它背后的实现原理,——「近场通信」(Near Field Communication,简称 NFC),却决非什么高端技术。NFC 与 Wi-Fi(上网)、蓝牙(音箱)、红外(遥控器)一样,是一种无线传输技术。

Apple Pay 使用的协议是苹果自研的 iBeacon,安卓手机在很久以前就已经支持了类似的技术(Android Beacons),他们的底层协议都是 Bluetooth Smart(蓝牙 4.0)。支付宝和手机 QQ 钱包也早已支持了基于 NFC 的移动「闪付」功能,只可惜流程没操作系统级别的 Apple Pay 这般顺畅,且大部分用户都没有闪付的使用习惯。

(以上这段描述存有争议,我仔细查阅了下 WWDC 大会Apple Pay Wiki,只提及了 NFC 模块,而没有提及具体的协议细节。感谢简书网友 @py大叔 指出,对这个细节感兴趣的同学请自行知乎《Apple Pay 引入 NFC 表明 Apple 抛弃 iBeacon 吗?》)

作为学前班级别的科普小能手,猫哥接下来将会分别从「技术原理」和「非技术原理」两个完全不同的视角,来给各位浅析一下 Apple Pay 背后的技术与安全制度设计,请理科生和文科生按个人喜好选择浏览。

技术原理

中学物理课本中有一节讲到了「电磁感应」,如果你拿着一根粗一点的电线靠近一块磁铁作上下摩擦运动,几分钟后你的手心会突然发射出一股快感涌遍你的全身……过了青春期的同学,应该能理解我这句话的意思 :P

因为这个动作会「切割磁力线,产生感应电流」,这就是电磁感应现象,发电机的实现原理也是如此。磁场越大感应电流就越大,当电流超过了人体所能承受的极限(电压 36V、电流 10mA),就会出现很恐怖事情,胆子够大的同学可以在我的公众号回复关键词「电大的」试试。胆小的同学就别尝试了,我们继续往下说。

所有无线传输设备的物理实现都离不开「电磁感应」的基本原理,Apple Pay 的 NFC 设备也不例外,它的这种传输技术属于无线射频(Radio Frequency,简称 RF)技术的一种。无线 RF 技术应用十分广泛,例如在食堂吃饭时用的饭卡,坐地铁公交时用的 IC 卡,还有公司的门禁卡都是基于 RF 技术实现。

学过大学物理的童鞋,——特指那些上课时没有趴在桌子上睡觉的同学,应该有学过「LC 振荡电路」这一节。睡了觉的同学也不用担心,因为我们还有百度……,让我们先一起来看一个最简易的 LC 振荡电路示意图(其中,L 表示电感,C 表示电容):

LC 振荡电路

由于这种回路比较特殊,会呈现出「周期性的电磁转化」现象,如果接个示波器的话,就能看到我们所熟悉的波形图。

示波器

当 IC 卡靠近刷卡器时,会接收到刷卡器发射出的电磁波,从而在其内部的振荡电路中感应出电流和磁场,并且这两种形式的能量会不断的相互转换。如果改变振荡电路的结构与元件,那么振荡电路辐射出的电磁波就会相应的发生改变(也就是说,每个 IC 卡发出的波波的大小都是不一样的)。这些电磁波被回传给了刷卡器,由磁信号转为电信号,再由电信号转成数字信号,从而还原出了被扫描设备的标识。

以上,即是 NFC 无线射频技术的基础原理。由于 NFC 射频技术的传输距离小于 0.1m(差不多是一根中指的长度),所以安全性比较高。但如果你是在下班高峰期去乘坐北上广深的地铁的话,距离上的安全性就无法得到保障了。

深圳深大地铁站下班高峰期

所以,虽然原理上 NFC 芯片在手机关机状态下也可以实现传输功能(例如,钱包里的 IC 卡是不用充电的),但现阶段的移动支付从安全性上考虑,通常还需要一个设备的「再确认」过程,在苹果手机上就是 Touch ID(指纹识别),这是一个十分重要的安全制度的设计。

非技术原理

NFC 技术虽然早已在安卓系统上实现,但安卓系统的权限控制过于开放,导致任何应用程序都能轻易的获取 root 权限,从而给用户带来隐私泄露的风险。支付宝和手机 QQ 钱包为了解决安全性问题,不得不将它们的「闪付」功能设计得十分复杂。归根结底,是因为 Android 系统的开放性,他没有采用苹果这种集权式的系统设计。

把权力关进制度的笼子里。

——中华人民共和国,习大大

相反,iPhone 手机正如苹果一直所吹嘘的那样,安全性设计得非常好。如果你想尝试暴力破解你的另一半的 iPhone 解锁密码,窥探 ta 的微信聊天记录,那么这台手机很可能会像下面这样变成一块砖头:

iPhone 已停用

然而,从我的 Apple Pay 实际体验视频上可以看出,「苹果设备具备在锁屏状态下被唤醒与调用应用的能力」。这种「超能力」如果落到「老大哥」手里,后果将会不堪设想。

其实,接下来我想聊的 Apple Pay 背后的「安全制度设计」,源于昨晚关于苹果的另外一则非头条新闻《库克拒绝帮助FBI解锁凶犯iPhone》。

库克警告说,一旦按照法院判令执行,将会开一个“危险的先例”,其后果“令人毛骨悚然”。政府能够通过法令解锁一台iPhone手机,就有权入侵任何人的手机攫取数据。政府将能够进一步侵犯公民隐私,并可以要求苹果开发监控软件,截取用户的消息,访问用户的健康记录或财务数据,跟踪用户的行踪,甚至远程调用用户的麦克风或摄像头,而用户对这一切毫不知情。

“我们相信FBI的意图是善意的,但是政府强迫我们为自己产品‘开后门’的做法是错误的。我们担心这一要求将最终损害政府旨在保护的公民自由。”库克在声明中表示。

这是一个很有意思的话题,美(rèn)国(hé)政府究竟有没有权利侵犯一个公民的隐私权?

然而,这则新闻中法院的判决是「合法的」,因为美国除了宪法是「成文法」以外,大部分时候法院在审判时都会沿用来自英国的「判例法」习惯,这就意味着法院有使用法律中未明确成文的普通判例法的权利。

关于判例法,我有个特别深的印象。在电影《控方证人》中(很有意思,强烈推荐),被告律师要求传唤被告的妻子入场时受到了原告律师的强烈反对,认为是不合法的要求。结果被告律师拿出一大摞档案「先例」,来证明在特殊情况下可以这样做。

电影《控方证人》剧照

面对法院的判决要求,苹果 CEO 库克船长的回决也是「十分的合理」,因为他认为,虽然技术上解锁是简单,但是如果开了这个先例,那就是侵犯了公民的自由,那就是违反了「美利坚合众国宪法第四修正案」!

(友情提示:以上链接可能打不开,但勤劳的小蜜蜂们在微信公众号「猫哥学前班」里能找到答案)

The right of the people to be secure in their persons, houses, papers, and effects, against unreasonable searches and seizures, shall not be violated, and no Warrants shall issue, but upon probable cause, supported by Oath or affirmation, and particularly describing the place to be searched, and the persons or things to be seized.

人民的人身、住宅、文件和财产不受无理搜查和扣押的权利,不得侵犯。除依照合理根据,以宣誓或代誓宣言保证,并具体说明搜查地点和扣押的人或物,不得发出搜查和扣押状。

——美国宪法第四修正案

根据该条法案,引申出了「美国非法证据排除规则」。

政府需要在已经掌握了相当的事实和证据来「让一个谨慎的人相信,需要逮捕的人士已经或正在犯下罪行」时才拥有逮捕的相当理由。这样的理由必须要在实施逮捕前就已存在,而不能是逮捕后再找到这样的理由,否则实施逮捕后所获得的证据将被认为是无效的,并且逮捕行为本身也是非法的。

——美国非法证据排除规则

由于本案中的枪击案凶手是一个「嫌疑犯」并非确凿的「罪犯」,所以说库克的回决是十分有力的。

一个优秀的、健全的社会制度,总有一些基础框架制度是不可以轻易改变的,例如宪法。「违反了美国宪法」这种大高帽,即使是美国大法官也不敢乱戴。

库克船长的声明,其背后其实反映出了这样的客观事实:「**」(法院的判决)和**「自由」(公民个人隐私)在一定程度上是对立的**。当这二者发生冲突时,我们将陷入一个两难的境地。

面对这样的难题,孟子在两千多年前也曾发出过一声感概:

鱼,我所欲也,熊掌亦我所欲也,二者不可得兼。

——孟子《鱼我所欲也》

在人类科学与文化发展史中,出现过不少类似两难的选择,引发过多次激烈的社会讨论,例如著名的「电车难题」。在电影《蝙蝠侠:黑暗骑士》(又是一个强烈推荐)的开头,也有一个类似的炸船难题:

电影里两艘船人数相等,一艘船是无辜群众,一艘船是罪犯,双方各有引爆器来炸毁对方的船只,如果两艘船规定时间内都不采取行动,结果两艘船都会被炸死。

如果是你,你会做出怎样的选择?

  • 炸无辜群众的船,反正我不在船上 :p
  • 炸罪犯的船,刚好为民除「害」 - -!
  • 好难,还是扔硬币吧 T_T

电影《蝙蝠侠·黑暗骑士》炸船剧照

在电影中,普通群众一方最终选择了「**」投票制,三分之二的人投票决定炸死对方的船只,从而保存己方,即用「**」来结束对方的「自由」。

苹果的库克船长这次可以轻易的回决法院的要求,下次面对来自「大多数的**」的压制,——例如不解锁会害死一批人,那选择可能就大不一样了。

好在这个问题,放在**,从来就不是个问题。呵呵。

作为一个爱吃野味的「非动物保护主义者」,孟老夫子在思考了 0.01 秒之后,很快就给出了他的答案:

鱼,我所欲也,熊掌亦我所欲也,二者不可得兼,舍鱼而取熊掌者也嘛~

拉普拉斯妖与期货大王

今天的新闻头条是 Google 的人工智能「阿尔法狗」(AlphaGo)战胜了围棋界的「最强王者」,——李世石·九段,猫哥全程观看了三个多小时的直播,将本次人类落败的根本原因总结在了下图之中。

机器没有人性的弱点

本期「猫哥学理财系列」的主题是介绍「期货」基础知识,文章中会出现另外两个比阿尔法狗更强大的逆天存在,它们是「拉普拉斯妖与期货大王」。


可能许多朋友和我一样都没有实际进行过「期货」交易,但在我看来,学习期货知识却很有必要。因为期货是商品价格的「天气预报」,了解期货交易原理,能帮助我们建立正确的投资哲学,还能帮助我们理解世界经济的现在与将来。

在正式开始介绍期货之前,我们先来认识一下「拉普拉斯妖」。

拉普拉斯妖

历史到今天为止有三只最著名的苹果:一个诱惑了夏娃,一个砸醒了牛顿,剩下一个,乔布斯用它改变了世界。这三只苹果说明了,性爱、求知、创新,是人类进步的阶梯……

牛顿三大运动定律与万有引力定律奠定了经典力学的基础,在他一百年之后的法国出现了一个著名的数学家,——拉普拉斯(Pierre-Simon Laplace)

拉普拉斯将万有引力定律引入天体力学的研究中,取得了瞩目的成就。他还对统计分析学和概率论作出了诸多贡献,以他名字命名的数学方法就包括:拉普拉斯变换、拉普拉斯定理和拉普拉斯方程。

在经典力学应用方面的成功,导致拉普拉斯成为一名「决定论」的坚定支持者。

我们可以把宇宙现在的状态视为其过去的果以及未来的因。假若一位智者会知道在某一时刻所有促使自然运动的力和所有组构自然的物体的位置,假若他也能够对这些数据进行分析,则在宇宙里,从最大的物体到最小的粒子,它们的运动都包含在一条简单公式里。对于这位智者来说,没有任何事物会是含糊的,并且未来只会像过去般出现在他眼前。

—— 拉普拉斯,1814 年「概率论」

后人把他所说的「智者」称为「拉普拉斯妖」,在**文化中,我们把这种现象称之为「因果轮回」。

拉普拉斯预言

因果决定论很容易理解,任何事情的发生,总有它的一个原因。今晚看不见月亮,明天就很可能下雨;晚上深更半夜不回家,就很可能接到某人打来的「夺命追魂 call」,如果谁没接到,那很可能是单身狗一只。

然而,在人的「自由意志选择」方面,因果决定论却不再适用

例如排队遇到被人插队的情况,你既可以选择骂他一顿,也可以选择揍他一顿,既可以选择友善地提醒他遵守规则不要插队,也可以选择做一只沉默的羔羊任人插入。

可见,拉普拉斯妖的确无法预测人的行动与**。

这是一个科学与哲学的二难推理问题,站在拉普拉斯妖肩膀上的爱因斯坦们,与手持时间之矢的海德格尔们,为这一话题已争论了上千年。

在我们所生存的现实世界里,经济活动是人性的产物。因此,拉普拉斯妖无法预测全球经济的走势,也无法预测 3000 点是否为** A 股的地平线。

预测经济的任务,只有「期货大王」才能做到。

历史上第一张期货合约

相传在 600 多年前的日本,有个名叫「后小松」的天皇得到了号令天下的神器「草薙剑」,从而结束了长达半个多世纪的日本南北朝对峙时期。天皇有个私生子,为避免卷入皇室争斗,从小就出家做了和尚。

小和尚聪慧过人,十二岁能背诵唐诗宋词三百首,二十六岁就已泛舟悟道。悟道后的和尚生活放荡不羁,公开宣扬及时行乐、投身欲海的价值观,成长为了一名「花和尚」。

美人云雨爱河深,楼子老禅楼上吟;
我有抱持睫吻兴,意无火聚舍身心。

——《题淫坊》

这个花和尚便是「聪明的一休」。

聪明的一休和尚

当时,大米是日本最重要的战略储备物资,经常对经济及军事活动造成重大的影响。为保障大米的供应和储备,时任幕府的足利大将军,让一休哥制订一个管理大米市场的办法。

一休哥告诉幕府,要想控制市场,就得先垄断市场。于是,幕府买光了市场上所有的大米现货,同时还和米商立下合同约定,来年新入市的大米,幕府可以用同样的价格全部收购。

这便是历史上第一张「�远期货物」合约,即期货合约。

当来年遇到丰收之年,米商们很乐意把大米卖给幕府,因为他们能以更低的价格收购到大米,比往年赚更多的钱。但遇到天灾人祸之年,由于大米减产,米商的实际现货收购价远高于期货合约卖出价,往往会亏得一塌糊涂。

注:以上期货发源史,由猫哥根据野史杜撰,仅供参考。

期货交易的三个特点

在实际的交易过程中,期货与现货商品、以及黄金、股票等金融衍生品有着很大的不同。它具有以下三个主要特征:

  • 双向交易。股票和其他交易品通常只能先买入后卖出,期货既可以「买多」开仓也可以直接「卖空」开仓,属双向交易。在期货交割日到期之前,需要同时持有相同品种、相同份额、相反方向的合约才能够「平仓」,否则会在交割日当天被强制平仓(个人投资者)或以实物进行交割(企业投资者);
  • 零和游戏。股票价格通常与企业市值成正相关,好的企业从长期来看盈利与市值会逐步上升,股票会上涨,股东的投资就能受益。但期货却是一个零和游戏,若有人做多赚了 1 万块,那对应反方向上一定有人卖空亏了 1 万块(算上交易手续费,实际亏得更多);
  • 价格发现。在大宗商品期货市场中,原材料供应商与采购商通常会持有到期合约,采用现货方式交割,其交易价格为当日期货收盘价。因此期货市场上的价格会尽可能的向未来真实的现货价格方向波动,具有价格发现的作用。

根据西方经济学的主流观点,「供求关系决定商品价格」,商品「供不应求」,价格就会上涨,「供过于求」,价格就会下跌。例如钻石之所以昂贵不是因为它真实稀缺,而是因为它背后有戴比尔斯这样的垄断组织,严格控制着每年投放进市场的钻石产量。

对比钻石的案例,大家可以思考下最近深圳与上海房价疯涨的背后原因。

供求与价格的关系

期货商品的产量同样会随着原料产地环境和世界局势的变化发生波动,从而导致商品价格随之波动。作为一种常见的套期保值工具,参与期货交易的各方一定会想法设法地准确预测商品的供求关系

所以说,期货也是经济的天气预报。期货的价格走势,一方面可以提前指导商品的实际价格,另一方面也可以从侧面反映出供求关系和局势的变化。

期货大王

我有个朋友在国信证券做期货操盘手,他告诉我在**期货界有「东邪西狂南帝北丐」等传奇人物,其中的北丐叫「付海棠」。

作为一个养过猪、种过大蒜和棉花的普通农民,付海棠的传奇经历是,——在期货市场从 5 万的本金赚到了 1.2 个亿,称之为「期货大王」毫不为过。

说我传奇是没有看透我,对别人来说,从 5 万元到 1.2 亿元,感觉不可能发生,其实在当时,这个成绩是很平常的,但他们不这么认为。

我种过地,期货上的很多品种都生产过,大豆、玉米、小麦、棉花、大蒜等。我能知道大多数农民是怎么想的。多次对大行情的看法,虽然不能说一个点位都不差,基本上还是比较准确的。

有些人炒了很多年的期货,却不知道期货是什么。期货做的是未来的价格,技术分析是事后诸葛亮。行情是等来的而不是做出来的。

世界上成功的投资派都不是技术家,包括索罗斯、巴菲特都是基本面分析。

——付海棠,《一个农民的亿万传奇》

做期货的有两类人,一类人像付海棠、「铜王冯成毅」一样,只做自己了解的期货品种,并有着长达二十年以上的认识。为了更加客观真实的反映商品的供求关系,他们还会在各大原料产地建立自己的信息收集网络。

另一类人,则是凭借技术分析与运气进行趋势判断的投机者,最后结果往往如**「投机之王」杰西·利弗莫尔** 一样悲惨。

期货作为一场零和游戏,它更像一个赌局,那些稳赢不输的人,不是因为他们有好运气与好牌技,而是因为他们有「特异功能」可以看到所有的牌,能够提前预测到结果。

图:电影《赌神》剧照

​在连拉普拉斯妖都无法预测的人类经济领域中,能赚到钱的是那些真正知道自己在做什么的人,因为成功离不开专业化,投资世界也不例外。

正如股神巴菲特所说:

同上帝一样,市场会帮助那些帮助他们自己的人。同上帝不一样的是,市场从来不原谅那些不知道自己在做什么的人。

——沃伦·巴菲特

记住,永远只投资于自己真正懂的领域

8102 年的程序员不需要 Hosts 和 Fiddler

加入鹅厂之后,我发现团队都在用一款叫做 Whistle 的工具,起初我以为这只是一款类似 Fiddler/Charles 的普通货色。然鹅,发现下面这两种用法之后,我把自己的膝盖摘下来献给了制作这款工具的大佬。

如果你还没用过 whistle,没关系。只需两步:

  1. 第一步,Node.js 环境下全局安装 npm i -g whistle 并启动 whistle w2 start
  2. 第二步,给 Chrome 浏览器装个 SwitchyOmega 的插件,添加一个将所有请求转发到 127.0.0.1:8899 的代理配置。如下图所示(Bypass List 部分也记得清掉)

switchyomega

环境准备好之后,我们开始进入今天的姿势,看 whistle 是如何取代本地 hosts 和 web server 的。

1、搭建静态资源 server

打开 whistle 管理后台 http://127.0.0.1:8899 ,在左侧导航的 Rules 面板写入一条规则:

# 规则:自定义域名或URL<空格>本地目录路径 (以下示例请替换为自己本地的写法)
my.demo/bw/ file:///Users/kaiye/Projects/Demo/002-black-white/

再用浏览器打开 http://my.demo/bw/ 的网址。Bingo!一个自定义域名的静态资源服务器搭建成功!

是不是比 nginx 配置简单一丢丢?如果安装了 whistle 的证书,还能直接支持 HTTPS!

2、动态 server 转发

如果我们把上例中的本地路径替换成一个本地服务端口,例如 webpack devServer 的端口。那么就可以实现本地带端口号的 host 配置功能,同时还能告别复杂的 devServer/nginx rewrite 配置:

// webpack.config.js 配置传统手艺
module.exports = {
  //...
  devServer: {
    proxy: {
      '/api': {
        target: ''https://other-server.example.com'',
        pathRewrite: {'^/api' : ''}
      }
    }
  }
};

假设本地 webpack 服务端口号为 8080,whistle 的配置规则示例如下:

# 任意域名绑定到本地任意服务
https://my.demo/ 127.0.0.1:8080

# 重写该域名的后端接口路径到线上服务地址
https://my.demo/api/ https://backend.example.com/api/
# 或直接转发到局域网某台机器的具体端口
https://my.demo/api2/ http://127.0.0.1:3000

接下来就可以打开 https://my.demo/ 像调试线上环境一样开发本地环境了。你还可以将 whistle 部署到局域网服务器,用来搭建一个多人协作的测试环境(也就是 nohost 解决方案)。

whistle 是一款免费且强大的抓包工具,除了本文提到的静态 server 和服务转发功能以外,还提供了大量内置协议用于支持 request/respond 动态修改与注入、websocket 调试、API mock 等功能,借助 whistle plugin 插件生态,不仅能获得极佳的移动端调试体验,还能满足各式各样的调试需求。更多 whistle 介绍,请访问 whistle 官网

如果你有关于环境搭建的问题和建议,欢迎留言交流。

新编辑器之神 VSCode VIM

这个世界上有 10 类程序员,一类是会用 VIM 的,另一类是不会的。

VIM 是一款命令行文本编辑器,内置于 macOS 和 Linux 操作系统中,它发明于上个世纪 80 年代。由于没有鼠标支持,所以 VIM 和现代编辑器的使用方式有很大的不同。

基于其独特的设计方式和高效的编辑效率,VIM 获得了“编辑器之神”的美誉,而使用 VIM 的程序员通常有着惊人的手速和强烈的极客精神。

VSCode + VIM 快捷键组合

VSCode 是一款完美的编辑器,现在它已经成长为 Github 上最大的开源项目。其官方团队的吕鹏,在他的极客时间专栏《玩转 VS Code》(已绝版)中,花费了大量篇幅来讲解其快捷键设计理念。

为了能将 VSCode + VIM 的快捷键组合效率最大化,VSCode 官方团队选择自己亲自维护 VIM 插件。

VSCode VIM 示例

如以上示例图所示,组合使用 VSCode 快捷键和 VIM 快捷键,能在不使用鼠标的前提下,快速地实现以下操作:

  • vib 选中小括号内的代码块
  • S Visual 模式下,使用 VSCode VIM 内置的 Surround 插件,在代码块外插入 HTML Tag
  • af Visual 模式下,快速选中更大范围代码块
  • % 跳转至对应的括号对({[]})
  • ⌘⇧\ 跳转至相应的符号对(VSCode 快捷键)
  • gd 跳转至代码定义处
  • ctrl+o (从代码定义处)跳转回上次代码位置
  • ⌘s 保存文件(VSCode 快捷键)

注:本文所有快捷键基于 macOS 配置,Windows 版 VSCode 快捷键主要区别是将 ⌘ 替换成 ctrl,其他 VIM 命令基本一致。

VIM 快速入门

想要精通 VIM 需要花费大量时间进行练习,形成肌肉记忆。而本文的目的,主要是为了让大家能快速上手如何在 VSCode 中使用 VIM(已经会 VIM 基本操作的朋友,可直接跳至下一章节)。

普通编辑器只有 1 种编辑模式,而 VIM 却有 6 种基本模式和 5 种派生模式。而在 VSCode 中,我们只需要使用以下三种模式,即可大幅提升编辑效率:

  • Normal Mode:默认模式,通常用于光标位置切换,使用复制、粘贴、删除等命令;在其他模式下,按下 ESC 键,即可回到 Normal Mode;
  • Insert Mode:插入模式,在 Normal 模式下,按下 io 等键,即可进入插入模式;
  • Visual Mode:可视化模式,一般用于文本的选择,Normal 模式下,按下字母 v 即可进入可视化选择模式。

建议没有用过 VIM 的同学,安装上 VSCode VIM 插件后,按以下命令熟悉一下:

  1. ⌘ ⇧ P Toggle VIM Mode。如果按下 ESC 键后,光标形态没有变化,则说明 VIM 插件未生效,继续 Toggle 切换,在编辑器左下角会显示当前模式;
  2. ⌘ N 新建一个文档,按下 i 进入 Insert Mode。键入 hello world
  3. 按下 ESC 回到 Normal Mode。按下 yyp 复制并粘贴该行;分别通过 hjkl 键来改变光标四个方向的位置;
  4. 按下 v 键进入 Visual Mode,继续按下 iw ,选中光标当前位置所在的单词,最后按下 d 删除该单词。

macOS VSCode VIM 插件配置

在 VSCode Settings 设置中,加入以下配置,能让 VSCode 和 VIM 结合的更好:

{
  // VIM 使用系统剪切板,将 ⌘C ⌘V 的内容和 YP 打通
  "vim.useSystemClipboard": true,
  // VIM 将以下快捷键返回给 VSCode 处理,效果是既可以使用 VIM 光标移位快捷键,也可以使用 VSCode 快捷键来移位
  "vim.handleKeys": {
    "<C-a>": false,
    "<C-e>": false,
    "<C-b>": false,
    "<C-f>": false,
    "<C-n>": false,
    "<C-p>": false,
  },
  // Normal 模式下将 Ctrl+j 绑定成 VIM 的 Ctrl+d 向下翻页效果
  "vim.normalModeKeyBindingsNonRecursive": [
    {
      "before": [
        "<C-j>",
      ],
      "commands": [
        "extension.vim_ctrl+d"
      ]
    },
    // <leader> 键默认为 \,按下 \f 能在 finder 中选中当前文件
    {
      "before": ["<leader>", "f"],
      "commands": ["workbench.action.files.revealActiveFileInWindows"]
    }
  ],
}

在 macOS VSCode 中默认的 Ctrl+d 为向后删除,安装上 VIM 插件后,默认的删除命令会被 VIM 的翻页命令覆盖。我们可以在 VSCode Keyboard Shortcuts 中配置以下内容,删除 VIM Ctrl+d 快捷键绑定(翻页由以上配置重新定义为 Ctrl+j):

[
  {
    "key": "ctrl+d",
    "command": "-extension.vim_ctrl+d",
    "when": "editorTextFocus && vim.active && !inDebugRepl"
  },
]

VIM Cheatsheet

VIM 的快捷命令非常多,一般人很难全部记住。但幸运地是,在 VSCode VIM 中,你可以同时使用 VSCode 快捷键加鼠标来解决问题,这要比直接使用 VIM 命令行的体验好得多。

以下是一些不错的 VIM 快捷 Cheatsheet,希望对你有所帮助。

https://www.barbarianmeetscoding.com/boost-your-coding-fu-with-vscode-and-vim/cheatsheet/

https://github.com/skywind3000/awesome-cheatsheets/blob/master/editors/vim.txt

十分钟学会 tmux

tmux 是一款终端复用命令行工具,一般用于 Terminal 的窗口管理。在 macOS 下,使用 iTerm2 能应付绝大多数窗口管理的需求。

iTerm2 的窗口管理

如上图所示,iTerm2 能新建多个标签页(快捷键 ⌘T),也能在同一个窗口中分割出多个窗格(快捷键 ⌘D 或 ⌘⇧D)。

tmux 相比 iTerm2 的优势在于:

  • iTerm2 的窗格切换快捷键(⌘⌥→)容易与其他软件全局快捷键冲突(例如 Spectacle 的窗口分割快捷键),tmux 由于存在前缀快捷键,所以不存在快捷键冲突问题;
  • tmux 可以在终端软件重启后通过命令行恢复上次的 session ,而终端软件则不行;
  • tmux 简洁优雅、订制性强,学会之后也能在 Linux 上使用,有助于逼格提升。

接下来我们花十分钟来掌握下 tmux 的基础用法:

安装运行

macOS 上使用 Homebrew 安装即可:

brew install tmux

安装完成后,运行 tmux 新建一个 tmux 的会话(session),此时窗口唯一的变化是在底部会出现一个 tmux 的状态栏。我们先按下 tmux 默认的前缀快捷键 ⌃b 将其激活为快捷键接收模式,再按下 % ,即可将当前窗口切分为左右两个窗格。

tmux 窗格

快捷键

一般情况下 tmux 中所有的快捷键都需要和前缀快捷键 ⌃b 来组合使用(注:⌃ 为 Mac 的 control 键),以下是常用的窗格(pane)快捷键列表,大家可以依次尝试下:

窗格操作

  • % 左右平分出两个窗格
  • " 上下平分出两个窗格
  • x 关闭当前窗格
  • { 当前窗格前移
  • } 当前窗格后移
  • ; 选择上次使用的窗格
  • o 选择下一个窗格,也可以使用上下左右方向键来选择
  • space 切换窗格布局,tmux 内置了五种窗格布局,也可以通过 ⌥1⌥5 来切换
  • z 最大化当前窗格,再次执行可恢复原来大小
  • q 显示所有窗格的序号,在序号出现期间按下对应的数字,即可跳转至对应的窗格

窗口操作

tmux 除了窗格以外,还有窗口(window) 的概念。依次使用以下快捷键来熟悉 tmux 的窗口操作:

  • c 新建窗口,此时当前窗口会切换至新窗口,不影响原有窗口的状态
  • p 切换至上一窗口
  • n 切换至下一窗口
  • w 窗口列表选择,注意 macOS 下使用 ⌃p⌃n 进行上下选择
  • & 关闭当前窗口
  • , 重命名窗口,可以使用中文,重命名后能在 tmux 状态栏更快速的识别窗口 id
  • 0 切换至 0 号窗口,使用其他数字 id 切换至对应窗口
  • f 根据窗口名搜索选择窗口,可模糊匹配

tmux 状态栏说明

会话操作

如果运行了多次 tmux 命令则会开启多个 tmux 会话(session)。在 tmux 会话中,使用前缀快捷键 ⌃b 配合以下快捷键可操作会话:

  • $ 重命名当前会话
  • s 选择会话列表
  • d detach 当前会话,运行后将会退出 tmux 进程,返回至 shell 主进程

在 shell 主进程下运行以下命令可以操作 tmux 会话:

tmux new -s foo # 新建名称为 foo 的会话
tmux ls # 列出所有 tmux 会话
tmux a # 恢复至上一次的会话
tmux a -t foo # 恢复名称为 foo 的会话,会话默认名称为数字
tmux kill-session -t foo # 删除名称为 foo 的会话
tmux kill-server # 删除所有的会话

除以上提到的快捷键以外,tmux 还有许多其他的快捷键和命令,使用前缀快捷键 ⌃b? 可以查看所有的快捷键列表,该列表视图为 tmux copy 模式,该模式下可使用以下快捷键(无需加 ⌃b 前缀):

  • ⌃v 下一页
  • Meta v 上一页 (tmux 快捷键为 Emacs 风格,这里的 Meta 键可用 Esc 模拟)
  • ⌃s 向前搜索
  • q 退出 copy 模式

常见配置与问题

1、鼠标滚屏

tmux 默认配置中最糟糕的体验就是滚屏查看和文本复制(大家可以先试试看)。你需要先使用 ⌃b [ 快捷键进入 copy 模式,然后使用翻页、字符定位来选择需要的字符,效率远没有鼠标选择来的快。

因此 tmux 提供了一些个性化配置项来优化这些配置,首先在 shell 中运行 touch ~/.tmux.conf 新建用户配置文件。在文件中增加以下内容:

# 开启鼠标模式
set -g mode-mouse on

# 允许鼠标选择窗格
set -g mouse-select-pane on

# 如果喜欢给窗口自定义命名,那么需要关闭窗口的自动命名
set-option -g allow-rename off

# 如果对 vim 比较熟悉,可以将 copy mode 的快捷键换成 vi 模式
set-window-option -g mode-keys vi

配置文件修改完成后,可以 tmux kill-server 重启所有 tmux 进程,或者在 tmux 会话中使用 ⌃b : 进入控制台模式,输入 source-file ~/.tmux.conf 命令重新加载配置。

注意:tmux 2.1 以上版本(使用 tmux -V 命令可查看版本号)对鼠标模式配置有调整,需要将以上配置文件中的前两项配置替换成 set-option -g mouse on 这一项配置。

2、鼠标复制

tmux 下开启鼠标滚屏后,复制文本有两种方式:

  • 方法 1:使用 ⌃b z 进入窗格全屏模式,鼠标选择文本的同时按住 option 键 ,然后使用 ⌘c 进行复制;
  • 方法 2:开启 iTerm2 「在选择时复制」选项,即可实现自动选择复制。如下图:

iTerm2 配置在选择时复制

3、tips

  • screen 是另外一款终端复用命令行,但他没有 tmux 好看好用;
  • tmux 有个 bug ,导致从它启动的 vscode 的复制粘贴快捷键会失效;
  • iTerm2 可以通过 「Preferences -> Profiles -> Keyboard Behavior -> Left option key acts as +Esc」将键盘的左侧 option 键映射为 Meta 键
  • zsh-autosuggestions 插件在 tmux 环境下有配色高亮的 bug,解决方案是在 .zshrc 文件中配置 export TERM=xterm-256color

另外,最近看到两篇不错的 awksed 命令入门,感兴趣的同学可以自己看一下。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.