Matlab初体验

从来没用过Matlab的我突然发现通选课作业要用Matlab做,这次做的东西比较简单,统计一堆DNA样本中的ATGC频率,然后给出一串DNA,判断它属于哪一类。

这里挖了两个坑:Matlab2017a开始才有对字符串的较好支持,大部分在线运行Matlab的网站不支持strlength与count等方法;函数内不能直接使用工作空间中的变量,必须使用evalin函数获取工作空间中的值。

关于屏幕共享/远程控制

远程控制

控制另一台电脑

Windows远程桌面

当之无愧的最优解,局域网环境下十分顺滑,外网环境下也很少感到卡顿(除非网络实在不好),据说有些企业版本还支持GPU,tql

VNC

有点卡慢,但通用性很强,几乎什么平台都支持。

Teamviewer

有点卡慢,但不得不说是远程环境下的最佳选择。Teamviwer的亮点也在于支持各种类型的设备,移动端到PC/Mac通吃。

屏幕共享/显示器拓展

一台电脑仅作为显示器或串流

Steam串流

支持各种应用程序而不仅是游戏,凭心而论,Steam串流的效果不错,不过延迟也是可以感受到的。只支持局域网。

Airserver

使用这个软件可以让Windows/Mac/iPad等设备的显示器作为mac/ios设备的拓展显示器,支持Airplay的设备可以将屏幕投射到安装了Airserver的设备上。实测中非常不稳定,很容易就掉线。

Windows10的投射和连接

这两个功能允许支持Miracast的安卓/Win设备投屏到Windows(将Windows设备作为Miracast显示器),也可以将这台电脑投射到支持Miracast显示的设备上。但稳定性和延迟都欠佳。

Duet Display

该软件支持将iPad作为Mac的第二显示屏,支持使用USB-lightning连接,速度尚可,画面质量一般(上述所有画面质量都挺一般的),可以作为选择。在iPad上的触控操作是有效的,这是一台触摸显示器。

结合LeanCloud做一个查询术语的单页应用

前言

计算机领域中存在大量的术语,如果恰好是自己未接触的领域,看到一连串不懂的英文缩写,一定是一件令人困惑的事。虽然有百度和谷歌等搜索引擎,如果我们能自建一个更专业的数据库,似乎对我们有很大帮助(可玩性很高)。

一些问题

虽然该项目看起来只是查询数据库,但实际开发过程中遇到了比较多的一些问题。梳理这些问题是有一定价值的,不仅能避免以后被困扰,而且能加深我对这个领域的认识。

与LeanCloud数据存储交互

最初知道LeanCloud,其实是有朋友的hexo博客下留有评论框,静态博客下的评论框引起了我的好奇,F12表明服务提供商是LeanCloud,我猜测它是以专门为app、网站等应用提供后端服务为生。

LeanCloud使用难度不算大,官方文档也还行,但我找了半天才找到我想要的查询数据库的方法和实例。

建立对SDK的引用对象

官方来源:https://leancloud.cn/docs/sdk_setup-js.html

var AV = require("leancloud-storage");
var { Query, User } = AV;
var APP_ID = "**Hidden**";
var APP_KEY = "**Hidden**";

AV.init({
  appId: APP_ID,
  appKey: APP_KEY
});

查询数据示例

这里演示了在Terms表中查找attr==某个值的记录,result是一个数组。

var query = new AV.Query("Terms");
    query.equalTo("attr", value);//选出 attr列的值 为value 的行
    //find以为还有first等方法,都返回promise对象
    query.find().then(res => {
      ...
    }).catch(err => {
        ...
    });

(补充)添加数据示例

该示例将在TestObject表新建一条words='Hello World!'的记录。

var TestObject = AV.Object.extend('TestObject');
var testObject = new TestObject();
testObject.save({
  words: 'Hello World!'
}).then(function(object) {
  alert('LeanCloud Rocks!');

监听全局键盘事件

这个单页应用实际由两个状态组成,一个状态显示搜索框,另一个状态显示结果/详情,我们想实现搜索框聚焦时按下enter切换到详情组件很简单,但反过来就有点麻烦,因为详情组件不支持聚焦。

在网页中,只有聚焦的元素才能监听键盘事件(聪明的你也一定观察到了),同时事件冒泡的方向是自下向上,综合这两点,我们有两个方向。第一个方向是通过tabindex属性使详情组件支持聚焦,第二个方向是直接向顶级元素添加键盘监听器。除了搜索组件与详情组件,网页还有导航栏与底部,如果失去焦点就不能通过快捷键返回,这不是我们想要的效果。

我们通过向document添加事件处理实现在详情状态下按esc返回搜索状态(position用来控制状态,keyCode==27的键正是esc):

    document.onkeydown = e => {
      if (this.position == true && e.keyCode == 27) {
        this.position = false;
      }
    };

Vue-cli与Vue-router结合

Vue-router的官方文档给出了cdn接入的示例,我们这里介绍结合Vue-cli使用。

首先,在项目根目录下npm i vue-router

然后,在main.js里导入(import VueRouter from 'vue-router')并注册到Vue(Vue.use(VueRouter))

再新建一个VueRouter实例:

const router = new VueRouter({
    routes: [
            { path: '/detail', component: Detail },
            { path: '/', component: SearchBox }
        ] 
})

修改一下Vue根实例:

new Vue({
    render: h => h(App),
    router
}).$mount('#app')

剩下的部分则是将<router-link>标签与<router-view>标签添加到需要使用的地方。

布局与CSS选择器

Layout

Bootstrap-vue的布局很方便,通过b-row与b-col节点上的align-v与align-self属性可以实现对齐效果。对于col内部的行内元素对齐,我使用了verticle-align属性,通常设置bottom。

vh

对于整页布局,除了传统的对html,body,div设置100%高度,还有一种方法,就是为div设置100vh的高度,该应用中我为导航栏与底部标签各设置了5vh的高度,内容区域高度90vh,刚好占满了浏览器可视区域。这么做存在的问题是对移动设备兼容性不佳,如果要适配移动设备,可以借助媒体查询断点使用其他方式布局移动端。

自动聚焦与$refs与Vue的生命周期

其实$refs我一直没怎么使用过,最大的问题是我不能从$refs获取的节点中得到很多html结点信息,修改结点属性时,不如直接用querySelector。但这里实现自动聚焦却很实用,代码如下:

 <b-form-input ref="focusThis" @keyup.enter="$emit('match',keyword)" v-model="keyword" list="my-list-id"/>
mounted(){
     this.$refs.focusThis.focus()
  }

为什么说生命周期?我以前习惯在create钩子里进行初始化操作,但create时结点还未渲染,我不得不把聚焦操作放到mounted钩子。

DEMO

https://demo.guohere.com/term-search/

数据库暂时只有两条记录'html'与'css',请用这两个条目试验。支持快捷键enter(匹配)与esc(返回)。

function*/生成器函数

function*语句允许你声明一个生成器函数,这种函数的返回值是一个Generator对象,它允许你控制函数的暂停、继续执行。这种同步操作允许我们使用JavaScript的异步编程——function*每次只返回一个特殊的指针,并不直接真正地返回值,因此function*内外的代码可以同时执行。

function* generator(param,...)
{
...
yield ...
}

异步执行

function* add(inc){
inc++
yield inc++
yield inc++
}
let f=add(10)
f.next()//inc==11 { value: 11, done: false }
f.next()//inc==12 { value: 12, done: false }
f.next()//inc==13 { value: undefined, done: true }

遇到yield时函数会暂停执行后面的代码,直到next()方法被调用,该方法的返回值包括表达式的结果和完成状态。使用函数生成器时函数不会执行,因此需要使用一次next()。

上文的程序为什么到最后变成undefined呢?这是因为每次next()都会执行到yield关键字后的表达式处,并且将yield后的表达式结果作为value返回。而add函数内只有两个yield,虽然三次调用next()才能完成调用过程,但最后一次不返回value,在函数末尾加上return语句就能让next返回return后的表达式值。值得一提的是,函数生成器返回的是Generator对象,但这不影响在函数生成器内使用return。

为什么value=11和12,不应该12和13吗?inc++实际上是先返回inc再+1,这里就是inc++和++inc的差别。

计算机网络(1)

基础概念

路由器

负责连接两条或以上传输线路的计算机。同时路由器也是一个网关,它在网络层交换数据包。

交换机

网络中每台计算机通过一条点对点的链路连接到交换机(switch)。交换机有多个端口(port),每个端口连接一台计算机。交换机的工作是中继网络中的数据包,通过数据包中的地址确定数据发送给哪台计算机。

网关

将两个不同的网络连接起来并提供必要转换的机器,其硬件和软件的总称叫网关(gateway),网关可以工作在协议的不同层次。

子网

定义一

广域网中运行应用程序的计算机被称为主机(host),而连接这些主机的网络的其余部分被称为通信子网(communication subnet)/子网(subnet)。子网的工作是把信息从一台主机传递给另一台主机。

在多数广域网中,子网由传输线路和交换元素组成。传输线路(transmission line)指有线或无线链路,交换元素(switching element)/交换机(switch)是负责连接两条或以上传输线路的计算机,他们现在又叫路由器(router)

层次相关

OSI模型

OSI(Open Systems Interconnection,开放系统互联)模型描述了较为通用的网络模型,它本身不定义服务或协议。

物理层(physical layer)

物理层关注在一条通信信道上传输原始比特,涉及传输方式和细节,以及物理传输介质等。

数据链路层(data link layer)

数据链路层的主要任务是隐藏物理传输中的错误,使物理连接变成逻辑上无差错的数据链路。发送方将数据拆分成数据帧(data frame)并顺序发送,如果服务是可靠的,接受方给发送方发回确认帧(acknowledgement frame),帧的尾部带有检查码。

网络层(network layer)

网络层的主要功能是控制子网的运行。网络层负责路由,处理拥塞,决定服务质量,允许不同协议的异构网络相互连接成为互联网络。

传输层(transport layer)

传输层接受上一层的数据,在必要的时候把这些数据分割成较小的单元,然后把这些数据单元传递给网络层,并且确保数据正确抵达另一端。OSI的1~3层是链式连接的,而4~7层是端到端的。

会话层(session layer)与表示层(presentation layer)

会话层提供了对话控制、令牌管理、同步功能等服务,表示层管理数据的语义、抽象结构。由于现在的应用层实现了部分会话层与表示层的功能,在TCP/IP协议中不存在这两层。

应用层(application layer)

应用层包含了用户通常需要的各种协议,如HTTP(HyperText Transfer Protocol)、HTTPS、FTP、SFTP等协议。

层次设计问题

路由(routing)

在源和目的地之间找到合适的路径。网络有时有一些链路或者路由器偶尔发生故障,网络应该能够选出别的线路,这个主题叫做路由。

寻址(addressing)和命名(naming)

每一层在特定的消息中都需要一种机制来标识发送方和接收方,这种机制在下层叫寻址,上层叫命名。

拥塞(congestion)

由于太多的计算机发送太多的流量,网络没有能力传递所有的数据包。此时需要流量控制,发生拥塞时,每台计算机都减少对网络的宽带需求,这种策略对每一层都适用。

服务质量(Quality of Service)

网络为需要实时(real-time)传递的应用程序与高吞吐量的应用程序提供服务,QoS是调和这些竞争需求的机制的名称。

Destructuring assignment

Array destructuring

var [a,b] = [1,2]

var [a,b] = c //c=[1,2]

Object destructuring

var {a,b} = {a : 1, b : 2}

({a,b} = {a : 1, b : 2})

var {a,b} = c //c={a : 1 , b : 2}

({a,b} = c)

also provide support for default values, assigning to new variable names

关于Object destructing

Object的key用于匹配,左边的value应该是一个变量,右边的value应该有一个值。var {c} = {c:1}实际上是var {c:c} = {c:1},key和value相同的时候可以简写是es6的语法糖。

转载:POST请求的Content-Type

https://imququ.com/post/four-ways-to-post-data-in-http.html

application/x-www-form-urlencoded

这应该是最常见的 POST 提交数据的方式了。浏览器的原生 <form> 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。请求类似于下面这样(无关的请求头在本文中都省略掉了):

BASHPOST http://www.example.com HTTP/1.1
Content-Type: application/x-www-form-urlencoded;charset=utf-8

title=test&sub%5B%5D=1&sub%5B%5D=2&sub%5B%5D=3

首先,Content-Type 被指定为 application/x-www-form-urlencoded;其次,提交的数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL 转码。大部分服务端语言都对这种方式有很好的支持。例如 PHP 中,$_POST['title'] 可以获取到 title 的值,$_POST['sub'] 可以得到 sub 数组。

很多时候,我们用 Ajax 提交数据时,也是使用这种方式。例如 JQuery 和 QWrap 的 Ajax,Content-Type 默认值都是「application/x-www-form-urlencoded;charset=utf-8」。

multipart/form-data

这又是一个常见的 POST 数据提交的方式。我们使用表单上传文件时,必须让 <form> 表单的 enctype 等于 multipart/form-data。直接来看一个请求示例:

BASHPOST http://www.example.com HTTP/1.1
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA

------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="text"

title
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="file"; filename="chrome.png"
Content-Type: image/png

PNG ... content of chrome.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--

这个例子稍微复杂点。首先生成了一个 boundary 用于分割不同的字段,为了避免与正文内容重复,boundary 很长很复杂。然后 Content-Type 里指明了数据是以 multipart/form-data 来编码,本次请求的 boundary 是什么内容。消息主体里按照字段个数又分为多个结构类似的部分,每部分都是以 --boundary 开始,紧接着是内容描述信息,然后是回车,最后是字段具体内容(文本或二进制)。如果传输的是文件,还要包含文件名和文件类型信息。消息主体最后以 --boundary-- 标示结束。关于 multipart/form-data 的详细定义,请前往 rfc1867 查看。

这种方式一般用来上传文件,各大服务端语言对它也有着良好的支持。

上面提到的这两种 POST 数据的方式,都是浏览器原生支持的,而且现阶段标准中原生 <form> 表单也只支持这两种方式(通过 <form> 元素的 enctype 属性指定,默认为 application/x-www-form-urlencoded。其实 enctype 还支持 text/plain,不过用得非常少)。

随着越来越多的 Web 站点,尤其是 WebApp,全部使用 Ajax 进行数据交互之后,我们完全可以定义新的数据提交方式,给开发带来更多便利。

application/json

application/json 这个 Content-Type 作为响应头大家肯定不陌生。实际上,现在越来越多的人把它作为请求头,用来告诉服务端消息主体是序列化后的 JSON 字符串。由于 JSON 规范的流行,除了低版本 IE 之外的各大浏览器都原生支持 JSON.stringify,服务端语言也都有处理 JSON 的函数,使用 JSON 不会遇上什么麻烦。

JSON 格式支持比键值对复杂得多的结构化数据,这一点也很有用。记得我几年前做一个项目时,需要提交的数据层次非常深,我就是把数据 JSON 序列化之后来提交的。不过当时我是把 JSON 字符串作为 val,仍然放在键值对里,以 x-www-form-urlencoded 方式提交。

Google 的 AngularJS 中的 Ajax 功能,默认就是提交 JSON 字符串。例如下面这段代码:

JSvar data = {'title':'test', 'sub' : [1,2,3]};
$http.post(url, data).success(function(result) {
    ...
});

最终发送的请求是:

BASHPOST http://www.example.com HTTP/1.1 
Content-Type: application/json;charset=utf-8

{"title":"test","sub":[1,2,3]}

这种方案,可以方便的提交复杂的结构化数据,特别适合 RESTful 的接口。各大抓包工具如 Chrome 自带的开发者工具、Firebug、Fiddler,都会以树形结构展示 JSON 数据,非常友好。但也有些服务端语言还没有支持这种方式,例如 php 就无法通过 $_POST 对象从上面的请求中获得内容。这时候,需要自己动手处理下:在请求头中 Content-Type 为 application/json 时,从 php://input 里获得原始输入流,再 json_decode 成对象。一些 php 框架已经开始这么做了。

当然 AngularJS 也可以配置为使用 x-www-form-urlencoded 方式提交数据。如有需要,可以参考这篇文章

text/xml

我的博客之前提到过 XML-RPC(XML Remote Procedure Call)。它是一种使用 HTTP 作为传输协议,XML 作为编码方式的远程调用规范。典型的 XML-RPC 请求是这样的:

HTMLPOST http://www.example.com HTTP/1.1 
Content-Type: text/xml

<?xml version="1.0"?>
<methodCall>
    <methodName>examples.getStateName</methodName>
    <params>
        <param>
            <value><i4>41</i4></value>
        </param>
    </params>
</methodCall>

XML-RPC 协议简单、功能够用,各种语言的实现都有。它的使用也很广泛,如 WordPress 的 XML-RPC Api,搜索引擎的 ping 服务等等。JavaScript 中,也有现成的库支持以这种方式进行数据交互,能很好的支持已有的 XML-RPC 服务。不过,我个人觉得 XML 结构还是过于臃肿,一般场景用 JSON 会更灵活方便。