iPhone 锁屏 WebSocket 断开后的自动重连 (JavaScript)

This is no exception either. Talk is cheap, I'll show you the code.

    var newSocket = function() {
        ws = new WebSocket(wsUri);
        ws.onopen = function(evt) {
            // send a request
            if ($('#tag').val().length > 0) {
                var req = {info: $('#tag').val()}
                ws.send(JSON.stringify(req))
            }
        }
        ws.onclose = function(evt) {
            reconnectSocket()
        }
        ws.onmessage = function(evt) {
            // do what you wanna do
        }
        ws.onerror = function(evt) {
        }
    };

    var reconnectSocket = function() {
        if (!ws || ws.readyState == WebSocket.CLOSED) {
            newSocket()
        }
    };

    $('#btn-go').click(function() {
        reconnectSocket()
        return false
    })

Go 语言 switch/case 的一个小坑

前几天竟然被 switch/case 坑了一小下,坦白讲,能掉进这个坑,纯粹是基本语法不过关,把 Go 当成 C++ 了。

下面是一个简化后的粟子,通过一个人的名字来判断我认不认识他,最初写下这段代码的期望结果是:如果 nameJohnKenny,把 i_knew_him 置为 true,表示我认识这两个人,别人(默认)不认识。熟悉 C++ 的同学一定知道我为什么这样写。

var i_knew_him bool = false
switch name {
case "John":
case "Kenny":
    i_knew_him = true
}

但我们现在写的是 Go 语言,执行结果不一样了(敲黑板

我的好朋友 John 迎面走了过来,我却假装不认识他,i_knew_him = true 根本没有执行到,因为这条表达式只属于 case "Kenny"……

正确的写法是什么样的呢?

case "John", "Kenny":
    i_knew_him  = true

详见 Go 语言规范

<全文完>

Neural Networks and Deep Learning

Key points

  • Perceptron
  • Sigmoid
  • Cost function
  • Gradient Descent / Stochastic Gradient Descent
  • Back-propagation
  • Chain rule
  • Quadratic cost
  • Cross-Entropy cost
  • Softmax + log-likelihood cost
  • Overfitting
  • Early stopping strategy
  • Hold out method
  • Regularization
  • Weight decay / L2 regularization
  • L1 regularization
  • Dropout
  • Artificially increasing the training set size
  • ...

TO BE CONTINUED

《Hadoop 大数据分析与挖掘实战》笔记

第一章 数据挖掘基础

数据探索方法

  • 数据质量分析
  • 数据特征分析

数据质量分析

(1) 缺失值分析

数据的缺失主要包括记录的缺失和记录中某个字段信息的缺失。统计分析含有缺失值的属性的个数,以及每个属性的未缺失数、缺失数与缺失率。缺失值的处理:删除存在缺失值的记录、对可能值进行插补、不处理。

(2) 异常值分析

检验数据是否有录入错误以及含有不合常理的数据。异常值是指样本中的个别值,其数值明显偏离其余的观测值。异常值也称为离群点,异常值的分析也称为离群点分析。

箱型图异常值标准:

< Q_l - 1.5IQR> Q_u + 1.5IQR

其中 IQR 是四分位间距:

IQR = Q_u - Q_l

箱型图没有对数据做任何限制性要求(如服从某种特定的分布形式)。

(3) 数据一致性分析

数据一致性是指数据的矛盾性、不相容性。

数据特征分析

数据特征分析主要包括:分布分析、对比分析、统计量分析、周期性分析、贡献度分析和相关性分析。

(1) 分布分析

  • 定量数据:对称 or 非对称、特大 or 特小的可疑值,可做出频率分布表、绘制频率分布直方图、绘制茎叶图
  • 定性数据:饼图、条形图

(2) 对比分析

把两个相互联系的指标进行对比,从数量上展示和说明研究对象规模的大小,水平的高低,速度的快慢,以及各种关系是否协调。特别适用于指标间的横纵向比较,时间序列的比较分析。

关键在于选择合适的对比标准。

(3) 统计量分析

用统计指标对定量数据进行统计描述,常从集中趋势和离中趋势两个方面进行分析。平均水平的指标是对个体集中趋势的度量,使用最广泛的是均值和中位数;反映变异程度的指标则是对个体离开平均水平的度量,使用较广泛的是标准差(方差)、四分位间距。

(4) 周期性分析

周期性分析是探索某个变量是否随着时间变化而呈现出某种周期变化趋势。时间尺度相对较长的周期性趋势有年度周期性趋势、季节性周期性趋势,相对较短的有月度周期性趋势、周度周期性趋势,甚至更短的天、小时周期性趋势。

(5) 贡献度分析

贡献度分析又称帕累托分析。原理是帕累托法则(又称 20/80 定律)。可以通过帕累托图直观呈现。

(6) 相关性分析

分析连续变量之间线性相关程度的强弱,并用适当的统计指标表示出来的过程称为相关性分析。判断两个变量是否具有线性相关关系的最直观的方法是直接绘制散点图。如果需要同时考察多个变量间的相关关系时,可利用散点图矩阵来同时绘制各变量间的散点图,从而快速发现多个变量间的主要相关性,这在进行多元线性回归时显得尤为重要。在二元变量的相关性分析过程中比较常用的有 Pearson 相关系数、Spearman 秩相关系数和判定系数。

数据预处理

  • 数据清洗
  • 数据集成
  • 数据变换
  • 数据规约

数据清洗

删除无关数据、重复数据,平滑噪音数据,筛选掉与挖掘主题无关的数据,处理缺失值、异常值。

(1) 缺失值处理

  • 删除记录
  • 插补:拉格朗日插值、牛顿插值
  • 不处理

(2) 异常值处理

分析异常值出现的可能原因,再判断异常值是否应该舍弃,如果是正确的数据,可以直接在具有异常值的数据集上进行建模。

数据集成

将多个数据源合并,在最低层上加以转换、提炼和集成。

数据变换

对数据进行规范化处理以适用于挖掘任务及算法需要。常用的变换方法有:简单函数变换、规范化、连续属性离散化、属性构造、小波变换。

(1) 简单函数变换

用来将不具有正态分布的数据变换成具有正态分布的数据;在时间序列分析中,有时简单的对数变换或差分运算可将非平稳序列转换为平稳序列。如:个人年收入的取值范围为 10000 元到 10 亿元,使用对数变换对其压缩是常用的一种变换处理。

常用:平方、开方、取对数、差分运算。

(2) 规范化

归一化处理是数据挖掘的一项基础工作。不同评价指标往往具有不同的量纲和量纲单位,数值间的差别可能很大,不进行处理可能会影响到数据分析的结果。

常用:最小-最大规范化、零均值规范化、小数定标规范化。

(3) 连续属性离散化

一些挖掘算法如 ID3、Apriori 要求数据是离散属性形式。

方法:在数据的取值范围内设定若干个离散的划分点,将取值范围划分为一些离散化的区间,最后用不同的符号或整数值代表落在每个子区间中的数据值。所以离散化涉及两个子任务:确定分类数、连续属性映射分类值。

常用的连续属性离散化方法有:等宽法、等频法、(一维)聚类。

(4) 属性构造

利用已有的属性集构造出新的属性,并加入再有的属性集中。

(5) 小波变换

新型的数据分析工具,是信号分析手段。小波变换具有多分辨率的特点,在时域和频域都具有表征信号局部特征的能力,通过伸缩和平移等运算过程对信号进行多尺度聚集分析,提供了一种非平稳信号的时频分析手段,可以由粗及细地逐步观察信号,从中提取有用信息。

数据规约

通过选择替代的、较小的数据来减小数据量,包括有参数方法和无参数方法两类。

  • 有参数方法是使用一个模型来评估数据,只需存放参数,不存放实际数据。如回归(线性回归和多元回归)和对数线性模型(近似离散属性集中的多维概率分布)。
  • 无参数方法需要存放实际数据,如直方图、聚类、抽样(采样)。

模型评价

分类与预测模型

使用测试集,通常用相对绝对误差、平均绝对误差、根均方差、相对平方根误差等指标来衡量。

聚类分析模型

仅根据样本数据本身将样本分组,组内相似性越大,组间差别越大,效果越好。

《Go 语言编程》笔记

今天花了 2.5 小时看完这本书,总体来说这本书的内容偏浅,拿来入门比较合适——当然对于我这种从不看书、只靠文档 + 实践学习语言的来说,一些基础的知识点还是有必要补补的。看书的过程简单记了下笔记,太基础的直接跳过了,只记了部分我认为比较关键的知识点。全书最核心的部分当数第四章——并发编程。

@author migege@github
@version 170622:1

语言特点

  • 并发与分布式
  • 软件工程
  • 编程哲学

基础

多返回值

func getName() (firstName, middleName, lastName, nickName string) {
    firstName = "A"
    middleName = "B"
    lastName = "C"
    nickName = "D"
    return
}

匿名函数和闭包

f := func(x, y int) int {
    return x + y
}

反射

type Bird struct {
    Name string
    LifeExpectance int
}

func main() {
    sparrow := &Bird{"Sparrow", 3}
    s := reflect.ValueOf(sparrow).Elem()
    typeOfT := s.Type()
    for i := 0; i < s.NumField(); i++ {
        f := s.Field(i)
        fmt.Printf("%d: %s %s = %v\n", i, typeOfT.Field(i).Name, f.Type(), f.Interface())
    }
}

Cgo

package main

/*
#include <stdio.h>
#include <stdlib.h>
*/
import "C"
import "unsafe"

func main() {
    cstr := C.CString("Hello, world!")
    C.puts(cstr)
    C.free(unsafe.Pointer(cstr))
}

工程管理

运行

go run

构建

go build

单元测试

go test

GDB 调试

gdb xxx

调试信息为 DWARFv3,>= gdb1.7

语法

预定义常量

const (
    c0 = iota
    c1 = iota
    c2 = iota
)

枚举

const (
    Sunday = itoa
    Monday
    Tuesday
    Wednesday
    Thursday
    Friday
    Saturday
    numberOfDays
)

数组切片

cap()len()

goto

竟然支持 goto

defer / panic() / recover()

defer func() {
    if r := recover(); r != nil {
        // do something
    }
}

foo()

passed by value

类型都是值传递

面向对象编程

匿名组合

虚基类

type Job struct {
    Command string
    *log.Logger
}

func (job *Job) Start() {
    job.Log("starting...")
}

非侵入式接口

一个类只需要实现了接口要求的所有函数,就认为这个类实现了该接口。

接口查询

var file1 Writer = ...
if file5, ok := file1.(two.IStream); ok {
}

类型查询

switch v := arg.(type) {
    case int:
    case string:
    default:
    // ...
}

并发编程

goroutine

go 关键字

并发通信

不要通过共享内存来通信,而应该通过通信来共享内存。

channel

ch <- 1

channel 在被读取前,写入操作是阻塞的。

<- ch

channel 在被写入前,读取操作是阻塞的。

基本语法

var ch chan int
var m map[string]chan bool
ch := make(chan int)

select

select {
    case <- ch1:
    case <- ch2:
    default:
}

缓冲机制

ch := make(chan int, 1024)

即使没有读取方,写入方也可以一直往 channel 里写入,在缓冲区被填满之前都不会阻塞。

超时机制

timeout := make(chan bool, 1)
go func() {
    time.Sleep(1e9)
    timeout <- true
}

select {
    case <- ch:
    // ...
    case <- timeout:
    // timeout
}

channel 可被传递

可以用来实现 pipe。

单向 channel

var ch1 chan<- float64 // 仅写入
var ch2 <-chan int // 仅读取

关闭 channel

close(ch)

x, ok := <-ch

多核并行化

runtime.GOMAXPROCS(runtime.NumCPU())

出让时间片

runtime.Gosched()

同步

同步锁

sync.Mutexsync.RWMutex

var l sync.Mutex
func foo() {
    l.Lock()
    defer l.Unlock()
}

全局唯一性操作

var once sync.Once
once.Do(...)

sync/atomic 子包

func CompareAndSwapUint64(val *unit64, old, new uint64) (swapped bool)

网络编程

Socket 编程

Dial()


### HTTP 编程

```net/http

RPC 编程

rpc.Register()

工程管理

gofmt

godoc

开发工具

gocode

其它

libtask

PM10 和 PM2.5 双爆表

有点突破认知了。

@北京

编译 VIM 配置参数(Python 2/3 支持)

for Python 2.n

./configure --with-features=huge --enable-pythoninterp --enable-cscope

for Python 3.n

./configure --with-features=huge --enable-python3interp --enable-cscope

DNSPod 如何查看域名解析的 domain_id 和 record_id

本文介绍调用 API 获取 DNSPod 域名解析需要的 domain_idrecord_id 参数的方法,所有的 DNSPod API 请求都必须提供 login_token 作为公共参数以验证用户身份是否合法。

获取 login_token

DNSPOD > 用户中心 > 安全设置 > API Token

使用英文 , 将 ID 和 Token 连接起来即公共请求参数 login_token

获取 domain_id

curl 'https://dnsapi.cn/Domain.List' -d 'login_token=<your_login_token>&format=json'

根据响应中的 domains 得到域名对应的 domain_id

获取 record_id

curl 'https://dnsapi.cn/Record.List' -d 'login_token=<your_login_token>&format=json&domain_id=<your_domain_id>'

根据响应中的 records 得到子域名记录对应的 record_id

阿里云短信接口 (Python)

废话不多说,直接贴代码,有兴趣的访问我的 github

#!/usr/bin/env python
# -*- coding:utf8 -*-
import sys

reload(sys)
sys.setdefaultencoding('utf8')


def sendsms(phone, param_string, access_key_id, access_key_secret, template_code, sign_name):
    from datetime import datetime
    import uuid
    import requests

    url = 'https://sms.aliyuncs.com/'
    ts = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
    once = str(uuid.uuid4())
    data = {
        'Action': 'SingleSendSms',
        'SignName': sign_name,
        'TemplateCode': template_code,
        'RecNum': phone,
        'ParamString': param_string,
        'Format': 'JSON',
        'Version': '2016-09-27',
        'AccessKeyId': access_key_id,
        'SignatureMethod': 'HMAC-SHA1',
        'Timestamp': ts,
        'SignatureVersion': '1.0',
        'SignatureNonce': once,
    }

    def __percent_encode(s):
        import urllib
        s = str(s)
        s = urllib.quote(s.decode('utf8').encode('utf8'), '')
        s = s.replace('+', '%20')
        s = s.replace('*', '%2A')
        s = s.replace('%7E', '~')
        return s

    def __gen_signature(data, req_method, secret):
        import hashlib
        import hmac
        import base64

        sorted_data = sorted(data, key=lambda v: v[0])
        vals = []
        for k, v in sorted_data:
            vals.append(__percent_encode(k) + '=' + __percent_encode(v))

        params = '&'.join(vals)
        string_to_sign = req_method + '&%2F&' + __percent_encode(params)
        key = secret + '&'
        signature = base64.encodestring(hmac.new(key, string_to_sign, hashlib.sha1).digest()).strip()
        return signature

    try:
        headers = {
            'Content-Type': 'application/x-www-form-urlencoded',
        }

        signature = __gen_signature(data.items(), 'POST', access_key_secret)
        data['Signature'] = signature

        r = requests.post(url, data=data, headers=headers)
        print r.text
    except Exception, e:
        print 'EXCEPT:', e


if __name__ == '__main__':
    pass

最后想说的是,阿里云文档中关于 base64 后的签名值还需要做一次 URLEncode 编码的说法是有问题的,事实证明只会报错:Specified signature is not matched with our calculation.,掉这坑里差点没爬上来。

MiLog 可以用 python 写插件啦

MiLog 发布一年多了,昨天才第一次真正有动力实现插件系统——总觉得用一个异步的外部脚本做 anti-spam,不怎么得劲,还是写一个插件系统比较靠谱,本来插件系统也是 MiLog 的规划功能之一,更重要的是:

  1. 简单的非核心功能并不想用 Go 写进 MiLog 里,最好只保持一个轻量级的 Core;
  2. 最好可以用 Python 写插件,没别的原因,我喜欢 Python 就足够了;

于是乎,MiLog Plugins System 诞生了,目前只支持用 Python 编写插件,最简单的插件只需要两个函数(参考 speak-chinese-please):

  1. register() 用于 MiLog 加载插件时注册事件;
  2. <事件名>() 用于处理事件回调;

将编写好的插件放在任意目录下,并在 conf/app.conf 中增加一行,指向该目录就行:

plugindir = <path_to_plugin_directory>

哦对了,做完以上步骤后 MiLog 需要重启,注意通过日志观察插件是否注册成功。

Now, enjoy!