海屿文章列表

HP 440 G5 安装黑苹果

  • 这里选择最新镜像下载
  • 使用 balenaEtcher 烧录至U盘
  • BIOS设置

    • 启用UEFI启动
    • 禁用安全启动
    • 禁用快速启动
    • IGPU图形内存设置为64mb(Broadwell和Skylake)
    • 如果可用,通过BIOS选项禁用串行端口
    • 如果可用,禁用“LAN / WLAN切换”
    • 禁用“局域网唤醒”和“USB唤醒”
  • 下载EFI文件并将其放到引导分区中,注意备份你之前的文件

其他注意事项:
安装完成后按F3显示隐藏启动项,第一次选择preboot进入
无线网卡无法驱动,需要用USB无线网卡。推荐comfast的wu810n无线网卡,十几块钱。驱动下载
耳机🎧驱动VoodooHDA.kext.zip

Typescript AOP 模式

AOP(Aspect Oriented Program)表示面向切面编程,它是OOP的补充,主要作用是将多个OOP模块中的通用代码抽取出来。切面的意思是系统中的一些通用功能,例如日志记录,缓存或验证。

例如,下面代码包含了日志记录等功能全部耦合在代码中,难以维护。

function sample(arg: string) {
    console.log("sample: " + arg);
    if(!isUserAuthenticated()) {
        throw new Error("User is not authenticated");
    }

    if(cache.has(arg)) {
        return cache.get(arg);
    }

    const result = 42; // TODO complex calculation
    cache.set(arg, result);
    return result;
}

通过TypeScript装饰器可以改写如下形式:

@log
@authorize
@cache
function sample(arg: string) {
    const result = 42;
    return result;
}

在JS中使用装饰器,可以参考该提案

基于布隆过滤器的依赖注入

如果你读过Shadowsocks或者Angular的代码,你会发现他里面都自己实现了一个布隆过滤器。
SS用他来匹配GFW名单,Angular中用来依赖注入服务名单。NodeInjector是Ivy渲染器引入的Angular注入器,它大量使用bloom过滤器来检索令牌。

Bloom过滤器的基本数据结构是位向量。

Bloom Filter原理:当一个元素被加入集合时,通过K个Hash函数将这个元素映射成一个位阵列(Bit array)中的K个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如果这些点有任何一个0,则被检索元素一定不在;如果都是1,则被检索元素很可能在。

Angular中的bloom比特位为256,因此我们有一个256位的向量,它被分成8个部分。

Angular 通过递增整数值生成(如果尚未定义)令牌的唯一ID,并将其置于静态__NG_ELEMENT_ID__属性。
它通过按位AND(&)运算符获取该数字并使其适合bloom大小,以便结果始终在0-255之间。

// 用原始 bloomBit 值决定检查那个 bloom 过滤器桶
// e.g: bf0 = [0 - 31], bf1 = [32 - 63], bf2 = [64 - 95], bf3 = [96 - 127], etc
const b7 = bloomBit & 0x80;
const b6 = bloomBit & 0x40;
const b5 = bloomBit & 0x20;
const tData = tView.data as number[];

if (b7) {
  b6 ? (b5 ? (tData[injectorIndex + 7] |= mask) : (tData[injectorIndex + 6] |= mask)) :
       (b5 ? (tData[injectorIndex + 5] |= mask) : (tData[injectorIndex + 4] |= mask));
} else {
  b6 ? (b5 ? (tData[injectorIndex + 3] |= mask) : (tData[injectorIndex + 2] |= mask)) :
       (b5 ? (tData[injectorIndex + 1] |= mask) : (tData[injectorIndex] |= mask));
}

代码都是位运算,看起来挺复杂,其实就是将2^bloomBit位置为1。下面是一个简单例子:

const bloomBit = 3 % 255 // 3
const mask = 1 << bloomBit;
             1 << 3 // 8
8..toString(2) // 1000
                           
1 bucket          00000000000000000000000000001000
....
8 bucket          00000000000000000000000000000000    

获取系统字体列表两种思路

浏览器没有获取本地字体列表的API,同时FLash也被浏览抛弃。需要一种新的方式判断字体是否支持。
下图列出了一些字体,特征各不一样。最直观的是字形,其次不同字体下的相同文字的宽度也是不一样的,由此我们能通过这两点差异对字体进行判断。
ziti.jpg

字体宽度

每种字体的宽度都不尽相同。
我们可以通过分别测量默认字体和目标字体的宽度,查看二者的差异。若果不一致则说明目标字体可用,否则说明不支持该字体,浏览器会退到了默认字体。

font-load-detection-three.c10e6f652d.png

在canvas中可以使用measureText测量文字渲染的宽度,这个宽度非常精确。

var canvas = document.createElement('canvas')
var ctx = canvas.getContext("2d");
var width = ctx.measureText('123').width; // 21.111328125

使用ctx.font可以设置字号和字体,例如ctx.font="30px Arial",默认为10px sans-serif

我们可以提前计算好各种字体的宽度表,就可以快速地识别字体样式。

像素比对

根据用户设置的字体将某一个字符绘制在canvas上,并提取像素信息与默认字体进行比对,看是否一致。
这种方法最为准确,当然缺点也很明显就是计算量较大。

let isSupportFontFamily = function (f) {
  let base = "Arial";
  if (f.toLowerCase() == base.toLowerCase()) return true
  let e = "a";
  let d = 100;
  let a = 100, i = 100;
  let c = document.createElement("canvas");
  let b = c.getContext("2d");
  c.width = a;
  c.height = i;
  b.textAlign = "center";
  b.fillStyle = "black";
  b.textBaseline = "middle";
  let g = function (j) {
    b.clearRect(0, 0, a, i);
    b.font = d + "px " + j + ", " + base;
    b.fillText(e, a / 2, i / 2);
    let k = b.getImageData(0, 0, a, i).data;
    return [].slice.call(k).filter(l => l != 0);
  };

  return g(base).join("") !== g(f).join("");
};