duangsuse::Echo
712 subscribers
4.24K photos
127 videos
583 files
6.45K links
import this:
美而不丑、明而不暗、短而不凡、长而不乱,扁平不宽,读而后码,行之天下,勿托地上天国。
异常勿吞,难过勿过,叹一真理。效率是很重要,盲目最是低效。
简明是可靠的先验,不是可靠的祭品。
知其变,守其恒,为天下式;穷其变,知不穷,得地上势。知变守恒却穷变知新,我认真理,我不认真。

技术相干订阅~
另外有 throws 闲杂频道 @dsuset
转载频道 @dsusep
极小可能会有批评zf的消息 如有不适可退出
suse小站(面向运气编程): https://WOJS.org/#/
Download Telegram
#China #tech 🌚 脸红不? 2021 还不会写 ANSI C 编译器的同学们(
https://blog.csdn.net/myan/article/details/490 《Lua让我脸红》
Python是荷兰人写的,Ruby是日本人写的, #Lua 是巴西人写的,我这个中国人只能在这里脸红。

“ 我1996年就学会了C,1997年就跑去研究Win32 API,后来是C++,STL,Java... 直到2002年看到C Interfaces and Implementations,才知道仅仅用ANSI C就可以实现一个强大的优美的library,直到2004年看到Lua的源代码才知道仅仅用ANSI C就可以实现一个非常快的虚拟机、非常棒的解释器/编译器和非常漂亮的语言实现。

但是,看完这条的第一个链接你就会了 🌝(跑,但这篇文章的确精炼而且 practical
AlPlank
另外如果你也想写一个五子连珠练手,请注意: 1. 珠移动速度不要太慢,70 ms 一格看起来很快但是实际上已经很慢了 2. 注意六消七消之类的情况,由于更难达成所以可以诱骗玩家多消刷分(就像诱惑玩家擦弹然后 biu 一样) 3. 生成新珠重新检查以防五连不消的神仙情况(这个最容易被忽略) 4. 双消(同时两个方向)不能只消一个 5. 移动珠子时把前端锁上保证线程安全。
咱检查了下互动 live2d-widget ,发现是只有 200 行的全界面逻辑,真正的实现在 https://github.com/stevenjoezhang/asteroids/blob/master/asteroids.js ,被直接插入到 <head>
https://github.com/stevenjoezhang/live2d-widget/blob/master/waifu-tips.js#L62

- 绘制叠加在 <body> 上,果然是 canvas
- W 前进 AD 转向,smooth 动量
- B 键显式可打击项: #CSS .ASTEROIDSBLINK .ASTEROIDSYEAHENEMY { outline: 2px dotted red; }
- Space 键向前方发炮,炮弹存活时间随机,击中目标(网页元素)或死亡后播放粒子动画

细节: click 被屏蔽,只能 Esc 退出;右下角显示 press Esc to quit<h1>{score}</h1> ;实际可多玩家(支持多实例)但操作杆一样

关键算法(即 mainloop 涉及的绘制过程):
- 打击元素->隐藏 document.elementFromPoint(x,y) ,TEXT_NODE 则隐藏 parent
- 飞船的 flames (尾部火焰)
- 炮弹死亡时的 particles
- 炮弹本身 bullets

这次重写(上次是 snakes #zhihu)也告诉我们,一个旧时代「小游戏」程序所必须做的框架性工作。 #drawing #game
duangsuse::Echo
咱检查了下互动 live2d-widget ,发现是只有 200 行的全界面逻辑,真正的实现在 https://github.com/stevenjoezhang/asteroids/blob/master/asteroids.js ,被直接插入到 <head> https://github.com/stevenjoezhang/live2d-widget/blob/master/waifu-tips.js#L62 - 绘制叠加在 <body> 上,果然是 canvas - W 前进 AD 转向,smooth…
#web #trick 关于 bookmarklet ,有一个小问题:因为 CSP(content security policy) 限制不能加载外部代码
javascript:var s=document.createElement('script');s.type='text/javascript';document.body.appendChild(s);s.src='http://www.websiteasteroids.com/asteroids.min.js';void(0);
也即
javascript:document.body.appendChild(document.createElement("script")).src="http://www.websiteasteroids.com/asteroids.min.js";void(0)
加载脚本是会被禁止的,据说可以在 CSS 注入 JS 代码... 不太懂
可以用 document.location=`` 测试以上 URI
fetch+eval 也不行呢
其实是网页设置不对... 替换链接为 https://cdn.jsdelivr.net/gh/stevenjoezhang/asteroids/asteroids.js 就可以了
打得不亦乐乎,可是这两个都要重写怎么办呢 😭
#web #css #js 比较成功的重写了五子棋的 UI ,但是 invaders 估计要耗这一天了。写的时候发现不加 <DOCTYPE html> 会导致 height: 50px 指定被克扣,可能是 XML namespace 的原因吧(混合 SVG 渲染的)
#life #plt 说点设计上的吧。(老看工程实践也累了,迫真
谈谈 mvng 的一个特性和 ParserKt 新版解决的两个问题,为什么修这两个问题就能把它带入实际工程。

我对 mvng 还是有点期望的,和 LiteratePy 一样(之后它们传参配合应该还要折腾一番),因为弄完这个后将来的一些项目就会比较好做(尤其是大批量 Android 示例时,可以视为 LiteratePy 的临时代替),我这个人非常讨厌『项目创建』流程,如果能削掉会帮我节省很多麻烦。

原来就是一个"20行py生成pom"的小实验,后来倾向把它做方便一点,支持更多格式模板以及客制化什么的
要让它可配置肯定要支持两个: 1. -x 支持 :file 引用文件 2. -x@args 引用的文件可从 pkg resources 里取,这样就能做 -s id=com.example @android 的便利简写

mvng 本来只是生成 pom ,现在可能要变成子命令为重— pom, cp, wrapper, repo, conv, inc
因为是概念,没必要逐一细讲,到时候会写文档的(cp 是免写 src/main 等文件夹、inc 是加依赖);但是 conv 用于转换 pom.xml 和 *.gradle 的格式,就比较灵性。

且不谈 subproject, setting.gradle 切分问题,
这俩一个是 XML tree 一个是 Groovy 脚本,根本不一样(实际上我估计也有人写过 gradle 导出 pom 的脚本),但通过静态方法,可以大致把二者归一化,如
dependencies { implementation "wtf" }
实际就是(可以用 groovy AST 等方式转换)
<dependencies>
<implementation sarg="wtf"/>
</dependencies>
我们可以用 XML 树描述大部分(这里就是单 string 参数的调用,肯定不包含 android build 的一些模板代码)定义,只需进行树遍历改写,构造等价关系,然后进行一个 mv src dst 操作(它是可逆向进行的)
举个例子:
def convDep(e, reverse):
if not e.name in {"implementation", "compile"}: return
if reverse:
e.name = "implementation" #不支持其它方式
e.sarg = f"{e.xpath("groupId")}:{e.xpath("artifactId")}"
pass.append(convDep)
像这样,reverse=False 的时候是 gradle->pom ,构造;反之就是析构,把 pom->gradle (if reverse) 放在前面也有利于看见结构是怎样对应的。
pass
是针对每一个 XML 节点按顺序运行的(匹配&)转化任务,正向的时候 [a, b, c] ,反向当然是 reverse=True 再 [c, b, a] 展开回来,这都不需要几行代码,关键在逻辑上要明白这类事
所有翻译 pass 运行完后就可以按照一个 dict 设置的对应关系,把 buildscript/dependencies 变成 dependencyManagement 这样,这个是可以双向操作的。

所以我们就能通过简单的方法构造 POM <-> gradle.xml<->gradle 这样的 convert 程序,还是挺麻烦的 🤪

最后再感叹一下我(或许还有一些同道,或许人们是害怕的吧)的命运,上面引用的那个 gist 有一段时间了,我用四国语言🐸写了足足 7 个文件,竟然没有一颗 star ⭐️,反观一些网红/前端开发,稍微写点好玩的应用就有无数人竖大拇指,真是emm....
SPA: single page application (基本要加 URL param router)
PJAX: persistence pushState javascript https://pjax.herokuapp.com/
Forwarded from RWTG9Y4's STDOUT
一次完全失败的 PJAX 升级
改成 PJAX 加载后各种变量 / 函数互相冲突, event 绑定不上, replaceState + pushState 造成访问统计重复, 验证码状态异常等一堆问题
SPA 还是好文明, PJAX 实在是太糟糕了 😐
#项目 #SakuraFrp
duangsuse::Echo
#life #plt 说点设计上的吧。(老看工程实践也累了,迫真 谈谈 mvng 的一个特性和 ParserKt 新版解决的两个问题,为什么修这两个问题就能把它带入实际工程。 我对 mvng 还是有点期望的,和 LiteratePy 一样(之后它们传参配合应该还要折腾一番),因为弄完这个后将来的一些项目就会比较好做(尤其是大批量 Android 示例时,可以视为 LiteratePy 的临时代替),我这个人非常讨厌『项目创建』流程,如果能削掉会帮我节省很多麻烦。 原来就是一个"20行py生成pom"的…
再说说 ParserKt 新版解决的 "StickyEnd" 和 LexerFeed 问题。

StickyEnd 是造成 TriePattern—PKT 的 keyword tokenizer 无法应用于整个输入(fullmatchPattern)的元凶
所谓 sticky end ,是
fullmatch 的逻辑是,无论 pat 是否匹配成功(没成功就往 StringBuilder 里填一字继续尝试),必须 match 到输入末尾,但这就有个问题——不能判断当前是否 EOF ,结末的异常会被 pat 视作 notParsed 返回,而如果靠 consume() 测试,无法区分拿不到时是无可跳的(可立即解析),还是真 EOF 了

fun KeywordPattern.greedy() = Piped(this) { it ?: //FIXME is not possible
try { takeWhile { it !in this@greedy.routes }.joinToString("").takeIf(String::isNotEmpty) }
catch (_: Feed.End) { notParsed }
}

例如,需要进行对 peek 内容的词法验证
Seq(::CharTuple, item('a'), StickyEnd(EOF, 'e')).read(CharInput.STDIN)

这个问题设计构造结果的回溯何时执行,一直相当混乱,我也不清楚它到底是怎么弄出来的。
在旧计划里,我打算把 isEnd 加到 interface FeedControl 上,从而允许这个操作
新 ParserKt ,废除了泛型 input (为提高性能,而且也不需要支持 token 流了),尽可能减少不必要的 Exception 使用(实际上 Feed.End 也几乎只有几个 extension fun 在利用, catch 总数并没达到每个组合子一个)
估计还是只能选择 Int codePoint + EOF 常数了。

之前我想过用状态机,后来发现不太合适(而且按那种组合方法,Lexer 和 Parser 在词法层面的定义不可能复用)
新的 LexerFeed 作为 underlying stream ,可以和上层 parser 协调工作(持有 state ,非0则不预跳空格),同时保存 beforeWhites 与 spans ,自动过滤各种 /**/ , // 的同时保留 1_000, "ab c" 字面量的正确词法,同时不创建任何中间结构(一般还是要按 tokenText/tokenType 来存一个的),做到最小内存开销

要兼容这个更改,只需提供 p.save(RANGE_KIND) 函数即可,这个函数负责在读取前向 lexer 提供 state ,并在结束后提供返回值,不存在解析 AST 与语法 AST 的区分,空格等排版信息通过隔离的 Map 与 ASTNode 对应。

之前不方便解析的各种「貌似」需要 peek-N>1 的内容也有 Piped 提供的便利函数可以解决, KeywordPattern 将支持 /**/, //, -- 等注释前缀的处理, p.calm() 镇静策略如常
新计划的解析器会管理整体语法树(while 旧的只是打算写 toTuple 或者说 asIterable 来提供show()时解构的便利),并且提供基于 function 这样的 incremental 解析的功能,当然这需要编辑器支持 mark range 才行,是指提供 source span 这方面也不会存在问题了。
duangsuse::Echo
再说说 ParserKt 新版解决的 "StickyEnd" 和 LexerFeed 问题。 StickyEnd 是造成 TriePattern—PKT 的 keyword tokenizer 无法应用于整个输入(fullmatchPattern)的元凶 所谓 sticky end ,是 fullmatch 的逻辑是,无论 pat 是否匹配成功(没成功就往 StringBuilder 里填一字继续尝试),必须 match 到输入末尾,但这就有个问题——不能判断当前是否 EOF ,结末的异常会被 pat 视作…
其实嵌套 Feed 本身就比直接 read() ,或者可内联的 read() 有更多开销
但提供这一(函数指针)的可能,就有更多用途(stdin, file, 更多 InputStream 上进行更细致交互)的可能
所谓设计,就是在既有的最低开销下,即可能保证最大的「可能性」。

有时候明明在用更高级的语言特性、更复杂的包装,却能收获更好的性能,是因为特性的启用带来了一些全新的选择——这使它们在特定情况下变得更快
重构 setTimeoutrequestAnimationFrame ,发现二者几乎等价…… 计算单位几乎不用变,只需检测 FPS 是否需略过此回刷新;原代码也比较优雅,用的 tDelta 计算
#math 我将无我... 🌝 其实根本没用到,作者喜欢从别处复制粘贴?或者喜欢自己写一大堆(repeating...)没用的结构?
话说作者挺喜欢给自己找麻烦,非得 let that = this; 一个,用了 27 次,我挺反感这种主语混淆不清的代码

好像挺 English 的,其实写半天我看不懂 this that 是在指什么,代码又为何要换人称 🌚
#China #Telegram 挂人 🌝
Forwarded from Deleted Account
亲,收到这个信息不要诧异,整套tg协议软件,拉人/群发/进群/采集/机器人/监控/注册机(日产上万号),你懂的,在tg上谁掌控了账号,谁就掌握了流量,万人大群必备 技术@: xieyi969
#news #kotlin #java #android 又一个停运的,它还挺重要啊
--
草,许多个人库会不能用的。
估计届时很多Andoid项目build会炸
许多上游不收PR会被fork