Skip to main content

· One min read


"NLP.js" is a general natural language utilities for nodejs. Currently supporting:

  • Guess the language of a phrase
  • Fast levenshtein distance of two strings
  • Search the best substring of a string with less levenshtein distance to a given pattern.
  • Get stemmers and tokenizers for several languages.
  • Sentiment Analysis for phrases (with negation support).
  • Named Entity Recognition and management, multilanguage, and accepting similar strings, so the introduced text does not need to be exact.
  • Natural Language Processing Classifier, to classify utterance into intents.
  • Natural Language Generation Manager, so from intents and conditions it can generate an answer.
  • NLP Manager: a tool able to manage several languages, the Named Entities for each language, the utterance and intents for the training of the classifier, and for a given utterance return the entity extraction, the intent classification and the sentiment analysis. Also, it is able to maintain a Natural Language Generation Manager for the answers.

· One min read

It is in fact possible to listen to the "expired" type keyevent notification using a subscribed client to the specific channel ( and listening to its message event.

通过 subscribe client 可以监听 __keyevent@{db}__:expired ( db 是你传入的配置 ) 频道来接收过期的事件 ,

const redis = require('redis')
const CONF = {db:3}

let pub, sub

// Activate "notify-keyspace-events" for expired type events
pub = redis.createClient(CONF)
pub.send_command('config', ['set','notify-keyspace-events','Ex'], subscribeExpired)

// Subscribe to the "notify-keyspace-events" channel used for expired type events
function subscribeExpired(e, r){
sub = redis.createClient(CONF)
const expired_subKey = `__keyevent@${CONF.db}__:expired`

sub.subscribe(expired_subKey, function () {
console.log(' [i] Subscribed to "'+expired_subKey+'" event channel : '+r)
sub.on('message', function (chan, msg){
console.log('[expired]', msg)}

//例如,设置一个 key 并设置 10s 超时
function TestKey(){
pub.set('testing', 'redis notify-keyspace-events : expired')
pub.expire('testing', 10)

· One min read

DB search sql:

  1. 筛选出拥有 openId 的用户,对这些用户进行按年月日分组,并统计每天新增的用户数
$match: { "openId": { $exists: true } }
$group : {
_id : { month: { $month: "$createDate" }, day: { $dayOfMonth: "$createDate" }, year: { $year: "$createDate" } },
count: { $sum: 1 }

· One min read
// "apn": "^2.1.2",
var apn = require('apn');

var service = new apn.Connection(

var apnVoipProvider = new apn.Provider(voipOptions);

apnNotification = new apn.Notification();
apnNotification.badge = 1;
apnNotification.sound = 'msg.mp3';
apnNotification.alert = 'hello';
apnNotification.payload = {
title: notification.title, id: notificationID, path: notification.path,

apnVoipProvider.send(apnNotification, token);

· One min read
"_id" : "Football",
"ancestors" : [
"Sports and fitness"
"parent" : "Sports and fitness"


var mongoose = require('mongoose');

var Category = mongoose.Schema({
_id: String

var categorySchema = mongoose.Schema({
ancestors: [Category],
parent: [Category]

// Initiate database connection
var db = mongoose.createConnection('mongodb://localhost/Categories');
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function callback () {
console.log("openDB categories");

module.exports.category = db.model('Category', categorySchema);
var categoryModel = require('../models/Category');
var Category = categoryModel.category;

exports.getAncestors = function(req, res) {
if ( == undefined){res.send("no id specified!"); return;}

Category.findOne({_id: 'Football'}, 'ancestors', function(err, ancestors){
if(err) console.log(err);



{ message: 'Cast to ObjectId failed for value "Football" at path "_id"',
name: 'CastError',
type: 'ObjectId',
value: 'Football',
path: '_id' }


mongoose 默认将 _id 设为 ObjectId 类型。

var categorySchema = mongoose.Schema({
_id: String,
ancestors: [{type: String }],
parent: {type: String}
},{ _id: false });

var Category = mongoose.model( "Category", categorySchema );

· One min read

· One min read


app.get('/', function (...) { ... });
app.get('/foo/:id', function (...) { ... });'/foo/:id', function (...) { ... });


get: [ '/', '/foo/:id' ],
post: [ '/foo/:id' ]


在 express 3.x 中

只需要 app.routes 就可以啦

在 express 4.x 中

Applications - built with express()


Routers - built with express.Router()


更多的答案尽在 StackOverflow how-to-get-all-registered-routes-in-express

· One min read

最近在项目中经常发生登录卡死的状况,由于是使用的 passport 单点登录,所以只能一步步排查,加日志。

最后发现是卡在一个 mongodb 查询那里,后来去官网查询后,发现查询超时时间默认是无限大的,所以导致我们看到的现象是 http 无返回,导致 http 超时了 , 因此 nginx 报 502 错误。

找到了 mongoose 文件的Connection部分,在下面可以看到有一些连接参数,其中就有 socketTimeoutMS 和 connectTimeoutMS,点击进入 mongodb 官方文档,可以看到Server 的参数中,socketTimeoutMS 默认是无限大的,这在连接外网 mongodb 时可能导致一些问题,我们需要加上超时参数。

var options = {
server: {
socketOptions: {
autoReconnect: true,
connectTimeoutMS: 10000,
socketTimeoutMS: 10000,

// Good way to make sure mongoose never stops trying to reconnect
mongoose.connect(uri, options);


尝试后发现,这个 socketTimeoutsocket 变成时的设置 timeout 是一个效果,闲置超时时间,但是在 linux 下似乎没有什么不正常,在 windwos 上就是启动后,过了这个时间就会抛出一个 timeout 错误。

· One min read


[8264] 08 Nov 09:28:43.943 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server.exe /path/to/redis.conf
[8264] 08 Nov 09:28:43.948 # Creating Server TCP listening socket *:6379: bind: No such file or directory

Redis 报错:

[6644] 02 Apr 23:11:58.976 # Creating Server TCP listening socket *:6379: bind: No such file or directory


1. redis-cli.exe
2. shutdown
3. exit
4. redis-server.exe

· One min read

Why Yarn

Yarn is Super Fast!!

Yarn caches every package it downloads so it never needs to again. It also parallelizes operations to maximize resource utilization so install times are faster than ever.

Common NPM commands in Yarn

NPM CommandYarn CommandDescription (wherever necessary)
npm installyarn
yarn install
Will install packages listed in the package.json file
npm install pkg-name
npm install --save pkg-name
yarn add pkg-nameBy default Yarn adds the pgk-name to package.json and yarn.lock files
npm install pkg-name@1.0.0yarn add pgk-name@1.0.0
npm install pkg-name --save-devyarn add pkg-name --dev
npm install pkg-name --peeryarn add pkg-name--peer
npm install pkg-name --optionalyarn add --optional
npm install -g pkg-nameyarn global add pkg-nameCareful, yarn add global pkg-name adds packages global and pkg-name locally!
npm updateyarn upgradeNote: It's called upgrade in yarn
npm uninstall pkg-nameyarn remove pkg-name
npm run script-nameyarn run script-name
npm inityarn init
npm packyarn packCreates a compressed gzip archive of the package dependencies
npm linkyarn link
npm outdatedyarn outdated
npm publishyarn publish
npm runyarn run
npm cache cleanyarn cache clean
npm loginyarn login (and logout)
npm testyarn test
npm install --productionyarn --production
npm --versionyarn version
npm infoyarn info

New Commands in Yarn

Yarn CommandDescription
yarn why pkg-name Builds a dependency graph on why this package is being used
yarn cleanFrees up space by removing unnecessary files and folders from dependencies
yarn licenses ls  Inspect the licenses of your dependencies
yarn licenses generate-disclaimer  Automatically create your license dependency disclaimer



· One min read


反引号位 (`) 位于键盘的 Tab 键的上方、1 键的左方。注意与单引号 (\') 位于 Enter 键的左方的区别。 在 Linux 中起着命令替换的作用。命令替换是指 shell 能够将一个命令的标准输出插在一个命令行中任何位置。

如下,shell 会执行反引号中的 date 命令,把结果插入到 echo 命令显示的内容中。

[root@localhost sh] $ echo The date is \`date\`
The date is 2011年 03月 14日 星期一 21:15:43 CST


[root@localhost sh] $ str="Today is Monday"
[root@localhost sh] $ echo $str
Today is Monday

如果没有单引号或双引号,shell 会把空格后的字符串解释为命令。

[root@localhost sh] $ str=Today is Monday
bash: is: command not found

单引号和双引号的区别。单引号告诉 shell 忽略所有特殊字符,而双引号忽略大多数,但不包括 $、\、`。

[root@localhost sh] $ testvalue=100
[root@localhost sh] $ echo 'The testvalue is $testvalue'
The testvalue is $testvalue
[root@localhost sh] $ echo "The testvalue is $testvalue"
The testvalue is 100


我在使用 gitlab 时,使用 shell runner 时,将对应的变量放在了一个单引号的命令中,但是其中的变量始终不替换,后来换成双引号就好了,所以查了一下 linux 下单引号双引号的区别。

· One min read



var foo = require("./dir/"+somevaribale+".js");




var module_path= "/dir/"+somevariable+".js";
var foo= require(module_path);

在 node 后端环境,这样是没有问题的。

但是在 webpack 打包的时候,这样就会有警告了: Critical dependencies

这个问题,是源自 webpack 中的require context问题。

在 github 上也有相关的讨论:

我试了这种方式,发现可以,所以分享一下,但是我没有在 electron 环境下尝试。

// webpack.config.js

module: {
// require
unknownContextRegExp: /$^/,
unknownContextCritical: false,

// require(expr)
exprContextRegExp: /$^/,
exprContextCritical: false,

// require("prefix" + expr + "surfix")
wrappedContextRegExp: /$^/,
wrappedContextCritical: false

· One min read

如果自己一个不小心的提交了一些敏感的信息到 git 上面,

而自己的项目有可能被其他人看到,如果查看历史记录还是能看到自己提交那些文件。那么如果彻底从历史记录中的删除这些文件 操作是在 Linux 下面做的 :

git filter-branch --index-filter 'git rm --cached --ignore-unmatch*' --prune-empty --tag-name-filter cat -- --all
git push origin master --force
rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
git gc --aggressive --prune=now

· One min read

NTS 框架中采用了新的方式记录浏览器的操作历史,因此在某些带 IFRAME 载入内容的项目中不希望这个 IFRAME 的变化影响到整个系统的操作历史,下面给出两种禁止 IFRAME 记录操作历史的解决方案,各有利弊视具体情况选取。


原理:利用 location 的 replace 方法载入新页面,关于 replace 方法的描述: When a document is replaced, it is also removed from the history object. Moreover, the user interface navigation methods, such as the Back and Forward buttons, will no longer access the URL. 分析:此方案有个前提条件就是父窗体需要有对 iframe 窗体的访问权限,因此此方案一般用于 iframe 载入的内容和父窗体是同域或者同父域的情形。 范例: case 1

第一种方案主要是通过 replace 来将 url 替换而不是 push 到浏览器历史中



原理:先销毁已有 iframe 再创建一个新的,然后通过新的 iframe 载入新的页面内容 分析:不存在跨域问题,但是会有 iframe 不断创建销毁的额外开销 范例: untitled2.png

第二种方式主要是删除 iframe 节点之后重新创建一个 iframe 元素。

iframe = document.createElement('iframe');
iframe.src = url;


· One min read



* auto port
* @authors luoyjx (
* @date 2016-10-16 20:42:57
var net = require('net');

var server = net.createServer();
server.on('error', console.log);
server.on('listening', function () {
var port = server.address().port;

server.close(function () {
console.log('auto port: %s', port);
// tcp 使用端口 0 表示系统分配端口


服务在启动的时候,首先去获取一个可用端口,将自己使用此端口启动,再注册到配置管理中,这样即可实现服务注册了。 配合 etcd 即可实现服务发现,不过还木有实践。

· One min read


git add 添加 git commit -m "xxx" 注释提交 git log 提交日志 git log --pretty=oneline 提交日志在一行显示 git reset --hard HEAD~1 回退到上一个提交 git reset --hard 467dcab 回到某个commit git reflog 查看命令历史 git checkout -- file 丢弃工作区修改 git rm 删除一个文件


git stash 当前工作现场“储藏”起来 git stash pop 恢复并删除stash内容 git stash apply 恢复 git stash drop 删除stash内容 git stash list 列出stash列表


git branch 查看分支
git branch `<name>` 创建分支
git checkout `<name>` 切换分支
git checkout -b `<name>` 创建+切换分支
git merge `<name>` 合并某分支到当前分支
git branch -d `<name>` 删除分支
git branch -D name 强行删除分之
git checkout -b dev origin/dev 创建远程分之到本地
git pull 从远程分之拉取
git branch --set-upstream dev origin/dev 指定本地dev分支与远程origin/dev分支的链接


git checkout master          切换到主分支
git checkout -b bug-001 创建bug-001分之
git add file 添加文件
git commit -m "fix bug 001" 提交文件并注释
git checkout master 切换到主分支
git merge --no-ff -m "merge bug fix 001" bug-001 bug-001分之合并到当前分支
git branch -d bug-001 删除bug分支


git tag 列出标签
git tag v1 打一个新标签
git tag v1 6224937 给某次提交打tag
git tag -a v1 -m "tag desc" 6224937 指定某一标签打tag并注释
git show v1 看到文字说明
git tag -d v1 删除标签
git push origin tagname 推送标签到远程仓库
git push origin --tags 一次推送所有本地未推送标签
git push origin :refs/tags/tagname 删除远程标签

· One min read


先查看下自己机器上的 OpenSSL 版本。

openssl version
cd /usr/local/src/
tar -zxvf openssl-1.0.1g.tar.gz
cd openssl-1.0.1g
./config shared zlib
make && make install


mv /usr/bin/openssl /usr/bin/openssl.old
mv /usr/include/openssl /usr/include/openssl.old

设置软连接使其使用新的OpenSSL版本 刚刚安装的OpenSSL默认安装在/usr/local/ssl

ln -s /usr/local/ssl/bin/openssl /usr/bin/openssl
ln -s /usr/local/ssl/include/openssl /usr/include/openssl


echo "/usr/local/ssl/lib" >> /etc/
ldconfig -v

我们再来看看 OpenSSL 版本信息.

1 2 3

openssl version

OpenSSL 1.0.1g 7 Apr 2014

如果是 1.0.1g,说明你安装正确了

· One min read




当然,通常的思路就是,把这个列表中的这行记录的那个属性值设为true即可,添加按钮就隐藏掉。 untitled1.png



    newArr = mapFunc(contact) {
var result = contact;

if ( === {
result.isFriend = true;
return result;

return Object.assign({}, oldState, {
contactsList: newArr,




    if ( === {
// 不能直接赋值,此处直接赋值,引用不变,被认为对象为改变,则不重新渲染
result = Object.assign({}, result, {isFriend: true});

· One min read




var fs = require('fs');
var pdf = fs.createReadStream(path);

res.writeHead(200, {
'Content-Type': 'application/force-download',
'Content-Disposition': 'attachment; filename=test.rar'


· One min read


Build regular expressions with natural language.



var ipMatch = /(?:(?:1\d\d|2[0-4]\d|25[0-5]|[1-9]\d|\d)\.){3}(?:1\d\d|2[0-4]\d|25[0-5]|[1-9]\d|\d)\b/;



var ipNumber =
RE ("1").then.digit.then.digit
.or ("2").then.oneOf.range("0", "4").then.digit
.or ("25").then.oneOf.range("0", "5")
.or .oneOf.range("1", "9").then.digit
.or .digit

ipMatch = RE.matching.exactly(3).group( ipNumber.then(".") )


通过npm : `

npm install re-build


bower install re-build