本文由于内容较多,建议在导航中找到你需要的章节转跳,除了文章开头的图片,其余图片都做了隐藏。
只是组件是一款好看又实用的桌面组件工具,自从2020年10月上架以来,完全的自定义、便捷的设置和方便的转跳受到用户的广泛好评。使用只是组件,你可以拥有10+预设组件,包含相框照片、待办、日期记录等;你可以可视化自定义一个全新的完全不同的组件或者导入他人的组件;你可以将网络数据解析后显示在组件内,点击组件你设定的地方转跳执行特定操作。不仅如此,只是组件所有功能均可以免费使用,仅限制最多已添加组件数量。
目前文档在更新中,预计十二月三十一号会完成更新。
希望你喜欢 只是组件!
苹果官方给出了一个如何添加小组件的说明:见这里。
这里只需要选择“只是组件”,添加本软件的Widget即可。
如果以添加一个文字Widget为例,分为这几部:
软件的所有组件都可以进行导入和导出,包括预设组件和自定义组件。
导入组件有两个入口,一个是桌面软件图标的Force touch,一个是主界面右上角的二维码图标。
导出组件在组件编辑界面右上角,图标为分享按钮。
导入导出都可以选择通过二维码或者通过字符串,如果组件包含的信息量过大,建议通过字符串导入导出。
这里提供一个导入导出简单演示的动图:点这里。
目前软件赠送的激活码均为单设备永久激活,激活码区分大小写。
激活方式为软件内激活。点击下方关于转到关于页,点击“分享应用”,在“激活码”框中输入。
如果激活码通过验证,稍等片刻软件就将解锁高级版内容。
如果激活失败,请确认软件是否有联网权限以及激活码是否准确没有缺失。
软件主程在安卓时代曾经花了很多的时间在安卓自定义组件上,可惜苹果上没有那么便捷的自定义,十分遗憾。
所以有了这个类PS的完全自定义组件,可以从头做一个专属组件,也可以导入别人做好的组件。
不过,最首先的一点,在做自定义组件的时候记得随时保存,即点击右上角的对勾。
这里提供一个动图,简单的可以感受一下这个自定义组件的大致内容:这里。
如果你愿意花几分钟看一下视频,可以点这里查看一个详细的操作演示:这里。
当然,百闻不如一试,充分的自定义只等你来实现想法。
我们也会定期收集优秀的自定义组件,做一个展示和分享,在这里你可以找到许多好看的组件。
欢迎你分享你的优秀作品,可以通过二维码添加交流群或者微博@我。
Widget的一大实用功能就是快捷转跳,通过点击Widget的特定位置,可以打开微信扫一扫、微信支付、健康码、乘车码等等,甚至可以通过捷径实现一系列的自动化操作。
在软件中可以通过预设组件的快捷启动组件和自定义组件的转跳特效完成这一效果。
预设组件的快捷启动较为简单,这里就不多加赘述。自定义组件的添加转跳可以查看这个动图。
关于快捷启动应该填写的内容,详细的可以查看这篇文章,软件未来可能也会增加一键添加捷径的功能。
Widget很大的一个实用性限制就是只能显示一些本地的内容,如果可以便捷的显示任意网络内容,那就实用的多。
所以软件提供了任意网络数据的格式化与显示,你可以通过以下三种格式解析网络数据:
网络数据会根据设定的更新间隔自动后台更新,但后台更新需要注意:
所以为了保证软件表现正常,请尽量在Widget中使用快捷转跳,否则Widget将被认为是不常用软件,无法后台唤起。
具体的操作我们提供了一个使用演示:这里。
其中文本解析中的规则,以数据源名字weather
为例,如果数据内容是这样的:
1 | { |
那么获取数据中温度的规则就是:
1 | $(fetch.weather.data.temp) |
其余的也是类似的规则,类推可知。
软件的另一大特色功能(另一大文档大头)是一个文本解析系统,通过类似Excel的简单规则,拼接各种数据,数据我们需要的内容。
我们提供了一个操作的展示:这里。
例如一个最简单的时间,规则就是:
1 | $(date.HH:mm) |
在网络数据一节还看到了关于网络数据的解析规则,除此以外,还有一些系统数据的获取规则。
类型 | 关键词 | 内容 | 示例 |
---|---|---|---|
电池 | battery | level, state, charging, lowpower | $(battery.level) |
蓝牙 | bluetooth | $(bluetooth) | |
系统 | record | country, language, reboot, brightness, volume, timezone, name, systemName, systemVersion, model | $(record.brightness) |
内存 | memory | all, active, activepercentage, inactive, inactivepercentage | $(record.active) |
硬盘 | disk | all, active, activepercentage, inactive, inactivepercentage | $(disk.active) |
Wifi | wifi | ip, ssid | $(wifi.ssid) |
健康 | health | stepCount | $(health.stepCount) |
之后将更新更多数据,文档也将同步更新。
Q: 邀请好友后没有马上更新数据。
A: 邀请数据的统计会在每天十二点更新,所以第二天再看就有新的数据了。
Q: 组件有时候会卡住不更新数据。
A: 组件本身刷新有非常小的概率出现这个问题,目前已经尽量降低刷新频率避免发生这个问题。如果的确卡住了,点进去重新保存一下即可。
Q: 后台数据没有按照更新时间准确更新?
A: 首先,请查看是否打开了软件的背景数据刷新,在设置中搜索”只是组件“。背景数据刷新本身不支持准确的时间间隔,系统会根据软件的要求协调各个软件在必要的时候刷新,但总体而言软件使用频率越高,系统会越多分配背景数据的刷新。只是组件支持了各种唤醒方式,尽量保证了刷新。建议配合快捷启动使用软件,使用快捷启动可以保证数据的按时刷新。
]]>关于软件
如果你还没有用过Anchor,我强烈建议你下载,App Store即可免费获取。快捷启动和高度自定义组件合集,这里是软件链接。
关于URL Scheme
URL Scheme是每个程序内置的快捷启动,并不一定有特定的格式,是存在一定可能随着某次更新产生更改的。
通过访问该链接,可以转跳相应的软件的相关功能。
部分软件,例如捷径,本身保证URL Scheme有特定的格式。
部分软件,例如微信,不保证URL Scheme内容和格式的稳定,在某次更新后目前只有扫码链接可用,非常糟糕,是常用软件里支持最少的。
这种快捷启动会给日常使用带来大量便利,例如支付宝的扫码、付款码、收款码,各个设置页面等等。
而在Anchor的设置中,每个组件都可以设置URL Scheme产生点击后的后续操作。只需要将下述的字符串输入即可。
用途 | URL Scheme |
---|---|
钱包 | shoebox:// |
邮件 | mailto://anchorapp@126.com |
电话 | tel://12345678 |
短信 | sms://12345678 |
显示日历 | calshow:// |
照片 | photos-redirect:// |
设置 | prefs:// |
用途 | URL Scheme |
---|---|
扫一扫 | alipayqr://platformapi/startapp?saId=10000007 |
打开收款 | alipays://platformapi/startapp?appId=20000123 |
乘车码 | alipayqr://platformapi/startapp?saId=200011235 |
付款码 | alipay://platformapi/startapp?appId=20000056 |
快递查询 | alipays://platformapi/startapp?appId=20000754 |
健康码 | alipays://platformapi/startapp?appId=20000067&url=https%3A%2F%2F68687564.h5app.alipay.com%2Fwww%2Findex.html |
用途 | URL Scheme |
---|---|
扫一扫 | weixin://scanqrcode |
用途 | URL Scheme |
---|---|
搜索 | jike://page.jk/search |
用户 | jike://page.jk/user/6b8159a9-bd2e-435d-ab9d-a8acba6778b0 |
主题 | jike://page.jk/topic/[topic-id] |
消息 | jike://page.jk/message/[message-id] |
用途 | URL Scheme |
---|---|
微博 | sinaweibo:// |
淘宝 | taobao:// |
QQ音乐 | qqmusic:// |
网易音乐听歌识曲 | orpheuswidget://recognize |
Bilibili | bilibili:// |
用途 | URL Scheme |
---|---|
调用捷径 | shortcuts://run-shortcut?name=[name]&input=[input] |
创建捷径 | shortcuts://create-shortcut |
打开特定捷径 | shortcuts://open-shortcut?name=[name] |
调用捷径后,在捷径中可以完成的内容就非常多了。
]]>正如在展示视频中看到的那样,专业版提供了完全自定义的命令和完全自定义的界面。
另外,非常感谢你对于Anchor的认可与支持!
路径:单击状态栏Anchor图标 -> 新增 -> 添加自定义组件。
组件可以设定四种自动运行模式,分别是:
运行模式 | 含义 |
---|---|
手动运行 | 将不会自动运行,需要通过点击”开始”运行 |
开启视窗时运行 | 将在点开状态栏、划出通知中心时运行 |
程序启动时运行 | 将会在主程序启动时自动运行一次 |
固定间隔自动运行 | 将根据间隔不断自动运行 |
正如你所看到的,自定义组件的程序与代码都可以自定义。
这里做一个最简单的测试,将程序更改为:
1 | python |
将代码更改为:
1 | print("Greeting from Anchor") |
你就会获得一个”结果”固定的组件,这里建议使用左侧彩蛋第二位的测试窗口,测试窗口提供了一个简单方便的测试环境。
状态栏除了默认的启动、隐藏、设置等,还支持添加其他的按钮。
支持的按钮有以下几类,添加多个按钮以”;”(英文分号)分隔:
种类 | 设定值 | 返回值 |
---|---|---|
目前结果值 | $文本一 | 结果值 |
固定值 | 文本二 | 文本二 |
输入值 | @文本三 | 输入值 |
那么以番茄钟为例,如果需要三个自定义按钮,分别为:30、目前剩余的时间、自定义时间。
那么”状态栏自定义按钮”就设定为:
1 | 30;$目前剩余时间;@自定义时间 |
这里可以添加一个自定义任务进行尝试,测试代码使用/bin/bash
的情况下可以使用:
1 | echo $1 |
建议将结果拖入状态栏内容,这样可以方便的在状态栏看到按钮点击的结果。
视窗界面将根据程序运行的结果自动生成,目前支持四种自定义视窗以及四种视窗的任意组合。
四种视窗分别为:终端富文本、HTML、控件以及文件。
首先介绍一下运行结果的控制。程序重新运行后运行结果将重新产生,或者通过清屏的控制字符也可以清空已有的运行结果,例如下面的bash
程序演示了如何控制运行结果。
1 | echo -e "first line" |
终端通过控制字符可以生成富文本,Anchor支持相关的大部分控制字符,但不支持光标移动类的控制字符。
所有正常输出内容将默认作为终端富文本处理。
例如下面的bash
程序演示了生成一个字符日历:
1 | cal | head -n 1; cal -h | tail -n +2 | grep --before-context 6 --after-context 6 --color=always -e " $(date +%e)" -e "^$(date +%e)" |
可以看到当日的日期如终端中一样进行了标红。
Anchor支持HTML,要求的输出格式为:
1 | { "type": "html", "data": "<div>body</div>" } |
由于自动计算高度的问题,HTML要求去除最外层的<html>
标签,直接使用<head>
/ <body>
标签。
例如下面的bash
程序演示了一个简单的HTML视窗:
1 | echo '{ |
Anchor提供四种视窗中可以使用的控件:
种类 | 关键词 |
---|---|
滑块 | slider |
文本输入 | textfield |
开关 | toggle |
文本显示 | text |
与HTML类似,使用控件的关键词为tools
,数据栏需要填入的内容为:
1 | [ |
例如下面的bash
程序展示了一个简单的控件视窗:
1 | echo '{ |
操作控件后,控件的属性将作为程序的参数传给程序并再次运行。
文件视窗提供一个接收文件拖曳的窗口,Json格式为:
1 | { "type": "file", "data": "" } |
收到文件拖曳后,文件名将作为参数传给程序并再次运行。
组合视窗的关键词为multi
,所以Json格式为:
1 | { "type": "multi", "data": [] } |
例如下面的bash
程序演示了一个简单的组合视窗:
1 | echo '{ |
由于Apple的沙盒策略,Anchor所有访问的文件都需要用户明确授权。
你可以在设置页添加可访问的文件夹,这里给出建议的操作:
~/.anchor
文件夹,并将需要访问的资源加入该文件夹ls /Users/name/.anchor
确认可以访问这里以Python为例演示使用其他程序。
在程序栏,更改为python
在代码栏,输入如下代码:
1 | import sys |
将显示Python的系统信息。
这里另外演示通过osascript
进行弹窗的操作。
在程序栏,更改为bash
在代码栏,输入如下代码:
1 | osascript -e 'display notification "hello world!" with title "Greeting" subtitle "More text" sound name "Submarine"' |
由于沙盒策略,软件即使可以访问也无法运行系统自带以外的可执行文件。
所以需要通过一个代理完成可执行文件的访问,也就是Anchor访问代理软件,代理软件运行可执行文件。
通过代理软件的中转,Anchor就可以完成可执行文件的调用。
按照我的使用习惯(虽然我也可以使用本地的非沙盒版本),我会将代理软件与Anchor设置开机自动运行。
代理软件非常简单,只需要一个本地的HTTP服务器以及一些调用可执行文件的命令,如果你想要使用我已经写好的软件,可以直接到我的Github中进行下载。
Q: 后续是否会支持Widget以及桌面小组件。
A: 在Big Sur正式更新后就会更新Widget,后续也将增加桌面小组件的功能。这些功能都将在普通版中提供,专业版与普通版的区别将保持仅有自定义界面与自定义代码。
Q: 通知中心的内容没有更新。
A: 只有在主程序启动的情况下组件的任务才会运行,所以请检查主程序是否已经运行。
Q: 是否有一些常用的功能组件提供?
A: 目前这些内容都放在Github上,后续如果用户量需要一个专门的网站了,届时会更新独立的网站。根据用户反馈非常常用的功能,将会更新到预定义组件里。当然有一些例如“显示隐藏文件”等系统已经有非常便捷的解决方案的功能(快捷键为:Command+Shift+.)将不会更新。
]]>开发者文档里有专门的一页,列出了目前可用的系统图标。但只有名字,没有相应的图片放在边上,也看不到尺寸。
github上发现了一个项目,可惜几年不更新了,图标数据也是写死在代码里的。项目名字叫fucking_nsimage_syntax
,不知道是不是也在吐槽开发者文档里不放图和尺寸。
如果自己写一个的话,基本是,网页抓取数据->数据对应图标和尺寸->SwiftUI展示,也很简单。
开发者文档载入是先框架后数据,简单看一下包,可以找到图标页的数据通过获取这一个网址取得:
1 | https://developer.apple.com/tutorials/data/documentation/appkit/nsimage/name.json |
既然已经想好SwiftUI展示,那就直接做进界面的方法里好了,这里就是一个简单的网页请求:
1 | extension ImageNameDemoView { |
我们要的数据全都在references
键里,通过判断后缀是否有Name
去除非图标的内容。
这里获取了需要的数据的数组,但这个数据只是属性名不是实际的值,所以还需要一个转化。
理论上来说这是个很简单的过程,想象中通过value(forKey:)
就可以解决。但NSImage现在还不是正常实现的类,所以这个方法和同理的反射都不能用。
这里是可以OC去取值的,但实际上取巧的办法就可行:
1 | extension ImageNameDemoView { |
图标和对应的尺寸就简单了:
1 | NSImage(named: name) |
大致构思一下界面,这里一行放十个图标,放一个按钮加载数据(onAppear
也成),右击图标显示属性名和大小。
所以大致的框架就出来了:
1 | struct ImageNameDemoView: View { |
下面把中间的文字换成有右键菜单的图片:
1 | Image(nsImage: NSImage(named: self.getNSImageName(self.images[x + y * self.columnNumber])) ?? NSImage()) |
界面就快速的完成了,大概是一个这样的界面:
SwiftUI已经有了越来越好的开发体验,单数据源绑定的逻辑,完备的组件和方法,让界面的构建变得十分简单。
加上Widgets等内容的大力支持,地位可以想见会快速上升。
就我的体验而言,目前有一些问题还是需要有思想准备。Swiftui错误提示仍旧非常糟糕,界面中小的语法错误会导致整个构建时间耗时非常久,并最后返回,最外层View
无法推断返回值类型这样的无用信息。
可能搜出来的答案很多是不合适的用法,也许我是个例,也许OC程序员写Swift都一样,看自动补全有好像能用的方法用了就行。例如文本框获取焦点,搜到的都是view.becomeFirstResponder()
。IOS上奇怪的可用,MacOS上奇怪的不能用。翻翻文档才会发现调用view.window?.makeFirstResponder(view)
才是标准的用法。
以及一些小问题,即使有NSViewRepresentable
的万能后备,有时候还是会因为一些神奇的原因重写整个组件,例如目前List
在MacOS上如果需要去掉分割线的背景需要重写整个List,甚至没有IOS上取巧的直接改写UITableView
的办法。
但总体,惊喜是会比坑多的,建议一试。
]]>第零天,官方发布了一张污损的海报预告有一个大型解谜活动,通过补全二维码可以获得活动入口。
1 | https://h5.codefuture.top/hybrid-gone-cat |
由于活动于第一天开始,所以无法进入活动,甚至因为界面设置问题无法看到规则。
通过浏览页面JS可以发现这样一些代码:
1 | // 代码段一 |
通过代码段四可以分析出通过currentIndex
判断页面,通过代码段二、三可以发现该值通过/chapters/list
获取,通过代码段一可以获得完整的地址https://meow.codefuture.top/api/chapters/list
。
虽然当时返回的是空值,但通过代码段三可以大致猜测一下返回值的结构,应该类似:
1 | {"data":[{"index":6,"feeds":[{"content":"content"}]}],"currentIndex":6} |
通过伪造返回值,将这段数据返回给网页,就可以在第零天预览规则和全部关卡的美工。
具体关卡的内容就需要等待上线后后端服务器在content
字段中返回。这段数据可以获得这样一个界面:伪造数据预览。
第一天通过宠语翻译器可以进入第一个彩蛋,网址为:
1 | https://h5.codefuture.top/hybrid-gone-cat-eggs/translator-egg.html |
在这个网站的头部,可以看到有由于失误加入的其他代码。
1 | <link as="style" href="https://static.codefuture.top/hybrid-gone-cat-eggsstatic/css/calendar-egg.132d081f1832e4ca3ac6.css" rel="preload"> |
所以可以猜到第二个彩蛋和calendar
有关,虽然这些文件存在错误,但是通过第一个彩蛋js和css正确的网址可以拼接出第二个彩蛋的js和css文件。
于是可以通过第二个彩蛋的css文件找到第二个彩蛋的猫图:
1 | https://static.codefuture.top/hybrid-gone-cat-eggs/static/image/calendar-egg.png |
通过将第二个彩蛋的css当成第一个彩蛋的css返回,将页面中的一改成二,就可以伪造出第二个彩蛋的页面。当然,如果第二个彩蛋的提示更改了那也是没办法的事情。
在第二个彩蛋的js中,可以找到这样的代码:
1 | i.default.updateShareInfo({ |
结合第一天翻译器及彩蛋页面的域名:
1 | https://h5.codefuture.top/hybrid-cat-translator |
不难猜出第二天的活动页面及彩蛋域名:
1 | https://h5.codefuture.top/hybrid-decrypt-calendar |
不过第一天的时候这两个页面由于时间没到没有开,会返回403。
但在第二天活动没开始之前页面就可以访问了,并且和伪造的第二个彩蛋没有区别。
对于重要的内容和文件一般都会有个提醒和监控,具体实现可能不一样,用着习惯就好。
第零天由于没有预告几点开始活动,当时是监控这个网址的返回值变化做的活动开启提醒:
1 | https://meow.codefuture.top/api/chapters/list |
通过监控主活动页面的JS,可以发现final的JS有更新一开始内容为:
1 | var g = ["喵~喵~喵呜呜呜~", "汪~汪~汪汪", "吱~吱吱", "喵~喵呜呜~"], |
后来更新为:
1 | var g = ["喵~喵~喵呜呜呜~"] |
第一天就把这一段内容在翻译器中试过,所以活动的时候也没想到这就是最终线索。
但回头回顾这个活动,翻译器返回值每天都更新,第三天翻译器返回值有更新也在情理之中。
也不知道这个返回值是南北大战活动结束更新还是定时更新。
即刻的后端返回HTTP数据包,”x-server”一项返回的是”Potato-Server”。
南北大战活动的解锁需要给babel-t单条点赞600,结果点了一天没点满,估计是故意的。最后第二天十点满了500点赞以后babel-t发了一张歌手伍佰的图,开启了南北大战活动。对,就是那个所以暂时将你眼睛闭了起来。
最后一页还更新了一张图,可惜的是,常规方法大部分人没办法看到,这里一起放出来:
其余彩蛋如果有人分享再继续更新,恭喜即刻回归 🎉!
]]>通过json构建前端,不难理解是怎么一回事,以一个简单的提交表单为例。
如果用json描述这个表单,是类似这样的东西:
1 | { |
如果去掉用于布局和美化的各种内容,就应该生成这样的代码:
1 | <div class="title> |
这样的话,如果有足够的模板,构建前端的内容就会非常的方便,而amis就是这样的一个项目。
amis可以实现我可以想象到的大部分页面,复杂的功能可以在有具体的需求的时候借助文档完成。
这里就把搭脚手架和怎么通过json增加一个最简单的页面做一个演示,复杂的页面实际上也就是个复杂的json而已。
我把添加简单页面的操作都放在一次提交中了,完整的内容可以看这里。
这个项目页面都放在routes/admin
中,所以我们新建routes/admin/demo/Third.tsx
。
然后把用来构建页面的json放进这个页面里,所以文件会是这样的:
1 | import schema2component from "../../../utils/schema2component"; |
页面的主页是routes/admin/index.tsx
,而侧边栏定义在navigations
变量里,我们只需要加一些内容:
1 | { |
这里用到了ThirdForm
,在文件头上加一个引用。
1 | import ThirdForm from './demo/Third'; |
就这么简单就完成了。
如果你想自己尝试,可以从我的github下载本项目,然后运行,账号密码都填1即可。
1 | npm install |
如果你不愿意本地搭这个环境,在docker里运行或者直接看个图也行,最后的效果是这样的:
完成一件事情变得越来越容易,甚至普通人动动手就能完成,就会有担心大量程序员不再被需要。
今天看到阮一峰博客上的一段话。
30年前,开发图形界面 GUI 很困难,Visual Basic 改变了这一点。
20年前,制作一个 Web 应用很困难,PHP 改变了这一点。
10年前,写一个复杂的网页布局很困难,Bootstrap 改变了这一点。
历史上,每当一个领域出现大量需要编程解决的问题,就会诞生一个通用的解决方案,解决掉90%的场景。然后,这个领域对程序员的需求就会快速减少。
我们没有办法阻止分工的逐渐变化,旧的技术越来越快的被替代、淘汰,但熟悉旧技术的人同时也有着在新分工下的优势。
类比而言,我们现在想吃面只需要开门拿个超市快递烧了水泡一下就有热腾腾的面吃。但这不意味着了解种植、制面工艺的人拥有的技能就不再被需要。自动化的种植需要手工种植的经验,种植的品种也可以有更多的精力去研究,了解工艺的人即使是做宣传也会有超出常人的优势。
我们现在熟悉的前端代码可能有一天都会被觉得非常硬核,只有少许专精于框架维护的开发者会去使用。学不动了就转岗去管理了。
另一方面,每一个普通人都实实在在的有了更多的力量,借助飞机,哺乳动物以900公里/小时移动,而哺乳动物需要做的只是走上去坐下。
]]>扬州网警巡查执法通过新浪微博发布消息称四月初抓捕了Pandownload的作者,舆论发酵后删除,凤凰网对原微博进行了截图。
今年 2 月,受害人刘某报案称其下载的“Pandownload”软件会在未授权的情况下,将自己百度网盘的数据共享出去,导致隐私照片和文件泄露。宝应县局网安民警立即开展案情分析研判,研习法律条文,解剖软件结构。面对满屏的数据,一盯就是几个小时。
经过梳理,警方发现该软件可以以非会员权限突破百度网盘官方设定,实现高速下载,系侵入、非法控制计算机信息系统的程序、工具,并且该软件的使用者达到数万人,致使北京百度网讯科技有限公司(“百度公司”)损失高达上千万元。
4月初,在掌握了充分证据后,宝应网安远赴广东,抓捕犯罪嫌疑人蔡某萌,当场查获电脑、手机等作案工具。
可以看出,该案已经作为刑事案件被立案侦查。目前,该项目与之后暂时出现的替代项目均关闭。
根据微博的内容,“该软件可以以非会员权限突破百度网盘官方设定,实现高速下载,系侵入、非法控制计算机信息系统的程序、工具”,即触犯非法获取计算机信息系统数据罪。
不用讨论的是,若cherryljr的软件存在后门窃取用户数据或者破解手段为入侵百度服务器,则显然构成犯罪。有意思的是,曾经有一个收费提供百度云盘资源搜索的软件,法院判定软件上传使用者分享链接的行为构成窃取用户数据,判决见这里。这次的案件报案人也是采取该理由,但盘搜技术上需要上传分享链接用于搜索,而破解限速仅下载即可。所以除非cherryljr存在后门行为,不会因为报案人的理由构成犯罪。
值得讨论的是,若仅是截取了下载链接,通过三方工具下载,是否仍旧会构成犯罪。虽然涉案软件没有开源,但类似有很多项目,其实都是这样的操作。我们就假设,截取链接三方下载,是比较接近涉案软件的解决方案。
根据我国刑法第285条一、二款:
【非法侵入计算机信息系统罪】违反国家规定,侵入国家事务、国防建设、尖端科学技术领域的计算机信息系统的,处三年以下有期徒刑或者拘役。
【非法获取计算机信息系统数据、非法控制计算机信息系统罪】违反国家规定,侵入前款规定以外的计算机信息系统或者采用其他技术手段,获取该计算机信息系统中存储、处理或者传输的数据,或者对该计算机信息系统实施非法控制,情节严重的,处三年以下有期徒刑或者拘役,并处或者单处罚金;情节特别严重的,处三年以上七年以下有期徒刑,并处罚金。
该罪保护的是社会法益,而非企业法益。非法获取计算机信息系统数据罪处于刑法第六章妨害社会管理秩序罪的第一节扰乱公共秩序罪,刑法体系而言,整章的犯罪均规制的是侵害社会法益的行为,包括该罪。若仅是企业的权益受到了损害,理应通过民事赔偿完成救济。
其司法解释中也重点强调了公众隐私的保护,公众个人信息数量较小的非法获取也构成犯罪。
即使过度使用免费通道的行为侵犯了财产性利益,也应该认定盗窃罪。
这里的技术问题可以做个类比,网盘就类似一家面包店,面包收钱,而试吃小样免费。面包店限制了一天只能买一次,所以不掏钱买面包就只有小样,吃不饱。于是聪明的人就多注册几个账号,去薅羊毛,也吃饱了。类比中,截取下载链接就是找到了小样窗口,三方多线程工具下载就是多账号薅羊毛。
需要注意到一个区别,本案并没有侵犯不公开数据。窃取阿里云备案完整信息案和本案不同。完整的备案信息含有个人隐私等不公开内容是内部文件,即使由于操作失误公网可以访问,恶意获取也属于非法。而本案中百度本就对所有用户提供免费的下载,数据也由其他用户上传。
涉案免费通道的使用边界不明,通过技术手段跑满免费带宽应属于合理使用。由于采取了更好的下载技术,同一链接,使用普通下载器和aria2下载,下载速度完全不同。同样的,aria2相对于百度提供的客户端而言,可以在同一链接的情况下获得更好的下载速度,使用更好的下载手段不应被认定为滥用。免费通道由于该技术满足了用户的下载需求,的确会产生了不符合自身商业意图的结果,公司可以从技术上进行限制,例如限制IP、下载模式识别、更高精度的限速模型、更低的限速、甚至关闭免费下载,来鼓励用户完成付费。
网盘产品主要是提供虚拟的存储空间,付费用户更快下载他人文件是附加功能,并非主要卖点及付费点。网盘归根到底是提供了云端的存储空间,用户可以云端备份文件、节省本地空间、同步手机相册等。网盘并非内容提供方,网络资源共享的途径多样,若网盘获取速度过慢,完全可以通过其他方式共享。优化下载文件速度的行为在另一方面也鼓励企业、个人将文件通过该网盘存储,难以判断商业上由此造成的影响。
根据刑法条文可知,实施犯罪行为的情况下需情节严重才构成犯罪,情节严重的具体解释规定在相关司法解释中。
具有下列情形之一的,应当认定为刑法第二百八十五条第二款规定的“情节严重”:
(一)获取支付结算、证券交易、期货交易等网络金融服务的身份认证信息十组以上的;
(二)获取第(一)项以外的身份认证信息五百组以上的;
(三)非法控制计算机信息系统二十台以上的;
(四)违法所得五千元以上或者造成经济损失一万元以上的;
(五)其他情节严重的情形。
本案可能涉及的为第四条,而本案的软件的确存在可能的经济损失。
违法所得更难证明,但也有更多可以讲的内容。性质而言,本案软件的获利方式为捐赠,但的确存在捐赠才可以获得最新测试版的情况,实践中可能被认为是一种特定的商业模式。金额而言,会存在是否扣除成本的两种观点,一般作为定罪处罚标准时会采取扣除成本的观点,对此人民法院报也有过一篇专门的报道。
如果认定对网盘免费带宽的使用非法,本案的确可能存在非法占有财产性利益的情况。这个情况下仍需要注意,本案盗窃罪成立原因为达到了数额较大的起点,情节轻微,退赃退赔可不作为犯罪处理。另外,就该案的情节而言,违法行为系违法使用带宽,社会危害性较小。
最基本的思路肯定是侵权责任纠纷,违法使用带宽,造成了额外的带宽费用,额外的带宽费用由违法行为导致,侵权人显然存在过错。
所以还有一个思路是不正当竞争纠纷。一,由于网站知名度等因素也会被认定为利益,认定营利性服务的经营者没有问题。涉案软件与网盘客户端的功能而言,使用涉案软件显然会导致不再使用网盘客户端,双方存在竞争关系。二,涉案软件必然影响网盘正常经营,研发时显然可以预见到。三,网盘旨在通过提供有区别的存储、下载等服务鼓励用户付费。涉案软件通过免费高速下载,让用户失去了付费的理由,破坏了网盘的商业模式。
不过就金额而言,带宽的费用损失难以精确的计算,侵权人违法所得也大都是小额捐赠,数额不大。
舆论一直在发酵,一方面,破解软件的作者受到了某种意义的保护,另一方面,百度网盘的会员也安全了,真是奇妙的双赢。
]]>本文需要基本的Swift基础,接触过SwiftUI,大概就是官方例子大致看过的水平即可。
这种链接是scheme://data
的形式,IOS会根据本地安装的应用搜索scheme
,找到后询问你是否要通过相关应用打开该链接。很常用的一个链接是微信的扫码weixin://scanqrcode
,通过这个链接直接打开微信的扫码。当然,首先需要本地安装了微信。它让类似捷径等一些自动化软件的功能大大增加。
有部分的Scheme是被保留的,可以通过这些保留的Scheme调用一些系统功能,例如短信、FaceTime,这里介绍了有哪些以及具体怎么使用这些内容,有兴趣可以尝试一下。
如果想要了解应用对应的scheme
是什么,解压缩ipa,然后在Info.plist
文件的CFBundleURLSchemes
字段就是设置的scheme
。但要了解scanqrcode
之类的具体应用,就麻烦的多,网上如果没有现成的内容就需要反编译去找了。
我试了试用SwiftUI来写这个小东西,是个很简单的过程。
新建一个项目以后,在ContentView.swift里面加上基本的显示UI即可。
1 | import SwiftUI |
这里可以加一个按钮试一试添加是否成功,那么就把NavigateList
加一点东西。
1 | struct NavigateList: View { |
按一下按钮,我们就假装收到了一条链接。
应用需要决定自己响应什么scheme
,这个在XCode > Project > Info > URL Types里面设置。
按照下面的图完成设置就行了。
这里完成设置以后,通过测试机子的Safari,地址栏填写geoffscheme://
就已经能打开应用了。
这边通过修改SceneDelegate
的方式接收数据,这里可能有两种情况。
不过首先,先把URL转换成显示用的Link的方法作为SceneDelegate
的类方法写好。
1 | func parseUrl(_ urlContext: UIOpenURLContext) -> Link { |
第一种情况,如果应用没有打开,也就是后台也没有该应用,那么链接会调用scene(_:willConnectTo:options)
方法。所以就给SceneDelegate
添加一个属性和一个方法。
1 | var rootView: ContentView? |
另一种情况,如果应用被打开了或者在后台,那么链接会调用scene(_:openURLContexts)
方法。所以再添加一个方法。
1 | func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) { |
然后通过在Safari中键入geoffscheme://demo
或者一些别的geoffscheme://
开头的内容,应用都可以被正确唤起并处理链接的内容。
这种链接是https://yourwebsite
的形式,它需要有一个支持HTTPS的域名并进行相关的配置。由于其安全性高,支付宝扫码支付、购买转跳等都是用的这种方式。
需要注意的是,这个方法需要一个加入苹果开发者的账号,所以这个内容还属于年费$99付费解锁。如果手头没有这样的账号的话,其实自己玩的应用URL Scheme也够用了。
以我的网站为例,如果我的应用要通过https://geofftools.cn
调用,那么我需要提供一个这样的文件:
1 | { |
这个文件可以放在两个位置,https://geofftools.cn/apple-app-site-association
或者 https://geofftools.cn/.well-known/apple-app-site-association
。
其中Apps
按要求留空(官方要求),appID
是TeamId和BundleId合起来,path
的路径里可以用* ? NOT
。
应用需要设置响应的网站,这个在XCode > Project > Capability > Associated Domains里面设置。没有加入付费的苹果开发者的话,这就没办法设置了。
这边填<service>:<fully qualified domain>
,例如applinks:geofftools.cn
。
和上面的操作类似,这里添加这样一个类方法。
1 | func scene(_ scene: UIScene, continue userActivity: NSUserActivity) { |
Universal Link更复杂也有更多的应用,URL Scheme则很容易配置也能满足基本需求,区别做成表格的话大概是这样一些不同。
Safari二次确认 | 需要本地安装 | 调用争抢 | 需要后端配合 | 需要加入开发者 | |
---|---|---|---|---|---|
Universal Link | √ | × | × | √ | √ |
URL Scheme | √ | √ | √ | × | × |
如果考虑安全性和易用性,肯定是Universal Link更合适,他调用应用不必须经过Safari,调用的名称也不会被其他应用占用。但如果只是做个小彩蛋,或者自己实现一些简单的功能,URL Scheme也是完全可以使用的选择。
]]>docker产生的文件经常需要sudo chmod o+rw *
然后访问,虽然麻烦,但好歹有sudo的权限。没有sudo权限的时候就没那么走运了,这时候我发现了三种操作可以解决这个问题。
文章分为三部分,解释了挂载的原理、提供了三种解决原理、就方案进行演示。若仅希望获得推荐的解决方案,可以直接跳到方案演示的使用子用户一节。
简而言之,docker的文件挂载中,容器内外uid与gid相同。
最简单的挂载磁盘,例如:docker run -v $PWD:/data bash
,就是将当前目录挂载到容器内的/data
目录。文件的权限可以通过ls -l
查看。
容器内可能有使用root用户和非root用户运行程序的两种情况。1)若容器内使用root运行程序,可以想象,产生的文件属于0:0,也就是root:root。容器外文件也会属于0:0,同样是root:root。这样产生的文件就需要容器外的root权限才可以操作。2)若容器内使用非root运行程序,例如blog:x:1000:1000::/home/blog:/bin/bash
,产生的文件属于1000:1000。容器外文件也会属于1000:1000,而容器外uid为1000的用户可能是frank,这是若碰巧你就是frank,你就可以顺利读取这个文件。但若你是uid为1001的david,而且frank是个讨厌鬼,你就告别这个文件了。甚至容器外根本没有uid为1000的用户,那这个文件就不属于任何人。
仅部分容器可以使用该方案,且难以判断是否可行。对于这些容易配置权限的容器,这个问题很容易解决,强制容器的运行用户docker run -u blog bash
即可。
我们这么定义容易配置权限的容器。
容器内所有用户都可以访问容器内所有需要访问、运行的资源
容器运行时由运行用户生成所有文件
满足这些要求,会让配置一个稍复杂容器的工作变得复杂许多甚至不可完成。如果你创建过容器,那你一定可以想象。第一点起码可以通过批量更改所有文件的o属性完成。第二点和第三点,容器运行的程序若需要绑定保留端口,就需要特别的各种设置;容器运行的程序若简单的要求需要管理员权限,我们不可能为了创建符合要求的docker更改甚至反编译程序。
而我们大部分时间使用到的容器都是他人配置好的,我们无法判断他人配置的容器是否属于容易配置权限的容器。这种容器若强制容器的运行用户除了无法保证产生文件的权限,还可能让容器意外崩溃。但说不准,bug就莫名奇妙消失了?
若容器内外文件的uid:gid可以不同,这个问题就可以很容易解决。的确有这么一个方案,让容器内所有的uid:gid以一定的规则映射,我推荐使用这一方案。文章的方案演示节中我会演示这一方案。
在官方文档中,这个方案本身是为了解决安全问题,见这里。发生容器挂载磁盘root权限提权也不是一次两次了,这算是一个官方的解决方案。
但这个方案会有一些限制:
--pid=host
或 --network=host
docker run --privileged
则必须同时使用--userns=host
都是不大的限制,使用的时候留个心眼即可。
有趣的是,OSX中不存在这一问题。
在和朋友讨论的时候,朋友们纷纷反映没有这个问题,不禁让我感叹贫穷限制了我的想象力。如果你使用的是OSX或者和我一样从朋友那里抢来了一台OSX,你可以尝试如下命令:
1 | mkdir data |
尽管OSX版本的docker有各种问题,但起码没有这个问题。这一切要归功于osxfs,官方文档中有一个基本的介绍。
其中Ownership一段提到了解决方案,容器内root映射到容器外运行docker的用户,容器内更改文件所有人的记录保存在com.docker.owner
中。具体细节还有一些别的,TL;DR。
Initially, any containerized process that requests ownership metadata of an object is told that its
uid
andgid
own the object. When any containerized process changes the ownership of a shared file system object, such as by using thechown
command, the new ownership information is persisted in thecom.docker.owner
extended attribute of the object. Subsequent requests for ownership metadata return the previously set values. Ownership-based permissions are only enforced at the macOS file system level with all accessing processes behaving as the user running Docker. If the user does not have permission to read extended attributes on an object (such as when that object’s permissions are0000
),osxfs
attempts to add an access control list (ACL) entry that allows the user to read and write extended attributes. If this attempt fails, the object appears to be owned by the process accessing it until the extended attribute is readable again.
所以内容被存储到了这里:
1 | docker run -it --rm \ |
所以这个方案无法应用在其他系统,而一般OSX上的docker也就是个测试。
如果使用特定用户构建容器,最后也是这个用户使用容器,就没有这个问题了。比如构建时容器内用户uid为1000,使用容器的用户uid也为1000。不过这样的容器基本不可移植,但自用时也不失为一个简单的办法。
另一个想法是,是否有用户的权限低于所有用户。就像root用户可以访问所有用户文件类似,若有一个用户的文件可以被所有用户访问,那使用这个用户创建docker就解决了这个问题。但实际上找不到这样一个用户,即使是nobody也不行,只有没有人可以访问没有人的文件。
容器内强制由容器外的当前用户运行容器内的程序。
1 | docker run -it --rm \ |
可以看到生成的文件由当前用户所有。
1 | ls -l data |
该方案最为简单,但正如原理节讲到的,对于很多容器,强制容器的运行用户无法保证产生文件的权限,还可能让容器意外崩溃。
该方案需要更改docker守护程序的运行参数,测试的时候建议开个虚拟机,这里以一个未进行任何配置的Ubuntu 16为例进行展示。
先完成准备,安装docker并创建用户blog作为演示用户。
1 | # install docker |
若不设置子用户,生成的文件将会归root所有。
1 | docker run -it --rm \ |
subuid的设置被放在/etc/subuid
中,当前用户的uid可以通过id -u
获取。subgid的设置被放在/etc/subgid
中,当前用户的专属group可以通过cat /etc/group | grep $USER
获取。这里假设blog:blog对应的uid:gid为1000:1000,那么这两个文件按照如下进行设置。子用户的格式是name:start:number
,意思是名字为name的用户生成的子用户是从start开始的number个。这两行产生了容器外uid为1000, 100000, 100001, 100002...
的一系列用户,和容器内的用户一一对应,容器内的uid为0, 1, 2, 3...
。显而易见,容器内的root映射到了容器外的当前用户,子用户组也是同理。
1 | # sudo vim /etc/subuid |
下面通过设置docker的配置文件,让docker知道需要启动用户映射,然后重启docker即可。
1 | # sudo vim /etc/docker/daemon.json |
到这一步,子用户的设置就完成了,可以试一试效果。
1 | docker run -it --rm \ |
虽然容器内使用root生成了归属于root的文件,但是容器外文件归属于设置了映射的当前用户。
]]>西方幽默理论有三个主要的理论流派,优越论、释放论和乖讹论。
这个理论认为,幽默是对某人或者某物的嘲笑,并由此获得优越感。这种方式包括表演者实施嘲笑,也包括表演者充当被嘲笑的对象。
萧伯纳一次在舞会上邀请一位大龄妇女,大龄妇女十分激动,询问自己是有什么过人之处。萧伯纳回应道,“我请你跳舞是因为这是一个慈善舞会,不是吗?”
仔细看来,甚至这个笑话可以说有侮辱妇女的成分,但的确是个好例子。
比如最近很火的小破站MV,自夸小队。其中其余三人顺利戴上了眼镜,中国boy不小心戳到眼睛。
比如卓别林、憨豆、周星驰,很多搞笑通过扮演被嘲笑的对象来达成。
这个理论认为,幽默是出于有压力的感情解除的确认。用弗洛伊德在《论幽默》一问里面的话说,就是感情消耗的节约。
金马奖上颁奖嘉宾调侃黄渤:你怎么穿个睡衣就来出席颁奖礼?
黄渤:因为这五年一直都在金马奖现场,这里已经像家一样。回到家里穿什么?回到家里一定要穿得舒服一点儿。
如果移除金马奖颁奖的紧张氛围,只是私下轻松的氛围下进行这段对话,就很难感受到搞笑。
这个理论认为,幽默是合理的期待落空。就是听众在笑话过程中产生了预期的结果,但结尾时获得了期待以外的结果,而这个意料之外的结果又异常和谐。
A: 你说我如果戴上分院帽会被分到哪个学院?以我的聪明应该会是斯莱特林吧。
B: 阿兹卡班。
这一理论特别常见,常见的抖机灵、搞笑配图、神最右大多是这一理论。
在文字横线处补写恰当的语句,使整段文字语义完整连贯。每处不超过15个字。
在为玫瑰剪枝的时候,不小心被刺刺到,一滴血珠渗出拇指,鲜红的血,颜色和盛放的红玫瑰一模一样。___?我在心里疑惑着。我一边吸着手指渗出的血珠,一边想着,……
答案:我缓缓打出一个问号
这需要大量的联想和创意,甚至铺垫两条故事线,好让最后的答案意料之外又情理之中。
例如思文奶奶的故事。
以下是脱口秀大会第二季呼兰决赛的稿子,不用冠军卡姆的稿子主要是因为卡姆的风格偏向于表演,很大部分的内容不在文字上,呼兰的脱口秀就更传统。
比赛到现在真的是弹尽粮绝,比赛三天前我的稿子还一塌糊涂。傍晚的时候给我爸发微信,我说,爸,我真写不出来,把我写的乱七八糟的发给他了。我爸他都没说安慰我一下,他回了我一下,我在外面应酬,等我回去我给你写一篇。我都没当回事儿,晚上十一点多,我爸发了一篇两千多字的稿子过来。我说哇,我在节目里面这么吐槽我爸妈,他还给我写稿子,这难道就是亲情的力量吗?结果一看那稿子,是我爸吐槽我爷爷的。
前面的铺垫产生了父子亲情的逾期,以为是个温暖的故事,没想到结尾是个一脉相承的吐槽父亲。另一个层面上来说,本来亲情和对儿子的支持是一个沉重的话题,最后的转折让紧张的气氛有了一个释放。
是吧,写的不咋地。好的话我就都用了嘛,我又不傻。
自己套入图方便、拿来主义的人设,可以算是一种自我贬低以产生搞笑的效果。
我爸写的脱口秀甚至有讽刺意味,可能是看了我的脱口秀,你这脱口秀怎么和你奶奶的鸡蛋酱似的,写脱口秀不舍得放梗呢。你这个脱口秀整麻烦了,找本字典里面放一个梗,天天能说脱口秀。
甚至用了夸张的手法,讽刺了自己脱口秀梗少的情况。
我小时候在东北,我爸有一次来一个英国的客户,随便吃了两顿饭之后英国人就飘了,觉得中国这酒也不好喝,中国人也不能喝,我这两天都没喝多。我爸想,这么合理的诉求,应该得到满足。就去跟他喝,临行前还问我说,就咱东北那些喝酒的绕口令,感情深一口闷,感情浅舔一舔,感情厚喝不够,感情铁喝吐血。用英语咋说呀?
最后一句用英语咋说呀,是意料之外不会去想到直接翻译的,但又很符合老父亲人设。
1、弗洛伊德 《诙谐及其与无意识的关系》
2、格雷格·迪安 《手把手教你玩脱口秀》
3、《脱口秀大会》
]]>在文章的最开始,我把效果图先展示一下,这就是我对着找了好久找不到的原图。自己做一个gif还挺有意思的,所以我把这部分也留了下来。文章中需要的最终成品gif可以在这里右击另存为下载,只想看设置的可以下载好直接跳到“转化为live photo”一节。
肯定不是所有人都了解怎么设置苹果手表的自定义动图表盘,这其实是一件很简单的事情。
苹果有一个拍摄live photo的功能,就是一张照片在后台还会同时存储一个mov格式的视频,当你在相册里长按图片就会播放这个视频,还原拍摄前后的情况。而如果把这种live photo设置成手表表盘,手表亮起时会自动播放该图片。
所以基础的思路就有了,制作动图,转化成live photo,设置到表盘。
处理图片就得说一句Adobe大法好。
就素材这一块,数位板、Inklet或者甚至备忘录都行,为了做这张动图,需要以下这一串图片:
之后我们需要把这些图片每一个作为一个图层导入Photoshop,通过开关可视达到gif的效果。
窗口中有一个时间轴需要打开,之后在时间轴里新建帧,开关可视即可。
每一帧的时间也可以不设置,反正intoLive会把每一帧都改成0.1秒。
原理来说,只要给图片添加mov就可以制作出gif,但这是苹果系统。
我试了一下能不能写个小脚本直接转,不过这个操作实在没办法脚本完成。写一个ios应用是可以实现的,不是很难,不过这和装个软件也没啥差别了。如果你感兴趣可以看一下这篇文章,里面具体讲了怎么手动制作live photo。
我们这里采用了intoLive,这个软件在保存图片时有个广告,可以接受啦。
读取图片,点击右上角制作,保存到相簿,三步就完成了。
设置到表盘之前我们需要让这张live photo最后停在冒着问号的界面,这就需要设置一下live photo的主要照片。
在相册里找到导出来的live photo,点击下面最左边live photo的标识,再把大图下面进度条拖到最后,点击设为主要图片,保存即可。
最后就是把live photo设置到表盘,点击分享(我的ios版本里是在左下角),找到一个创建表盘。
之后在苹果手表上设置使用该表盘就可以了。
最后有一个小提示,如果你是常亮版本的手表,关闭常亮就可以看到效果了。
]]>本文中介绍三种文件格式的区别的时候,转换roff语言与富文本使用到了groff命令,可能需要安装。
在md转化为富文本的时候除了groff命令,还使用到了pandoc命令,可以进行一个安装。
以scpp的文档展示一下三种格式的区别。
1 | SCPP(1) SCPP(1) |
根据不同的终端,富文本的显示是通过加入不同的特殊字符达到效果。
由于是放在代码框里面,特殊字符不会被处理成加粗、倾斜等格式,这些在终端中会显示。
下文生成的scpp.1
就是包含特殊字符的文档。
终端不同,特殊字符的约定不同。也就是说Windows终端上生成的富文本放到Linux的终端上显示就可能不正常。
由于书写麻烦也不通用,而源文档需要书写简单而且通用,所以有了下面两种格式。
roff是gnu默认的标记语言,用纯文本就可以写出有格式的文档,大量我们man命令看到的内容都是用这个格式写成的。
1 | .TH SCPP 1 "9 September 2019" |
其中例如.TH
、\fB\fP
等内容让文档可以产生加粗、标题等各种格式。
将这个文件存储为scpp.roff
,之后输入这个命令就可以看到显示效果:
1 | groff -Tascii -man scpp.roff | more |
是不是就看到了目标文档的效果,如果你想看到特殊字符可以把他输出到文件:
1 | groff -Tascii -man scpp.roff > scpp.1 |
roff格式的文件有大量的标记,如果你感兴趣,可以在这里扩展阅读。
markdown是目前非常常用的标记语言,也是纯文本编写有格式的文档,大量现在的博客都是用这个语言写成的。
相较而言,markdown的标记更少但也更简单,入门方便,也提供图片、表格等的插入。
本文档使用md格式就是这个样子:
1 | --- |
将这个文件存储为scpp.md
,之后输入这个命令就可以看到显示效果:
1 | pandoc --standalone -f markdown -t man -o scpp_md.roff scpp.md | groff -Tascii -man scpp_md.roff | more |
其中--standalone
标签是为了给文档生成的独立的文件头。
开头的那些元数据提供了生成roff所需的一些必要内容。
为了让其与所有其他的man文档格式相同,我们先转为roff格式,再通过groff转化为富文本。
到了这一步,已经了解了三种不同的文件格式,也可以用最熟悉的markdown格式写man文档。
下一步就是将写好的内容进行安装,让帮助文件生效了。
不同的系统有不同的man手册目录,linux是/usr/man
,osx是/usr/share/man
。
将文件生成在该目录就可以了。
1 | groff -Tascii -man scpp.roff > /usr/man/man1/scpp.1 |
之后使用man scpp
就能看到你自己写的man文档。
本文主要记录了放进点文件的代码的内容,附带的把设置ssh密钥对也放在文章后面。如果熟悉这些内容,可供复制的代码直接在效果展示一节。
文章开始,照例展示一下成品,将本文的代码放到点文件(.bashrc)里之后,就可以通过自定义的scpp命令完成文件的上传下载,看上去会是这样的:
1 | scpp push -r local_folder ./ |
为了方便直接取用,如果不想看具体的文章,将下面这行代码添加到点文件当中,更改用户名、地址、配置即可:
1 | scpp(){(read U S P<<<'user ip ~/tmp/';O='-P 22';H='usage: scpp [push|pull] [scp options] source target';if [ $1 != 'push' ]&&[ $1 != 'pull' ]||[ $# -lt 3 ];then echo $H;return 2;fi;[ $1 = 'push' ]&&scp ${@:2:$#-3} $O ${@:(-2):1} $U@$S:$P${!#};[ $1 = 'pull' ]&&scp ${@:2:$#-3} $O $U@$S:$D${@:(-2):1} ${!#})} |
scp命令和ssh一起都会装好,但是使用的时候看上去都是这样的:
1 | scp -P 22 package.tar.gz username@server_ip:~/tmp/package |
每次上传下载都会需要把配置和用户名、地址完整打一遍,即使上翻命令然后改也非常不方便。
其实重复的内容有三个,用户名、地址、配置,有时候我会把他们添加到环境变量里,于是就变成:
1 | scp $OPTIONS package.tar.gz $USERNAME@$SERVER:$DEFAULT_PATH/package |
虽然不会省很多事儿,但起码不会输错了,如果变量名无所谓阅读的话还是能省不少事儿的。
为了进一步简化,就干脆写了个函数:
1 | function scpp () { |
将这个函数放进点文件(.bashrc),重新加载即可。
当然,需要把用户名、地址、常规配置、默认远端文件夹改成你需要的内容。
1 | source .bashrc |
加载了这个函数后,上传下载就简化成这样了:
1 | scpp push package.tar.gz ./ |
当然根据需要,完全可以再更改完配置后把代码简化成一行,点文件加一行代码就可以达到这个效果。
经常忘记免密码登录需要设置的那个密钥对,这里顺带也做一个记录。
1 | cd ~/.ssh |
简单的来说就是创建密钥对然后放进去,如果还是不行,检查一下文件权限和ssh设置。
1 | cat /etc/ssh/sshd_config | grep RSAAuthentication |
scp和ssh就是类似的东西,免密码登录不需要额外的设置。
最简单的方式,可以使用complete命令添加自动补全。
先提供完整的补全命令,放在.bashrc中即可:
1 | _scpp(){ [[ ${#COMP_WORDS[*]} -le 2 ]]&&COMPREPLY=($(compgen -W 'pull push' ${COMP_WORDS[1]}))||COMPREPLY=($(compgen -A file)); };complete -F _scpp scpp |
下面分解来解释一下命令里有些什么。
通过如下命令让_scpp
函数处理scpp
的自动补全:
1 | complete -F _scpp scpp |
处理函数中常用的变量有这些:
variable | description |
---|---|
COMP_WORDS | 类型为数组,存放当前命令行中输入的所有单词 |
COMP_CWORD | 类型为整数,当前输入的单词在COMP_WORDS中的索引 |
COMPREPLY | 类型为数组,候选的补全结果 |
COMP_WORDBREAKS | 类型为字符串,表示单词之间的分隔符 |
COMP_LINE | 类型为字符串,表示当前的命令行输入字符 |
COMP_POINT | 类型为整数,表示光标在当前命令行的哪个位置 |
函数最后设置的COMPREPLY
数组会通过<TAB>
完成补全。
更具体的补全就是简单的文档内容,可以在这里扩展阅读。
这篇文章的基本问题是这个:
我需要在PPT中展示一个非常复杂的关系,图包含大量节点和连线。关系图可以根据演示的情况实时变化,方便讨论。
所以大致思路是这样的,在PPT中添加网页控件,在网页控件中通过ECharts绘制需要的图形。过程中碰到的主要问题有:
完成后的效果可以见这里。
为了方便测试,这里提供了完整项目的下载,需注意项目中未包括基础HTML一节中应下载的echarts-en.js
,额外下载即可。
PPT的设置为,添加控件、控件自动运行、消除不必要提示,最终达到与原生表格没有差别的体验。
为了方便下面的叙述,以下内容均运行在Windows 10,Office 2016,文件列表如下:
1 | drag-demo |
在开发工具一栏中,选择其他控件,其中可以找到Microsoft Web Browser
,点击确定。
但因为ActiveX的关系,这边一般都会提示,“无法插入此ActiveX控件”。
为了解决问题,需要更改如下注册表(Win+R regedit),允许插入控件。如下键值若没有,新建即可,全部改为0。Office如果不是16的话根据Office版本更改最后一条。
1 | HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\ActiveX Compatibility\{8856F961-340A-11D0-A96B-00C04FD705A2}\Compatibility Flags |
由于IE版本可能不同,这里还需要限制Web Browser
使用特定版本的IE,将下面的键值改为十进制的10001。
1 | HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION\PowerPnt.exe |
以上内容参考该指南,如果设置了还是不能成功插入可以进一步阅读指南。
双击该控件可以打开VBA的编辑窗口,将如下代码添加到最开头。
1 | Sub OnSlideShowPageChange() |
这就是一个简单的VBA,每次切换页面都会调用OnSlideShowPageChange
函数,在该函数中进行判断,若页码为Web Browser
所在的页码则将页面转到本地的网页主页。
即使这样操作后,网页主页加载本地的JS还是会提示,“为帮助保护你的安全,你的Web浏览器已经限制此文件现实可能访问你的计算机的活动内容。单击此处查看选项”。虽然所有JS写进网页里也是个办法,但终究不方便。这里可以通过在HTML中DOCTYPE
后加入如下的一行,规避这一提醒。
1 | <!-- saved from url=(0013)about:internet --> |
全部完成之后由于使用的VBA,需要将PPT保存为“启用宏的PowerPoint演示文稿”(main.pptm),另存即可。
ECharts设置为基础HTML,生成关系图,添加拖拽。
由于IE的兼容性问题,以下的代码都经过了一些例如用var
替换const
的操作,这也没办法。如果你知道如何将Chrome作为控件加入PPT,请一定留言告诉我。
基础的代码如下:
1 |
|
在body
中添加一个div
用于显示图表,之后引入ECharts和配置文件。
echarts-en.js
是ECharts包,为了方便离线使用,这里下载到了本地(下载地址见这里)。
ECharts的图形生成是通过设置Option字典完成的,也就是根据文档创建一个Option字典,通过chart.setOption(option)
完成设置。
关系图对应的是series
项下类型为graph
的内容,代码如下:
1 | var BASE_GRAPH_ID = 'relationship' |
由于其他布局都存在回弹或者自动重新排列的问题,这里没办法使用force
布局提供的拖拽。也无法使用默认布局,默认布局在拖拽一个节点后其他节点会重新排布。所以最后我们选择坐标系布局,每一个节点预先设置位置,在坐标数量多的情况下也可以随机数或者借助另一个默认布局,确定节点的位置。
二维坐标的关系图节点没有默认的拖拽,而一般的图形均有拖拽的默认选项。所以实现的思路为,在关系图每一个节点上覆盖一个透明的可拖拽图形,拖拽透明图形的时候同步更改节点的位置。
实现代码如下,需要复制在上述代码后面:
1 | var dragOption = { |
其中涉及的一个问题是关系图的布局和单独图形的坐标系统不同,同样的[100, 100]
在两个坐标系统中位置是不一样的。单独图形是直接根据像素确定的,关系图则有图形专门的坐标系统。通过convertToPixel
和convertFromPixel
可以完成转换。
我这里是使用Chrome完成的Debug,全部结束之后运行main.pptm,再放映幻灯片。
]]>博客生成的代码框,格式经过简化就是如下的内容:
1 | <figure class="highlight javascript"> |
这些代码均为自动生成,也没有什么可以讨论的。代码高亮通过span
实现;由于代码与行号生成在两个td
中,所以复制代码的时候不会复制到行号。
换行涉及到三个内容,具体实现的代码为:
1 | figure .code span { |
其中分别的作用为:
空白符的处理简而言之是这样一张表:
属性 | 多个换行 | 空格和换行 | 自动换行 | 行末空格 |
---|---|---|---|---|
normal | 保留一个 | 保留一个 | 是 | 移除 |
nowrap | 保留一个 | 保留一个 | 否 | 移除 |
pre | 保留 | 保留 | 否 | 保留 |
pre-wrap | 保留 | 保留 | 是 | 保留不换行 |
pre-line | 保留 | 保留一个 | 是 | 移除 |
break-spaces | 保留 | 保留一个 | 是 | 保留换行 |
我们的代码,对于多个换行需要全部保留,多个空格和换行需要全部保留,需要自动换行,行末空格保留但不需要因为空白字符换行。所以就white-space
的属性可以选择pre-wrap
。
虽然空白符处理中我们设置了需要换行,但是过长的单词还是会导致行宽超出预设的宽度。
属性 | 如何处理过长单词 |
---|---|
normal | 保留 |
break-word | 断开 |
我们不希望因为有过长的单词导致出现横向滚动栏,所以这里可以选择break-word
。但考虑到与word-break
属性的作用重合,而且word-break
属性更适合汉语的特别处理,所以就不再使用overflow-wrap
。
换行的设置也可以使用这个,这个属性可以将汉语整句视为一个单词不换行(直到有标点符号为止)。
属性 | 英文处理 | 中文处理 |
---|---|---|
normal | 不断开单词 | 断开句子 |
break-all | 断开单词 | 断开句子 |
keep-all | 不断开单词 | 不断开句子 |
break-word | 可能的话不断开单词 | 断开句子 |
其中break-all
与break-word
的区别为:若一行可以容纳一个单词但是无法容纳两个,break-all
将断开第二个单词,break-word
将把第二个单词放在第二行。
根据要求,我们就选用了break-all
。这里其实和使用overflow-wrap: break-word
是一样的效果。
自动换行之后就需要行号的位置根据代码的长度做相应变化,博客里本来有代码框自动调整宽度的代码,这里将行高的调整也加进去。
1 | +function($) { |
这里与行号位置相关的部分就是29-32行的内容,根据offsetHeight
调整height
。
仅是这样还是无法更改行号的位置,原因在于目前显示代码使用的都是span
元素。我们若需要通过height
调整行号所占的高度,应将其显示方式改为inline-block
,所以增加如下CSS:
1 | figure.highlight pre > .line { |
其中如果不设置display: inline-block
,line-height
与height
也将不相同,可能出现的小数将导致不必要的麻烦。
到这里就完成了全部关于代码换行的设置。
]]>这篇文章比较长,你可以挑着看,我也为此生成了目录。想听故事的话可以看“基本情况”这一节,想了解一些商标基础的话可以看“商标注册基础内容”这一节,只想看个结论的话“具体分析”这一节就够了。
网上可以搜到相关的内容主要为:
2019年6月6日,“畅言”公众号(现已改名“云评论”)发布“关于侵犯科大讯飞股份有限公司注册商标权的致歉声明”。其中提到,“畅言”由于侵犯科大讯飞商标权,“畅言评论”将使用新名称“云评论”。
1 | 科大讯飞股份有限公司: |
本声明涉及到两家公司,北京云站科技有限公司(下称“云站科技”)与科大讯飞股份有限公司(下称“科大讯飞”)。
云站科技旗下的“畅言”商标主要用于畅言评论系统,网络中可见的最早的记录为2012年11月27日,谷歌记录到了畅言评论发布了WordPress的插件(截图见这里)。而后畅言评论系统一直多见于各类论坛与博客,至今一直保持更新。由于目前国内各类评论插件都停止更新或不能使用,畅言评论系统已经成为很多人第三方评论系统的首选。
科大讯飞旗下的“畅言”商标主要用于畅言多媒体教学系统,网络中可见的最早记录为2012年3月29日,谷歌记录到了畅言智慧课堂教学系统的介绍文章(截图见这里)。而后网络上关于该服务的介绍较少,该情况可能因为该教学系统主要销售和宣传方式不是网络途径。目前科大讯飞旗下畅言相关的内容可在畅言云网站见到,更新了大量相关内容。
当天,“云评论”官网上图标及各类提示都完成了替换。
不过云评论的二级域名还是保持了changyan.sohu.com
。很大可能该域名不会弃用,“云评论”插件的载入也是依赖这一二级域名。一方面,这一二级域名显然并非商标权侵权行为。另一方面,启用另一域名yunpinglun.sohu.com
作为一般用户的入口,让产品名称和二级域名统一并不会产生大量额外支出。
作为云评论的用户,我发现”云评论“广告栏位中竟然出现了侵权相对方科大讯飞的广告,我做了一个截图。
作为用户不得不提的是,这两天的更新里针对广告部分做了优化,往常常规使用的CSS去广告已经失效。个人还是支持这一做法的,不付费用别人的产品,不屏蔽广告也是应有之义。不过如果广告实在太丑或者太打扰用户,通过一些手段改改大小或者换个地方合不合适呢?
通过公告可以看到商标权侵权的双方为,科大讯飞股份有限公司及北京云站科技有限公司。根据两公司的名字及案由,很容易的就能够搜索到公告信息(截图见这里)。
1 | (2019)皖0191民初1247号 公告 |
据此可以看到该案已经进入了司法程序,可能已经产生生效的法律文书。为此,我尝试搜索了中国裁判文书网(搜索结果见这里),截止到2019年6月10日没有找到相应的判决。考虑到调解书和部分判决书不上网以及判决书需要一定时间才会上网,这一结果也在情理之中。
不过不得不吐槽一下,查询过程当中裁判文书网大部分时间都处于“系统繁忙,请您稍后再试”的状态,搜索实在难以完成。当我看到有一个注册界面的时候,我朴素的以为由于我不是注册用户,搜索享受着爬虫待遇。结果不仅注册无法完成,“用户名查重失败:Index was outside the bounds of the array.”;而且找朋友借了一个账号后搜索速度完全没有好转。
通过开庭的信息,可以确定的是云站科技与科大讯飞之间确实存在商标权权属争议及侵权纠纷,该纠纷最后以云站科技停止使用“畅言”商标结束。
国家知识产权局商标局有下设中国商标网,通过其中的综合搜索,搜索商标名称为“畅言”的商标,可以找到“畅言”相关的34个商标。
其中本次的双方注册情况为:
具体内容我做了一张表,表的内容见这里。
这里涉及到几类商标,具体的内容有《类似商品和服务区分表》具体作了解释,简单的来说:
考虑到2019年2月20日已作出开庭公告,2019年4月9日云站科技申请商标的行为在后,可以推测云站科技认为其在9、38、42类享有商标权,具体的小类为上述几类。
其中几个小类的商标权科大讯飞并未申请,分别为0907、0923、3801、3802、4220。科大讯飞有在先申请的为0901与0908。
就商品/服务项目而言,类似群重合的部分注册情况为:
中国商标网的搜索结果中可以看到云站科技注册的商标,通过网上简单的字体比对可以发现云站科技注册的“畅言云评”图标构成十分简单。图标为800x800的图片,内容为“畅言云评”四个字,字体为宋体,没有特别的设计或装饰。
我将“畅言云评”的商标与宋体的这四个字做了一个对比,对比图见这里。
其中宋体是一个有意思的字体,宋体一直给人一种默认自带的感觉,但其实他的著作权归属于北京中易中标电子信息技术有限公司(下称“中易中标”)。我们常见的微软自带宋体背后,中易中标与微软签订过《字体许可协议》,微软获得了中易中标的许可。但由于Windows 98及之后的系统不属于授权范围,中易中标于2007年起诉微软,产生了(2007)一中民初字第5362号的著作权纠纷,具体内容即为宋体及黑体的著作权侵权。
可见宋体的商用需要获得中易中标的授权,未授权的使用属于侵犯著作权的行为。不过中易中标可见的诉讼记录中除了微软的诉讼未发现对任何一家公司的判决,可能其怠于行使民事权利甚至默认该类侵权行为,当然考虑到该公司背景也完全可能通过其他途径实现民事权利。
商标注册有一系列流程,具体而言包含,向商标局提交申请书、形式审查、实质审查、初步审定公告、注册公告、注册。每一步骤的期限以及具体要求法律都有明确的规定,整体流程完成后即完成注册。
整个过程还是很复杂的,有兴趣的这里提供一张流程图(点击这里查看)。
可以看到整个注册过程就是审查与公告,经过了法定的公告期没有成立的异议则申请人可以获得申请商标的商标权。
本文中提到了商标的大类与小类,标准来讲,商标的大类即国际分类,商标的小类即类似群。从上面的申请表及国标网显示的内容可能会发现,商标申请仅需要提供类别和商品/服务项目,不需要填写类似群。商标/服务项目是类似群更下层的分类,以笔记本电脑为例,其大类(国际分类)为9,小类(类似群)为0901,商标/服务项目是笔记本电脑(090103)。
那么商标权是怎么保护的呢,大类相同就可保护,还是需要商标/服务项目相同才可保护?结论是很有意思的,保护和分类并没有必然的关系。
根据《最高人民法院知识产权案件年度报告(2011)》,商标保护的认定不能根据物理属性确认,而应判断是否能共存。若侵权商标与原商标无法共存,则应认定侵权商标涉及的商品也在原商标的保护范围内。“最高人民法院审查认为:商标法设置商品类似关系,是因为商标主要是按商品类别进行注册、管理和保护。在商标授权确权和侵权判定过程中,进行商标法意义上相关商品是否类似的判断,并非作相关商品物理属性的比较,而是主要考虑商标能否共存或者决定商标保护范围的大小。”
为此,最高法以鞋商标侵权服装商标为例,具体阐述了该问题。“避免来源混淆是商品类似关系判断时要坚持的一项基本原则。本案中,争议商标指定使用的商品为鞋和靴,引证商标核定使用的商品是服装等。虽然两者在具体的原料、用途等方面具有一些差别,但是两者的消费对象是相同的,而且在目前的商业环境下,一个厂商同时生产服装和鞋类产品,服装和鞋通过同一渠道销售,比如同一专卖店、专柜销售的情形较为多见。同时,争议商标与引证商标中的“鸟图形”虽然在细部上略有差异,但两者基本形态相同,且根据查明的事实,引证商标通过使用具有较高的知名度。在这种情况下,如果两商标在服装和鞋类商品上共存,容易使相关公众认为两商品是同一主体提供的,或者其提供者之间存在特定联系。因此,争议商标与引证商标构成类似商品上的近似商标。”
关于《类似商品和服务区分表》,也就是其中大类、小类、商标/服务项目的分类,最高法院给出了这样一个态度。“最高人民法院认为,《区分表》可以作为判断类似商品或者服务的参考,但不能机械、简单地以《区分表》为依据或标准,而应当更多地考虑实际因素,结合个案的情况进行认定。”
所以一般同类的商品属于侵权,但实际上也完全可能存在跨类的侵权,例如最高法提到的鞋与服装的跨类侵权。
《中华人民共和国商标法》
第十三条 为相关公众所熟知的商标,持有人认为其权利受到侵害时,可以依照本法规定请求驰名商标保护。
第四十九条 注册商标成为其核定使用的商品的通用名称或者没有正当理由连续三年不使用的,任何单位或者个人可以向商标局申请撤销该注册商标。商标局应当自收到申请之日起九个月内做出决定。有特殊情况需要延长的,经国务院工商行政管理部门批准,可以延长三个月。
第五十七条 有下列行为之一的,均属侵犯注册商标专用权:
(一)未经商标注册人的许可,在同一种商品上使用与其注册商标相同的商标的;
(二)未经商标注册人的许可,在同一种商品上使用与其注册商标近似的商标,或者在类似商品上使用与其注册商标相同或者近似的商标,容易导致混淆的;
(三)销售侵犯注册商标专用权的商品的;
(四)伪造、擅自制造他人注册商标标识或者销售伪造、擅自制造的注册商标标识的;
(五)未经商标注册人同意,更换其注册商标并将该更换商标的商品又投入市场的;
(六)故意为侵犯他人商标专用权行为提供便利条件,帮助他人实施侵犯商标专用权行为的;
(七)给他人的注册商标专用权造成其他损害的。
第五十九条 商标注册人申请商标注册前,他人已经在同一种商品或者类似商品上先于商标注册人使用与注册商标相同或者近似并有一定影响的商标的,注册商标专用权人无权禁止该使用人在原使用范围内继续使用该商标,但可以要求其附加适当区别标识。
第六十三条 侵犯商标专用权的赔偿数额,按照权利人因被侵权所受到的实际损失确定;实际损失难以确定的,可以按照侵权人因侵权所获得的利益确定;权利人的损失或者侵权人获得的利益难以确定的,参照该商标许可使用费的倍数合理确定。对恶意侵犯商标专用权,情节严重的,可以在按照上述方法确定数额的一倍以上五倍以下确定赔偿数额。赔偿数额应当包括权利人为制止侵权行为所支付的合理开支。
《最高人民法院关于审理商标民事纠纷案件适用法律若干问题的解释》
第十一条 商标法第五十二条第(一)项规定的类似商品,是指在功能、用途、生产部门、销售渠道、消费对象等方面相同,或者相关公众一般认为其存在特定联系、容易造成混淆的商品。
类似服务,是指在服务的目的、内容、方式、对象等方面相同,或者相关公众一般认为存在特定联系、容易造成混淆的服务。
商品与服务类似,是指商品和服务之间存在特定联系,容易使相关公众混淆。
本案双方的商标不同,属于近似商标,应适用《商标法》第五十七条第二款认定侵权,“未经商标注册人的许可,在同一种商品上使用与其注册商标近似的商标,或者在类似商品上使用与其注册商标相同或者近似的商标,容易导致混淆的”。也就是说,一方面,侵权的前提是商品属于同一种类。另一方面,使用近似商标并不一定承担侵权责任,还必须判断是否会使消费者产生混淆。
云站科技的“畅言评论”自2012年起提供的服务均为社会化评论系统,科大讯飞的“畅言教育”自2012年起提供的服务均为教育辅助系统。“畅言评论”为评论插件,是完整网页或者应用的可选组成部分,“畅言教育”为教学辅助应用,是完整的应用,难以认定为同一种商品。侵权的前提无法达到,故难以认定为侵权。从混淆的角度来说,“畅言评论”提供的是评论服务,“畅言教育”提供的是教育资源与数据,内容上无法构成混淆。“畅言评论”的消费者是需要评论功能的开发者,“畅言教育”的消费者是需要教育资源与数据的教育机构或开发者,目标消费者人群不同,难以产生混淆的效果。
故从前提或混淆的效果,本案均难以认定为商标权侵权。
关于更名的结果已经不用说了,云站科技选择不再使用“畅言”商标。
就用户的吸引与流失,老用户而言,可以想象没什么影响,改名后第一次点进后台可能会有些惊讶。而新用户,身边使用过”畅言“评论插件的朋友,大都是通过旧的文章介绍了解到他。如果无法再通过搜索”畅言“找到该插件,势必会影响新用户的产生。
好在目前,我通过常用的几个搜索引擎进行了搜索,云站科技的网站目前仍旧排在“畅言”搜索结果的首位。但值得注意的是,”畅言“教育平台的搜索结果,虽在前两位的”畅言“评论系统后面,但也占据了后面的四个到五个位置。随着更名后的时间推移以及科大讯飞可能的加大”畅言“教育平台的宣传力度,也许不久之后”畅言“评论系统将被挤出搜索的第一页,从而无法通过积累的“畅言”口碑获得用户。
另一个值得一提的是,科大讯飞在云站科技投放了广告,科大讯飞在使用云评论插件的广告栏位。我也好奇这个广告栏位的使用,是云站科技给出的补偿,还是科大讯飞付钱买商标的方式呢?单就从云站科技实际侵权的可能性较小的角度来看,这一点云站科技的常法律师出具的法律意见书中一定会提到,很大可能使用广告栏会是付费的。
国内云评论服务的提供商越来越少,起码“云评论”还是个完备可用的选择。“云评论”评论系统这次更名,失去了“畅言”的商标,避免了一个麻烦,可能获得了一笔不知数额的广告费。总有一种把自家牌匾卖了换钱的感觉,揭得开锅谁卖牌匾,和他死磕到底呗。也不知道现在“云评论”的经营情况如何,还能不能继续下去。
]]>本文主要列出替换的JS,简述了一下找回调函数的思路。
畅言的emoji传到前台的数据是[emoji:d83cdfc6]
格式。
所以我们需要做的就是把这一段文字转化成Unicode字符,这是个很简单的操作。
1 | // 限定只更新畅言评论栏中的内容 |
下面问题就在于能不能找到回调函数,在评论载入完成后调用替换。
目前暂时没有找出可用的回调,现在最简单的使用window.onload = function(){}
完成了替换。
所以目前的结果就是页面载入完成后替换,->这里<-是代码。
我发现upload/changyan.js中有changyan.api.ready
的函数。1
2
3
4window.changyan.api.ready = function(fn) {
window.changyan.api.tmpHandles = window.changyan.api.tmpHandles || [];
window.changyan.api.tmpHandles.push(fn);
};
之后src/adapter.min.js中通过runReadyFn
完成回调。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28var runReadyFn = function() {
if (window.changyan.tmpHandles && window.changyan.tmpHandles.length) {
for (var i = 0; i < window.changyan.tmpHandles.length; i++) {
var _fn = window.changyan.tmpHandles[i];
_fn && _fn();
}
window.changyan.tmpHandles = [];
}
};
window.changyan.rendered = false;
$$event.listen("changyan:cmt-header:header-rendered", function() {
if (!window.changyan.rendered) {
runReadyFn();
window.changyan.rendered = true;
}
});
$$event.listen("changyan:mobile-cmt-list:list-render", function() {
if (!window.changyan.rendered) {
runReadyFn();
window.changyan.rendered = true;
}
});
$$event.listen("changyan:cmt-box:box-render", function() {
if (!window.changyan.rendered) {
runReadyFn();
window.changyan.rendered = true;
}
});
在研究代码的过程当中,发现代码中还有残留下来的内容。
比如extensions/longloop.js中的:1
e("C:/Users/Yaodoggy/Documents/Program Files/Wamp/wamp/www-mdevp/mdevp/cache/www/longloop/longloop.js")
本来这事儿应该是这周末的安排,不过也是赶巧,下午闲着的时候畅言客服给我来了个电话,闲着也是闲着就写了一半。也是我的风格了,服务器是云服务器客服一个电话我顺带配好的,备案是备案机构一个电话我顺带备好的。随意是一方面吧,这类事儿总体完成的效率还真不低。于是晚上回家就把剩下的一半写掉了,这篇文章没什么理论,主要是简单的配置代码,复制过去有空的时候慢慢看好了。
官网有自适应的代码安装方式:
1 | <div id="SOHUCS" ></div> |
把提供的appid和conf填好,尝试访问就可以用了。
使用的时候发现畅言是可以http访问的,如果你对于全站HTTPS有特别的要求,可以通过返回HTTP请求的时候添加如下内容:
1 | Content-Security-Policy: default-src https: |
不过因为牵扯到Web版本和PC版本的CSS存在区别,这里的JS代码还需要做一些小的改动。
这类就简单的添加了两个不同的CSS。
1 | <div id="SOHUCS" ></div> |
这段代码使用的两个CSS分别是changyan-mobile.css
和changyan.css
。
畅言默认的样式偏圆,也不是扁平的风格,我大致网上找了找现有的样式做了个修改。
这段代码是changyan.css
:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102.module-cmt-box {
padding: 10px 0 ;
margin-top: -10px ;
overflow: visible ;
}
.header-login {
left: 90px ;
border: 0 ;
border-radius: 0 ;
margin-top: 88px ;
border-radius: 21px ;
}
.post-wrap-border-l,.post-wrap-border-r,.post-wrap-border-t-l,.post-wrap-border-t-r {
display: none;
}
.post-wrap-main {
border: 0 ;
}
.post-wrap-w {
background: #f0f0f0;
}
.btn-fw {
background: #5fb878 url(data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCI+PHBhdGggZD0iTTgxNy42NTcgNzc1Ljc1OEw0NTQuNzEgNjY0LjA4bDM2Mi45NS00MTguNzg4TDM0My4wMzIgNjY0LjA4IDYzLjgzNyA1NTIuNDAzIDk1Ny4yNTYgNzcuNzc1IDgxNy42NTcgNzc1Ljc1OHpNNDU0LjcxIDk0My4yNzVWNzQ3Ljg0bDExMS42NzQgNTUuODRMNDU0LjcxIDk0My4yNzR6IiBmaWxsPSIjZmZmIi8+PC9zdmc+) center no-repeat ;
width: 60px ;
height: 60px ;
border-radius: 30px;
margin-top: -5px ;
margin-right: 40px ;
background-size: 30px ;
box-shadow: 5px 5px 10px rgba(0,0,0,.2);
-webkit-transition: .3s;
transition: .3s;
outline: none;
}
.btn-fw:hover {
box-shadow: 4px 4px 10px rgba(0,0,0,.2);
}
.block-head-w,.cmt-list-type {
height: 0px ;
}
.section-service-w {
height: 0;
opacity: 0;
}
.head-img-w {
margin: 0 ;
}
.head-img-wimg {
width: 25px ;
height: 25px ;
}
.head-img-w {
top: 118px ;
left: 95px ;
}
.wrap-action-gw {
border-bottom: 1px solid #dee4e9 ;
padding-top: 30px ;
padding-bottom: 1pc ;
}
.cmt-list-number,.title-name-gw-tag,.type-lists,.wrap-name-w {
display: none ;
}
.cmt-list-type {
margin: 0 ;
}
.build-floor-gw {
background: #f0f0f0 ;
}
.block-cont-gw {
padding: 20px 0 ;
border: 0 ;
}
.section-list-w {
width: 95% ;
margin-left: 2% ;
}
.build-floor-gw {
background: #f9f9f9 ;
}
.user-name-gw>a {
text-decoration: none ;
}
这段代码是changyan-mobile.css
。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74.module-mobile-cmt-header {
height: 150px
}
.comment-number-tri {
border-left: 0
}
.comment-number {
margin-top: 1px
}
.comment-number, .comment-text {
background-color: transparent ;
font-size: 16px ;
color: black ;
font-weight: 500 ;
padding: 0
}
.header-right {
float: left
}
.header-login {
display: inline-block ;
margin-top: -12px ;
font-family: sans-serif ;
font-size: 14px
}
.header-pho {
width: 2em ;
height: 2em ;
background-size: 2em
}
.mobile-header-head {
margin: 85px 0 0 0 ;
height: 0
}
.comment-textarea {
height: 0 ;
float: left ;
margin-top: -150px
}
.header-comment-number {
margin: -6px 0 0 10px
}
.comment-input {
border: 0 ;
background-color: transparent ;
font-family: sans-serif ;
font-size: 14px ;
border-radius: 0 ;
height: 90px ;
margin-top: 15px
}
.box-footer-button {
background: #b1b1b1 url(data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCI+PHBhdGggZD0iTTgxNy42NTcgNzc1Ljc1OEw0NTQuNzEgNjY0LjA4bDM2Mi45NS00MTguNzg4TDM0My4wMzIgNjY0LjA4IDYzLjgzNyA1NTIuNDAzIDk1Ny4yNTYgNzcuNzc1IDgxNy42NTcgNzc1Ljc1OHpNNDU0LjcxIDk0My4yNzVWNzQ3Ljg0bDExMS42NzQgNTUuODRMNDU0LjcxIDk0My4yNzR6IiBmaWxsPSIjZmZmIi8+PC9zdmc+) center no-repeat ;
background-size: 30px 30px ;
width: 100px ;
height: 50px ;
border-radius: 10px ;
margin-right: 10px
}
.list-footer-wrapper-wap {
display: none
}
下面那个评论就是已经设置好了的畅言插件了。
之后根据博客的类型将这个CSS文件压缩好每次载入即可。
]]>