分类
折腾 码农

对mpvue进行前端测试

采用Vue.js的测试方法,为mpvue添加测试。

配置

  1. 打开package.json,添加如下内容(注意自行在必要的地方添加逗号):
    "scripts"中添加"test": "jest"
    "dependencies"中添加"vue": "^2.4.4"
    "devDependencies"中添加

    “@vue/test-utils”: “^1.0.0-beta.13”
    “jest”: “^21.2.1”
    “vue-jest”: “^2.6.0”
    “vue-template-compiler”: “^2.4.4”

添加(与scripts同级)

        "jest": {
            "moduleFileExtensions": [
                "js",
                "json",
                "vue"
            ],
            "transform": {
              "^.+\\.js$": "<rootDir>/node_modules/babel-jest",
              ".*\\.(vue)$": "<rootDir>/node_modules/vue-jest"
            },
            "moduleNameMapper": {
              "^@/(.*)$": "<rootDir>/src/$1"
            }
          }

2. 在命令行中进入对应目录,输入npm install

查看配置效果

  1. 创建test文件夹(与package.json同级目录),新建test.js文件,输入以下内容:
        describe('Our test file', () => {
    
              it('should be working now', () => {
                expect('a').toBe('a')
              })
    
        })
    
  2. 在命令行中输入npm test
  3. 我们应该会看到如下内容:

编写真正的测试文件

  1. 假设我们想测试的组件为components文件夹下的card(mpvue模板生成的组件)
  2. 不用对card.vue文件做任何改动(主要是不需要添加name):
  3. test.js内容修改为:
        import { mount } from '@vue/test-utils'
        import card from '../src/components/card'
    
        describe('card', () => {
            const wrapper = mount(card)
    
            it('<p> tag should have class: card', () => {
                let p =  wrapper.find('p')
                expect(p.classes()).toContain('card')
            })
    
        })
    
  4. 在命令行中输入npm test
  5. 我们应该会看到如下内容:

注意事项、参考资料

  1. 文件命名:xxx.vue对应的测试文件名为xxx.spec.js
  2. 这里使用的是jest,而不是mocha
  3. 参考资料(包括更多语法):https://vue-test-utils.vuejs.org/zh/guides/#%E8%B5%B7%E6%AD%A5
分类
程序和算法

搜索引擎中的Page Rank算法

PageRank算法

PageRank算法总的来说就是预先给每个网页一个PR值(下面用PR值指代PageRank值),由于PR值物理意义上为一个网页被访问概率,所以一般是\(\frac{1}{N}\),其中N为网页总数。另外,一般情况下,所有网页的PR值的总和为1。如果不为1的话也不是不行,最后算出来的不同网页之间PR值的大小关系仍然是正确的,只是不能直接地反映概率了。

所以PageRank算法实际上就是预先给定PR值后,通过每个网页之间的链接关系不断迭代,直至达到平稳分布为止。

各个网页的PR值之间的关系一般情况下表示为如下的式子:

\(PR(p_i)=α\sum_{p_j∈M_{p_i}}\frac{PR(p_j)}{L(p_j)}+\frac{(1-α)}{N}\)

其中\(M_{p_i}\)是所有对\(p_i\)网页有出链的网页集合;\(L(p_j)\)是网页的出链数目;\(N\)是网页总数;\(α\)是阻尼系数,即用户离开当前网页重新输入网址访问的概率,一般取0.85。

根据这一关系不断迭代,当算法收敛的时候,得到的PR值即使每个网页的PR排序值。


算法实现

digraph类

由于一个搜索引擎中的网页数不胜数,使用一个矩阵存储各个网页之间的链接关系是不可能的,这里采用有向图类来优化稀疏矩阵的存储。

  • 类的方法一览表
名字 参数 说明
init_nodes self, nodes 初始化向图图的节点
init_edges self, edges 初始化向图图的边
add_edge self, edge 增加向图图中的边
neighbors self, node 返回参数节点的所有后继节点
incidents self, node 返回参数节点的所有前驱节点
  • digraph类源代码
class digraph:
 def init_nodes(self, nodes):
  self.nodes = nodes

 def init_edges(self, edges):
  self.edges = edges

 def add_edge(self, edge):
  self.edges.append(edge)

 def neighbors(self, node):
  neighbors = []
  for edge in self.edges:
   if edge[0] == node:
    neighbors.append(edge[1])
  return neighbors

 def incidents(self, node):
  incidents = []
  for edge in self.edges:
   if edge[1] == node:
    incidents.append(edge[0])
  return incidents

PRIterator类

PRIterator类是用来迭代计算PR值的类,由一个有向图和一个阻尼系数构造,阻尼系数即公式中的α。默认的最大迭代次数是100,确定迭代是否结束,即PR值是否收敛的参数为0.00001,即ϵ。

只有一个方法——page_rank方法,来迭代计算PR值直至收敛。同时如果一个节点没有任何的后继节点,那么相当于所有的节点都是它的后继节点,即一个网页没有出链的情况下,下一秒访问任何网页的概率都是相等的。

  • PRIterator类源代码
class PRIterator:
 __doc__ = '''计算一张图中的PR值'''

 def __init__(self, dg, damping_factor):
  self.damping_factor = damping_factor  # 阻尼系数,即α
  self.max_iterations = 100             # 最大迭代次数
  self.min_delta = 0.00001              # 确定迭代是否结束的参数,即ϵ
  self.graph = dg

 def page_rank(self):
  #  先将图中没有出链的节点改为对所有节点都有出链
  for node in self.graph.nodes:
   if len(self.graph.neighbors(node)) == 0:
    for node2 in self.graph.nodes:
     self.graph.add_edge((node, node2))

  nodes = self.graph.nodes
  graph_size = len(nodes)

  if graph_size == 0:
   return {}
  page_rank = dict.fromkeys(nodes, 1.0 / graph_size)  # 给每个节点赋予初始的PR值
  damping_value = (1.0 - self.damping_factor) / graph_size  # 公式中的(1−α)/N部分

  flag = False
  for i in range(self.max_iterations):
   change = 0
   for node in nodes:
    rank = 0
    for incident_page in self.graph.incidents(node):  # 遍历所有"入射"的页面
     rank += self.damping_factor * (page_rank[incident_page] / len(self.graph.neighbors(incident_page)))
    rank += damping_value
    change += abs(page_rank[node] - rank)  # 绝对值
    page_rank[node] = rank

   print("This is NO.%s iteration" % (i + 1))

   if change < self.min_delta:
    flag = True
    break
  if flag:
   print("finished in %s iterations!" % node)
  else:
   print("finished out of 100 iterations!")
  return page_rank

主函数

主函数的作用就是读取网页的链接数据,初始化有向图,迭代计算PR值直至收敛,最后输出计算结果。

测试的数据为维基百科网站上所有网页的链接数据,由于数据共有103689条,这里不再给出详细数据,文末附有数据集及源码,可执行文件下载链接。这里给出一部分样例的截图如下。数据格式为:网页ID——链接到的网页ID。

在主程序中,需要输入测试数据的路径和阻尼系数。运行结果如下图。

  • 主程序源代码
if __name__ == '__main__':
 # python NewPageRankDemo.py

 # 输入数据和输出结果所在的文件夹位置
 directory = input('输入数据和输出结果所在的文件夹位置:\n示例输入:C:\\Users\\37618\\Desktop\\PageRank\\\n')
 damping_factor = input('输入阻尼系数α(一般取0.85):\n')
 damping_factor = float(damping_factor)

 # 储存训练样本数据
 f = open(directory + 'WikiData.txt')

 nodes = []
 edges = []

 for v in f:
  tmp = v.split("\t")
  tmp[1] = tmp[1].split("\n")[0]
  if nodes.count(tmp[0]) == 0:
   nodes.append(tmp[0])
  if nodes.count(tmp[1]) == 0:
   nodes.append(tmp[1])
  edges.append((tmp[0], tmp[1]))

 # 输出预测结果
 import sys

 output = sys.stdout
 outputfile = open(directory + 'result(' +str(damping_factor)+ ').txt', 'w')
 sys.stdout = outputfile

 dg = digraph()

 dg.init_nodes(nodes)

 dg.init_edges(edges)

 pr = PRIterator(dg, damping_factor)
 page_ranks = pr.page_rank()

 print("The final page rank is\n")
 for page_rank in page_ranks:
  print(page_rank, ' ', page_ranks.get(page_rank))

 outputfile.close()
 sys.stdout = output

示例输出如下图。

可以看到,程序在31次迭代后在ID为8274的网页处收敛,并输出了所有网页的PR值。

[mdx_warning title=”特别注意”]10万条数据的迭代非常占内存,请配置垃圾的笔记本们慎重尝试![/mdx_warning]


源代码链接

源代码链接,附带测试数据集及测试输出,源代码及说明,可执行文件

分类
作品

随手拍(八)

今天还是随手拍~感觉乌云也可以很好看呢(๑•̀ㅂ•́)و✧

[mdx_fold title=”拍摄参数”]
ISO:50
快门:1/125秒
光圈:F/2.0
焦距:等效14mm
[/mdx_fold]

[mdx_fold title=”随手拍系列”]
第一期
第二期
第三期
第四期
第五期
第六期
第七期
href=”https://blog.potatofield.cn/%e9%9a%8f%e6%89%8b%e6%8b%8d%ef%bc%88%e5%85%ab%ef%bc%89/”>第八期
[/mdx_fold]

分类
作品

随手拍(七)

昨天是累到腿软的一天╮(╯▽╰)╭没有更新也是情有可原的对不对~

今天就来一张随手拍吧(๑•̀ㅂ•́)و✧昨天在海洋世界的收获ヽ(✿゚▽゚)ノ

[mdx_fold title=”拍摄参数”]
ISO:6400
快门:1/320秒
光圈:F/3.5
焦距:等效24mm
[/mdx_fold]

[mdx_fold title=”随手拍系列”]
第一期
第二期
第三期
第四期
第五期
第六期
第七期
href=”https://blog.potatofield.cn/%e9%9a%8f%e6%89%8b%e6%8b%8d%ef%bc%88%e5%85%ab%ef%bc%89/”>第八期
[/mdx_fold]

分类
摄影日志

五万次快门

今天整理电脑上的照片,偶然发现自己已经拍过超过五万张作品了。准确地说,是50358张。

五万张作品,其实并不多。严格来说,这个数字算上了我在很小时候拿着一台佳能的入门级Cybershot拍着玩以及各种各样用手机拍出来的游客照。里面真正用心拍的严肃的摄影作品,算起来大概一万到两万张。

开始拍照是很久以前的事情了,在我几乎还不能记事起,就总是用家里的胶片傻瓜相机到处乱咔擦。那台机器到底是奥林巴斯还是柯达,我已经记不清楚了;只记得当时拍照的过程很简单,闭起一只眼往取景器里面看,然后按快门就完事了。这个时候,拍照对我来说只是一种记录生活的方式。照片好不好看?无所谓,能看出来照片拍得是谁以及在哪里拍的就够了。

2005年,我有了一台数码相机。是叔父送的,佳能的Cybershot A510。那是一台精巧的银白色机器,有很多的自动模式,还有一伸一缩能够变焦的镜头。对我来说,这算是个有意思的新玩具。这台相机让我有了更多拍照的动力,但是对我来说,拍照仍然只是一件纯粹“记录”性质的工作——就像写流水账日记一样。

开始对自己的作品产生审美上的诉求,是从2008年拿到大法家的DSC-H50开始。那是一台长焦机,不可换镜头,但是有着单反一般看上去比较“炫酷”的外观。一方面有些幼稚可笑,另一方面有些狂妄自大,此时的我竟常以“摄影师”自居。当然,彼时的幼稚和狂妄未尝不是好事——总以“摄影师”自居的我,总得拿出些看得过去的照片给同学看,也正是因此我对照片有了美观方面的追求。从那时起,我不再只用照片记流水账,而真正开始琢磨怎么样让摄影作品拍得更好看。

这台DSC-H50我用了很久,从2008年一直用到2017年初。我的五万张照片里,这台相机贡献了大半。但是直到此时,我还是不合格的——一直只用,也只会用自动模式,从来不去调整参数。九年的时间里,我只训练了构图的水平——尽管构图水平的提升也极其有限。这段时间的我,只能算是“水平并不高的业余摄影爱好者”。

真正开始严肃认真地练习摄影,是从2017年2月开始。那个学期我选了一门摄影课,也买了一台单反相机,尼康D7200。我开始认真地研究各种拍摄参数对摄影的影响,开始更加认真地构图,开始慢慢学习后期技巧。我要求自己只用手动模式,要求自己每次出去拍摄都带着全套镜头和滤镜。从那时起,我的作品水平才慢慢有了真真切切的提高,我才敢说自己玩的是“摄影”而不是“拍照片”。

单反买来到现在一年半,也是开始认真学摄影一年半,快门数也差不多两万了,我的收获可以说是难以想象的。所谓收获,绝不只是发朋友圈得到几个赞或是参加比赛得到什么奖,而是定格下美好的画面带来的成就感。更重要的是,我能真正沉到摄影这个圈子——这个圈子,让我学会正视自己,学会变得更加谦逊。现在我是绝不敢再自诩为“厉害的摄影师”了,充其量算是“摄影爱好者”。玩摄影玩得越多,接触到的真正的摄影师也越多,见识的好作品也就越多。这能使我更充分认识到自己作品的不足,从而更加努力地提升自己的水平。

五万次快门,真的一点也不多。我想,当我的快门数达到十万甚至五十万的时候回来看这篇文章,应该又会有不同的感受吧。

分类
影评

聊一聊《药神》

土豆哥昨天并没有更新╮(╯▽╰)╭

哎呀(ˉ▽ ̄~)不要在意这些细节,这几天比较忙嘛~(其实是昨天忘了……)

当然,既然立下了日更的flag,就不能让它随便倒啦,于是,今天土豆哥又出来更新文章了(๑•̀ㅂ•́)و✧


今天是一篇影评,我们来聊一聊今天刚刚上映的新片《我不是药神》。

说起来,土豆哥有一段时间没写影评了(*/ω\*)一方面,没到假期看的电影少,即使看了也没有太多时间写影评;另一方面,能真正戳进我心里的影片并不多。现在进入小学期(差不多相当于假期???),有时间看电影了,正好又碰上了这样一部电影的上映,不写点什么实在说不过去了。

《我不是药神》,是一部真正戳进我心里的电影。老实说,我看着看着,先是笑,后来就哭了。要我给它做个评价,可以简单概括成两个字:良心。这是一部良心的电影。

“良心”有两个意思。首先,这部电影拍摄制作过程是很用心的。它没有请小鲜肉小鲜花吸引流量然后随随便便拍烂片骗粉丝钱,而是真正想要拍出一部好电影。

宁浩和徐峥的监制班底,一众实力派演员的加盟,保证了整部电影在演技上不会出现尴尬,每个演员都把自己的角色演活了,而让自己消失了。演惯了喜剧的徐峥演起悲情戏分毫不含糊,“关谷神奇”王传君也给了观众一个完全不同于《爱情公寓》的荧幕形象。演员们虽然不“老”,但绝对可以称得上“戏骨”。这在烂片成风的华语电影中,可以称得上一股清流。

上面这个憔悴而且有些形象猥琐的癌症患者,能让你把他和《爱情公寓》中乐观而又逗X的关谷神奇联系起来吗?我相信不能。这种同以往经典角色的割裂成功与否,可以说是衡量演员演技好坏的重要标准。

除了演技,电影的灯光和摄影也经得起检验。虽然达不到很多影史经典大片的水准,但至少是不俗的。

好的光影效果,要能够让人看出人物的性格,境况,或是心理。这些点,在《药神》中都做到了。

拍得好,是“良心”的一方面;另一方面,这部电影本身是有良心的,是有温度的。

影片改编自2015年轰动全国的一起走私和贩卖假药案件,整个故事基本取材于案件的主人公“药侠”陆勇的经历。为了给各位读者保留观影的乐趣,这里只简单讲讲真实案件的案情,不说电影剧情。

现实中,陆勇因为罹患白血病,需要长期服用极为昂贵的瑞士进口药物。因为偶然的机会,他发现印度生产的仿制药药效相似,而价格却远远低于瑞士正版药物。之后,他开始频繁购买印度仿制药,并开始为国内的其他病友代购。

陆勇代购的印度仿制药挽救了无数罹患白血病但因贫困无法购买原版药物的患者的生命,他本人被病友们称为“药侠”。然而,由于印度药物未在国内合法注册,陆勇因为贩卖假药等罪名被逮捕。

随后,一千多名因陆勇的代购而活下来的病友联名上书,要求对他免于刑事处罚。此案引起了国内媒体的极大关注,最终检察院决定免于起诉。此案也极大地推动了国内的医疗改革,瑞士原版的药物也在许多省份纳入了医保体系。

影片为了故事性,对案件情节和人物关系做了较大的修改,但核心故事仍然没变。最重要的是,核心内涵没变——关注“人”,关注那些挣扎在生存线上的人。

电影把目光聚焦在那些罹患疾病而又因为贫穷而苦苦求生的人,去听他们的诉求。他们的要求很简单,就是想要普普通通地活下去。但是生活的不幸和贫穷的重担让他们这简简单单的要求几乎成为奢望。和陆勇代购印度仿制药帮助病友的初衷一样,电影选择把聚光灯照向蜷缩在生活角落中的他们——这种人文情怀,是这部电影真正催泪真正闪光的地方。

电影另一个出彩的地方,在于对情和法冲突的严肃探讨。这一对矛盾,构成了电影中的基本矛盾。它既是故事情节的冲突点,也是电影主创情感表达的窗口——情和法起了冲突,说明我们的法律体系仍不够完备,我们的社会还存在不那么美好的一面;但结局则表达着美好的愿望,对社会变得越来越好的希冀。这一点,使得电影再一次升华。

在现实中,检察院对陆勇不予起诉的决定,是在情和法之间找到了巧妙而恰当的平衡;随后的社会舆论和医疗改革,让我们看到了国家和社会前行的决心与努力。人世间不可能处处是光明,但这部电影,以及电影背后的陆勇案件,让我们有信心认为,明天可以更好一点,明天会更好一点。


如果你还没有看这部电影,那么土豆哥强烈向你推荐。它是一部值得你掏出电影票钱并且坐在电影院花两个小时认真观看的电影。

分类
其它

恢复更新了,水一篇~

宝贝们大家好呀ヽ(✿゚▽゚)ノ

销声匿迹了三个星期的土豆哥又出现了(๑•̀ㅂ•́)و✧大家有没有想我呀~

考试周总算熬过去了,搬家也顺利搞定了,现在土豆哥开始悠闲惬意(???)的小学期生活了(~ ̄▽ ̄)~

话说滨海新区还是蛮不错的,泰达校区的宿舍条件虽然比津南那啥了不少,但是它周边方便啊!!!天天晚上出去浪的生活不是梦o(*≧▽≦)ツ(然而并没有钱……)

(请无视那栋在雾气中飘渺的没盖完的超级高楼……)

今天没准备啥文章……就是单纯出来水一下╮(╯▽╰)╭明天应该会上一点干活的,比如手把手教你傻瓜化搭建网站等~

所以,宝贝们拜拜~(我接着去浪去了

分类
其它

暂时停更两周

从5月9号到现在,马铃薯田地保持了超过一个月的日更(๑•̀ㅂ•́)و✧当时立的flag没有倒,可喜可贺ヽ(✿゚▽゚)ノ

不过,马上要进入考试周了,土豆哥(以及土豆哥邀请的其他作者)都要开始疯狂复习模式了(〒▽〒)所以,马铃薯田地从明天开始停更两周╮(╯▽╰)╭等土豆哥和小伙伴们把考试周熬过去再恢复日更(~ ̄▽ ̄)~

暂时停更的这段时间,大家不要忘了我哦(づ ̄3 ̄)づ╭❤

就酱,拜拜~

分类
折腾

【前端笔记】使用iframe嵌入等比缩放的哔哩哔哩视频

之前在《【考前安利】助梦南开》这篇文章里,土豆哥说要告诉大家怎么样嵌入来自哔哩哔哩的iframe视频,今天拖了几天的文章总算开始写了(๑•̀ㅂ•́)و✧

今天算是给【前端笔记】系列开个头吧,作为一名(伪)前端工程师,土豆哥可能时不时会在马铃薯田地放一些关于前端的技巧和学习心得<( ̄︶ ̄)>欢迎感兴趣的小朋友们来关注哦ヽ(✿゚▽゚)ノ


这篇笔记主要讲的是如何在网页中嵌入来自哔哩哔哩的视频。

目前国内大多数视频网站都提供了分享的途径,对于嵌入到其他网页的分享大多采用iframe。iframe是HTML的一个标签,它支持在HTML页面中以框架的形式显示来自其他网页的内容。通过使用iframe,你可以把来自视频网站的播放器嵌入到你的网页。

哔哩哔哩当然也提供了用于嵌入到其他网页的iframe代码。但是,不知道为什么(可能因为哔哩哔哩的程序员和我一样懒吧╮(╯▽╰)╭),哔哩哔哩的iframe播放器是没有等比适应的o(≧A≦)o简单来说,就会造成下面的效果——

嵌入的视频宽度实现了自适应,但是高度没有实现等比缩放,因此看起来很……扁(╯-_-)╯╧╧


首先,我们需要定义一个CSS类。

.aspect-ratio {
  position: relative;
  width: 100%;
  height: 0;
  padding-bottom: 75%;
}

.aspect-ratio iframe {
  position: absolute;
  width: 100%;
  height: 100%;
  left: 0;
  top: 0;
}

在aspect-ratio类中,宽度被设为100%,高度被设为0,padding-bottom属性(外部下边距)被设为75%。因为当padding-bottom的值为百分比时,百分比计算的基准为父元素的宽,而aspect-ratio类的宽度为父元素宽度的100%,所以它的外部下边距也就占宽度的75%。这样,aspect-ratio类的实际宽高比(包含边距的宽高比)就变为了四比三。另外,aspect-ration类的position必须定义为relative,保证它的定位是相对于原始位置定义。

在aspect-ratio类下的iframe元素宽高都被设为100%。因为当元素的position属性设为absolute且width和height属性的值为百分比时,百分比计算基准分别为父元素包含外边距的款和高。所以,此时iframe元素会沾满整个aspect-ratio类的父元素,也就是形成四比三的宽高比。

定义完CSS之后,再来写HTML内容,把哔哩哔哩提供的iframe框架嵌入页面。这里,先获取哔哩哔哩提供的iframe代码:

<iframe src="//player.bilibili.com/player.html?aid=24287094&cid=40734416&page=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"> </iframe>

然后,用一个aspect-ratio类的块内容把iframe包起来——

<div class="aspect-ratio">
    <iframe src="//player.bilibili.com/player.html?aid=24287094&cid=40734416&page=1" scrolling="yes" border="0" frameborder="no" framespacing="1" allowfullscreen="true"></iframe>
</div>

这样一来,就可以实现等比缩放的自适应iframe框架啦~

手机端的显示也是正常的——

这种方法不只可以用于嵌入哔哩哔哩视频,对于其它的iframe框架都是可以的哦(~ ̄▽ ̄)~

分类
作品

随手拍(六)

今天偷个懒(/▽\)来一篇随手拍——中国银行总部大厦~

[mdx_fold title=”拍摄参数”]
ISO:50
快门:1/1000秒
光圈:F/2.4
焦距:2.09mm(等效焦距14mm)
[/mdx_fold]

[mdx_fold title=”随手拍系列”]
第一期
第二期
第三期
第四期
第五期
第六期
第七期
href=”https://blog.potatofield.cn/%e9%9a%8f%e6%89%8b%e6%8b%8d%ef%bc%88%e5%85%ab%ef%bc%89/”>第八期
[/mdx_fold]