每天学习一个命令:gzip 压缩文件

gunzip 是个使用广泛的解压缩程序,它用于解开被 gzip 压缩过的文件,这些压缩文件预设最后的扩展名为”.gz”。 事实上 gunzip 就是 gzip 的硬连接,因此不论是压缩或解压缩,都可通过 gzip 指令单独完成。

命令格式

unzip  [-Z]  [-cflptTuvz[abjnoqsCDKLMUVWX$/:^]]  file[.zip] [file(s) ...]
   [-x xfile(s) ...] [-d exdir]

常用参数:

  • -c 将输出写到标准输出上,并保留原有文件
  • -d 把 .gz 文件解压出来
  • -l 查看当前压缩文件的信息。
  • -r 递归式地查找指定目录并压缩其中的所有文件或者是解压缩
  • -t 测试,检查压缩文件是否完整
  • -num 用指定的数字 num 调整压缩的速度,-1 或 –fast 表示最快压缩方法(低压缩比),-9 或 –best 表示最慢压缩方法(高压缩比)系统缺省值为 6
  • -v 对每一个压缩和解压的文件,显示文件名和压缩比。

使用实例

压缩

gzip file1

压缩直接使用 gzip 加上文件名,还可以指定压缩率默认是 6 ,最高是 9 最低是 1。

解压缩

gzip -dv file.gz

显示压缩包内容

gzip -l file.gz

可以显示压缩之后的大小 解压缩之后的大小 压缩率是多少,大概像下图这样。

compressed       uncompressed         ratio          uncompressed_name
  23124234          110229            60.4%          file.gz

2018-12-11 linux , gzip , tar , command

Set up Drools Workbench with tomcat

在本机使用 Tomcat 启动 Drools Workbench,通常情况下直接使用 Docker 起就行了,但是为了学习 KIE Drools Workbench,这边就补习一下 Tomcat 启动方式。

基本的准备工作包括:

  • JDK, JAVA_HOME
  • Tomcat
  • Drools 相关工具
  • sudo 使用权限

installation

Make sure you have Tomcat installed.

Follow this link to download the drools workbench. And choose the Tomcat version to download.

You will get kie-drools-wb-7.11.0.Final-tomcat8.war file. And you can just rename it to kie-drools-wb.war .

And copy(deploy) the .war to TOMCAT/webapps directory. 这个名字决定了在 URL 中的路径,需要注意下。

dependency jars

Download following related jars and copy them to TOMCAT/lib:

  • btm-2.1.4.jar
  • btm-tomcat55-lifecycle-2.1.4.jar
  • h2-1.4.193.jar
  • jta-1.1.jar
  • slf4j-api-1.7.2.jar
  • slf4j-jdk14-1.7.2.jar
  • kie-tomcat-integration-7.11.0.Final.jar kie-tomcat-integration
  • javax.security.jacc-api-1.6.jar JACC (javax.security.jacc:artifactId=javax.security.jacc-api)

These jars can be found at https://mvnrepository.com/

conf

Firstly, modify the vim tomcat\conf\tomcat_user.xml file, and add following between <tomcat-users></tomcat-users>. This file control the privilege of tomcat which is used by KIE:

<role rolename="admin"/>
<role rolename="analyst"/>
<role rolename="user"/>
<role rolename="kie-server"/>
<role rolename="manager"/>
<role rolename="manager-gui"/>
<role rolename="manager-status"/>
<user username="workbench" password="workbench" roles="admin,kie-server"/>
<user username="kieserver" password="kieserver" roles="kie-server"/>
<user username="admin" password="admin" roles="admin,manager-gui,manager-status,manager, user"/>

Note, analyst or admin roles is required to be authorized to use kie-wb.

Secondly, create setenv.sh (or setenv.bat) under tomcat/bin/

TOMCAT_HOME="/opt/tomcat/"
DATA_PATH="/home/einverne/data/kie-wb"
CATALINA_OPTS="-Xmx512M  \
            -XX:MaxPermSize=512m  \
            -Dbtm.root=$TOMCAT_HOME \
            -Dbitronix.tm.configuration=$TOMCAT_HOME\conf\btm-config.properties \
            -Djbpm.tsr.jndi.lookup=java:comp/env/TransactionSynchronizationRegistry \
            -Djava.security.auth.login.config=$TOMCAT_HOME\webapps\kie-drools-wb\WEB-INF\classes\login.config \
            -Dorg.jboss.logging.provider=jdk \
            -Dorg.uberfire.nio.git.dir=$DATA_PATH \
            -Dorg.uberfire.nio.git.ssh.cert.dir=$DATA_PATH \
            -Dorg.guvnor.m2repo.dir=$DATA_PATH/repo \
            -Dorg.uberfire.metadata.index.dir=$DATA_PATH"

NOTE: On Debian based systems $CATALINA_HOME needs to be replaced with $CATALINA_BASE. ($CATALINA_HOME defaults to /usr/share/tomcat8 and $CATALINA_BASE defaults to /var/lib/tomcat8/)

NOTE: this is an example for unix like systems for Windows $CATALINA_HOME needs to be replaced with windows env variable or absolute path

NOTE: java.security.auth.login.config value includes name of the folder in which application is deployed by default it assumes kie-drools-wb so ensure that matches real installation. login.config file can be externalized as well meaning be placed outside of war file.

还有一个需要注意的是,如果想要在 Drools Workbench 中使用 git clone ssh://admin@localhost:8001/ 这样的工具,有两点需要特别注意,一个就是这个配种中的

-Djava.security.auth.login.config=$TOMCAT_HOME\webapps\kie-drools-wb\WEB-INF\classes\login.config \

这个 login.config 地址一定要配置正确,尤其是 webapps 后面的路径,不同的环境可能配置的路径不一样。第二点就是在上面的角色配置中需要启用一个叫做 user 的角色,并且将自己的用户名配置到 user 角色下。1 2

Then add valve configuration into TOMCAT_HOME/conf/server.xml inside Host element as last valve definition:

<Valve className="org.kie.integration.tomcat.JACCValve" />

Create btm-config.properties file under tomcat/conf and add this:

bitronix.tm.serverId=tomcat-btm-node0
bitronix.tm.journal.disk.logPart1Filename=%{btm.root}%\work\btm1.tlog
bitronix.tm.journal.disk.logPart2Filename=%{btm.root}%\work\btm2.tlog
bitronix.tm.resource.configuration=%{btm.root}%\conf\resources.properties

Create resources.properties file under tomcat/conf:

resource.ds1.className=bitronix.tm.resource.jdbc.lrc.LrcXADataSource
resource.ds1.uniqueName=jdbc/jbpm
resource.ds1.minPoolSize=10
resource.ds1.maxPoolSize=20
resource.ds1.driverProperties.driverClassName=org.h2.Driver
resource.ds1.driverProperties.url=jdbc:h2:mem:jbpm
resource.ds1.driverProperties.user=sa
resource.ds1.driverProperties.password=
resource.ds1.allowLocalTransactions=true

打开 KIE

打开 http://localhost:8080 端口应该能看到 Tomcat 页面,在 Tomcat 管理 app 页面中 (http://localhost:8080/manager/html) 启动 KIE

在列表中会看到 kie-wb 这个项目,初始状态应该是 stop 状态,点击启动,观察 Tomcat 下 logs/catalina.out 应该能够看到启动日志,如果出现错误,需要处理一下。通常情况下可能会出现创建目录失败的问题,手动创建目录并给予写入权限即可。

等待启动后,点击左边的 path 进入应用,使用 Tomcat 中配置的权限登录。

reference


2018-12-02 drools , kie , drools-workbench , tomcat , linux , rule-engine

Tomcat 安装及使用

DescriptionApache Tomcat implements several Java EE specifications including Java Servlet, JavaServer Pages, Java EL, and WebSocket, and provides a “pure Java” HTTP web server environment in which Java code can run.

Apache License 2.0

installation

Firstly, make sure jdk is installed.

Download the latest binary release of Tomcat from the official site

wget http://apache.website-solution.net/tomcat/tomcat-8/v8.5.41/bin/apache-tomcat-8.5.41.tar.gz
sudo tar zxvf apache-tomcat-8.5.41.tar.gz -C /opt/
sudo ln -s /opt/apache-tomcat-8.5.41 /opt/tomcat

Then, for security purposes, Tomcat should be run as an unprivileged user( not root), so we have to create necessary group and users.

sudo groupadd tomcat

And create a tomcat user. And we make this user a member of tomcat group, with a shell of /bin/false( so nobody can log into the account ), and with a home directory of /opt/tomcat (where we install Tomcat) sudo useradd -s /bin/false -g tomcat -d /opt/tomcat tomcat

Now, tomcat user is set up.

Give the tomcat group ownership over the entire installation directory:

sudo chgrp -R tomcat /opt/tomcat

And give the tomcat group read access to the conf directory and all of its contents.

sudo chmod -R g+r conf
sudo chmod g+x conf
sudo chown -R tomcat webapps/ work/ temp/ logs/

Create a systemd Service file

sudo vim /etc/systemd/system/tomcat.service

And paste this:

[Unit]
Description=Apache Tomcat Web Application Container
After=network.target

[Service]
Type=forking

Environment=JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre
Environment=CATALINA_PID=/opt/tomcat/temp/tomcat.pid
Environment=CATALINA_HOME=/opt/tomcat
Environment=CATALINA_BASE=/opt/tomcat
Environment='CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC'
Environment='JAVA_OPTS=-Djava.awt.headless=true -Djava.security.egd=file:/dev/./urandom'

ExecStart=/opt/tomcat/bin/startup.sh
ExecStop=/opt/tomcat/bin/shutdown.sh

User=tomcat
Group=tomcat
UMask=0007
RestartSec=10
Restart=always

[Install]
WantedBy=multi-user.target

And remember to replace your own java home.

Next, reload the systemd daemon

sudo systemctl daemon-reload
sudo systemctl start tomcat
sudo systemctl status tomcat

How you can visit http://localhost:8080 to check Tomcat page. Oh if you have ufw installed, don’t forget to allow traffic by:

sudo ufw allow 8080

And finally, if you want to go with Tomcat when start up, you can enable Tomcat automatically starts at boot:

sudo systemctl enable tomcat

management

In order to use the manager web app that comes with Tomcat, we must add a login to our Tomcat server.

sudo vim /opt/tomcat/conf/tomcat-users.xml

and edit:

<tomcat-users . . .>
  <user username="admin" password="password" roles="manager-gui,admin-gui"/>
</tomcat-users>

Restart your server

sudo systemctl restart tomcat

you can get what you want:

http://localhost:8080/manager/html
http://localhost:8080/host-manager/html

questions

修改 Tomcat 端口

修改 conf 目录下 server.xml 文件,修改 http 访问端口,默认为 8080

<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />

搜索 Connector port 修改这里的端口号。

reference


2018-12-01 tomcat , java-ee , java-web

MySQL 中的日志配置和管理

MySQL 中默认是没有开启日志记录的,所以需要手动修改配置文件开启日志。而在 MySQL 中我们需要关心的有三类日志:

  • The error log 错误日志,这一类日志包括了服务器运行时,包括启动和停止时的错误等信息
  • The General Query Log 查询日志,通常是 mysqld 进行连接,断开连接,查询等等操作的日志
  • The Slow Query Log 慢查询日志,包含了慢查询的 SQL 语句

在配置中没有开启任何日志记录时,MySQL 相关的日志在 /var/log/syslog 中。之所以关注到 MySQL 的日志是因为发现服务器上 MySQL 间隔一定时间就自动重启,想要找出原因,开启日志之后观察了一段时间,初步排查可能是 clamav 执行时占用内存导致 MySQL 内存不足挂掉。现在把所有的日志都开启观察一段时间再看看。

开启日志

修改 /etc/mysql/my.cnf 中的配置,开启 MySQL 服务器日志,不同发行版的配置地址可能不相同:

[mysqld_safe]
log_error=/var/log/mysql/error.log

[mysqld]
log_error=/var/log/mysql/error.log

开启查询日志

general_log_file        = /var/log/mysql/mysql.log
general_log             = 1

开启慢查询日志

log_slow_queries       = /var/log/mysql/mysql-slow.log
long_query_time = 2
log-queries-not-using-indexes

修改保存配置之后需要重新启动 mysql

sudo service mysql restart

在运行时开启日志

如果不想重启服务器,可以在运行时,通过 mysql client 登录之后 mysql -u root -p 然后执行命令来开启:

SET GLOBAL general_log = 'ON';
SET GLOBAL slow_query_log = 'ON';

reference


2018-11-29 mysql , log , database , linux

Java 查漏补缺之:ThreadLocal 使用

ThreadLocal 线程本地变量,每个线程保存变量的副本,对副本的改动,对其他的线程而言是透明的。

特性

  • The object is not shared between threads, so it can be used without the need for synchronization
  • it is available throughout the life of the thread, meaning you don’t have to pass it all over the place through method calls

适用场景

  • 每个线程都需要自己的数据存储对象
  • 实例被多个方法共享,但是不希望多线程共享

一个典型的例子就是用 ThreadLocal 来保存一次请求的 Session 数据,程序的不同地方可能需要读取 Session 的内容,也要往 Session 中写入数据。

常用方法

// 设置当前线程的线程局部变量的值
void set(Object value);

// 该方法返回当前线程所对应的线程局部变量
public Object get();

// 将当前线程局部变量的值删除
public void remove();

ThreadLocal 类允许我们创建只能被同一个线程读写的变量,通常的用法是当有一些 Object 不是线程安全,但是又想避免使用同步 访问机制时。比如 SimpleDateFormat,因此可以使用 ThreadLocal 来给每一个线程提供一个线程自己的对象。

public class Foo
{
    // SimpleDateFormat is not thread-safe, so give one to each thread
    private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
        @Override
        protected SimpleDateFormat initialValue()
        {
            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        }
    };

    public String formatIt(Date date)
    {
        return formatter.get().format(date);
    }
}

ThreadLocal 对象是给定线程中对象的引用,因此在服务端使用线程池时极有可能造成 classloading leaks 内存泄露 ,在使用时需要特别注意清理。ThreadLocal 持有的任何对象空间在 Java 永久堆上,即使重新部署 webapp 也不回收这部分内存,可能造成 java.lang.OutOfMemoryError 异常。

原理

利用 HashMap,在 map 中保存了 Thread -> 线程变量的关系,因此在多线程之间是隔离的,但同时也耗费了内存空间。

reference


2018-11-28 java , thread

为知笔记导出和备份

WizNote 已经用了好几年,虽然也一直在续费,但总感觉将死不死,基于整理这几年近 4000 条的笔记的目的,也一方面为迁移出 WizNote 的目的,研究一下 WizNote 笔记导出和备份的方法。

文中有些具体分析,基于 WizNote for Linux Version 2.5.8 版本,不同版本之间可能有些差异,务必要注意。

在 Linux 下 WizNote 笔记本地缓存放在~/.wiznote/{your-account-email-addr}/data/notes目录下面,都是{GUID}的方式存放,这些文件都是 zip 文件,每个文件里面包含 html , 图片以及元数据。元数据meta.xml 包含了每个 note 的相关信息,比如标题描述等等

如果需要更详细的信息,可以通过读 SQLite 的工具打开 ~/.wiznote/{your-account-email-addr}/data/index.db 文件

准备工作

在导出数据之前有一些准备工作,先同步所有数据,在 Preference 中,Sync 同步选项下

  • Personal sync method 选 Download all data
  • Group sync method 选择 Download all data when sync
  • Download attachment 选择 Download all attachments

否则可能导致本地缓存不是全部的笔记而造成一定程度数据丢失。

解决方法

在 index.db 数据库中有两张很重要的表,WIZ_DOCUMENT 其中包括了所有笔记的信息,包括笔记的 GUID,标题等等信息,具体的表结构可以查看后文附录中内容。另外一张很重要的表是 WIZ_DOCUMENT_ATTACHMENT 其中存储了笔记附件信息。

表中重要的几列

  • DOCUMENT_GUID 看名字就能够猜出来这是笔记的全局唯一 ID,对应着 data 目录中存储的笔记 ID
  • DOCUMENT_TITLEDOCUMENT_LOCATION 等等顾名思义就不多说
  • 上面提及的两张表通过 DOCUMENT_GUID 形成关联,一个笔记可能会对应一个或者多个附件,这些信息都包含在附件表中

所以对应的解决方案就是中 db 中读取笔记的 meta 信息,从磁盘 data 目录中找到对应的笔记,解压缩,然后将对应的附件拷贝到对应的笔记目录。

源码地址:https://github.com/einverne/ExptWizNote

附录

表结构 WIZ_DOCUMENT

create table WIZ_DOCUMENT
(
  DOCUMENT_GUID              char(36)     not null
    primary key,
  DOCUMENT_TITLE             varchar(768) not null,
  DOCUMENT_LOCATION          varchar(768),
  DOCUMENT_NAME              varchar(300),
  DOCUMENT_SEO               varchar(300),
  DOCUMENT_URL               varchar(2048),
  DOCUMENT_AUTHOR            varchar(150),
  DOCUMENT_KEYWORDS          varchar(300),
  DOCUMENT_TYPE              varchar(20),
  DOCUMENT_OWNER             varchar(150),
  DOCUMENT_FILE_TYPE         varchar(20),
  STYLE_GUID                 char(38),
  DT_CREATED                 char(19),
  DT_MODIFIED                char(19),
  DT_ACCESSED                char(19),
  DOCUMENT_ICON_INDEX        int,
  DOCUMENT_SYNC              int,
  DOCUMENT_PROTECT           int,
  DOCUMENT_READ_COUNT        int,
  DOCUMENT_ATTACHEMENT_COUNT int,
  DOCUMENT_INDEXED           int,
  DT_INFO_MODIFIED           char(19),
  DOCUMENT_INFO_MD5          char(32),
  DT_DATA_MODIFIED           char(19),
  DOCUMENT_DATA_MD5          char(32),
  DT_PARAM_MODIFIED          char(19),
  DOCUMENT_PARAM_MD5         char(32),
  WIZ_VERSION                int64,
  INFO_CHANGED               int default 1,
  DATA_CHANGED               int default 1
);

WIZ_DOCUMENT_ATTACHMENT 结构

create table WIZ_DOCUMENT_ATTACHMENT
(
  ATTACHMENT_GUID        char(36)     not null
    primary key,
  DOCUMENT_GUID          varchar(36)  not null,
  ATTACHMENT_NAME        varchar(768) not null,
  ATTACHMENT_URL         varchar(2048),
  ATTACHMENT_DESCRIPTION varchar(600),
  DT_INFO_MODIFIED       char(19),
  ATTACHMENT_INFO_MD5    char(32),
  DT_DATA_MODIFIED       char(19),
  ATTACHMENT_DATA_MD5    char(32),
  WIZ_VERSION            int64
);

2018-11-27 wiznote , notebook , backup , markdown

Nginx location 匹配规则

之前的关于 Nginx Config 的文章是当时看 Nginx 书记录下来的笔记,很大略,没有实际操作,等终究用到 location 的时候发现还是有很多需要注意的问题,比如匹配的优先顺序,比如 root 和 alias 的区别等等,所以单独拿一篇文章来记录一下目前遇到的问题,并来解决一下。

location 匹配顺序

之前的文章 也简单的提到了 Nginx 配置中 location 块,这个配置能够是的针对 URL 中不同的路径分别可以配置不同的处理路径。我当前遇到的问题就是提供 API 接口的项目和静态文件的项目是两个单独的项目,我需要 / 处理 proxy_pass 到本地一个端口,而 /resources 到本地另外一个静态资源文件的路径。

location 的语法在很多的文档教程中都被描述为:

location [ = | ~ | ~* | ^~ ] uri { ... }
  • = 用于非正则精确匹配 uri ,要求字符串与 uri 严格匹配,如果匹配成功,则停止向下搜索,并立即处理此请求
  • ^~ 用于非正则 uri 前,Nginx 服务器找到标示 uri 和请求字符串匹配程度最高的 location 后立即使用该 location 处理请求,不再匹配 location 块的正则 url
  • ~ 表示该 uri 包含正则,并且区分大小写
  • ~* 表示 uri 包含正则,不区分大小写

从四个类别中就能看出来,location 使用两种表示方法,一种为不带 ~ 的前缀字符,一种是带有 ~ 的正则。

需要注意的是:

  • 使用正则那么 location 定义的顺序很重要,第一个匹配的正则,之后就立即执行了
  • 使用精确匹配可以提高查询速度,比如经常请求的路径可以精确匹配 =

一个具体的请求 path 过来之后,Nginx 的具体匹配过程可以分为这么几步:

  • 检查前缀字符定义的 location,记录最长的匹配项
  • 如果找到了精确匹配 = 的 location,结束查找,只用该配置
  • 按顺序查找正则定义的 location,如果匹配则停止查找
  • 如果没有匹配的正则,则使用之前记录的最长匹配 location

那么针对特定的问题:

location ^~ /resources {
    alias /home/einverne/project/static/;
    # autoindex on;
}
location ~ / {
    proxy_pass http://localhost:9000;
}

首先对于静态文件,我们要让匹配到的第一时间就命中,所以使用了 ^~

关于 location 匹配结尾的斜杠

在 location 后面接的表达式中的 slash 斜杠,可有可无,并没有影响。而对于 URL 中的尾部 / 则是,当有 / 时表示目录,没有时表示文件。当有 / 是服务器会自动去对应目录下找默认文件,而如果没有/ 则会优先去匹配文件,如果找不到文件才会重定向到目录,查默认文件。

root 和 alias 的区别

在 Location 或者其他 Nginx 配置中会经常看到 rootalias ,开始我以为这两者是能够混用的,但其实两者有着很大的区别。root 指令会将 location 中的部分附加到 root 定义的末尾形成一个完整的路径;而 alias 则不会包含 location 中定义的部分。

比如:

location /static {
    root /var/www/app/static/;
    autoindex off;
}

那么当 Nginx 寻找路径时会是:

/var/www/app/static/static/

如果这个在 static 目录的 static 目录不存在则显而易见会产生 404 错误。这是因为 location 中的 static 部分被附加到了 root 指定的路径后面,因此正确的做法是:

location /static {
    root /var/www/app/;
    autoindex off;
}

而对于 alias 正确的做法则是:

location /static {
    alias /var/www/app/static/;
    autoindex off;
}

reference


2018-11-13 nginx , location , regex , web-server , server

koajs 简单使用

Koa 是一个背靠 Express 的团队设计的全新的 Web 框架,旨在使之成为一个更轻量,更丰富,更加 robust 的基础框架。通过促进异步方法的使用,Koa 允许使用者抛弃 callback 调用,并且大大简化了错误处理。Koa 并没有将中间件绑定到核心代码,而是提供了一组优雅的方法让编写服务更加快速,通过很多第三方的扩展给 Koa 提供服务,从而实现更加丰富完整的 HTTP server。

Koa is a new web framework designed by the team behind Express, which aims to be a smaller, more expressive, and more robust foundation for web applications and APIs. By leveraging async functions, Koa allows you to ditch callbacks and greatly increase error-handling. Koa does not bundle any middleware within its core, and it provides an elegant suite of methods that make writing servers fast and enjoyable.

安装和入门

Koa 需要 node v7.6.0 及以上版本

nvm install 7
npm i koa
node my-koa-app.js

先从简单的例子说起,实现一个简单的 HTTP 服务:

const Koa = require('koa');
const app = new Koa();

const main = ctx => {
  ctx.response.body = 'Hello World';
};

app.use(main);
app.listen(3000);

Koa 有一个 Context 对象,表示一次请求上下文,通过对该对象的访问来控制返回给客户端的内容。

路由

Koa 的原生路由就需要使用者自己通过字符串匹配来维护复杂的路由,通过扩展 koa-route 可以实现更加丰富的路由选择

const route = require('koa-route');

const about = ctx => {
  ctx.response.type = 'html';
  ctx.response.body = '<a href="/">About</a>';
};

const main = ctx => {
  ctx.response.body = 'Hello World';
};

app.use(route.get('/', main));
app.use(route.get('/about', about));

那么这样之后通过 localhost:3000/localhost:3000/about 就可以访问不同内容。

对于静态资源可以使用 koa-static

const path = require('path');
const serve = require('koa-static');
const main = serve(path.join(__dirname));
app.use(main);

更多的内容可以参考文末链接。

reference


2018-11-12 koa , web-framework , angularjs , angular

gulp 工具简单使用

Gulp 是基于 Node.js 的前端构建工具,可以通过 Gulp 实现前端代码编译,压缩,测试,图片压缩,浏览器自动刷新,等等,Gulp 提供了很多插件

大概可以理解成 makefile 之于 C++, Maven 之于 Java 吧,通过定义任务简化前端代码构建过程中繁琐的过程。

简单使用

全局安装

npm i gulp -g

然后在项目根目录安装一遍

npm i gulp --save-dev

一般在根目录创建 gulpfile.js 文件,用来编写 gulp task。

以压缩图片举例:

gulp.task('images', function() {
  return gulp.src('src/images/**/*')
    .pipe(imagemin({ optimizationLevel: 3, progressive: true, interlaced: true }))
    .pipe(gulp.dest('dist/assets/img'))
    .pipe(notify({ message: 'Images task complete' }));
});

再运行 gulp images 就可以将 src/images 文件夹及子文件夹图片压缩,最后存放到 dist 目录。

关于压缩图片其实有很多选择:

reference


2018-11-09 gulp , nodejs , angularjs. npm , sass

使用 nltk 词形还原

今天在用 mdx-server 将 mdx 文件导出 HTTP 接口时发现 mdx-server 项目并不支持类似与 GoldenDict Morphology 构词法一样的规则,所以只能够在 mdx-server 外自行处理英语单词的词形变化,搜索一圈之后发现了 NLTK。

英语中词形还原叫做 lemmatization,是将一个任何形式的单词还原为一般形式的意思。另外一个相关的概念是 stemming 也就是词干提取,抽取单词的词干或者词根。这两种方法在自然语言处理中都有大量的使用。这两种方式既有联系也有很大差异。

  • 两者的目标相似,lemmatization 和 stemming 目标都是将单词的衍生形态简化或者归并为词干 stem 或者原形,都是对相同单词不同形态的还原
  • lemmatization 和 stemming 的结果有交叉,cats 的结果相同
  • 主流实现方法类似,通过语言中存在的规则和词典映射提取
  • 主要应用领域相似,应用于信息检索和文本,自然语言处理等方面

区别

词干提取采用缩减方法,将词转变为词干,cats 变为 cat,将 effective 处理成 effect,而词性还原采用转变的方法,将词还原为一般形态,将 drove 变为 drive,将 driving 变为 drive

Stemming

In linguistic morphology and information retrieval, stemming is the process for reducing inflected (or sometimes derived) words to their stem, base or root form—generally a written word form. The stem need not be identical to the morphological root of the word; it is usually sufficient that related words map to the same stem, even if this stem is not in itself a valid root. Algorithms for stemming have been studied in computer science since the 1960s. Many search engines treat words with the same stem as synonyms as a kind of query expansion, a process called conflation.

Stemming programs are commonly referred to as stemming algorithms or stemmers.

Lemmatization

Lemmatisation (or lemmatization) in linguistics, is the process of grouping together the different inflected forms of a word so they can be analysed as a single item.

In computational linguistics, lemmatisation is the algorithmic process of determining the lemma for a given word. Since the process may involve complex tasks such as understanding context and determining the part of speech of a word in a sentence (requiring, for example, knowledge of the grammar of a language) it can be a hard task to implement a lemmatiser for a new language.

In many languages, words appear in several inflected forms. For example, in English, the verb ‘to walk’ may appear as ‘walk’, ‘walked’, ‘walks’, ‘walking’. The base form, ‘walk’, that one might look up in a dictionary, is called the lemma for the word. The combination of the base form with the part of speech is often called the lexeme of the word.

Lemmatisation is closely related to stemming. The difference is that a stemmer operates on a single word without knowledge of the context, and therefore cannot discriminate between words which have different meanings depending on part of speech. However, stemmers are typically easier to implement and run faster, and the reduced accuracy may not matter for some applications.

NLTK Lemmatization

The NLTK Lemmatization 方法基于 WordNet 内置的 morphy function.

>>> from nltk.stem import WordNetLemmatizer
>>> wordnet_lemmatizer = WordNetLemmatizer()
>>> wordnet_lemmatizer.lemmatize(‘dogs’)
u’dog’
>>> wordnet_lemmatizer.lemmatize(‘churches’)
u’church’
>>> wordnet_lemmatizer.lemmatize(‘aardwolves’)
u’aardwolf’
>>> wordnet_lemmatizer.lemmatize(‘abaci’)
u’abacus’
>>> wordnet_lemmatizer.lemmatize(‘hardrock’)
‘hardrock’
>>> wordnet_lemmatizer.lemmatize(‘are’)
‘are’
>>> wordnet_lemmatizer.lemmatize(‘is’)
‘is’

lemmatize() 方法有第二个 pos 参数,可以传入 n 表示 noun,或者 v 表示 verb,或者其他的形容词等等,提高准确度。

更多的 doc 可以参考 API。

reference


2018-11-08 nltk , lemmatization , stemming , nlp , goldendict , dictionary

电子书

最近文章

  • Substratum Android 上的主题引擎 Substratum 是一款 Android 上的主题工具,能够不用 root 来达到系统级主题修改。并且在该工具下有一群爱好者和社区开发了无数的美观且实用的主题。Substratum 开始于以前非常流行的 CyanogenMod, Cyanogen 内置了该主题引擎,并使得修改主题异常简单。但是不幸的是,Cyanogen 没有继续下去, 但是 Substratum 死灰复燃。最初的时候 Substratum 还需要 Root 来使用,但是 Android Oreo 之后就可以不依赖于 Root 了。
  • Flask Babel 使用 Flask babel 是 Flask 的语言扩展,允许非常简单的方式让 Flask 支持多语言。
  • Android 内核中的 CPU 调频 CPU 调频模块主要分为三块:
  • QQ 音乐 qmcflac 文件解密 首先说重点,代码来自:
  • Vim 插件之全局搜索:ack.vim 这篇文章看开始陆陆续续记录一下用过的 Vim Plugin,虽然有些一直也在用但从没有好好整理过,正好这篇开一个计划吧。