Blog

English Time Expressions

English Time Expressions Guide #

Review

  1. 2019/12/08

This comprehensive guide covers the essential aspects of expressing time in English, including time points, centuries, years, months, and dates.

1. Time Point Expressions #

1.1 Basic Time Reading #

  • All times can be read directly as “hour + minute”:
    • 6:10 → six ten
    • 8:30 → eight thirty
    • 2:40 → two forty

1.2 Past and To Expressions #

  • For times within 30 minutes: “minutes + past + hour”

    ...

Website Protocol

请各位用户遵守下列协议:

  1. 遵纪守法
  2. 遵重人格
  3. 遵重人权
  4. 勿有歧视
  5. 倡导自由
  6. 恪守理性
  7. 敢于直言

用户协议

请各位用户遵守下列协议:

  1. 遵纪守法

    • 用户应遵守所在国家和地区的法律法规。
  2. 尊重人格

    • 用户应尊重他人的人格和尊严,不得进行人身攻击。
  3. 尊重人权

    • 用户应尊重他人的基本人权,不得侵犯他人的合法权益。
  4. 反对歧视

    • 用户不得基于种族、性别、宗教、年龄等进行歧视。
  5. 倡导自由

    • 用户应倡导言论自由,但不得传播虚假信息。
  6. 恪守理性

    • 用户应保持理性,避免情绪化言论。
  7. 敢于直言

    • 用户应勇于表达自己的观点,但需基于事实。
  8. 保护隐私

    • 用户应尊重他人的隐私,不得未经允许收集或传播他人信息。
  9. 维护安全

    • 用户应维护网络安全,不得进行任何破坏性行为。

IndexedDB Demo

IndexedDB Demo #

interface IData {
  componentName: string;
  propName: string;
  voId: number;
  renterKey: string;
  componentName_voId: string;
}

class Database {
  private static _instance: Database;

  private connection;

  constructor() {
    const openRequest = indexedDB.open('development-database', 1);

    openRequest.onupgradeneeded = (e: any) => {
      const db = e.target.result;
      console.log('Database upgradeneeded');

      if (!db.objectStoreNames.contains('voStore')) {
        const store = db.createObjectStore('voStore', { keyPath: 'componentName_voId' });
        store.createIndex('componentName_voId', 'componentName_voId', { unique: true });
        store.createIndex('componentName', 'componentName', { unique: false });
        store.createIndex('voId', 'voId', { unique: false });
      }
    };

    openRequest.onsuccess = (e: any) => {
      const db = e.target.result;
      this.connection = db;
    };

    openRequest.onerror = (e: any) => {
      console.log('Database init error', e.target.error.name);
    };
  }

  static getDB() {
    if (!Database._instance) {
      Database._instance = new Database();
    }
    return Database._instance;
  }

  // 更新所有跟 componentName 相关的数据
  public updateByComponentName(list: IData[], componentName: string): Promise<{ code: number; msg: string; }> {
    return new Promise((resolve) => {
      const tx = this.connection.transaction('voStore', 'readwrite');
      const store = tx.objectStore('voStore');

      this._searchByComponentName(componentName, store).then((data) => {
        const listByName: IData[] = data;

        list.forEach((item) => {
          if (listByName.some((l) => item.componentName_voId === l.componentName_voId)) {
            // update
            const putRequest = store.put(item);
            putRequest.onsuccess = () => {
              console.log('update');
            };
          } else {
            // new add
            const addRequest = store.add(item);

            addRequest.onsuccess = () => {
              console.log('add');
            };
          }
        });

        // remove not found
        const removeList = listByName.filter((l) => list.every((i) => i.componentName_voId !== l.componentName_voId));
        removeList.forEach((l) => {
          const deleteRequest = store.delete(l.componentName_voId);
          deleteRequest.onsuccess = () => {
            console.log('delete');
          };
        });
      });

      tx.oncomplete = () => {
        resolve({
          code: 200,
          msg: '更新成功',
        });
      };
    });
  }

  private _searchByComponentName(componentName: string, store: any): Promise<IData[]> {
    return new Promise((resolve) => {
      const index = store.index('componentName');
      const getRequest = index.openCursor(IDBKeyRange.only(componentName));
      const result: IData[] = [];

      getRequest.onsuccess = (e) => {
        const cursor = e.target.result;

        if (cursor) {
          result.push(cursor.value);
          cursor.continue();
        } else {
          // 没有更多数据
          resolve(result);
        }
      };
    });
  }

  public searchByComponentName(componentName: string): Promise<IData[]> {
    const tx = this.connection.transaction('voStore', 'readwrite');
    const store = tx.objectStore('voStore');

    return new Promise((resolve) => {
      const index = store.index('componentName');
      const getRequest = index.openCursor(IDBKeyRange.only(componentName));
      const result: IData[] = [];

      getRequest.onsuccess = (e) => {
        const cursor = e.target.result;

        if (cursor) {
          result.push(cursor.value);
          cursor.continue();
        } else {
          // 没有更多数据
          resolve(result);
        }
      };
    });
  }
}

export default Database;

Reference #

https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API

...

Rechange Git History User

修改GIT History提交的姓名和邮箱 #

#!/bin/sh
git filter-branch --env-filter '
OLD_EMAIL="旧邮箱@example.com"
CORRECT_NAME="新姓名"
CORRECT_EMAIL="新邮箱@example.com"
if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]; then
    export GIT_COMMITTER_NAME="$CORRECT_NAME"
    export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]; then
    export GIT_AUTHOR_NAME="$CORRECT_NAME"
    export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags

替换脚本中的 OLD_EMAILCORRECT_NAMECORRECT_EMAIL 为实际值

chmod +x email.sh && ./email.sh
git push --force --all

网站内容防复制及追踪

I. 引言:网站内容保护的挑战在 #

数字时代,在线内容的价值日益凸显,但同时也面临着前所未有的脆弱性。数字信息的便捷性使得复制和传播变得轻而易举,这给内容创作者带来了知识产权盗窃、抄袭和收入损失等诸多问题。因此,网站所有者和内容创建者越来越关注如何有效地保护其在线内容。本文旨在探讨防止网站用户复制内容以及追踪此类尝试的各种方法。

II. 复制预防的技术实现 #

A. 使用 CSS 禁用文本选择 #

body {
  user-select: none;
}

虽然 JavaScript 也可以用于禁用文本选择(通过处理 selectstart 事件),但通常首选 CSS 方法,因为它更简单且效率更高。值得注意的是,即使使用 CSS 阻止了视觉上的文本选择,底层的文本内容仍然可能通过编程方式被访问。这意味着基于 CSS 的预防主要是针对普通用户的威慑,而不是一种强大的安全措施。

B. 使用 JavaScript 阻止右键单击上下文菜单 #

阻止用户右键单击网页是另一种常见的防止内容复制的技术。JavaScript 提供了多种方法来实现这一点。最常用的方法是使用 contextmenu 事件。当用户尝试右键单击页面上的某个元素时,会触发此事件。通过 JavaScript 拦截此事件并阻止其默认行为(显示上下文菜单),可以有效地禁用右键单击功能。

document.addEventListener("contextmenu", (event) => event.preventDefault());

此外,还可以使用 oncontextmenu HTML 属性直接在 HTML 元素中禁用右键单击,例如:

<div oncontextmenu="return false;"></div>

虽然这种方法更直接,但不如使用 addEventListener 灵活。addEventListener 通常被认为是处理 DOM 事件的更现代和更灵活的方式。

值得一提的是,CSS 也可以通过 pointer-events: none; 属性禁用右键单击功能。然而,这种方法的一个主要缺点是它也会禁用所有其他指针交互,例如点击,这在许多情况下是不可取的。因此,对于禁用右键单击上下文菜单,JavaScript 通常是更实用的选择。

阻止右键单击通常被用作防止用户轻松访问文本和图像的"复制"选项的一种手段。

C. 阻止键盘复制快捷键(Ctrl+C 等) #

除了禁用文本选择和右键单击之外,还可以使用 JavaScript 来尝试阻止用户使用键盘快捷键复制内容,例如 Ctrl+C(在 Windows 上)或 Command+C(在 macOS 上)。这通常通过监听 keydownkeyup 事件来实现。

...

macOS Remove MDM

禁用 macOS 上的远程管理(MDM) #

在Mac上,远程管理系统可以方便地进行各种管理任务,但有时需要将其移除,特别是在设备更换所有权或将设备从企业使用转为个人使用的情况下。

MDM 是一种技术,允许组织远程配置、管理和保护其拥有的设备,包括强制执行安全策略、部署应用程序和进行故障排除 。另一种形式的远程管理是 Apple 远程桌面,它与 MDM 不同,允许直接控制和观察屏幕 。当用户从公司回购这些曾经受管理的 MacBook 时,这些远程管理功能可能会仍然存在,从而限制用户对设备的完全控制。因此,移除所有形式的远程管理对于希望获得设备完全自主权的用户来说至关重要。

检查 #

检查 MDM 注册状态 #

如果设备未通过 Apple 的设备注册计划(DEP)注册,并且没有 MDM 注册,则可能会显示“Error fetching Device Enrollment configuration: Client is not DEP enabled.” 。如果设备已注册到 MDM,则此命令可能会显示相关的配置信息,包括 MDM 服务器的详细信息 。

sudo profiles show -type enrollment

show type

此命令可以返回不同的状态,例如“No MDM enrollment”(未进行 MDM 注册)、“MDM enrolled”(已进行 MDM 注册)、“DEP Enrolled”(已进行 DEP 注册)等 。

profiles status -type enrollment

status type

配置 #

当标准的 MDM 描述文件移除方法无效时,通常是因为设备受到了更高级别的管理,例如设备监管或通过 Apple 的设备注册计划(DEP)、Apple 商务管理(ABM)或 Apple 校园教务管理(ASM)进行的注册。

...

Hugo

Hugo Introduction #

Overview #

Hugo is a static site generator written in Go, optimized for speed and designed for flexibility. With its advanced templating system and fast asset pipelines, Hugo renders a complete site in seconds, often less.

Due to its flexible framework, multilingual support, and powerful taxonomy system, Hugo is widely used to create:

  • Corporate, government, nonprofit, education, news, event, and project sites
  • Documentation sites
  • Image portfolios
  • Landing pages
  • Business, professional, and personal blogs
  • Resumes and CVs

Hugo’s fast asset pipelines include:

...

Agent Overview

What’s Agent? #

An agent is an LLM equipped with instructions, tools and handoffs. This means that given an open-ended task, the LLM can autonomously plan how it will tackle the task, using tools to take actions and acquire data, and using handoffs to delegate tasks to sub-agents.

Orchestration

Agent Orchestration #

Orchestration refers to the flow of agents in your app. Which agents run, in what order, and how do they decide what happens next? There are two main ways to orchestrate agents:

  • Allowing the LLM to make decisions: this uses the intelligence of an LLM to plan, reason, and decide on what steps to take based on that.
  • Orchestrating via code: determining the flow of agents via your code.

Orchestrating via LLM #

An agent is an LLM equipped with instructions, tools and handoffs. This means that given an open-ended task, the LLM can autonomously plan how it will tackle the task, using tools to take actions and acquire data, and using handoffs to delegate tasks to sub-agents.

...

Openai Agent

OpenAI 新功能发布 #

2025/03/11 OpenAI 发布了新的功能

We believe agents will soon become integral to the workforce, significantly enhancing productivity across industries.

  • Response API:是 Assistant API 的升级版
  • 内置工具:WebSearch, File Search, Computer use agent, code interpreter
  • Agents SDK: 用于编排 Agent 的workflow,支持 single agent 和 multi agent
  • 监控工具:2个追踪 Agent 工作流,分别是 LogsTraces https://platform.openai.com/traces

Response API #

The Responses API is our new API primitive for leveraging OpenAI’s built-in tools to build agents. It combines the simplicity of Chat Completions with the tool-use capabilities of the Assistants API.

...