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

技术相干订阅~
另外有 throws 闲杂频道 @dsuset
转载频道 @dsusep
极小可能会有批评zf的消息 如有不适可退出
suse小站(面向运气编程): https://WOJS.org/#/
Download Telegram
借着这个官方手刃同人的机会,咱来谈一谈 Channel comment board 应该怎么写。

这里不提及回调、消息队列、按钮盘和内联之类的细节,只写成接受必要参数的 fun onXXX() 的形式

与 Telegram 的数据交流与存储责任优先提及:
inline keyboard 各钮的文本和 callback ID 由tg保存,回调含 targetMessage

bot PM(private message) 含事件 onMessageEdited, onMessageDeleted

单单实现添加评论很简单,在按钮链至PM /start 后提示用户输入,再更新目标消息、插入"${user.name}: ${msg.text}"即可。

不过这个流程会被打断成 inline-button 存 targetMessage 再 pm 得检查关于 user 的 state (1参, targetBoard) 才能做到收到后更新。

这个状态表优化后就是 Map<UID, MID>
可以设计为 UserState: add(u,v) get(u) pop(u) 的形式

onKeyboardCallback(msg,key) = state.add(msg.user, msg)
onMessage(chat,msg) if (chat.isPM)
msg.command == "start" -> if (state.get(msg.user) != null) /*提示*/
state.pop(msg.user)?.let { /*更新board*/ }

如果要支持编辑/删除消息操作,必须进行一定程度的关系型数据库建模。
因为文本是由 board 保存的,可以仅对 board msgId : PM msgId 实际储存,从而能在 PM 删除时 getBoardMsg

Board(channelId, msgId)
hasMany PM(msgId)

顺便存 chan. Id 也无所谓,如果实现 channel 的 board 枚举用得到

至于编辑可以实现 parse:(String) -> Map<UID, String> 操作和对应的 toBoardText() 操作,当然也可以直接 String.modifyBoardText(i, text)

以字符串保存列表必须处理转义问题(比如单项的换行符必须保留,人类可读,就可以用 "\n(.*):  " 切分而替换单项的文本,不过在 tg 里用 bold mark 标注用户名就可以了),但这样还是比独立存储文本再去拼合的开销低。

但仅这样还差一点:不知道要修改的是第几条。假设一个 board 同 user 只能有一条评论,可以再建立一个记录 Board hasMany BoardUser(no, user) ,或者如果 SQL 扩展支持数组的话,直接保存用户ID数组

必须保存创建编号来升序排列,而可 indexOf 查出编辑消息用户的位置,不过这样也就可以同时做一个『最近评论』页了…… (以编号降序,某人在某板评论了 board.findPM(/**/) )

毕竟关系数型据库的 record 除了 "relation" 外也称为 "entity"

当然,更正经的做法是直接保留 PM 的创建顺序,然后查某pm在某board里的位置(pm.board/*findBoard()!!*/.indexOf(pm)),上面是提示思维过程。

关系型数据库的名字可不是白叫的,它不是像 CSV 一样,仅仅像 ORM(object rel. mapping) 一样是 List<T> ,尽管它所支持的“关系”非常初步,而且基于 foreign key,只有 hasOne/hasMany 以及 relation "wtf" 的双边关系。
今天早上胡思乱想了一会,给一个写起来节约空间,基本上算英文绝句初版的 AtScript (为啥东西设计的现在提了也没用) 弄了个有意思的缩进语法:

thing WTF were
  fun init() = noOp()
  val layout = verticalLayout:
    text("emmm")
    button()

这个英文版的结构是 class/thing/insta/fun 用 were, for/while/if/when 用 do , 闭包用 do |a,b| 。

这个利用分号的语法也是为了节约击键次数(为此里面的类型都是 Bool,IntX+Idx+Cnt,Char,Str 这样)设计的特殊调用参数列表语法,有了它应该还可以结合 optional 参数,拿来写 DOM:

import markup.html.*
root = body:
  script(src="wtf.js")
  div(css="list"):
    a("#", "link")

print(Document:
  head(title("bad"))
  root)


实现什么的不用担心啦,就是在 o.x, o[i] 和 o() 左递归链后面加料(:) 呢。

说起来,如果 o() 不在左递归链里,而是把 o.op() 解析为 GiveSelf(o, Call("op", [])) 也是可以的,但是和底层不太对仗也容易搞混优先级,不过优点是可以写出 o.!contains(x) 这种基于函数变换的表达式(就有点像 Elixir 的 |> railway 了),哈哈。

不过重点不是这个。我打算给这么语言支持 suspend function (也就是 coroutine)

实现起来并不困难,扩充于 FunctionAst 建立一个 CoFunctionAst 就好了,里面嵌套的 CoFunc.invoke 也靠 instanceof 判断能提供 指令指针栈的 resume 信息, CascadeMap+LexicalBinding 就能保留闭包数据,可惜只能做到 Python/ES6 的语句级别保留执行状态。

其实我对 coroutine 是不了解的,除了知道 Lua 是非对称协程(只能将执行权转交给 resume 者的协程)、 ES6 的 await/async 和 co 的 Promise/Thunk(返回“收回调”函数的函数) 是由将 suspended 协程(下片也即其“回调”部分)交给其之前 yield 的 Promise 的方式来解决回调嵌套外,不知道具体的利用方法(如序列化、 "suspend fun" 的封装)。

为此我去问同写 Kotlin 的冰封哥,Kotlin 的协程为什么会有"Scope",答复是“CoroutineScope 是 CPS 变换的 Context” (CPS, continuation passing style, 传递函数进程的手段),我一直没弄懂这个上下文到底是咋用的,它和 Scoping 又有没有关系。

CPS 可理解为上面 ES6 await/async 二者一起(await=yield, async=co) 进行 await op1(); op2() 变执行实为 op1(() => op2()) 的手段

我不解的是,如果 continuation 是传递回,那必须 capture 住整个栈,但传递上是不需要的。
如果 Kotlin 的 CPS 就是把 o.await() 前的部分交给 o ,复苏 continuation 就仅需 return 到调用栈某一层因为栈上已经保留了所需信息,为什么会需要 CoroutineIntrinsics 的 create,resume,suspendOrReturn 三基元呢?
这种方法能实现 Sequence(即 generator) ,看起来它比协程高级,那么它到底和被数据化的子程序状态(coroutine)有什么关系?

百思不得其解,于是我打算以我懂的 ES6 generator 来实现(缺点是只能把 yield 建模为语句而不是函数)

但是我仍想用三基元,而且还是想让 yield 函数去带参 suspend 当前协程。

结果我发现了一个问题,导致我有点理解了 Kotlin 的设计:协程挂起后该由谁恢复?

suspend fun s123 were
  yield(1); yield(2); yield(3)

(老实说 #Kotlin 的“无需分号化”也有点迷, println(1) println (2) 算不算中缀调用说不清)

上例 s123() 挂起了可以得到当前项,最后可以抛 StopIteration 之类(或作为 resume() 返回值),可是假设我是要实现 Iterator 而必须有 next/hasNext ,从而我得保留 1项的流不变视口,在语言内部自然是不适合处理(为扩展性)

于是我想到了 fun sequence(builder: suspend BuilderScope.() -> T) 收的函数类型,其实有 BuilderScope.yield

这样你可以把 sequence builder 直接表达为 Iterator :

var lastItem: T? = runCatching { resume(builder) }.getOrNull()
// 只是举个例子, T:Any? 也可独立出 var hasLast
fun hasNext() = lastItem != null
fun next() = lastItem.also { /**/ }


明白了,那么 delay(1000).await() 也就可以理解为 Scope 里的 ext fun Async/*Deferred*/<Unit>.await() ,这也就解释了 Kotlin 支持 local fun 却不支持其 with receiver 是因为仅 class 级别可以。

它和协程对象本身的关系就是:(制定一个顺序,这里举例回调)

runOp(callback={ resume(this@Scope) })

结合星野大佬的经验 http://blog.hoshino9.org/2018/12/31/paint-board.html

var timer = GlobalScope.async { delay(1000) }
fun main() = runBlocking {
println("begin")
timer.await()
timer = async { delay(3000) }
println("finshed")
}

据说 runBlocking 会在所有内部 coroutine 执行后返回,所以此程序在 timer= 时阻塞,要改正只需换回 GlobalScope.async 。

await 本身也算协程,感觉应该很奇怪,但这是必须的。
假设没有任何 CPS 编译优化, op.await() 就应该是把当前上下文(协程状态)交给 op 以待其 resume ,所以 await 当然是非阻塞的,而且它会将当前协程挂起 (suspend fun)
方便。原来就想 Cloudflare workers 可以拿来托管 bot 🤔
Forwarded from Soha 的日常 (Soha Jin)
刚才给本频道添加了一个关联群组,那么以后本频道就有评论区了!(鼓掌👏
但那个群组只是为了启用评论功能而设置的,所以请不要加入。如需评论,请直接点击频道内推文下方的评论按钮(没有按钮的话就请升级到 Telegram 的最新版本),那个功能不需要加入群组也可以正常使用。
如果加入了那个群,会被机器人踢出并封禁 1 天,被封禁的时候评论功能也是不可用的。
至于为什么这么做已经在上一条推文中提过了。
机器人用到的代码公开在这里
#Linux #freedom Telegram BLUG shut 了🤔
Forwarded from BLUG Username Hold
请各位订阅者如有需要,左转到主站 https://beijinglug.club 和聊天室。谢谢茄子~
Forwarded from 螺莉莉的黑板报
https://deno.land/x/cat_you/
奇葩 deno 模块大赏:cat_you,提供一个 API 可以生成随机的猫咪 ASCII Art。
#迷惑行为大赏
是啊, 23+2 mod 24 = 1 位置记数法进制问题的确很基础,然后乘法表什么的的确扯,就是 (1..9)./*flat*/map { a -> (1..9).map { b -> if (b>a)/*(1*9==9*1)*/ "" else "$a×$b = ${a*b}"} } 嘛,不稀奇呢
Forwarded from 螺莉莉的黑板报
「正确的讨论方式」
啧啧,花了那么久特化,最后往回修了啊。
#China #web #dev #Low 啧啧,今日头条内核、今日头条推荐、今日头条CV
Forwarded from 螺莉莉的黑板报
【轶闻】【悲报】今日头条在搞自己的浏览器内核了,今后除了死妈的腾讯 X5 你还要去调一个傻逼头条内核,搞不好还要被强迫在手机上装一个头条的产品用来调兼容性。
滚啊,赶紧滚啊!头条你赶紧倒闭啊!不要啊!你们不要过来啊! QAQ|||
你们再这么瞎几把搞我也去写癌批批了!再也不信仰 Open Web 了!
QAQ|||

(个人认为,自己瞎鸡把搞浏览器内核这种行为比搞个「红心浏览器」更让人感到恶心。)
Forwarded from Qv2ray Outpost
⚠️来自 Qv2ray 项目组的消息⚠️

Qv2ray 项目组与其它相关领域人员经过研究后发现,V2ray 默认设置会出现严重 TLS 安全性问题

在 V2ray 内核默认不开启 AllowInsecureCipher 的情况下,V2ray + 任意启用 TLS 的配置都会带来 100% ⚠️识别率(参见 issue https://github.com/v2ray/v2ray-core/issues/2509

在综合考虑到 精准识别 V2ray 流量解密不安全加密套件 的实现成本后,我们建议所有用户开启 AllowInsecureCipher

—————————————————
== 右键链接,点击编辑,右侧 TLS 设置中即可查看有无 TLS
—————————————————
此问题的 临时 解决方案:
- 在首选项打开 AllowInsecureCipher重新导入/更新订阅
—————————————————
未使用 TLS 的用户不受此次问题影响
Trojan 用户不受此次问题影响
—————————————————
Forwarded from 螺莉莉的黑板报
https://fuck-castic.github.io/
全国青少年科技创新大赛离谱项目名单。

我非常明确的反对这个项目,孩子没有错,有错的是家长,但是你们却把什么都不懂的孩子拿到台面上批斗,我觉得这是非常不合适的。这已经不是有道德瑕疵了,这种项目本身就是不道德的。

在进行道德审判前请务必想清楚你在反对的是谁、你在做的事情究竟伤害了谁。

0/10

#RORIRI_BENCH
#Telegram var lastMsg = g.history[0]; val isAh={t:String -> t.all{it == "啊"} && t.length > lastMsg.text.length || t.length <= 3 } ; onNewMessage { if (it.user == lastMsg.user || isAh(it.text.replace("AhAhAh","啊")) ) +(it.delete()) else lastMsg=it }
Forwarded from 螺莉莉的黑板报
迷惑行为大赏

一个只能啊啊叫的群
@AhAhAhGroup

一个只能耸肩的群
@ShrugGroup