分类目录归档:佳佳教程

[javascript]字符串映射到固定颜色

碰到一个需要给图表上数据打颜色的场景,我希望对于同一个名字的数据每次出来的颜色都是一样的,于是想了半分钟,搞出了这么个方案
“`javascript
function strToRGB(name){
let sum=0;
for(let s of name)sum+=s.codePointAt(0);
return [sum%128,sum%126,sum%124];
}
“`
原理是把每一个字符的unicode值累加起来,然后对这个和分别取3个余数。

除数选1到256都可以,选多少取决于希望结果出现在哪个范围,我这里为了让结果颜色偏暗,所以选了128左右的除数。

Windows半夜自动开机

首先容我说一句,搞出自动唤醒电脑更新系统这个策略的人是烧饼,搞出更新后无视用户任务自动重启电脑的人也是烧饼,说不定还是同一个人。

从Win10开始就有不少人遇到了这个问题,最后发现是系统更新半夜唤醒了电脑,关闭方法是在“任务计划程序”里找到”\Microsoft\Windows\UpdateOrchestrator\Schedule Wake To Work”这一项,把它禁用,如果提示权限不够无法操作,可以搜索一下如何禁用这个任务计划。

这篇文章我要说的是另一个问题,自从升级到Win11之后,之前在10里面已经改过的设置又被改回来了,又开始每天晚上自动开机跑更新,而且即使再改,它依然会被恢复到默认状态,晚上还是会自动开机,真实烧饼行为。于是只能换个办法来解决这个问题,我找到的一个办法是,既然任务计划唤醒电脑靠的是唤醒定时器,那么只要把唤醒定时器整个禁用掉应该就好了。

关闭方法是在当前的电源计划设置里找到“睡眠”→”允许使用唤醒定时器“,把启用改成禁用即可。现在几个晚上下来都没有再出现自动启动的情况了。

继续阅读Windows半夜自动开机

[ffmpeg]转码后音画不同步

音画不同步多半是在vfr(可变帧率)和cfr(固定帧率)之间转换的时候视频帧时间戳没有更新导致的,不知道为啥ffmpeg会默认以这种一定会导致错误的方式工作,但我们手动加入参数后就可以修正这个问题。

如果是一个vfr视频,ffmpeg默认会转换成cfr,如果不希望它转换的话,则在前置参数的位置加一个`-vsync passthrough` ,视频帧率模式就不会被转换了,这样只要原视频音画是同步的,那转出来音画肯定也是同步的,因为时间戳完全没有变。

[MySQL]This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled

MySQL中创建函数的时候如果出现了这个错误,表示创建语句中缺少错误中所示的3个函数行为声明,只要根据需求加在Begin前面就可以了。

如果你不确定,那就需要加`DETERMINISTIC` ,如果这个函数不会去操作数据库就写`NO SQL` (不是完全不能有SQL语句),如果需要读取数据就加`READS SQL DATA` 。

比如

CREATE DEFINER=`root`@`%` FUNCTION `poi`() RETURNS int
    NO SQL
BEGIN
	SELECT 1+1 into @r;
	return @r;
END

[Node.js]解决‘gbk’ codec can’t decode byte 0x80 in position

每次换一个环境执行npm i都会碰到这样的问题,记录一下解决方法,

方法1:手动去报错的文件里指定编码为UTF-8,我自己第一次解决这个问题就是用的这个办法,刚刚想找找看有没有别的解决方法的时候发现别人也有去手动改源码的,放个参考链接

简单地说就是找到报错的那行,给open函数加个`encoding=’utf-8’` 参数就可以解决问题,但这样属于改了人家文件,更新后还是会变回去的,所以现在我不这样做了。

方法2:去控制面板的区域设置里到“管理”标签页下,“更改系统区域设置”,把“Beta版:使用Unicode UTF-8提供全球语言支持(U)”勾上,然后重启一下,python就会默认用utf-8来读文件了。

这个方法会改变整个系统的默认代码页,最主要的影响是会导致使用非Unicode的程序乱码甚至崩溃,还有在gbk设置时以ansi保存的含有中文的bat脚本会乱码。如果影响不大的话倒是可以让系统一直保持在这个区域选项上,影响某些软件的正常使用的话在执行完需要的编译任务后还得改回去。在这种模式下可以使用“locale emulator”这样的软件以Chinese模式启动程序,以解决程序的乱码和崩溃问题。

方法3:我没试过,理论上应该可行,从python本体入手,把它的默认编码设置成utf-8,参考这里的方案2。这个没用

[MYSQL]删除JSON数组中特定数字

这问题折腾了我一下午,首先是mysql中没有现成的方法来寻找数组中数字的位置,然后是谷歌百度bing用中文和英文搜索都没找到可用又不烂的办法,爆栈网有一个高票答案,但是似乎并不对,JSON_SEARCH只能用来搜索字符串在json中的位置,数字不支持,不知道他是怎么得到结果的。

经过我晚上的继续摸索,翻遍了官方所有json相关的文档,终于让我拼出了一个方案,就是用`JSON_TABLE` 先把数组转成表,然后用where剔除里面不要的数字,再用`JSON_ARRAYAGG`转回json数组,以下是示例代码
“`sql
set @j='[1,2,5,8,9]’;
select JSON_ARRAYAGG(b) from JSON_TABLE(
@j,
“$[*]”
COLUMNS(
b int PATH “$”
)
) as `破mysql连个数组查找方法都没有`
where b<>5;
“`
这样就可以得到结果[1, 2, 8, 9],5被删掉了。

这个方法虽然并不优雅,但也没办法,谁叫MySQL连在数组里找数字的位置都做不到呢。

继续阅读[MYSQL]删除JSON数组中特定数字

[MySQL]对json字段中的数组创建索引

Mysql中在json字段里存放数组时,如果需要快速查找到包含某个数字或字符串的数组,则需要在这个数组上建立索引,其`multi-valued` 索引能满足这种需求。

在已有表的情况下,执行以下语句创建一个数字数组索引:
“`sql
ALTER TABLE 表名 ADD INDEX 索引名((CAST(json字段->’$.指向数组的对象名’ AS UNSIGNED ARRAY)));
“`
这个语句把json字段中的一个数组以无符号数组读出,并对每个数字进行索引,这样要寻找包含某数字的数组时,将使用索引提速。

如果数组内的成员都为字符串,可以这样创建索引(要注意,该表的排序规则需为`utf8mb4_0900_as_cs`,否则会报错):
“`sql
ALTER TABLE 表名 ADD INDEX 索引名((CAST(json字段->’$.指向数组的对象名’ AS CHAR(255) ARRAY)));
“`

接下来使用类似这样的语句查找拥有某个数字的数组所在的条目
“`sql
SELECT * FROM 表名 where 要找的数字 MEMBER OF(json字段->’$.指向数组的对象名’);
“`
或同时查找多个数字(字符串查找同理)
“`sql
SELECT * FROM 表名 where JSON_CONTAINS(json字段->’$.指向数组的对象名’, CAST(‘[1,2,3,4,5]’ AS JSON));
“`
使用了该索引后,作用在相关字段上的`JSON_OVERLAPS` 函数也会使用索引。

参考:https://dev.mysql.com/doc/refman/8.0/en/create-index.html

WebGL2画球

本文演示的代码均在这里,本文仅说明原理,不会细化到webgl基础。

最近学会了用WebGL2画球,其实学会也有两个多月了,但由于某些误解一直没法生成正确的贴图映射,导致贴图错乱,直到两周前才突然开窍发现了原因,又拖到今天才来发这么一篇文章。忙里偷闲做事就是效率低下,好在并没有什么迫切需求要做,慢慢学也无所谓。

要用WebGL画球主要就是要先建个球模,然后给它上色或者贴图。要贴图就要搞清楚每个顶点和贴图的坐标映射关系,不同的球模类型映射关系也不一样,我这画的是最容易理解的经纬球,即以地球仪那种经纬线为线框的球体。

接下来开始我们的正题。

先摆一个随便找的经纬球

现在假装看不见经线(竖线),只能看见纬线(横线),那么这个球外面每隔一定的角度就绕着一个正圆,我们生成模型也可以用这种逻辑,首先生成一个正圆,然后把它按角度调整好大小并放到正确的位置上。关于生成一个合适边数的圆的方法我在前一篇文章已经写过了,这里就不再赘述了。

继续阅读WebGL2画球

画一个尽量圆的圆

在屏幕上绘制圆的时候实际上就是在画一个正多边形,只是边非常多而已。

这篇文章来水一个画多少边合适的问题。(注:我并不是不知道canvas2d有圆弧绘制函数,这是为下一篇文章准备的内容)

要一个圆的边看起来平滑,就需要边数足够多,直到在屏幕上看不出它有棱角就够了,这里摆一幅图。

继续阅读画一个尽量圆的圆

ParseError: ‘import’ and ‘export’ may appear only with ‘sourceType: module

首先这个错误是Browserify报出来的,看着网上一篇篇给babel加preset的解决方案让我一度以为这是babel出问题了。

解决方案,添加模块`npm i esmify` 。

然后在browserify的plugin里添加一个`require(‘esmify’)` ,就可以解决以上报错。

举例

browserify({
	basedir:dir,
	debug: true,
	plugin: [
		[ require('esmify') ],
	],
})

 

============================以下是旧文============================

但我按照那些方案依然不能解决这个问题,比如加stage-0,还有加es2015的preset之类的,另外现在这些preset已经被弃用了,官方推荐用preset-env来代替。而我手动加了commonjs的plugin也一样报错。

一番研究之后发现我其他所有es模块被引用都能正常打包,唯独node_module里面的一个模块的es6模块不能加载,看来Browserify是默认不允许node_module里的模块以es6格式输出模块的。所以解决方案是要么把文件从node_module里移出来,要么想办法让Browserify允许node_module以es6输出模块,我最后用的是前者,因为那个sourceType:module我怎么设置也依然没有效果。

PHP输出内容到控制台

有时候本地开发的时候会使用`php -S` 命令启动一个服务器来调试,由于该web服务器模式直接echo会把内容输出到页面上,所以需要想办法把内容输出到控制台界面。

php里有几个`php://` 开头的特殊读写流可以使用,文档见此:https://www.php.net/manual/en/wrappers.php.php

虽然该页面上说有常量`STDIN` 、`STDOUT` 和`STDERR` ,但是不知道为啥使用它们会报错不存在常量,所以我们可以自己定义:

define('STDOUT',fopen('php://stdout', 'a'));
define('STDERR',fopen('php://stderr', 'a'));
define('STDIN',fopen('php://stdin', 'r'));

然后就可以定义自己的输出函数来输出到控制台了

function stdout($c){
	fwrite(STDOUT, $c);
}
function stdoutl($c){
	stdout($c.PHP_EOL);
}

stdoutl("poi");//输出到控制台,并换一行

 

Windows下挂载目录为驱动器

曾经我的电脑使用一块128G的SSD来放系统,程序和其他文件都在另一块机械硬盘里,后来换上了960G的SSD之后光是放了个系统和装了一些软件依然还空着500多G,所以想着还是把原本的80多G软件全都移到SSD里去吧。

那么问题来了,这些软件的安装位置全是D盘,如果直接把程序移走那会出很多问题,这就意味着我必须要确保把它们移到SSD后依然属于D盘,然后就想到了两个常规方案:分区,挂vhd。

首先是分区,在我用了macos和一些linux后越来越觉得分区这个操作很多余,完全可以使用文件夹来取代分区。主要问题在于分区会产生额外的空间限制,所以慢慢地我开始不再给自己的硬盘分区了,于是这个方案排除,但如果没有其它选择,这个方案还是优于vhd的。

然后是vhd,考虑到性能损耗和文件碎片问题,直接就排除了,我也不想看到一个几十G大的vhd。

由于当时我已经把所有软件移到了`C:\files\Drivers\D` ,所以直接开始寻找是否有办法直接把目录挂在为一个驱动器。一查果然有,一般都是说用subst命令直接把目录挂在为驱动器,如`subst p: c:\poi` 就可以把c盘的poi目录挂在为p盘。但是这个方案在win10似乎有些bug,需要一些曲折的操作来实现,所以不太好使。然后继续找办法。

最后在某一篇文章里发现可以在注册表里直接加驱动器,位置是`\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\DOS Devices` ,打开到这个位置可以看到已经有一些映射设置了。

那篇文章里写了一个注册表文件,内容类似

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\DOS Devices]
"P:"="\\??\\C:\\poi"

但是我试了一下发现并没有用,重启之后挂载出来了一个打了问号的驱动器,那么说明这个映射源并不存在,所以我这里的值不能这么写。

然后我参考了一下这个列表里的其它条目,感觉也许可以从`\DosDevices\` 下面直接进入驱动器号,所以改成了`\DosDevices\C:\files\Drivers\D` ,重启了一下果然挂载上了,现在这个目录会在开机时被挂载为D盘,并且由于属于同一个盘所以会和C盘显示同样的空间使用情况,有一个小问题就是这个盘没法修改卷标,所以也会和C盘显示一样的名字。挂载后的样子如下:

名字什么的无所谓了,好用就行。

另外这样挂载的驱动器没有回收站,但是可以去原始目录里删除文件,其实问题不大。

===========更新============

这个方法挂载的盘会在系统大版本更新的时候被重置,更新结束后映射会消失,需要重新设置,不建议用来映射存放程序的目录

PHP并行cURL中socks代理问题

这是一篇被坑记录。关键字: CURLOPT_PROXY, CURLPROXY_SOCKS5, curl, curl_multi_init, curl_multi_add_handle, curl_multi_exec, curl_getinfo, socks5.

我的友链状态是通过cron任务定时调用php脚本来检查的,并且这个脚本通过curl走socks5代理出去请求网站和对应的logo。

本来这个脚本是遍历json中的友链一个个去请求然后设置状态的,逻辑上没有任何问题,也可以顺利完成检测,问题是这样的检测时间太长了,如果我手动请求检测脚本的地址那么一定会执行超时,而且我会看不见结果。于是我想把这个脚本里的请求改成并行的,一次性请求所有网站。然后问题来了,按照php手册上 curl_multi系列的函数改好了脚本之后无论怎么运行怎么修改一定会执行失败。无论怎么修改,curl multi组一定会超时,所有请求都会失败,浪费了我六七个小时研究这个问题。

 

直到我偶然间看到了这个页面上的这段话

10.1 SOCKS proxy connections are done blocking

Both SOCKS5 and SOCKS4 proxy connections are done blocking, which is very bad when used with the multi interface.

我记得曾经我就尝试过把这个脚本改成并行请求,但也是因为无论如何都会请求失败后来直接放弃了。这个影响那么大的bug几年过去了依然没有修好,不愧是世界上最好的语言。

也就是说现在php的并行cURL不能设置socsk代理,否则一定会阻塞住然后请求失败,要解决这个问题只能改用http代理。