Homebrew介绍和使用

一、Homebrew是什么

Homebrew是一款Mac OS平台下的软件包管理工具,拥有安装、卸载、更新、查看、搜索等很多实用的功能。简单的一条指令,就可以实现包管理,而不用你关心各种依赖和文件路径的情况,十分方便快捷。
援引 官方 的一句话:又提示缺少套件啦?别担心,Homebrew 随时守候。Homebrew —— OS X 不可或缺的套件管理器。

阅读更多

Node.js的版本升级

查看本地node版本

node -v

安装n模块

npm install -g n(mac需要在命令的前面加上sudo)

升级到指定的版本/最新版本,升级之前,可以执行n ls(查看可以升级的版本)

n 8.10.1(版本号)
或者你可以安装最新的稳定版本
n stable

4.安装完成以后,检查一下是否升级成功

node -v

Linux软连接和硬链接

Linux软连接和硬链接

Linux链接概念

Linux链接分两种,一种被称为硬链接(Hard Link),另一种被称为符号链接(Symbolic Link)。默认情况下,ln命令产生硬链接。

【硬连接】

硬连接指通过索引节点来进行连接。在Linux的文件系统中,保存在磁盘分区中的文件不管是什么类型都给它分配一个编号,称为索引节点号(Inode Index)。在Linux中,多个文件名指向同一索引节点是存在的。一般这种连接就是硬连接。硬连接的作用是允许一个文件拥有多个有效路径名,这样用户就可以建立硬连接到重要文件,以防止“误删”的功能。其原因如上所述,因为对应该目录的索引节点有一个以上的连接。只删除一个连接并不影响索引节点本身和其它的连接,只有当最后一个连接被删除后,文件的数据块及目录的连接才会被释放。也就是说,文件真正删除的条件是与之相关的所有硬连接文件均被删除。

【软连接】

另外一种连接称之为符号连接(Symbolic Link),也叫软连接。软链接文件有类似于Windows的快捷方式。它实际上是一个特殊的文件。在符号连接中,文件实际上是一个文本文件,其中包含的有另一文件的位置信息。

阅读更多

iframe 报错 Refused to display 'URL' in a frame because it set 'X-Frame-Options' to 'DENY'

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/X-Frame-Options

X-Frame-Options 有三个值:

  • DENY
    表示该页面不允许在 frame 中展示,即便是在相同域名的页面中嵌套也不允许。

  • SAMEORIGIN
    表示该页面可以在相同域名页面的 frame 中展示。

  • ALLOW-FROM uri
    表示该页面可以在指定来源的 frame 中展示。

换一句话说,如果设置为 DENY,不光在别人的网站 frame 嵌入时会无法加载,在同域名页面中同样会无法加载。另一方面,如果设置为 SAMEORIGIN,那么页面就可以在同域名页面的 frame 中嵌套。

express 配置

const helmet = require('helmet');
const app = express();
app.use(helmet.frameguard({ action: 'SAMEORIGIN' }))

或者使用:

const frameguard = require('frameguard')
app.use(frameguard({ action: 'SAMEORIGIN' }))

泛型

介绍

软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。

在像C#和Java这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。

阅读更多

接口

介绍

TypeScript 的核心原则之一是对值所具有的_结构_进行类型检查。 它有时被称做“鸭式辨型法”或“结构性子类型化”。 在 TypeScript 里,接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约。

阅读更多

为什么要用setTimeout来模拟setInterval

setTimeout(fn,time): 等待time时间后执行fn
setInterval(fn,time): 每隔time时间执行fn

我们希望setInterval是每隔一段时间自动执行,但是实际应用中,setInterval并不会按照我们预想的那样,它通常存在如下两个缺点。

1. 在执行的时候可能会跳过指定时间间隔
2. 多个定时器函数会立刻执行

我们就实际场景来说一下这两个缺陷

阅读更多

枚举

枚举

使用枚举我们可以定义一些带名字的常量。 使用枚举可以清晰地表达意图或创建一组有区别的用例。 TypeScript支持数字的和基于字符串的枚举。

阅读更多

ios 提醒事项同步日历快捷指令脚本

  • AppStore 安装运行脚本的软件 scriptable

scriptable https://docs.scriptable.app

const DUR_MONTH = 1

const startDate = new Date()
startDate.setMonth(startDate.getMonth() - DUR_MONTH)
console.log(`日历的开始时间 ${startDate.toLocaleDateString()}`)

const endDate = new Date()
endDate.setMonth(endDate.getMonth() + DUR_MONTH)
console.log(`日历的结束时间 ${endDate.toLocaleDateString()}`)

const reminders = await Reminder.allDueBetween(startDate, endDate)
console.log(`获取 ${reminders.length} 条提醒事项`)

var calendar = await Calendar.forEvents()

//获取日历名和对应的日历
var m_dict = {}
for (cal of calendar) {
    m_dict[cal.title] = cal
}

const events = await CalendarEvent.between(startDate, endDate, calendar)
console.log(`获取 ${events.length} 条日历`)

for (const reminder of reminders) {
    //reminder的标识符
    const id = reminder.identifier.split('-')[0]
    const targetNote = `🍧 ${id} 🍰`
    // 添加标识符存进备注 用来防止重复添加
    const [targetEvent] = events.filter(
        (e) => e.notes != null && e.notes.indexOf(targetNote) != -1
    ) //过滤重复的reminder
    if (!m_dict[reminder.calendar.title]) {
        console.warn('找不到日历' + reminder.calendar.title)
        continue
    }
    if (targetEvent) {
        //console.log(`找到已经创建的事项 ${reminder.title}`)
        updateEvent(targetEvent, reminder)
    } else {
        console.warn(`创建事项 ${reminder.title}${reminder.calendar.title}`)
        const newEvent = new CalendarEvent()
        const notes = reminder.notes ? reminder.notes : ''
        newEvent.notes = targetNote + '\n\n' + notes //要加入备注
        updateEvent(newEvent, reminder)
    }
}

Script.complete()

function updateEvent(event, reminder) {
    event.title = `${reminder.title}`
    cal_name = reminder.calendar.title
    cal = m_dict[cal_name]
    event.calendar = cal
    //已完成事项
    if (reminder.isCompleted) {
        event.title = `✅ ${reminder.title}`
        event.isAllDay = false
        event.startDate = reminder.completionDate
        var ending = new Date(reminder.completionDate)
        ending.setHours(ending.getHours() + 1)
        event.endDate = ending

        var period =
            (reminder.dueDate - reminder.completionDate) / 1000 / 3600 / 24
        period = period.toFixed(1)
        if (period < 0) {
            period = -period
            event.location = ' 延期' + period + '天完成'
        } else if (period == 0) {
            event.location = ' 准时完成'
        } else {
            event.location = ' 提前' + period + '天完成'
        }
    }
    //未完成事项
    else {
        const nowtime = new Date()
        var period = (reminder.dueDate - nowtime) / 1000 / 3600 / 24
        period = period.toFixed(1)
        if (period < 0) {
            //待办顺延

            event.location = ' 延期' + -period + '天'
            //如果不是在同一天,设置为全天事项
            if (reminder.dueDate.getDate() != nowtime.getDate()) {
                event.title = `❌ ${reminder.title}`
                event.startDate = nowtime
                event.endDate = nowtime
                event.isAllDay = true
            }
            //在同一天的保持原来的时间
            else {
                event.title = `⭕️ ${reminder.title}`
                event.isAllDay = false
                event.startDate = reminder.dueDate
                var ending = new Date(reminder.dueDate)
                ending.setHours(ending.getHours() + 1)
                event.endDate = ending
            }
            console.log(`【${reminder.title}】待办顺延${-period}天`)
        } else {
            event.title = `⭕️ ${reminder.title}`
            event.isAllDay = false
            event.location = '还剩' + period + '天'
            event.startDate = reminder.dueDate
            var ending = new Date(reminder.dueDate)
            ending.setHours(ending.getHours() + 1)
            event.endDate = ending
        }
    }
    event.save()
}
  • 提醒事项数据格式
{
  "identifier": "29803A1E-6C2F-454D-B366-2C67EB1F24BD",
  "title": "Recite word",
  "isCompleted": false,
  "isOverdue": true,
  "priority": 0,
  "dueDate": "2021-03-11T23:20:00.000Z",
  "dueDateIncludesTime": true,
  "completionDate": null,
  "creationDate": "2021-03-12T03:28:00.621Z",
  "calendar": {
    "identifier": "282088E0-DC16-4827-BA21-9B9FD5F0A16F",
    "title": "Learn",
    "isSubscribed": false,
    "allowsContentModifications": true,
    "color": {
      "hex": "FF2968",
      "red": 1,
      "green": 0.1607843041419983,
      "blue": 0.40784314274787903,
      "alpha": 1
    }
  }
}

ios 提醒事项同步日历快捷指令脚本

介绍

传统的JavaScript程序使用函数和基于原型的继承来创建可重用的组件,但对于熟悉使用面向对象方式的程序员来讲就有些棘手,因为他们用的是基于类的继承并且对象是由类构建出来的。 从ECMAScript 2015,也就是ECMAScript 6开始,JavaScript程序员将能够使用基于类的面向对象的方式。 使用TypeScript,我们允许开发者现在就使用这些特性,并且编译后的JavaScript可以在所有主流浏览器和平台上运行,而不需要等到下个JavaScript版本。

阅读更多