解决恼人的Win10输入法问题——TSFTool

前言

相信如果是经常使用电脑的小伙伴,尤其是从98,2000,XP,Win7一路用过来的老用户,一定对现在版本的Win10默认输入法有很多意见,比如快捷键冲突不能使用ctrl+shift切换输入法为了玩Xbox修改了区域和语言结果默认输入法不是英语等等,我之前也是饱受这些事情困扰,直到发现了今天的主角——TSFTool。

软件介绍

TSFTool 是 IMETool 的继承者,是运行在 Windows10/Windows Server 2019 操作系统下的输入法设置工具,支持 TSF 输入法框架,并部分兼容旧的 IMM 输入法框架。

简单点说就是一个用于修改系统输入法设置的工具,可以绕过系统设置的限制。

作者:Silence

发布地址:TSFTool 输入法设置工具

分流下载地址:TSFTool 0.9.2.0.zip

使用方式

设置默认输入法为美式键盘

禁用的输入法列表中,选择美式键盘,点击右侧启用,之后在启用的输入法列表中选择美式键盘,点击右侧上移,移动到最顶部,然后在启用的输入法列表中右键点击美式键盘,选择设置为默认输入法

禁用微软拼音

启用的输入法列表中右键点击微软拼音,选择禁用

关于Nginx的一些骚操作

前几天给服务器重装了个系统,用来反向代理一些接口,结果学会了几个骚操作,分享给大家。

反向代理使用了多个证书的网站

一上来属于是一个坑,我们都知道同一个IP可以被很多个域名指向,通过不同的域名来访问同一个IP的服务器,则是通过header里的host来判断是访问到哪个站点。但是这里面会有一种情况,就是这个站点是具有tls加密也就是https加密,同时这个站点配置了多个证书,这时候如果你直接代理的话,则会报证书错误,必须在location里添加proxy_ssl_server_name on,例如下面这样。

1proxy_set_header Host "www.example.com";
2proxy_ssl_server_name on;

这样源站的服务器才能知道你是为了哪一个域名和证书而来,才回给你发放对应的证书。 注:其实这个就是SNI功能,某些网站的访问就是在这一部被屏蔽掉的。

前端跨域时的处理

前端跨域限制是浏览器的一种安全措施,叫做同源策略(Sameoriginpolicy),属于是浏览器的一种很基础的安全策略。在同源策略限制下,网页的JS会不允许访问协议、域名或者端口不同的内容和资源。但是有时候我们前端的代码可能会需要访问不同域名或者端口的接口,所以我们会使用Nginx来处理跨域问题。 一般情况下,我们在网站配置的location下面,增加下面两条,就可以允许服务器被跨域访问了。

1add_header Access-Control-Allow-Origin * always;
2add_header Access-Control-Allow-Headers * always;

但是在做反向代理的时候,如果源站配置过同源限制,则需要再加上下面这两条。

1proxy_hide_header Access-Control-Allow-Origin;
2proxy_hide_header Access-Control-Allow-Headers;

这两条的意思是丢弃掉源站的同源配置,同时你增加了新的配置,这样才能正确配置。 但是其实还有一个问题,就是浏览器会发送methodoptions的请求,用来判断是否可以接收跨域请求。 那既然我们已经允许了全部的跨域请求,我们就可以给options请求直接返回一个200告诉他可以。

1if ($request_method = "OPTIONS") {
2	return 200;
3}

由此一来我们就可以随便调用这个反向代理的接口了。

反向代理Url使用变量

反向代理时,有可能源网址并不是固定的,而是随着某些nginx的变量改变的,这种时候,就要在proxy_pass中拼接一个变量,像下面这样。

1set $name 'tom';
2proxy_pass https://www.example.com/$name;

但是如果直接这样使用可能会报错,需要在server字段下,添加dns配置,如下。

1resolver 8.8.8.8;

这样才能在proxy_pass中拼接变量。

使用lua获取post请求的body

这是这次学到的最骚的一个操作,一般来说nginx是不能直接获取到post请求中的内容的,但是大家都知道lua是一种非常容易嵌入各种各样环境的语言,nginx中也是有嵌入lua可以使用的,所以我们可以通过lua来获取postbody

首先如果想获取body的话,需要先在server字段中,添加如下配置。

1lua_need_request_body on;

这条配置代表了声明lua需要读取requestbody

之后我们在location下,添加如下配置。

1set $name '';
2rewrite_by_lua_block {
3	local post = ngx.req.get_post_args()
4	ngx.var.name = post.name
5}
6proxy_pass https://www.example.com/$name;

首先先使用原生nginx语句,定义一个变量name,之后添加rewrite_by_lua_block代码段,这里因为我是需要在proxy_pass之前处理数据,所以使用了rewrite_by_lua_block,还有其他的节点可以使用,下面再说。 然后内部就是lua语句了,定义一个post变量,赋值为ngx.req.get_post_args()的返回值,这里就获取到了body的数据了,之后ngx.var.name这个变量就等于是之前我们使用set定义的变量name,所以这里就是给变量name赋值post.name,也就是我们请求上送过来的body中的name字段。 最后再把name变量拼接到proxy_pass后面。 于是就实现了,可以通过post请求中的name字段,来修改反向代理的地址了。

扩展内容——关于在nginx中使用lua

nginx提供了几个lua代码的处理阶段,具体如下表。

处理阶段 可用范围
init_by_lua http
set_by_lua server, server if, location, location if
rewrite_by_lua http, server, location, location if
access_by_lua http, server, location, location if
content_by_lua location, location if
header_filter_by_lua http, server, location, location if
body_filter_by_lua http, server, location, location if
log_by_lua http, server, location, location if
timer *

init_by_lua

在nginx重新加载配置文件时,运行里面lua脚本,常用于全局变量的申请。 例如lua_shared_dict共享内存的申请,只有当nginx重起后,共享内存数据才清空,这常用于统计。

set_by_lua

设置一个变量,常用与计算一个逻辑,然后返回结果 该阶段不能运行Output API、Control API、Subrequest API、Cosocket API

rewrite_by_lua

在access阶段前运行,主要用于rewrite

access_by_lua

主要用于访问控制,能收集到大部分变量,类似status需要在log阶段才有。 这条指令运行于nginx access阶段的末尾,因此总是在 allow 和 deny 这样的指令之后运行,虽然它们同属 access 阶段。

content_by_lua

阶段是所有请求处理阶段中最为重要的一个,运行在这个阶段的配置指令一般都肩负着生成内容(content)并输出HTTP响应。

header_filter_by_lua

一般只用于设置Cookie和Headers等 该阶段不能运行Output API、Control API、Subrequest API、Cosocket API

body_filter_by_lua

一般会在一次请求中被调用多次, 因为这是实现基于 HTTP 1.1 chunked 编码的所谓“流式输出”的。 该阶段不能运行Output API、Control API、Subrequest API、Cosocket API

log_by_lua

该阶段总是运行在请求结束的时候,用于请求的后续操作,如在共享内存中进行统计数据,如果要高精确的数据统计,应该使用body_filter_by_lua。 该阶段不能运行Output API、Control API、Subrequest API、Cosocket API

timer

可参考官方文档:http://wiki.nginx.org/HttpLuaModule

在lua代码中,可以使用ngx.var.变量名获取ngxin的原生变量,例如ngx.var.name等价于nginx中的$name,但是注意的一点是,这个变量必须预先在nginx中声明。

可以在不同的请求阶段后面增加_block,则可以使用代码块形式嵌入lua脚本,如下。

1set $name '';
2rewrite_by_lua "
3	ngx.var.name = 'tom'
4"
5rewrite_by_lua_block {
6	ngx.var.name = "tom"
7}
Web前端开发面试题整理

导语

研究面试题是一件很有意义的事情,面试题里很多的知识点或许并不完全在工作中会用到,但是经常会涉及到一些底层知识,这些知识如果可以理解领悟的话,对程序设计还是会有不少的帮助的,这里就把之前见到的一些面试问题整理一下放在这里,然后我也可以一边分享一边学习。 如果有小伙伴发现有哪些问题我的答案有误,欢迎指正

ES6 相关

ES6 的新特性有哪些

const 和 let 变量声明

在 ES6 之前,变量声明都是采用的var,而var有一个特型叫做作用域提升,就是你无论在哪里声明这个变量,在运行时都会把这个声明提升到代码最前面执行,然后这样就会导致逻辑的混乱,而letconst解决了这个问题,同时这两者都是块级作用域,只会在一个花括号{}内生效,可以很好的避免作用域混乱产生逻辑错误。 一般情况下,使用let表示变量,用const表示常量。

 1var a = 1;
 2b = 2;
 3console.log(b); // 输出 2
 4function test(){
 5	let c = 3;
 6	const d = 4;
 7	console.log(a); // 输出 1
 8	console.log(b); // 输出 0,这里因为是在下面的 var b = 0 后面执行,所以 b 被赋值 0
 9	console.log(c); // 输出 3
10	console.log(d); // 输出 4
11}
12var b = 0;
13// 这里看做 var b 和 b = 0,var b 被提升到作用域顶部
14// 所以 b 会被先赋值 2 ,在这里再被赋值 0
15test()
16console.log(a); // 输出 1
17console.log(b); // 输出 0
18console.log(c); // 报错 c 未定义
19console.log(d); // 报错 d 未定义

模板字符串

在 ES6 之前,我们往往这么处理模板字符串:

1$("body").html("This demonstrates the output of HTML \
2content to the page, including student's\
3" + name + ", " + seatNumber + ", " + sex + " and so on.");

里面充满了+"\\,可读性和可维护性就不是很好。 但是在 ES6 之后,我们可以这样来处理模板字符串:

1$("body").html(`This demonstrates the output of HTML content to the page, 
2including student's ${name}, ${seatNumber}, ${sex} and so on.`);

``来包裹模板字符串。用${}来包裹变量。可以简单清晰的处理模板字符串。

箭头函数

这个本质就是语法糖了,不用写function,如果是直接返回一个值或者表达式的场合,还可以省略掉return{},而且可以继承当前上下文的this对象,用起来会比较方便。

 1// ES6 之前
 2var add = function (a, b) {
 3    return a + b;
 4};
 5// ES6 之后使用箭头函数
 6var add = (a, b) => a + b;
 7
 8// ES6 之前
 9[1,2,3].map((function(x){
10    return x + 1;
11}).bind(this));
12// ES6 之后使用箭头函数
13[1,2,3].map(x => x + 1);

函数参数的默认值

在 ES6 之前,函数的参数是不能直接设置默认值的,我们只能通过判断参数是否存在,再对其进行赋值,而 ES6 简化了这一点,可以直接赋初始值了。

 1// ES6 之前
 2function who(name) {
 3    if (!name) {
 4        name = '张三'
 5    }
 6    console.log(name);
 7}
 8
 9// ES6 之后
10function who(name = '张三') {
11    console.log(name);
12}
13
14who('李四'); // 输出 李四
15who(); // 输出 张三

Vue相关

谈一谈Vue.nextTick()函数

Vue中是异步更新DOM的,Vue.nextTick()是Vue框架提供给我们的DOM更新后的回调函数,当数据变化,DOM更新后,就会执行该函数,常见于需要处理DOM场合,例如。

 1// 改变数据
 2vm.message = 'changed'
 3
 4// 想要立即使用更新后的DOM。这样不行,因为设置message后DOM还没有更新
 5console.log(vm.$el.textContent) // 并不会得到'changed'
 6
 7// 这样可以,nextTick里面的代码会在DOM更新后执行
 8Vue.nextTick(function(){
 9    console.log(vm.$el.textContent) // 可以得到'changed'
10})
一场异世界冒险的梦——我与《泰拉瑞亚》的故事

相遇 v1.2

我和《泰拉瑞亚》相遇的时间,是我在哈尔滨实习的时候。

那时和几个同学住在一个虽然有面积90平方米,但是里面几乎什么都没有的宿舍。每天实训结束之后回到宿舍里,没网,没信号,没空调的环境可以说是想当的无聊,那时移动互联网还不够发达,没有4G,流量也少。但是幸好我们都是搞计算机的,每个人都有一台笔记本。于是局域网联机游戏成为了我们首选的娱乐行为。 但是CS啊,红警啊,魔兽什么的,都玩腻了,然后因为我开了MC服务器,带起了一小波沙盒热潮。结果在MC的热度不行了的时候,我发现了《泰拉瑞亚》,我看这是一款重战斗的沙盒之后,兴奋不已,毕竟在MC里打怪实在是没有快感,于是抱着试试游戏怎么样的态度,我自己打开了单机版。

一上来先是熟悉了一下操作和游戏的流程,因为以前有玩MC的基础,所以清晰的理解了要想致富先撸树的套路,还是比较轻松的开了局的。然后就开始探索世界,挖矿石,开宝箱,打怪物,掉装备。这几件事让我非常的快乐,毕竟谁不喜欢打怪刷装备呢?然后查了一些教程,学会了如何造房子,以及接下来大概应该打什么怪物。于是我就拎着炸弹去打「克苏鲁之脑」去了。

结果到了血池,我也不记得什么情况,反正炸了几个心脏,爆了几个装备,然后我就被一群小眼睛搞死了。不过收获颇多,一把手枪,还有一把长枪。之后虽然不知道挑战了多少次,但我至今依旧清晰的记得,我最后是用那把长枪戳爆了「克苏鲁之脑」的本体,然后掉落了一堆新的矿石。在那一瞬间,我就爱上了这款游戏。

于是我便忍不住和室友安利了起来,我试着自己开了一个局域网服务器,然后室友们通过IP连接纷纷加入了我的服务器,我记得我们一起干翻了「世界吞噬者」之后的兴奋,第一次被野生的「克苏鲁之眼」袭击时的惊慌,第一次用上「陨石套装」的快乐,以及第一次见到「肉山」的紧张。在这个小小的世界里,我和我的室友们化身成一位位冒险者,在这里探索,冒险,生存,生活。

这是一段只属于学生时代的快乐,虽然这段快乐时间只持续到我们干翻「肉山」而已……

相恋 v1.3

工作之后,一直在和朋友打英雄联盟。

我很菜,我也知道我很菜,但是当我定级赛定到「黄铜1」的时候,我还是非常的难受,然后狂刷一个通宵,就为了上到「白银5」。我本想逆天而行,然而我败了。之后感累不爱,至今也没再玩过英雄联盟了。

于是这一停不要紧,要紧的是节假日完全不知道玩啥了。结果不知怎么的,又跑去玩MC,然后玩着玩着我就又跑来Terraria了(这MC怕不是Terraria的引流器)。

因为2015年的时候我已经入坑Steam了,于是这次Terraria更新了1.3,并且还有官方中文,这对于我来说还是非常的有吸引力的,同时还支持了Steam直连,联机变得更方便了(虽然直连贼卡)。于是我就又搞了台服务器,开始了Terraria的旅程。

之前在实习时玩的进度比较靠前,所以其实解锁的东西也不多。但是这次和几个硬核玩家一起开荒,冲进度的速度真的是快了不少,很快就打到肉后了。然后我才意识到,原来我们在肉前那些让我沉迷的要素,仅仅是冰山一角,肉山后的内容对比肉山前简直翻了好几倍,新的矿石,新的怪物,新的地形,新的装备,新的事件,这些东西让我们肾上腺素激增,狂刷一个月。我们在里面盖了大楼,搭了各种防御工事,挖隔离带,建钓鱼场,就这样狂刷一个月。之后打了几乎所有的Boss和入侵事件,也算是1.3版本大毕业。然后陆续的大家就跑去玩别的了。但是这一个月的欢乐时光,真的是难得的愉快回忆了。

相知 v1.4

不玩游戏很久了。

工作越来越忙,能玩游戏的时间越来越少,我觉得玩游戏就得用大块的时间去玩,不然没有办法投入到游戏里面,玩什么都不快乐。

我一直在寻找在我忙碌的工作之余,可以偶尔进去消遣一下的游戏。那种不会因为几天没有打开,就世界大变的,不会因为和同伴的时间错开导致无事可做的,而且又不能过于没有目标和结果等等,思来想去也没有什么合适的游戏。结果突然间,Terraria更新了1.4版本,添加了一大堆要素,并且称这是最后一次更新了,于是我就再一次目光注意到了Terraria。

我脑子里一直想找这样一种游戏,探索感强,能经常的给你一些惊喜,游戏节奏只有在特定的地方很紧张,大部分时间都很悠闲,不会强求你赶进度,最好能联机,要素要多,要能经得起折腾。

结果思来想去,Terraria不是全都符合吗,于是凑了俩人,又开了个服务器玩了起来。

这次服务器我用了更高级的TShock,支持了更多的指令,而且学会了各种各样的黑科技,但是玩着玩着却感觉,虽然我觉得我现在终于把这个游戏研究的更透彻了,但是我却也越来越感受不到快乐。曾经的冒险在脑子里开始转化成了数据,曾经的惊喜现在也变成了必然。而且曾经我引以为豪的杀时间的特点,在现在越来越忙的状态下,让我感受到更加的焦虑。

我开始思考,是游戏变了,时代变了,还是我变了?虽然我更了解了你,但是我却没那么喜欢你了?

未来 v1.5

回想第一次知道这个游戏,已经过去了8年多,这8年间,我从学生变成社会人,从东北来到北京,从什么都不会的小白成长到可以自己写服务端插件。但是泰拉世界还是那个泰拉世界,向导也还是那个向导。可是我变了,我开始不能适应这个世界的冒险了。我开始追求效率,开始追求更多的刺激,开始追求更快得到结果。而那个充满幻想的冒险,似乎也永远的留在记忆之中了。

也许未来的某一天,我又会以另一个身份重新诞生到泰拉世界,看着这个世界中的花草树木与危机四伏。只希望那时,你还是那个你,而我,可以变回曾经充满好奇的那个自己。

用DS4当全平台手柄——八位堂手柄转换器体验

Cover: しずりんかわいい - 四葉はる@Pixiv

前言

最近一直在沉迷动森,因为我的NS是朋友送的,比较旧了,所以现在摇杆也是非常的漂,钓鱼钓着钓着人就自己往旁边跑,于是我就动了买一个手柄的心思。

于是就去看看有什么可以选择的吧,基本上也就是官方Pro手柄,第三方无线手柄,高仿Pro手柄里面挑了。结果看来看去总会觉得有各种的理由让我下不去手买,比如Pro手柄虽然大家都说不错,但是一个是500多的价格还是蛮贵的,再一个任天堂的做工着实让我不敢恭维,总感觉就我的手劲玩下去可能半年手柄就要报废。再看看第三方手柄,什么良值,八位堂,总觉得手柄多多少少会有点问题,比如不能唤醒啊,或者看网上有人说很容易坏,震动差等等。至于所谓的高仿Pro手柄,什么1比1手柄,我愣是没找到买的渠道。

结果正在一筹莫展的时候,在八位堂的店里看到了一个「无线手柄转换器」,因为以前听说过类似的东西,就点进去看了看。这一看,好家伙,这东西居然可以把一个平台的手柄直接转换成另一个平台的,具体看了看,DS4手柄转接到NS上,除了不能唤醒以外,其他的据说和无线JoyCon一样,于是我看着桌子上PS4旁边的两把DS4手柄露出了邪恶的笑容……

不过也不能说买就买,首先我还是去网上看了看评价,结果看网上有人说延迟很高,没办法愉快玩耍,也有说震动太厉害,鲈鱼震成皇带鱼的,不过也有人说体验非常的完美,所以最后我思来想去还是准备先买个试试看。

开箱

明明买的时候找了一家发货地是北京的店,就想可以早点收到,结果不知道快递经历了什么,三天才到我的手上……于是赶紧迫不及待的打开了这个小盒子。

明明八位堂是个中国公司,不过这个小盒子上倒是一个中国字都没有,颇有一副山寨货的气质。

打开盒子,可以看到我们的转换器本体,一个马里奥里砖块风格的,看起来像是一个U盘的小玩意。

这个东西大小和U盘也是非常的接近,拿在手里面还是很小的,上面这个盖子取下来之后并没有收纳的方式,所以估计这个盖子哪天应该也会和很多U盘盖子一样神秘失踪……

我就知道你们肯定想要壁纸的原图 https://yande.re/post/show/605035

使用体验

NS体验

都说会有严重的延迟,我赶紧按照教程接上了NS,打开了《太鼓达人》。

随便选了首歌,良!可!Miss!Miss!Miss!可!Miss!Miss!……

我丢这个延迟根本没办法玩啊!

然后我寻思对比一下原装JoyCon的体验吧,接上JoyCon,随便选首歌。

良!可!Miss!Miss!Miss!可!Miss!Miss!……

emmmm行吧,老任的锅,无线打太鼓达人看来就是不太行。

那我打开「动森」试试看吧,结果转换器在动森里发挥稳定,终于不用忍受漂移的摇杆了。

PC体验

既然这样那我再试试接PC好了,虽然DS4手柄也可以通过驱动转换模拟成Xbox手柄来玩PC游戏,但是总有驱动不好用的时候,而转接器接上去之后直接就是识原生别成了Xbox手柄了,各种莫名奇妙的兼容问题应该都不会遇到了。

试了试前几天XGP里下载的《如龙0》吧,结果体验良好,并没有什么延迟或者操作不跟手的体验。

然后我突然想到,Steam里还躺着一个《DJMAX RESPECT V》呢,赶紧打开试试。

结果体验还是惊到我了,几乎和我在PS4平台玩的体验一模一样,轻松打出100%判定,打了几首歌也基本就是自己的正常水准。(所以侧面证明延迟高就是任天堂的锅)

总结

总的来说我的初始目的可以实现,而且还给我带来了一定的惊喜,如果你手里有DS4手柄,或者和我一样索尼系玩得多,更习惯于DS4的按键习惯,想用DS4手柄接其他主机的,那我还是比较推荐购买的,而且99元的价格也比较亲民,至少比再买一款同级别的手柄便宜得多了。

不过还是有几个问题在这里写一下,防止大家踩坑。

  • 一个转换器只能连接一个手柄
  • 转换器每次断电后都需要重新配对
  • NS平台转换器无法唤醒主机