diff --git a/justfile b/justfile new file mode 100644 index 00000000000..204ba7e3d53 --- /dev/null +++ b/justfile @@ -0,0 +1,27 @@ +[private] +@default: + just --list --justfile {{justfile()}} + +# Show git status with color +status: + git add -u && git diff --color=always --staged --stat | tee + +# Pull current branch with rebase and autostash +pull: + git pull --rebase --autostash origin `git branch --show-current` + +# Install TikZ dependencies +prepare-tikz: + apk add texlive icu-data-full texmf-dist-latexextra texmf-dist-langchinese texmf-dist-pictures + apk add -X http://mirrors.aliyun.com/alpine/edge/testing pdf2svg + +# Convert TikZ files to SVG +tikz: + time node ./site/dist/scripts/tikz2svg.js ./notes/courses/cs221/assets/*.tikz + +# Optimize SVG files +svgo: + pnpm svgo ./notes/courses/cs221/assets/*.svg + +hello name: + @echo "Hello, {{name}} !" diff --git a/notes/ai/prompt-awesome.md b/notes/ai/prompt-awesome.md index 3213cfba5b4..8d09863d40b 100644 --- a/notes/ai/prompt-awesome.md +++ b/notes/ai/prompt-awesome.md @@ -10,6 +10,7 @@ tags: - [PlexPt/awesome-chatgpt-prompts-zh](https://github.com/PlexPt/awesome-chatgpt-prompts-zh) - ChatGPT 中文调教指南。各种场景使用指南。学习怎么让它听你的话。 - https://prompts.chat/ +- https://publicprompts.art/ - temperature - top_p - 主题 diff --git a/notes/db/relational/mysql/mysql-cookbook.md b/notes/db/relational/mysql/mysql-cookbook.md index 8545fe87f15..af14af5d9f9 100644 --- a/notes/db/relational/mysql/mysql-cookbook.md +++ b/notes/db/relational/mysql/mysql-cookbook.md @@ -27,3 +27,40 @@ WHERE ORDER BY total_bytes DESC; ``` + +## analyze_small_tables + +```sql +DELIMITER $$ + +CREATE PROCEDURE analyze_small_tables() +BEGIN + DECLARE done INT DEFAULT FALSE; + DECLARE schema_name VARCHAR(255); + DECLARE table_name VARCHAR(255); + DECLARE cur CURSOR FOR + SELECT table_schema, table_name + FROM table_size + WHERE table_schema not in ('information_schema', 'performance_schema', 'mysql','sys') + AND row_estimate < 10; + DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; + + OPEN cur; + + read_loop: LOOP + FETCH cur INTO schema_name, table_name; + IF done THEN + LEAVE read_loop; + END IF; + + SET @stmt = CONCAT('ANALYZE TABLE ', schema_name, '.', table_name); + PREPARE stmt FROM @stmt; + EXECUTE stmt; + DEALLOCATE PREPARE stmt; + END LOOP; + + CLOSE cur; +END$$ + +DELIMITER ; +``` diff --git a/notes/dev/build/just.md b/notes/dev/build/just.md index c1b6f2650d8..ec7c76cf6c4 100644 --- a/notes/dev/build/just.md +++ b/notes/dev/build/just.md @@ -4,15 +4,170 @@ title: just # just -:::caution +- [casey/just](https://github.com/casey/just) + - CC0-1.0, Rust + - command runner, **不是** 构建工具 + - 不需要 make 的 .PHONY + - 不需要 文件依赖管理 + - 能接收 命令行参数 + - 会加载 .env + - 支持自定义语言的 任务运行 + - 能够从子目录执行 +- 参考 + - Jetbrains [Just](https://plugins.jetbrains.com/plugin/18658-just) 插件 + - VSC [Just](https://marketplace.visualstudio.com/items?itemName=nefrob.vscode-just-syntax) 插件 + - [nefrob/vscode-just](https://github.com/nefrob/vscode-just) -- 自身功能非常受限 -- 不值得投入太多精力去折腾 +```bash +brew install just # macOS brew +apk add just # AlpineLinux -::: +just --list +just --list PATH # PATH 支持 :: 分割多个 +just --summary # 空格分割的所有 target -- [casey/just](https://github.com/casey/just) +just os=bsd # 修改变量 +just --set os bsd + +just --choose # 选择 target - 依赖 fzf +# 调用其他目录 +(cd foo && just build) +just foo/build +just foo/ + +just bar::b # 搜索 foo.just, foo/mod.just, foo/justfile, foo/.justfile + +just --fmt --check --unstable +just --dump # --dump-format json +just --timestamp recipe --timestamp-format '%H:%M:%S%.3f %Z' # strftime +``` + +## justfile + +- justfile, .justfile +- global - `just --global-justfile`, `just -g` + - $XDG_CONFIG_HOME/just/justfile + - $HOME/.config/just/justfile + - $HOME/justfile + - $HOME/.justfile + +| opt | for | +| -------- | --------------------------------------- | +quite | 静默模式 | +| fallback | 如果 recipe 不存在,尝试向上找 justfile | + +```justfile +mod bar # 定义模块名字 - 作为子命令运行 just bar b +mod foo 'PATH' # 从给定的 path 加载模块 mod.just, justfile, .justfile +mod? foo + +# 引入其他 justfile +import 'foo/bar.just' +import? 'foo/bar.just' + +# for Node.js +export PATH := "./node_modules/.bin:" + env_var('PATH') + +# 启用 unstable 特性 +# JUST_UNSTABLE +# 例如 [script(COMMAND)] +set unstable + +# 修改默认工作目录 +set working-directory := 'bar' + +alias b := build # 设置别名 + +set shell := ["bash", "-uc"] +set shell := ["zsh", "-cu"] # 修改 shell + +[private] +default: + @just --list --justfile {{justfile()}} + +# 注释 +js: + #!/usr/bin/env node + console.log('Greetings from JavaScript!') + +# 这种方式也保证所有都在一个 shell 运行而不是一行一个 shell +sh: + #!/usr/bin/env sh + hello='Yo' + echo "$hello from a shell script!" + +# 默认文档内容 +[doc('Say hello to someone.')] +hello name: + @echo "Hello, {{name}}!" + +[no-cd] # 避免 cd 到 justfile 所在目录 +build name: + @echo "Building {{name}}..." + +# 会读取 TEST_NAME 环境变量 +test $TEST_NAME="1": + +# 依赖可以带参数 +xbuild: (build "main") +# 透传参数,默认参数 +push target=xyz: (build target) +# 复杂默认参数 +test triple=(arch + "-unknown-unknown") input=(arch / "input.dat"): + +# varidic 参数 / 可变参数 +backup +FILES: +backup *FILES: + +[working-directory: 'bar'] # 针对命令修改工作目录 +@bar: + +# 执行顺序是 a b c d +b: a && c d + +[no-exit-message] +git *args: + @git {{args}} +``` + +- recipe + - private + - 以 `_` 开头为 private + - 者使用 `[private]` 标记为 private + - 不会在 list 显示 + - quite + - `set quiet` + - `[no-quiet]` 取消 quite + - `@line` + - `@recipe:` + - 默认 quiet, + - 在行首加 `@` 取消 quiet + - Shebang recipes 默认 quite +- 内置函数别名 + - `_directory` -> `_dir` + - `home_directory()` -> ``home_dir()` +- 内置函数 + - arch, num_cpus, os, os_family + - shell + - env(key) / env_var(key), env(key, default) / env_var_or_default(key, default) + - is_dependency() - 当前 recipe 作为依赖 运行 + - invocation_directory(), invocation_directory_native() + - justfile(), justfile_directory() + - source_file(), source_directory() + - just_executable() + - just_pid() + - error +- 字符串函数、 case 转换函数、路径函数、随机、hash、日期、版本号、 XDG 目录 +- console 颜色常量 +- recipe 属性 + - confirm, doc, extension, group, no-cd, no-exit-message, no-quiet, private, script + - working-directory + - positional-arguments + - linux, macos, unix, windows, openbsd +- 语法 + - if/else ```bash -brew install just # macOS brew +# 确保是单个命令 - 以免把 serve 当成参数 +just --one build serve ``` diff --git a/notes/dev/design/design-crm.md b/notes/dev/design/design-crm.md index 0df1983c4bb..4d12f0222d1 100644 --- a/notes/dev/design/design-crm.md +++ b/notes/dev/design/design-crm.md @@ -119,3 +119,91 @@ tags: - 多语言界面 - Multi-language Support - 多币种支持 - Multi-Currency Support - 多时区支持 - Multi-Timezone Support + +# 主要对象 + +## 线索 + +- **产生时机**: + - 当潜在客户表现出初步兴趣或行为时,例如: + - 通过线上表单、邮件订阅或广告活动提交信息 + - 参与研讨会、展会等市场活动 + - 访问网站并下载内容(如白皮书、案例分析等) + - 销售或市场团队主动开发与联系的潜在客户 +- **状态**: + - 线索尚未经过资格评估,属于前期阶段。 +- **生命周期**: + - 新建 + - 资格评估中 + - 转化为商机 + - 无效/作废 +- **负责人**: + - 市场团队 + - 销售开发代表(SDR) + +--- + +## 商机 + +- **产生时机**: + - 当线索被识别为有明确购买意向或需求时,例如: + - 客户表达购买意向或预算已明确 + - 进入销售漏斗,并与销售团队进行进一步沟通 + - 初步报价、产品展示或解决方案探讨 + - 通过线索资格评估,符合潜在客户标准 +- **状态**: + - 商机代表可能达成交易的销售机会,进入重点跟进阶段。 +- **生命周期**: + - 新建 + - 需求确认 + - 方案/报价中 + - 谈判/合同签署 + - 赢单/输单 +- **负责人**: + - 销售团队 + - 客户经理 + +--- + +## 联系人 {#contact} + +- **创建时机**: + - 当确定与某个个体建立了明确的联系关系时,例如: + - 线索转化为商机时,确认联系人信息 + - 通过商务沟通,明确具体负责人与决策人 + - 在客户组织中识别到需要维护和联系的个人 + - 联系人的角色(如采购经理、技术负责人等)已明确 +- **状态**: + - 联系人属于具体的人,通常与客户(Account)关联。 +- **生命周期**: + - 新建 + - 活跃 + - 不活跃 + - 失效 +- **负责人**: + - 销售团队 + - 客户服务代表 + +--- + +## 客户 {#account} + +- **创建时机**: + - 当潜在客户被认定为需要长期维护或有合作价值时,例如: + - 线索或商机转化为实际客户(完成交易后) + - 公司或组织被确认具有业务潜力并需要建立档案 + - 销售团队对目标客户进行系统管理与分配 + - 已签订合同或即将进入采购阶段 +- **状态**: + - 客户(Account)通常指的是企业、组织或个体客户的整体档案。 + - 账号(Account)会与多个联系人(Contact)和商机(Opportunity)关联。 +- **生命周期**: + - 新建 + - 活跃 + - 维护中 + - 不活跃 + - 关闭 +- **负责人**: + - 客户经理 + - 销售团队 + - 客户成功团队 diff --git a/notes/dev/design/design-erp.md b/notes/dev/design/design-erp.md index 5cf086be050..ca661f6710c 100644 --- a/notes/dev/design/design-erp.md +++ b/notes/dev/design/design-erp.md @@ -131,6 +131,7 @@ export interface AnyResource { state?: string; // 状态 - 粗粒度系统定义 status?: string; // 阶段 - 细粒度业务定义 + statusReason?: string; // 状态原因 stateLabel?: string; // 自动 resolve 出来的显示内容 statusLabel?: string; diff --git a/notes/dev/design/design-frontend.md b/notes/dev/design/design-frontend.md new file mode 100644 index 00000000000..a55fcbc4181 --- /dev/null +++ b/notes/dev/design/design-frontend.md @@ -0,0 +1,43 @@ +--- +tags: + - Frontend + - React +--- + +# Frontend + +# FAQ + +## 静态前端配置 + +> 加载 Bootstrap 配置 - 例如 API 地址 + +1. 构建时根据 branch 加载配置 + +```ts +import { defineConfig, loadEnv, type PluginOption } from 'vite'; +export default defineConfig(({ mode, command }) => { + const env = {}; + console.log(`Vite ${command} mode=${mode} branch=${process.env.CI_COMMIT_BRANCH || ''}`); + Object.assign(env, loadEnv(mode, process.cwd(), '')); + + // 加载 .env.branch 覆盖 + if (process.env.CI_COMMIT_BRANCH) { + Object.assign(env, loadEnv(process.env.CI_COMMIT_BRANCH, process.cwd(), '')); + } + process.env = Object.assign(process.env, env); + + return defineConfig({}); +}); +``` + +1. 部署时通过覆盖 json 配置 + - 请求 `${location.origin}/config.json` 获取配置 + - 允许配置不存在 + - 部署时可以将 /config.json 重定向 + - 部署时可以将 `/app/public/config.json` 内容进行替换 +1. 回滚到 `${location.origin}/api` 作为默认 API 地址 +1. 通过请求 API 获取配置 + - SaaS 场景 + - 允许用户输入租户 ID/名字 + - 服务端判断 referer/url 判断返回的配置信息 diff --git a/notes/dev/design/design-task.md b/notes/dev/design/design-task.md index bd9c0691f66..7db182a1322 100644 --- a/notes/dev/design/design-task.md +++ b/notes/dev/design/design-task.md @@ -5,6 +5,21 @@ tags: # 任务管理 +- Task Management System + - e.g. Trello, Jira, Asana +- Workflow Management System + - e.g. Camunda, Activiti +- Job Scheduling Systems + - e.g. Apache Airflow, Azkaban +- Business Process Management + - e.g. Bizagi, Appian, Pega +- 参考 + - Digital Archiving Workflow + - [CCA Digital Archives Processing Manual](https://github.com/CCA-Public/digital-archives-manual) + - CCA - Canadian Centre for Architecture - 加拿大建筑中心 + - https://github.com/amiaopensource/open-workflows + - [Digital preservation workflows](https://www.nationalarchives.gov.uk/archives-sector/advice-and-guidance/managing-your-collection/preserving-digital-collections/digital-preservation-workflows/) + ## 任务管理系统设计 ### 核心对象 diff --git a/notes/dev/format/jsonschema/README.md b/notes/dev/format/jsonschema/README.md index dd020ee9de9..6bf0b67c86c 100644 --- a/notes/dev/format/jsonschema/README.md +++ b/notes/dev/format/jsonschema/README.md @@ -398,3 +398,9 @@ interface JSONSchema { ``` - protobufjs 使用 long 包 + +## Bundle + +- `$defs` +- https://json-schema.org/blog/posts/bundling-json-schema-compound-documents +- https://json-schema.org/understanding-json-schema/structuring diff --git a/notes/devops/container/buildkit.md b/notes/devops/container/buildkit.md index 1682d8037d5..6106b12012c 100644 --- a/notes/devops/container/buildkit.md +++ b/notes/devops/container/buildkit.md @@ -51,6 +51,10 @@ docker buildx build -t test . docker buildx build --platform linux/amd64,linux/arm64 --pull --push -t test . ``` +| env | value | notes | +| ----------------- | ----- | ---------------------- | +| BUILDKIT_PROGRESS | auto | auto,plain,tty,rawjson | + - driver - docker - docker-container diff --git a/notes/devops/web/caddy/README.md b/notes/devops/web/caddy/README.md index 92994c3b803..0c7591f1cb1 100644 --- a/notes/devops/web/caddy/README.md +++ b/notes/devops/web/caddy/README.md @@ -63,6 +63,18 @@ caddy add-package github.com/caddy-dns/cloudflare - Named matchers - `@name` - 表达式 匹配 - https://github.com/google/cel-spec +- placeholders + - https://caddyserver.com/docs/caddyfile/concepts#placeholders + - https://caddyserver.com/docs/json/apps/http/#docs + - https://caddyserver.com/docs/conventions#placeholders + +:::caution + +- log format append 的 value 只支持 global 的 placeholder + - 因为日志是在 HTTP 请求上下文之外处理的 + - 不支持 per-request placeholders + +::: ``` @mutable `{method}.startsWith("P")` diff --git a/notes/languages/parser/peg/interfaces.peggy b/notes/languages/parser/peg/interfaces.peggy new file mode 100644 index 00000000000..67e4e2422ae --- /dev/null +++ b/notes/languages/parser/peg/interfaces.peggy @@ -0,0 +1,141 @@ +/* +Grammar for interfaces + +grammar: https://github.com/wenerme/wener/blob/master/notes/languages/parser/peg/interfaces.peggy +playground: https://peggyjs.org/online +================================ + +- https://github.com/ifupdown-ng/ifupdown-ng/blob/main/doc/interfaces.scd +- https://github.com/ifupdown-ng/ifupdown-ng/blob/972644e4bff23b8637cc8d6ecf040f28ca504038/libifupdown/interface-file.c#L475-L488 + +================================ + +auto br0 +iface br0 + use bridge + requires bond0 + address 203.0.113.2/24 + gateway 203.0.113.1 + address 203.0.113.2/24 + address 2001:db8:1000:2::2/64 + gateway 203.0.113.1 + gateway 2001:db8:1000:2::1 + +iface bond0 + use bond + requires eth0 eth1 + bond-mode 802.3ad + bond-xmit-hash-policy layer2+3 +iface home inet dhcp + +*/ + +{ + var section; + var last; + function push(v) { + v.line = location().start.line; + if (!v.comment) delete v.comment; + if (!v.notes) delete v.notes; + + switch (v.type) { + case "Interface": + case "Template": + section = v; + break; + case "Auto": + case "Source": + case "SourceDirectory": + section = null; + break; + case "Comment": + break; + } + + let out = v; + if (section && section !== v) { + section.children ||= []; + section.children.push(v); + out = null; + } + return out; + } + function finalize(lines) { + lines = lines.flatMap((v) => v).filter(Boolean); + // todo attach comment + return lines; + } + + function iface(v) { + if (v.type === "template") { + v.type = "Template"; + } else { + v.type = "Interface"; + } + // todo tags to executor, extract inherits + return push(v); + } +} + +Main = lines:(@Line NL)* EOF { return finalize(lines); } + +Line + = comment:Comment { return push({ type: "Comment", comment }); } + / _ "auto" _ name:ident notes:Comment? { + return push({ type: "Auto", name, notes }); + } + / _ "source" _ filename:Value notes:Comment? { + return push({ type: "Source", filename, notes }); + } + / _ "source-directory" _ directory:Value notes:Comment? { + return push({ type: "SourceDirectory", directory, notes }); + } + / _ + type:("iface" / "interface" / "template") + __ + name:ident + _ + tags:("inet" / "dhcp" / "loopback" / "ppp" / "inherits" __ ident)|.., __| + notes:Comment? { return iface({ type, name, tags, notes }); } + / _ key:Keyword _ value:Value notes:Comment? { + return push({ type: "Keyword", key, value, notes }); + } + / _ { return push({ type: "EmptyLine" }); } + +Comment = _ "#" comment:CommentText? { return comment?.trim(); } + +CommentText = chars:(!NL .)* { return text(); } + +Keyword = chars:[a-zA-Z0-9]+ { return text(); } + +Value = chars:(!(NL / "#") .)+ { return text().trim(); } + +ident = ([a-zA-Z] [_a-zA-Z0-9]*) { return text(); } + +ip + = ipv4 + / ipv6 + +cidr = ip "/" [0-9]+ + +ipv4 = ipv4_part "." ipv4_part "." ipv4_part "." ipv4_part + +ipv4_part + = [0-9] + / [1-9] [0-9] + / "1" [0-9] [0-9] + / "2" [0-4] [0-9] + / "25" [0-5] + +ipv6 = [0-9a-fA-F:]+ + +EOF = !. + +NL + = "\r\n" + / "\n" + / "\r" + +_ = [ \t]* + +__ = [ \t]+ diff --git a/notes/languages/parser/peg/miniquery.peggy b/notes/languages/parser/peg/miniquery.peggy new file mode 100644 index 00000000000..7414c32833a --- /dev/null +++ b/notes/languages/parser/peg/miniquery.peggy @@ -0,0 +1,381 @@ +/* +Grammar for MiniQuery AST + +grammar: https://github.com/wenerme/wener/blob/master/notes/languages/parser/peg/miniquery.peggy +playground: https://peggyjs.org/online +================================ + +- https://www.postgresql.org/docs/current/sql-select.html +- https://www.postgresql.org/docs/current/sql-expressions.html +- https://google.aip.dev/160 +- https://www.sqlite.org/syntaxdiagrams.html +- https://github.com/florajs/sql-parser/blob/main/sql.pegjs + +Examples +========== + +-- test +(id > 10) and b < 10 or ( +1 = 1 +-- comment +or a in [] +or a in () -- a +or a not in [] +or a not in () +or a is true +or a is false +or a is not true +or a is not false +or a is null +or a is not null +or a like '%a%' +or a not like '%a%' +or a between 1 and 2 +or a between "11" and "12" +or a in [1,] +or a in [1,1.1,true,false,null,b] +or a > now() +or a > +1.0 +or a < -.1 +and a > date(col) +and b > date( col1, ) +and b<>date( c1,1,.1,true, null,) +and true +and false +and 1 +and "1" +and a.b.c > 1 +and a > 1 +-- comment +or (b < 2 or c.d.e = true ) +-- +and a not in [1,2,3,] +and a between 1 and 2 +-- contains +and tags @> ['Hello'] +and !( tags @> ['Hello'] ) +) +*/ + +{ + /* eslint-disable @typescript-eslint/interface-name-prefix,@typescript-eslint/no-empty-interface,no-case-declarations,no-control-regex,prefer-const */ + // ts-nocheck + + function logic(op, left, right) { + if (!op) { + return left; + } + if (right.type === "logic" && right.op === op) { + return { type: "logic", op, exprs: [left, ...right.exprs] }; + } + return { type: "logic", op, exprs: [left, right] }; + } + function _op(op) { + return op + .flat() + .filter((v) => v && v.trim()) + .join(" ") + .toLowerCase(); + } + + function createUnaryExpr(operator, expr) { + return { type: "unary", operator, expr }; + } + function createBinaryExpr(operator, left, right) { + return { type: "binary", operator, left, right }; + } + + function createList(head, tail) { + return [head, ...tail.map((item) => item[3])]; + } + + function createBinaryExprChain(head, tail) { + return tail.reduce( + (result, item) => createBinaryExpr(item[1], result, item[3]), + head + ); + } +} + + +Main = AliasExpr + +QueryExpr = @value:Expr EOF + +AliasExpr + = expr:Expr alias:(_ KW_AS _ @name:name)? { + return !alias ? expr : { type: "alias", expr, alias }; + } + +Expr = _ @expr:OrExpr _ + +OrExpr + = head:AndExpr tail:(_ KW_OR _ AndExpr)* { + return createBinaryExprChain(head, tail); + } + +AndExpr + = head:NotExpr tail:(_ KW_AND _ NotExpr)* { + return createBinaryExprChain(head, tail); + } + +NotExpr + = ComparisonExpr + / (KW_NOT / "!" !"=") _ expr:NotExpr { return createUnaryExpr("NOT", expr); } + +ComparisonExpr + = left:AdditiveExpr _ rh:ComparisonOpRight? { + if (!rh) return left; + else if (rh.type === "arithmetic") + return createBinaryExprChain(left, rh.tail); + else return createBinaryExpr(rh.op, left, rh.right); + } + +ComparisonOpRight + = l:(_ (">=" / ">" / "<=" / "<>" / "<" / "=" / "!=") _ AdditiveExpr)+ { + return { type: "arithmetic", tail: l }; + } + / in _ "(" _ Exprs _ ")" + +//// / in_op_right +// / between_op_right +// / is_op_right +// / like_op_right + +//in_op_right +// = op:in_op __ LPAREN __ l:expr_list __ RPAREN { +// return { op, right: l }; +// } +// / op:in_op __ e:var_decl { +// return { op, right: e }; +// } + +AdditiveExpr + = head:MultiplicativeExpr tail:(_ ("+" / "-") _ MultiplicativeExpr)* { + return createBinaryExprChain(head, tail); + } + +MultiplicativeExpr + = head:PrimaryExpr tail:(_ ("*" / "/" / "%") _ PrimaryExpr)* { + return createBinaryExprChain(head, tail); + } + +PrimaryExpr + = literal + / ref + / FuncCall + / "(" _ @expr:Expr _ ")" + +// = literal +// / cast_expr +// / aggr_func +// / func_call +// / case_expr +// / column_ref +// / param +// / LPAREN __ e:expr __ RPAREN { +// return { ...e, parentheses: true }; +// } +// / LPAREN __ list:expr_list __ RPAREN { +// return { ...list, parentheses: true }; +// } +// / var_decl +// / interval_expr + +FuncCall + = AggrFunc + / name:name _ "(" _ Exprs _ ")" + +AggrFunc + = name:KW_COUNT _ "(" _ expr:StarExpr _ ")" { + return { type: "AggrFunc", name, args: [expr] }; + } + / count + +StarExpr = "*" { return { type: "start" }; } + +Exprs = head:Expr tail:(_ "," _ Expr)* _ ","? + +// func_call +// = name:ident __ LPAREN __ l:expr_list? __ RPAREN { +// return { type: 'function', name, args: l ? l : { type: 'expr_list', value: [] } }; +// } +// / name:(KW_YEAR / KW_MONTH / KW_DAY / KW_HOUR / KW_MINUTE) __ LPAREN __ l:expr_list? __ RPAREN { +// return { type: 'function', name, args: l ? l : { type: 'expr_list', value: [] } }; +// } +// / name:scalar_func { +// return { type: 'function', name, args: { type: 'expr_list', value: [] } }; +// } + +// scalar_func +// = KW_CURRENT_DATE +// / KW_CURRENT_TIME +// / KW_CURRENT_TIMESTAMP +// / KW_CURRENT_USER +// / KW_USER +// / KW_SESSION_USER +// / KW_SYSTEM_USER + +CompoundExpr + = left:RelExpr + rest:(__ op:logic __ right:CompoundExpr { return { op, right }; })? { + return logic(rest?.op, left, rest?.right); + } + +RelExpr + = "(" value:Expr ")" { return { type: "paren", value }; } + / "!" value:RelExpr { return { type: "not", value }; } + / field:Field __ "between" __ value1:literal __ "and" __ value2:literal + / field:Field + _ + op:(">=" / "<=" / "<>" / ">" / "<" / "===" / "==" / "!=" / "=" / ":") + _ + value:literal + / field:Field _ op:("@>" / "<@" / "&&") _ value:Array + / field:Field _ op:"~" _ value:string + / field:Field __ op:(is __ null) + / field:Field __ op:(is __ not __ null) + / field:Field __ op:((not __)? in) __ value:Array + / field:Field __ op:((not __)? (like / ilike)) __ value:string + +// = left:InExpr rest:(_ op:('>=' / '<='/ '<>' / '>' / '<' / '==' / '!=' / '=' / '@<' / '@>') _ right:RelExpr {return {op,right}}) ? {return rest?{type:'rel',op:rest.op,left,right:rest.right}:left} + +// InExpr +// = left:PredicateExpr rest:(__ op:((not __)? in) _ values:Array {return {op:_op(op),values}})? {return rest?{type:'in',left,...rest}:left} + +// PredicateExpr +// = left:BetweenExpr rest:( +// __ op:(is __ (not __)?) right:(null / bool) {return {op:_op(op),right}} +// / __ op:((not __)? like) __ right:string {return {op:_op(op),right}} +// )? {return rest?{type:'predicate',left,...rest}:left} + +// BetweenExpr +// = left:CallExpr rest:(__ op:((not __)? between) __ a:CallExpr _ and _ b:CallExpr {return {op:_op(op),a,b}}) ? {return rest?{type:'between',left,...rest}:left} + +// CallExpr +// = name:name '(' _ Values _ ')' {return {type:'function',name}} +// / next:PriExpr {return next} + +// PriExpr +// = '(' expr:Expr ')' {return {type:'paren',expr}} // paren +// / not __ expr:Expr {return {type:'not',expr}} // not +// // / Array +// / next:Value {return next} +// / '+' _ expr:Expr {return {type:'positive',expr}}// pos +// / '-' expr:Expr {return {type:'negetive',expr}}// neg + +Field + = ref + / name + +JsonReference = field (("->" / "->>") string)+ + +field + = ident + / ref + +Value + = literal + / ref + / ident + +Values + = next:( + a:Value _ b:(_ "," _ next:Value { return next; })* ","? { + return b ? [a, ...b] : a; + } + )? { return next || []; } + +Array + = "[" next:Values "]" { return next; } + / "(" next:Values ")" { return next; } + +ident = name { return { type: "id", name: text() }; } + +ref = a:name|1.., _ "." _| { return { type: "ref", value: a }; } + +name = ([a-zA-Z] [_a-zA-Z0-9]*) { return text(); } + +in + = "in" + / "IN" { return "in"; } + +is + = "is" + / "IS" { return "is"; } + +like + = "like" + / "LIKE" { return "like"; } + +ilike + = "ilike" + / "ILIKE" { return "ilike"; } + +between + = "between" + / "BETWEEN" { return "between"; } + +and = ("and" / "AND") { return "and"; } + +not = ("not" / "NOT") { return "not"; } + +or = ("or" / "OR") { return "or"; } + +logic + = and + / or + +as = "AS"i !ident_start + +count = "count"i !ident_start + +literal + = string + / float + / int + / bool + / null + +int = [1-9] [0-9]* { return { type: "integer", value: parseInt(text()) }; } + +float + = [0-9]* "." [0-9]+ { return { type: "float", value: parseFloat(text()) }; } + +string + = "'" v:[^']* "'" { return { type: "string", value: v.join("") }; } + / "\"" v:[^"]* "\"" { return { type: "string", value: v.join("") }; } + +null = ("null" / "NULL") { return { type: "null", value: null }; } + +bool + = ("true" / "false" / "TRUE" / "FALSE") { + return { type: "boolean", value: text().toLowerCase() === "true" }; + } + +ident_start = [A-Za-z_] + +KW_AND = "and"i !ident_start +KW_AS = "as"i !ident_start +KW_AVG = "avg"i !ident_start +KW_BETWEEN = "between"i !ident_start +KW_COUNT = "count"i !ident_start +KW_IN = "in"i !ident_start +KW_IS = "is"i !ident_start +KW_LIKE = "like"i !ident_start +KW_MAX = "max"i !ident_start +KW_MIN = "min"i !ident_start +KW_NOT = "not"i !ident_start +KW_OR = "or"i !ident_start +KW_SUM = "sum"i !ident_start + +_ "whitespace" = white* { return ""; } + +__ "whitespace" = white+ { return " "; } + +white + = "/*" [^*]* "*/" + / "--" [^\r\n]* ("\n" / EOF) + / [ \t\n\r] + +EOF = !. diff --git a/notes/languages/parser/peg/ssh-config.peggy b/notes/languages/parser/peg/ssh-config.peggy new file mode 100644 index 00000000000..6abe0de1bb4 --- /dev/null +++ b/notes/languages/parser/peg/ssh-config.peggy @@ -0,0 +1,106 @@ +/* +Grammar for SSH Config + +grammar: https://github.com/wenerme/wener/blob/master/notes/languages/parser/peg/ssh-config.peggy +playground: https://peggyjs.org/online +================================ + +- https://man7.org/linux/man-pages/man5/ssh_config.5.html +- https://github.com/cyjake/ssh-config +- https://github.com/sorend/sshconf + + +Host *.co.uk +Host 192.168.0.? +Include ~/.ssh/*.ssh-config +Match User admin + AllowTcpForwarding yes +Match canonical final host server.example.org +Match user alice host *.example.com +# This comment +# will attache to +# next directive +Host abc # Notes + HostName test +*/ + +{ + var section; + var last; + function push(v) { + v.line = location().start.line; + if (!v.comment) delete v.comment; + if (!v.notes) delete v.notes; + + switch (v.type) { + case "Match": + case "Host": + section = v; + break; + case "Comment": + break; + } + + let out = v; + if (section && section !== v) { + section.children ||= []; + section.children.push(v); + out = null; + } + return out; + } + function finalize(lines) { + lines = lines.flatMap((v) => v).filter(Boolean); + // todo attach comment + return lines; + } +} + +Main = lines:(@Line NL)* EOF { return finalize(lines); } + +Line + = comment:Comment { return push({ type: "Comment", comment }); } + / _ "Host"i _ hosts:HostPattern|1.., __| notes:Comment? { + return push({ type: "Host", hosts, notes }); + } + / _ "Match"i _ conditions:MatchCriteria|1.., __| notes:Comment? { + return push({ type: "Match", conditions, notes }); + } + / _ key:Keyword _ value:Value notes:Comment? { + return push({ type: "Directive", key, value, notes }); + } + / _ { return push({ type: "EmptyLine" }); } + +MatchCriteria + = key:("all"i / "canonical"i / "final"i) { return { key, value: true }; } + / key:("user"i / "localuser"i / "host"i / "originalhost"i) __ value:value { + return { key, value }; + } + / "exec"i __ value + / "tagged"i __ value + +value = $(!(__ / NL / "#") .)+ + +HostPattern + = negtive:"!"? pattern:$(!(__ / NL / "#") .)+ { + return { pattern, negtive: Boolean(negtive) }; + } + +Comment = _ "#" comment:CommentText? { return comment?.trim(); } + +CommentText = chars:(!NL .)* { return text(); } + +Keyword = chars:[a-zA-Z0-9]+ { return text(); } + +Value = chars:(!(NL / "#") .)+ { return text().trim(); } + +EOF = !. + +NL + = "\r\n" + / "\n" + / "\r" + +_ = [ \t]* + +__ = [ \t]+ diff --git a/notes/languages/php/composer.md b/notes/languages/php/composer.md index 389cd68f17f..c3629274db1 100644 --- a/notes/languages/php/composer.md +++ b/notes/languages/php/composer.md @@ -63,6 +63,71 @@ composer install --no-ansi --no-dev --no-interaction --no-plugins --no-progress require __DIR__ . '/vendor/autoload.php'; ``` +## composer.json + +```bash +# 可以通过 config.platform 覆盖 +composer show --platform +``` + +```json title="composer.json" +{ + "name": "vendor-name/package-name", + "description": "This is a package", + // library - 默认 - 会将文件 copy 到 vendor + // project - 项目 + // metapackage + // composer-plugin + // php-ext + // php-ext-zend + "type": "library", + "license": "MIT", + "license": [], + "keywords": [], + "homepage": "https://example.com", + "readme": "README.md", + // 发布时间 + // YYYY-MM-DD, YYYY-MM-DD HH:MM:SS + "time": "2021-01-01", + "authors": [ + { + "name": "Author Name", + "email": "", + "homepage": "", + "role": "" + } + ], + "support": {}, + // {type,url}[] + "funding":[], + "require": { + "php": "^7.4", + "vendor-name/package-name": "^1.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "autoload": { + "psr-4": { + "VendorName\\PackageName\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "VendorName\\PackageName\\Tests\\": "tests/" + } + }, + "scripts": { + "test": "phpunit" + }, + // https://getcomposer.org/doc/06-config.md + "config":{} +} +``` + +- https://getcomposer.org/schema.json +- https://getcomposer.org/doc/04-schema.md + ## config - $HOME/.composer - data-dir/home @@ -70,7 +135,7 @@ require __DIR__ . '/vendor/autoload.php'; - config.json - keys.dev.pub - keys.tags.pub - - cache/ - cache-dir + - cache/ - cache-dir macOS ~/Library/Caches/composer - files/ - repo/ - vcs/ diff --git a/notes/languages/php/php-awesome.md b/notes/languages/php/php-awesome.md index 33fca2e89ea..a5060f6b5d2 100644 --- a/notes/languages/php/php-awesome.md +++ b/notes/languages/php/php-awesome.md @@ -12,7 +12,10 @@ tags: - http://www.phptherightway.com/ - [PHP-FIG](http://www.php-fig.org/) - [PSRs](http://www.php-fig.org/psr/) +- [php/pie](https://github.com/php/pie) +- [pear/pear-core](https://github.com/pear/pear-core) - https://github.com/ziadoz/awesome-php +- https://getcomposer.org - styleci - composer require styleci/cli:^1.2 --dev diff --git a/notes/languages/php/php-glossary.md b/notes/languages/php/php-glossary.md new file mode 100644 index 00000000000..f9942def2ba --- /dev/null +++ b/notes/languages/php/php-glossary.md @@ -0,0 +1,16 @@ +--- +tags: + - Glossary +--- + +# PHP Glossary + +| abbr. | stand for | meaning | +| ------- | ---------------------------------------- | ---------------------- | +| PHP | PHP: Hypertext Preprocessor | 超文本预处理器 | +| PECL | PHP Extension Community Library | PHP 扩展社区库 | +| PEAR | PHP Extension and Application Repository | PHP 扩展和应用程序库 | +| PHP-FPM | PHP FastCGI Process Manager | PHP FastCGI 进程管理器 | +| FastCGI | Fast Common Gateway Interface | 快速通用网关接口 | +| PIE | PHP Installer for Extensions | PHP 扩展安装器 | +| PSR | PHP Standard Recommendation | PHP 标准推荐 | diff --git a/notes/languages/php/php-pecl.md b/notes/languages/php/php-pecl.md index 98cc091c976..f29a8297175 100644 --- a/notes/languages/php/php-pecl.md +++ b/notes/languages/php/php-pecl.md @@ -10,7 +10,18 @@ After Alpine v3.5, the `/usr/bin/php` is php7, before that is php5 in php5-cli p ::: +- PECL - PHP Extension Community Library +- https://pecl.php.net/ + ```bash +# ABI Version +# PHP Extension Build => API20240924,NTS +php -i | grep "PHP Extension Build" +pecl config-get ext_dir +php-config --extension-dir + +pecl list + # igbinary # https://pecl.php.net/package/igbinary pecl install -o -f igbinary diff --git a/notes/languages/php/php-typing.md b/notes/languages/php/php-typing.md index 2025b8fb45d..1c4efbd496f 100644 --- a/notes/languages/php/php-typing.md +++ b/notes/languages/php/php-typing.md @@ -4,4 +4,55 @@ title: PHP Typing # PHP Typing -- https://www.php.net/manual/en/language.types.declarations.php +:::caution + +- 不支持 generics + +::: + +```php + `(A&B)|(A&C)` + - ~~`A|(B&(C|D))`~~ -> `A|(B&C)|B&D)` +- Typed array `int[]` - PHP 8.3 +- Typed Class Constants - PHP 8.3 + +## 参考 {#reference} + +- https://phpstan.org/writing-php-code/phpdoc-types +- https://www.php.net/manual/zh/language.types.declarations.php +- https://wiki.php.net/rfc/typed_properties_v2 +- https://wiki.php.net/rfc/typed-properties diff --git a/notes/os/linux/shell/ssh/ssh-config.md b/notes/os/linux/shell/ssh/ssh-config.md index fed198ea8da..7bfe395e70a 100644 --- a/notes/os/linux/shell/ssh/ssh-config.md +++ b/notes/os/linux/shell/ssh/ssh-config.md @@ -56,6 +56,16 @@ Match - Match - canonical, final, exec, host, originalhost, user, localuser, all + - all:始终匹配。在 Match 行上仅写 all,或紧接在 canonical、final 后面写时表示无条件匹配。 + - canonical:当主机名已被 CanonicalizeHostname 选项处理并规范化(canonicalization)后,再次解析配置文件时此条件为真。这常用于那些只适用于规范化后的主机名的配置规则。 + - final:请求在配置文件解析结束前再做一次最终解析,并在那次最终解析过程中匹配。若 CanonicalizeHostname 开启,那么 canonical 和 final 会在同一阶段匹配。 + - exec:执行后续指定的命令,如果该命令返回退出状态码 0 则匹配为真。这可用于动态决策逻辑,如基于脚本结果调整后续配置。 + - localnetwork:将本地主机的活动网络接口地址与给定的网络列表(CIDR 格式)匹配。如果本地网卡 IP 位于该网段中则为真。这在移动设备在不同网络间切换时很有用,但需要谨慎使用,因为网络地址信息在安全场景中并不一定可靠。 + - host:根据最终使用的目标主机名匹配,常用的 * 通配符也可使用。 + - originalhost:根据用户在命令行上输入的原始主机名(尚未规范化的)进行匹配。 + - tagged:匹配由 Tag 指令设定的标签名或在 ssh 命令行中用 -P 选项指定的标签。 + - user:匹配目标远程主机上的登录用户名。 + - localuser:匹配本地执行 ssh 命令的用户。 > 通配 Host 需要放在后面 diff --git a/notes/platform/aliyun/aliyun-market.md b/notes/platform/aliyun/aliyun-market.md new file mode 100644 index 00000000000..ce8663006c8 --- /dev/null +++ b/notes/platform/aliyun/aliyun-market.md @@ -0,0 +1,7 @@ +--- +title: Aliyun Market +--- + +# Aliyun Market + +- `*.market.alicloudapi.com` diff --git a/notes/platform/google/README.md b/notes/platform/google/README.md index c97ee250bba..fdf2d119d30 100644 --- a/notes/platform/google/README.md +++ b/notes/platform/google/README.md @@ -58,7 +58,7 @@ wget -q -U Mozilla -O output.mp3 "http://translate.google.com/translate_tts?ie=U - `inurl:` - `intitle:` - `intitle:关键词1 关键词2` -- `related:example.com` +- `related:example.com` 相关网站 - 占位符 `*` - 数字范围 `..` - 缓存版本 `cache:example.com` diff --git a/notes/service/api/grpc/connect.md b/notes/service/api/grpc/connect.md index c17fe10a52d..9214bb044b8 100644 --- a/notes/service/api/grpc/connect.md +++ b/notes/service/api/grpc/connect.md @@ -1,5 +1,7 @@ --- title: Connect +tags: + - Protocol --- # Connect @@ -19,19 +21,37 @@ title: Connect - connect - unary: application/proto, application/json - striming: application/connect+proto, application/connect+json -- 参考 - - [Connect Protocol Reference](https://connect.build/docs/protocol/) - - [bufbuild/protobuf-es](https://github.com/bufbuild/protobuf-es) - - JS PB 实现 - - [bufbuild/connect-crosstest](https://github.com/bufbuild/connect-crosstest) - - 兼容测试 -## Connect 协议 +## Awesome + +- [Connect Protocol Reference](https://connect.build/docs/protocol/) +- [connectrpc/vanguard-go](https://github.com/connectrpc/vanguard-go) + - Apache-2.0, Go + - Gateway + - REST, gRPC, gRPC-Web, and Connect +- [bufbuild/protobuf-es](https://github.com/bufbuild/protobuf-es) + - JS PB 实现 +- [bufbuild/connect-crosstest](https://github.com/bufbuild/connect-crosstest) + - 兼容测试 +- [connectrpc/connect-es](https://github.com/connectrpc/connect-es) + +## 协议 {#protocol} ```http POST /./ ``` +## connect-es + +- router = `{handlers,service(),rpc()}` + - handlers - universal handler + - 支持所有协议 + - 包含元信息 + - service 注册整个 service + - rpc 注册一个方法 + - handler = 协议协商 -> interceptor -> impl + - interceptor 无法访问当前的 impl + ## connect-web - [connectrpc/connect-es](https://github.com/connectrpc/connect-es) @@ -42,7 +62,6 @@ POST /./ npm install @bufbuild/protoc-gen-es @bufbuild/protoc-gen-connect-web PATH=$PATH:$(pwd)/node_modules/.bin - ``` ## connect-go @@ -90,7 +109,7 @@ plugins: - Handler - 当个 RPC 方法处理 - 实现 Connect, gRPC, gRPC-Web 协议 - - 提供 ServeHTTP + - 提供 ServeHTTP - 构造 - NewBidiStreamHandler - NewClientStreamHandler diff --git a/notes/service/api/grpc/grpc-php.md b/notes/service/api/grpc/grpc-php.md index f72dcd9abaa..c7b938f3bf9 100644 --- a/notes/service/api/grpc/grpc-php.md +++ b/notes/service/api/grpc/grpc-php.md @@ -13,8 +13,11 @@ tags: composer require grpc/grpc composer require google/protobuf +# /opt/homebrew/lib/php/pecl//grpc.so pecl install grpc # by pecl - e.g. macOS apk add php82-pecl-grpc # AlpineLinux + +php -i | grep "PHP Extension Build" # ABI 版本 ``` ```json title=composer.json @@ -24,10 +27,19 @@ apk add php82-pecl-grpc # AlpineLinux "App\\": "app/", "": "gen/" } + }, + "require": { + "grpc/grpc": "^1.41", + "google/protobuf": "^3.19", + "ext-grpc": "*" } } ``` +```ini title="php.ini" +extension=grpc.so +``` + ```php { } export type TItem = TPageItem | TMetaItem | TFolder; + +export type PageMapItem = Folder | MdxFile | MetaJsonFile; +export interface Folder { + name: string; + route: string; + children: FileType[]; +} +export type MdxFile = { + name: string; + route: string; + frontMatter?: FrontMatterType; +}; +export type MetaJsonFile = { + data: { + [fileName: string]: Meta; + }; +}; ``` ## Nextra v4 diff --git a/notes/service/data/data-awesome.md b/notes/service/data/data-awesome.md index f30554b2509..9eb971a8a99 100644 --- a/notes/service/data/data-awesome.md +++ b/notes/service/data/data-awesome.md @@ -14,6 +14,11 @@ tags: - https://gitee.com/skyoo/Enterprise-Registration-Data-of-Chinese-Mainland - https://github.com/chenli90s/govinfo - 企业数据 +- 手机归属地 + - 《电信网编号计划(2017年版)》 + - https://nac.miit.gov.cn/#/noticeDetail?id=600126024 + - [xluohome/phonedata](https://github.com/xluohome/phonedata) + - [ls0f/phone](https://github.com/ls0f/phone) - service - https://github.com/OpenRefine/OpenRefine - [microsoft/Data-Science-For-Beginners](https://github.com/microsoft/Data-Science-For-Beginners) diff --git a/notes/service/data/data-schema.md b/notes/service/data/data-schema.md deleted file mode 100644 index d99f1b7b1a6..00000000000 --- a/notes/service/data/data-schema.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: 数据格式 ---- - -# Schema - -## PhonNumber - -- https://en.wikipedia.org/wiki/National_conventions_for_writing_telephone_numbers - -**US 10 digits** - -``` -^(\+\d{1,2}\s?)?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}$ -``` - -- https://stackoverflow.com/a/16699507/1870054 -- https://regex101.com/r/j48BZs/2 - -**中国** - -- Landlines - - (0XXX) YYY YYYY - - XXX ,2-3 位, trunks - - YYYY YYYY, 7-8 位, subscriber/local number -- 手机号 - - 1WX YYYY ZZZZ - - W 3-9 -- Toll Free - - 400 XXX XXXX - - 800 XXXX XXXX -- Service numbers - - 3-5 位 diff --git a/notes/service/data/schema/division.md b/notes/service/data/schema/division.md new file mode 100644 index 00000000000..b98a18ec3e5 --- /dev/null +++ b/notes/service/data/schema/division.md @@ -0,0 +1,39 @@ +--- +title: DivisionCode +--- + +# 行政区划 + +- division code / administrative division code + - 行政区划代码 + - 与 省市区 关联 +- region code + - 区域代码 + - 更加广泛的概念 + +```ts +/** + * 行政区划元数据 + */ +interface DivisonCodeMetadata { + divisionCode: string; + province: string; + city: string; + county: string; + village: string; + level: number; + + codes: string[]; + labels: string[]; + + latitude: number; + longitude: number; + + /** + * 已经废弃的区划代码 + */ + deprecated?: boolean; +} +``` + +- https://www.ibm.com/support/pages/country-or-region-codes-0 diff --git a/notes/service/data/schema/phonenumber.md b/notes/service/data/schema/phonenumber.md new file mode 100644 index 00000000000..1f30c8e2240 --- /dev/null +++ b/notes/service/data/schema/phonenumber.md @@ -0,0 +1,112 @@ +--- +title: 电话号码元数据 +--- + +# PhoneNumber + +- E.164 + - 国际标准格式 + - +国家代码 区号 电话号码 + - +86 10 12345678 + - 分组格式 + - +1 (202) 555-0123 + - +86 138-1234-5678 +- ITU-T E.123 + - 国际格式 +1 202 555 0123 + - 本地格式 202-555-0123。 + +```ts +interface PhoneNumberMetadata { + phoneNumber: string; + countryCode: string; + areaCode: string; + + isp: string; + province: string; + city: string; + divisionCode: string; + latitude: number; + longitude: number; + + // 可能存在定位不准确有多个地址的情况 + locations: Array<{ + province: string; + city: string; + divisionCode: string; + latitude: number; + longitude: number; + }>; +} +``` + +- https://en.wikipedia.org/wiki/National_conventions_for_writing_telephone_numbers +- [google/libphonenumber](https://github.com/google/libphonenumber) + - 支持非常多语言 +- Javascript/Node + - [catamphetamine/libphonenumber-js](https://gitlab.com/catamphetamine/libphonenumber-js) + - npm:libphonenumber-js + - [google/libphonenumber](https://github.com/google/libphonenumber) + - npm:google-libphonenumber - 非官方 + - [aftership/phone](https://github.com/aftership/phone) + - npm:phone + - [grantila/awesome-phonenumber](https://github.com/grantila/awesome-phonenumber) + - npm:awesome-phonenumber + - https://npmtrends.com/awesome-phonenumber-vs-google-libphonenumber-vs-libphonenumber-js-vs-phone + +**US 10 digits** + +``` +^(\+\d{1,2}\s?)?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}$ +``` + +- https://stackoverflow.com/a/16699507/1870054 +- https://regex101.com/r/j48BZs/2 + +## 中国 {#china} + +- Landlines + - (0XXX) YYY YYYY + - XXX ,2-3 位, trunks + - YYYY YYYY, 7-8 位, subscriber/local number +- 手机号 + - 1WX YYYY ZZZZ + - W 3-9 +- Toll Free + - 400 XXX XXXX + - 800 XXXX XXXX +- Service numbers + - 3-5 位 + +--- + +- [中国大陆服务电话号码](https://zh.wikipedia.org/zh-sg/中国大陆服务电话号码) + - 1××:通常为紧急电话或查号台; + - 100××:通常为电信运营商的客服电话; + - 12×××:通常为政府部门的服务热线; + - 400-×××-××××、800-×××-××××、95/96×××(5-8位数):通常为商业服务类电话; + +## Carrier + +- Mobile Country Code (MCC) 和 Mobile Network Code (MNC) + - by 国际电信联盟(ITU-T) + - 用于 标识移动网络运营商 + - MCC(Mobile Country Code):表示国家代码(如中国是 460,美国是 310)。 + - MNC(Mobile Network Code):表示运营商代码(如中国移动的 MNC 是 00, 02, 07)。 + - MCC-MNC 标识某个国家的某个运营商 + - 中国移动:460-00 + - 中国联通:460-01 + - 美国 AT&T:310-410 + - http://mcc-mnc.com/ +- Carrier Identification Codes (CIC) 运营商识别码 + - by 美国 FCC +- Public Land Mobile Network (PLMN) - 公共陆地移动网络 + - =MCCMNC + - 广泛应用于 GSM 和 LTE 网络 +- ITU-T E.212 + - 定义了 IMSI(International Mobile Subscriber Identity,国际移动用户标识)的结构,包含 MCC 和 MNC。 + - IMSI:460000123456789 + - MCC = 460(中国) + - MNC = 00(中国移动) +- 商业 + - GSMA Mobile Network Code (MNC) Database + - Twilio Lookup API diff --git a/notes/service/forge/git/git-faq.md b/notes/service/forge/git/git-faq.md index d176bdfb833..c96c8f95080 100644 --- a/notes/service/forge/git/git-faq.md +++ b/notes/service/forge/git/git-faq.md @@ -275,7 +275,7 @@ Signed-off-by: wener - 明确 sign-off 身份 - [What is the Sign Off feature in Git for?](https://stackoverflow.com/a/1962112/1870054) -## 迁移子目录为仓库 +## 迁移子目录为仓库 {#subdir-to-repo} ```bash # git filter-branch --prune-empty --subdirectory-filter FOLDER-NAME BRANCH-NAME @@ -285,7 +285,7 @@ git subtree split -P -b - [Detach (move) subdirectory into separate Git repository](https://stackoverflow.com/questions/359424) -## 迁移分支为仓库 +## 迁移分支为仓库 {#branch-to-repo} ```bash mkdir /path/to/new/repo && cd "$@" diff --git a/notes/service/forge/github/README.md b/notes/service/forge/github/README.md index 4bfd9403692..f0e795c24a2 100644 --- a/notes/service/forge/github/README.md +++ b/notes/service/forge/github/README.md @@ -10,6 +10,9 @@ title: Github GitHub as an authority for SSH public keys - https://codeload.github.com/bufbuild/buf/tar.gz/refs/tags/v1.3.0 - https://trendshift.io/ + - blocked story + - [](https://medium.com/@catamphetamine/c32c61f061d3) + ```bash curl https://github.com/wenerme.keys >> ~/.ssh/authorized_keys diff --git a/notes/service/geo/geo-awesome.md b/notes/service/geo/geo-awesome.md index 5dc7614c6f1..23e4e86a1fa 100644 --- a/notes/service/geo/geo-awesome.md +++ b/notes/service/geo/geo-awesome.md @@ -5,5 +5,12 @@ tags: # Geo Awesome +- Longitude - lon, lng, X - 经度 +- Latitude - lat, Y - 纬度 +- Altitude - alt, Z - 海拔 +- Bearing - brg - 方位角 +- Speed - spd - 速度 +- Accuracy - acc - 精度 - [googollee/eviltransform](https://github.com/googollee/eviltransform) - WGS-84 <-> GCJ-02 + diff --git a/notes/service/geo/geo-glossary.md b/notes/service/geo/geo-glossary.md new file mode 100644 index 00000000000..0666801c3a1 --- /dev/null +++ b/notes/service/geo/geo-glossary.md @@ -0,0 +1,13 @@ +--- +tags: + - Glossary +--- + +# Geo Glossary + +- Longitude - lng, lon, X - 经度 +- Latitude - lat, Y - 纬度 +- Altitude - alt, Z - 海拔 +- Bearing - brg - 方位角 +- Speed - spd - 速度 +- Accuracy - acc - 精度 diff --git a/notes/service/network/proxy/proxy-awesome.md b/notes/service/network/proxy/proxy-awesome.md index 46bbba8e99a..6449a39aed7 100644 --- a/notes/service/network/proxy/proxy-awesome.md +++ b/notes/service/network/proxy/proxy-awesome.md @@ -51,9 +51,9 @@ tags: - v1 和 v2 不兼容 - brook wss - https://github.com/txthinking/brook -- obfs - 混淆 - 用于 ss,ssr,hysteria - - tls1.2_ticket_auth, tls1.2_ticket_fastauth - - http_simple, http_post +- [enfein/mieru](https://github.com/enfein/mieru) + - 一些设计思考 https://github.com/enfein/mieru/issues/8 +- naive - http proxy - nginx - squid @@ -64,6 +64,9 @@ tags: - ss - ShadowSocks - ssr - ShadowSocksR - 不活跃,不推荐使用 +- obfs - 混淆 - 用于 ss,ssr,hysteria + - tls1.2_ticket_auth, tls1.2_ticket_fastauth + - http_simple, http_post - CCProxy, Proxycap, Proxifier - Tunnel - [ginuerzh/gost](https://github.com/ginuerzh/gost) diff --git a/notes/service/workflow/bpms/bpms-glossary.md b/notes/service/workflow/bpms/bpms-glossary.md new file mode 100644 index 00000000000..6f3b2a62b44 --- /dev/null +++ b/notes/service/workflow/bpms/bpms-glossary.md @@ -0,0 +1,15 @@ +--- +tags: + - Glossary +--- + +# BPMS Glossary + +| abbr. | stand for | meaning | +| ----- | ----------------------------------- | ------------------ | +| BPEL | Business Process Execution Language | 业务流程执行语言 | +| BPM | Business Process Management | 业务流程管理 | +| BPMN | Business Process Model and Notation | 业务流程建模与标记 | +| BPMS | Business Process Management System | 业务流程管理系统 | +| CMMN | Case Management Model and Notation | 案例管理建模与标记 | +| DMN | Decision Model and Notation | 决策建模与标记 | diff --git a/notes/web/nodejs/nodejs-faq.md b/notes/web/nodejs/nodejs-faq.md index c5f3c8ef21a..27741a372f4 100644 --- a/notes/web/nodejs/nodejs-faq.md +++ b/notes/web/nodejs/nodejs-faq.md @@ -135,6 +135,10 @@ exec /usr/bin/env node --input-type=module - "$@" < "$0" node --experimental-default-type=module cli ``` +```js +node --input-type=module --eval 'console.log("Hello, world!")' +``` + - ESM - 增加 mjs 文件后缀即可 - https://github.com/nodejs/node/issues/49444 diff --git a/notes/web/react/react-awesome.md b/notes/web/react/react-awesome.md index 24d8399fec5..8795aee58ca 100644 --- a/notes/web/react/react-awesome.md +++ b/notes/web/react/react-awesome.md @@ -80,15 +80,14 @@ npm add date-fns lodash-es react-fast-compare - `@blueprintjs/select` - 多功能 select 组件 - 不控制样式,以逻辑为主 -- [radix-ui/primitives](https://github.com/radix-ui/primitives) - - by WorkOS - - Slot 组件 - asChild 时使用 child 组件进行渲染,传递所有 props - [nextui-org/nextui](https://github.com/nextui-org/nextui) - 与 vercel 无关 - [rsuite/rsuite](https://github.com/rsuite/rsuite) - 各方面神似 AntD - 但比 AntD 轻的多 - [ant-design/ant-design](./antd.md) + - MIT, TS - 1.3MB + - antd 直接依赖 49 个, 间接依赖 19 个 - 共计 68 个依赖 - @ant-design/icons - dayjs - rx- @@ -147,7 +146,36 @@ npm add date-fns lodash-es react-fast-compare - 很多样式都通过 props 控制 - 如果喜欢这样的还不如选择 tailwindcss 更加规范实用 -## 移动端 UI 组件 +## Headless UI 组件 {#headless-ui} + +- [radix-ui/primitives](https://github.com/radix-ui/primitives) + - by WorkOS + - Slot 组件 - asChild 时使用 child 组件进行渲染,传递所有 props +- [tailwindlabs/headlessui](https://github.com/tailwindlabs/headlessui) + - 功能性 headless 组件 + - popover + - listbox/select + - combobox/autocomplete + - menu/dropdown + - switch/toggle + - disclosure + - dialog/modal + - radio group + - tabs + - transition +- [mui/base-ui](https://github.com/mui/base-ui) + - MIT, TS + - npm:@base-ui-components/react + - from the creators of Radix, Floating UI, and Material UI + - https://mui.com/blog/base-ui-2024-plans/ + - https://mui.com/blog/introducing-base-ui/ + - 2022 MUI, npm:@mui/base + - https://mui.com/base-ui/getting-started/ +- [nandorojo/dripsy](https://github.com/nandorojo/dripsy) + - MIT, TS + - for React Native + Web. + +## 移动端 UI 组件 {#mobile-ui} - [tailwind-mobile](https://github.com/tailwind-mobile/tailwind-mobile) - [ant-design/ant-design-mobile](https://github.com/ant-design/ant-design-mobile) @@ -455,7 +483,7 @@ npm add date-fns lodash-es react-fast-compare - https://github.com/wojtekmaj - react-calendar, react-clock, react-pdf -### 编辑器 +### 编辑器 {#editor} - Markdown - [andrerpena/react-mde](https://github.com/andrerpena/react-mde) @@ -465,7 +493,7 @@ npm add date-fns lodash-es react-fast-compare - [margox/braft-editor](https://github.com/margox/braft-editor) - [margox/braft-extensions](https://github.com/margox/braft-extensions) - 扩展包 -## 路由 +## 路由 {#router} - [ReactTraining/react-router](https://github.com/ReactTraining/react-router) - React 16.8 hook 之前已经存在 @@ -512,7 +540,7 @@ npm add date-fns lodash-es react-fast-compare ## 功能组件 -> 大多为 Headless +> 大多为 Headless/unstyled - TanStack - [react-table](./react-table.md) @@ -529,20 +557,7 @@ npm add date-fns lodash-es react-fast-compare - 支持 SSR - [gregberge/loadable-components](https://github.com/gregberge/loadable-components) - 异步加载组件 -- [tailwindlabs/headlessui](https://github.com/tailwindlabs/headlessui) - - 功能性 headless 组件 - - popover - - listbox/select - - combobox/autocomplete - - menu/dropdown - - switch/toggle - - disclosure - - dialog/modal - - radio group - - tabs - - transition -- [nandorojo/dripsy](https://github.com/nandorojo/dripsy) -- [its-danny/use-lilius](https://github.com/its-danny/use-lilius) +- ~~[its-danny/use-lilius](https://github.com/its-danny/use-lilius)~~ - date-fns - DateInput diff --git a/notes/web/script/js/js-fs.md b/notes/web/script/js/js-fs.md index fa8e782a880..7704d05bbad 100644 --- a/notes/web/script/js/js-fs.md +++ b/notes/web/script/js/js-fs.md @@ -5,6 +5,7 @@ tags: # JS File System API + - FileSystem - `{name,root}` - Chrome 7, Safari 11.1 - FileSystemEntry @@ -12,6 +13,9 @@ tags: - FileSystemDirectoryEntry - FileSystemDirectoryEntry.createReader() - FileSystemDirectoryReader +- 类型定义 + - npm:@types/wicg-file-system-access + - npm:@types/filesystem **获取 FS 的方式** @@ -23,6 +27,7 @@ tags: - Window.showDirectoryPicker - Window.showOpenFilePicker - Window.showSaveFilePicker +- ~~Window.requestFileSystem~~ --- diff --git a/notes/web/script/lib/canvas.md b/notes/web/script/lib/canvas.md index d21ac8cfa70..9b37be73d7c 100644 --- a/notes/web/script/lib/canvas.md +++ b/notes/web/script/lib/canvas.md @@ -6,7 +6,14 @@ tags: # canvas +- [Automattic/node-canvas](https://github.com/Automattic/node-canvas) + - MIT, JS, C++ + - Cairo backed Canvas implementation for NodeJS. + ```bash +# AlpineLinux +apk add pkgconf cairo-dev pango-dev libpng-dev jpeg-dev giflib-dev librsvg-dev + # macOS # https://github.com/Automattic/node-canvas/issues/2036 brew install pkg-config cairo pango libpng jpeg giflib librsvg