#871 OSPO:开源办公室

2023-04-15

OSPO 是 Open Source Program Office(开源计划办公室)的缩写,它是一个专门负责管理和支持一个组织的开源项目的部门或团队。OSPO 可以帮助组织制定开源策略,确保开源项目遵循法律和伦理标准,建立和维护与其他开源社区的联系,以及管理知识产权和许可证问题等。

OSPO 的职责范围通常包括以下方面:

  1. 管理开源软件开发过程中的知识产权和许可证问题;
  2. 确保开源项目遵循法律、伦理和道德标准;
  3. 帮助组织与其他开源社区建立联系和合作;
  4. 支持组织的开源战略和决策制定;
  5. 管理组织内部的开源项目和参与度;
  6. 组织和管理贡献者社区。

OSPO 对于大型组织或企业来说,是实现开源战略和管理开源项目的重要手段之一。

#870 ISO 8601 与时间格式化

2023-04-10

https://en.wikipedia.org/wiki/ISO_8601

占位符

占位符 描述
%Y 四位数的年份
%m 两位数的月份
%d 两位数的日数
%H 24 小时制的小时数
%M 两位数的分钟数
%S 两位数的秒数
%z 时区偏移量,格式如 +0800
%a 星期几的缩写,例如:Mon、Tue 等
%A 星期几的全称,例如:Monday、Tuesday 等
%b 月份的缩写,例如:Jan、Feb 等
%B 月份的全称,例如:January、February 等
%c 本地日期时间,例如:Tue Aug 16 21:30:00 1988
%f 微秒,范围是 0~999999
%j 年份中的第几天,范围是 001~366
%p 上午或下午,例如:AM、PM
%r 12 小时制的时间,例如:09:30:00 PM
%s 自 1970 年 1 月 1 日以来的秒数
%u 星期几,范围是 1~7,其中 1 表示星期一
%w 星期几,范围是 0~6,其中 0 表示星期日
%x 本地日期,例如:08/16/88
%X 本地时间,例如:21:30:00
%y 两位数的年份,例如:88
%Z 时区名称或缩写,例如:UTC、GMT、EST 等

Linux

date -u +"%Y-%m-%dT%H:%M:%S.%3NZ"

Python

import datetime

now = datetime.datetime.now()
iso8601 = now.isoformat(timespec='milliseconds')
print(iso8601)

PHP

$now = new DateTime();
$iso8601 = $now->format('Y-m-d\TH:i:s.v\Z');
echo $iso8601;

Java

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
String iso8601 = now.format(formatter);
System.out.println(iso8601);

JS

const now = new Date();
const iso8601 = now.toISOString();
console.log(iso8601);

C

#include <stdio.h>
#include <time.h>

int main() {
    char iso8601[30];
    time_t now = time(NULL);
    strftime(iso8601, sizeof iso8601, "%Y-%m-%dT%H:%M:%S.000Z", gmtime(&now));
    printf("%s\n", iso8601);
    return 0;
}

Golang

package main

import (
    "fmt"
    "time"
)

func main() {
    now := time.Now().UTC()
    iso8601 := now.Format("2006-01-02T15:04:05.000Z")
    fmt.Println(iso8601)
}

#869 对焦虑的看法

2023-04-09

我们经常说这个世界的节奏越来越快,而快节奏会伴随各种压力。
例如,工作、学业、家庭或社交等方面可能会让我们感到紧张、压抑、困惑或不安。
这些压力主要源于担心不能如期望地完成各种任务,从而导致不良后果。

这些压力常常伴随着焦虑,焦虑带来压力,压力加重焦虑。

会不会丢掉工作?
以后的路怎么走?
会不会跟不上形势?

我想来想去,觉得这就是对未来的不确定性的一种恐慌。
过去的人们生活在一种稳定不变的社会中,几乎一辈子也不会发生什么太大的变化。
这样的世界早已远去。

但是可能是由于人类的本性,大多数人都希望生活在稳定的环境中,这种稳定可以带来安全感。
现代社会种的各种不确定性使得我们无法完全掌控自己的生活,从而导致焦虑的产生。


就写到这里,以后再继续补充。

#868 转载:在 URL 中存储状态

2023-04-08

I'm working on a flowchart editor that runs in the browser, and I wanted a way for people to use it without having to sign in, or store any data on our server. I wanted to give them control over their data and to be able to store it locally to open and edit later. And also easily share it with other people. It's easy to do this by supporting file upload/download, but I wanted something simpler, like the ability to share by sending a url. I also didn't want to store anything on the backend (at least for the free tier).
我正在开发一个在浏览器中运行的流程图编辑器,我希望人们不用登录,不用在我们的服务器上存储任何数据就能使用它。
我想让用户控制自己的数据,并能够将其存储在本地,以便以后打开和编辑,而且也很容易与他人分享。
通过支持文件上传/下载很容易做到这一点,但我想要一些更简单的东西,比如通过发送 url 来共享。
我也不想在后端存储任何东西(至少对于免费服务部分)。

I decied to encode the entire application state as a Base64 encoded string in the hashmark of the url. For example, a url would look like (note its truncated since they are very long):
我决定将整个应用程序状态编码为 Base64 字符串,放在 url 井号部分,例如(截断之后):

knotend.com/g/a#N4IgzgpgTglghgGxgLwnARgiAxA9lAWxAC5QA7X...

Everything after the /g/a# is a stringified version of a json object that contains all the information about the flowchart. It gets stringified, then compressed, then Base64 encoded. I update the url on every graph edit, so copying the graph state is as simple as copying the url in your browser bar.
流程图有关的所有信息存储在 JSON 对象中,被转换成字符串,压缩,Base64,最后放在 URL 中。
每次编辑图形的时候更新 URL,复制 URL 就可以复制图形状态。

Here's the pseudo code for creating the url, and then later reading it:
伪代码:

const stateString = JSON.stringify(appState); // appState is a json object
const compressed = compress(stateString);
const encoded = Base64.encode(compressed);
// Push that `encoded` string to the url
// ... Later, on page load or on undo/redo we read the url and
// do the following
const decoded = Base64.decode(encoded); // same encoded as above, but read from url
const uncompressed = uncompress(decoded);
const newState = JSON.parse(uncompressed);
// Now load your application with the newState

There are several options for implementing the compress/uncompress functions, such as lz-stirng or pako.
有一些库可以实现压缩解压缩,比如 lz-string,pako。

Since I update it on every graph edit, I get something major for free -- undo/redo. The browser's history stack becomes my undo/redo functionality. The user can hit the browser back/forward buttons, or Command-Z,Command-Shift-Z which I map to history pop and push. This is a major win for something which is a free product that I wanted to ship quickly.
因为每次编辑图形都会更新 URL,依赖浏览器的历史功能,通过前进、后退按钮,或者快捷键 Command-Z、Command-Shift-Z,还能实现撤销和重做。

Another great benefit is that these urls can be embedded. That means the user can put their graph on any web page that supports embedding. I see people typically do this with wikis like Notion, which means you can share with a team without anyone needing an account on my site.
另一个巨大的好处是这些 URL 可以被嵌入。这意味着用户可以将他们的图形放在任何支持嵌入的 Web 页面上。
我看到人们通常在 Notion 这样的笔记软件中使用,这意味着您可以与团队共享,而不需要任何人在我的网站上注册帐户。

You can see how it works by checking out knotend, the keyboard-centric flowchart editor that I'mw working on.
你可以在 knotend 中看到这个到底是怎么实现。knotend 是我正在开发的一个键盘为中心的流程图编辑器。

Prior work and thank yous.
之前的工作,谢谢。

I'm not the first one to take this approach. I've seen atleast mermaidjs do this before, and I'm sure there are others.
我不是第一个采用这种方法的人。我以前至少见过 mermaidjs 这样做,我相信还有其他人。

Thank you to this comment by redleader55 on hacker news for pointing out that using window.location.hashmark is better for storing longer urls since some browsers will truncate the url when sending it over http. But that this doesn't apply to the hashmark, which stays client side.
感谢 redleader55 在 hacker news 上的评论,你指出使用 window.location.hashmark 更适合存储较长的 url,因为一些浏览器在通过 http 发送 url 时会截断 url。但这并不适用于 hashmark,它停留在客户端。

See conversation on Hacker News https://news.ycombinator.com/item?id=34312546

#867 ChatGPT 无法访问(又可以访问了)

2023-04-04

04/09 更新:发现借道小日子可以访问。可能是定向封锁了部分梯子。


我换浏览器,换梯子,清理 Cookie,还是无法打开。

图片占位符:拜拜就拜拜,下一个更乖

#866 inode 使用率太高的问题

2023-04-03

Jenkins 发布失败,日志显示 scp No space left on device,也就是磁盘空间不足。

查看之后发现是磁盘占用其实不高,不过 inode 使用率满了(其实监控也在报),也就是说小文件太多了。

[staff001@192.168.64.234 ~]# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/vda1              40G   29G  8.7G  77% /
tmpfs                 972M     0  972M   0% /dev/shm
/dev/vdb               99G   41G   54G  44% /data

[staff001@192.168.64.234 ~]# df -i
Filesystem            Inodes   IUsed   IFree IUse% Mounted on
/dev/vda1            2621440 2621440       0  100% /
tmpfs                 248685       1  248684    1% /dev/shm
/dev/vdb             6553600  467525 6086075    8% /data

通过经验和 find 命令找到文件太多的目录:

find /var -xdev -printf '%h\n'          | sort | uniq -c | sort -n | awk '{sum+=$1;print $0;}END{print "\nTotal: "sum}'

# 只看二级目录的数据
find /var -xdev -type f | cut -d / -f 3 | sort | uniq -c | sort -n | awk '{sum+=$1;print $0;}END{print "\nTotal: "sum}'

#865 MySQL sort limit 的一个小问题

2023-04-01

sort limit 中有一个相同 sort 项随机选择的逻辑,比如:
我们 sort 之后得到的结果是 a, b, c, d
加上 limit 3 之后,可能返回的是 b, a, d(a、b 的排序列相同,c、d 的排序列相同)
和预期的不一定是吻合的,这个可能需要注意一下。

官方文档的描述:

If you combine LIMIT row_count with ORDER BY, MySQL stops sorting as soon as it has found the first row_count rows of the sorted result, rather than sorting the entire result.
如果将 LIMIT row_countORDER BY 结合使用,MySQL 会在找到排序结果的前 row_count 行后立即停止排序,而不是对整个结果进行排序。

CREATE TABLE `testSortLimit` (
    `id` INT(10) NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(50) NOT NULL,
    `sort` INT(10) NOT NULL DEFAULT '0',
    PRIMARY KEY (`id`) USING BTREE
)
ENGINE=InnoDB;

INSERT INTO testSortLimit (name, sort) VALUES
("aaa", 0), ("eee", 1), ("iii", 1), ("mmm", 1),
("bbb", 0), ("fff", 1), ("jjj", 1), ("nnn", 1),
("ccc", 0), ("ggg", 1), ("kkk", 1), ("ooo", 1),
("ddd", 0), ("hhh", 1), ("lll", 1), ("ppp", 1);

SELECT * FROM testSortLimit;
SELECT * FROM testSortLimit ORDER BY sort ASC;
SELECT * FROM testSortLimit ORDER BY sort ASC LIMIT 6;
id name sort
1 aaa 0
5 bbb 0
9 ccc 0
13 ddd 0
2 eee 1
3 iii 1
4 mmm 1
6 fff 1
7 jjj 1
8 nnn 1
10 ggg 1
11 kkk 1
12 ooo 1
14 hhh 1
15 lll 1
16 ppp 1
id name sort
5 bbb 0
9 ccc 0
13 ddd 0
1 aaa 0
12 ooo 1
11 kkk 1

参考资料与拓展阅读

#864 赞美内网云

2023-03-31

之前用过 Sunny-Ngrok,注册一个账号,有免费的套餐,有很多种方式部署使用。
刚发现现在要搞实名认证,而且只有付费才能使用。

在网上搜索了一下,发现一个好用的内网穿透工具:内网云。免费,然后更方便。
不需要注册,用的 SSH 方案,只需要一行 ssh 命令,做一个远程端口转发,就能实现内网穿透。
给了我这样的开发者非常大的便利。希望能一直用下去~

ssh -R 80:127.0.0.1:8080 sh@sh3.neiwangyun.net
Welcome to network server by neiwangyun.net
current server node : sh3.neiwangyun.net
----------------------------------------------------------
Basic Tunnel Information
  username      : sh
  type          : anonymous
  subdomain     : sxxelgxzm6efshsh3.neiwangyun.net
  remote_ip     : 121.60.84.218
  bandwidth     : 2 Mbps
  expire_time   : 2 hours
  unid          : d8scvjne5lt2c3svr2rny...
----------------------------------------------------------
Local Server
  local server: 127.0.0.1:8000
----------------------------------------------------------
Access to the Tunnel
  cname         : not support
  http          : http://sxxelgxzm6efshsh3.neiwangyun.net
  https         : https://sxxelgxzm6efshsh3.neiwangyun.net
  ipport        : sxxelgxzm6efshsh3.neiwangyun.net:25207
----------------------------------------------------------
Ctrl+C Exit Process

#863 Shell 循环执行

2023-03-23

根据《今天我靠chatgpt早下班2小时!太强了!》整理:

#!/bin/bash

# 锁文件路径
lockfile="/tmp/my.lock"

function cleanup {
    echo "清理锁文件"
    rm -f "$lockfile"
    exit 1
}
# 注册清理函数,确保无论脚本如何退出都会执行
trap cleanup EXIT

if [ -e "$lockfile" ]; then
    echo "WARNING: 另一个实例正在运行!"
else
    touch "$lockfile"
    echo "脚本开始执行"
    while true; do
        sh a.sh
        sleep 300  # 5分钟的间隔时间,单位为秒
    done
    rm "$lockfile"
    echo "脚本退出执行"
fi