Alfred2 有道翻译 Workflow 不可用的解决方法

一直在使用的 Alfred2 有道翻译的 Workflow 今天突然就不能使用了,刚开始以为是网络的问题,多次确认之后排除了网络的原因。想着可能是有道翻译的 API 更新了,使用以前的 API 调用会失败,然后就想着看看这个 Workflow 中使用的是哪个 API,那么怎么查看这个 Workflow 究竟用的是哪个 API 呢?

我们一步步来吧,首先打开 Alfred2 的设置页面,选中 Workflows Tab 页:

Alfred2 Settings -> Workflows Tab然后双击标题为 yd 的 Script Filter,或者右键选中标题为 yd 的 Script Filter,然后选择 Configure 菜单项,进入 yd Script Filter 的配置界面:

Alfred2 Youdao Workflow Configure

然后我们会看到一些命令啥的,不要管它咯,直接点击右下方那个 Open workflow folder 按钮,打开这个有道翻译的 Workflow 资源存放目录,如下:

Alfred2 Youdao Workflow Folder

从上一个设置页面中,我们可以看到 translate.php 文件应该是真正干活的脚本,所以我们打开目录中的 translate.php 脚本文件,然后我们就可以看到这个脚本是如何通过访问有道的开放 API 来完成翻译的工作的。

translate.php

用红色标注出来的两个参数就是这个 Workflow 不再工作的原因,可能是因为有道翻译的这个 Workflow 使用的人太多,而大家都是直接从 alfredworkflow 上下载的,Workflow 中的 API Key 就是这个 Workflow 的作者当时自行申请的一个 Key,而有道对于每个 API Key 有一个每日访问次数限制为 1000,所以很有可能就是因为现在使用 keyfrom=SeekBetterMe&key=164530784 这两个参数的人太多导致 API 访问次数超限了,所以有道翻译已经不再返回查询结果了。

那么既然找到问题了,我们只需要自己申请一个新的给自己用的 API Key 就好了。找到有道翻译 API 的首页

有道翻译 API 首页

点击我是开发者,进入调用数据接口页面,填写正确的网站信息,马上就可以获取一个专属于自己的 API Key,然后将其替换到 translate.php 文件中就可以了。

申请有道翻译 API Key

然后保存 translate.php 文件,重新呼出 Alfred2 有道翻译的 Workflow 就可以了。

读《卡拉马佐夫兄弟》

「一粒麦子不落在地里死了,仍旧只是一粒;若是落在地里死了,就会结出许多粒麦子来。」
—— 佐西马长老

已经忘了是何时听说过陀思妥耶夫斯基这个名字了,初次听闻这个名字只是觉得好长好难记,后来一而再地从不同的人口中听闻陀思妥耶夫斯基此人,并且多次听到他人对其的赞赏,便买了《卡拉马佐夫兄弟》来读一读。

俄罗斯人名都很长很复杂,例如书中的主人公为一家父子四人,父亲——费多尔·巴夫洛维奇·卡拉马佐夫,长子——德米特里·费多罗维奇·卡拉马佐夫,次子——伊凡·费多罗维奇·卡拉马佐夫,幼子——阿历克赛·费多罗维奇·卡拉马佐夫,这已经让我很头疼了,在读前 100 来页的时候,出场人物已经很多,加上各种更加长的女性角色的名字,而且俄罗斯人因为名字长貌似都有简短的昵称,书中也是全称和昵称穿插着出现,真心有的时候看了半天都不知道到底在说谁,有的时候就真的翻回去看这到底是谁的名字来着。

全书读起来不是很轻松,也许是翻译的年代稍微远一些,行文造句上可能跟现在我们平时的口语有些不同,再加上书中有大段大段的关于宗教和哲学的论述,读来确实有些吃力。

通篇读下来,幼子阿辽沙如天使般的爱人们,宽容这世间一切的罪,次子伊凡背负中沉重的精神负担而不得解脱,在新科技和社会主义等新生事物的冲击下怀着对传统社会宗教价值观的深深的怀疑,长子生活糜烂至极,却又偶尔率真诚实,内里并非一个十分可恶之人。而他们那可怜的老父亲,如小丑般活着,如笑话般死去,并给整个家庭带来了沉重的罪孽。

整部小说虽说情节设定非常棒,但是我认为最精彩的还是伊凡关于宗教的论述,伊凡谈到了一个假想,假想耶稣再次复活了,回到了世俗社会中来,在宗教大法官烧死上百个异教徒的广场上就这么悄悄地复活了,他回道了世俗社会中。

但是他却被宗教大法官给逮捕了,在狱中宗教大法官对复活的他说道:
「『是你么?真的是你么?』他没有得到回答,便又急速地接着说,『别出声,别回答吧。你又能说出什么来呢?我完全知道你要说的话。你也没有权利在你以前说过的话之外再添加什么,你为什么到这里来妨碍我们?你确实是来妨碍我们的,你自己也知道。但你知道不知道明天将会发生什么?我不知道你是谁,也不是到你是不是真的仅仅像他,但是到了明天,我将加以裁判,把你当做一个最凶恶的邪教徒放在火堆上烧死,而今天吻你脚的那些人,明天就会在我一挥手之下,争先恐后跑到你的火堆前面添柴,这个你知道吗?是的,你也许知道这个。』他在深刻的沉思中加了这句话,目不转睛地紧盯着他的囚犯。」

伊凡说,这就是罗马天主教最主要的特点:「既然你已经把一切都教给了教皇,那就一切都已经在教皇的手里,你现在根本不必来,至少目前你不该来碍事。」

宗教大法官认为是他们给人们带来了幸福,而耶稣在离开他们的时候已经把这个权利交给了他们,如今也不可能再从他们手里夺回去。

「他们恰恰认为他和他的人们的功绩,就在于他们终于压制了自由,而且他们这样做,是为了使人们幸福。『因为只是到了现在(他自然指的是有宗教裁判制的时代),才破天荒第一次可以想到人们的幸福。人造出来就是叛逆者,难道叛逆者能有幸福么?已经有人警告你了,』他对他说,『你没有少受到警告和指示,但是你不肯听这警告,你不承认那条可以使人们得到幸福的唯一的道路,幸而你离开的时候,把这事情交付给了我们。你答应,你用话语证实,你给予我们系绳和解绳的权利,你自然已经不能再想从我们手里夺取这个权利。你为什么跑来妨碍我们啊?』」

接下来关于自由和面包的论述也是如此精彩。

「哎,他们没有我们是永远也不能喂饱自己的!在他们还有自由的时候,任何的科学都不会给予他们面包,结果是他们一定会把他们的自由送到我们的脚下,对我们说:『你们尽管奴役我们吧,只要给我们食物吃就行。』他们终于自己会明白,自由和充分饱餐地上的面包,这两者是不可兼得的,因为他们永远也不善于在自己之间好好地进行分配!他们也将深信,他们永远不能得到自由,因为他们软弱,渺小,没有道德,他们是叛逆成性的。你答应给他们天上的面包,但是我再重复一句,在软弱而永远败德不义的人类的眼里,它还能和地上的面包相比么?就算是为了天上的面包,有几千人以至几万人跟着你走,那么几百万以至几万万没有力量为了天上的面包而放弃地上的面包的人,又该怎样呢?是不是只有几万伟大而强有力的人是你所珍重的,而那其余的几百万人,那多得像海边沙子似的芸芸众生,那些虽软弱但却爱你的人,就只能充当伟大和强有力的人们脚下的泥土呢?」

全篇中诸如以上精彩的论述还有不少,这也是我首次在阅读小说的过程中不断地被震到的一本书。书中对于人物性格特点的刻画更是细致入微,例如对拉基金的那种小人行径和可恶嘴脸就表现得淋漓尽致,实为一部好书,虽说读起来有些累人,也值了。

2015 年 12 月读书笔记

《失乐园》

真心好看的一本小说,毫不避讳如外科解剖般细致的大段落性描写,恰如其分又极端写实的心理活动的呈现,让久木和凛子直接在你的眼前活了。

你可以看到他俩在酒店里,在出租屋里,在度假别墅里做爱,你能感受到久木与妻子在餐桌上的沉默和尴尬,你能感受到凛子和丈夫在家中的冷暴力。

二人在一次次突破世俗伦理的束缚之后,最终成功的走到了一起。但是两人却选择了在这幸福的最高点赴死,不是向那冰冷坚硬的伦常示威,而是向那琐碎的生活和必然衰减的热情抗议。两人深知结合之后,随着时间的推移,家务琐事的牵绊,二人之间的这种热情和默契会日渐磨灭,正如他们与自己的原配之间那般,也无奈找不到破解之道,最终选择在激情燃烧得最为旺盛的刹那走向毁灭,双双赤裸狠狠地抱在一起,满足地离开了这个让他们失望透顶的世界。

《把时间当作朋友》

得知李笑来这个人已经有些年头了,之前只是知晓他是新东方的名师,喜欢写博客,然后就没有了,大概我还一直有订阅他的博客。

再次关注到他,就是因为成功的比特币投资者这个巨大的光环吧。我就是这么俗,哈哈。关注了他的微信公众号之后呢,想着有必要读读这本屡次出现在他文章里头的这本听起来很正能量和主旋律的书(我就是这么装逼,书还没读呢,就先给人定性了),读了之后,有点相见恨晚。

书中反复讲了很多很棒的道理,也非常刻薄地指出了我们绝大多数人的致命弱点,打脸真的好疼,至少我很疼。

疼完了之后呢,我开始尝试去做一些事情了,我继续坚持每天的晨跑(当然北京的这个天气,想必大家也都知道,雾霾天是个很操蛋而且高发的天气,所以会造成一些小间断),然后开始写每天的流水账时间日志。

效果好不好,目前还不能说,我想先坚持个一年再回来看。不论做什么计划,关键在于实践和坚持嘛,书里头就是这么说的,所以,咱们走着瞧。

《甘南纪事》

这是我读的杨显惠先生的第二本书,第一本是《夹边沟纪事》,读完了非常震惊和感动,深为杨先生这种非虚构类文学作品的风格吸引。在叙实之余不落入一种纯文本性的记录和纯对话式的段落,而是适当地通过一些虚拟想象还原每个故事的主人公和出场人物的心理状态和活动变化,又不过分渲染这些私人的揣度,这是一种恰到好处的还原和超越。

此次读《甘南纪事》显然较之前读《夹边沟纪事》要来得轻松许多,心情也没有那么沉重。书中不是穿插一些甘南地区的水美山美,朴实多彩的甘南藏人的风土人情,都让自己有点沉醉其中了,有机会定要去扎尕那探寻一番在书中多次出现的白石头山。

书中多次指明了村民调解委员会在藏人生活中的重要性,特别是在村民公共事务中扮演的重要角色,其中关于僧侣、老人,甚至以前的头人等等在委员会中处理相关事务时所遵循的社会组织原则以及所体现出来的智慧,甚至可以说是迷人的。而这些流传下来的传统和智慧,与现今的社会组织结构难免会产生一些冲突,例如公安局这个角色在藏民们心中和生活中扮演的是一个什么角色,以及藏民们是如何对待各种新型的事物,例如保暖内衣和防风服等等,书中那些淳朴可爱的藏民们会用他们每天的生活给你最真实的答案。

《你的灯亮着吗?》

这本书我第一次看到的是一个在网上流传的 PDF 版本,当时自己拿到打印店去打印了全书,自己也读了一部分,应该是把电梯的那个案例的部分给读完了,也许后面的部分没有继续读下去,也许读完了之后完全忘光光了,因为这次重新再读一回,发现自己隐约能记起来的也就是电梯的案例。

关于这个案例,在我自己身上还有个小事情蛮有趣的。08 年 10 月份前后,腾讯来我们学校校招,然后笔试通过之后,我就去参加面试了,面试的时候,面试官是个年轻帅气的小伙子,然后他先让我尝试着解决一个算法编程问题,我尝试了十分钟左右,没有什么思路,然后面试官考虑到时间有限(当时计划我是下午4点半开始面试,实际上我面试的时间已经6点多了,实际上我已经饿了),换了一个开放式的题目就是这个电梯的案例。我想了大概几秒钟吧,我觉得我还是应该坦白告诉面试官这本书我读过,我要是直接把书里头的内容给搬出来,这个就是抄袭,我也不能确定我能怎么样把我看过这本书的事实掩盖住,又不露痕迹地展现我自己独立思考的能力自己和看问题的视角的独特性。最终,我很快地就告诉我的面试官,我说这本书我看过,希望能换一个题目,面试官笑了笑,然后给我换了另一个开放式的题目。这回的题目是一个智力题,然后我就被我的智商打败了,最终我就这么灰头土脸地结束了我的腾讯校招面试了。

所以这次重新读这本书的过程中,其实我有多次已经读不下去了,但是我还是不断地告诉自己必须读下去,最终读完了。我想说的是,本书的趣味性并不是那么高,有几个还蛮有趣的案例分析但是不多,文中也有不少比较别致的观点,但是说真的读起来确实蛮无趣的。也许以后得某天再读会有新的感受和收获吧。

《21 世纪资本论(精华本)》

原本以为这是全本,后来读了总感觉特别不对,很多的结论和数据扑面而来,完全消化不了,主要阐述的观点貌似是这样的「21 世纪里头,继承遗产的重要性将会更为突出,社会将会再次形成明显的阶级分层,而且财富将会更加集中化」,大概就是这样吧。不建议读这个所谓的精华本,我是在「多看阅读」上面读的,完全不建议,想读的话还是找全本来读吧。

Unity3D 中粒子特效不在摄像机渲染范围内 Play 之后导致特效延时播放的解决方法

从项目启动之初,我们就引进了 PoolManager 插件来做诸多对象的缓存,防止游戏中对象的频繁 Instantiate 和 Destroy,造成不必要的性能问题。PoolManager 是一个非常成熟的插件,也提供了很多非常友好的接口以供开发者使用,其中也有针对 ParticleSystem 对象的 Spawn/Despawn 机制,所以我们就很自然的使用了 PoolManager 插件来管理整个游戏中的所有特效对象。

particle_system_spawn_pool_management

对于特效对象,我们游戏中的管理逻辑大体如下:

也就是说我们的粒子特效对象是重用的,在每次重新被 Spawn 出来的时候都会重新调用一次 Play 方法来重新播放这个粒子特效,这个方案看上去很正常有木有?确实没有啥硬伤对吧。

但是在我们实际的测试过程中,我们很早就发现了一个很奇怪的问题,就是偶尔场景中会出现一些不应该出现的技能特效。例如,在场景中偶遇到一个小怪,小怪在攻击的过程中玩家控制主角快速跑开了(主摄像机一直跟随主角),然后灯小怪的攻击结束之后,主角再次跑回到小怪面前进行战斗,然后此时偶尔就会看到小怪并没有在进行任何攻击,只是在战斗待机或者移动,但是屏幕上会凭空播放一些这个小怪的攻击技能对应的特效(其实找到这个问题重现的方法,也就是这个 Bug 的规律也是费尽心思啊,想想看这货都存在快 TMD 一年了,直到现在我才真正地捉到它)。

既然已经找到了重现的方法,也清楚了 Bug 出现的规律,也就是当小怪释放技能时(技能动作带有技能粒子特效),由于主角的移动导致摄像机跟着主角在场景中移动,最终小怪释放的技能粒子特效并不在摄像机的 Culling 区域中,而此时我们通过了 PoolManager 插件 Spawn 出来了一个新的粒子特效,然后调用了 ParticleSystem 的 Play 方法来播放粒子特效。我们预想的是该粒子特效在我们调用 Play 之后就会播放,然后就交给 PoolManager 自行管理就好了(PoolManager 插件会监听粒子是否已经完全发射/播放结束,如果是,就会将这个粒子对象 Despawn 掉,放回到 PoolManager 中对应的 SpawnPool 中以备后续再次使用)。

问题就出在这里,PoolManager 中监听粒子对象是否完全发射/播放结束的方法是通过轮询 ParticleSystem 的 IsAlive 方法来进行判断的,代码如下:

// ParticleSystem (Shuriken) Version...
private IEnumerator ListenForEmitDespawn(ParticleSystem emitter)
{
    // Wait for the delay time to complete
    // Waiting the extra frame seems to be more stable and means at least one 
    //  frame will always pass
    yield return new WaitForSeconds(emitter.startDelay + 0.25f);

    // Do nothing until all particles die or the safecount hits a max value
    float safetimer = 0;   // Just in case! See Spawn() for more info
    while (emitter.IsAlive(true))
    {
        if (!PoolManagerUtils.activeInHierarchy(emitter.gameObject))
        {
            emitter.Clear(true);
            yield break;  // Do nothing, already despawned. Quit.
        }

        safetimer += Time.deltaTime;
        if (safetimer > this.maxParticleDespawnTime)
            Debug.LogWarning
            (
                string.Format
                (
                    "SpawnPool {0}: " +
                        "Timed out while listening for all particles to die. " +
                        "Waited for {1}sec.",
                    this.poolName,
                    this.maxParticleDespawnTime
                )
            );

        yield return null;
    }

    // Turn off emit before despawning
    //emitter.Clear(true);
    this.Despawn(emitter.transform);
}

这个 IsAlive 判断就是问题的关键,经过测试我们发现了一个 Unity3D 的机制,当我们首次将 PartileSystem 对象 Instantiate 出来时,不论其是否在摄像机的 Culling 区域内,调用 ParticleSystem 的 Play 方法或者将其 playOnAwake 设置为 True 都会播放该 ParticleSystem 对象。而在其首次 Instantiate 之后,再次调用 Play 方法来播放该粒子特效时,如果粒子不在任何一个 Camera 的Culling 区域内(包括 Culling Layer Mask 是否相符以及是否在 Camera 的可视范围内),实际上粒子并不会发射,直到其进入到某个 Camera 的 Culling 区域内才会触发粒子的发射(实际在 Unity Editor 中测试的时候,最终发现粒子进入 Scene Window 的可视区域和 Game Window 的可视区域都会触发粒子的发射,实际上 Scene Window 的 Preview 就是有一个我们不可见的 Camera 在进行渲染)。此处需要说明的是以下两点:

  1. Unity 版本为 4.6.9f1;
  2. 粒子特效的 Renderer Mode 是 Billboard。

至此,我们终于完全弄明白了为什么会出现某些技能的粒子特效无端地在场景里播放了,原因就是因为该特效在 Instantiate 出来调用过一次 Play 方法之后(由于我们所有的特效默认 playOnAwake 属性都是 true,所以我们通过 PoolManager 加载的粒子特效的 Prefab 实际上在首次 Spawn 之前都已经自动调用过一次 Play 方法了),再次调用 Play 方法来播放该粒子特效的时候,该粒子特效所处的坐标位置并不在主摄像机的 Culling 区域内,所以根本就不会触发粒子的发射而是在等候下次进入摄像机的 Culling 区域时再触发。在我们游戏中的最终表现就是在屏幕边缘与小怪发生战斗,当小怪释放技能的时候快速往小怪的反方向移动,等着小怪来追击,我们再折返跑回刚刚与小怪发生战斗的地方,这个时候我们就能看到几个小怪的技能特效凭空在场景中自动播放了,真乃煞是奇妙啊。

好吧,说了这么多,那么我们既然知道是这个原因了,那么怎么解决呢?我们看到了  ListenForEmitDespawn 方法中有一个针对粒子特效在 Spawn 出来之后时间的检测,其检测粒子对象自 Spawn 以来的时长是否超出 SpawnPool 中定义的最大 Despawn 时长,跟实际的粒子对象并无直接关系,而且即便该粒子对象 Spawn 出来的时长已经超出最大的 Despawn 时限,也只是会简单地输出了一个警告的 Log 信息。

那么我们自己的处理逻辑应该是怎样的呢?我的处理方法是在粒子对象被 Spawn 出来之后,除了通过其自身的 IsAlive 方法来检测该粒子对象是否还是激活状态,在其 Spawn 出来的同时就启动一个 Coroutine 用来检测其自 Spawn 出来的时长是否超出 ParticleSystem 的 duration 设置值,如果已超出,那么就将其 Clear 并且 Stop,然后再将其 Despawn 掉。依次修改后的 ListenForEmitDespawn 方法如下:

// ParticleSystem (Shuriken) Version...
private IEnumerator ListenForEmitDespawn(ParticleSystem emitter)
{
    // Wait for the delay time to complete
    // Waiting the extra frame seems to be more stable and means at least one 
    //  frame will always pass
    yield return new WaitForSeconds(emitter.startDelay + 0.25f);

    // Do nothing until all particles die or the safecount hits a max value
    float safetimer = 0;   // Just in case! See Spawn() for more info
    while (emitter.IsAlive(true))
    {
        if (!PoolManagerUtils.activeInHierarchy(emitter.gameObject))
        {
            emitter.Clear(true);
            yield break;  // Do nothing, already despawned. Quit.
        }

        safetimer += Time.deltaTime;
        if (safetimer > emitter.duration) {
	        Debug.LogWarning
	        (
	            string.Format
	            (
	                "SpawnPool {0}: " +
	                    "Timed out while listening for all particles to die. " +
	                    "Waited for {1}sec.",
	                this.poolName,
	                emitter.duration
	            )
	        );
			break;
		}
            
        yield return null;
    }

    // Turn off emit before despawning
	emitter.Stop(true);
    emitter.Clear(true);
    this.Despawn(emitter.transform);
}

如何搞定 UnityEngine.UI.dll is in timestamps but is not known in guidmapper… 错误

在使用 Unity 开发的过程中,不知道什么情况下就会碰到这么两个错误(根据平台和使用的 Unity 版本不同,路径可能不一样,我这边列出的也不是完整的路径):

UnityExtensions/Unity/GUISystem/4.6.9/UnityEngine.UI.dll is in timestamps but is not known in guidmapper…

UnityExtensions/Unity/GUISystem/4.6.9/Editor/UnityEditor.UI.dll is in timestamps but is not known in guidmapper…

有的人建议是直接把我们的 Project 目录下的 Library 目录直接删除掉,不过这样一来,重新再次打开 Unity Editor 的时候,整个工程的资源都需要重新导入,而且通常我们还是在移动平台模式下进行开发,也就是等它把资源导入进来之后,我们还需要做一次 Switch Platform 的操作,真的好慢好慢好慢啊(也许可以通过 Asset Cache Server 来提速,但是我没有用过,所以不敢乱说)。

那么我们有什么办法呢,这里介绍一个比较好的方法,总共分三步:

  1. 进入出错的两个 dll 文件所在目录中,将出错的两个 dll 文件重命名为任意文件名,例如:UnityEngine.UI.dll.backup 和 UnityEditor.UI.dll.backup;
  2. 重启 Unity Editor,等整个工程加载结束之后,我们会看到很多红色的错误日志输出,甭理它就好了,关闭 Unity Editor;
  3. 回到那两个 dll 文件所在的目录,将刚刚重命名的两个 dll 文件分别修改回来,UnityEngine.UI.dll 和 UnityEditor.UI.dll,然后再次启动 Unity Editor,接下来就是见证奇迹的时刻了。

好了,就是这么简单。