gyp: No Xcode or CLT version detected!

最近升级了系统之后,做 npm install 操作时会报错如下

gyp: No Xcode or CLT version detected!
gyp ERR! configure error
gyp ERR! stack Error: `gyp` failed with exit code: 1
gyp ERR! stack     at ChildProcess.onCpExit (/usr/local/lib/node_modules/npm/node_modules/node-gyp/lib/configure.js:351:16)
gyp ERR! stack     at ChildProcess.emit (events.js:203:13)
gyp ERR! stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:272:12)
gyp ERR! System Darwin 19.4.0
gyp ERR! command "/usr/local/bin/node" "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
gyp ERR! cwd /Users/hliang/Documents/wwwroot/tbw.ixcv.com/vuebackend/node_modules/fsevents
gyp ERR! node -v v12.7.0
gyp ERR! node-gyp -v v5.1.0
gyp ERR! not ok

解决方式如下:

$ sudo rm -rf $(xcode-select -print-path)
$ xcode-select --install

服务器挖矿病毒查杀(crontab pastebin.com)

服务器异常症状

  • CPU使用率过高,网络出口流量异常;
  • crontab异常,出现 pastebian.com 相关的 wget 命令

查杀方法

安装busybox

wget http://busybox.net/downloads/busybox-1.21.0.tar.bz2
yum -y install bzip2
tar -xvf busybox-1.21.0.tar.bz2
cd ./busybox-1.21.0
make defconfig
make
make install
ln -s `pwd`/busybox /usr/bin/busybox
busybox|grep BusyBox |grep v

如果出现以下信息,说明安装成功

BusyBox v1.21.0 (2019-04-15 19:51:44 CST) multi-call binary.

注意,部分挖矿病毒会修改动态链接库,用 vim 打开下面文件,并注释掉其中的内容

Continue reading →

supervisor配置文件模板

项目中需要使用到supervisor来管理常驻内存的后台程序,配置文件样例如下:

[program: smproxy]
command=/usr/local/php/bin/php /usr/local/smproxy/SMProxy start --console    ;服务启动命令
directory=/usr/local/smproxy/    ;命令执行目录
user=root    ;执行命令用户
autorestart=true    ;是否自动重启
autostart=true ;启动supervisor时是否自行启动该程序
;redirect_stderr=true   ;如果为true则将stderr发送到stdout相应的log文件中去
;;stdout_logfile=/var/log/supervisor/app.log ;制定stdout的输出文件
;;stdout_logfile_maxbytes=10MB   ;限定logfile的大小, 默认为50M
;;stdout_logfile_backups=10 ;保存logfile的最大数目,如果操作这个数目则对最早的logfile进行覆盖,默认为10
;;environment=A="1", B="2" ;设置环境变量,这里可以保存运行程序需要的参数 

注:

通过yum安装的supervisor,默认配置文件目录为 /etc/supervisord.d

Homebrew切换到国内镜像源

Mac自带的Homebrew由于GFW的原因,连接到官方源的速度往往都是死慢死慢的,于是考虑到将其切换到国内的镜像源上。

切换过程如下:

# cd "$(brew --repo)"
# git remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/brew.git
# cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core"
# git remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/homebrew-core.git
# brew update

好了,已经成功的将其切换到了清华大学的源上。

JavaScript上万关键字瞬间匹配

既然考虑的是那种极端的关键字搜索,通常的逐个遍历搜索显然是行不通的。如今用的是JavaScript,若不使用Hash表实在是太对不起这门语言了。有着对表特天独厚的支持,不妨就拿出少量的空间来换取大量的时间吧。

代码在下面:

var treeSearch = {
    makeTree: function(strKeys) {
        'use strict';
        var tblCur = {},
            tblRoot,
            key,
            str_key,
            Length,
            j,
            i;
        tblRoot = tblCur;
        for (j = strKeys.length - 1; j >= 0; j -= 1) {
            str_key = strKeys[j];
            Length = str_key.length;
            for (i = 0; i < Length; i += 1) {
                key = str_key.charAt(i);
                if (tblCur.hasOwnProperty(key)) {
                    //生成子节点
                    tblCur = tblCur[key];
                } else {
                    tblCur = tblCur[key] = {};
                }
            }
            tblCur.end = true; //最后一个关键字没有分割符
            tblCur = tblRoot;
        }
        return tblRoot;
    },
    search: function(content, tblRoot) {
        'use strict';
        var tblCur,
            p_star = 0,
            n = content.length,
            p_end,
            match, //是否找到匹配
            match_key,
            match_str,
            arrMatch = [], //存储结果
            arrLength = 0; //arrMatch的长度索引
        while (p_star < n) {
            tblCur = tblRoot; //回溯至根部
            p_end = p_star;
            match_str = '';
            match = false;
            do {
                match_key = content.charAt(p_end);
                if (!(tblCur = tblCur[match_key])) {
                    //本次匹配结束
                    p_star += 1;
                    break;
                } else {
                    match_str += match_key;
                }
                p_end += 1;
                if (tblCur.end === true) {
                    //是否匹配到尾部  //找到匹配关键字
                    match = true;
                }
            } while (true);

            if (match === true) {
                //最大匹配
                arrMatch[arrLength] = {
                    //增强可读性
                    key: match_str,
                    begin: p_star - 1,
                    end: p_end
                };
                arrLength += 1;
                p_star = p_end;
            }
        }
        return arrMatch;
    }
};

测试代码:

function test(strContent, strKeys) {
    var arrMatch,
        tblRoot = treeSearch.makeTree(strKeys),
        t = new Date();
    arrMatch = treeSearch.search(strContent, tblRoot);
    console.log('time is: ' + (new Date() - t) + 'mm');
    console.log(arrMatch);
}

var s = (function() {
    var Things = [' ', '\n', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
    var s = '';
    for (var i = 1000000; i >= 0; i--) {
        s += Things[parseInt(Math.random() * Things.length) % Things.length];
    }
    return s;
})();
test(s, ['abc', 'efge', 'fun', 'tree']);