Friday, April 30, 2021

V2EX - 技术

V2EX - 技术


请问大佬们 CentOS7 的时间时区问题

Posted: 30 Apr 2021 05:08 AM PDT

# timedatectl
Local time: 六 2021-05-01 03:53:59 CST
Universal time: 五 2021-04-30 19:53:59 UTC
RTC time: 五 2021-04-30 19:53:58
Time zone: Asia/Shanghai (CST, +0800)
NTP enabled: yes
NTP synchronized: no
RTC in local TZ: no
DST active: n/a

我的时区确实已经选择上海,感觉 Local time 和 Universal time 反了过来,请问要怎么正确设置?

五年 PHP ,看了一下招聘行情,快要放弃最好的语言了

Posted: 30 Apr 2021 05:08 AM PDT

在深圳一家二线小厂转眼混了两年,迫于面对 salary 编程,想挪坑就搜了下招聘 PHP 的,一言难尽,感觉要失业,有内推的老哥,带我飞 cGhwY29kZXI2NjY=

建立了一个 tg 频道 发布一些开发新闻

Posted: 30 Apr 2021 05:05 AM PDT

集合了一些官方的 rss 可以替代官方的 newsletter

Android Dev News Blog: Android Developers Blog Podcast: Android Developers Backstage Medium: Android Developers

YouTube: Android Developers https://t.me/androiddevnews

日常工作中,你都会画哪些图,用什么工具画

Posted: 30 Apr 2021 04:46 AM PDT

我先来:
1 、流程图,通常用 Visio 或 PPT 画
2 、用例图
3 、思维导图,通常用 mindmaster
4 、数据统计图,通常用 excel 的画趋势图比较多,很偶尔用 LaTeX 画
5 、顶层设计图,通常用 PPT 画

最近在 B 站上看有些木匠、车工、建筑大师们画的图都很好看,而且很精细,相比软工或计算机似乎比较分散啊

搞了一个五秒盾方案,大伙帮忙看看都有哪些漏洞。

Posted: 30 Apr 2021 04:32 AM PDT

因为一些原因需要搞一个类似于 Cloudflare 的五秒盾,不是给公司用的,给个人站点用的。大伙看看有没有什么问题,比如绕过的方法,或者一些漏洞可以被用来攻击。

下面是流程图。

注意:流程图中提到的服务器是类似 Apache 和 Nginx 这样的服务器软件。

1C83AF6E11CD5164.jpg

我又来了啦~关于前端框架简单介绍的视频~

Posted: 30 Apr 2021 04:30 AM PDT

往期回顾: https://v2ex.com/t/774011

上一次尝试做的视频大家都说太长了,今天下午休假了在家继续折腾~~~这次试着逮住一个简单的点来进行介绍,时长比较短的确也比较难深入讲解哈哈哈哈哈哈

还在兴头上所以忍不住跑来分享下<del>后面继续再搞视频,就不那么频繁来骚扰大家啦,等我囤多点再来嚷嚷</del>

有人在生产环境使用 Quarkus 了吗

Posted: 30 Apr 2021 04:28 AM PDT

之前用 vert.x,后来发现了 quarkus,试了一下,发现现在 bug 实在太多了啊。

想用 kotlin,但是支持不是太好,2.x 开始支持协程,现在用异步只能用 mutiny 。。

c 端业务有哪些技术挑战?

Posted: 30 Apr 2021 04:21 AM PDT

高并发?一致性?性能? 哪些业务场景下会遇到这些挑战呢,电商?

[信息安全] 开放几个课程 ��

Posted: 30 Apr 2021 04:20 AM PDT

今天遇到了一个 curl 的问题,感觉有点坑

Posted: 30 Apr 2021 03:49 AM PDT

把今天遇到的一个实际问题简化一下,命令是:curl www.baidu.com/a/?expire=2&token=3,其中查询参数里面的 token 是必须有的,否则对方会报 403 。然后执行后发现居然响应是 403 ?加上 -vvv 看了一下,原来 curl 把我的命令给转化为了 curl www.baidu.com/a/?expire=2 & curl token=3,把 url 加引号后就正常了,也就是 curl "www.baidu.com/a/?expire=2&token=3"。感觉有点坑,也可能是我太菜了不知道这个。。。

Miui12.5 开发板已经好几周收不到 FCM 推送了,官方也不回复,各位有什么头绪吗?

Posted: 30 Apr 2021 03:17 AM PDT

[好奇��️] 大佬们平时都在早哪里看技术博客,免费、付费都可

Posted: 30 Apr 2021 02:59 AM PDT

大佬们平时都在早哪里看技术博客,免费、付费都可

自动订阅 app 被拒了 理由太沙雕了

Posted: 30 Apr 2021 02:54 AM PDT

最近写了个工具 app,里面有 3 个续订时间,月,季度、年, 提交上去给了个这拒绝理由:

We have started the review of your app, but we are not able to continue because we cannot locate the 月会员 and 季会员 in-app purchases within your app.

确实我的 app 里只给了一个年度会员试用后购买,因为我考虑是自动续费的,月度和季度会员可以在订阅管理更改。

有人碰到过这种问题吗

neo4j ui 上节点名称怎么全部显示, 现在展示的是缩略形式

Posted: 30 Apr 2021 02:45 AM PDT

如图所示 gEn1l4.png

DiskSpil...

Bounde...

A 记录与 CNAME 记录能同时共存吗?

Posted: 30 Apr 2021 01:52 AM PDT

各位大佬,域名解析中,

A 记录,比如绑定 www.xxx.com 到网站 IP
CNAME 记录,绑定 www.xxx.com 到 cdn 节点网址

CNAME 的线路类型选择境外,A 的线路默认,服务商是 DNSPOD,这样可以吗?

大量的对象创建,内存申请,有没有好的办法优化

Posted: 30 Apr 2021 01:17 AM PDT

求教各路大神们,如题,已经使用了 tcmalloc 和 protobuf arena,
多线程场景下,每个线程内部都会存在大量的对象创建(通过 arena createMessage ),对象结构复杂暂时无法优化,目前性能依旧很差,耗时很高,有没有好的方法

关于使用截图软件截图后,粘贴到编辑器图片格式是 PNG

Posted: 30 Apr 2021 01:00 AM PDT

请教各位一个问题,因为查找了很多资料都没找到解决办法。
问题描述
1 、使用截图工具进行截图:QQ 截图、微信截图、snipaste 等截屏软件,使用快捷键进行截图;
2 、在编辑器进行粘贴:UEditor 、有道云笔记、石墨文档等编辑器进行粘贴,会显示图片格式为 PNG 格式。
问题咨询
如果能实现粘贴后,粘贴格式为 JPG,或者 WebP 格式,同一张图片 PNG 比 JPG 质量高 2-3 倍。
感谢各位
因为发布文章使用的是对截图粘贴后自动上传保存,PNG 图片过大,如果再另存上传,步骤又过于繁琐。
所以请教各位有没有遇到类似问题,应该如何解决。

请教一个 nginx 的 rewrite 写法。

Posted: 29 Apr 2021 11:36 PM PDT

x.city.cn/post/???? 到  ai.city.cn/???? 的 url rewrite 。

感谢~~~

使用 Javascript 制作 BadApple 字符画视频

Posted: 29 Apr 2021 11:33 PM PDT

badapple

本文配有视频:点击播放视频

结合文章一起看效果更好


写作的背景

是这样的,最近有 B 站的小伙伴在我某个视频下评论,让我分享一下,这个BadApple动态效果怎么做。好家伙,我开始还不知道 badapple 是什么,结果我一看,so easy~。

image.png

不过,既然有小伙伴提出了这个问题,我就写一个完整教程,下次再有小伙伴问,直接看这篇,保管你用任何语言,任何框架都做得出来。

先拆解需求

  1. 播放视频
  2. 将视频每一帧的画面转为点阵 /像素 RGB 值
  3. 将 RGB 转灰度值
  4. 按照灰度值填充字符

需求很简单,稍微复杂的部分只有 RGB 转灰度,那我们直接开撸代码,使用vanilla.js框架(这是个梗,不明白的话自己搜)来完成开发。

1. 播放视频

使用 JS 创建一个video标签,并为它设置视频源路径

var videoDom = document.createElement("video"); videoDom.src = "./video/badapple.mp4"; videoDom.style.width = "900px"; videoDom.style.height = "675px"; 

由于我们最终的效果并不需要看到这个视频原画面,所以我们也不用将这个dom添加到网页body当中去。

添加一个控制视频播放和暂停的按钮

var btnPlayAndPause = document.createElement("div"); btnPlayAndPause.style.color = "#fff"; btnPlayAndPause.style.textAlign = "center"; btnPlayAndPause.style.position = "absolute"; btnPlayAndPause.style.top = btnPlayAndPause.style.left = "0px"; btnPlayAndPause.style.width = videoDom.style.width; btnPlayAndPause.style.height = btnPlayAndPause.style.lineHeight = videoDom.style.height; btnPlayAndPause.style.cursor = "pointer"; btnPlayAndPause.style.fontSize = "30px"; btnPlayAndPause.style.zIndex = 2; btnPlayAndPause.innerText = "play"; document.body.appendChild(btnPlayAndPause); 

当按钮点击的时候,切换videoDom的播放 /暂停状态

btnPlayAndPause.addEventListener("click",function(){         if(btnPlayAndPause.innerText === "play"){                 videoDom.play();         }else{                 videoDom.pause();         } }) 

监听videoDomcanplay事件,并渲染第一帧

videoDom.addEventListener('canplay',function(){     renderVideoFrame(videoDom); }); 

监听videoDomplay(播放),pause(暂停),stop(停止)事件在播放时启动字符画面渲染,暂停或停止时也停止掉字符画面渲染。

videoDom.addEventListener('play',function(){     console.log("开始播放");     btnPlayAndPause.innerText = "";      startRender(); });  //监听播放结束 videoDom.addEventListener('pause',function(){     console.log("播放暂停");     btnPlayAndPause.innerText = "play";      stopRender(); });   //监听播放结束 videoDom.addEventListener('ended',function(){     console.log("播放结束");     btnPlayAndPause.innerText = "play";      stopRender(); }); 

画面渲染的绘制频率和浏览器的绘制频率保持一致,这样不会丢掉任何一个画面,但算力消耗会更大。

var timerId; function startRender() {         timerId = requestAnimationFrame(updateRender); } function updateRender(){         renderVideoFrame(videoDom);         timerId = requestAnimationFrame(updateRender); } function stopRender(){         cancelAnimationFrame(timerId); } 

2. 将视频每一帧的画面转为点阵 /像素 RGB 值

这里我们要利用html5canvas标签,首先将视频的画面原封不动的绘制到canvas上。

function renderVideoFrame(videoDom) {     var videoSize = {width:parseFloat(videoDom.videoWidth),height:parseFloat(videoDom.videoHeight)};      var canvas = document.querySelector("#canvas");     if(!canvas){             canvas = document.createElement("canvas");             canvas.id = "canvas";             canvas.style.width = videoDom.style.width;             canvas.style.height = videoDom.style.height;             canvas.style.position = "absolute";             canvas.style.zIndex = 1;             canvas.style.left = canvas.style.top = "0";             canvas.width = videoSize.width;             canvas.height = videoSize.height;              document.body.appendChild(canvas);     }      const ctx = canvas.getContext("2d");      ctx.drawImage(videoDom, 0, 0, videoSize.width, videoSize.height); } 

注意看我这里做了判断,只在场景上没有指定canvas的时候,才创建它。

接着通过contextdrawImage方法,将视频绘制到场景上,现在我们body虽然没有video标签,但我们也能看到视频了。

image.png

接着我们再通过contextgetImageData方法,获得画布里的全部点阵 /像素数据。

var imgData = ctx.getImageData(0, 0, videoSize.width, videoSize.height).data; 

这是一个庞大的数组,数组的长度由width*height*4(宽度 x 高度 x4 )组成,4 代表 RGBA 四个值。

//如果这个画布是宽 2 个像素,高 1 个像素的话,那么 getImageData 获得数组结构如下 [r,g,b,a,r,g,b,a] 

这个理解了之后我们来看如何获得指定位置的RGBA值。

for (var h = 0; h < videoSize.height; h++) {     for(var w = 0; w < videoSize.width; w++){             var position = (videoSize.width * h + w) * 4;             var r = imgData[position], g = imgData[position + 1], b = imgData[position + 2];     } } 

通过画布宽度和高度的两次for循环,换算得出所有点阵 /像素在数组中的起始序号。

  • r = imgData[position]
  • g = imgData[position + 1]
  • b = imgData[position + 2]

大家可以看到,一块 200x300 的画布=6 万个点阵=长度为 24 万的数组,我们肯定不能按照像素 1:1 来绘制,这样运算量过大,并且绘制出来的效果也不好,你根本看不清文字内容。

所以我们要加入一个间隔,比如1:12,这样运算量大大减少,但是绘制出来的精度也会降低。

2021-04-19 16_09_36.gif

实现这个效果我们不需要alpha,接下来的重头戏是把 RGB 转为灰度值,灰度值再转化为笔画密度的文字,比如黑色的像素块我们就用这个字来替换。

3. RGB 转灰度值

我采用了文中所列的第二种方法

Gray = (R*30 + G*59 + B*11 + 50) / 100 - 0.5 

这个值在0.5-255.5之间

4. 按照灰度值填充字符

首先我们要建立一个灰度字符数组,按照笔画密度 /视觉灰度(从高到低)排列,最后留一个空白字符去表现纯白色。

var asciiList = ['猿','帅','老','大', ' ']; 

将灰度值转为字符数组的序号,使用Math.min方法来确保序号不会越界

var i = Math.min(asciiList.length-1,parseInt(gray / (255 / asciiList.length))); 

总结

这是一个自我接触计算机以来就知道的特效,我的职业历史上也用各种语言分别实现过。其实拆解需求后,核心就是获取画面点阵信息,RGB 数据转灰度或者二值化(仅黑白两色)。再根据灰度信息替换为字符即可。

希望我的这篇教程让你彻底学会,以后不管用什么语言,什么环境,找到对应的 API,都能开发出来这个效果。

One More Thing

照我以往的风格,我也将这个特效代码做了个收藏夹的版本,B 站任意视频都可以用这个效果来播放~

javascript:!(function(){console.log("badapple effect enabled");function renderVideoFrame(videoDom){var asciiList=['猿','帅','老','大',' '];var scale=parseInt(videoDom.videoHeight/parseFloat($(videoDom).css("height")));var gap=12/scale;console.log(scale);var videoSize={width:parseFloat(videoDom.videoWidth/scale),height:parseFloat(videoDom.videoHeight/scale)};var canvas=document.querySelector("#badapplecanvas");if(!canvas){canvas=document.createElement("canvas");canvas.id="badapplecanvas";canvas.style.width=videoDom.style.width;canvas.style.height=videoDom.style.height;canvas.style.position="absolute";canvas.style.background="#fff";canvas.style.zIndex=999;canvas.style.top="0";canvas.style.left=(parseFloat($(videoDom).css("width"))-videoSize.width)/2+"px";canvas.width=videoSize.width;canvas.height=videoSize.height;videoDom.parentElement.appendChild(canvas)}const ctx=canvas.getContext("2d");ctx.drawImage(videoDom,0,0,videoSize.width,videoSize.height);var imgData=ctx.getImageData(0,0,videoSize.width,videoSize.height).data;ctx.clearRect(0,0,videoSize.width,videoSize.height);ctx.font=gap+"px Verdana";for(var h=0;h<videoSize.height;h+=gap){for(var w=0;w<videoSize.width;w+=gap){var position=(videoSize.width*h+w)*4;var r=imgData[position],g=imgData[position+1],b=imgData[position+2];var gray=(r*30+g*59+b*11+50)/100;var i=Math.min(asciiList.length-1,parseInt(gray/(255/asciiList.length)));ctx.fillText(asciiList[i],w,h)}}}var videoDom=document.querySelector("video");videoDom.style.display="none";videoDom.addEventListener('canplay',function(){renderVideoFrame(videoDom)});videoDom.addEventListener('play',function(){console.log("开始播放");startRender()});videoDom.addEventListener('pause',function(){console.log("播放暂停");stopRender()});videoDom.addEventListener('ended',function(){console.log("播放结束");stopRender()});var timerId;function startRender(){timerId=requestAnimationFrame(updateRender)}function updateRender(){renderVideoFrame(videoDom);timerId=requestAnimationFrame(updateRender)}function stopRender(){cancelAnimationFrame(timerId)}})() 

新建一个网页书签,把以上代码复制粘贴到网址中,名称随便取。打开任意 B 站视频页,点击该书签,即可开启字符画播放模式,快试试吧...

image.png

现如今隐私权限管理上有能跟 XPrivacyLua 平起平坐的吗?

Posted: 29 Apr 2021 11:07 PM PDT

曾经试过用 Device Info HW 这类的 app 去测试各种权限管理 app 的限制能力,只有 只有 只有 XPrivacyLua 能把这个 app 收拾的服服贴贴,什么制造商、品牌、型号、设备、版本号、基带、指纹等等各种信息全部搞成"unknown"(必须配合付费版的 pro 的功能,否则还是有两三项信息能被获取)。而其他的什么 appops 之流,根本就是摆设,反正品牌型号设备这些参数全部被拿到了...

时代总是在进步,如今有啥新出的隐私 /权限管理 app 能和 XPrivacyLua 平起平坐吗?

Laravel Octane 初体验

Posted: 29 Apr 2021 10:02 PM PDT

老哥们有碰到过 AWS EC2 突然无法连接的情况吗

Posted: 29 Apr 2021 09:56 PM PDT

公司最近有台 EC2 突然无法 SSH 连接,登录 AWS console 看到 CPU 使用率突然上升到 10%(平常也就 0.3%左右),怀疑是不是被用来挖矿了?虽然重启了就好了,但是怎么反查或者预防这种情况呢?

这里有一段代码,有一些小细节,不是很明白。请教一下

Posted: 29 Apr 2021 09:13 PM PDT

// 1 struct Base {     int retCode {};     std::string retErrorString; };  // 2 template <typename Type> struct EventResult : Base {     Type retValue {}; };  // 3 template <> struct EventResult<void> : Base {}; 

代码段 1 中间的 int retCode 后面为什么要添加一对{},代码 2 也有类似的,Type retValue {} 代码段 2 已经定义好了模板,为什么要添加代码段 3 ?

Android studio 最新 canary15 发布,初步支持 M1

Posted: 29 Apr 2021 08:31 PM PDT

Android Studio Arctic Fox Canary 15 contains preliminary support for Apple Silicon (arm64).
有没有大佬测试测试性能 github.com/yozhik/AndroidStudioBenchmark

云上 chia 解决方案

Posted: 29 Apr 2021 07:25 PM PDT

chia 云挖矿方案
方案一(高 IO 型 IT5 IT5.4XLARGE64 16 核 64GB SDD3570GB*1 )*3 + 低频存储(存储按使用量计费)服务器刊例价 2650 元 /台*3=7950 元 企业新拓客户续费赠送 5000 元代金卷 ,单台服务器可以并发 P 图 8,24 小时两轮可以 P 图数量 3235GB ;
方案二 (高 IO 型 IT5 IT5.4XLARGE64 16 核 64GB SDD3570GB*1 )*14+ 低频存储(存储按使用量计费)服务器费用 37100 元 企业新拓客户续费赠送 20000 元代金卷,单台服务器可以并发 P 图 8,24 小时两轮可以 P 图数量 22646GB ;

请问有没有支持两步验证的硬件呀?

Posted: 29 Apr 2021 07:09 PM PDT

目前的两步验证( Two-factor authenticator )需要一个类似于 Microsoft authenticator 的手机 APP 。如果遇到系统大更新,保不准就会出现软件崩溃问题。如果做成一个单独的硬件,则可以避免这个问题。

但两步验证的硬件似乎只有类似 Yubico,目前没有很多开发商支持这个协议。但是如果可以使用 Microsoft authenticator 常用的作为时间的函数的数字验证码等我方式来做,可以减少很多兼容性问题。

我查了一下淘宝和本站,好像还没有关于类似的硬件的讨论,请问大家知道有类似的硬件出现吗?

理解 HTTP 缓存机制

Posted: 29 Apr 2021 06:04 PM PDT

理解 HTTP 缓存机制

原文链接: https://www.liuxing.io/blog/http-cache/

HTTP 缓存主要分强制缓存和协商缓存。强制缓存由 Cache-Control,Exipres ( HTTP1.0 )控制。浏览器直接读本地缓存,不会再跟服务器端交互,状态码 200 。协商缓存由 Last-Modified / IfModified-Since,Etag /If-None-Match 实现,每次请求需要让服务器判断一下资源是否更新过,从而决定浏览器是否使用缓存,如果是,则返回 304,否则重新完整响应

[TOC]

有关" Use After Free"的问题

Posted: 29 Apr 2021 01:22 PM PDT

C++学艺不精看不懂这个错,请各位大佬帮忙看一下这里为什么会报一个Use After Free啊。

Result<pcrepp, pcrepp::compile_error> pcrepp::from_str(std::string pattern, int options) {     const char *errptr;     int eoff;     auto code = pcre_compile(pattern.c_str(),                              options | PCRE_UTF8,                              &errptr,                              &eoff,                              nullptr);      if (!code) {         return Err(compile_error{errptr, eoff});     }      return Ok(pcrepp(std::move(pattern), code));//这一行报错 } //报错信息 //call to `Result` eventually accesses memory that was invalidated by call to `free()` on line 86 indirectly during the call to `Ok`. //84.     } //85.  //86.     return Ok(pcrepp(std::move(pattern), code)); //        ^ //87. } //88.   

Ok方法

template<typename T, typename CleanT = typename std::decay<T>::type> types::Ok<CleanT> Ok(T&& val) {     return types::Ok<CleanT>(std::forward<T>(val)); } 

Result的构造函数

    Result(types::Ok<T> ok)         : ok_(true)     {         storage_.construct(std::move(ok));     }  

谢谢各位大佬了[抱拳]

可以把自己写的程序打包之后推送到 yum 仓库吗?

Posted: 29 Apr 2021 10:00 AM PDT

RT,我有一个 Go 语言开发的小工具,我想把它编译之后的二进制文件打包成 rpm 包并发布到 CentOS yum 仓库上,搜了一下没有找到相关的东西,恳求了解的大神解答一下,谢谢。

用 wrk 和 ab 给 NIO 做压测的时候, selector 卡死了

Posted: 29 Apr 2021 06:24 AM PDT

不知道各位大神有没有遇到过这个问题。

用 wrk 或者 ab 给 NIO 做压测,第一轮没什么问题,但是如果第一轮结束后 立刻进行第二轮,第三轮,第四轮, 很快就会出现卡死的情况。 尤其是 wrk,测试结果一轮比一轮惨,惨到极致后又恢复到第一轮的水准。 ab 倒是挺稳的,就是连续多轮后会卡死

已经排查过自己的程序了,卡死期间: 队列 0 积压,CPU 占用也为 0.

在 selector 的循环中 试过打印一段文字,当卡死的情况发生时,这段文字也不打印了,所以初步怀疑是 selector 卡死了。

出现的原因 也大概在两个点:

1. 我的电脑太烂了,可能承受不了这么多的连接频繁访问。
2. 读 channel 的时候卡死了,目前我是读到 read 返回 0 为止,理论上不会卡的。而且如果出现空转了,cpu 不应该为 0.

一头雾水,求各位大神给个排查的思路。

以下是测试的命令

wrk: ./wrk -c 100 -t 3 -d 3s http://127.0.0.1:8080/json
ab: ab -c 100 -n 1000 http://127.0.0.1:8080/json

No comments:

Post a Comment